1
2
3
4{ $Id$}
5{
6 *****************************************************************************
7 *                             GtkWSStdCtrls.pp                              *
8 *                             ----------------                              *
9 *                                                                           *
10 *                                                                           *
11 *****************************************************************************
12
13 *****************************************************************************
14  This file is part of the Lazarus Component Library (LCL)
15
16  See the file COPYING.modifiedLGPL.txt, included in this distribution,
17  for details about the license.
18 *****************************************************************************
19}
20unit GtkWSStdCtrls;
21
22{$mode objfpc}{$H+}
23
24interface
25
26uses
27  Classes, SysUtils, Math,
28  LCLType, LMessages, LCLProc, Controls, Graphics, StdCtrls, Forms,
29  {$IFDEF gtk2}
30  glib2, gdk2pixbuf, gdk2, gtk2, Pango, Gtk2WSPrivate,
31  {$ELSE}
32  glib, gdk, gtk, gdkpixbuf,
33  GtkFontCache, Gtk1WSPrivate,
34  {$ENDIF}
35  InterfaceBase, WSStdCtrls, WSLCLClasses, WSProc, WSControls,
36  GtkInt, GtkDef, GTKWinApiWindow, GtkGlobals, GtkProc, GtkExtra, GtkWSPrivate;
37
38
39type
40
41  { TGtkWSScrollBar }
42
43  TGtkWSScrollBar = class(TWSScrollBar)
44  protected
45    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
46  published
47    class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
48    class procedure SetParams(const AScrollBar: TCustomScrollBar); override;
49  end;
50
51  { TGtkWSCustomGroupBox }
52
53  TGtkWSCustomGroupBox = class(TWSCustomGroupBox)
54  protected
55    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
56  published
57  {$ifdef gtk1}
58    class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
59    class procedure GetPreferredSize(const AWinControl: TWinControl;
60                        var PreferredWidth, PreferredHeight: integer;
61                        WithThemeSpace: Boolean); override;
62    class procedure SetText(const AWinControl: TWinControl; const AText: string); override;
63  {$endif}
64  end;
65
66  { TGtkWSGroupBox }
67
68  TGtkWSGroupBox = class(TWSGroupBox)
69  published
70  end;
71
72  { TGtkWSCustomComboBox }
73
74  TGtkWSCustomComboBox = class(TWSCustomComboBox)
75  published
76  {$IFDEF GTK1}
77    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
78    class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
79    class function GetDroppedDown(const ACustomComboBox: TCustomComboBox): Boolean; override;
80    class function GetSelStart(const ACustomComboBox: TCustomComboBox): integer; override;
81    class function GetSelLength(const ACustomComboBox: TCustomComboBox): integer; override;
82    class function GetItemIndex(const ACustomComboBox: TCustomComboBox): integer; override;
83    class function GetMaxLength(const ACustomComboBox: TCustomComboBox): integer; override;
84    class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override;
85
86    class procedure SetArrowKeysTraverseList(const ACustomComboBox: TCustomComboBox;
87      NewTraverseList: boolean); override;
88    class procedure SetDroppedDown(const ACustomComboBox: TCustomComboBox; ADroppedDown: Boolean); override;
89    class procedure SetSelStart(const ACustomComboBox: TCustomComboBox; NewStart: integer); override;
90    class procedure SetSelLength(const ACustomComboBox: TCustomComboBox; NewLength: integer); override;
91    class procedure SetItemIndex(const ACustomComboBox: TCustomComboBox; NewIndex: integer); override;
92    class procedure SetMaxLength(const ACustomComboBox: TCustomComboBox; NewLength: integer); override;
93    class procedure SetStyle(const ACustomComboBox: TCustomComboBox; NewStyle: TComboBoxStyle); override;
94    class procedure SetText(const AWinControl: TWinControl; const AText: String); override;
95
96    class function  GetItems(const ACustomComboBox: TCustomComboBox): TStrings; override;
97    class procedure Sort(const ACustomComboBox: TCustomComboBox; AList: TStrings; IsSorted: boolean); override;
98    class procedure SetColor(const AWinControl: TWinControl); override;
99    class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
100  {$ENDIF}
101  end;
102
103  { TGtkWSComboBox }
104
105  TGtkWSComboBox = class(TWSComboBox)
106  published
107  end;
108
109  { TGtkWSCustomListBox }
110
111  TGtkWSCustomListBox = class(TWSCustomListBox)
112  published
113  {$IFDEF GTK1}
114    class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
115    class function GetIndexAtXY(const ACustomListBox: TCustomListBox; X, Y: integer): integer; override;
116    class function GetItemIndex(const ACustomListBox: TCustomListBox): integer; override;
117    class function GetItemRect(const ACustomListBox: TCustomListBox; Index: integer; var ARect: TRect): boolean; override;
118    class function GetSelCount(const ACustomListBox: TCustomListBox): integer; override;
119    class function GetSelected(const ACustomListBox: TCustomListBox; const AIndex: integer): boolean; override;
120    class function GetStrings(const ACustomListBox: TCustomListBox): TStrings; override;
121    class function GetTopIndex(const ACustomListBox: TCustomListBox): integer; override;
122
123    class procedure SelectItem(const ACustomListBox: TCustomListBox; AIndex: integer; ASelected: boolean); override;
124    class procedure SetBorder(const ACustomListBox: TCustomListBox); override;
125    class procedure SetItemIndex(const ACustomListBox: TCustomListBox; const AIndex: integer); override;
126    class procedure SetSelectionMode(const ACustomListBox: TCustomListBox; const AExtendedSelect, AMultiSelect: boolean); override;
127    class procedure SetSorted(const ACustomListBox: TCustomListBox; AList: TStrings; ASorted: boolean); override;
128    class procedure SetTopIndex(const ACustomListBox: TCustomListBox; const NewTopIndex: integer); override;
129    class procedure SetColor(const AWinControl: TWinControl); override;
130    class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
131  {$ENDIF}
132  end;
133
134  { TGtkWSListBox }
135
136  TGtkWSListBox = class(TWSListBox)
137  published
138  end;
139
140  { TGtkWSCustomEdit }
141
142  TGtkWSCustomEdit = class(TWSCustomEdit)
143  published
144    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
145    class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
146    class function GetSelStart(const ACustomEdit: TCustomEdit): integer; override;
147    class function GetSelLength(const ACustomEdit: TCustomEdit): integer; override;
148
149    class procedure SetCharCase(const ACustomEdit: TCustomEdit; NewCase: TEditCharCase); override;
150    class procedure SetEchoMode(const ACustomEdit: TCustomEdit; NewMode: TEchoMode); override;
151    class procedure SetMaxLength(const ACustomEdit: TCustomEdit; NewLength: integer); override;
152    class procedure SetPasswordChar(const ACustomEdit: TCustomEdit; NewChar: char); override;
153    class procedure SetReadOnly(const ACustomEdit: TCustomEdit; NewReadOnly: boolean); override;
154    class procedure SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); override;
155    class procedure SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); override;
156    class procedure SetText(const AWinControl: TWinControl; const AText: string); override;
157
158    class procedure GetPreferredSize(const AWinControl: TWinControl;
159                        var PreferredWidth, PreferredHeight: integer;
160                        WithThemeSpace: Boolean); override;
161    class procedure SetColor(const AWinControl: TWinControl); override;
162  end;
163
164  { TGtkWSCustomMemo }
165
166  TGtkWSCustomMemo = class(TWSCustomMemo)
167  published
168    {$ifdef GTK1}
169    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
170    class function CreateHandle(const AWinControl: TWinControl;
171                        const AParams: TCreateParams): TLCLIntfHandle; override;
172    class procedure AppendText(const ACustomMemo: TCustomMemo;
173                               const AText: string); override;
174    class function  GetStrings(const ACustomMemo: TCustomMemo): TStrings; override;
175    class procedure SetEchoMode(const ACustomEdit: TCustomEdit;
176                                NewMode: TEchoMode); override;
177    class procedure SetMaxLength(const ACustomEdit: TCustomEdit;
178                                 NewLength: integer); override;
179    class procedure SetPasswordChar(const ACustomEdit: TCustomEdit;
180                                    NewChar: char); override;
181    class procedure SetReadOnly(const ACustomEdit: TCustomEdit;
182                                NewReadOnly: boolean); override;
183    class procedure SetScrollbars(const ACustomMemo: TCustomMemo;
184                                  const NewScrollbars: TScrollStyle); override;
185    class procedure SetWordWrap(const ACustomMemo: TCustomMemo;
186                                const NewWordWrap: boolean); override;
187    class procedure SetColor(const AWinControl: TWinControl); override;
188    class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
189    {$endif}
190  end;
191
192  { TGtkWSEdit }
193
194  TGtkWSEdit = class(TWSEdit)
195  published
196  end;
197
198  { TGtkWSMemo }
199
200  TGtkWSMemo = class(TWSMemo)
201  published
202  end;
203
204  { TGtkWSCustomStaticText }
205
206  TGtkWSCustomStaticText = class(TWSCustomStaticText)
207  protected
208    class function GetLabelWidget(AFrame: PGtkFrame): PGtkLabel;
209    class function GetBoxWidget(AFrame: PGtkFrame): PGtkEventBox;
210  published
211    class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
212    class procedure SetAlignment(const ACustomStaticText: TCustomStaticText;
213                                 const NewAlignment: TAlignment); override;
214    class procedure GetPreferredSize(const AWinControl: TWinControl;
215                        var PreferredWidth, PreferredHeight: integer;
216                        WithThemeSpace: Boolean); override;
217    class function  GetText(const AWinControl: TWinControl; var AText: String): Boolean; override;
218    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo);
219    class procedure SetColor(const AWinControl: TWinControl); override;
220    class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
221    class procedure SetStaticBorderStyle(const ACustomStaticText: TCustomStaticText; const NewBorderStyle: TStaticBorderStyle); override;
222    class procedure SetText(const AWinControl: TWinControl; const AText: String); override;
223  end;
224
225  { TGtkWSStaticText }
226
227  TGtkWSStaticText = class(TWSStaticText)
228  published
229  end;
230
231  { TGtkWSButtonControl }
232
233  TGtkWSButtonControl = class(TWSButtonControl)
234  published
235  end;
236
237  { TGtkWSButton }
238
239  TGtkWSButton = class(TWSButton)
240  public
241    {SetCallbacks is made public so that it can be called from
242     TGtkWSBitBtn.CreateHandle.
243     TODO: move it to TGtkPrivateButton}
244    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
245  published
246    {$ifdef Gtk1}
247    class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
248    class procedure GetPreferredSize(const AWinControl: TWinControl;
249                        var PreferredWidth, PreferredHeight: integer;
250                        WithThemeSpace: Boolean); override;
251    class function  GetText(const AWinControl: TWinControl; var AText: String): Boolean; override;
252
253    class procedure SetColor(const AWinControl: TWinControl); override;
254    class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
255    class procedure SetDefault(const AButton: TCustomButton; ADefault: Boolean); override;
256    class procedure SetShortcut(const AButton: TCustomButton; const ShortCutK1, ShortCutK2: TShortcut); override;
257    class procedure SetText(const AWinControl: TWinControl; const AText: String); override;
258    {$endif Gtk1}
259  end;
260
261  { TGtkWSCustomCheckBox }
262
263  TGtkWSCustomCheckBox = class(TWSCustomCheckBox)
264  protected
265    class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
266  published
267  {$IFDEF GTK1}
268    class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
269    class function  RetrieveState(const ACustomCheckBox: TCustomCheckBox): TCheckBoxState; override;
270    class procedure SetShortCut(const ACustomCheckBox: TCustomCheckBox; const ShortCutK1, ShortCutK2: TShortCut); override;
271    class procedure SetState(const ACB: TCustomCheckBox; const ANewState: TCheckBoxState); override;
272    class procedure GetPreferredSize(const AWinControl: TWinControl;
273                        var PreferredWidth, PreferredHeight: integer;
274                        WithThemeSpace: Boolean); override;
275    class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
276  {$ENDIF}
277  end;
278
279  { TGtkWSCheckBox }
280
281  TGtkWSCheckBox = class(TWSCheckBox)
282  published
283  end;
284
285  { TGtkWSToggleBox }
286
287  TGtkWSToggleBox = class(TWSToggleBox)
288  published
289    class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
290  end;
291
292  { TGtkWSRadioButton }
293
294  TGtkWSRadioButton = class(TWSRadioButton)
295  published
296    class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
297  end;
298
299function  WidgetGetSelStart(const Widget: PGtkWidget): integer;
300procedure WidgetSetSelLength(const Widget: PGtkWidget; NewLength: integer);
301
302{$ifdef gtk1}
303{$I gtk1memostringsh.inc}
304{$endif}
305
306implementation
307
308uses
309  GtkWSControls;
310
311const
312  StaticBorderShadowMap: array[TStaticBorderStyle] of TGtkShadowType =
313  (
314    GTK_SHADOW_NONE,
315    GTK_SHADOW_ETCHED_IN,
316    GTK_SHADOW_IN
317  );
318
319{$ifdef gtk1}
320{$I gtk1memostrings.inc}
321{$endif}
322
323{ helper routines }
324
325
326
327function WidgetGetSelStart(const Widget: PGtkWidget): integer;
328begin
329  if Widget <> nil then
330  begin
331    if PGtkOldEditable(Widget)^.selection_start_pos
332       < PGtkOldEditable(Widget)^.selection_end_pos
333    then
334      Result:= PGtkOldEditable(Widget)^.selection_start_pos
335    else
336      Result:= PGtkOldEditable(Widget)^.current_pos;// selection_end_pos
337  end else
338    Result:= 0;
339end;
340
341procedure WidgetSetSelLength(const Widget: PGtkWidget; NewLength: integer);
342begin
343  if Widget<>nil then
344  begin
345    gtk_editable_select_region(PGtkOldEditable(Widget),
346      gtk_editable_get_position(PGtkOldEditable(Widget)),
347      gtk_editable_get_position(PGtkOldEditable(Widget)) + NewLength);
348  end;
349end;
350
351{ TGtkWSScrollBar }
352
353class procedure TGtkWSScrollBar.SetCallbacks(const AGtkWidget: PGtkWidget;
354  const AWidgetInfo: PWidgetInfo);
355begin
356  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
357
358  if TScrollBar(AWidgetInfo^.LCLObject).Kind = sbHorizontal then
359    TGtkWidgetset(Widgetset).SetCallback(LM_HSCROLL, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject)
360  else
361    TGtkWidgetset(Widgetset).SetCallback(LM_VSCROLL, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
362end;
363
364class function TGtkWSScrollBar.CreateHandle(const AWinControl: TWinControl;
365  const AParams: TCreateParams): TLCLIntfHandle;
366var
367  Adjustment: PGtkAdjustment;
368  Widget: PGtkWidget;
369  WidgetInfo: PWidgetInfo;
370begin
371  with TScrollBar(AWinControl) do
372  begin
373    Adjustment := PgtkAdjustment(
374                   gtk_adjustment_new(1, Min, Max, SmallChange, LargeChange,
375                     Pagesize));
376
377    if (Kind = sbHorizontal) then
378      Widget := gtk_hscrollbar_new(Adjustment)
379    else
380      Widget := gtk_vscrollbar_new(Adjustment);
381  end;
382  gtk_object_set_data(PGTKObject(Adjustment), odnScrollBar, Widget);
383
384  Result := TLCLIntfHandle(PtrUInt(Widget));
385  {$IFDEF DebugLCLComponents}
386  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
387  {$ENDIF}
388  WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams);
389  Set_RC_Name(AWinControl, Widget);
390  SetCallbacks(Widget, WidgetInfo);
391end;
392
393class procedure TGtkWSScrollBar.SetParams(const AScrollBar: TCustomScrollBar);
394var
395  Adjustment: PGtkAdjustment;
396begin
397  with AScrollBar do
398  begin
399    //set properties for the range
400    Adjustment := gtk_range_get_adjustment (GTK_RANGE(Pointer(Handle)));
401    Adjustment^.lower := Min;
402    Adjustment^.Upper := Max;
403    Adjustment^.Value := Position;
404    Adjustment^.step_increment := SmallChange;
405    Adjustment^.page_increment := LargeChange;
406  end;
407end;
408
409{ TGtkWSCustomListBox }
410
411{$IFDEF GTK1}
412
413class function TGtkWSCustomListBox.CreateHandle(const AWinControl: TWinControl;
414  const AParams: TCreateParams): TLCLIntfHandle;
415var
416  Widget: PGtkWidget;
417  WidgetInfo: PWidgetInfo;
418  ScrolledWnd: PGtkScrolledWindow absolute Widget;
419  ListBox: TCustomListBox absolute AWinControl;
420  List: Pointer;
421begin
422  Widget := gtk_scrolled_window_new(nil, nil);
423  GTK_WIDGET_UNSET_FLAGS(ScrolledWnd^.hscrollbar, GTK_CAN_FOCUS);
424  GTK_WIDGET_UNSET_FLAGS(ScrolledWnd^.vscrollbar, GTK_CAN_FOCUS);
425  gtk_scrolled_window_set_policy(ScrolledWnd, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
426  gtk_widget_show(Widget);
427
428  List := gtk_list_new;
429  gtk_scrolled_window_add_with_viewport(ScrolledWnd, List);
430  gtk_container_set_focus_vadjustment(List,
431               gtk_scrolled_window_get_vadjustment(ScrolledWnd));
432  gtk_container_set_focus_hadjustment(PGtkContainer(List),
433               gtk_scrolled_window_get_hadjustment(ScrolledWnd));
434  gtk_widget_show(List);
435
436  WidgetInfo := CreateWidgetInfo(Widget, AWinControl, AParams);
437  SetMainWidget(Widget, List);
438  WidgetInfo^.CoreWidget := List;
439
440  TGtkWidgetSet(WidgetSet).SetSelectionMode(AWinControl, Widget,
441    ListBox.MultiSelect, ListBox.ExtendedSelect);
442
443  Result := TLCLIntfHandle(PtrUInt(Widget));
444  {$IFDEF DebugLCLComponents}
445  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
446  {$ENDIF}
447  Set_RC_Name(AWinControl, Widget);
448
449  TGtkPrivateListClass(WSPrivate).SetCallbacks(Widget, WidgetInfo);
450end;
451
452class function TGtkWSCustomListBox.GetIndexAtXY(
453  const ACustomListBox: TCustomListBox; X, Y: integer): integer;
454var
455  ScrolledWindow: PGtkScrolledWindow;
456  VertAdj: PGTKAdjustment;
457  AdjValue: integer;
458  ListWidget: PGtkList;
459  AWidget: PGtkWidget;
460  GListItem: PGList;
461  ListItemWidget: PGtkWidget;
462begin
463  Result:=-1;
464
465  if ACustomListBox.FCompStyle in [csListBox, csCheckListBox] then
466  begin
467    AWidget:=PGtkWidget(ACustomListBox.Handle);
468    ListWidget:=PGtkList(GetWidgetInfo(AWidget, True)^.CoreWidget);
469    ScrolledWindow:=PGtkScrolledWindow(AWidget);
470    VertAdj:=gtk_scrolled_window_get_vadjustment(ScrolledWindow);
471    if VertAdj=nil then
472      AdjValue:=y
473    else
474      AdjValue:=RoundToInt(VertAdj^.value)+y;
475    GListItem:=ListWidget^.children;
476    while GListItem<>nil do begin
477      inc(Result);
478      ListItemWidget:=PGtkWidget(GListItem^.data);
479      dec(AdjValue,ListItemWidget^.Allocation.Height);
480      if AdjValue<0 then exit;
481      GListItem:=GListItem^.next;
482    end;
483    Result:=-1;
484  end;
485end;
486
487class function TGtkWSCustomListBox.GetItemIndex(const ACustomListBox: TCustomListBox
488  ): integer;
489var
490  Widget: PGtkWidget;// pointer to gtk-widget
491  GList : pGList;    // Only used for listboxes, replace with widget!!!!!
492  Handle: HWND;
493begin
494  Handle := ACustomListBox.Handle;
495  {!$IFdef GTK1}
496  if Handle<>0 then
497  begin
498    Widget := nil;
499    if Widget = nil then
500    begin
501      GList:= PGtkList(GetWidgetInfo(Pointer(Handle), True)^.
502                        CoreWidget)^.selection;
503      if GList <> nil then
504        Widget:= PGtkWidget(GList^.data);
505    end;
506    if Widget = nil then
507      Result:= -1
508    else
509      Result:= gtk_list_child_position(PGtkList(
510                    GetWidgetInfo(Pointer(Handle), True)^.
511                                  CoreWidget), Widget);
512  end
513  else
514     Result:=-1;
515  {!$EndIf}
516end;
517
518class function TGtkWSCustomListBox.GetItemRect(
519  const ACustomListBox: TCustomListBox; Index: integer; var ARect: TRect
520  ): boolean;
521var
522  ScrolledWindow: PGtkScrolledWindow;
523  VertAdj: PGTKAdjustment;
524  AdjValue: integer;
525  ListWidget: PGtkList;
526  AWidget: PGtkWidget;
527  GListItem: PGList;
528  ListItemWidget: PGtkWidget;
529begin
530  Result:=false;
531  FillChar(ARect,SizeOf(ARect),0);
532
533  if ACustomListBox.FCompStyle in [csListBox, csCheckListBox] then
534  begin
535    AWidget:=PGtkWidget(ACustomListBox.Handle);
536    ListWidget:=PGtkList(GetWidgetInfo(AWidget, True)^.CoreWidget);
537    ScrolledWindow:=PGtkScrolledWindow(AWidget);
538    VertAdj:=gtk_scrolled_window_get_vadjustment(ScrolledWindow);
539
540    if VertAdj=nil then
541      AdjValue:=0
542    else
543      AdjValue:= (-RoundToInt(VertAdj^.value));
544
545    GListItem:=ListWidget^.children;
546    while GListItem<>nil do
547    begin
548      ListItemWidget:=PGtkWidget(GListItem^.data);
549      if Index=0 then
550      begin
551        ARect.Left:=0;
552        ARect.Top:=AdjValue;
553        ARect.Right:=ListItemWidget^.Allocation.Width;
554        ARect.Bottom:=ARect.Top+ListItemWidget^.Allocation.Height;
555        Result:=true;
556        exit;
557      end;
558      inc(AdjValue,ListItemWidget^.Allocation.Height);
559      dec(Index);
560      GListItem:=GListItem^.next;
561    end;
562  end;
563end;
564
565class function  TGtkWSCustomListBox.GetSelCount(const ACustomListBox: TCustomListBox
566  ): integer;
567var
568  Handle: HWND;
569begin
570  Handle := ACustomListBox.Handle;
571
572  Result := g_list_length(PGtkList(GetWidgetInfo(Pointer(Handle),
573     True)^.CoreWidget)^.selection);
574end;
575
576class function TGtkWSCustomListBox.GetSelected(const ACustomListBox: TCustomListBox;
577  const AIndex: integer): boolean;
578var
579  Handle: HWND;
580  Widget      : PGtkWidget; // pointer to gtk-widget (local use when neccessary)
581  //GList       : pGList;     // Only used for listboxes, replace with widget!!!!!
582  ListItem    : PGtkListItem;// currently only used for listboxes
583begin
584  Result := false;      { assume: nothing found }
585  Handle := ACustomListBox.Handle;
586
587  { Get the child in question of that index }
588  Widget:=GetWidgetInfo(Pointer(Handle),True)^.CoreWidget;
589  ListItem:= g_list_nth_data(PGtkList(Widget)^.children, AIndex);
590  if (ListItem<>nil)
591  and (g_list_index(PGtkList(Widget)^.selection, ListItem)>=0)
592  then Result:=true
593
594  //if CompareText(ACustomListBox.Name,'LBProperties')=0 then
595  //  debugln('TGtkWSCustomListBox.GetSelected ',DbgSName(ACustomListBox),' Index=',dbgs(AIndex),' Selected=',dbgs(Result));
596end;
597
598class function  TGtkWSCustomListBox.GetStrings(const ACustomListBox: TCustomListBox
599  ): TStrings;
600var
601  Widget: PGtkWidget;// pointer to gtk-widget
602  Handle: HWND;
603begin
604  Handle := ACustomListBox.Handle;
605
606  Widget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget;
607  Result := TGtkListStringList.Create(PGtkList(Widget),
608    ACustomListBox, ACustomListBox.fCompStyle = csCheckListBox);
609  if ACustomListBox is TCustomListBox then
610    TGtkListStringList(Result).Sorted := ACustomListBox.Sorted;
611end;
612
613class function  TGtkWSCustomListBox.GetTopIndex(const ACustomListBox: TCustomListBox): integer;
614begin
615  Result := GetIndexAtXY(ACustomListBox, 0, 0);
616end;
617
618class procedure TGtkWSCustomListBox.SelectItem(const ACustomListBox: TCustomListBox;
619  AIndex: integer; ASelected: boolean);
620var
621  Widget: PGtkWidget;// pointer to gtk-widget (local use when neccessary)
622  Handle: HWND;
623begin
624  //if CompareText(ACustomListBox.Name,'LBProperties')=0 then
625  //  debugln('TGtkWSCustomListBox.SelectItem ',DbgSName(ACustomListBox),' Index=',dbgs(AIndex),' Selected=',dbgs(ASelected));
626  Handle := ACustomListBox.Handle;
627
628  Widget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget;
629  if ASelected then gtk_list_select_item(PGtkList(Widget), AIndex)
630  else gtk_list_unselect_item(PGtkList(Widget), AIndex);
631end;
632
633class procedure TGtkWSCustomListBox.SetBorder(const ACustomListBox: TCustomListBox);
634var
635  Handle: HWND;
636  Widget: PGtkWidget;// pointer to gtk-widget
637begin
638  Handle := ACustomListBox.Handle;
639  Widget:= PGtkWidget(PGtkBin(Handle)^.child);
640  gtk_viewport_set_shadow_type(PGtkViewPort(Widget), BorderStyleShadowMap[ACustomListBox.BorderStyle]);
641end;
642
643class procedure TGtkWSCustomListBox.SetItemIndex(const ACustomListBox: TCustomListBox;
644  const AIndex: integer);
645var
646  Handle: HWND;
647  Widget: PGtkWidget;
648begin
649  //if CompareText(ACustomListBox.Name,'LBProperties')=0 then
650  //  debugln('TGtkWSCustomListBox.SetItemIndex ',DbgSName(ACustomListBox),' Index=',dbgs(AIndex));
651  Handle := ACustomListBox.Handle;
652  if Handle<>0 then
653  begin
654    LockOnChange(PGtkObject(Handle),+1);
655    Widget:=GetWidgetInfo(Pointer(Handle),True)^.CoreWidget;
656
657    if AIndex >= 0 then
658      gtk_list_select_item(PGtkList(Widget), AIndex)
659    else
660      gtk_list_unselect_all(PGtkList(Widget));
661
662    LockOnChange(PGtkObject(Handle),-1);
663  end;
664end;
665
666class procedure TGtkWSCustomListBox.SetSelectionMode(
667  const ACustomListBox: TCustomListBox;
668  const AExtendedSelect, AMultiSelect: boolean);
669begin
670  //if CompareText(ACustomListBox.Name,'LBProperties')=0 then
671  //  debugln('TGtkWSCustomListBox.SetSelectionMode ',DbgSName(ACustomListBox));
672  TGtkWidgetSet(WidgetSet).SetSelectionMode(ACustomListBox,
673    PGtkWidget(ACustomListBox.Handle), AMultiSelect, AExtendedSelect);
674end;
675
676class procedure TGtkWSCustomListBox.SetSorted(const ACustomListBox: TCustomListBox;
677  AList: TStrings; ASorted: boolean);
678begin
679  //if CompareText(ACustomListBox.Name,'LBProperties')=0 then
680  //  debugln('TGtkWSCustomListBox.SetSorted ',DbgSName(ACustomListBox));
681  if AList is TGtkListStringList then
682    TGtkListStringList(AList).Sorted := ASorted
683  else
684    raise Exception.Create('');
685end;
686
687class procedure TGtkWSCustomListBox.SetTopIndex(
688  const ACustomListBox: TCustomListBox; const NewTopIndex: integer);
689var
690  ScrolledWindow: PGtkScrolledWindow;
691  VertAdj: PGTKAdjustment;
692  AdjValue, MaxAdjValue: integer;
693  ListWidget: PGtkList;
694  AWidget: PGtkWidget;
695  GListItem: PGList;
696  ListItemWidget: PGtkWidget;
697  i: Integer;
698  requisition: TGtkRequisition;
699begin
700  //if CompareText(ACustomListBox.Name,'LBProperties')=0 then
701  //  debugln('TGtkWSCustomListBox.SetTopIndex ',DbgSName(ACustomListBox));
702  AWidget:=PGtkWidget(ACustomListBox.Handle);
703  ListWidget:=PGtkList(GetWidgetInfo(AWidget, True)^.CoreWidget);
704  ScrolledWindow:=PGtkScrolledWindow(AWidget);
705  AdjValue:=0;
706  GListItem:=ListWidget^.children;
707  i:=0;
708  while GListItem<>nil do begin
709    ListItemWidget:=PGtkWidget(GListItem^.data);
710    if i>=NewTopIndex then break;
711    if ListItemWidget<>nil then begin
712      gtk_widget_size_request(ListItemWidget,@requisition);
713      inc(AdjValue,requisition.height);
714    end;
715    //DebugLn(['TGtkWSCustomListBox.SetTopIndex ',i,' AdjValue=',AdjValue,' Flags=',WidgetFlagsToString(ListItemWidget)]);
716    inc(i);
717    GListItem:=GListItem^.next;
718  end;
719  VertAdj:=gtk_scrolled_window_get_vadjustment(ScrolledWindow);
720  MaxAdjValue:=RoundToInt(VertAdj^.upper);
721  if AdjValue>MaxAdjValue then AdjValue:=MaxAdjValue;
722  //DebugLn(['TGtkWSCustomListBox.SetTopIndex AdjValue=',AdjValue,' VertAdj^.upper=',VertAdj^.upper,' VertAdj^.page_size=',VertAdj^.page_size]);
723  gtk_adjustment_set_value(VertAdj,AdjValue);
724end;
725
726class procedure TGtkWSCustomListBox.SetColor(const AWinControl: TWinControl);
727var
728  AWidget, ListWidget: PGTKWidget;
729begin
730  if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit;
731  AWidget := PGtkWidget(AWinControl.Handle);
732  ListWidget := GetWidgetInfo(AWidget, True)^.CoreWidget;
733  GtkWidgetSet.SetWidgetColor(ListWidget, AWinControl.Font.Color,
734    AWinControl.Color,
735    [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,
736     GTK_STYLE_BASE]);
737end;
738
739class procedure TGtkWSCustomListBox.SetFont(const AWinControl: TWinControl;
740  const AFont: TFont);
741var
742  Widget: PGtkWidget;
743  GList: PGList;
744  ChildWidget: PGTKLabel;
745begin
746  if not AWinControl.HandleAllocated then exit;
747
748  { Get the selections }
749  Widget := GetWidgetInfo(Pointer(AWinControl.Handle))^.CoreWidget;
750  GList :=  PGtkList(Widget)^.children;
751  while Assigned(GList) do
752  begin
753    //  DebugLn('TGtkWSCustomListBox.SetFont for item ',PGTKLabel(PGtkBin(GList^.data)^.child)^.thelabel);
754    ChildWidget := PGTKLabel(PGtkBin(GList^.data)^.child);
755
756    GtkWidgetSet.SetWidgetColor(PGtkWidget(ChildWidget), AFont.Color, clNone,
757      [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
758      GtkWidgetSet.SetWidgetFont(PGtkWidget(ChildWidget), AFont);
759      GList := GList^.Next;
760  end;
761end;
762
763{$ENDIF}
764
765
766{ TGtkWSCustomComboBox }
767
768{$IFDEF GTK1}
769
770function gtkComboBoxChanged(Widget: PGtkWidget; Info: PWidgetInfo): GBoolean; cdecl;
771var
772  Mess : TLMessage;
773  GtkComboWidget: PGtkCombo;
774  GtkListWidget: PGtkList;
775  LCLIndex: PInteger;
776  GtkIndex: Integer;
777begin
778  Result := CallBackDefaultReturn;
779
780  if ComponentIsDestroyingHandle(TWinControl(Info^.LCLObject)) or
781     (Info^.ChangeLock > 0) or
782     (gtk_signal_n_emissions_by_name(PGtkObject(widget), 'changed') > 1) or
783     (GTK_WIDGET_VISIBLE(PGtkCombo(Info^.CoreWidget)^.popwin)) then exit;
784
785  {$IFDEF EventTrace}
786  EventTrace('changed', Info^.LCLObject);
787  {$ENDIF}
788
789  FillChar(Mess, SizeOf(Mess), 0);
790  Mess.Msg := LM_CHANGED;
791  DeliverMessage(Info^.LCLObject, Mess);
792
793  GtkComboWidget := PGtkCombo(Info^.CoreWidget);
794  GtkListWidget := PGtkList(GtkComboWidget^.list);
795  LCLIndex := PInteger(Info^.UserData);
796
797  //Check if an item is selected
798  if (GtkListWidget^.selection <> nil) then
799  begin
800    GtkIndex := gtk_list_child_position(GtkListWidget,
801      PGtkWidget(GtkListWidget^.selection^.data));
802    //If the selected item index changed send a LM_SELCHANGE msg
803    if LCLIndex^ <> GtkIndex then
804    begin
805      gtk_list_set_selection_mode(GtkListWidget, GTK_SELECTION_BROWSE);
806      LCLIndex^ := GtkIndex;
807      Mess.Msg := LM_SELCHANGE;
808      DeliverMessage(Info^.LCLObject, Mess);
809    end;
810  end
811  else
812  begin
813    LCLIndex^ := -1;
814    gtk_list_set_selection_mode(GtkListWidget, GTK_SELECTION_SINGLE);
815  end;
816end;
817
818class function TGtkWSCustomComboBox.GetDroppedDown(
819  const ACustomComboBox: TCustomComboBox): Boolean;
820var
821  ComboWidget: PGtkCombo;
822begin
823  if not WSCheckHandleAllocated(ACustomComboBox, 'GetDroppedDown') then
824    Exit(False);
825  ComboWidget:=PGtkCombo(ACustomComboBox.Handle);
826  Result := GTK_WIDGET_VISIBLE(ComboWidget^.popwin);
827end;
828
829class procedure TGtkWSCustomComboBox.SetDroppedDown(
830  const ACustomComboBox: TCustomComboBox; ADroppedDown: Boolean);
831
832  procedure gtk_combo_get_pos(combo : PGtkCombo; var x : gint; var  y : gint;
833    var height : gint; var width : gint);
834  var
835    popwin : PGtkbin;
836    widget : PGtkWidget;
837    popup : PGtkScrolledwindow;
838    real_height : gint;
839    list_requisition : PGtkRequisition;
840    show_hscroll : gboolean;
841    show_vscroll : gboolean;
842    avail_height : gint;
843    min_height : gint;
844    alloc_width : gint;
845    work_height : gint;
846    old_height : gint;
847    old_width : gint;
848    okay_to_exit : boolean;
849  const
850    EMPTY_LIST_HEIGHT = 15;
851  begin
852    show_hscroll := False;
853    show_vscroll := False;
854
855    widget := GTK_WIDGET(combo);
856    popup  := GTK_SCROLLED_WINDOW (combo^.popup);
857    popwin := GTK_BIN (combo^.popwin);
858
859    gdk_window_get_origin (combo^.entry^.window, @x, @y);
860
861    real_height := MIN (combo^.entry^.requisition.height,
862                    combo^.entry^.allocation.height);
863    y := y + real_height;
864
865    avail_height := gdk_screen_height () - y;
866
867    New(list_requisition);
868    if combo^.list<>nil then begin
869      gtk_widget_size_request (combo^.list, list_requisition);
870    end else begin
871      list_requisition^.height:=1;
872      list_requisition^.width:=1;
873    end;
874
875    min_height := MIN (list_requisition^.height,popup^.vscrollbar^.requisition.height);
876    if  GTK_LIST (combo^.list)^.children = nil then
877      list_requisition^.height := list_requisition^.height + EMPTY_LIST_HEIGHT;
878
879    alloc_width := (cardinal(widget^.allocation.width) -
880      2 * cardinal(gtk_widget_get_xthickness(gtk_bin_get_child(popwin))) -
881      2 * border_width(GTK_CONTAINER (gtk_bin_get_child(popwin))^) -
882      2 * border_width(GTK_CONTAINER (combo^.popup)^) -
883      2 * border_width(GTK_CONTAINER (gtk_bin_get_child(PGTKBin(popup)))^) -
884      2 * cardinal(gtk_widget_get_xthickness(gtk_bin_get_child(PGTKBin(popup)))));
885
886    work_height := (2 * cardinal(gtk_widget_get_ythickness(gtk_bin_get_child(popwin))) +
887      2 * border_width(GTK_CONTAINER (gtk_bin_get_child(popwin))^) +
888      2 * border_width(GTK_CONTAINER (combo^.popup)^) +
889      2 * border_width(GTK_CONTAINER (gtk_bin_get_child(PGTKBin(popup)))^) +
890      2 * cardinal(gtk_widget_get_xthickness(gtk_bin_get_child(PGTKBin(popup)))));
891
892    repeat
893      okay_to_exit := True;
894      old_width := alloc_width;
895      old_height := work_height;
896
897      if ((not show_hscroll) and (alloc_width < list_requisition^.width)) then
898      begin
899           work_height := work_height +  popup^.hscrollbar^.requisition.height +
900          GTK_SCROLLED_WINDOW_CLASS(gtk_object_get_class(combo^.popup))^.scrollbar_spacing;
901        show_hscroll := TRUE;
902        okay_to_exit := False;
903      end;
904      if ((not show_vscroll) and (work_height + list_requisition^.height > avail_height)) then
905      begin
906        if ((work_height + min_height > avail_height) and (y - real_height > avail_height)) then
907        begin
908          y := y - (work_height + list_requisition^.height + real_height);
909          break;
910        end;
911        alloc_width := alloc_width -
912          popup^.vscrollbar^.requisition.width +
913          GTK_SCROLLED_WINDOW_CLASS(gtk_object_get_class(combo^.popup))^.scrollbar_spacing;
914        show_vscroll := TRUE;
915        okay_to_exit := False;
916      end;
917    until ((old_width <> alloc_width) or (old_height <> work_height) or okay_to_exit);
918
919    width := widget^.allocation.width;
920    if (show_vscroll) then
921      height := avail_height
922    else
923      height := work_height + list_requisition^.height;
924    if (x < 0) then
925      x := 0;
926
927    Dispose(list_requisition);
928  end;
929
930var
931  ComboWidget: PGtkCombo;
932  height, width, x, y : gint;
933  old_width, old_height : gint;
934begin
935  if not WSCheckHandleAllocated(ACustomComboBox, 'SetDroppedDown') then Exit;
936  ComboWidget:=PGtkCombo(ACustomComboBox.Handle);
937  if ADroppedDown<>GTK_WIDGET_VISIBLE(ComboWidget^.popwin) then begin
938    if ADroppedDown then begin
939      old_width := ComboWidget^.popwin^.allocation.width;
940      old_height := ComboWidget^.popwin^.allocation.height;
941      gtk_combo_get_pos(ComboWidget,x,y,height,width);
942      if ((old_width <> width) or (old_height <> height)) then
943      begin
944        gtk_widget_hide (GTK_SCROLLED_WINDOW(ComboWidget^.popup)^.hscrollbar);
945        gtk_widget_hide (GTK_SCROLLED_WINDOW(ComboWidget^.popup)^.vscrollbar);
946      end;
947      gtk_widget_set_uposition (comboWidget^.popwin,x, y);
948      gtk_widget_set_usize(ComboWidget^.popwin,width ,height);
949      gtk_widget_realize(ComboWidget^.popwin);
950
951      {$IFDEF DebugGDKTraps}
952      BeginGDKErrorTrap;
953      {$ENDIF}
954      gdk_window_resize(ComboWidget^.popwin^.window,width,height);
955      {$IFDEF DebugGDKTraps}
956      EndGDKErrorTrap;
957      {$ENDIF}
958
959      gtk_widget_show (ComboWidget^.popwin);
960      gtk_widget_grab_focus(ComboWidget^.popwin);
961    end else
962      gtk_widget_hide (ComboWidget^.popwin);
963  end;
964end;
965
966class procedure TGtkWSCustomComboBox.SetCallbacks(const AGtkWidget: PGtkWidget;
967  const AWidgetInfo: PWidgetInfo);
968begin
969  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
970  with TGtkWidgetset(Widgetset) do
971  begin
972    //gtk1 and gtk2 have different 'changed' event handlers
973    g_signal_connect(PGtkObject(PGtkCombo(AGtkWidget)^.entry),
974      'changed', TGTKSignalFunc(@gtkComboBoxChanged), AWidgetInfo);
975    g_signal_connect(PGtkObject(PGtkCombo(AGtkWidget)^.popwin),
976      'hide', TGTKSignalFunc(@gtkComboBoxChanged), AWidgetInfo);
977    SetCallback(LM_COMMAND, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
978  end;
979end;
980
981class function TGtkWSCustomComboBox.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle;
982var
983  ComboBox: TComboBox absolute AWinControl;
984  Widget: PGtkWidget;
985  WidgetInfo: PWidgetInfo;
986  ComboWidget: PGtkCombo absolute Widget;
987
988  ItemList: TGtkListStringList;
989  GtkList: PGtkList;
990  Allocation: TGtkAllocation;
991  LCLIndex: PInteger;
992begin
993  Widget := gtk_combo_new();
994
995  SetMainWidget(Widget, ComboWidget^.entry);
996  SetMainWidget(Widget, ComboWidget^.button);
997
998  gtk_combo_disable_activate(ComboWidget);
999  gtk_combo_set_case_sensitive(ComboWidget, GdkTrue);
1000
1001  GtkList:=PGtkList(ComboWidget^.List);
1002
1003  // Items
1004  ItemList:= TGtkListStringList.Create(GtkList, ComboBox, False);
1005  gtk_object_set_data(PGtkObject(Widget), GtkListItemLCLListTag, ItemList);
1006  ItemList.Assign(ComboBox.Items);
1007  ItemList.Sorted:= ComboBox.Sorted;
1008
1009  WidgetInfo := CreateWidgetInfo(Widget, AWinControl, AParams);
1010  New(LCLIndex);
1011  WidgetInfo^.UserData := LCLIndex;
1012  WidgetInfo^.DataOwner := True;
1013
1014  // ItemIndex
1015
1016  // Switching the selection mode is necessary to avoid the following problems:
1017  // - The first added item is automatically selected when mode is "BROWSE"
1018  // - Is not possible to select the previous selected item if mode is "BROWSE"
1019  //   and current index is -1
1020  // - The item is deselected after a second click if mode is "SINGLE"
1021  // - The OnSelect event could be fired after add the first item when mode is
1022  //   "BROWSE". Since LM_SELCHANGE is sent in 'changed' event now, no problem.
1023  // So basically the mode is set to BROWSE when a item is selected and
1024  //   "SINGLE" when there's no item selected
1025  if ComboBox.ItemIndex >= 0 then
1026  begin
1027    gtk_list_set_selection_mode(GtkList, GTK_SELECTION_BROWSE);
1028    gtk_list_select_item(GtkList, ComboBox.ItemIndex);
1029    LCLIndex^ := ComboBox.ItemIndex;
1030  end
1031  else
1032  begin
1033    gtk_list_set_selection_mode(GtkList, GTK_SELECTION_SINGLE);
1034    LCLIndex^ := -1;
1035  end;
1036
1037  // MaxLength
1038  gtk_entry_set_max_length(PGtkEntry(ComboWidget^.entry),guint16(ComboBox.MaxLength));
1039
1040  {$IFDEF DebugLCLComponents}
1041  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
1042  {$ENDIF}
1043  Result := THandle(PtrUInt(Widget));
1044
1045
1046  Allocation.X := AParams.X;
1047  Allocation.Y := AParams.Y;
1048  Allocation.Width := AParams.Width;
1049  Allocation.Height := AParams.Height;
1050  gtk_widget_size_allocate(Widget, @Allocation);
1051
1052  Set_RC_Name(AWinControl, Widget);
1053  SetCallbacks(Widget, WidgetInfo);
1054end;
1055
1056class function  TGtkWSCustomComboBox.GetSelStart(
1057  const ACustomComboBox: TCustomComboBox): integer;
1058begin
1059  Result := WidgetGetSelStart(PGtkWidget(PGtkCombo(ACustomComboBox.Handle
1060                              )^.entry));
1061end;
1062
1063class function  TGtkWSCustomComboBox.GetSelLength(
1064  const ACustomComboBox: TCustomComboBox): integer;
1065begin
1066  with PGtkOldEditable(PGtkCombo(ACustomComboBox.Handle)^.entry)^ do begin
1067    Result:= Abs(integer(selection_end_pos)-integer(selection_start_pos));
1068  end;
1069end;
1070
1071class function TGtkWSCustomComboBox.GetText(const AWinControl: TWinControl;
1072  var AText: String): Boolean;
1073begin
1074  //DebugLn('TGtkWSCustomComboBox.GetText ',DbgSName(ACustomComboBox),' ',GetWidgetDebugReport(PGtkWidget(ACustomComboBox.Handle)));
1075  AText := gtk_entry_get_text(PGtkEntry(PGtkCombo(AWinControl.Handle)^.entry));
1076  //if AWinControl.Name='FileExtensionsComboBox' then
1077  //  DebugLn('TGtkWSCustomComboBox.GetText ',DbgSName(AWinControl),' ',GetWidgetDebugReport(PGtkWidget(AWinControl.Handle)),' AText="',AText,'"');
1078  Result:=true;
1079end;
1080
1081class function TGtkWSCustomComboBox.GetItemIndex(
1082  const ACustomComboBox: TCustomComboBox): integer;
1083var
1084  ListWidget: PGtkList;
1085begin
1086  //DebugLn('TGtkWSCustomComboBox.GetItemIndex ',DbgSName(ACustomComboBox),' ',GetWidgetDebugReport(PGtkWidget(ACustomComboBox.Handle)));
1087  ListWidget := PGtkList(PGtkCombo(ACustomComboBox.Handle)^.list);
1088  if ListWidget^.selection <> nil then
1089    Result := gtk_list_child_position(ListWidget, ListWidget^.selection^.data)
1090  else
1091    Result := -1;
1092end;
1093
1094class function  TGtkWSCustomComboBox.GetMaxLength(
1095  const ACustomComboBox: TCustomComboBox): integer;
1096begin
1097  Result:= PGtkEntry(PGtkCombo(ACustomComboBox.Handle)^.entry)^.text_max_length;
1098end;
1099
1100class procedure TGtkWSCustomComboBox.SetArrowKeysTraverseList(
1101  const ACustomComboBox: TCustomComboBox;
1102  NewTraverseList: boolean);
1103var
1104  GtkCombo: PGtkCombo;
1105begin
1106  GtkCombo := GTK_COMBO(Pointer(ACustomComboBox.Handle));
1107  if ACustomComboBox.ArrowKeysTraverseList then
1108  begin
1109    gtk_combo_set_use_arrows(GtkCombo,GdkTrue);
1110  end else
1111  begin
1112    gtk_combo_set_use_arrows(GtkCombo,GdkFalse);
1113  end;
1114end;
1115
1116class procedure TGtkWSCustomComboBox.SetSelStart(
1117  const ACustomComboBox: TCustomComboBox; NewStart: integer);
1118begin
1119  if NewStart < 0 then NewStart := 0; // prevent SegFault in gtk
1120  gtk_editable_set_position(
1121           PGtkOldEditable(PGtkCombo(ACustomComboBox.Handle)^.entry), NewStart);
1122end;
1123
1124class procedure TGtkWSCustomComboBox.SetSelLength(
1125  const ACustomComboBox: TCustomComboBox; NewLength: integer);
1126begin
1127  WidgetSetSelLength(PGtkCombo(ACustomComboBox.Handle)^.entry, NewLength);
1128end;
1129
1130class procedure TGtkWSCustomComboBox.SetItemIndex(
1131  const ACustomComboBox: TCustomComboBox; NewIndex: integer);
1132var
1133  ComboWidget: PGtkCombo;
1134  WidgetInfo: PWidgetInfo;
1135begin
1136  ComboWidget := PGtkCombo(ACustomComboBox.Handle);
1137  WidgetInfo := GetWidgetInfo(ComboWidget);
1138  //Store the LCLIndex
1139  PInteger(WidgetInfo^.UserData)^ := NewIndex;
1140  //Avoid calling OnChange/OnSelect events
1141  Inc(WidgetInfo^.ChangeLock);
1142  //gtk_list_select_item does not update the list when Index is -1
1143  if NewIndex > -1 then
1144  begin
1145    gtk_list_set_selection_mode(PGtkList(ComboWidget^.list),
1146      GTK_SELECTION_BROWSE);
1147    gtk_list_select_item(PGtkList(ComboWidget^.list), NewIndex);
1148  end
1149  else
1150  begin
1151    gtk_list_set_selection_mode(PGtkList(ComboWidget^.list),
1152      GTK_SELECTION_SINGLE);
1153    gtk_entry_set_text(PGtkEntry(ComboWidget^.entry), '');
1154  end;
1155  Dec(WidgetInfo^.ChangeLock);
1156end;
1157
1158class procedure TGtkWSCustomComboBox.SetMaxLength(
1159  const ACustomComboBox: TCustomComboBox; NewLength: integer);
1160begin
1161  gtk_entry_set_max_length(PGtkEntry(PGtkCombo(ACustomComboBox.Handle)^.entry),
1162                           guint16(NewLength));
1163end;
1164
1165class procedure TGtkWSCustomComboBox.SetStyle(
1166  const ACustomComboBox: TCustomComboBox; NewStyle: TComboBoxStyle);
1167var
1168  GtkCombo: PGtkCombo;
1169begin
1170  GtkCombo := GTK_COMBO(Pointer(ACustomComboBox.Handle));
1171  if not ACustomComboBox.Style.HasEditBox then
1172  begin
1173    // do not set ok_if_empty = true, otherwise it can hang focus
1174    gtk_combo_set_value_in_list(GtkCombo,GdkTrue,GdkTrue);
1175    gtk_combo_set_use_arrows_always(GtkCombo,GdkTrue);
1176    gtk_combo_set_case_sensitive(GtkCombo,GdkFalse);
1177  end
1178  else
1179  begin
1180    // do not set ok_if_empty = true, otherwise it can hang focus
1181    gtk_combo_set_value_in_list(GtkCombo,GdkFalse,GdkTrue);
1182    gtk_combo_set_use_arrows_always(GtkCombo,GdkFalse);
1183    gtk_combo_set_case_sensitive(GtkCombo,GdkTrue);
1184  end;
1185end;
1186
1187class procedure TGtkWSCustomComboBox.SetText(const AWinControl: TWinControl;
1188  const AText: String);
1189var
1190  ComboControl: TCustomComboBox absolute AWinControl;
1191  ComboWidget: PGtkCombo;
1192  WidgetInfo: PWidgetInfo;
1193  i: Integer;
1194begin
1195  if ComboControl.ReadOnly then
1196  begin
1197    i := ComboControl.Items.IndexOf(AText);
1198    TGtkWSCustomComboBox.SetItemIndex(ComboControl, i);
1199  end
1200  else
1201  begin
1202    ComboWidget := PGtkCombo(AWinControl.Handle);
1203    WidgetInfo := GetWidgetInfo(ComboWidget);
1204    // lock combobox, so that no OnChange event is not fired
1205    Inc(WidgetInfo^.ChangeLock);
1206    // set text
1207    // The String > PChar conversion ensures at least a null terminated string
1208    gtk_entry_set_text(PGtkEntry(ComboWidget^.entry), PChar(AText));
1209    // unlock combobox
1210    Dec(WidgetInfo^.ChangeLock);
1211  end;
1212end;
1213
1214class function  TGtkWSCustomComboBox.GetItems(
1215  const ACustomComboBox: TCustomComboBox): TStrings;
1216begin
1217  Result := TStrings(gtk_object_get_data(PGtkObject(ACustomComboBox.Handle),
1218                                         GtkListItemLCLListTag));
1219end;
1220
1221class procedure TGtkWSCustomComboBox.Sort(const ACustomComboBox: TCustomComboBox;
1222  AList: TStrings; IsSorted: boolean);
1223begin
1224  TGtkListStringList(AList).Sorted := IsSorted;
1225end;
1226
1227class procedure TGtkWSCustomComboBox.SetColor(const AWinControl: TWinControl);
1228var
1229  AWidget, EntryWidget: PGTKWidget;
1230begin
1231  if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit;
1232  AWidget := PGtkWidget(AWinControl.Handle);
1233  EntryWidget := PGtkCombo(AWidget)^.entry;
1234  GtkWidgetSet.SetWidgetColor(EntryWidget, AWinControl.Font.Color, AWinControl.Color,
1235    [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,GTK_STYLE_BASE]);
1236end;
1237
1238class procedure TGtkWSCustomComboBox.SetFont(const AWinControl: TWinControl;
1239  const AFont: TFont);
1240var
1241  AWidget: PGTKWidget;
1242  EntryWidget: PGtkWidget;
1243begin
1244  if not AWinControl.HandleAllocated then exit;
1245
1246  AWidget := PGtkWidget(AWinControl.Handle);
1247  EntryWidget := PGtkCombo(AWidget)^.entry;
1248
1249  if EntryWidget<>nil then
1250  begin
1251    GtkWidgetSet.SetWidgetColor(EntryWidget, AFont.Color, clNone,
1252       [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
1253    GtkWidgetSet.SetWidgetFont(EntryWidget, AFont);
1254  end;
1255end;
1256{$ENDIF}
1257
1258{ TGtkWSCustomEdit }
1259
1260class procedure TGtkWSCustomEdit.SetCallbacks(const AGtkWidget: PGtkWidget;
1261  const AWidgetInfo: PWidgetInfo);
1262begin
1263  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
1264
1265  with TGtkWidgetset(Widgetset) do
1266  begin
1267    SetCallback(LM_CHANGED, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1268    SetCallback(LM_ACTIVATE, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1269    SetCallback(LM_CUT, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1270    SetCallback(LM_COPY, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1271    SetCallback(LM_PASTE, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1272  end;
1273end;
1274
1275class function TGtkWSCustomEdit.CreateHandle(const AWinControl: TWinControl;
1276  const AParams: TCreateParams): TLCLIntfHandle;
1277var
1278  Widget: PGtkWidget; // ptr to the newly created GtkWidget
1279  WidgetInfo: PWidgetInfo;
1280begin
1281  Widget := gtk_entry_new();
1282  gtk_editable_set_editable(PGtkEditable(Widget), not TCustomEdit(AWinControl).ReadOnly);
1283  gtk_widget_show_all(Widget);
1284  Result := TLCLIntfHandle(PtrUInt(Widget));
1285  {$IFDEF DebugLCLComponents}
1286  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
1287  {$ENDIF}
1288  if Result = 0 then
1289    Exit;
1290  WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams);
1291  Set_RC_Name(AWinControl, Widget);
1292  SetCallbacks(Widget, WidgetInfo);
1293end;
1294
1295class function  TGtkWSCustomEdit.GetSelStart(const ACustomEdit: TCustomEdit): integer;
1296begin
1297  Result := WidgetGetSelStart(GetWidgetInfo(Pointer(ACustomEdit.Handle),
1298                              true)^.CoreWidget);
1299end;
1300
1301class function TGtkWSCustomEdit.GetSelLength(const ACustomEdit: TCustomEdit): integer;
1302begin
1303  with PGtkOldEditable(GetWidgetInfo(Pointer(ACustomEdit.Handle), true)^.
1304    CoreWidget)^ do
1305  begin
1306    Result:=Abs(integer(selection_end_pos)-integer(selection_start_pos));
1307  end;
1308end;
1309
1310class procedure TGtkWSCustomEdit.SetCharCase(const ACustomEdit: TCustomEdit;
1311  NewCase: TEditCharCase);
1312begin
1313  // TODO: implement me!
1314end;
1315
1316class procedure TGtkWSCustomEdit.SetEchoMode(const ACustomEdit: TCustomEdit;
1317  NewMode: TEchoMode);
1318begin
1319  // XXX TODO: GTK 1.x does not support EchoMode emNone.
1320  // This will have to be coded around, but not a priority
1321  SetPasswordChar(ACustomEdit, ACustomEdit.PasswordChar);
1322end;
1323
1324class procedure TGtkWSCustomEdit.SetMaxLength(const ACustomEdit: TCustomEdit;
1325  NewLength: integer);
1326var
1327  Widget: PGtkWidget;
1328begin
1329  Widget:=PGtkWidget(ACustomEdit.Handle);
1330  if GtkWidgetIsA(Widget, GTK_TYPE_ENTRY) then
1331    gtk_entry_set_max_length(GTK_ENTRY(Widget), guint16(NewLength));
1332end;
1333
1334class procedure TGtkWSCustomEdit.SetPasswordChar(const ACustomEdit: TCustomEdit;
1335  NewChar: char);
1336var
1337  Widget: PGtkWidget;
1338begin
1339  Widget:=PGtkWidget(ACustomEdit.Handle);
1340  if GtkWidgetIsA(Widget, GTK_TYPE_ENTRY) then
1341    gtk_entry_set_visibility(GTK_ENTRY(Widget),
1342      (ACustomEdit.EchoMode = emNormal) and (NewChar = #0));
1343end;
1344
1345class procedure TGtkWSCustomEdit.SetReadOnly(const ACustomEdit: TCustomEdit;
1346  NewReadOnly: boolean);
1347var
1348  Widget: PGtkWidget;
1349begin
1350  Widget := PGtkWidget(ACustomEdit.Handle);
1351  if GtkWidgetIsA(Widget, GTK_TYPE_ENTRY) then
1352    gtk_entry_set_editable(GTK_ENTRY(Widget), not NewReadOnly);
1353end;
1354
1355class procedure TGtkWSCustomEdit.SetSelStart(const ACustomEdit: TCustomEdit;
1356  NewStart: integer);
1357var
1358  Widget: PGtkWidget;
1359  MaxPos: Integer;
1360begin
1361  Widget:=GetWidgetInfo(Pointer(ACustomEdit.Handle), true)^.CoreWidget;
1362  if WidgetGetSelStart(Widget)=NewStart then exit;
1363  // sometimes the gtk freezes the memo, changes something and emits the change
1364  // event. Then the LCL gets notified and wants to react: force thaw (unfreeze)
1365  if GTK_IS_TEXT(Widget) then
1366  begin
1367    gtk_text_thaw(PGtkText(Widget));
1368    MaxPos := gtk_text_get_length(PGtkText(Widget));
1369  end
1370  else
1371  if GTK_IS_ENTRY(Widget) then
1372    MaxPos := PGtkEntry(Widget)^.text_length
1373  else
1374    MaxPos := 0;
1375  gtk_editable_set_position(PGtkOldEditable(Widget), Min(NewStart, MaxPos));
1376  WidgetSetSelLength(Widget,0); // Setting the selection start should cancel any selection
1377end;
1378
1379class procedure TGtkWSCustomEdit.SetSelLength(const ACustomEdit: TCustomEdit;
1380  NewLength: integer);
1381begin
1382  WidgetSetSelLength(GetWidgetInfo(Pointer(ACustomEdit.Handle),true)^.CoreWidget,
1383                     NewLength);
1384end;
1385
1386class procedure TGtkWSCustomEdit.SetText(const AWinControl: TWinControl;
1387  const AText: string);
1388var
1389  Widget: PGtkWidget;
1390  Mess : TLMessage;
1391begin
1392  if not WSCheckHandleAllocated(AWinControl, 'SetText') then
1393    Exit;
1394  {$IFDEF VerboseTWinControlRealText}
1395  DebugLn(['TGtkWSCustomEdit.SetText START ',DbgSName(AWinControl),' AText="',AText,'"']);
1396  {$ENDIF}
1397  Widget:=PGtkWidget(AWinControl.Handle);
1398  // some gtk2 versions fire the change event twice
1399  // lock the event and send the message afterwards
1400  // see bug http://bugs.freepascal.org/view.php?id=14615
1401  LockOnChange(PgtkObject(Widget), +1);
1402  try
1403    gtk_entry_set_text(PGtkEntry(Widget), PChar(AText));
1404  finally
1405    LockOnChange(PgtkObject(Widget), -1);
1406  end;
1407  {$IFDEF VerboseTWinControlRealText}
1408  DebugLn(['TGtkWSCustomEdit.SetText SEND TEXTCHANGED message ',DbgSName(AWinControl),' New="',gtk_entry_get_text(PGtkEntry(AWinControl.Handle)),'"']);
1409  {$ENDIF}
1410  FillByte(Mess,SizeOf(Mess),0);
1411  Mess.Msg := CM_TEXTCHANGED;
1412  DeliverMessage(AWinControl, Mess);
1413
1414  {$IFDEF VerboseTWinControlRealText}
1415  DebugLn(['TGtkWSCustomEdit.SetText END ',DbgSName(AWinControl),' New="',gtk_entry_get_text(PGtkEntry(AWinControl.Handle)),'"']);
1416  {$ENDIF}
1417end;
1418
1419class procedure TGtkWSCustomEdit.GetPreferredSize(const AWinControl: TWinControl;
1420  var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean);
1421begin
1422  GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight,
1423                          WithThemeSpace);
1424  //debugln('TGtkWSCustomEdit.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight));
1425end;
1426
1427class procedure TGtkWSCustomEdit.SetColor(const AWinControl: TWinControl);
1428var
1429  AWidget: PGTKWidget;
1430begin
1431  if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit;
1432  AWidget := PGtkWidget(AWinControl.Handle);
1433  // don't change selected state
1434  GtkWidgetSet.SetWidgetColor(AWidget, clNone, AWinControl.Color,
1435    [GTK_STATE_NORMAL, GTK_STYLE_BASE]);
1436end;
1437
1438{ TGtkWSCustomStaticText }
1439
1440class function TGtkWSCustomStaticText.GetLabelWidget(AFrame: PGtkFrame): PGtkLabel;
1441begin
1442  {$IFDEF GTK2}
1443  Result := PGtkLabel(PGtkBin(GetBoxWidget(AFrame))^.child);
1444  {$ELSE}
1445  Result := PGtkLabel(GetBoxWidget(AFrame)^.bin.child);
1446  {$ENDIF}
1447end;
1448
1449class function TGtkWSCustomStaticText.GetBoxWidget(AFrame: PGtkFrame): PGtkEventBox;
1450begin
1451  {$IFDEF GTK2}
1452  Result := PGtkEventBox(PGtkBin(AFrame)^.child);
1453  {$ELSE}
1454  Result := PGtkEventBox(AFrame^.bin.Child);
1455  {$ENDIF}
1456end;
1457
1458class function TGtkWSCustomStaticText.CreateHandle(
1459  const AWinControl: TWinControl; const AParams: TCreateParams
1460  ): TLCLIntfHandle;
1461var
1462  AStaticText: TCustomStaticText;
1463  WidgetInfo: PWidgetInfo;
1464  Allocation: TGTKAllocation;
1465  EventBox, LblWidget: PGtkWidget;
1466begin
1467  // TStaticText control is a Text area with frame around. Both Text and Area around
1468  // text can have their own color
1469
1470  // To implement that in gtk we need:
1471  // 1. GtkLabel to handle Text
1472  // 2. GtkEventBox to draw color area around GtkLabel (since GtkLabel have no window)
1473  // 3. GtkFrame to draw frame around Text area
1474  // GtkFrame is our main widget - it is container and it contains GtkEventBox
1475  // GtkEventBox is also containter and it contains GtkLabel
1476
1477  AStaticText := AWinControl as TCustomStaticText;
1478  Result := TLCLIntfHandle(PtrUInt(gtk_frame_new(nil))); // frame is the main container - to decorate label
1479  if Result = 0 then Exit;
1480
1481  gtk_frame_set_shadow_type(PGtkFrame(Result), StaticBorderShadowMap[AStaticText.BorderStyle]);
1482
1483  EventBox := gtk_event_box_new;  // our area
1484  LblWidget := gtk_label_new(PChar(TCustomStaticText(AWinControl).Caption)); // our text widget
1485  gtk_container_add(PGtkContainer(EventBox), LblWidget);
1486  SetLabelAlignment(PGtkLabel(LblWidget), AStaticText.Alignment);
1487  gtk_widget_show(LblWidget);
1488  gtk_widget_show(EventBox);
1489  gtk_container_add(PGtkContainer(Result), EventBox);
1490
1491  {$IFDEF DebugLCLComponents}
1492  DebugGtkWidgets.MarkCreated(Pointer(Result), dbgsName(AWinControl));
1493  {$ENDIF}
1494
1495  WidgetInfo := CreateWidgetInfo(Pointer(Result), AStaticText, AParams);
1496  WidgetInfo^.CoreWidget := EventBox;
1497  gtk_object_set_data(PGtkObject(EventBox), 'widgetinfo', WidgetInfo);
1498
1499  Allocation.X := AParams.X;
1500  Allocation.Y := AParams.Y;
1501  Allocation.Width := AParams.Width;
1502  Allocation.Height := AParams.Height;
1503  gtk_widget_size_allocate(PGtkWidget(Result), @Allocation);
1504
1505  Set_RC_Name(AWinControl, PGtkWidget(Result));
1506  SetCallbacks(PGtkWidget(Result), WidgetInfo);
1507end;
1508
1509class procedure TGtkWSCustomStaticText.SetAlignment(const ACustomStaticText: TCustomStaticText;
1510  const NewAlignment: TAlignment);
1511var
1512  LblWidget: PGtkLabel;
1513begin
1514  if not WSCheckHandleAllocated(ACustomStaticText, 'SetAlignment')
1515  then Exit;
1516
1517  LblWidget := GetLabelWidget(PGtkFrame(ACustomStaticText.Handle));
1518  SetLabelAlignment(LblWidget, NewAlignment);
1519end;
1520
1521class procedure TGtkWSCustomStaticText.GetPreferredSize(const AWinControl: TWinControl;
1522  var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean);
1523begin
1524  GetGTKDefaultWidgetSize(AWinControl, PreferredWidth, PreferredHeight,
1525                          WithThemeSpace);
1526  //debugln('TGtkWSCustomStaticText.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight));
1527end;
1528
1529class function TGtkWSCustomStaticText.GetText(const AWinControl: TWinControl;
1530  var AText: String): Boolean;
1531begin
1532  // The text is static, so let the LCL fallback to FCaption
1533  Result := False;
1534end;
1535
1536class procedure TGtkWSCustomStaticText.SetText(const AWinControl: TWinControl;
1537  const AText: String);
1538var
1539  FrameWidget: PGtkFrame;
1540  LblWidget: PGtkLabel;
1541  DC: HDC;
1542  ALabel: PChar;
1543begin
1544  if not WSCheckHandleAllocated(AWincontrol, 'SetText')
1545  then Exit;
1546
1547  FrameWidget := PGtkFrame(AWinControl.Handle);
1548  LblWidget := GetLabelWidget(FrameWidget);
1549
1550  if TStaticText(AWinControl).ShowAccelChar then
1551  begin
1552    DC := Widgetset.GetDC(HWND(PtrUInt(LblWidget)));
1553    ALabel := TGtkWidgetSet(WidgetSet).ForceLineBreaks(
1554                          DC, PChar(AText), TStaticText(AWinControl).Width, false);
1555    Widgetset.DeleteDC(DC);
1556    GtkWidgetSet.SetLabelCaption(LblWidget, ALabel
1557       {$IFDEF Gtk1}, AWinControl, PGtkWidget(FrameWidget), 'grab_focus'{$ENDIF});
1558    StrDispose(ALabel);
1559  end else
1560  begin
1561    gtk_label_set_text(LblWidget, PChar(AText));
1562    gtk_label_set_pattern(LblWidget, nil);
1563  end;
1564end;
1565
1566class procedure TGtkWSCustomStaticText.SetStaticBorderStyle(
1567  const ACustomStaticText: TCustomStaticText;
1568  const NewBorderStyle: TStaticBorderStyle);
1569begin
1570  if not WSCheckHandleAllocated(ACustomStaticText, 'SetStaticBorderStyle')
1571  then Exit;
1572  gtk_frame_set_shadow_type(PGtkFrame(ACustomStaticText.Handle), StaticBorderShadowMap[NewBorderStyle]);
1573end;
1574
1575class procedure TGtkWSCustomStaticText.SetCallbacks(
1576  const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo);
1577begin
1578  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
1579
1580  SignalConnect(AGtkWidget, 'grab_focus', @gtkActivateCB, AWidgetInfo);
1581end;
1582
1583class procedure TGtkWSCustomStaticText.SetColor(const AWinControl: TWinControl);
1584begin
1585  if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit;
1586
1587  GtkWidgetSet.SetWidgetColor(PGtkWidget(GetBoxWidget(PGtkFrame(AWinControl.Handle))),
1588                              clNone, AWinControl.Color,
1589                              [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,
1590                               GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
1591end;
1592
1593class procedure TGtkWSCustomStaticText.SetFont(const AWinControl: TWinControl;
1594  const AFont: TFont);
1595var
1596  Widget: PGtkWidget;
1597begin
1598  if not WSCheckHandleAllocated(AWinControl, 'SetFont')
1599  then Exit;
1600
1601  Widget := PGtkWidget(GetLabelWidget(PGtkFrame(AWinControl.Handle)));
1602
1603  GtkWidgetSet.SetWidgetColor(Widget, AFont.Color, clNone,
1604       [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
1605  GtkWidgetSet.SetWidgetFont(Widget, AFont);
1606end;
1607
1608{ TGtkWSButton }
1609
1610function GtkWSButton_Clicked(AWidget: PGtkWidget; AInfo: PWidgetInfo): GBoolean; cdecl;
1611var
1612  Msg: TLMessage;
1613begin
1614  Result := CallBackDefaultReturn;
1615  if AInfo^.ChangeLock > 0 then Exit;
1616  Msg.Msg := LM_CLICKED;
1617  Result := DeliverMessage(AInfo^.LCLObject, Msg) = 0;
1618end;
1619
1620class procedure TGtkWSButton.SetCallbacks(const AGtkWidget: PGtkWidget;
1621  const AWidgetInfo: PWidgetInfo);
1622begin
1623  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
1624  SignalConnect(AGtkWidget, 'clicked', @GtkWSButton_Clicked, AWidgetInfo);
1625end;
1626
1627{$IFDEF Gtk1}
1628
1629class function TGtkWSButton.CreateHandle(const AWinControl: TWinControl;
1630  const AParams: TCreateParams): TLCLIntfHandle;
1631var
1632  Button: TCustomButton;
1633  WidgetInfo: PWidgetInfo;
1634  Allocation: TGTKAllocation;
1635begin
1636  Button := AWinControl as TCustomButton;
1637  Result := TLCLIntfHandle(PtrUInt(gtk_button_new_with_label('button')));
1638  if Result = 0 then Exit;
1639  {$IFDEF DebugLCLComponents}
1640  DebugGtkWidgets.MarkCreated(Pointer(Result),'button');
1641  {$ENDIF}
1642
1643  WidgetInfo := CreateWidgetInfo(Pointer(Result), Button, AParams);
1644
1645  Allocation.X := AParams.X;
1646  Allocation.Y := AParams.Y;
1647  Allocation.Width := AParams.Width;
1648  Allocation.Height := AParams.Height;
1649  gtk_widget_size_allocate(PGtkWidget(Result), @Allocation);
1650
1651  Set_RC_Name(AWinControl, PGtkWidget(Result));
1652  SetCallbacks(PGtkWidget(Result), WidgetInfo);
1653end;
1654
1655class function TGtkWSButton.GetText(const AWinControl: TWinControl; var AText: String): Boolean;
1656begin
1657  // The button text is static, so let the LCL fallback to FCaption
1658  Result := False;
1659end;
1660
1661class procedure TGtkWSButton.SetDefault(const AButton: TCustomButton; ADefault: Boolean);
1662begin
1663  if not WSCheckHandleAllocated(AButton, 'SetDefault')
1664  then Exit;
1665
1666  if ADefault
1667  and (GTK_WIDGET_CAN_DEFAULT(pgtkwidget(AButton.Handle))) then
1668    //gtk_widget_grab_default(pgtkwidget(handle))
1669  else begin
1670    {DebugLn('LM_BTNDEFAULT_CHANGED ',TCustomButton(Sender).Name,':',Sender.ClassName,' widget can not grab default ',
1671      ' visible=',GTK_WIDGET_VISIBLE(PGtkWidget(Handle)),
1672      ' realized=',GTK_WIDGET_REALIZED(PGtkWidget(Handle)),
1673      ' mapped=',GTK_WIDGET_MAPPED(PGtkWidget(Handle)),
1674      '');}
1675    //  gtk_widget_Draw_Default(pgtkwidget(Handle));  //this isn't right but I'm not sure what to call
1676  end;
1677end;
1678
1679class procedure TGtkWSButton.SetShortcut(const AButton: TCustomButton; const ShortCutK1, ShortCutK2: TShortcut);
1680begin
1681  if not WSCheckHandleAllocated(AButton, 'SetShortcut')
1682  then Exit;
1683
1684  {$IFDEF Gtk1}
1685  Accelerate(AButton, PGtkWidget(AButton.Handle), ShortCutK1, 'clicked');
1686  {$ENDIF}
1687  // gtk2: shortcuts are handled by the LCL
1688end;
1689
1690class procedure TGtkWSButton.SetText(const AWinControl: TWinControl; const AText: String);
1691var
1692  BtnWidget: PGtkButton;
1693  LblWidget: PGtkLabel;
1694begin
1695  if not WSCheckHandleAllocated(AWincontrol, 'SetText')
1696  then Exit;
1697
1698  BtnWidget := PGtkButton(AWinControl.Handle);
1699  {$IFDEF GTK2}
1700  LblWidget := PGtkLabel(PGtkBin(BtnWidget)^.Child);
1701  {$ELSE}
1702  LblWidget := PGtkLabel(BtnWidget^.Child);
1703  {$ENDIF}
1704
1705  if LblWidget = nil
1706  then begin
1707    //DebugLn(Format('trace: [WARNING] Button %s(%s) has no label', [AWinControl.Name, AWinControl.ClassName]));
1708    LblWidget := PGtkLabel(gtk_label_new(''));
1709    gtk_container_add(PGtkContainer(BtnWidget), PGtkWidget(LblWidget));
1710  end;
1711
1712  GtkWidgetSet.SetLabelCaption(LblWidget, AText
1713           {$IFDEF Gtk1}, AWinControl,PGtkWidget(BtnWidget), 'clicked'{$ENDIF});
1714end;
1715
1716class procedure TGtkWSButton.SetColor(const AWinControl: TWinControl);
1717var
1718  Widget: PGTKWidget;
1719begin
1720  if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit;
1721  Widget := PGtkWidget(AWinControl.Handle);
1722  GtkWidgetSet.SetWidgetColor(Widget, clNone, AWinControl.Color,
1723       [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
1724end;
1725
1726class procedure TGtkWSButton.SetFont(const AWinControl: TWinControl;
1727  const AFont: TFont);
1728var
1729  Widget: PGTKWidget;
1730  LblWidget: PGtkWidget;
1731begin
1732  if not AWinControl.HandleAllocated then exit;
1733
1734  Widget:= PGtkWidget(AWinControl.Handle);
1735  LblWidget := (pGtkBin(Widget)^.Child);
1736
1737  if LblWidget <> nil then
1738  begin
1739    GtkWidgetSet.SetWidgetColor(LblWidget, AFont.Color, clNone,
1740       [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
1741    GtkWidgetSet.SetWidgetFont(LblWidget, AFont);
1742  end;
1743end;
1744
1745class procedure TGtkWSButton.GetPreferredSize(const AWinControl: TWinControl;
1746  var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean);
1747begin
1748  GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight,
1749                          WithThemeSpace);
1750  //debugln('TGtkWSButton.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight));
1751end;
1752
1753{$ENDIF Gtk1}
1754
1755{ TGtkWSCustomCheckBox }
1756
1757class procedure TGtkWSCustomCheckBox.SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo);
1758begin
1759  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
1760  TGtkWidgetset(WidgetSet).SetCallback(LM_CHANGED, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1761end;
1762
1763{$IFDEF Gtk1}
1764
1765class function TGtkWSCustomCheckBox.CreateHandle(
1766  const AWinControl: TWinControl; const AParams: TCreateParams
1767  ): TLCLIntfHandle;
1768var
1769  Widget: PGtkWidget;
1770  WidgetInfo: PWidgetInfo;
1771  Allocation: TGTKAllocation;
1772begin
1773  Widget := gtk_check_button_new_with_label(AParams.Caption);
1774  {$IFDEF DebugLCLComponents}
1775  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
1776  {$ENDIF}
1777  Result := THandle(PtrUInt(Widget));
1778  WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams);
1779
1780  Allocation.X := AParams.X;
1781  Allocation.Y := AParams.Y;
1782  Allocation.Width := AParams.Width;
1783  Allocation.Height := AParams.Height;
1784  gtk_widget_size_allocate(PGtkWidget(Result), @Allocation);
1785
1786  Set_RC_Name(AWinControl, PGtkWidget(Result));
1787  SetCallbacks(PGtkWidget(Result), WidgetInfo);
1788end;
1789
1790class function  TGtkWSCustomCheckBox.RetrieveState(
1791  const ACustomCheckBox: TCustomCheckBox): TCheckBoxState;
1792var
1793  ToggleButton: PGtkToggleButton;
1794begin
1795  ToggleButton:=PGtkToggleButton(ACustomCheckBox.Handle);
1796  if (gtk_object_get_data(PgtkObject(ToggleButton),'Grayed')<>nil) then
1797    Result:=cbGrayed
1798  else if gtk_toggle_button_get_active(ToggleButton) then
1799    Result := cbChecked
1800  else
1801    Result := cbUnChecked;
1802end;
1803
1804class procedure TGtkWSCustomCheckBox.SetShortCut(
1805  const ACustomCheckBox: TCustomCheckBox; const ShortCutK1, ShortCutK2: TShortCut);
1806begin
1807  Accelerate(ACustomCheckBox, PGtkWidget(ACustomCheckBox.Handle), ShortCutK1,
1808    'activate_item');
1809end;
1810
1811class procedure TGtkWSCustomCheckBox.SetState(const ACB: TCustomCheckBox;
1812  const ANewState: TCheckBoxState);
1813var
1814  GtkObject: PGtkObject;
1815begin
1816  if not WSCheckHandleAllocated(ACB, 'SetState')
1817  then Exit;
1818
1819  GtkObject := PGtkObject(ACB.Handle);
1820  LockOnChange(GtkObject,1);
1821  if ANewState=cbGrayed then
1822    gtk_object_set_data(GtkObject, 'Grayed', GtkObject)
1823  else
1824    gtk_object_set_data(GtkObject, 'Grayed', nil);
1825  gtk_toggle_button_set_active(PGtkToggleButton(GtkObject), ANewState = cbChecked);
1826  LockOnChange(GtkObject,-1);
1827end;
1828
1829class procedure TGtkWSCustomCheckBox.GetPreferredSize(const AWinControl: TWinControl;
1830  var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean);
1831begin
1832  GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight,
1833                          WithThemeSpace);
1834  //debugln('TGtkWSCustomCheckBox.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight));
1835end;
1836
1837class procedure TGtkWSCustomCheckBox.SetFont(const AWinControl: TWinControl;
1838  const AFont: TFont);
1839var
1840  Widget: PGTKWidget;
1841  LblWidget: PGtkWidget;
1842begin
1843  if not AWinControl.HandleAllocated then exit;
1844
1845  Widget:= PGtkWidget(AWinControl.Handle);
1846  LblWidget := (pGtkBin(Widget)^.Child);
1847
1848  if LblWidget<>nil then
1849  begin
1850    GtkWidgetSet.SetWidgetColor(LblWidget, AFont.Color, clNone,
1851       [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]);
1852    GtkWidgetSet.SetWidgetFont(LblWidget, AFont);
1853  end;
1854end;
1855
1856{$ENDIF}
1857
1858{ TGtkWSCustomMemo }
1859
1860{$ifdef GTK1}
1861
1862class procedure TGtkWSCustomMemo.SetCallbacks(const AGtkWidget: PGtkWidget;
1863  const AWidgetInfo: PWidgetInfo);
1864begin
1865  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
1866  with TGtkWidgetset(Widgetset) do
1867  begin
1868    SetCallback(LM_CHANGED, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1869    SetCallback(LM_ACTIVATE, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1870    SetCallback(LM_CUT, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1871    SetCallback(LM_COPY, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1872    SetCallback(LM_PASTE, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject);
1873  end;
1874end;
1875
1876class function TGtkWSCustomMemo.CreateHandle(const AWinControl: TWinControl;
1877  const AParams: TCreateParams): TLCLIntfHandle;
1878var
1879  P: Pointer;
1880  TempWidget: PGtkWidget;
1881  WidgetInfo: PWidgetInfo;
1882begin
1883  P := gtk_scrolled_window_new(nil, nil);
1884  TempWidget := gtk_text_new(nil, nil);
1885  gtk_container_add(p, TempWidget);
1886
1887  GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.hscrollbar, GTK_CAN_FOCUS);
1888  GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.vscrollbar, GTK_CAN_FOCUS);
1889  gtk_scrolled_window_set_policy(PGtkScrolledWindow(p),
1890                                 GTK_POLICY_AUTOMATIC,
1891                                 GTK_POLICY_AUTOMATIC);
1892  gtk_text_set_adjustments(PGtkText(TempWidget),
1893    gtk_scrolled_window_get_hadjustment(PGtkScrolledWindow(p)),
1894    gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(p)));
1895
1896  WidgetInfo := CreateWidgetInfo(P, AWinControl, AParams);
1897  SetMainWidget(p, TempWidget);
1898  WidgetInfo^.CoreWidget := TempWidget;
1899
1900  gtk_text_set_editable (PGtkText(TempWidget), not TCustomMemo(AWinControl).ReadOnly);
1901  if TCustomMemo(AWinControl).WordWrap then
1902    gtk_text_set_line_wrap(PGtkText(TempWidget), GdkTrue)
1903  else
1904    gtk_text_set_line_wrap(PGtkText(TempWidget), GdkFalse);
1905  gtk_text_set_word_wrap(PGtkText(TempWidget), GdkTrue);
1906
1907  gtk_widget_show_all(P);
1908
1909  {$IFDEF DebugLCLComponents}
1910  DebugGtkWidgets.MarkCreated(P,dbgsName(AWinControl));
1911  {$ENDIF}
1912  Result := TLCLIntfHandle(PtrUInt(P));
1913  //DebugLn(['TGtkWSCustomMemo.CreateHandle ']);
1914  Set_RC_Name(AWinControl, P);
1915  SetCallbacks(P, WidgetInfo);
1916end;
1917
1918class procedure TGtkWSCustomMemo.AppendText(const ACustomMemo: TCustomMemo;
1919  const AText: string);
1920var
1921  Widget: PGtkWidget;
1922  CurMemoLen: gint;
1923begin
1924  if Length(AText) = 0 then
1925    exit;
1926
1927  Widget:=GetWidgetInfo(Pointer(ACustomMemo.Handle), true)^.CoreWidget;
1928  gtk_text_freeze(PGtkText(Widget));
1929  CurMemoLen := gtk_text_get_length(PGtkText(Widget));
1930  //debugln('TGtkWSCustomMemo.AppendText "',AText,'" CurMemoLen=',dbgs(CurMemoLen));
1931  gtk_editable_insert_text(PGtkOldEditable(Widget), PChar(AText), Length(AText),
1932                           @CurMemoLen);
1933  //debugln('TGtkWSCustomMemo.AppendText B CurMemoLen=',dbgs(CurMemoLen));
1934  gtk_text_thaw(PGtkText(Widget));
1935end;
1936
1937class function TGtkWSCustomMemo.GetStrings(const ACustomMemo: TCustomMemo): TStrings;
1938var
1939Widget: PGtkText;
1940begin
1941  Widget:=PGtkText(GetWidgetInfo(Pointer(ACustomMemo.Handle), true)^.CoreWidget);
1942  Result:=TGtkMemoStrings.Create(Widget, ACustomMemo);
1943end;
1944
1945class procedure TGtkWSCustomMemo.SetEchoMode(const ACustomEdit: TCustomEdit;
1946  NewMode: TEchoMode);
1947begin
1948  // no password char in memo
1949end;
1950
1951class procedure TGtkWSCustomMemo.SetMaxLength(const ACustomEdit: TCustomEdit;
1952  NewLength: integer);
1953var
1954  ImplWidget: PGtkWidget;
1955  i: integer;
1956begin
1957  if (ACustomEdit.MaxLength > 0) then
1958  begin
1959    ImplWidget := GetWidgetInfo(PGtkWidget(ACustomEdit.Handle), true)^.CoreWidget;
1960    i := gtk_text_get_length(GTK_TEXT(ImplWidget));
1961    if i > ACustomEdit.MaxLength then
1962       gtk_editable_delete_text(PGtkOldEditable(ImplWidget),
1963                                ACustomEdit.MaxLength, i);
1964  end;
1965end;
1966
1967class procedure TGtkWSCustomMemo.SetPasswordChar(const ACustomEdit: TCustomEdit;
1968  NewChar: char);
1969begin
1970  // no password char in memo
1971end;
1972
1973class procedure TGtkWSCustomMemo.SetReadOnly(const ACustomEdit: TCustomEdit;
1974  NewReadOnly: boolean);
1975var
1976  ImplWidget   : PGtkWidget;
1977begin
1978  ImplWidget:= GetWidgetInfo(PGtkWidget(ACustomEdit.Handle), true)^.CoreWidget;
1979  gtk_text_set_editable (GTK_TEXT(ImplWidget), not ACustomEdit.ReadOnly);
1980end;
1981
1982class procedure TGtkWSCustomMemo.SetColor(const AWinControl: TWinControl);
1983var
1984  AWidget: PGTKWidget;
1985begin
1986  if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit;
1987  AWidget := PGtkWidget(AWinControl.Handle);
1988  AWidget := GetWidgetInfo(AWidget, true)^.CoreWidget;
1989  GtkWidgetSet.SetWidgetColor(AWidget, clNone, AWinControl.Color,
1990    [GTK_STATE_NORMAL, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT, GTK_STATE_SELECTED,
1991     GTK_STYLE_BASE]);
1992end;
1993
1994class procedure TGtkWSCustomMemo.SetFont(const AWinControl: TWinControl;
1995  const AFont: TFont);
1996var
1997  AWidget: PGTKWidget;
1998begin
1999  if not AWinControl.HandleAllocated then exit;
2000
2001  AWidget:= PGtkWidget(AWinControl.Handle);
2002  AWidget:= GetWidgetInfo(AWidget, true)^.CoreWidget;
2003
2004  if AWidget<>nil then begin
2005    GtkWidgetSet.SetWidgetColor(AWidget, AFont.Color, clNone,
2006       [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,
2007        GTK_STYLE_TEXT]);
2008    GtkWidgetSet.SetWidgetFont(AWidget, AFont);
2009  end;
2010end;
2011
2012class procedure TGtkWSCustomMemo.SetScrollbars(const ACustomMemo: TCustomMemo;
2013  const NewScrollbars: TScrollStyle);
2014var
2015  wHandle: HWND;
2016begin
2017  wHandle := ACustomMemo.Handle;
2018  case ACustomMemo.Scrollbars of
2019    ssHorizontal:     gtk_scrolled_window_set_policy(
2020                        GTK_SCROLLED_WINDOW(wHandle),
2021                        GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
2022    ssVertical:       gtk_scrolled_window_set_policy(
2023                        GTK_SCROLLED_WINDOW(wHandle),
2024                        GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
2025    ssBoth:           gtk_scrolled_window_set_policy(
2026                        GTK_SCROLLED_WINDOW(wHandle),
2027                        GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
2028    ssAutoHorizontal: gtk_scrolled_window_set_policy(
2029                        GTK_SCROLLED_WINDOW(wHandle),
2030                        GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
2031    ssAutoVertical:   gtk_scrolled_window_set_policy(
2032                        GTK_SCROLLED_WINDOW(wHandle),
2033                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2034    ssAutoBoth:       gtk_scrolled_window_set_policy(
2035                        GTK_SCROLLED_WINDOW(wHandle),
2036                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2037  else
2038    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wHandle),
2039                                   GTK_POLICY_NEVER, GTK_POLICY_NEVER);
2040  end;
2041end;
2042
2043class procedure TGtkWSCustomMemo.SetWordWrap(const ACustomMemo: TCustomMemo;
2044  const NewWordWrap: boolean);
2045var
2046  ImplWidget   : PGtkWidget;
2047begin
2048  ImplWidget:= GetWidgetInfo(PGtkWidget(ACustomMemo.Handle), true)^.CoreWidget;
2049  gtk_text_freeze(PGtkText(ImplWidget));
2050  if ACustomMemo.WordWrap then
2051    gtk_text_set_line_wrap(GTK_TEXT(ImplWidget), GdkTrue)
2052  else
2053    gtk_text_set_line_wrap(GTK_TEXT(ImplWidget), GdkFalse);
2054  gtk_text_set_word_wrap(GTK_TEXT(ImplWidget), GdkTrue);
2055  gtk_text_thaw(PGtkText(ImplWidget));
2056end;
2057
2058{$endif}
2059
2060{ TGtkWSCustomGroupBox }
2061
2062class procedure TGtkWSCustomGroupBox.SetCallbacks(const AGtkWidget: PGtkWidget;
2063  const AWidgetInfo: PWidgetInfo);
2064begin
2065  TGtkWSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
2066end;
2067
2068{$ifdef gtk1}
2069class function TGtkWSCustomGroupBox.CreateHandle(
2070  const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle;
2071var
2072  TempWidget: PGTKWidget;       // pointer to gtk-widget (local use when neccessary)
2073  p : pointer;          // ptr to the newly created GtkWidget
2074  Allocation: TGTKAllocation;
2075  WidgetInfo: PWidgetInfo;
2076begin
2077  if AParams.Caption <> '' then
2078    P := gtk_frame_new(AParams.Caption)
2079  else
2080    P := gtk_frame_new(nil);
2081  WidgetInfo := CreateWidgetInfo(P, AWinControl, AParams);
2082  TempWidget := CreateFixedClientWidget;
2083  gtk_container_add(GTK_CONTAINER(p), TempWidget);
2084  WidgetInfo^.ClientWidget := TempWidget;
2085  WidgetInfo^.CoreWidget := TempWidget;
2086  gtk_object_set_data(PGtkObject(TempWidget), 'widgetinfo', WidgetInfo);
2087  gtk_widget_show(TempWidget);
2088  gtk_widget_show(P);
2089
2090  Result := TLCLIntfHandle(PtrUInt(P));
2091
2092  Allocation.X := AParams.X;
2093  Allocation.Y := AParams.Y;
2094  Allocation.Width := AParams.Width;
2095  Allocation.Height := AParams.Height;
2096  gtk_widget_size_allocate(P, @Allocation);
2097
2098  Set_RC_Name(AWinControl, P);
2099  SetCallbacks(P, WidgetInfo);
2100end;
2101
2102class procedure TGtkWSCustomGroupBox.GetPreferredSize(const AWinControl: TWinControl;
2103  var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean);
2104var
2105  Widget: PGtkWidget;
2106  border_width: Integer;
2107begin
2108  Widget := PGtkWidget(AWinControl.Handle);
2109
2110  PreferredWidth := (gtk_widget_get_xthickness(Widget)) * 2
2111                    +PGtkFrame(Widget)^.label_width;
2112  PreferredHeight := Max(gtk_widget_get_ythickness(Widget),
2113                         PGtkFrame(Widget)^.label_height)
2114                     + gtk_widget_get_ythickness(Widget);
2115
2116  if WithThemeSpace then begin
2117    border_width:=(PGtkContainer(Widget)^.flag0 and bm_TGtkContainer_border_width)
2118                   shr bp_TGtkContainer_border_width;
2119    inc(PreferredWidth, border_width);
2120    inc(PreferredHeight,2*border_width);
2121  end;
2122end;
2123
2124class procedure TGtkWSCustomGroupBox.SetText(const AWinControl: TWinControl;
2125  const AText: string);
2126begin
2127  if not WSCheckHandleAllocated(AWinControl, 'SetText') then Exit;
2128  if AText <> '' then
2129    gtk_frame_set_label(PGtkFrame(AWinControl.Handle), PChar(AText))
2130  else
2131    gtk_frame_set_label(PGtkFrame(AWinControl.Handle), nil);
2132end;
2133{$endif}
2134
2135{ TGtkWSRadioButton }
2136
2137class function TGtkWSRadioButton.CreateHandle(const AWinControl: TWinControl;
2138  const AParams: TCreateParams): TLCLIntfHandle;
2139var
2140  Widget, TempWidget: PGtkWidget;
2141  LabelWidget: PGtkLabel;
2142  TempInt: Integer;
2143  WidgetInfo: PWidgetInfo;
2144  Allocation: TGTKAllocation;
2145begin
2146  with TRadioButton(AWinControl) do
2147  begin
2148    // Look for our parent's control and use the first radio we find for grouping
2149    TempWidget := nil;
2150    if (Parent <> nil) then
2151    begin
2152      for TempInt := 0 to Parent.ControlCount - 1 do
2153      begin
2154        if (Parent.Controls[TempInt] is TRadioButton) and
2155           TWinControl(Parent.Controls[TempInt]).HandleAllocated then
2156        begin
2157          TempWidget := PGtkWidget(TWinControl(Parent.Controls[TempInt]).Handle);
2158          Break;
2159        end;
2160      end;
2161    end;
2162
2163    if TempWidget <> nil then
2164      Widget := gtk_radio_button_new_with_label(PGtkRadioButton(TempWidget)^.group,'')
2165    else
2166      Widget := gtk_radio_button_new_with_label(nil, '');
2167
2168    LabelWidget := PGtkLabel(gtk_bin_get_child(PGtkBin(@PGTKToggleButton(Widget)^.Button)));
2169    GtkWidgetSet.SetLabelCaption(LabelWidget, AParams.Caption
2170       {$IFDEF Gtk1}, AWinControl, Widget, 'clicked'{$ENDIF});
2171  end;
2172
2173  {$IFDEF DebugLCLComponents}
2174  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
2175  {$ENDIF}
2176  Result := THandle(PtrUInt(Widget));
2177  WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams);
2178
2179  Allocation.X := AParams.X;
2180  Allocation.Y := AParams.Y;
2181  Allocation.Width := AParams.Width;
2182  Allocation.Height := AParams.Height;
2183  gtk_widget_size_allocate(Widget, @Allocation);
2184
2185  Set_RC_Name(AWinControl, Widget);
2186  TGtkWSCustomCheckBox.SetCallbacks(Widget, WidgetInfo);
2187end;
2188
2189{ TGtkWSToggleBox }
2190
2191class function TGtkWSToggleBox.CreateHandle(const AWinControl: TWinControl;
2192  const AParams: TCreateParams): TLCLIntfHandle;
2193var
2194  Widget: PGtkWidget;
2195  WidgetInfo: PWidgetInfo;
2196  Allocation: TGTKAllocation;
2197begin
2198  Widget := gtk_toggle_button_new_with_label(AParams.Caption);
2199  {$IFDEF DebugLCLComponents}
2200  DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
2201  {$ENDIF}
2202  Result := THandle(PtrUInt(Widget));
2203  WidgetInfo := CreateWidgetInfo(Pointer(Result), AWinControl, AParams);
2204
2205  Allocation.X := AParams.X;
2206  Allocation.Y := AParams.Y;
2207  Allocation.Width := AParams.Width;
2208  Allocation.Height := AParams.Height;
2209  gtk_widget_size_allocate(Widget, @Allocation);
2210
2211  Set_RC_Name(AWinControl, Widget);
2212  TGtkWSCustomCheckBox.SetCallbacks(Widget, WidgetInfo);
2213end;
2214
2215end.
2216