{ $Id$} { ***************************************************************************** * Gtk2WSStdCtrls.pp * * ----------------- * * * * * ***************************************************************************** ***************************************************************************** * * * This file is part of the Lazarus Component Library (LCL) * * * * See the file COPYING.modifiedLGPL.txt, included in this distribution, * * for details about the copyright. * * * * This program 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. * * * ***************************************************************************** } unit Gtk2WSStdCtrls; {$mode objfpc}{$H+} {$PACKRECORDS c} interface uses // Bindings glib2, gdk2, gtk2, Pango, // RTL, FCL, LCL Classes, SysUtils, Math, Controls, Graphics, StdCtrls, LMessages, LCLType, LCLProc, // Widgetset WSControls, WSProc, WSStdCtrls, WSLCLClasses, GtkWSStdCtrls, Gtk2Int, GtkDef, Gtk2CellRenderer, GTKWinApiWindow, GtkGlobals, GtkProc, InterfaceBase, GtkWSPrivate, Gtk2WSPrivate, GtkExtra; type { !!! Both are used: TGtkComboBoxEntry (with entry) and TGtkComboBox (without entry), but not the old TGtkCombo !!! } PGtkComboBoxPrivate = ^TGtkComboBoxPrivate; TGtkComboBoxPrivate = record model: PGtkTreeModel; col_column, row_column: gint; wrap_width: gint; active_row: PGtkTreeRowReference; tree_view: PGtkWidget; column: PGtkTreeViewColumn; cell_view: PGtkWidget; cell_view_frame: PGtkWidget; button: PGtkwidget; box: PGtkWidget; arrow: PGtkWidget; serarator: PGtkWidget; popup_widget: PGtkWidget; popup_window: PGtkWidget; popup_frame: PGtkWidget; scrolled_window: PGtkwidget; end; { TGtk2WSScrollBar } TGtk2WSScrollBar = class(TWSScrollBar) private protected class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; public class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class procedure SetParams(const AScrollBar: TCustomScrollBar); override; end; { TGtk2WSCustomGroupBox } TGtk2WSCustomGroupBox = class(TGtkWSCustomGroupBox) private protected public class function GetDefaultClientRect(const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer; var aClientRect: TRect ): boolean; override; class procedure SetFont(const AWinControl: TWinControl; const AFont : tFont); override; end; { TGtk2WSGroupBox } TGtk2WSGroupBox = class(TGtkWSGroupBox) private protected public end; { TGtk2WSCustomComboBox } { !!! Both are used: TGtkComboBoxEntry (with entry) and TGtkComboBox (without entry), but not the old TGtkCombo !!! } TGtk2WSCustomComboBox = class(TGtkWSCustomComboBox) private protected class procedure ReCreateCombo(const ACustomComboBox: TCustomComboBox; const AWithEntry: Boolean; const AWidgetInfo: PWidgetInfo); virtual; class procedure SetRenderer(const ACustomComboBox: TCustomComboBox; AWidget: PGtkWidget; AWidgetInfo: PWidgetInfo); virtual; class procedure SetCallbacks(const AWinControl: tWinControl; const AWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; public class procedure GetPreferredSize(const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; class function GetSelStart(const ACustomComboBox: TCustomComboBox): integer; override; class function GetSelLength(const ACustomComboBox: TCustomComboBox): integer; override; class function GetItemIndex(const ACustomComboBox: TCustomComboBox): integer; override; class function GetMaxLength(const ACustomComboBox: TCustomComboBox): integer; override; class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override; class procedure SetArrowKeysTraverseList(const ACustomComboBox: TCustomComboBox; NewTraverseList: boolean); override; class procedure SetSelStart(const ACustomComboBox: TCustomComboBox; NewStart: integer); override; class procedure SetSelLength(const ACustomComboBox: TCustomComboBox; NewLength: integer); override; class procedure SetItemIndex(const ACustomComboBox: TCustomComboBox; NewIndex: integer); override; class procedure SetMaxLength(const ACustomComboBox: TCustomComboBox; NewLength: integer); override; class procedure SetStyle(const ACustomComboBox: TCustomComboBox; NewStyle: TComboBoxStyle); override; class procedure SetReadOnly(const ACustomComboBox: TCustomComboBox; NewReadOnly: boolean); override; class function GetItems(const ACustomComboBox: TCustomComboBox): TStrings; override; class procedure Sort(const ACustomComboBox: TCustomComboBox; AList: TStrings; IsSorted: boolean); override; class procedure SetColor(const AWinControl: TWinControl); override; class procedure SetFont(const AWinControl: TWinControl; const AFont : tFont); override; class procedure SetText(const AWinControl: TWinControl; const AText: String); override; class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class procedure DestroyHandle(const AWinControl: TWinControl); override; end; { TGtk2WSComboBox } TGtk2WSComboBox = class(TGtkWSComboBox) private protected public end; { TGtk2WSCustomListBox } TGtk2WSCustomListBox = class(TGtkWSCustomListBox) private protected class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; public class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class function GetIndexAtY(const ACustomListBox: TCustomListBox; y: integer): integer; override; class function GetItemIndex(const ACustomListBox: TCustomListBox): integer; override; class function GetItemRect(const ACustomListBox: TCustomListBox; Index: integer; var ARect: TRect): boolean; override; class function GetSelCount(const ACustomListBox: TCustomListBox): integer; override; class function GetSelected(const ACustomListBox: TCustomListBox; const AIndex: integer): boolean; override; class function GetStrings(const ACustomListBox: TCustomListBox): TStrings; override; class function GetTopIndex(const ACustomListBox: TCustomListBox): integer; override; class procedure SelectItem(const ACustomListBox: TCustomListBox; AnIndex: integer; ASelected: boolean); override; class procedure SetBorder(const ACustomListBox: TCustomListBox); override; class procedure SetItemIndex(const ACustomListBox: TCustomListBox; const AIndex: integer); override; class procedure SetSelectionMode(const ACustomListBox: TCustomListBox; const AExtendedSelect, AMultiSelect: boolean); override; class procedure SetSorted(const ACustomListBox: TCustomListBox; AList: TStrings; ASorted: boolean); override; class procedure SetTopIndex(const ACustomListBox: TCustomListBox; const NewTopIndex: integer); override; class procedure SetFont(const AWinControl: TWinControl; const AFont : TFont); override; end; { TGtk2WSListBox } TGtk2WSListBox = class(TGtkWSListBox) private protected public end; { TGtk2WSCustomEdit } TGtk2WSCustomEdit = class(TGtkWSCustomEdit) private protected public class function GetSelStart(const ACustomEdit: TCustomEdit): integer; override; class function GetSelLength(const ACustomEdit: TCustomEdit): integer; override; class procedure SetEchoMode(const ACustomEdit: TCustomEdit; NewMode: TEchoMode); override; class procedure SetPasswordChar(const ACustomEdit: TCustomEdit; NewChar: char); override; class procedure SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); override; class procedure SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; end; { TGtk2WSCustomMemo } TGtk2WSCustomMemo = class(TWSCustomMemo) private protected class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; public class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class function GetSelStart(const ACustomEdit: TCustomEdit): integer; override; class function GetSelLength(const ACustomEdit: TCustomEdit): integer; override; class function GetStrings(const ACustomMemo: TCustomMemo): TStrings; override; class procedure SetAlignment(const ACustomMemo: TCustomMemo; const AAlignment: TAlignment); override; class procedure SetColor(const AWinControl: TWinControl); override; class procedure SetFont(const AWinControl: TWinControl;const AFont : TFont); override; class procedure SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); override; class procedure SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; class procedure SetWantTabs(const ACustomMemo: TCustomMemo; const NewWantTabs: boolean); override; class procedure SetEchoMode(const ACustomEdit: TCustomEdit; NewMode: TEchoMode); override; class procedure SetPasswordChar(const ACustomEdit: TCustomEdit; NewChar: char); override; class procedure SetCharCase(const ACustomEdit: TCustomEdit; NewCase: TEditCharCase); override; class procedure SetMaxLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; class procedure SetReadOnly(const ACustomEdit: TCustomEdit; NewReadOnly: boolean); override; class procedure GetPreferredSize(const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; class function GetCaretPos(const ACustomEdit: TCustomEdit): TPoint; override; class procedure SetCaretPos(const ACustomEdit: TCustomEdit; const NewPos: TPoint); override; end; { TGtk2WSEdit } TGtk2WSEdit = class(TGtkWSEdit) private protected public end; { TGtk2WSMemo } TGtk2WSMemo = class(TGtkWSMemo) private protected public end; { TGtk2WSCustomLabel } { TGtk2WSCustomLabel = class(TGtkWSCustomLabel) private protected public end; } { TGtk2WSLabel } { TGtk2WSLabel = class(TGtkWSLabel) private protected public end; } { TGtk2WSButtonControl } TGtk2WSButtonControl = class(TGtkWSButtonControl) private protected public end; { TGtk2WSButton } TGtk2WSButton = class(TGtkWSButton) private protected class function GetButtonWidget(AEventBox: PGtkEventBox): PGtkButton; class function GetLabelWidget(AEventBox: PGtkEventBox): PGtkLabel; class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); override; public class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class procedure GetPreferredSize(const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override; class procedure SetColor(const AWinControl: TWinControl); override; class procedure SetFont(const AWinControl: TWinControl; const AFont : TFont); override; class procedure SetDefault(const AButton: TCustomButton; ADefault: Boolean); override; class procedure SetShortcut(const AButton: TCustomButton; const OldShortcut, NewShortcut: TShortcut); override; class procedure SetText(const AWinControl: TWinControl; const AText: String); override; end; { TGtk2WSCustomCheckBox } TGtk2WSCustomCheckBox = class(TGtkWSCustomCheckBox) private protected public class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class procedure GetPreferredSize(const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; class function RetrieveState(const ACustomCheckBox: TCustomCheckBox ): TCheckBoxState; override; class procedure SetShortCut(const ACustomCheckBox: TCustomCheckBox; const OldShortCut, NewShortCut: TShortCut); override; class procedure SetState(const ACustomCheckBox: TCustomCheckBox; const NewState: TCheckBoxState); override; class procedure SetFont(const AWinControl: TWinControl; const AFont : tFont); override; end; { TGtk2WSCheckBox } TGtk2WSCheckBox = class(TGtkWSCheckBox) private protected public end; { TGtk2WSToggleBox } TGtk2WSToggleBox = class(TGtkWSToggleBox) private protected public end; { TGtk2WSRadioButton } TGtk2WSRadioButton = class(TGtkWSRadioButton) private protected public end; { TGtk2WSCustomStaticText } TGtk2WSCustomStaticText = class(TGtkWSCustomStaticText) private protected public end; { TGtk2WSStaticText } TGtk2WSStaticText = class(TGtkWSStaticText) private protected public end; {$DEFINE MEMOHEADER} {$I gtk2memostrings.inc} {$UNDEF MEMOHEADER} function GetComboBoxEntry(Widget: PGtkWidget): PGtkEntry; implementation uses GtkWSControls, Gtk2WSControls, LCLMessageGlue, Forms; function GetComboBoxEntry(Widget: PGtkWidget): PGtkEntry; begin if GtkWidgetIsA(Widget, GTK_TYPE_COMBO_BOX_ENTRY) then Result := PGtkEntry(GTK_BIN(Widget)^.child) else Result := nil; end; {$I gtk2memostrings.inc} { TGtk2WSCustomListBox } procedure StoreFirstSelectedPath(model:PGtkTreeModel; path:PGtkTreePath; iter:PGtkTreeIter; data:gpointer); cdecl; begin //DebugLn(['StoreFirstSelectedPath ',PInteger(Data)^,' ',gtk_tree_path_get_indices(Path)^]); if PInteger(Data)^ < 0 then PInteger(Data)^ := gtk_tree_path_get_indices(Path)^; end; class function TGtk2WSCustomListBox.GetItemIndex( const ACustomListBox: TCustomListBox): integer; var Widget: PGtkWidget; Path: PGtkTreePath; Column: PGtkTreeViewColumn; begin Result := -1; if not WSCheckHandleAllocated(ACustomListBox, 'GetItemIndex') then Exit; Widget := GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget; if GtkWidgetIsA(Widget, gtk_tree_view_get_type) then begin gtk_tree_view_get_cursor(PGtkTreeView(Widget), Path, column); if Path <> nil then Result := gtk_tree_path_get_indices(Path)^ else Result := -1; end; end; class function TGtk2WSCustomListBox.GetItemRect( const ACustomListBox: TCustomListBox; Index: integer; var ARect: TRect ): boolean; begin Result := False; FillChar(ARect, SizeOf(ARect), 0); case ACustomListBox.fCompStyle of csListBox, csCheckListBox: begin // ToDo end; end; end; class function TGtk2WSCustomListBox.GetTopIndex( const ACustomListBox: TCustomListBox): integer; begin Result := GetIndexAtY(ACustomListBox, 0); end; class procedure TGtk2WSCustomListBox.SelectItem( const ACustomListBox: TCustomListBox; AnIndex: integer; ASelected: boolean); var Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) Selection: PGtkTreeSelection; ListStoreModel: PGtkTreeModel; Iter : TGtkTreeIter; begin if not WSCheckHandleAllocated(ACustomListBox, 'SelectItem') then Exit; Widget:=GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget; ListStoreModel := gtk_tree_view_get_model(PGtkTreeView(Widget)); Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); if gtk_tree_model_iter_nth_child(ListStoreModel, @Iter, nil, AnIndex) then begin case ASelected of True: if not gtk_tree_selection_iter_is_selected(Selection, @Iter) then gtk_tree_selection_select_iter(Selection, @Iter); False: if gtk_tree_selection_iter_is_selected(Selection, @Iter) then gtk_tree_selection_unselect_iter(Selection, @Iter); end; end; end; class procedure TGtk2WSCustomListBox.SetBorder( const ACustomListBox: TCustomListBox); begin gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(ACustomListBox.Handle), BorderStyleShadowMap[ACustomListBox.BorderStyle]); end; class procedure TGtk2WSCustomListBox.SetItemIndex( const ACustomListBox: TCustomListBox; const AIndex: integer); var Widget: PGtkWidget; WidgetInfo: PWidgetInfo; Selection: PGtkTreeSelection; Path: PGtkTreePath; procedure ClearCursor; inline; begin if gtk_tree_row_reference_valid(PGtkTreeView(Widget)^.priv^.cursor) then begin gtk_tree_row_reference_free(PGtkTreeView(Widget)^.priv^.cursor); PGtkTreeView(Widget)^.priv^.cursor := nil; end; end; begin if not WSCheckHandleAllocated(ACustomListBox, 'SetItemIndex') then Exit; WidgetInfo := GetWidgetInfo(Pointer(ACustomListBox.Handle), True); Widget := WidgetInfo^.CoreWidget; if not GtkWidgetIsA(Widget, gtk_tree_view_get_type) then raise Exception.Create(''); Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); Inc(WidgetInfo^.ChangeLock); if (AIndex < 0) then if (gtk_tree_selection_get_mode(Selection) <> GTK_SELECTION_SINGLE) then Path := gtk_tree_path_new_first else Path := nil else Path := gtk_tree_path_new_from_indices(AIndex, -1); // if singleselection mode then selection = itemindex if Path <> nil then gtk_tree_view_set_cursor(PGtkTreeView(Widget), Path, nil, False) else if gtk_tree_selection_get_mode(Selection) = GTK_SELECTION_SINGLE then begin ClearCursor; gtk_tree_selection_unselect_all(Selection); end; if Path <> nil then gtk_tree_path_free(Path); Dec(WidgetInfo^.ChangeLock); end; class procedure TGtk2WSCustomListBox.SetSelectionMode( const ACustomListBox: TCustomListBox; const AExtendedSelect, AMultiSelect: boolean); var Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) Selection: PGtkTreeSelection; begin if not WSCheckHandleAllocated(ACustomListBox, 'SetSelectionMode') then Exit; Widget := GetWidgetInfo(Pointer(ACustomListBox.Handle),True)^.CoreWidget; Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); case AMultiSelect of True : gtk_tree_selection_set_mode(Selection, GTK_SELECTION_MULTIPLE); False: gtk_tree_selection_set_mode(Selection, GTK_SELECTION_SINGLE); //GTK_SELECTION_NONE, //GTK_SELECTION_SINGLE, //GTK_SELECTION_BROWSE, //GTK_SELECTION_MULTIPLE end; end; class procedure TGtk2WSCustomListBox.SetSorted(const ACustomListBox: TCustomListBox; AList: TStrings; ASorted: boolean); begin if AList is TGtkListStoreStringList then TGtkListStoreStringList(AList).Sorted := ASorted //else if AList is TGtkCListStringList then // TGtkCListStringList(AList).Sorted := ASorted else raise Exception.Create(''); end; class procedure TGtk2WSCustomListBox.SetTopIndex( const ACustomListBox: TCustomListBox; const NewTopIndex: integer); var Widget: PGtkWidget; ListStoreModel: PGtkTreeModel; Iter: TGtkTreeIter; TreeView: PGtkTreeView; APath: Pointer; begin if not WSCheckHandleAllocated(ACustomListBox, 'SetTopIndex') then Exit; Widget := GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget; TreeView := PGtkTreeView(Widget); ListStoreModel := gtk_tree_view_get_model(TreeView); if not gtk_tree_model_iter_nth_child(ListStoreModel, @Iter, nil, NewTopIndex) then exit; APath := gtk_tree_model_get_path(ListStoreModel, @Iter); gtk_tree_view_scroll_to_cell(TreeView, APath, NULL, true, 0.0, 0.0); gtk_tree_path_free(APath); end; class procedure TGtk2WSCustomListBox.SetFont(const AWinControl: TWinControl; const AFont: TFont); var Widget: PGtkWidget; begin if not WSCheckHandleAllocated(AWinControl, 'SetFont') then Exit; Widget := GetWidgetInfo(Pointer(AWinControl.Handle), True)^.CoreWidget; Gtk2WidgetSet.SetWidgetColor(Widget, AWinControl.Font.Color, clNone, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED, GTK_STYLE_TEXT]); Gtk2WidgetSet.SetWidgetFont(Widget, AFont); end; function gtk2ListBoxSelectionChangedAfter(Widget: PGtkWidget; WidgetInfo: PWidgetInfo): gboolean; cdecl; var Mess: TLMessage; begin Result := CallBackDefaultReturn; if WidgetInfo^.ChangeLock > 0 then Exit; {$IFDEF EventTrace} EventTrace('gtk2ListSelectionChangedAfter', WidgetInfo^.LCLObject); {$ENDIF} FillChar(Mess,SizeOf(Mess),0); Mess.msg := LM_SelChange; DeliverMessage(WidgetInfo^.LCLObject, Mess); end; class function TGtk2WSCustomListBox.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; var TVWidget: PGtkWidget; p: PGtkWidget; // ptr to the newly created GtkWidget liststore : PGtkListStore; Selection: PGtkTreeSelection; renderer : PGtkCellRenderer; column : PGtkTreeViewColumn; WidgetInfo: PWidgetInfo; begin Result := TGtkWSBaseScrollingWinControl.CreateHandle(AWinControl, AParams); p := PGtkWidget(Result); if Result = 0 then exit; {$IFDEF DebugLCLComponents} DebugGtkWidgets.MarkCreated(p,dbgsName(AWinControl)); {$ENDIF} GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.hscrollbar, GTK_CAN_FOCUS); GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.vscrollbar, GTK_CAN_FOCUS); gtk_scrolled_window_set_policy(PGtkScrolledWindow(p), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(p), BorderStyleShadowMap[TCustomListBox(AWinControl).BorderStyle]); gtk_widget_show(p); liststore := gtk_list_store_new (2, [G_TYPE_STRING, G_TYPE_POINTER, nil]); TVWidget:= gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); g_object_unref (G_OBJECT (liststore)); renderer := LCLIntfCellRenderer_New(); column := gtk_tree_view_column_new_with_attributes ('LISTITEMS', renderer, ['text', 0, nil]); gtk_cell_layout_set_cell_data_func(PGtkCellLayout(column), renderer, @LCLIntfCellRenderer_CellDataFunc, nil, nil); gtk_tree_view_append_column (GTK_TREE_VIEW (TVWidget), column); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (TVWidget), False); gtk_container_add(GTK_CONTAINER(p), TVWidget); gtk_widget_show(TVWidget); SetMainWidget(p, TVWidget); WidgetInfo := GetWidgetInfo(p, false); WidgetInfo^.CoreWidget := TVWidget; Selection := gtk_tree_view_get_selection(PGtkTreeView(TVWidget)); case TCustomListBox(AWinControl).MultiSelect of True : gtk_tree_selection_set_mode(Selection, GTK_SELECTION_MULTIPLE); False: gtk_tree_selection_set_mode(Selection, GTK_SELECTION_SINGLE); end; g_signal_connect_after(Selection, 'changed', G_CALLBACK(@gtk2ListBoxSelectionChangedAfter), WidgetInfo); // Sets the callbacks SetCallbacks(p, WidgetInfo); end; class procedure TGtk2WSCustomListBox.SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); begin TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); end; class function TGtk2WSCustomListBox.GetIndexAtY( const ACustomListBox: TCustomListBox; y: integer): integer; var aTreeView: PGtkTreeView; aTreeColumn: PGtkTreeViewColumn; aTreePath: PGtkTreePath; begin Result := -1; if not WSCheckHandleAllocated(ACustomListBox, 'GetIndexAtY') then Exit; case ACustomListBox.fCompStyle of csListBox, csCheckListBox: begin aTreeView := GTK_TREE_VIEW(GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget); if gtk_tree_view_get_path_at_pos(aTreeView, 0, Y, aTreePath, aTreeColumn, nil, nil) then begin Result := gtk_tree_path_get_indices(aTreePath)[0]; gtk_tree_path_free(aTreePath); exit; end; end; end; end; class function TGtk2WSCustomListBox.GetSelCount( const ACustomListBox: TCustomListBox): integer; var Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) Selection: PGtkTreeSelection; ListStoreModel: PGtkTreeModel; Rows: PGList; begin Result := 0; if not WSCheckHandleAllocated(ACustomListBox, 'GetSelCount') then Exit; Widget := GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget; Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); Rows := gtk_tree_selection_get_selected_rows(Selection, @ListStoreModel); Result := g_list_length(Rows); g_list_free(Rows); end; class function TGtk2WSCustomListBox.GetSelected( const ACustomListBox: TCustomListBox; const AIndex: integer): boolean; var Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) Selection: PGtkTreeSelection; ListStoreModel: PGtkTreeModel; Item : TGtkTreeIter; begin Result := False; { assume: nothing found } if not WSCheckHandleAllocated(ACustomListBox, 'GetSelected') then Exit; Widget := GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget; ListStoreModel := gtk_tree_view_get_model(PGtkTreeView(Widget)); Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); if gtk_tree_model_iter_nth_child(ListStoreModel, @Item, nil, AIndex) then begin Result := gtk_tree_selection_iter_is_selected(Selection, @Item); end; end; class function TGtk2WSCustomListBox.GetStrings( const ACustomListBox: TCustomListBox): TStrings; var Widget: PGtkWidget;// pointer to gtk-widget begin Result:=nil; if not WSCheckHandleAllocated(ACustomListBox, 'GetStrings') then Exit; case ACustomListBox.fCompStyle of {csCListBox: begin Widget:= GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; Result := TGtkCListStringList.Create(PGtkCList(Widget)); if ACustomListBox is TCustomListBox then TGtkCListStringList(Result).Sorted := TCustomListBox(ACustomListBox).Sorted; end; } csCheckListBox, csListBox: begin Widget := GetWidgetInfo(Pointer(ACustomListBox.Handle), True)^.CoreWidget; Result := TGtkListStoreStringList.Create( gtk_tree_view_get_model(PGtkTreeView(Widget)), Ord(ACustomListBox.fCompStyle = csCheckListBox), ACustomListBox); TGtkListStoreStringList(Result).Sorted := ACustomListBox.Sorted; end; else raise Exception.Create('TGtk2WSCustomListBox.GetStrings'); end; end; { TGtk2WSCustomCheckBox } class function TGtk2WSCustomCheckBox.CreateHandle( const AWinControl: TWinControl; const AParams: TCreateParams ): TLCLIntfHandle; var Widget: PGtkWidget; WidgetInfo: PWidgetInfo; Allocation: TGTKAllocation; begin { ToDo verify if the check box has correct z-order and disable GTK_WIDGET_NO_WINDOW if not.} Widget := gtk_check_button_new_with_label(AParams.Caption); {$IFDEF DebugLCLComponents} DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); {$ENDIF} Result := THandle(PtrUInt(Widget)); WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams); Allocation.X := AParams.X; Allocation.Y := AParams.Y; Allocation.Width := AParams.Width; Allocation.Height := AParams.Height; gtk_widget_size_allocate(PGtkWidget(Result), @Allocation); Set_RC_Name(AWinControl, PGtkWidget(Result)); SetCallbacks(PGtkWidget(Result), WidgetInfo); end; class procedure TGtk2WSCustomCheckBox.GetPreferredSize( const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); begin GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight, WithThemeSpace); end; class function TGtk2WSCustomCheckBox.RetrieveState( const ACustomCheckBox: TCustomCheckBox): TCheckBoxState; var ToggleButton: PGtkToggleButton; begin ToggleButton:=PGtkToggleButton(ACustomCheckBox.Handle); if ACustomCheckBox.AllowGrayed and gtk_toggle_button_get_inconsistent(ToggleButton) then Result:=cbGrayed else if gtk_toggle_button_get_active(ToggleButton) then Result := cbChecked else Result := cbUnChecked; end; class procedure TGtk2WSCustomCheckBox.SetShortCut( const ACustomCheckBox: TCustomCheckBox; const OldShortCut, NewShortCut: TShortCut); begin //DebugLn(['TGtk2WSCustomCheckBox.SetShortCut ',NewShortCut]); Accelerate(ACustomCheckBox, PGtkWidget(ACustomCheckBox.Handle), NewShortcut, 'clicked' //'activate_item' ); end; class procedure TGtk2WSCustomCheckBox.SetState( const ACustomCheckBox: TCustomCheckBox; const NewState: TCheckBoxState); var GtkObject: PGtkObject; ToggleButton: PGtkToggleButton; begin //debugln('TGtk2WSCustomCheckBox.SetState A ',DbgSName(ACustomCheckBox),' State=',dbgs(ord(ACustomCheckBox.State))); GtkObject := PGtkObject(ACustomCheckBox.Handle); LockOnChange(GtkObject,1); ToggleButton:=PGtkToggleButton(GtkObject); gtk_toggle_button_set_active(ToggleButton, NewState=cbChecked); gtk_toggle_button_set_inconsistent(ToggleButton, NewState=cbGrayed); LockOnChange(GtkObject,-1); end; class procedure TGtk2WSCustomCheckBox.SetFont(const AWinControl: TWinControl; const AFont: tFont); var Widget: PGTKWidget; LblWidget: PGtkWidget; begin if not AWinControl.HandleAllocated then exit; if AFont.IsDefault then exit ; Widget:= PGtkWidget(AWinControl.Handle); LblWidget := (pGtkBin(Widget)^.Child); if LblWidget<>nil then begin Gtk2WidgetSet.SetWidgetColor(LblWidget, AWinControl.font.color, clNone, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); Gtk2WidgetSet.SetWidgetFont(LblWidget, AFont); end; end; {$I gtk2wscustommemo.inc} { TGtk2WSCustomEdit } class function TGtk2WSCustomEdit.GetSelStart(const ACustomEdit: TCustomEdit ): integer; var Entry: PGtkEntry; begin Result := 0; if not WSCheckHandleAllocated(ACustomEdit, 'GetSelStart') then Exit; Entry := PGtkEntry(ACustomEdit.Handle); Result := Min(Entry^.current_pos, Entry^.selection_bound); end; class function TGtk2WSCustomEdit.GetSelLength(const ACustomEdit: TCustomEdit ): integer; var Entry: PGtkEntry; begin Result := 0; if not WSCheckHandleAllocated(ACustomEdit, 'GetSelLength') then Exit; Entry := PGtkEntry(ACustomEdit.Handle); Result := ABS(Entry^.current_pos - Entry^.selection_bound); end; class procedure TGtk2WSCustomEdit.SetEchoMode(const ACustomEdit: TCustomEdit; NewMode: TEchoMode); var Entry: PGtkEntry; begin if not WSCheckHandleAllocated(ACustomEdit, 'SetEchoMode') then Exit; Entry := PGtkEntry(ACustomEdit.Handle); if NewMode in [emNone,emPassword] then begin gtk_entry_set_visibility(Entry,false); SetPasswordChar(ACustomEdit,ACustomEdit.PasswordChar); end else begin gtk_entry_set_visibility(Entry,true); end; end; class procedure TGtk2WSCustomEdit.SetPasswordChar( const ACustomEdit: TCustomEdit; NewChar: char); var PWChar: Integer; Entry: PGtkEntry; begin if not WSCheckHandleAllocated(ACustomEdit, 'SetPasswordChar') then Exit; Entry := PGtkEntry(ACustomEdit.Handle); if ACustomEdit.EchoMode=emNone then PWChar:=0 else begin PWChar:=ord(ACustomEdit.PasswordChar); if (PWChar<192) or (PWChar=ord('*')) then PWChar:=9679; end; gtk_entry_set_invisible_char(Entry,PWChar); end; class procedure TGtk2WSCustomEdit.SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); var NewPos: Integer; Entry: PGtkEntry; begin if not WSCheckHandleAllocated(ACustomEdit, 'SetSelStart') then Exit; Entry := PGtkEntry(ACustomEdit.Handle); if GetSelStart(ACustomEdit) = NewStart then exit; NewPos := Min(NewStart, Entry^.text_max_length); gtk_entry_set_position(Entry, NewPos); end; class procedure TGtk2WSCustomEdit.SetSelLength( const ACustomEdit: TCustomEdit; NewLength: integer); var Entry: PGtkEntry; begin if not WSCheckHandleAllocated(ACustomEdit, 'SetSelLength') then Exit; Entry := PGtkEntry(ACustomEdit.Handle); gtk_entry_select_region(Entry, Entry^.current_pos, Entry^.current_pos + NewLength); end; class procedure TGtk2WSCustomComboBox.ReCreateCombo( const ACustomComboBox: TCustomComboBox; const AWithEntry: Boolean; const AWidgetInfo: PWidgetInfo); var ComboWidget: PGtkWidget; Model: PGtkTreeModel; Index: Integer; Text: String; Box: PGtkWidget; ItemList: TGtkListStoreStringList; LCLIndex: PLongint; begin Box:=PGtkWidget(ACustomComboBox.Handle); ComboWidget := AWidgetInfo^.CoreWidget; // keep the model (increase ref count) Model := gtk_combo_box_get_model(PGtkComboBox(ComboWidget)); g_object_ref(G_OBJECT(Model)); // keep items ItemList := ACustomComboBox.Items as TGtkListStoreStringList; LCLIndex := AWidgetInfo^.UserData; if not Assigned(LCLIndex) then begin //debugln('Gtk2WSCustomComboBox ReCreateCombo: LCLIndex unassigned!'); LCLIndex := New(PLongint); LCLIndex^ := -1; AWidgetInfo^.UserData := LCLIndex; AWidgetInfo^.DataOwner := True; end; // this should work but may not in all circumstances Index := -1; if AWithEntry = False then begin // the current widget HAS an entry GetText(ACustomComboBox, Text); Index := ACustomComboBox.Items.IndexOf(Text); end; if Index = -1 then Index := GetItemIndex(ACustomComboBox); gtk_object_set_data(PGtkObject(ComboWidget), GtkListItemLCLListTag,nil); gtk_widget_destroy(ComboWidget); // create the new widget with the old model case AWithEntry of True : ComboWidget := gtk_combo_box_entry_new_with_model(Model, 0); False: ComboWidget := gtk_combo_box_new_with_model(Model); end; // undone the above increase of the ref count gtk_object_set_data(PGtkObject(ComboWidget),GtkListItemLCLListTag,ItemList); g_object_unref (G_OBJECT(Model)); SetMainWidget(Box, GTK_BIN(ComboWidget)^.child); AWidgetInfo^.CoreWidget := ComboWidget; gtk_object_set_data(Pointer(ComboWidget), 'widgetinfo', AWidgetInfo); SetItemIndex(ACustomComboBox, Index); if AWithEntry then begin SetMaxLength(ACustomComboBox, TComboBox(ACustomComboBox).MaxLength); SetReadOnly(ACustomComboBox, ACustomComboBox.ReadOnly); end; SetRenderer(ACustomComboBox, ComboWidget, AWidgetInfo); gtk_container_add(PGtkContainer(AWidgetInfo^.ClientWidget), ComboWidget); gtk_widget_show_all(AWidgetInfo^.ClientWidget); SetCallbacks(ACustomComboBox, Box, AWidgetInfo); end; class procedure TGtk2WSCustomComboBox.SetRenderer( const ACustomComboBox: TCustomComboBox; AWidget: PGtkWidget; AWidgetInfo: PWidgetInfo); var renderer : PGtkCellRenderer; begin renderer := LCLIntfCellRenderer_New(); g_object_set_data(G_OBJECT(renderer), 'widgetinfo', AWidgetInfo); gtk_cell_layout_clear(PGtkCellLayout(AWidget)); gtk_cell_layout_pack_start(PGtkCellLayout(AWidget), renderer, True); gtk_cell_layout_set_attributes(PGtkCellLayout(AWidget), renderer, ['text', 0, nil]); gtk_cell_layout_set_cell_data_func(PGtkCellLayout(AWidget), renderer, @LCLIntfCellRenderer_CellDataFunc, nil, nil); end; procedure GtkPopupShowCB(AMenu: PGtkMenuShell; WidgetInfo: PWidgetInfo); cdecl; begin // let the LCL change the items on the fly: LCLSendDropDownMsg(TControl(WidgetInfo^.LCLObject)); end; procedure GtkPopupHideCB(AMenu: PGtkMenuShell; WidgetInfo: PWidgetInfo); cdecl; begin LCLSendCloseUpMsg(TControl(WidgetInfo^.LCLObject)); end; function GtkPopupCloseUp(WidgetInfo: Pointer): gboolean; cdecl; begin LCLSendCloseUpMsg(TControl(PWidgetInfo(WidgetInfo)^.LCLObject)); Result := gtk_False;// stop the timer end; procedure GtkNotifyCB(AObject: PGObject; pspec: PGParamSpec; WidgetInfo: PWidgetInfo); cdecl; var AValue: TGValue; AMenu: PGtkWidget; ComboBox: TCustomComboBox; begin if pspec^.name = 'popup-shown' then begin FillChar(AValue, SizeOf(AValue), 0); // fill by zeros g_value_init(@AValue, G_TYPE_BOOLEAN); // initialize for boolean g_object_get_property(AObject, pspec^.name, @AValue); // get property value if AValue.data[0].v_int = 0 then // if 0 = False then it is close up gtk_timeout_add(0,@GtkPopupCloseUp, WidgetInfo) else // in other case it is drop down begin ComboBox:=WidgetInfo^.LCLObject as TCustomComboBox; ComboBox.IntfGetItems; LCLSendDropDownMsg(ComboBox); AMenu := PGtkComboBoxPrivate(PGtkComboBox(WidgetInfo^.CoreWidget)^.priv)^.popup_widget; if GTK_IS_MENU(AMenu) then gtk_menu_reposition(PGtkMenu(AMenu)); end; end; end; procedure GtkChangedCB(AWidget: PGtkWidget; WidgetInfo: PWidgetInfo); cdecl; var LCLIndex: PLongint; Index, GtkIndex: Integer; begin if WidgetInfo^.ChangeLock > 0 then Exit; LCLSendChangedMsg(TControl(WidgetInfo^.LCLObject)); Index := -1; LCLIndex := WidgetInfo^.UserData; if Assigned(LCLIndex) then Index := LCLIndex^ else debugln('Gtk2WSCustomComboBox GtkChangedCB: LCLIndex unassigned!'); GtkIndex := gtk_combo_box_get_active(GTK_COMBO_BOX(WidgetInfo^.CoreWidget)); if Index <> GtkIndex then begin LCLSendSelectionChangedMsg(TControl(WidgetInfo^.LCLObject)); if Assigned(LCLIndex) then LCLIndex^ := GtkIndex; end; end; {procedure GtkSelectedCB(AWidget: PGtkWidget; WidgetInfo: PWidgetInfo); cdecl; begin if WidgetInfo^.UserData <> nil then Exit; LCLSendSelectionChangedMsg(TControl(WidgetInfo^.LCLObject)); end;} class procedure TGtk2WSCustomComboBox.SetCallbacks( const AWinControl: TWinControl; const AWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); var AGtkObject: PGtkObject; AEntry: PGtkObject; AButton: PGtkObject; APrivate: PGtkComboBoxPrivate; AMenu: PGtkObject; BtnPressID: guint; HandlerID: guint; ComboWidget: PGtkComboBox; InputObject: PGtkObject; begin ComboWidget:=PGtkComboBox(AWidgetInfo^.CoreWidget); AGtkObject := PGtkObject(AWidget); AEntry := PGtkObject(GetComboBoxEntry(PGtkWidget(ComboWidget))); APrivate := PGtkComboBoxPrivate(ComboWidget^.priv); AButton := PGtkObject(APrivate^.button); //DebugLn(['TGtk2WSCustomComboBox.SetCallbacks ',dbgsName(AWinControl),' AButton=',GetWidgetClassName(PGtkWidget(AButton)),' ComboWidget=',GetWidgetClassName(PGtkWidget(ComboWidget))]); // we have to remove the handler gtk sets up to get the mouse down messages BtnPressID := g_signal_lookup('button_press_event', GTK_TYPE_COMBO_BOX); if AButton<>nil then begin HandlerID := g_signal_handler_find(AButton, G_SIGNAL_MATCH_ID, BtnPressID, 0, nil, nil, nil); if HandlerID > 0 then begin g_signal_handler_disconnect(AButton, HandlerID); end; end; g_signal_connect(ComboWidget, 'changed', TGCallback(@GtkChangedCB), AWidgetInfo); // First the combo (or the entry) if gtk_is_combo_box_entry(ComboWidget) then begin InputObject:=AEntry; end else begin InputObject:=AGTKObject; end; Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEMOVE, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONDOWN, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONUP, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONDBLCLK, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONDBLCLK, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONDBLCLK, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONDOWN, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONUP, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONDOWN, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONUP, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEWHEEL, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_PAINT, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_FOCUS, InputObject, AWinControl); // And now the same for the Button in the combo if AButton<>nil then begin Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEENTER, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MOUSELEAVE, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEMOVE, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONDOWN, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONUP, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONUP, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONDOWN, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONUP, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONDOWN, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONUP, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEWHEEL, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_PAINT, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_FOCUS, AButton, AWinControl); end; // if we are a GtkComboBoxEntry if GtkWidgetIsA(PGtkWidget(AEntry), GTK_TYPE_ENTRY) then begin // Anything? end; AMenu := nil; if (APrivate^.popup_widget <> nil) and (GTK_IS_MENU(APrivate^.popup_widget)) then AMenu := GTK_OBJECT(APrivate^.popup_widget) else if (APrivate^.popup_window <> nil) and (GTK_IS_MENU(APrivate^.popup_window)) then AMenu := GTK_OBJECT(APrivate^.popup_window); if Assigned(AMenu) and (gtk_major_version = 2) and (gtk_minor_version < 10) then begin g_signal_connect(AMenu, 'show', G_CALLBACK(@GtkPopupShowCB), AWidgetInfo); g_signal_connect_after(AMenu, 'selection-done', G_CALLBACK(@GtkPopupHideCB), AWidgetInfo); end; if (gtk_major_version >= 2) and (gtk_minor_version >= 10) then g_signal_connect(ComboWidget, 'notify', TGCallback(@GtkNotifyCB), AWidgetInfo); // g_signal_connect(ComboWidget, 'set-focus-child', TGCallback(@GtkPopupShowCB), AWidgetInfo); g_object_set_data(G_OBJECT(AWidget), 'Menu', APrivate^.popup_widget); end; class procedure TGtk2WSCustomComboBox.GetPreferredSize( const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); var Ignore: Integer; begin GetGTKDefaultWidgetSize(AWinControl, Ignore, PreferredHeight, WithThemeSpace); PreferredWidth := 0; end; class function TGtk2WSCustomComboBox.GetSelStart( const ACustomComboBox: TCustomComboBox): integer; var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; AStart, AEnd: gint; begin Result := 0; WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); // if the combo is an editable ... Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then Result := gtk_editable_get_position(PGtkEditable(Entry)) else Result := Min(AStart, AEnd); end; end; class function TGtk2WSCustomComboBox.GetSelLength( const ACustomComboBox: TCustomComboBox): integer; var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; AStart, AEnd: gint; begin Result := 0; WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); // if the combo is an editable ... Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then Exit(gtk_editable_get_position(PGtkEditable(Entry))); Result := ABS(AStart - AEnd); end; end; class function TGtk2WSCustomComboBox.GetItemIndex( const ACustomComboBox: TCustomComboBox): integer; var WidgetInfo: PWidgetInfo; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); Result := gtk_combo_box_get_active(PGtkComboBox(WidgetInfo^.CoreWidget)); end; class function TGtk2WSCustomComboBox.GetMaxLength( const ACustomComboBox: TCustomComboBox): integer; var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); // if the combo is an editable ... Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin Result := gtk_entry_get_max_length(Entry); end else begin Result := integer(PtrUInt(g_object_get_data(PGObject(WidgetInfo^.CoreWidget), 'max-length'))); end; end; class function TGtk2WSCustomComboBox.GetText(const AWinControl: TWinControl; var AText: String): Boolean; var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; Index: Integer; begin Result := True; WidgetInfo := GetWidgetInfo(Pointer(AWinControl.Handle)); // if the combo is an editable ... Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin AText := gtk_entry_get_text(Entry); exit; end; // if we are a fixed un-editable combo then ... Index := GetItemIndex(TCustomComboBox(AWinControl)); if Index > -1 then AText := TCustomComboBox(AWinControl).Items.Strings[Index]; end; class procedure TGtk2WSCustomComboBox.SetArrowKeysTraverseList( const ACustomComboBox: TCustomComboBox; NewTraverseList: boolean); begin // TODO // This is not an option that is available for this widget // we will have to eat the keystrokes to set this to false end; class procedure TGtk2WSCustomComboBox.SetSelStart( const ACustomComboBox: TCustomComboBox; NewStart: integer); var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin //gtk_entry_select_region(Entry, NewStart, NewStart); gtk_editable_set_position(PGtkEditable(Entry), NewStart); end; end; class procedure TGtk2WSCustomComboBox.SetSelLength( const ACustomComboBox: TCustomComboBox; NewLength: integer); var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; Start: Integer; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin Start := GetSelStart(ACustomComboBox); gtk_editable_select_region(PGtkEditable(Entry), Start, Start + NewLength); end; end; class procedure TGtk2WSCustomComboBox.SetItemIndex( const ACustomComboBox: TCustomComboBox; NewIndex: integer); var P: PGtkWidget; WidgetInfo: PWidgetInfo; LCLIndex: PLongint; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); p := WidgetInfo^.CoreWidget; if gtk_combo_box_get_active(PGtkComboBox(p)) = NewIndex then exit; // to be delphi compatible OnChange only fires in response to user actions not program actions // so we use WidgetInfo^.ChangeLock as a flag to not signal the OnChange Event Inc(WidgetInfo^.ChangeLock); gtk_combo_box_set_active(PGtkComboBox(p), NewIndex); LCLIndex := WidgetInfo^.UserData; if not Assigned(LCLIndex) then begin LCLIndex := New(PLongint); WidgetInfo^.UserData := LCLIndex; WidgetInfo^.DataOwner := True; end; LCLIndex^ := NewIndex; Dec(WidgetInfo^.ChangeLock); end; class procedure TGtk2WSCustomComboBox.SetMaxLength( const ACustomComboBox: TCustomComboBox; NewLength: integer); var WidgetInfo: PWidgetInfo; Entry: PGtkEntry; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin gtk_entry_set_max_length(Entry, NewLength); end; // We save this in the CoreWidget for when the Entry Changes styles g_object_set_data(PGObject(WidgetInfo^.CoreWidget), 'max-length', Pointer(PtrInt(NewLength))); end; class procedure TGtk2WSCustomComboBox.SetStyle( const ACustomComboBox: TCustomComboBox; NewStyle: TComboBoxStyle); var WidgetInfo: PWidgetInfo; p: PGtkWidget; begin if csDesigning in ACustomComboBox.ComponentState then exit; WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); p := WidgetInfo^.CoreWidget; case NewStyle of csDropDown, csSimple: begin if gtk_is_combo_box_entry(p) then Exit; ReCreateCombo(ACustomComboBox, True, WidgetInfo); end; csDropDownList, csOwnerDrawFixed, csOwnerDrawVariable: begin if not gtk_is_combo_box_entry(p) then Exit; ReCreateCombo(ACustomComboBox, False, WidgetInfo); end; end; end; class procedure TGtk2WSCustomComboBox.SetReadOnly( const ACustomComboBox: TCustomComboBox; NewReadOnly: boolean); var WidgetInfo: PWidgetInfo; Entry: PGtkWidget; begin WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle)); if gtk_is_combo_box_entry(WidgetInfo^.CoreWidget) then begin Entry := GTK_BIN(WidgetInfo^.CoreWidget)^.child; gtk_entry_set_editable(PGtkEntry(Entry), not NewReadOnly); end; end; class function TGtk2WSCustomComboBox.GetItems( const ACustomComboBox: TCustomComboBox): TStrings; var ComboWidget: PGtkWidget; Handle: HWND; begin Handle := ACustomComboBox.Handle; ComboWidget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; Result := TGtkListStoreStringList(gtk_object_get_data(PGtkObject(ComboWidget), GtkListItemLCLListTag)); end; class procedure TGtk2WSCustomComboBox.Sort(const ACustomComboBox: TCustomComboBox; AList: TStrings; IsSorted: boolean); var ComboWidget: PGtkWidget; Handle: HWND; begin Handle := ACustomComboBox.Handle; ComboWidget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; TGtkListStoreStringList(gtk_object_get_data(PGtkObject(ComboWidget), GtkListItemLCLListTag)).Sorted := IsSorted; end; class procedure TGtk2WSCustomComboBox.SetColor(const AWinControl: TWinControl); var WidgetInfo: PWidgetInfo; Child: PGtkWidget; // can be GtkCellRenderer or GtkEntry begin WidgetInfo := GetWidgetInfo(Pointer(AWinControl.Handle)); Child := GTK_BIN(WidgetInfo^.CoreWidget)^.child; Gtk2WidgetSet.SetWidgetColor(Child, AWinControl.Font.Color, AWinControl.Color, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,GTK_STYLE_BASE]); end; class procedure TGtk2WSCustomComboBox.SetFont(const AWinControl: TWinControl; const AFont : TFont); var Entry: PGtkEntry; WidgetInfo: PWidgetInfo; begin if not AWinControl.HandleAllocated then exit; if AFont.IsDefault then exit; WidgetInfo := GetWidgetInfo(Pointer(AWinControl.Handle)); Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); if Entry<>nil then begin Gtk2WidgetSet.SetWidgetColor(PGtkWidget(Entry), AWinControl.font.color, clNone, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,GTK_STYLE_TEXT]); Gtk2WidgetSet.SetWidgetFont(PGtkWidget(Entry), AFont); end; end; class procedure TGtk2WSCustomComboBox.SetText(const AWinControl: TWinControl; const AText: String); var WidgetInfo: PWidgetInfo; Entry: PGtkWidget; Index: Integer; begin WidgetInfo := GetWidgetInfo(Pointer(AWinControl.Handle)); // we use user ChangeLock to not signal onchange Inc(WidgetInfo^.ChangeLock); if gtk_is_combo_box_entry(WidgetInfo^.CoreWidget) then begin Entry := GTK_BIN(WidgetInfo^.CoreWidget)^.child; gtk_entry_set_text(PGtkEntry(Entry), PChar(AText)); end else begin // if not an entry it is a readonly list so we will try to comply by matching the text to an item Index := TCustomComboBox(AWinControl).Items.IndexOf(AText); SetItemIndex(TCustomComboBox(AWinControl), Index); end; Dec(WidgetInfo^.ChangeLock); end; class function TGtk2WSCustomComboBox.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; var Box, // this makes it easy to switch between GtkComBox and GtkComboBoxEntry ComboWidget: PGtkWidget; // ptr to the newly created GtkWidget ListStore : PGtkListStore; WidgetInfo: PWidgetInfo; ACustomComboBox: TCustomComboBox; ItemList: TGtkListStoreStringList; LCLIndex: PLongint; begin ACustomComboBox:=TCustomComboBox(AWinControl); Box := gtk_event_box_new; {$IFDEF DebugLCLComponents} DebugGtkWidgets.MarkCreated(Box,dbgsName(AWinControl)); {$ENDIF} WidgetInfo := CreateWidgetInfo(Box, AWinControl, AParams); ListStore := gtk_list_store_new (2, [G_TYPE_STRING, G_TYPE_POINTER, nil]); case ACustomComboBox.Style of csDropDown, csSimple: ComboWidget := gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL (ListStore), 0); csDropDownList, csOwnerDrawFixed, csOwnerDrawVariable : ComboWidget := gtk_combo_box_new_with_model(GTK_TREE_MODEL (ListStore)); end; g_object_unref (G_OBJECT (liststore)); gtk_container_add(PGtkContainer(Box), ComboWidget); gtk_widget_show_all(Box); SetRenderer(ACustomComboBox, ComboWidget, WidgetInfo); SetMainWidget(Box, ComboWidget); SetMainWidget(Box, GTK_BIN(ComboWidget)^.child); if PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button <> nil then SetMainWidget(Box, PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button); LCLIndex := New(PLongint); //Should not set the ItemIndex value here? LCLIndex^ := -1; WidgetInfo^.CoreWidget := ComboWidget; WidgetInfo^.ClientWidget := Box; WidgetInfo^.UserData := LCLIndex; WidgetInfo^.DataOwner := True; //gtk_widget_add_events(Box, GDK_ALL_EVENTS_MASK); SetCallbacks(AWinControl, Box, WidgetInfo); // Items ItemList:= TGtkListStoreStringList.Create( gtk_combo_box_get_model(PGtkComboBox(ComboWidget)),0,ACustomComboBox); gtk_object_set_data(PGtkObject(ComboWidget),GtkListItemLCLListTag,ItemList); ItemList.Assign(ACustomComboBox.Items); if ACustomComboBox.Items is TStringList then ItemList.Sorted:=TStringList(ACustomComboBox.Items).Sorted; Result := TLCLIntfHandle(PtrUInt(Box)); end; class procedure TGtk2WSCustomComboBox.DestroyHandle( const AWinControl: TWinControl); var Handle: HWND; ComboWidget: PGtkWidget; begin Handle := AWinControl.Handle; ComboWidget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; gtk_object_set_data(PGtkObject(ComboWidget),GtkListItemLCLListTag,nil); //DebugLn(['TGtk2WSCustomComboBox.DestroyHandle ',dbgsName(AWinControl),' ClassParent=',ClassParent.ClassName]); // inherited DestroyHandle doesn't work, because that is determined at // compile time, while the WS class hierarchy is created at runtime TWSWinControlClass(Classparent).DestroyHandle(AWinControl); end; { TGtk2WSCustomGroupBox } class function TGtk2WSCustomGroupBox.GetDefaultClientRect( const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer; var aClientRect: TRect): boolean; var FrameBorders: TRect; begin Result:=false; //DebugLn(['TGtk2WSCustomGroupBox.GetDefaultClientRect ',DbgSName(AWinControl),' ',aWidth,'x',aHeight]); if AWinControl.HandleAllocated then begin end else begin FrameBorders:=GetStyleGroupboxFrameBorders; aClientRect:=Rect(0,0, Max(0,aWidth-FrameBorders.Left-FrameBorders.Right), Max(0,aHeight-FrameBorders.Top-FrameBorders.Bottom)); Result:=true; end; //if Result then DebugLn(['TGtk2WSCustomGroupBox.GetDefaultClientRect END FrameBorders=',dbgs(FrameBorders),' aClientRect=',dbgs(aClientRect)]); end; class procedure TGtk2WSCustomGroupBox.SetFont(const AWinControl: TWinControl; const AFont: tFont); var Frame: PGtkFrame; Lbl: PGtkWidget; begin Frame:=PGtkFrame(Pointer(AWinControl.Handle)); Lbl := gtk_frame_get_label_widget(Frame); if Lbl <> nil then begin Gtk2WidgetSet.SetWidgetColor(Lbl, AWinControl.Font.Color, clNone, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); Gtk2WidgetSet.SetWidgetFont(Lbl, AFont); end; inherited SetFont(AWinControl, AFont); end; function Gtk2WSButton_Clicked(AWidget: PGtkWidget; AInfo: PWidgetInfo): GBoolean; cdecl; var Msg: TLMessage; begin Result := CallBackDefaultReturn; if AInfo^.ChangeLock > 0 then Exit; Msg.Msg := LM_CLICKED; Result := DeliverMessage(AInfo^.LCLObject, Msg) = 0; end; { TGtk2WSButton } class function TGtk2WSButton.GetButtonWidget(AEventBox: PGtkEventBox): PGtkButton; begin Result := PGtkButton(PGtkBin(AEventBox)^.child); end; class function TGtk2WSButton.GetLabelWidget(AEventBox: PGtkEventBox): PGtkLabel; begin Result := PGtkLabel(PGtkBin(GetButtonWidget(AEventBox))^.child); end; class procedure TGtk2WSButton.SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); begin TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); SignalConnect(AWidgetInfo^.ClientWidget, 'clicked', @Gtk2WSButton_Clicked, AWidgetInfo); end; { Under Gtk 2 we need to put a GtkEventBox under the GtkButton, because a GtkButton has no window and that causes the Z-Order to be wrong. } class function TGtk2WSButton.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; var Button: TCustomButton; WidgetInfo: PWidgetInfo; Allocation: TGTKAllocation; EventBox, BtnWidget: PGtkWidget; begin Button := AWinControl as TCustomButton; //DebugLn(['TGtk2WSButton.CreateHandle ',dbgsName(Button)]); { Creates the container control for the button, the EventBox } EventBox := gtk_event_box_new; Result := TLCLIntfHandle(PtrUInt(EventBox)); {$IFDEF DebugLCLComponents} DebugGtkWidgets.MarkCreated(EventBox,'button'); {$ENDIF} { Creates the button and inserts it into the EventBox } BtnWidget := gtk_button_new_with_label('button'); gtk_container_add(PGtkContainer(EventBox), BtnWidget); gtk_widget_show_all(EventBox); gtk_event_box_set_visible_window(PGtkEventBox(EventBox), False); { This commented commands can be used if we have event-related problems because of the EventBox } // gtk_widget_add_events(EventBox, GDK_ALL_EVENTS_MASK); // gtk_event_box_set_above_child(PGtkEventBox(EventBox), True); { The WidgetInfo is important for the form designer } WidgetInfo := CreateWidgetInfo(Pointer(Result), Button, AParams); WidgetInfo^.CoreWidget := EventBox; WidgetInfo^.ClientWidget := BtnWidget; //DebugLn(['TGtk2WSButton.CreateHandle ',GetWidgetInfo(EventBox)=WidgetInfo,' ',GetWidgetInfo(EventBox)^.ClientWidget=BtnWidget]); // gtk_object_set_data(PGtkObject(Result), 'widgetinfo', WidgetInfo); SetMainWidget(EventBox, BtnWidget); Allocation.X := AParams.X; Allocation.Y := AParams.Y; Allocation.Width := AParams.Width; Allocation.Height := AParams.Height; gtk_widget_size_allocate(EventBox, @Allocation); Set_RC_Name(AWinControl, EventBox); SetCallbacks(EventBox, WidgetInfo); end; class function TGtk2WSButton.GetText(const AWinControl: TWinControl; var AText: String): Boolean; begin // The button text is static, so let the LCL fallback to FCaption Result := False; end; class procedure TGtk2WSButton.SetDefault(const AButton: TCustomButton; ADefault: Boolean); begin if not WSCheckHandleAllocated(AButton, 'SetDefault') then Exit; if ADefault and (GTK_WIDGET_CAN_DEFAULT(pgtkwidget(AButton.Handle))) then //gtk_widget_grab_default(pgtkwidget(handle)) else begin {DebugLn('LM_BTNDEFAULT_CHANGED ',TCustomButton(Sender).Name,':',Sender.ClassName,' widget can not grab default ', ' visible=',GTK_WIDGET_VISIBLE(PGtkWidget(Handle)), ' realized=',GTK_WIDGET_REALIZED(PGtkWidget(Handle)), ' mapped=',GTK_WIDGET_MAPPED(PGtkWidget(Handle)), '');} // gtk_widget_Draw_Default(pgtkwidget(Handle)); //this isn't right but I'm not sure what to call end; end; class procedure TGtk2WSButton.SetShortcut(const AButton: TCustomButton; const OldShortcut, NewShortcut: TShortcut); begin if not WSCheckHandleAllocated(AButton, 'SetShortcut') then Exit; // gtk2: shortcuts are handled by the LCL end; class procedure TGtk2WSButton.SetText(const AWinControl: TWinControl; const AText: String); var BtnWidget: PGtkButton; LblWidget: PGtkLabel; begin if not WSCheckHandleAllocated(AWincontrol, 'SetText') then Exit; BtnWidget := GetButtonWidget(PGtkEventBox(AWinControl.Handle)); LblWidget := PGtkLabel(PGtkBin(BtnWidget)^.Child); if LblWidget = nil then begin Assert(False, Format('trace: [WARNING] Button %s(%s) has no label', [AWinControl.Name, AWinControl.ClassName])); LblWidget := PGtkLabel(gtk_label_new('')); gtk_container_add(PGtkContainer(BtnWidget), PGtkWidget(LblWidget)); end; Gtk2WidgetSet.SetLabelCaption(LblWidget, AText); end; class procedure TGtk2WSButton.SetColor(const AWinControl: TWinControl); var BtnWidget: PGTKWidget; begin BtnWidget := PGTKWidget(GetButtonWidget(PGtkEventBox(AWinControl.Handle))); Gtk2WidgetSet.SetWidgetColor(BtnWidget, clNone, AWinControl.color, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); end; class procedure TGtk2WSButton.SetFont(const AWinControl: TWinControl; const AFont : TFont); var LblWidget: PGtkWidget; begin if not AWinControl.HandleAllocated then exit; if AFont.IsDefault then exit; LblWidget := PGtkWidget(GetLabelWidget(PGtkEventBox(AWinControl.Handle))); if (LblWidget <> nil) then begin Gtk2WidgetSet.SetWidgetColor(LblWidget, AWinControl.font.color, clNone, [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); Gtk2WidgetSet.SetWidgetFont(LblWidget, AFont); end; end; class procedure TGtk2WSButton.GetPreferredSize(const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); begin GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight, WithThemeSpace); //debugln('TGtkWSButton.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight)); end; { TGtk2WSScrollBar } class procedure TGtk2WSScrollBar.SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); begin TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); g_signal_connect(AGtkWidget, 'change-value', TGCallback(@Gtk2RangeScrollCB), AWidgetInfo); end; class function TGtk2WSScrollBar.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; var Adjustment: PGtkAdjustment = nil; Widget: PGtkWidget; WidgetInfo: PWidgetInfo; begin with TScrollBar(AWinControl) do begin { Adjustment := GTK_ADJPgtkAdjustment( gtk_adjustment_new(1, Min, Max, SmallChange, LargeChange, Pagesize)); } if (Kind = sbHorizontal) then Widget := gtk_hscrollbar_new(Adjustment) else Widget := gtk_vscrollbar_new(Adjustment); end; Result := TLCLIntfHandle(PtrUInt(Widget)); {$IFDEF DebugLCLComponents} DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); {$ENDIF} WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams); Set_RC_Name(AWinControl, Widget); SetCallbacks(Widget, WidgetInfo); end; class procedure TGtk2WSScrollBar.SetParams(const AScrollBar: TCustomScrollBar); var Range: PGtkRange; begin Range := GTK_RANGE(Pointer(AScrollBar.Handle)); //set properties for the range // Note: gtk only allows: Min < Max gtk_range_set_range (Range, AScrollBar.Min, Max(AScrollBar.Min+1,AScrollBar.Max)); gtk_range_set_increments(Range, AScrollBar.SmallChange, AScrollBar.LargeChange); gtk_range_set_value (Range, AScrollBar.Position); end; initialization //////////////////////////////////////////////////// // I M P O R T A N T //////////////////////////////////////////////////// // To improve speed, register only classes // which actually implement something //////////////////////////////////////////////////// RegisterWSComponent(TScrollBar, TGtk2WSScrollBar); RegisterWSComponent(TCustomGroupBox, TGtk2WSCustomGroupBox); // RegisterWSComponent(TGroupBox, TGtk2WSGroupBox); RegisterWSComponent(TCustomComboBox, TGtk2WSCustomComboBox); // RegisterWSComponent(TComboBox, TGtk2WSComboBox); RegisterWSComponent(TCustomListBox, TGtk2WSCustomListBox, TGtk2PrivateList); // RegisterWSComponent(TListBox, TGtk2WSListBox); RegisterWSComponent(TCustomEdit, TGtk2WSCustomEdit); RegisterWSComponent(TCustomMemo, TGtk2WSCustomMemo); // RegisterWSComponent(TEdit, TGtk2WSEdit); // RegisterWSComponent(TMemo, TGtk2WSMemo); // RegisterWSComponent(TCustomLabel, TGtk2WSCustomLabel); // RegisterWSComponent(TLabel, TGtk2WSLabel); // RegisterWSComponent(TButtonControl, TGtk2WSButtonControl); RegisterWSComponent(TCustomButton, TGtk2WSButton); // RegisterWSComponent(TCustomCheckBox, TGtk2WSCustomCheckBox); RegisterWSComponent(TCustomCheckBox, TGtk2WSCustomCheckBox); // RegisterWSComponent(TToggleBox, TGtk2WSToggleBox); // RegisterWSComponent(TRadioButton, TGtk2WSRadioButton); // RegisterWSComponent(TCustomStaticText, TGtk2WSCustomStaticText); // RegisterWSComponent(TStaticText, TGtk2WSStaticText); //////////////////////////////////////////////////// end.