1{ $Id$}
2{
3 *****************************************************************************
4 *                             Gtk2WSCheckLst.pp                             *
5 *                             -----------------                             *
6 *                                                                           *
7 *                                                                           *
8 *****************************************************************************
9
10 *****************************************************************************
11  This file is part of the Lazarus Component Library (LCL)
12
13  See the file COPYING.modifiedLGPL.txt, included in this distribution,
14  for details about the license.
15 *****************************************************************************
16}
17unit Gtk2WSCheckLst;
18
19{$mode objfpc}{$H+}
20
21interface
22
23uses
24  // RTL
25  SysUtils, Classes,
26  Gtk2, GLib2, Gtk2Def,
27  // LCL
28////////////////////////////////////////////////////
29// I M P O R T A N T
30////////////////////////////////////////////////////
31// To get as little as posible circles,
32// uncomment only when needed for registration
33////////////////////////////////////////////////////
34  CheckLst, StdCtrls, Controls, LCLType, LMessages, LCLProc,
35////////////////////////////////////////////////////
36  WSCheckLst, WSLCLClasses;
37
38type
39
40  { TGtk2WSCheckListBox }
41
42  { TGtk2WSCustomCheckListBox }
43
44  TGtk2WSCustomCheckListBox = class(TWSCustomCheckListBox)
45  private
46    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
47  published
48    class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
49    class function GetItemEnabled(const ACheckListBox: TCustomCheckListBox;
50      const AIndex: integer): Boolean; override;
51    class function GetState(const ACheckListBox: TCustomCheckListBox;
52      const AIndex: integer): TCheckBoxState; override;
53    class procedure SetItemEnabled(const ACheckListBox: TCustomCheckListBox;
54      const AIndex: integer; const AEnabled: Boolean); override;
55    class procedure SetState(const ACheckListBox: TCustomCheckListBox;
56      const AIndex: integer; const AState: TCheckBoxState); override;
57  end;
58
59
60implementation
61
62uses
63  Gtk2WSControls, Gtk2Proc, Gtk2CellRenderer;
64
65const
66  gtk2CLBState = 0; // byte
67  gtk2CLBText = 1; // PGChar
68  gtk2CLBDisabled = 3; // gboolean
69
70{ TGtk2WSCheckListBox }
71
72function Gtk2WS_CheckListBoxSelectionChanged({%H-}Widget: PGtkWidget;
73  WidgetInfo: PWidgetInfo): gboolean; cdecl;
74var
75  Mess: TLMessage;
76begin
77  Result := False;
78  if WidgetInfo^.ChangeLock > 0 then
79    Exit;
80  FillChar(Mess{%H-},SizeOf(Mess),0);
81  Mess.msg := LM_SELCHANGE;
82  DeliverMessage(WidgetInfo^.LCLObject, Mess);
83end;
84
85procedure Gtk2WS_CheckListBoxDataFunc({%H-}tree_column: PGtkTreeViewColumn;
86  cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; {%H-}data: Pointer); cdecl;
87var
88  b: byte;
89  ADisabled: gboolean;
90  AValue: TCheckBoxState;
91begin
92  gtk_tree_model_get(tree_model, iter, [gtk2CLBState, @b, -1]);
93  gtk_tree_model_get(tree_model, iter, [gtk2CLBDisabled, @ADisabled, -1]);
94  AValue := TCheckBoxState(b); // TCheckBoxState is 4 byte
95  g_object_set(cell, 'inconsistent', [gboolean(AValue = cbGrayed), nil]);
96  if AValue <> cbGrayed then
97    gtk_cell_renderer_toggle_set_active(PGtkCellRendererToggle(cell), AValue = cbChecked);
98
99  g_object_set(cell, 'activatable', [gboolean(not ADisabled), nil]);
100end;
101
102procedure Gtk2WS_CheckListBoxToggle({%H-}cellrenderertoggle : PGtkCellRendererToggle;
103  arg1 : PGChar; WidgetInfo: PWidgetInfo); cdecl;
104var
105  Mess: TLMessage;
106  Param: PtrInt;
107  Iter : TGtkTreeIter;
108  TreeView: PGtkTreeView;
109  ListStore: PGtkTreeModel;
110  Path: PGtkTreePath;
111  AState: TCheckBoxState;
112begin
113  {$IFDEF EventTrace}
114  EventTrace('Gtk2WS_CheckListBoxToggle', WidgetInfo^.LCLObject);
115  {$ENDIF}
116  Val(arg1, Param);
117
118  TreeView := PGtkTreeView(WidgetInfo^.CoreWidget);
119  ListStore := gtk_tree_view_get_model(TreeView);
120
121  if gtk_tree_model_iter_nth_child(ListStore, @Iter, nil, Param) then
122    begin
123      TCustomCheckListBox(WidgetInfo^.LCLObject).Toggle(Param);
124      AState:=TCustomCheckListBox(WidgetInfo^.LCLObject).State[Param];
125
126      gtk_list_store_set(ListStore, @Iter, [gtk2CLBState,
127        Byte(AState), -1]);
128    end;
129
130
131  Path := gtk_tree_path_new_from_indices(Param, -1);
132  if Path <> nil then
133  begin
134    if TreeView^.priv^.tree <> nil then
135      gtk_tree_view_set_cursor(TreeView, Path, nil, False);
136    gtk_tree_path_free(Path);
137  end;
138
139  FillChar(Mess{%H-}, SizeOf(Mess), #0);
140  Mess.Msg := LM_CHANGED;
141
142  Mess.Result := 0;
143  Mess.WParam := Param;
144  DeliverMessage(widgetInfo^.lclObject, Mess);
145
146end;
147
148class procedure TGtk2WSCustomCheckListBox.SetCallbacks(const AGtkWidget: PGtkWidget;
149  const AWidgetInfo: PWidgetInfo);
150//var
151//  Selection: PGtkTreeSelection;
152begin
153  TGtk2WSBaseScrollingWinControl.SetCallbacks(AGtkWidget,AWidgetInfo);
154
155  {Selection :=} gtk_tree_view_get_selection(PGtkTreeView(AWidgetInfo^.CoreWidget));
156  //SignalConnect(PGtkWidget(Selection), 'changed', @Gtk2WS_ListBoxChange, AWidgetInfo);
157end;
158
159class function TGtk2WSCustomCheckListBox.CreateHandle(
160  const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle;
161var
162  TreeViewWidget: PGtkWidget;
163  p: PGtkWidget;                 // ptr to the newly created GtkWidget
164  liststore : PGtkListStore;
165  Selection: PGtkTreeSelection;
166  renderer : PGtkCellRenderer;
167  column : PGtkTreeViewColumn;
168  WidgetInfo: PWidgetInfo;
169begin
170  Result := TGtk2WSBaseScrollingWinControl.CreateHandle(AWinControl,AParams);
171  p := {%H-}PGtkWidget(Result);
172
173  if Result = 0 then exit;
174
175  WidgetInfo := GetWidgetInfo(p);
176
177  GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.hscrollbar, GTK_CAN_FOCUS);
178  GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.vscrollbar, GTK_CAN_FOCUS);
179  gtk_scrolled_window_set_policy(PGtkScrolledWindow(p),
180                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
181  gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(p), GTK_SHADOW_IN);
182  gtk_widget_show(p);
183
184  liststore := gtk_list_store_new (4,
185                          [G_TYPE_UCHAR, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, nil]);
186  TreeViewWidget := gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
187  g_object_unref(G_OBJECT(liststore));
188
189  // Check Column
190  renderer := gtk_cell_renderer_toggle_new();
191  {$ifdef windows}
192  // standard indicator size = 13 and its looks ugly under windows
193  g_object_set(renderer, 'indicator-size', [14, nil]);
194  {$endif}
195  column := gtk_tree_view_column_new;
196  gtk_tree_view_column_set_title(column, 'CHECKBTNS');
197  gtk_tree_view_column_pack_start(column, renderer, True);
198  gtk_tree_view_column_set_cell_data_func(column, renderer,
199    @Gtk2WS_CheckListBoxDataFunc, WidgetInfo, nil);
200  gtk_cell_renderer_toggle_set_active(GTK_CELL_RENDERER_TOGGLE(renderer), True);
201  gtk_tree_view_append_column(GTK_TREE_VIEW(TreeViewWidget), column);
202  gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), True);
203
204  SignalConnect(PGtkWidget(renderer), 'toggled', @Gtk2WS_CheckListBoxToggle, WidgetInfo);
205
206  // Text Column
207  renderer := LCLIntfCellRenderer_New; // gtk_cell_renderer_text_new();
208  column := gtk_tree_view_column_new_with_attributes(
209                             'LISTITEMS', renderer, ['text', gtk2CLBText, nil]);
210
211  gtk_tree_view_column_set_cell_data_func(Column, renderer, TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), WidgetInfo, nil);
212  gtk_tree_view_append_column(GTK_TREE_VIEW(TreeViewWidget), column);
213  gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), True);
214
215  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(TreeViewWidget), False);
216
217  gtk_container_add(GTK_CONTAINER(p), TreeViewWidget);
218  gtk_widget_show(TreeViewWidget);
219
220  SetMainWidget(p, TreeViewWidget);
221  GetOrCreateWidgetInfo(p)^.CoreWidget := TreeViewWidget;
222
223  Selection := gtk_tree_view_get_selection(PGtkTreeView(TreeViewWidget));
224
225  case TCustomCheckListBox(AWinControl).MultiSelect of
226    True : gtk_tree_selection_set_mode(Selection, GTK_SELECTION_MULTIPLE);
227    False: gtk_tree_selection_set_mode(Selection, GTK_SELECTION_SINGLE);
228  end;
229
230  g_signal_connect_after(Selection, 'changed',
231    G_CALLBACK(@Gtk2WS_CheckListBoxSelectionChanged), WidgetInfo);
232
233  Set_RC_Name(AWinControl, P);
234  if not AWinControl.HandleObjectShouldBeVisible and not (csDesigning in AWinControl.ComponentState) then
235    gtk_widget_hide(p);
236  SetCallbacks(p, WidgetInfo);
237end;
238
239class function TGtk2WSCustomCheckListBox.GetItemEnabled(
240  const ACheckListBox: TCustomCheckListBox; const AIndex: integer): Boolean;
241var
242  Iter : TGtkTreeIter;
243  TreeView: PGtkTreeView;
244  WidgetInfo: PWidgetInfo;
245  ListStore: PGtkTreeModel;
246  Disabled: gboolean;
247begin
248  Result := True;
249  WidgetInfo := GetWidgetInfo({%H-}PGtkWidget(ACheckListBox.Handle));
250
251  TreeView := PGtkTreeView(WidgetInfo^.CoreWidget);
252  ListStore := gtk_tree_view_get_model(TreeView);
253  if gtk_tree_model_iter_nth_child(ListStore, @Iter, nil, AIndex) then
254  begin
255    gtk_tree_model_get(ListStore, @Iter, [gtk2CLBDisabled, @Disabled, -1]);
256    Result := not Disabled;
257  end;
258end;
259
260class function TGtk2WSCustomCheckListBox.GetState(
261  const ACheckListBox: TCustomCheckListBox; const AIndex: integer
262  ): TCheckBoxState;
263var
264  Iter : TGtkTreeIter;
265  TreeView: PGtkTreeView;
266  WidgetInfo: PWidgetInfo;
267  ListStore: PGtkTreeModel;
268  b: byte;
269begin
270  Result := cbUnchecked;
271  WidgetInfo := GetWidgetInfo({%H-}PGtkWidget(ACheckListBox.Handle));
272
273  TreeView := PGtkTreeView(WidgetInfo^.CoreWidget);
274  ListStore := gtk_tree_view_get_model(TreeView);
275  if gtk_tree_model_iter_nth_child(ListStore, @Iter, nil, AIndex) then
276  begin
277    gtk_tree_model_get(ListStore, @Iter, [gtk2CLBState, @b, -1]);
278    Result := TCheckBoxState(b);
279  end;
280end;
281
282class procedure TGtk2WSCustomCheckListBox.SetItemEnabled(
283  const ACheckListBox: TCustomCheckListBox; const AIndex: integer;
284  const AEnabled: Boolean);
285var
286  Iter : TGtkTreeIter;
287  TreeView: PGtkTreeView;
288  WidgetInfo: PWidgetInfo;
289  ListStore: PGtkTreeModel;
290  Disabled: gboolean;
291begin
292  WidgetInfo := GetWidgetInfo({%H-}PGtkWidget(ACheckListBox.Handle));
293
294  TreeView := PGtkTreeView(WidgetInfo^.CoreWidget);
295  ListStore := gtk_tree_view_get_model(TreeView);
296  if gtk_tree_model_iter_nth_child(ListStore, @Iter, nil, AIndex) then begin
297    Disabled:=not AEnabled;
298    gtk_list_store_set(ListStore, @Iter, [gtk2CLBDisabled, Disabled, -1]);
299  end;
300end;
301
302class procedure TGtk2WSCustomCheckListBox.SetState(
303  const ACheckListBox: TCustomCheckListBox; const AIndex: integer;
304  const AState: TCheckBoxState);
305var
306  Iter : TGtkTreeIter;
307  TreeView: PGtkTreeView;
308  WidgetInfo: PWidgetInfo;
309  ListStore: PGtkTreeModel;
310begin
311  WidgetInfo := GetWidgetInfo({%H-}PGtkWidget(ACheckListBox.Handle));
312
313  TreeView := PGtkTreeView(WidgetInfo^.CoreWidget);
314  ListStore := gtk_tree_view_get_model(TreeView);
315  if gtk_tree_model_iter_nth_child(ListStore, @Iter, nil, AIndex) then
316  begin
317    gtk_list_store_set(ListStore, @Iter, [gtk2CLBState, Byte(AState), -1]);
318  end;
319end;
320
321end.
322