(* GTK-Kylix Library: GTKView - GtkTreeView and its modifications Version 0.6.21 (last updated 2006-05-06) Copyright (C) 2006 Tomas Bzatek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA. *) unit GTKView; {$O+} // Optimization needs to be enabled for this unit due to bug in compiler (fixed columns doesn't work) interface uses gtk2, gdk2, gdk2pixbuf, glib2, Classes, GTKControls, GTKConsts, GTKUtils, GTKClasses, GTKForms, GTKPixbuf; // Quick jump: QForms QControls QStdCtrls QComCtrls type TGTKListItem = class; TGTKTreeViewColumn = class; (****************************************** TGTKTREEVIEWCOLUMN ******************************************************************) TGTKTreeViewColumnSizingMode = (smGrowOnly, smAutoSize, smFixed); TGTKTreeViewSortOrder = (soAscending, soDescending, soNone); TGTKTreeViewColumnType = (ctText, ctToggle, ctImageText); TGTKTreeViewColumnEditedEvent = procedure(Sender: TObject; Column: TGTKTreeViewColumn; Item: TGTKListItem; var NewText: string; var AllowChange: boolean; var DataColumn: integer) of object; TGTKTreeViewColumnToggledEvent = procedure(Sender: TObject; Column: TGTKTreeViewColumn; Item: TGTKListItem) of object; TGTKTreeViewColumn = class(TComponent) private FOwner: TComponent; FColumnType: TGTKTreeViewColumnType; FOnEdited: TGTKTreeViewColumnEditedEvent; FOnToggled: TGTKTreeViewColumnToggledEvent; FOnClicked: TNotifyEvent; FIndex: integer; function GetCaption: string; function GetVisible: boolean; function GetResizable: boolean; function GetSizingMode: TGTKTreeViewColumnSizingMode; function GetWidth: integer; function GetFixedWidth: integer; function GetMinWidth: integer; function GetMaxWidth: integer; function GetClickable: boolean; function GetAlignment: Double; function GetReorderable: boolean; function GetSortID: integer; function GetShowSortIndicator: boolean; function GetSortOrder: TGTKTreeViewSortOrder; procedure SetCaption(Value: string); procedure SetVisible(Value: boolean); procedure SetResizable(Value: boolean); procedure SetSizingMode(Value: TGTKTreeViewColumnSizingMode); procedure SetFixedWidth(Value: integer); procedure SetMinWidth(Value: integer); procedure SetMaxWidth(Value: integer); procedure SetClickable(Value: boolean); procedure SetAlignment(Value: Double); procedure SetReorderable(Value: boolean); procedure SetSortID(Value: integer); procedure SetShowSortIndicator(Value: boolean); procedure SetSortOrder(Value: TGTKTreeViewSortOrder); procedure SetColumnType(Value: TGTKTreeViewColumnType); public FColumn: PGtkTreeViewColumn; FRenderer, FPixbufRenderer: PGtkCellRenderer; constructor Create(AOwner: TComponent); override; constructor CreateTyped(AOwner: TComponent; ColType: TGTKTreeViewColumnType); destructor Destroy; override; procedure AddAttribute(Attribute: string; Value: integer); procedure SetProperty(AProperty: string; Value: integer); overload; procedure SetProperty(AProperty: string; Value: string); overload; procedure SetProperty(AProperty: string; Value: Double); overload; procedure SetProperty(AProperty: string; Value: pointer); overload; procedure AddImageAttribute(Attribute: string; Value: integer); procedure SetImageProperty(AProperty: string; Value: integer); overload; procedure SetImageProperty(AProperty: string; Value: string); overload; procedure SetImageProperty(AProperty: string; Value: Double); overload; procedure SetImageProperty(AProperty: string; Value: pointer); overload; procedure ClearAttributes; property Parent: TComponent read FOwner; published property Caption: string read GetCaption write SetCaption; property Visible: boolean read GetVisible write SetVisible; property Resizable: boolean read GetResizable write SetResizable; property SizingMode: TGTKTreeViewColumnSizingMode read GetSizingMode write SetSizingMode; property Width: integer read GetWidth; property FixedWidth: integer read GetFixedWidth write SetFixedWidth; property MinWidth: integer read GetMinWidth write SetMinWidth; property MaxWidth: integer read GetMaxWidth write SetMaxWidth; property Clickable: boolean read GetClickable write SetClickable; property Alignment: Double read GetAlignment write SetAlignment; property Reorderable: boolean read GetReorderable write SetReorderable; property SortID: integer read GetSortID write SetSortID; property ShowSortIndicator: boolean read GetShowSortIndicator write SetShowSortIndicator; property SortOrder: TGTKTreeViewSortOrder read GetSortOrder write SetSortOrder; property ColumnType: TGTKTreeViewColumnType read FColumnType write SetColumnType; property Index: integer read FIndex; property OnEdited: TGTKTreeViewColumnEditedEvent read FOnEdited write FOnEdited; property OnToggled: TGTKTreeViewColumnToggledEvent read FOnToggled write FOnToggled; property OnClicked: TNotifyEvent read FOnClicked write FOnClicked; end; (****************************************** TGTKTREEVIEWCOLUMNS *****************************************************************) TGTKTreeViewColumns = class(TComponent) private FOwner: TComponent; FList: TList; function GetCount: Integer; function GetItem(Index: Integer): TGTKTreeViewColumn; procedure SetItem(Index: Integer; Value: TGTKTreeViewColumn); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function Add: TGTKTreeViewColumn; function AddTyped(ColType: TGTKTreeViewColumnType): TGTKTreeViewColumn; procedure Insert(Index: Integer; Item: TGTKTreeViewColumn); procedure Delete(Index: Integer); procedure Clear; procedure AutosizeColumns; property Items[Index: Integer]: TGTKTreeViewColumn read GetItem write SetItem; default; property Parent: TComponent read FOwner; published property Count: Integer read GetCount; end; (****************************************** TGTKLISTITEM ************************************************************************) TGTKListItem = class(TComponent) private FOwner: TComponent; FIndex: longint; FData: pointer; function GetSelected: boolean; procedure SetSelected(Value: boolean); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function AsString(Index: longint): string; function AsInteger(Index: longint): integer; function AsPointer(Index: longint): pointer; function AsBoolean(Index: longint): boolean; procedure SetValue(Index: longint; Value: string); overload; procedure SetValue(Index: longint; Value: integer); overload; procedure SetValue(Index: longint; Value: pointer); overload; procedure SetValue(Index: longint; Value: boolean); overload; procedure SetCursor(const FocusColumnNo: integer; const StartEditing, UseAlignment: boolean; const AlignX, AlignY: Double); procedure StartEditing(ColumnNo: integer); procedure RedrawRow; property Data: pointer read FData write FData; property Parent: TComponent read FOwner; function IsVisible: boolean; published property Selected: boolean read GetSelected write SetSelected; property Index: integer read FIndex; end; (****************************************** TGTKLISTITEMS ***********************************************************************) TGTKListColumnType = (lcText, lcNumber, lcPointer, lcPixbuf, lcBoolean); TGTKListItems = class(TComponent) private FStore: PGtkListStore; FOwner: TComponent; FList: TList; function GetCount: longint; function GetItem(Index: longint): TGTKListItem; procedure SetItem(Index: longint; Value: TGTKListItem); public constructor Create(AOwner: TComponent); override; constructor CreateTyped(AOwner: TComponent; ColumnTypes: array of TGTKListColumnType); destructor Destroy; override; procedure SetColumnTypes(Types: array of TGTKListColumnType); function Add: TGTKListItem; procedure Insert(Index: longint; Item: TGTKListItem); procedure Append(Item: TGTKListItem); procedure Delete(Index: longint); procedure Clear; property Items[Index: longint]: TGTKListItem read GetItem write SetItem; default; property Parent: TComponent read FOwner; published property Count: longint read GetCount; end; (****************************************** TGTKVIEW ****************************************************************************) TGTKSelectionMode = (smNone, smSingle, smBrowse, smMultiple); TGTKCellDataFunc = procedure (Sender: TObject; tree_view: PGtkTreeView; tree_column : PGtkTreeViewColumn; cell : PGtkCellRenderer; tree_model : PGtkTreeModel; iter : PGtkTreeIter) of object; TGTKSortCoversionFunc = function (Sender: TObject; const Index: integer): integer of object; TGTKView = class(TGTKContainer) private FColumns: TGTKTreeViewColumns; FOnSelectionChanged: TNotifyEvent; FTreeModelSort: PGtkTreeModelSort; FCellDataFunc: TGTKCellDataFunc; FTreeModel: PGtkTreeModel; FToSortedConvFunc, FFromSortedConvFunc: TGTKSortCoversionFunc; function GetSelectionMode: TGTKSelectionMode; function GetShowHeaders: boolean; function GetRulesHint: boolean; function GetReorderable: boolean; function GetEnableSearch: boolean; function GetSearchColumn: integer; function GetSortColumnID: integer; function GetSortOrder: TGTKTreeViewSortOrder; procedure SetSelectionMode(Value: TGTKSelectionMode); procedure SetShowHeaders(Value: boolean); procedure SetRulesHint(Value: boolean); procedure SetReorderable(Value: boolean); procedure SetEnableSearch(Value: boolean); procedure SetSearchColumn(Value: integer); procedure SetSortColumnID(Value: integer); procedure SetSortOrder(Value: TGTKTreeViewSortOrder); protected public FSelection: PGtkTreeSelection; constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure SelectAll; procedure DeselectAll; procedure SetSortInfo(ColumnID: integer; Order: TGTKTreeViewSortOrder); function ConvertToSorted(Index: integer): integer; function ConvertFromSorted(Index: integer): integer; procedure ConvertPathToChild(var Path: PGtkTreePath); procedure ConvertChildToPath(var Path: PGtkTreePath); published property Columns: TGTKTreeViewColumns read FColumns write FColumns; property SelectionMode: TGTKSelectionMode read GetSelectionMode write SetSelectionMode; property OnSelectionChanged: TNotifyEvent read FOnSelectionChanged write FOnSelectionChanged; property ShowHeaders: boolean read GetShowHeaders write SetShowHeaders; property RulesHint: boolean read GetRulesHint write SetRulesHint; property Reorderable: boolean read GetReorderable write SetReorderable; property EnableSearch: boolean read GetEnableSearch write SetEnableSearch; property SearchColumn: integer read GetSearchColumn write SetSearchColumn; property SortColumnID: integer read GetSortColumnID write SetSortColumnID; property SortOrder: TGTKTreeViewSortOrder read GetSortOrder write SetSortOrder; property CellDataFunc: TGTKCellDataFunc read FCellDataFunc write FCellDataFunc; property FromSortedCoversionFunc: TGTKSortCoversionFunc read FFromSortedConvFunc write FFromSortedConvFunc; property ToSortedCoversionFunc: TGTKSortCoversionFunc read FToSortedConvFunc write FToSortedConvFunc; end; (****************************************** TGTKLISTVIEW ************************************************************************) TGTKLVItemActivateEvent = procedure (Sender: TObject; Item: TGTKListItem) of object; TGTKTreeViewCompareFunc = function (Sender: TObject; var model: PGtkTreeModel; var a, b: PGtkTreeIter): integer of object; TGTKListView = class(TGTKView) private FOnItemActivate: TGTKLVItemActivateEvent; FSortable: boolean; FCompareFunc: TGTKTreeViewCompareFunc; FOnColumnsChanged: TNotifyEvent; protected FListItems: TGTKListItems; procedure Recreate; function GetSelected: TGTKListItem; procedure SetSelected(Value: TGTKListItem); public constructor Create(AOwner: TComponent); override; constructor CreateTyped(AOwner: TComponent; Sortable: boolean; ColumnTypes: array of TGTKListColumnType); destructor Destroy; override; procedure StartEditing(ColumnNo: integer); function GetItemAtPos(X, Y: integer): TGTKListItem; published property Items: TGTKListItems read FListItems write FListItems; property Selected: TGTKListItem read GetSelected write SetSelected; property OnItemActivate: TGTKLVItemActivateEvent read FOnItemActivate write FOnItemActivate; property CompareFunc: TGTKTreeViewCompareFunc read FCompareFunc write FCompareFunc; property OnColumnsChanged: TNotifyEvent read FOnColumnsChanged write FOnColumnsChanged; end; (********************************************************************************************************************************) (********************************************************************************************************************************) implementation uses SysUtils, DateUtils; (********************************************************************************************************************************) (********************************************************************************************************************************) constructor TGTKView.Create(AOwner: TComponent); begin inherited Create(AOwner); FColumns := TGTKTreeViewColumns.Create(Self); FOnSelectionChanged := nil; FToSortedConvFunc := nil; FFromSortedConvFunc := nil; end; destructor TGTKView.Destroy; begin FColumns.Free; inherited Destroy; end; function TGTKView.GetSelectionMode: TGTKSelectionMode; begin Result := TGTKSelectionMode(gtk_tree_selection_get_mode(FSelection)); end; procedure TGTKView.SetSelectionMode(Value: TGTKSelectionMode); begin gtk_tree_selection_set_mode(FSelection, Integer(Value)); end; procedure TGTKView.SelectAll; begin gtk_tree_selection_select_all(FSelection); end; procedure TGTKView.DeselectAll; begin gtk_tree_selection_unselect_all(FSelection); end; function TGTKView.GetShowHeaders: boolean; begin Result := gtk_tree_view_get_headers_visible(PGtkTreeView(FWidget)); end; procedure TGTKView.SetShowHeaders(Value: boolean); begin gtk_tree_view_set_headers_visible(PGtkTreeView(FWidget), Value); end; function TGTKView.GetRulesHint: boolean; begin Result := gtk_tree_view_get_rules_hint(PGtkTreeView(FWidget)); end; procedure TGTKView.SetRulesHint(Value: boolean); begin gtk_tree_view_set_rules_hint(PGtkTreeView(FWidget), Value); end; function TGTKView.GetReorderable: boolean; begin Result := gtk_tree_view_get_reorderable(PGtkTreeView(FWidget)); end; procedure TGTKView.SetReorderable(Value: boolean); begin gtk_tree_view_set_reorderable(PGtkTreeView(FWidget), Value); end; function TGTKView.GetEnableSearch: boolean; begin Result := gtk_tree_view_get_enable_search(PGtkTreeView(FWidget)); end; procedure TGTKView.SetEnableSearch(Value: boolean); begin gtk_tree_view_set_enable_search(PGtkTreeView(FWidget), Value); end; function TGTKView.GetSearchColumn: integer; begin Result := gtk_tree_view_get_search_column(PGtkTreeView(FWidget)); end; procedure TGTKView.SetSearchColumn(Value: integer); begin gtk_tree_view_set_search_column(PGtkTreeView(FWidget), Value); end; function TGTKView.GetSortColumnID: integer; var sort_column_id: gint; order: TGtkSortType; begin Result := -1; sort_column_id := -1; if (FTreeModelSort <> nil) and gtk_tree_sortable_get_sort_column_id(PGtkTreeSortable(FTreeModelSort), @sort_column_id, @order) then Result := sort_column_id; end; procedure TGTKView.SetSortColumnID(Value: integer); begin if FTreeModelSort <> nil then gtk_tree_sortable_set_sort_column_id(PGtkTreeSortable(FTreeModelSort), Value, TGtkSortType(GetSortOrder)); end; procedure TGTKView.ConvertChildToPath(var Path: PGtkTreePath); var NewPath: PGtkTreePath; begin if Assigned(FTreeModelSort) then if not Assigned(FToSortedConvFunc) then begin NewPath := gtk_tree_model_sort_convert_child_path_to_path(FTreeModelSort, Path); Path := NewPath; end else begin NewPath := gtk_tree_path_new_from_string(PChar(IntToStr(FToSortedConvFunc(Self, StrToIntDef(gtk_tree_path_to_string(Path), 0))))); Path := NewPath; end; end; procedure TGTKView.ConvertPathToChild(var Path: PGtkTreePath); var NewPath: PGtkTreePath; begin if Assigned(FTreeModelSort) then if not Assigned(FFromSortedConvFunc) then begin NewPath := gtk_tree_model_sort_convert_path_to_child_path(FTreeModelSort, Path); Path := NewPath; end else begin NewPath := gtk_tree_path_new_from_string(PChar(IntToStr(FFromSortedConvFunc(Self, StrToIntDef(gtk_tree_path_to_string(Path), 0))))); Path := NewPath; end; end; function TGTKView.GetSortOrder: TGTKTreeViewSortOrder; var sort_column_id: gint; order: TGtkSortType; begin Result := soNone; order := 0; if (FTreeModelSort <> nil) and gtk_tree_sortable_get_sort_column_id(PGtkTreeSortable(FTreeModelSort), @sort_column_id, @order) then Result := TGTKTreeViewSortOrder(order); end; procedure TGTKView.SetSortOrder(Value: TGTKTreeViewSortOrder); begin if FTreeModelSort <> nil then gtk_tree_sortable_set_sort_column_id(PGtkTreeSortable(FTreeModelSort), GetSortColumnID, TGtkSortType(Value)); end; procedure TGTKView.SetSortInfo(ColumnID: integer; Order: TGTKTreeViewSortOrder); begin if FTreeModelSort <> nil then gtk_tree_sortable_set_sort_column_id(PGtkTreeSortable(FTreeModelSort), ColumnID, TGtkSortType(Order)); end; function TGTKView.ConvertToSorted(Index: integer): integer; var Path: PGtkTreePath; Iter: TGtkTreeIter; begin Result := Index; Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(Index))); if not Assigned(Path) then Exit; if Assigned(FTreeModelSort) then Path := gtk_tree_model_sort_convert_child_path_to_path(FTreeModelSort, Path); if not Assigned(Path) then Exit; Result := gtk_tree_path_get_indices(Path)^; gtk_tree_path_free(Path); end; function TGTKView.ConvertFromSorted(Index: integer): integer; var Path: PGtkTreePath; Iter: TGtkTreeIter; begin Result := Index; Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(Index))); if not Assigned(Path) then Exit; if Assigned(FTreeModelSort) then Path := gtk_tree_model_sort_convert_path_to_child_path(FTreeModelSort, Path); if not Assigned(Path) then Exit; Result := gtk_tree_path_get_indices(Path)^; gtk_tree_path_free(Path); end; procedure CellDataFunc(tree_column : PGtkTreeViewColumn; cell : PGtkCellRenderer; tree_model : PGtkTreeModel; iter : PGtkTreeIter; data : gpointer); cdecl; begin if Assigned(TGTKView(data).FCellDataFunc) then TGTKView(data).FCellDataFunc(TGTKView(data), PGtkTreeView(TGTKView(data).FWidget), tree_column, cell, tree_model, iter); end; (********************************************************************************************************************************) (********************************************************************************************************************************) constructor TGTKListView.Create(AOwner: TComponent); begin inherited Create(AOwner); FListItems := TGTKListItems.Create(Self); FSortable := False; FCompareFunc := nil; Recreate; end; destructor TGTKListView.Destroy; begin FListItems.Free; inherited Destroy; end; procedure TGTKListView_changed(treeselection: PGtkTreeSelection; user_data: gpointer); cdecl; begin if Assigned(TGTKListView(user_data).FOnSelectionChanged) then TGTKListView(user_data).FOnSelectionChanged(TGTKListView(user_data)); end; procedure TGTKListView_row_activated(treeview: PGtkTreeView; arg1: PGtkTreePath; arg2: PGtkTreeViewColumn; user_data: gpointer); cdecl; var Item: TGTKListItem; AIndex: integer; begin Item := nil; if Assigned(arg1) then begin TGTKListView(user_data).ConvertPathToChild(arg1); AIndex := gtk_tree_path_get_indices(arg1)^; Item := TGTKListView(user_data).Items[AIndex]; Item.FIndex := AIndex; end; if Assigned(TGTKListView(user_data).FOnItemActivate) then TGTKListView(user_data).FOnItemActivate(TGTKListView(user_data), Item); end; procedure TGTKListView_columns_changed(treeselection: PGtkTreeSelection; user_data: gpointer); cdecl; begin if Assigned(TGTKListView(user_data).FOnColumnsChanged) then TGTKListView(user_data).FOnColumnsChanged(TGTKListView(user_data)); end; procedure TGTKListView.Recreate; begin if Assigned(FWidget) then gtk_widget_destroy(PGtkWidget(FWidget)); FTreeModelSort := nil; if not FSortable then FWidget := gtk_tree_view_new_with_model(PGtkTreeModel(FListItems.FStore)) else begin FTreeModelSort := gtk_tree_model_sort_new_with_model(FListItems.FStore); FWidget := gtk_tree_view_new_with_model(FTreeModelSort); end; FSelection := gtk_tree_view_get_selection(PGtkTreeView(FWidget)); g_signal_connect(FSelection, 'changed', G_CALLBACK(@TGTKListView_changed), Self); g_signal_connect(FWidget, 'row-activated', G_CALLBACK(@TGTKListView_row_activated), Self); g_signal_connect_after(FWidget, 'columns-changed', G_CALLBACK(@TGTKListView_columns_changed), Self); FTreeModel := gtk_tree_view_get_model(PGtkTreeView(FWidget)); Show; end; constructor TGTKListView.CreateTyped(AOwner: TComponent; Sortable: boolean; ColumnTypes: array of TGTKListColumnType); begin inherited Create(AOwner); FListItems := TGTKListItems.CreateTyped(Self, ColumnTypes); FSortable := Sortable; FCompareFunc := nil; Recreate; end; function TGTKListView.GetSelected: TGTKListItem; var Iter: TGtkTreeIter; Path: PGtkTreePath; AIndex: integer; i: integer; begin Result := nil; Path := nil; if not gtk_tree_selection_get_selected(gtk_tree_view_get_selection(PGtkTreeView(FWidget)), nil, @Iter) then Exit; Path := gtk_tree_model_get_path(gtk_tree_view_get_model(PGtkTreeView(FWidget)), @iter); if not Assigned(Path) then Exit; ConvertPathToChild(Path); // WriteLn('Selected Converted: ', String(gtk_tree_path_to_string(Path))); if Assigned(Path) then begin AIndex := gtk_tree_path_get_indices(Path)^; Result := Items[AIndex]; Result.FIndex := AIndex; gtk_tree_path_free(Path); end; end; procedure TGTKListView.SetSelected(Value: TGTKListItem); var Path: PGtkTreePath; begin Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(Value.FIndex))); ConvertChildToPath(Path); gtk_tree_selection_select_path(FSelection, Path); gtk_tree_path_free(Path); end; function GtkTreeIterCompareFunc(model: PGtkTreeModel; a: PGtkTreeIter; b: PGtkTreeIter; user_data: gpointer): gint; cdecl; var Value: TGValue; s: string; begin if not Assigned(TGTKListView(user_data).FCompareFunc) then begin Value.g_type := 0; gtk_tree_model_get_value(model, a, TGTKView(user_data).GetSortColumnID, @Value); s := string(PChar(Value.data[0].v_pointer)); Value.g_type := 0; gtk_tree_model_get_value(model, b, TGTKView(user_data).GetSortColumnID, @Value); Result := AnsiCompareStr(s, PChar(Value.data[0].v_pointer)); end else Result := TGTKListView(user_data).FCompareFunc(TGTKView(user_data), model, a, b); end; procedure TGTKListView.StartEditing(ColumnNo: integer); var Iter: TGtkTreeIter; Path: PGtkTreePath; begin if not gtk_tree_selection_get_selected(FSelection, nil, @Iter) then Exit; Path := gtk_tree_model_get_path(FTreeModel, @iter); if not Assigned(Path) then Exit; gtk_tree_view_set_cursor(PGtkTreeView(FWidget), Path, FColumns[ColumnNo].FColumn, True); end; function TGTKListView.GetItemAtPos(X, Y: integer): TGTKListItem; var Path: PGtkTreePath; Column: PGtkTreeViewColumn; AIndex: integer; begin Result := nil; if gtk_tree_view_get_path_at_pos(PGtkTreeView(FWidget), X, Y, Path, Column, nil, nil) then begin if not Assigned(Path) then Exit; ConvertPathToChild(Path); AIndex := gtk_tree_path_get_indices(Path)^; Result := Items[AIndex]; Result.FIndex := AIndex; gtk_tree_path_free(Path); end; end; (********************************************************************************************************************************) (********************************************************************************************************************************) constructor TGTKListItems.Create(AOwner: TComponent); const Types : GType = G_TYPE_STRING; begin inherited Create(AOwner); FOwner := AOwner; FStore := gtk_list_store_newv(1, @Types); FList := TList.Create; end; destructor TGTKListItems.Destroy; begin if not (csDestroying in ComponentState) then begin Clear; FList.Free; gtk_object_destroy(PGtkObject(FStore)); end; inherited Destroy; end; constructor TGTKListItems.CreateTyped(AOwner: TComponent; ColumnTypes: array of TGTKListColumnType); var i: integer; Cols : array[0..255] of GType; begin inherited Create(AOwner); FOwner := AOwner; FList := TList.Create; for i := Low(ColumnTypes) to High(ColumnTypes) do case ColumnTypes[i] of lcText : Cols[i] := G_TYPE_STRING; lcNumber : Cols[i] := G_TYPE_LONG; lcPointer : Cols[i] := G_TYPE_POINTER; lcPixbuf : Cols[i] := GDK_TYPE_PIXBUF; lcBoolean : Cols[i] := G_TYPE_BOOLEAN; end; FStore := gtk_list_store_newv(Length(ColumnTypes), @Cols); end; procedure TGTKListItems.SetColumnTypes(Types: array of TGTKListColumnType); var i: integer; Cols : array[0..255] of GType; begin for i := Low(Types) to High(Types) do case Types[i] of lcText : Cols[i] := G_TYPE_STRING; lcNumber : Cols[i] := G_TYPE_LONG; lcPointer : Cols[i] := G_TYPE_POINTER; lcPixbuf : Cols[i] := GDK_TYPE_PIXBUF; lcBoolean : Cols[i] := G_TYPE_BOOLEAN; end; g_object_unref(PGObject(FStore)); FStore := gtk_list_store_newv(Length(Types), @Cols); (FOwner as TGTKListView).Recreate; end; function TGTKListItems.GetItem(Index: longint): TGTKListItem; begin Result := TGTKListItem(FList[Index]); Result.FIndex := Index; end; procedure TGTKListItems.SetItem(Index: longint; Value: TGTKListItem); begin FList[Index] := Value; end; function TGTKListItems.Add: TGTKListItem; begin Result := TGTKListItem.Create(Self); Result.FIndex := GetCount; // Insert(GetCount, Result); Append(Result); end; function TGTKListItems.GetCount: longint; begin Result := FList.Count; end; procedure TGTKListItems.Clear; var i: longint; begin for i := Count - 1 downto 0 do Delete(i); // !!!! DON'T use here gtk_list_store_clear(FStore), because it causes memory leaks !!!! end; procedure TGTKListItems.Delete(Index: longint); var x: pointer; Iter: TGtkTreeIter; begin x := FList[Index]; if gtk_tree_model_get_iter_from_string(PGtkTreeModel(FStore), @Iter, StringToPgchar(IntToStr(Index))) then begin // (FOwner as TGTKView).CovertSortableIter(Iter); gtk_list_store_remove(FStore, @Iter); end; FList.Delete(Index); TObject(x).Free; end; procedure TGTKListItems.Insert(Index: longint; Item: TGTKListItem); var Iter: TGtkTreeIter; begin FList.Insert(Index, Item); gtk_list_store_insert(FStore, @Iter, Index); end; procedure TGTKListItems.Append(Item: TGTKListItem); var Iter: TGtkTreeIter; begin FList.Add(Item); gtk_list_store_append(FStore, @Iter); end; (********************************************************************************************************************************) (********************************************************************************************************************************) constructor TGTKTreeViewColumns.Create(AOwner: TComponent); begin inherited Create(AOwner); FOwner := AOwner; FList := TList.Create; end; destructor TGTKTreeViewColumns.Destroy; begin if not (csDestroying in ComponentState) then begin Clear; FList.Free; end; inherited Destroy; end; function TGTKTreeViewColumns.GetItem(Index: Integer): TGTKTreeViewColumn; begin Result := TGTKTreeViewColumn(FList[Index]); Result.FIndex := Index; end; procedure TGTKTreeViewColumns.SetItem(Index: Integer; Value: TGTKTreeViewColumn); begin FList[Index] := Value; end; function TGTKTreeViewColumns.Add: TGTKTreeViewColumn; begin Result := TGTKTreeViewColumn.Create(Self); Result.FIndex := GetCount; Insert(GetCount, Result); end; function TGTKTreeViewColumns.AddTyped(ColType: TGTKTreeViewColumnType): TGTKTreeViewColumn; begin Result := TGTKTreeViewColumn.CreateTyped(Self, ColType); Result.FIndex := GetCount; Insert(GetCount, Result); end; function TGTKTreeViewColumns.GetCount: Integer; begin Result := FList.Count; end; procedure TGTKTreeViewColumns.Clear; var i: Integer; begin for i := Count - 1 downto 0 do Delete(i); end; procedure TGTKTreeViewColumns.Delete(Index: Integer); var x : pointer; begin if not (csDestroying in ComponentState) then gtk_tree_view_remove_column(PGtkTreeView((FOwner as TGTKControl).FWidget), TGTKTreeViewColumn(FList[Index]).FColumn); x := FList[Index]; FList.Delete(Index); TObject(x).Free; end; procedure TGTKTreeViewColumns.Insert(Index: Integer; Item: TGTKTreeViewColumn); begin FList.Insert(Index, Item); Item.FIndex := Index; gtk_tree_view_insert_column(PGtkTreeView((FOwner as TGTKControl).FWidget), Item.FColumn, Index); if Assigned((FOwner as TGTKView).FTreeModelSort) then gtk_tree_sortable_set_sort_func(PGtkTreeSortable((FOwner as TGTKView).FTreeModelSort), Index, TGtkTreeIterCompareFunc(@GtkTreeIterCompareFunc), FOwner, nil); gtk_tree_view_column_set_cell_data_func(Item.FColumn, Item.FRenderer, @CellDataFunc, (FOwner as TGTKView), nil); if Item.ColumnType = ctImageText then gtk_tree_view_column_set_cell_data_func(Item.FColumn, Item.FPixbufRenderer, @CellDataFunc, (FOwner as TGTKView), nil); end; procedure TGTKTreeViewColumns.AutosizeColumns; begin gtk_tree_view_columns_autosize(PGtkTreeView((FOwner as TGTKControl).FWidget)); end; (********************************************************************************************************************************) (********************************************************************************************************************************) constructor TGTKTreeViewColumn.Create(AOwner: TComponent); begin inherited Create(AOwner); FOwner := AOwner; FColumn := gtk_tree_view_column_new; FRenderer := nil; FPixbufRenderer := nil; FOnEdited := nil; FOnToggled := nil; FOnClicked := nil; SetColumnType(ctText); end; constructor TGTKTreeViewColumn.CreateTyped(AOwner: TComponent; ColType: TGTKTreeViewColumnType); begin inherited Create(AOwner); FOwner := AOwner; FColumn := gtk_tree_view_column_new; FRenderer := nil; FPixbufRenderer := nil; FOnEdited := nil; FOnToggled := nil; FOnClicked := nil; SetColumnType(ColType); end; destructor TGTKTreeViewColumn.Destroy; begin if not (csDestroying in ComponentState) then begin gtk_object_destroy(PGtkObject(FRenderer)); if GTK_IS_OBJECT(FColumn) then gtk_object_destroy(PGtkObject(FColumn)); end; inherited Destroy; end; function TGTKTreeViewColumn.GetCaption: string; begin Result := PgcharToString(gtk_tree_view_column_get_title(FColumn)); end; procedure TGTKTreeViewColumn.SetCaption(Value: string); begin gtk_tree_view_column_set_title(FColumn, StringToPgchar(Value)); end; function TGTKTreeViewColumn.GetVisible: boolean; begin Result := gtk_tree_view_column_get_visible(FColumn); end; procedure TGTKTreeViewColumn.SetVisible(Value: boolean); begin gtk_tree_view_column_set_visible(FColumn, Value); end; function TGTKTreeViewColumn.GetResizable: boolean; begin Result := gtk_tree_view_column_get_resizable(FColumn); end; procedure TGTKTreeViewColumn.SetResizable(Value: boolean); begin gtk_tree_view_column_set_resizable(FColumn, Value); end; function TGTKTreeViewColumn.GetSizingMode: TGTKTreeViewColumnSizingMode; begin Result := TGTKTreeViewColumnSizingMode(gtk_tree_view_column_get_sizing(FColumn)); end; procedure TGTKTreeViewColumn.SetSizingMode(Value: TGTKTreeViewColumnSizingMode); begin gtk_tree_view_column_set_sizing(FColumn, TGtkTreeViewColumnSizing(Value)); end; function TGTKTreeViewColumn.GetWidth: integer; begin Result := gtk_tree_view_column_get_width(FColumn); end; function TGTKTreeViewColumn.GetFixedWidth: integer; begin Result := gtk_tree_view_column_get_fixed_width(FColumn); end; procedure TGTKTreeViewColumn.SetFixedWidth(Value: integer); begin gtk_tree_view_column_set_fixed_width(FColumn, Value); end; function TGTKTreeViewColumn.GetMinWidth: integer; begin Result := gtk_tree_view_column_get_min_width(FColumn); end; procedure TGTKTreeViewColumn.SetMinWidth(Value: integer); begin gtk_tree_view_column_set_min_width(FColumn, Value); end; function TGTKTreeViewColumn.GetMaxWidth: integer; begin Result := gtk_tree_view_column_get_max_width(FColumn); end; procedure TGTKTreeViewColumn.SetMaxWidth(Value: integer); begin gtk_tree_view_column_set_max_width(FColumn, Value); end; function TGTKTreeViewColumn.GetClickable: boolean; begin Result := gtk_tree_view_column_get_clickable(FColumn); end; procedure TGTKTreeViewColumn.SetClickable(Value: boolean); begin gtk_tree_view_column_set_clickable(FColumn, Value); end; function TGTKTreeViewColumn.GetAlignment: Double; begin Result := gtk_tree_view_column_get_alignment(FColumn); end; procedure TGTKTreeViewColumn.SetAlignment(Value: Double); begin gtk_tree_view_column_set_alignment(FColumn, Value); end; function TGTKTreeViewColumn.GetReorderable: boolean; begin Result := gtk_tree_view_column_get_reorderable(FColumn); end; procedure TGTKTreeViewColumn.SetReorderable(Value: boolean); begin gtk_tree_view_column_set_reorderable(FColumn, Value); end; function TGTKTreeViewColumn.GetSortID: integer; begin Result := gtk_tree_view_column_get_sort_column_id(FColumn); end; procedure TGTKTreeViewColumn.SetSortID(Value: integer); begin gtk_tree_view_column_set_sort_column_id(FColumn, Value); end; function TGTKTreeViewColumn.GetShowSortIndicator: boolean; begin Result := gtk_tree_view_column_get_sort_indicator(FColumn); end; procedure TGTKTreeViewColumn.SetShowSortIndicator(Value: boolean); begin gtk_tree_view_column_set_sort_indicator(FColumn, Value); end; function TGTKTreeViewColumn.GetSortOrder: TGTKTreeViewSortOrder; begin Result := TGTKTreeViewSortOrder(gtk_tree_view_column_get_sort_order(FColumn)); end; procedure TGTKTreeViewColumn.SetSortOrder(Value: TGTKTreeViewSortOrder); begin gtk_tree_view_column_set_sort_order(FColumn, TGtkSortType(Value)); end; procedure TGTKTreeViewColumn_edited(cell: PGtkCellRendererText; const path_string, new_text: pgchar; data: gpointer); cdecl; var NewText: string; AllowChange: boolean; DataColumn, AIndex: integer; Path: PGtkTreePath; begin if Assigned(TGTKTreeViewColumn(data).FOnEdited) then begin NewText := PgcharToString(new_text); AllowChange := True; DataColumn := TGTKTreeViewColumn(data).FIndex; Path := gtk_tree_path_new_from_string(path_string); if not Assigned(Path) then Exit; AIndex := gtk_tree_path_get_indices(Path)^; TGTKTreeViewColumn(data).FOnEdited(TGTKTreeViewColumn(data), TGTKTreeViewColumn(data), ((TGTKTreeViewColumn(data).FOwner as TGTKTreeViewColumns).FOwner as TGTKListView).Items[AIndex], NewText, AllowChange, DataColumn); if AllowChange and (((TGTKTreeViewColumn(data).FOwner as TGTKTreeViewColumns).FOwner as TGTKListView).Items.Count < AIndex) then ((TGTKTreeViewColumn(data).FOwner as TGTKTreeViewColumns).FOwner as TGTKListView).Items[AIndex].SetValue(DataColumn, NewText); gtk_tree_path_free(Path); end; end; procedure TGTKTreeViewColumn_toggled(cell: PGtkCellRendererToggle; const path_string: pgchar; data: gpointer); cdecl; var Path: PGtkTreePath; AIndex: integer; begin if Assigned(data) and Assigned(TGTKTreeViewColumn(data).FOnToggled) then begin Path := gtk_tree_path_new_from_string(path_string); if not Assigned(Path) then Exit; AIndex := gtk_tree_path_get_indices(Path)^; TGTKTreeViewColumn(data).FOnToggled(TGTKTreeViewColumn(data), TGTKTreeViewColumn(data), ((TGTKTreeViewColumn(data).FOwner as TGTKTreeViewColumns).FOwner as TGTKListView).Items[AIndex]); end; end; procedure TGTKTreeViewColumn_clicked(treeviewcolumn: PGtkTreeViewColumn; user_data: gpointer); cdecl; begin if Assigned(user_data) and Assigned(TGTKTreeViewColumn(user_data).FOnClicked) then TGTKTreeViewColumn(user_data).FOnClicked(TGTKTreeViewColumn(user_data)); end; procedure TGTKTreeViewColumn.SetColumnType(Value: TGTKTreeViewColumnType); begin FColumnType := Value; if Assigned(FRenderer) then begin gtk_tree_view_column_clear(FColumn); gtk_object_destroy(PGtkObject(FRenderer)); end; case Value of ctText : FRenderer := gtk_cell_renderer_text_new; ctToggle : FRenderer := gtk_cell_renderer_toggle_new; ctImageText : begin FRenderer := gtk_cell_renderer_text_new; FPixbufRenderer := gtk_cell_renderer_pixbuf_new; end; end; if Value = ctImageText then gtk_tree_view_column_pack_start(FColumn, FPixbufRenderer, False); gtk_tree_view_column_pack_start(FColumn, FRenderer, True); if (Value = ctImageText) or (Value = ctText) then g_signal_connect(FRenderer, 'edited', G_CALLBACK(@TGTKTreeViewColumn_edited), Self); if Value = ctToggle then g_signal_connect(FRenderer, 'toggled', G_CALLBACK(@TGTKTreeViewColumn_toggled), Self); g_signal_connect_after(FColumn, 'clicked', G_CALLBACK(@TGTKTreeViewColumn_clicked), Self); end; procedure TGTKTreeViewColumn.AddAttribute(Attribute: string; Value: integer); begin gtk_tree_view_column_add_attribute(FColumn, FRenderer, StringToPgchar(Attribute), Value); end; procedure TGTKTreeViewColumn.AddImageAttribute(Attribute: string; Value: integer); begin gtk_tree_view_column_add_attribute(FColumn, FPixbufRenderer, StringToPgchar(Attribute), Value); end; procedure TGTKTreeViewColumn.ClearAttributes; begin gtk_tree_view_column_clear_attributes(FColumn, FRenderer); end; procedure TGTKTreeViewColumn.SetProperty(AProperty: string; Value: integer); var AValue: TGValue; begin AValue.g_type := G_TYPE_LONG; AValue.data[0].v_long := Value; g_object_set_property(PGObject(FRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetProperty(AProperty: string; Value: string); var AValue: TGValue; begin AValue.g_type := G_TYPE_STRING; AValue.data[0].v_pointer := StringToPgchar(Value); g_object_set_property(PGObject(FRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetProperty(AProperty: string; Value: Double); var AValue: TGValue; begin AValue.g_type := G_TYPE_DOUBLE; AValue.data[0].v_double := Value; g_object_set_property(PGObject(FRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetProperty(AProperty: string; Value: pointer); var AValue: TGValue; begin AValue.g_type := G_TYPE_POINTER; AValue.data[0].v_pointer := Value; g_object_set_property(PGObject(FRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetImageProperty(AProperty: string; Value: integer); var AValue: TGValue; begin AValue.g_type := G_TYPE_LONG; AValue.data[0].v_long := Value; g_object_set_property(PGObject(FPixbufRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetImageProperty(AProperty: string; Value: string); var AValue: TGValue; begin AValue.g_type := G_TYPE_STRING; AValue.data[0].v_pointer := StringToPgchar(Value); g_object_set_property(PGObject(FPixbufRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetImageProperty(AProperty: string; Value: Double); var AValue: TGValue; begin AValue.g_type := G_TYPE_DOUBLE; AValue.data[0].v_double := Value; g_object_set_property(PGObject(FPixbufRenderer), StringToPgchar(AProperty), @AValue); end; procedure TGTKTreeViewColumn.SetImageProperty(AProperty: string; Value: pointer); var AValue: TGValue; begin AValue.g_type := G_TYPE_POINTER; AValue.data[0].v_pointer := Value; g_object_set_property(PGObject(FPixbufRenderer), StringToPgchar(AProperty), @AValue); end; (********************************************************************************************************************************) (********************************************************************************************************************************) constructor TGTKListItem.Create(AOwner: TComponent); begin inherited Create(AOwner); FOwner := AOwner; FData := nil; end; destructor TGTKListItem.Destroy; begin inherited Destroy; end; function TGTKListItem.AsString(Index: longint): string; var Iter: TGtkTreeIter; AValue: TGValue; begin Result := ''; if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then begin AValue.g_type := 0; gtk_tree_model_get_value(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, @AValue); Result := PgcharToString(AValue.data[0].v_pointer); end; end; function TGTKListItem.AsInteger(Index: longint): integer; var Iter: TGtkTreeIter; AValue: TGValue; begin Result := 0; if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then begin AValue.g_type := 0; gtk_tree_model_get_value(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, @AValue); Result := AValue.data[0].v_long; end; end; function TGTKListItem.AsPointer(Index: longint): pointer; var Iter: TGtkTreeIter; AValue: TGValue; begin Result := nil; if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then begin AValue.g_type := 0; gtk_tree_model_get_value(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, @AValue); Result := AValue.data[0].v_pointer; end; end; function TGTKListItem.AsBoolean(Index: longint): boolean; var Iter: TGtkTreeIter; AValue: TGValue; begin Result := False; if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then begin AValue.g_type := 0; gtk_tree_model_get_value(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, @AValue); Result := boolean(AValue.data[0].v_int); end; end; procedure TGTKListItem.SetValue(Index: longint; Value: string); var Iter: TGtkTreeIter; begin if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then gtk_list_store_set(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, StringToPgchar(Value), -1); end; procedure TGTKListItem.SetValue(Index: longint; Value: integer); var Iter: TGtkTreeIter; begin if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then gtk_list_store_set(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, Value, -1); end; procedure TGTKListItem.SetValue(Index: longint; Value: pointer); var Iter: TGtkTreeIter; begin if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then gtk_list_store_set(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, Value, -1); end; procedure TGTKListItem.SetValue(Index: longint; Value: boolean); var Iter: TGtkTreeIter; begin if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then gtk_list_store_set(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, Index, Value, -1); end; function TGTKListItem.GetSelected: boolean; var Iter: TGtkTreeIter; begin Result := False; if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then begin // ((FOwner as TGTKListItems).FOwner as TGTKView).ConvertSortableIter(Iter); Result := gtk_tree_selection_iter_is_selected(((FOwner as TGTKListItems).FOwner as TGTKView).FSelection, @Iter); end; end; procedure TGTKListItem.SetSelected(Value: boolean); var Iter, NewIter: TGtkTreeIter; Path: PGtkTreePath; begin try if gtk_tree_model_get_iter_from_string(PGtkTreeModel((FOwner as TGTKListItems).FStore), @Iter, StringToPgchar(IntToStr(FIndex))) then begin if Assigned(((FOwner as TGTKListItems).FOwner as TGTKView).FTreeModelSort) then begin gtk_tree_model_sort_convert_child_iter_to_iter(((FOwner as TGTKListItems).FOwner as TGTKView).FTreeModelSort, @NewIter, @Iter); Iter := NewIter; end; if Value then gtk_tree_selection_select_iter(((FOwner as TGTKListItems).FOwner as TGTKView).FSelection, @Iter) else gtk_tree_selection_unselect_iter(((FOwner as TGTKListItems).FOwner as TGTKView).FSelection, @Iter); end; except end; end; procedure TGTKListItem.SetCursor(const FocusColumnNo: integer; const StartEditing, UseAlignment: boolean; const AlignX, AlignY: Double); var Path: PGtkTreePath; Column: PGtkTreeViewColumn; // Renderer: PGtkCellRenderer; i : integer; begin Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(FIndex))); if not Assigned(Path) then Exit; ((FOwner as TGTKListItems).FOwner as TGTKView).ConvertChildToPath(Path); if not Assigned(Path) then Exit; Column := ((FOwner as TGTKListItems).FOwner as TGTKView).Columns[FocusColumnNo].FColumn; // Renderer := ((FOwner as TGTKListItems).FOwner as TGTKView).Columns[FocusColumnNo].FRenderer; for i := 1 to 2 do gtk_main_iteration_do(False); // This ugly piece of code HAVE TO BE HERE due some focus-related problems in GtkTreeView gtk_tree_view_set_cursor(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, Column, StartEditing); // gtk_tree_view_set_cursor(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, Column, StartEditing); // gtk_tree_view_set_cursor_on_cell(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, Column, Renderer, StartEditing); gtk_tree_view_scroll_to_cell(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, nil, UseAlignment, AlignX, AlignY); gtk_tree_path_free(Path); end; procedure TGTKListItem.StartEditing(ColumnNo: integer); var CellEditable: PGtkCellEditable; Path: PGtkTreePath; Column: PGtkTreeViewColumn; BackgroundRect, CellRect: TGdkRectangle; begin Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(FIndex))); if not Assigned(Path) then Exit; ((FOwner as TGTKListItems).FOwner as TGTKView).ConvertChildToPath(Path); if not Assigned(Path) then Exit; Column := ((FOwner as TGTKListItems).FOwner as TGTKView).Columns[ColumnNo].FColumn; gtk_tree_view_get_background_area(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, Column, @BackgroundRect); gtk_tree_view_get_cell_area(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, Column, @CellRect); gtk_tree_view_column_focus_cell(Column, ((FOwner as TGTKListItems).FOwner as TGTKView).Columns[ColumnNo].FRenderer); CellEditable := gtk_cell_renderer_start_editing(((FOwner as TGTKListItems).FOwner as TGTKView).Columns[ColumnNo].FRenderer, nil, ((FOwner as TGTKListItems).FOwner as TGTKView).FWidget, PChar(StringToPgchar(IntToStr(FIndex))), @BackgroundRect, @CellRect, {GTK_CELL_RENDERER_SELECTED or GTK_CELL_RENDERER_SORTED} 0); gtk_widget_show(CellEditable); // gtk_cell_editable_start_editing(CellEditable, nil); gtk_tree_path_free(Path); end; procedure TGTKListItem.RedrawRow; var Rect, BackgroundRect: TGdkRectangle; Path: PGtkTreePath; Column: PGtkTreeViewColumn; begin Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(FIndex))); if not Assigned(Path) then Exit; ((FOwner as TGTKListItems).FOwner as TGTKView).ConvertChildToPath(Path); if not Assigned(Path) then Exit; Column := ((FOwner as TGTKListItems).FOwner as TGTKView).Columns[0].FColumn; gtk_tree_view_get_background_area(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, Column, @BackgroundRect); Rect.x := 0; Rect.width := ((FOwner as TGTKListItems).FOwner as TGTKView).FWidget^.allocation.width; Rect.y := BackgroundRect.y; Rect.height := BackgroundRect.height; gdk_window_invalidate_rect(gtk_tree_view_get_bin_window(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget)), @Rect, True); gtk_tree_path_free(Path); end; function TGTKListItem.IsVisible: boolean; var CellRect, VisibleRect: TGdkRectangle; Path: PGtkTreePath; begin Result := False; gtk_tree_view_get_visible_rect(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), @VisibleRect); if not Assigned(Path) then Exit; Path := gtk_tree_path_new_from_string(StringToPgchar(IntToStr(FIndex))); ((FOwner as TGTKListItems).FOwner as TGTKView).ConvertChildToPath(Path); if not Assigned(Path) then Exit; gtk_tree_view_get_background_area(PGtkTreeView(((FOwner as TGTKListItems).FOwner as TGTKView).FWidget), Path, nil, @CellRect); gtk_tree_path_free(Path); Result := (CellRect.y > VisibleRect.y) and (CellRect.y + CellRect.height < VisibleRect.y + VisibleRect.height); end; (********************************************************************************************************************************) (********************************************************************************************************************************) end.