1 {
2 *****************************************************************************
3 * gtk3widgets.pas *
4 * ------------- *
5 * *
6 * *
7 *****************************************************************************
8
9 *****************************************************************************
10 This file is part of the Lazarus Component Library (LCL)
11
12 See the file COPYING.modifiedLGPL.txt, included in this distribution,
13 for details about the license.
14 *****************************************************************************
15 }
16
17 unit gtk3widgets;
18 {$i gtk3defines.inc}
19 {$mode objfpc}
20 {$H+}
21
22 interface
23
24 uses
25 Classes, SysUtils, types, math,
26 // LCL
27 Controls, StdCtrls, ExtCtrls, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
28 Spin, CheckLst, PairSplitter, LCLType, LCLProc, LMessages, LCLMessageGlue, LCLIntf,
29 // GTK3
30 LazGtk3, LazGdk3, LazGObject2, LazGLib2, LazCairo1, LazPango1, LazGdkPixbuf2,
31 gtk3objects, gtk3procs, gtk3private, Gtk3CellRenderer;
32
33 type
34 TByteSet = set of byte;
35
36 // records
37 TPaintData = record
38 PaintWidget: PGtkWidget;
39 ClipRect: PRect;
40 ClipRegion: Pcairo_region_t;
41 end;
42
43 TDefaultRGBA = record
44 R: Double;
45 G: Double;
46 B: Double;
47 Alpha: Double;
48 end;
49
50 TGtk3WidgetType = (wtWidget, wtStaticText, wtProgressBar, wtLayout,
51 wtContainer, wtMenuBar, wtMenu, wtMenuItem, wtEntry, wtSpinEdit,
52 wtNotebook, wtTabControl, wtComboBox,
53 wtGroupBox, wtCalendar, wtTrackBar, wtScrollBar,
54 wtScrollingWin, wtListBox, wtListView, wtCheckListBox, wtMemo, wtTreeModel,
55 wtCustomControl, wtScrollingWinControl,
56 wtWindow, wtDialog, wtHintWindow);
57 TGtk3WidgetTypes = set of TGtk3WidgetType;
58
59 { TGtk3Widget }
60
61 TGtk3Widget = class(TGtk3Object, IUnknown)
62 private
63 FFocusableByMouse: Boolean; {shell we call SetFocus on mouse down. Default = False}
64 FEnterLeaveTime: Cardinal;
65 FHasPaint: Boolean;
66 FKeysToEat: TByteSet;
67 FPaintData: TPaintData;
68 FContext: HDC;
69 FCairoContext: Pcairo_t;
70 FWidgetType: TGtk3WidgetTypes;
71 FParams: TCreateParams;
72 FOwnWidget: Boolean;
73 FOwner: PGtkWidget;
74 FCentralWidget: PGtkWidget;
75 FWidget: PGtkWidget;
76 FProps: TStringList;
77 FWidgetRGBA: array [0{GTK_STATE_NORMAL}..4{GTK_STATE_INSENSITIVE}] of TDefaultRGBA;
78 FCentralWidgetRGBA: array [0{GTK_STATE_NORMAL}..4{GTK_STATE_INSENSITIVE}] of TDefaultRGBA;
79
CanSendLCLMessagenull80 function CanSendLCLMessage: Boolean;
GetCairoContextnull81 function GetCairoContext: Pcairo_t;
GetEnablednull82 function GetEnabled: Boolean;
GetFontnull83 function GetFont: PPangoFontDescription;
GetStyleContextnull84 function GetStyleContext: PGtkStyleContext;
GetVisiblenull85 function GetVisible: Boolean;
86 procedure SetEnabled(AValue: Boolean);
87 procedure SetFont(AValue: PPangoFontDescription);
88 procedure SetVisible(AValue: Boolean);
89 procedure SetStyleContext(AValue: PGtkStyleContext);
90 protected
91 // IUnknown implementation
QueryInterfacenull92 function QueryInterface(constref iid: TGuid; out obj): LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
_AddRefnull93 function _AddRef: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
_Releasenull94 function _Release: LongInt; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
EatArrowKeysnull95 function EatArrowKeys(const AKey: Word): Boolean; virtual;
getTextnull96 function getText: String; virtual;
97 procedure setText(AValue: String); virtual;
GetContextnull98 function GetContext: HDC; virtual;
CreateWidgetnull99 function CreateWidget(const Params: TCreateParams):PGtkWidget; virtual;
100 procedure DestroyWidget; virtual;
101 procedure DoBeforeLCLPaint; virtual;
102
GetColornull103 function GetColor: TColor; virtual;
104 procedure SetColor(AValue: TColor); virtual;
GetFontColornull105 function GetFontColor: TColor; virtual;
106 procedure SetFontColor(AValue: TColor); virtual;
107 public
108 LCLObject: TWinControl;
109 public
110 constructor Create(const AWinControl: TWinControl; const AParams: TCreateParams); virtual; overload;
111 constructor CreateFrom(const AWinControl: TWinControl; AWidget: PGtkWidget); virtual;
112
113 procedure InitializeWidget; virtual;
114 procedure DeInitializeWidget;
115 procedure RecreateWidget;
116 procedure DestroyNotify(AWidget: PGtkWidget); virtual;
117 destructor Destroy; override;
118
CanFocusnull119 function CanFocus: Boolean; virtual;
GetFocusableByMousenull120 function GetFocusableByMouse: Boolean;
getClientOffsetnull121 function getClientOffset: TPoint; virtual;
getWidgetPosnull122 function getWidgetPos: TPoint; virtual;
123
124 procedure OffsetMousePos(APoint: PPoint); virtual;
125
DeliverMessagenull126 function DeliverMessage(var Msg; const AIsInputEvent: Boolean = False): LRESULT; virtual;
GtkEventMouseEnterLeavenull127 function GtkEventMouseEnterLeave(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
GtkEventKeynull128 function GtkEventKey(Sender: PGtkWidget; Event: PGdkEvent; AKeyPress: Boolean): Boolean; virtual; cdecl;
GtkEventMousenull129 function GtkEventMouse(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
GtkEventMouseMovenull130 function GtkEventMouseMove(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
GtkEventPaintnull131 function GtkEventPaint(Sender: PGtkWidget; AContext: Pcairo_t): Boolean; virtual; cdecl;
GtkEventResizenull132 function GtkEventResize(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
133 procedure GtkEventFocus(Sender: PGtkWidget; Event: PGdkEvent); cdecl;
134 procedure GtkEventDestroy; cdecl;
GtkEventMouseWheelnull135 function GtkEventMouseWheel(Sender: PGtkWidget; Event: PGdkEvent): Boolean; virtual; cdecl;
136
IsValidHandlenull137 function IsValidHandle: Boolean;
IsWidgetOknull138 function IsWidgetOk: Boolean; virtual;
IsIconicnull139 function IsIconic: Boolean; virtual;
140
getTypenull141 function getType: TGType;
getTypeNamenull142 function getTypeName: PgChar;
143
144 procedure lowerWidget; virtual;
145 procedure raiseWidget; virtual;
146 procedure stackUnder(AWidget: PGtkWidget); virtual;
147
GetCapturenull148 function GetCapture: TGtk3Widget; virtual;
SetCapturenull149 function SetCapture: HWND; virtual;
150
getClientRectnull151 function getClientRect: TRect; virtual;
getClientBoundsnull152 function getClientBounds: TRect; virtual;
GetContainerWidgetnull153 function GetContainerWidget: PGtkWidget; virtual;
GetPositionnull154 function GetPosition(out APoint: TPoint): Boolean; virtual;
155 procedure Release; override;
156 procedure Hide; virtual;
getParentnull157 function getParent: TGtk3Widget;
GetWindownull158 function GetWindow: PGdkWindow; virtual;
159 procedure Move(ALeft, ATop: Integer);
160 procedure Activate; virtual;
161 procedure preferredSize(var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); virtual;
162 procedure SetCursor(ACursor: HCURSOR);
163 procedure SetFocus; virtual;
164 procedure SetParent(AParent: TGtk3Widget; const ALeft, ATop: Integer); virtual;
165 procedure Show; virtual;
166 procedure ShowAll; virtual;
167 procedure Update(ARect: PRect);
168 property CairoContext: Pcairo_t read GetCairoContext;
169 property Color: TColor read GetColor write SetColor;
170 property Context: HDC read GetContext;
171 property Enabled: Boolean read GetEnabled write SetEnabled;
172 property Font: PPangoFontDescription read GetFont write SetFont;
173 property FontColor: TColor read GetFontColor write SetFontColor;
174 property KeysToEat: TByteSet read FKeysToEat write FKeysToEat;
175 property PaintData: TPaintData read FPaintData write FPaintData;
176 property StyleContext: PGtkStyleContext read GetStyleContext write SetStyleContext;
177 property Text: String read getText write setText;
178 property Visible: Boolean read GetVisible write SetVisible;
179 property Widget: PGtkWidget read FWidget;
180 property WidgetType: TGtk3WidgetTypes read FWidgetType;
181 end;
182
183 { TGtk3Editable }
184
185 TGtk3Editable = class(TGtk3Widget)
186 private
GetReadOnlynull187 function GetReadOnly: Boolean;
188 procedure SetReadOnly(AValue: Boolean);
189 protected
190 PrivateCursorPos: Integer; // used only for delayed selStart and selLength
191 PrivateSelection: Integer;
getCaretPosnull192 function getCaretPos: TPoint; virtual;
193 procedure SetCaretPos(AValue: TPoint); virtual;
194 public
getSelStartnull195 function getSelStart: Integer; virtual;
getSelLengthnull196 function getSelLength: Integer; virtual;
197 procedure setSelStart(AValue: Integer); virtual;
198 procedure setSelLength(AValue: Integer); virtual;
199 property CaretPos: TPoint read GetCaretPos write SetCaretPos;
200 property ReadOnly: Boolean read GetReadOnly write SetReadOnly;
201 end;
202
203 { TGtk3Entry }
204
205 TGtk3Entry = class(TGtk3Editable)
206 private
GetAlignmentnull207 function GetAlignment: TAlignment;
208 procedure SetAlignment(AValue: TAlignment);
209 protected
EatArrowKeysnull210 function EatArrowKeys(const AKey: Word): Boolean; override;
getTextnull211 function getText: String; override;
212 procedure setText(AValue: String); override;
CreateWidgetnull213 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
214 public
215 procedure InitializeWidget; override;
216 procedure SetEchoMode(AVisible: Boolean);
217 procedure SetMaxLength(AMaxLength: Integer);
218 procedure SetPasswordChar(APasswordChar: Char);
IsWidgetOknull219 function IsWidgetOk: Boolean; override;
220 property Alignment: TAlignment read GetAlignment write SetAlignment;
221 end;
222
223 { TGtk3SpinEdit }
224
225 TGtk3SpinEdit = class(TGtk3Entry)
226 private
GetMaximumnull227 function GetMaximum: Double;
GetMinimumnull228 function GetMinimum: Double;
GetNumDigitsnull229 function GetNumDigits: Integer;
GetNumericnull230 function GetNumeric: Boolean;
GetStepnull231 function GetStep: Double;
GetValuenull232 function GetValue: Double;
233 procedure SetNumDigits(AValue: Integer);
234 procedure SetNumeric(AValue: Boolean);
235 procedure SetStep(AValue: Double);
236 procedure SetValue(AValue: Double);
237 protected
CreateWidgetnull238 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull239 function EatArrowKeys(const AKey: Word): Boolean; override;
240 public
IsWidgetOknull241 function IsWidgetOk: Boolean; override;
242 procedure SetRange(AMin, AMax: Double);
243 property Minimum: Double read GetMinimum;
244 property Maximum: Double read GetMaximum;
245 property Numeric: Boolean read GetNumeric write SetNumeric;
246 property NumDigits: Integer read GetNumDigits write SetNumDigits;
247 property Step: Double read GetStep write SetStep;
248 property Value: Double read GetValue write SetValue;
249 end;
250
251 { TGtk3Range }
252
253 TGtk3Range = class(TGtk3Widget)
254 private
GetPositionnull255 function GetPosition: Integer;
GetRangenull256 function GetRange: TPoint;
257 procedure SetPosition(AValue: Integer);
258 procedure SetRange(AValue: TPoint);
259 public
260 procedure InitializeWidget; override;
261 procedure SetStep(AStep: Integer; APageSize: Integer);
262 property Range: TPoint read GetRange write SetRange;
263 property Position: Integer read GetPosition write SetPosition;
264 end;
265
266 { TGtk3TrackBar }
267
268 TGtk3TrackBar = class(TGtk3Range)
269 private
270 FOrientation: TTrackBarOrientation;
GetReversednull271 function GetReversed: Boolean;
272 procedure SetReversed(AValue: Boolean);
273 protected
CreateWidgetnull274 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
275 public
GetTrackBarOrientationnull276 function GetTrackBarOrientation: TTrackBarOrientation;
277 procedure SetScalePos(AValue: TTrackBarScalePos);
278 procedure SetTickMarks(AValue: TTickMark; ATickStyle: TTickStyle);
279 property Reversed: Boolean read GetReversed write SetReversed;
280 end;
281
282 { TGtk3ScrollBar }
283
284 TGtk3ScrollBar = class(TGtk3Range)
285 protected
CreateWidgetnull286 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
287 public
288 procedure SetParams;
289 end;
290
291 { TGtk3ProgressBar }
292
293 TGtk3ProgressBar = class(TGtk3Widget)
294 private
GetOrientationnull295 function GetOrientation: TProgressBarOrientation;
GetPositionnull296 function GetPosition: Integer;
GetShowTextnull297 function GetShowText: Boolean;
GetStylenull298 function GetStyle: TProgressBarStyle;
299 procedure SetOrientation(AValue: TProgressBarOrientation);
300 procedure SetPosition(AValue: Integer);
301 procedure SetShowText(AValue: Boolean);
302 procedure SetStyle(AValue: TProgressBarStyle);
303 protected
CreateWidgetnull304 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
305 public
306 procedure InitializeWidget; override;
307 property Orientation: TProgressBarOrientation read GetOrientation write SetOrientation;
308 property Position: Integer read GetPosition write SetPosition;
309 property ShowText: Boolean read GetShowText write SetShowText;
310 property Style: TProgressBarStyle read GetStyle write SetStyle;
311 end;
312
313 { TGtk3Calendar }
314
315 TGtk3Calendar = class(TGtk3Widget)
316 protected
CreateWidgetnull317 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
318 public
319 procedure GetDate(out AYear, AMonth, ADay: Word);
320 procedure SetDate(const AYear, AMonth, ADay: Word);
321 procedure SetDisplayOptions(const ADisplayOptions: TGtkCalendarDisplayOptions);
322 end;
323
324 { TGtk3StaticText }
325
326 TGtk3StaticText = class(TGtk3Widget)
327 private
GetAlignmentnull328 function GetAlignment: TAlignment;
GetStaticBorderStylenull329 function GetStaticBorderStyle: TStaticBorderStyle;
330 procedure SetAlignment(AValue: TAlignment);
331 procedure SetStaticBorderStyle(AValue: TStaticBorderStyle);
332 protected
getTextnull333 function getText: String; override;
334 procedure setText(AValue: String); override;
CreateWidgetnull335 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
336 public
337 property Alignment: TAlignment read GetAlignment write SetAlignment;
338 property StaticBorderStyle: TStaticBorderStyle read GetStaticBorderStyle write SetStaticBorderStyle;
339 end;
340
341 { TGtk3Container }
342
343 TGtk3Container = class(TGtk3Widget)
344 public
345 procedure AddChild(AWidget: PGtkWidget; const ALeft, ATop: Integer); virtual;
346 end;
347
348 { TGtk3Page }
349
350 TGtk3Page = class(TGtk3Container)
351 private
352 FPageLabel: PGtkLabel;
353 protected
354 procedure setText(AValue: String); override;
getTextnull355 function getText: String; override;
CreateWidgetnull356 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
357 procedure DestroyWidget; override;
358 public
getClientRectnull359 function getClientRect: TRect; override;
360 end;
361
362 { TGtk3NoteBook }
363
364 TGtk3NoteBook = class (TGtk3Container)
365 protected
CreateWidgetnull366 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
367 public
getClientRectnull368 function getClientRect: TRect; override;
getPagesCountnull369 function getPagesCount: integer;
370 procedure InsertPage(ACustomPage: TCustomPage; AIndex: Integer);
371 procedure MovePage(ACustomPage: TCustomPage; ANewIndex: Integer);
372 procedure RemovePage(AIndex: Integer);
373 procedure SetPageIndex(AIndex: Integer);
374 procedure SetShowTabs(const AShowTabs: Boolean);
375 procedure SetTabPosition(const ATabPosition: TTabPosition);
376 procedure SetTabLabelText(AChild: TCustomPage; AText: String);
GetTabLabelTextnull377 function GetTabLabelText(AChild: TCustomPage): String;
378 end;
379
380 { TGtk3Bin }
381
382 TGtk3Bin = class(TGtk3Container)
383
384 end;
385
386
387 { TGtk3Paned }
388
389 TGtk3Paned = class(TGtk3Container)
390 protected
CreateWidgetnull391 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
392 end;
393
394 { TGtk3SplitterSide }
395
396 TGtk3SplitterSide = class(TGtk3Container)
397 protected
CreateWidgetnull398 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
399 end;
400
401
402 { TGtk3MenuShell }
403
404 TGtk3MenuShell = class(TGtk3Container)
405 public
406 MenuObject: TMenu;
407 constructor Create(const AMenu: TMenu; AMenuBar: PGtkMenuBar); virtual; overload;
408 procedure Insert(AMenuShell: PGtkMenuShell; APosition: Integer);
409 procedure InitializeWidget; override;
410 end;
411
412 { TGtk3MenuBar }
413
414 TGtk3MenuBar = class(TGtk3MenuShell)
415 protected
CreateWidgetnull416 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
417 end;
418
419 { TGtk3Menu }
420
421 TGtk3Menu = class(TGtk3MenuShell)
422 protected
CreateWidgetnull423 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
424 public
425 PopupPoint: TPoint;
426 constructor CreateFromMenuItem(const AMenuItem: TMenuItem); virtual; overload;
427 end;
428
429 { TGtk3MenuItem }
430
431 TGtk3MenuItem = class(TGtk3Bin)
432 private
GetCaptionnull433 function GetCaption: string;
434 procedure SetCaption(AValue: string);
435 protected
CreateWidgetnull436 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
437 public
438 MenuItem: TMenuItem;
439 constructor Create(const AMenuItem: TMenuItem); virtual; overload;
440 procedure InitializeWidget; override;
441 property Caption: string read GetCaption write SetCaption;
442 end;
443
444 { TGtk3ScrollableWin }
445
446 TGtk3ScrollableWin = class(TGtk3Container)
447 private
448 FBorderStyle: TBorderStyle;
449 FScrollX: Integer;
450 FScrollY: Integer;
GetHScrollBarPolicynull451 function GetHScrollBarPolicy: TGtkPolicyType;
GetVScrollBarPolicynull452 function GetVScrollBarPolicy: TGtkPolicyType;
453 procedure SetBorderStyle(AValue: TBorderStyle);
454 procedure SetHScrollBarPolicy(AValue: TGtkPolicyType); virtual;
455 procedure SetVScrollBarPolicy(AValue: TGtkPolicyType); virtual;
456 public
457 procedure SetScrollBarsSignalHandlers;
getClientBoundsnull458 function getClientBounds: TRect; override;
getHorizontalScrollbarnull459 function getHorizontalScrollbar: PGtkScrollbar; virtual; abstract;
getVerticalScrollbarnull460 function getVerticalScrollbar: PGtkScrollbar; virtual; abstract;
getScrolledWindownull461 function getScrolledWindow: PGtkScrolledWindow; virtual; abstract;
462 property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle;
463 property HScrollBarPolicy: TGtkPolicyType read GetHScrollBarPolicy write SetHScrollBarPolicy;
464 property VScrollBarPolicy: TGtkPolicyType read GetVScrollBarPolicy write SetVScrollBarPolicy;
465 property ScrollX: Integer read FScrollX write FScrollX;
466 property ScrollY: Integer read FScrollY write FScrollY;
467 end;
468
469 { TGtk3ToolBar }
470
471 TGtk3ToolBar = class(TGtk3Container)
472 protected
CreateWidgetnull473 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
474 end;
475
476 { TGtk3Memo }
477
478 TGtk3Memo = class(TGtk3ScrollableWin)
479 private
GetAlignmentnull480 function GetAlignment: TAlignment;
GetReadOnlynull481 function GetReadOnly: Boolean;
GetWantTabsnull482 function GetWantTabs: Boolean;
GetWordWrapnull483 function GetWordWrap: Boolean;
484 procedure SetAlignment(AValue: TAlignment);
485 procedure SetReadOnly(AValue: Boolean);
486 procedure SetWantTabs(AValue: Boolean);
487 procedure SetWordWrap(AValue: Boolean);
488 protected
getTextnull489 function getText: String; override;
490 procedure setText(AValue: String); override;
CreateWidgetnull491 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull492 function EatArrowKeys(const AKey: Word): Boolean; override;
493 public
getHorizontalScrollbarnull494 function getHorizontalScrollbar: PGtkScrollbar; override;
getVerticalScrollbarnull495 function getVerticalScrollbar: PGtkScrollbar; override;
GetScrolledWindownull496 function GetScrolledWindow: PGtkScrolledWindow; override;
497 public
498 property Alignment: TAlignment read GetAlignment write SetAlignment;
499 property ReadOnly: Boolean read GetReadOnly write SetReadOnly;
500 property WantTabs: Boolean read GetWantTabs write SetWantTabs;
501 property WordWrap: Boolean read GetWordWrap write SetWordWrap;
502 end;
503
504 { TGtk3ListBox }
505
506 TGtk3ListBox = class(TGtk3ScrollableWin)
507 private
508 FListBoxStyle: TListBoxStyle;
GetItemIndexnull509 function GetItemIndex: Integer;
GetMultiSelectnull510 function GetMultiSelect: Boolean;
511 procedure SetItemIndex(AValue: Integer);
512 procedure SetListBoxStyle(AValue: TListBoxStyle);
513 procedure SetMultiSelect(AValue: Boolean);
514 protected
CreateWidgetnull515 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull516 function EatArrowKeys(const AKey: Word): Boolean; override;
517 procedure InitializeWidget; override;
518 public
getHorizontalScrollbarnull519 function getHorizontalScrollbar: PGtkScrollbar; override;
getVerticalScrollbarnull520 function getVerticalScrollbar: PGtkScrollbar; override;
GetScrolledWindownull521 function GetScrolledWindow: PGtkScrolledWindow; override;
522 public
GetSelCountnull523 function GetSelCount: Integer;
GetSelectionnull524 function GetSelection: PGtkTreeSelection;
GetItemSelectednull525 function GetItemSelected(const AIndex: Integer): Boolean;
526 procedure SelectItem(const AIndex: Integer; ASelected: Boolean);
527 procedure SetTopIndex(const AIndex: Integer);
528 property ItemIndex: Integer read GetItemIndex write SetItemIndex;
529 property MultiSelect: Boolean read GetMultiSelect write SetMultiSelect;
530 property ListBoxStyle: TListBoxStyle read FListBoxStyle write SetListBoxStyle;
531 end;
532
533 { TGtk3CheckListBox }
534
535 TGtk3CheckListBox = class(TGtk3ListBox)
536 protected
CreateWidgetnull537 function CreateWidget(const Params: TCreateParams): PGtkWidget; override;
538 end;
539
540 { TGtk3ListView }
541
542 TGtk3ListView = class(TGtk3ScrollableWin)
543 private
544 FPreselectedIndices: TFPList;
545 FImages: TFPList;
546 FIsTreeView: Boolean;
547 protected
CreateWidgetnull548 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull549 function EatArrowKeys(const AKey: Word): Boolean; override;
550 public
551 destructor Destroy; override;
552 {interface implementation}
getHorizontalScrollbarnull553 function getHorizontalScrollbar: PGtkScrollbar; override;
getVerticalScrollbarnull554 function getVerticalScrollbar: PGtkScrollbar; override;
GetScrolledWindownull555 function GetScrolledWindow: PGtkScrolledWindow; override;
556 procedure ClearImages;
557 procedure ColumnDelete(AIndex: Integer);
ColumnGetWidthnull558 function ColumnGetWidth(AIndex: Integer): Integer;
559 procedure ColumnInsert(AIndex: Integer; AColumn: TListColumn);
560 procedure SetAlignment(AIndex: Integer; AColumn: TListColumn; AAlignment: TAlignment);
561 procedure SetColumnAutoSize(AIndex: Integer; AColumn: TListColumn; AAutoSize: Boolean);
562 procedure SetColumnCaption(AIndex: Integer; AColumn: TListColumn; const ACaption: String);
563 procedure SetColumnMaxWidth(AIndex: Integer; AColumn: TListColumn; AMaxWidth: Integer);
564 procedure SetColumnMinWidth(AIndex: Integer; AColumn: TListColumn; AMinWidth: Integer);
565 procedure SetColumnWidth(AIndex: Integer; AColumn: TListColumn; AWidth: Integer);
566 procedure SetColumnVisible(AIndex: Integer; AColumn: TListColumn; AVisible: Boolean);
567 procedure ColumnSetSortIndicator(const AIndex: Integer; const AColumn: TListColumn; const ASortIndicator: TSortIndicator);
568
569 procedure ItemDelete(AIndex: Integer);
570 procedure ItemInsert(AIndex: Integer; AItem: TListItem);
571 procedure ItemSetText(AIndex, ASubIndex: Integer; AItem: TListItem; const AText: String);
572 procedure ItemSetState(const AIndex: Integer; const AItem: TListItem; const AState: TListItemState;
573 const AIsSet: Boolean);
ItemGetStatenull574 function ItemGetState(const AIndex: Integer; const AItem: TListItem; const AState: TListItemState;
575 out AIsSet: Boolean): Boolean;
576
577 procedure UpdateImageCellsSize;
578
579 property Images: TFPList read FImages write FImages;
580 property IsTreeView: Boolean read FIsTreeView;
581 end;
582
583 { TGtk3Box }
584
585 TGtk3Box = class(TGtk3Container)
586
587 end;
588
589 { TGtk3StatusBar }
590
591 TGtk3StatusBar = class(TGtk3Box)
592 protected
CreateWidgetnull593 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
594 end;
595
596 { TGtk3Panel }
597
598 TGtk3Panel = class(TGtk3Bin)
599 private
600 FBevelInner: TBevelCut;
601 FBevelOuter: TBevelCut;
602 FBorderStyle: TBorderStyle;
603 FText: String;
604 protected
605 procedure SetColor(AValue: TColor); override;
CreateWidgetnull606 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
607 procedure DoBeforeLCLPaint; override;
getTextnull608 function getText: String; override;
609 procedure setText(AValue: String); override;
610 public
611 property BevelInner: TBevelCut read FBevelInner write FBevelInner;
612 property BevelOuter: TBevelCut read FBevelOuter write FBevelOuter;
613 property BorderStyle: TBorderStyle read FBorderStyle write FBorderStyle;
614 end;
615
616 { TGtk3GroupBox }
617
618 TGtk3GroupBox = class(TGtk3Bin)
619 protected
CreateWidgetnull620 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
getTextnull621 function getText: String; override;
622 procedure setText(AValue: String); override;
623 public
624 end;
625
626 { TGtk3ComboBox }
627
628 TGtk3ComboBox = class(TGtk3Bin)
629 private
630 FCellView: PGtkCellView;
GetItemIndexnull631 function GetItemIndex: Integer;
632 procedure SetDroppedDown(AValue: boolean);
633 procedure SetItemIndex(AValue: Integer);
GetDroppedDownnull634 function GetDroppedDown: boolean;
635 protected
CreateWidgetnull636 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull637 function EatArrowKeys(const AKey: Word): Boolean; override;
getTextnull638 function getText: String; override;
639 procedure setText(AValue: String); override;
640 public
641 procedure DumpPrivateStructValues(ADbgEvent: String);
642 public
CanFocusnull643 function CanFocus: Boolean; override;
644 procedure SetFocus; override;
GetCellViewnull645 function GetCellView: PGtkCellView;
GetPopupWidgetnull646 function GetPopupWidget: PGtkWidget;
GetButtonWidgetnull647 function GetButtonWidget: PGtkWidget;
GetCellViewFramenull648 function GetCellViewFrame: PGtkWidget;
649 procedure InitializeWidget; override;
650 property DroppedDown: boolean read GetDroppedDown write SetDroppedDown;
651 property ItemIndex: Integer read GetItemIndex write SetItemIndex;
652 end;
653
654 { TGtk3Button }
655
656 TGtk3Button = class(TGtk3Bin)
657 private
658 FMargin: Integer;
659 FLayout: Integer;
660 FSpacing: Integer;
getLayoutnull661 function getLayout: Integer;
getMarginnull662 function getMargin: Integer;
663 procedure SetLayout(AValue: Integer);
664 procedure SetMargin(AValue: Integer);
665 procedure SetSpacing(AValue: Integer);
666 protected
getTextnull667 function getText: String; override;
668 procedure setText(AValue: String); override;
CreateWidgetnull669 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
670 public
IsWidgetOknull671 function IsWidgetOk: Boolean; override;
672 procedure SetDefault(const ADefault: Boolean);
673 property Layout: Integer read getLayout write SetLayout;
674 property Margin: Integer read getMargin write SetMargin;
675 property Spacing: Integer read FSpacing write SetSpacing;
676 end;
677
678 { TGtk3ToggleButton }
679
680 TGtk3ToggleButton = class(TGtk3Button)
681 protected
CreateWidgetnull682 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
683 public
684 procedure InitializeWidget; override;
685 end;
686
687 { TGtk3CheckBox }
688
689 TGtk3CheckBox = class(TGtk3ToggleButton)
690 private
GetStatenull691 function GetState: TCheckBoxState;
692 procedure SetState(AValue: TCheckBoxState);
693 protected
CreateWidgetnull694 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
695 public
696 property State: TCheckBoxState read GetState write SetState;
697 end;
698
699 { TGtk3RadioButton }
700
701 TGtk3RadioButton = class(TGtk3CheckBox)
702 private
703 protected
CreateWidgetnull704 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
705 procedure InitializeWidget; override;
706 public
707 end;
708
709 { TGtk3CustomControl }
710
711 TGtk3CustomControl = class(TGtk3ScrollableWin)
712 private
713 protected
CreateWidgetnull714 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull715 function EatArrowKeys(const AKey: Word): Boolean; override;
716 public
717 procedure InitializeWidget; override;
getClientRectnull718 function getClientRect: TRect; override;
getHorizontalScrollbarnull719 function getHorizontalScrollbar: PGtkScrollbar; override;
getVerticalScrollbarnull720 function getVerticalScrollbar: PGtkScrollbar; override;
GetScrolledWindownull721 function GetScrolledWindow: PGtkScrolledWindow; override;
722 end;
723
724 { TGtk3ScrollingWinControl }
725
726 TGtk3ScrollingWinControl = class(TGtk3CustomControl)
727 protected
CreateWidgetnull728 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
729 end;
730
731 { TGtk3Splitter }
732
733 TGtk3Splitter = class(TGtk3Panel)
734 public
735 end;
736
737
738 { TGtk3Window }
739
740 TGtk3Window = class(TGtk3ScrollableWin) {we are TGtk3Bin actually, but it won't hurt since we need scroll}
741 private
742 FIcon: PGdkPixBuf;
743 FScrollWin: PGtkScrolledWindow;
744 FMenuBar: PGtkMenuBar;
745 FBox: PGtkBox;
GetSkipTaskBarHintnull746 function GetSkipTaskBarHint: Boolean;
GetTitlenull747 function GetTitle: String;
748 procedure SetIcon(AValue: PGdkPixBuf);
749 procedure SetSkipTaskBarHint(AValue: Boolean);
750 procedure SetTitle(AValue: String);
751 protected
CreateWidgetnull752 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
EatArrowKeysnull753 function EatArrowKeys(const AKey: Word): Boolean; override;
getTextnull754 function getText: String; override;
755 procedure setText(AValue: String); override;
756 public
getClientBoundsnull757 // function getClientBounds: TRect; override;
758 function getClientRect: TRect; override;
getHorizontalScrollbarnull759 function getHorizontalScrollbar: PGtkScrollbar; override;
getVerticalScrollbarnull760 function getVerticalScrollbar: PGtkScrollbar; override;
GetScrolledWindownull761 function GetScrolledWindow: PGtkScrolledWindow; override;
762 public
763 destructor Destroy; override;
764 procedure Activate; override;
765 procedure Gtk3ActivateWindow(AEvent: PGdkEvent);
Gtk3CloseQuerynull766 function Gtk3CloseQuery: Boolean;
GetWindownull767 function GetWindow: PGdkWindow; override;
GetMenuBarnull768 function GetMenuBar: PGtkMenuBar;
GetBoxnull769 function GetBox: PGtkBox;
GetWindowStatenull770 function GetWindowState: TGdkWindowState;
771 property Icon: PGdkPixBuf read FIcon write SetIcon;
772 property SkipTaskBarHint: Boolean read GetSkipTaskBarHint write SetSkipTaskBarHint;
773 property Title: String read GetTitle write SetTitle;
774 end;
775
776 { TGtk3HintWindow }
777
778 TGtk3HintWindow = class(TGtk3Window)
779 private
780 FText: String;
781 protected
getTextnull782 function getText: String; override;
783 procedure setText(AValue: String); override;
CreateWidgetnull784 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
785 end;
786
787 { TGtk3Dialog }
788
789 TGtk3Dialog = class(TGtk3Widget)
790 protected
CreateWidgetnull791 function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
792 public
793 CommonDialog: TCommonDialog;
794 procedure InitializeWidget; override;
795 end;
796
797 { TGtk3FileDialog }
798
799 TGtk3FileDialog = class(TGtk3Dialog)
800 private
801 protected
CreateWidgetnull802 function CreateWidget(const Params: TCreateParams): PGtkWidget; override;
803 public
804 constructor Create(const ACommonDialog: TCommonDialog); virtual; overload;
805 end;
806
807 { TGtk3FontSelectionDialog }
808
809 TGtk3FontSelectionDialog = class(TGtk3Dialog)
810 protected
CreateWidgetnull811 function CreateWidget(const Params: TCreateParams): PGtkWidget; override;
812 public
813 constructor Create(const ACommonDialog: TCommonDialog); virtual; overload;
814 end;
815
816 {main event filter for all widgets, also called from widgetset main eventfilter}
Gtk3WidgetEventnull817 function Gtk3WidgetEvent(widget: PGtkWidget; event: PGdkEvent; data: GPointer): gboolean; cdecl;
818
819 implementation
820
821 uses gtk3int;
822
Gtk3EventToStrnull823 function Gtk3EventToStr(AEvent: TGdkEventType): String;
824 begin
825 Result := 'GDK_NOTHING';
826 case AEvent of
827 // GDK_DELETE:
828 0: Result := 'GDK_DELETE';
829 // GDK_DESTROY:
830 1: Result := 'GDK_DESTROY';
831 // GDK_EXPOSE:
832 2: Result := 'GDK_EXPOSE';
833 // GDK_MOTION_NOTIFY:
834 3: Result := 'GDK_MOTION_NOTIFY';
835 // GDK_BUTTON_PRESS:
836 4: Result := 'GDK_BUTTON_PRESS';
837 // GDK_2BUTTON_PRESS:
838 5: Result := 'GDK_2BUTTON_PRESS';
839 // GDK_3BUTTON_PRESS:
840 6: Result := 'GDK_3BUTTON_PRESS';
841 // GDK_BUTTON_RELEASE:
842 7: Result := 'GDK_BUTTON_RELEASE';
843 // GDK_KEY_PRESS:
844 8: Result := 'GDK_KEY_PRESS';
845 // GDK_KEY_RELEASE:
846 9: Result := 'GDK_KEY_RELEASE';
847 // GDK_ENTER_NOTIFY:
848 10: Result := 'GDK_ENTER_NOTIFY';
849 // GDK_LEAVE_NOTIFY:
850 11: Result := 'GDK_LEAVE_NOTIFY';
851 // GDK_FOCUS_CHANGE:
852 12: Result := 'GDK_FOCUS_CHANGE';
853 // GDK_CONFIGURE:
854 13: Result := 'GDK_CONFIGURE';
855 // GDK_MAP:
856 14: Result := 'GDK_MAP';
857 // GDK_UNMAP:
858 15: Result := 'GDK_UNMAP';
859 // GDK_PROPERTY_NOTIFY:
860 16: Result := 'GDK_PROPERTY_NOTIFY';
861 // GDK_SELECTION_CLEAR:
862 17: Result := 'GDK_SELECTION_CLEAR';
863 // GDK_SELECTION_REQUEST:
864 18: Result := 'GDK_SELECTION_REQUEST';
865 // GDK_SELECTION_NOTIFY:
866 19: Result := 'GDK_SELECTION_NOTIFY';
867 // GDK_PROXIMITY_IN:
868 20: Result := 'GDK_PROXIMITY_IN';
869 // GDK_PROXIMITY_OUT:
870 21: Result := 'GDK_PROXIMITY_OUT';
871 // GDK_DRAG_ENTER:
872 22: Result := 'GDK_DRAG_ENTER';
873 // GDK_DRAG_LEAVE:
874 23: Result := 'GDK_DRAG_LEAVE';
875 // GDK_DRAG_MOTION_:
876 24: Result := 'GDK_DRAG_MOTION_';
877 // GDK_DRAG_STATUS_:
878 25: Result := 'GDK_DRAG_STATUS_';
879 // GDK_DROP_START:
880 26: Result := 'GDK_DROP_START';
881 // GDK_DROP_FINISHED:
882 27: Result := 'GDK_DROP_FINISHED';
883 // GDK_CLIENT_EVENT:
884 28: Result := 'GDK_CLIENT_EVENT';
885 // GDK_VISIBILITY_NOTIFY:
886 29: Result := 'GDK_VISIBILITY_NOTIFY';
887 // GDK_SCROLL:
888 31: Result := 'GDK_SCROLL';
889 // GDK_WINDOW_STATE:
890 32: Result := 'GDK_WINDOW_STATE';
891 // GDK_SETTING:
892 33: Result := 'GDK_SETTING';
893 // GDK_OWNER_CHANGE:
894 34: Result := 'GDK_OWNER_CHANGE';
895 // GDK_GRAB_BROKEN:
896 35: Result := 'GDK_GRAB_BROKEN';
897 // GDK_DAMAGE:
898 36: Result := 'GDK_DAMAGE';
899 // GDK_TOUCH_BEGIN:
900 37: Result := 'GDK_TOUCH_BEGIN';
901 // GDK_TOUCH_UPDATE:
902 38: Result := 'GDK_TOUCH_UPDATE';
903 // GDK_TOUCH_END:
904 39: Result := 'GDK_TOUCH_END';
905 // GDK_TOUCH_CANCEL:
906 40: Result := 'GDK_TOUCH_CANCEL';
907 // GDK_EVENT_LAST:
908 41: Result := 'GDK_EVENT_LAST';
909 end;
910 end;
911
Gtk3MenuItemEventnull912 function Gtk3MenuItemEvent(widget: PGtkWidget; event: PGdkEvent; data: GPointer): gboolean; cdecl;
913 begin
914 Result := False;
915
916 if not Assigned(Application) or (Assigned(Application) and Application.Terminated) then
917 exit;
918
919 // DebugLn('Gtk3MenuItemEvent triggered ',dbgsName(TGtk3MenuItem(Data).MenuItem),
920 // ' ',Gtk3EventToStr(event^.type_));
921
922 case event^.type_ of
923 // GDK_DELETE
924 0:
925 begin
926 // DebugLn('****** GDK_DELETE FOR ',dbgsName(TGtk3Widget(Data).LCLObject),' main_level=',dbgs(gtk_main_level));
927 end;
928 // GDK_DESTROY
929 1:
930 begin
931 // DebugLn('****** GDK_DESTROY FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
932 end;
933 // GDK_EXPOSE
934 2:
935 begin
936 // DebugLn('****** GDK_EXPOSE FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
937 // Gtk3DrawWidget is attached to 'draw' signal, Expose event doesn't trigger
938 // under gtk3.
939 // we use 'draw' signal Gtk3DrawEvent()
940 // Result := TGtk3Widget(Data).GtkEventPaint(Widget, Event);
941 end;
942 // GDK_MOTION_NOTIFY
943 3:
944 begin
945 // Result := TGtk3Widget(Data).GtkEventMouseMove(Widget, Event);
946 end;
947 // GDK_BUTTON_PRESS:
948 4:
949 begin
950 // Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
951 end;
952 // GDK_2BUTTON_PRESS:
953 5:
954 begin
955 // if not TGtk3Widget(Data).LCLObject.Focused and TGtk3Widget(Data).LCLObject.CanFocus then
956 // LCLIntf.SetFocus(HWND(TGtk3Widget(Data)));
957 // Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
958 end;
959 // GDK_3BUTTON_PRESS:
960 6:
961 begin
962 // if not TGtk3Widget(Data).LCLObject.Focused and TGtk3Widget(Data).LCLObject.CanFocus then
963 // LCLIntf.SetFocus(HWND(TGtk3Widget(Data)));
964 // Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
965 end;
966 // GDK_BUTTON_RELEASE:
967 7:
968 begin
969 // Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
970 end;
971
972 // GDK_KEY_PRESS
973 8:
974 begin
975 // if Widget^.has_focus then // or (Widget = TGtk3Widget(data).GetContainerWidget) then
976 // Result := TGtk3Widget(Data).GtkEventKey(Widget, Event, True);
977 end;
978 // GDK_KEY_RELEASE
979 9:
980 begin
981 // if Widget^.has_focus then // or (Widget = TGtk3Widget(data).GetContainerWidget) then
982 // Result := TGtk3Widget(Data).GtkEventKey(Widget, Event, False);
983 end;
984
985 // GDK_ENTER_NOTIFY
986 10:
987 begin
988 // TGtk3Widget(Data).GtkEventMouseEnterLeave(Widget, Event);
989 end;
990 // GDK_LEAVE_NOTIFY
991 11:
992 begin
993 // TGtk3Widget(Data).GtkEventMouseEnterLeave(Widget, Event);
994 end;
995 12:
996 begin
997 // GDK_FOCUS_CHANGE
998 end;
999 // GDK_CONFIGURE
1000 13:
1001 begin
1002 // GDK_CONFIGURE
1003 end;
1004 14: // GDK_MAP
1005 begin
1006 // DebugLn('****** GDK_MAP FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1007 end;
1008 16: // GDK_PROPERTY_NOTIFY
1009 begin
1010 // DebugLn('****** GDK_PROPERTY_NOTIFY FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1011 end;
1012 28: // GDK_CLIENT_EVENT
1013 begin
1014 // DebugLn('****** GDK_CLIENT_EVENT FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1015 end;
1016 29: // GDK_VISIBILITY_NOTIFY
1017 begin
1018 // Result := TGtk3Widget(Data).GtkEventShowHide(Widget, Event);
1019 // DebugLn('****** GDK_VISIBILITY_NOTIFY FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
1020 end;
1021 31: // GDK_SCROLL
1022 begin
1023 // DebugLn('****** GDK_SCROLL ' + dbgsName(TGtk3Widget(Data).LCLObject));
1024 end;
1025 end;
1026 end;
1027
1028 function Gtk3WidgetEvent(widget: PGtkWidget; event: PGdkEvent; data: GPointer): gboolean; cdecl;
1029 begin
1030 {$IFDEF GTK3DEBUGCOMBOBOX}
1031 if (Data <> nil) and (wtComboBox in TGtk3Widget(Data).WidgetType) and
1032 (event^.type_ <> GDK_MOTION_NOTIFY) then
1033 begin
1034 if (Widget = TGtk3ComboBox(Data).GetPopupWidget) then
1035 DebugLn('***** Gtk3WidgetEvent(MENU triggered ',dbgsName(TGtk3Widget(Data).LCLObject),
1036 ' ',Gtk3EventToStr(event^.type_))
1037 else
1038 if (Widget = TGtk3ComboBox(Data).GetButtonWidget) then
1039 DebugLn('***** Gtk3WidgetEvent(BUTTON triggered ',dbgsName(TGtk3Widget(Data).LCLObject),
1040 ' ',Gtk3EventToStr(event^.type_))
1041 else
1042 if (Widget = PGtkWidget(TGtk3ComboBox(Data).GetCellView)) then
1043 DebugLn('***** Gtk3WidgetEvent(CELLVIEW triggered ',dbgsName(TGtk3Widget(Data).LCLObject),
1044 ' ',Gtk3EventToStr(event^.type_))
1045 else
1046 if (Widget = TGtk3ComboBox(Data).Widget) then
1047 DebugLn('***** Gtk3WidgetEvent(EVENTBOX triggered ',dbgsName(TGtk3Widget(Data).LCLObject),
1048 ' ',Gtk3EventToStr(event^.type_));
1049 end;
1050 {$ENDIF}
1051 {$IFDEF GTK3DEBUGCORE}
1052 // if event^.type_ = GDK_EXPOSE then
1053 if event^.type_ <> GDK_MOTION_NOTIFY then
1054 DebugLn('Gtk3WidgetEvent triggered ',dbgsName(TGtk3Widget(Data).LCLObject),
1055 ' ',Gtk3EventToStr(event^.type_));
1056 {$ENDIF}
1057 Result := False;
1058 if Assigned(Application) and Application.Terminated then
1059 exit;
1060 case event^.type_ of
1061 // GDK_DELETE
1062 0:
1063 begin
1064 // DebugLn('****** GDK_DELETE FOR ',dbgsName(TGtk3Widget(Data).LCLObject),' main_level=',dbgs(gtk_main_level));
1065 if wtWindow in TGtk3Widget(Data).WidgetType then
1066 begin
1067 TGtk3Window(Data).Gtk3CloseQuery;
1068 // let lcl destroy widget
1069 Result := True;
1070 end;
1071 end;
1072 // GDK_DESTROY
1073 1:
1074 begin
1075 // DebugLn('****** GDK_DESTROY FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
1076 end;
1077 // GDK_EXPOSE
1078 2:
1079 begin
1080 DebugLn('****** GDK_EXPOSE FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
1081 // Gtk3DrawWidget is attached to 'draw' signal, Expose event doesn't trigger
1082 // under gtk3.
1083 // we use 'draw' signal Gtk3DrawEvent()
1084 // Result := TGtk3Widget(Data).GtkEventPaint(Widget, Event);
1085 end;
1086 // GDK_MOTION_NOTIFY
1087 3:
1088 begin
1089 if wtWindow in TGtk3Widget(Data).WidgetType then
1090 begin
1091 if Widget = TGtk3Widget(Data).Widget then
1092 exit;
1093 end;
1094 Result := TGtk3Widget(Data).GtkEventMouseMove(Widget, Event);
1095 end;
1096 // GDK_BUTTON_PRESS:
1097 4:
1098 begin
1099 // set focus before gtk does that, so we have same behaviour as other ws
1100 if TGtk3Widget(Data).GetFocusableByMouse and
1101 not TGtk3Widget(Data).LCLObject.Focused and
1102 TGtk3Widget(Data).LCLObject.CanFocus then
1103 begin
1104 //FIXME: combobox updates popup-shown property too late
1105 // so we dont know yet if its dropped down or not
1106 if (wtComboBox in TGtk3Widget(Data).WidgetType) then
1107 begin
1108 TGtk3ComboBox(Data).DumpPrivateStructValues('GDK_BUTTON_PRESS btn='+IntToStr(Event^.button.button));
1109 end;
1110 if (wtWindow in TGtk3Widget(Data).WidgetType) then
1111 begin
1112 TGtk3Widget(Data).Activate;
1113 end else
1114 LCLIntf.SetFocus(HWND(TGtk3Widget(Data)));
1115 end;
1116
1117 Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
1118 end;
1119 // GDK_2BUTTON_PRESS:
1120 5:
1121 begin
1122 // set focus before gtk does that, so we have same behaviour as other ws
1123 if TGtk3Widget(Data).GetFocusableByMouse and
1124 not TGtk3Widget(Data).LCLObject.Focused and
1125 TGtk3Widget(Data).LCLObject.CanFocus then
1126 LCLIntf.SetFocus(HWND(TGtk3Widget(Data)));
1127 Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
1128 end;
1129 // GDK_3BUTTON_PRESS:
1130 6:
1131 begin
1132 // set focus before gtk does that, so we have same behaviour as other ws
1133 if TGtk3Widget(Data).GetFocusableByMouse and
1134 not TGtk3Widget(Data).LCLObject.Focused and
1135 TGtk3Widget(Data).LCLObject.CanFocus then
1136 LCLIntf.SetFocus(HWND(TGtk3Widget(Data)));
1137 Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
1138 end;
1139 // GDK_BUTTON_RELEASE:
1140 7:
1141 begin
1142 Result := TGtk3Widget(Data).GtkEventMouse(Widget , Event);
1143 end;
1144
1145 // GDK_KEY_PRESS
1146 8:
1147 begin
1148 if Widget^.has_focus then
1149 Result := TGtk3Widget(Data).GtkEventKey(Widget, Event, True);
1150 end;
1151 // GDK_KEY_RELEASE
1152 9:
1153 begin
1154 if Widget^.has_focus then // or (Widget = TGtk3Widget(data).GetContainerWidget) then
1155 Result := TGtk3Widget(Data).GtkEventKey(Widget, Event, False);
1156 end;
1157
1158 // GDK_ENTER_NOTIFY
1159 10:
1160 begin
1161 if wtWindow in TGtk3Widget(Data).WidgetType then
1162 begin
1163 if Widget <> TGtk3Widget(Data).GetContainerWidget then
1164 exit;
1165 end;
1166 (*
1167 DebugLn('** ENTER_NOTIFY ',dbgs(Event^.crossing.send_event),' TIME ',dbgs(Event^.crossing.time),' MODE ',dbgs(Event^.crossing.mode),
1168 ' WIDGET ',dbgHex(PtrUInt(Widget)),' LCLObject ',dbgsName(TGtk3Widget(Data).LCLObject),
1169 ' Widget=?',dbgs(Widget=TGtk3Widget(Data).GetContainerWidget));
1170 *)
1171 (*
1172 if wtComboBox in TGtk3Widget(Data).WidgetType then
1173 begin
1174 // DebugLn('** ENTER_NOTIFY ',dbgs(Event^.crossing.send_event),' TIME ',dbgs(Event^.crossing.time),' MODE ',dbgs(Event^.crossing.mode),
1175 // ' ENTERLEAVETIME=',dbgs(TGtk3ComboBox(Data).FEnterLeaveTime),' WIDGET ',dbgHex(PtrUInt(Widget)));
1176 TGtk3ComboBox(Data).DumpPrivateStructValues('GDK_ENTER_NOTIFY');
1177 if Widget <> TGtk3Widget(Data).Widget then
1178 exit;
1179 // upisi u combobox enter time, ako je enter.time - leave.time < 20 onda ne salji msg !
1180 TGtk3ComboBox(Data).FEnterLeaveTime := Event^.crossing.time;
1181 end;
1182 *)
1183 TGtk3Widget(Data).GtkEventMouseEnterLeave(Widget, Event);
1184 end;
1185 // GDK_LEAVE_NOTIFY
1186 11:
1187 begin
1188 if wtWindow in TGtk3Widget(Data).WidgetType then
1189 begin
1190 if Widget <> TGtk3Widget(Data).GetContainerWidget then
1191 exit;
1192 end;
1193 (*
1194 DebugLn('** LEAVE_NOTIFY ',dbgs(Event^.crossing.send_event),' TIME ',dbgs(Event^.crossing.time),' MODE ',dbgs(Event^.crossing.mode),
1195 ' WIDGET ',dbgHex(PtrUInt(Widget)),' LCLObject ',dbgsName(TGtk3Widget(Data).LCLObject),
1196 ' Widget=?',dbgs(Widget=TGtk3Widget(Data).GetContainerWidget));
1197 *)
1198 (*
1199 if wtComboBox in TGtk3Widget(Data).WidgetType then
1200 begin
1201 // DebugLn('** LEAVE_NOTIFY ',dbgs(Event^.crossing.send_event),' TIME ',dbgs(Event^.crossing.time),' MODE ',dbgs(Event^.crossing.mode),
1202 // ' TIME DIFF=',dbgs(Event^.crossing.time - TGtk3ComboBox(Data).FEnterLeaveTime),
1203 // ' WIDGET ',dbgHex(PtrUInt(Widget)));
1204 if Widget <> TGtk3Widget(Data).Widget then
1205 exit;
1206 if Event^.crossing.time - TGtk3ComboBox(Data).FEnterLeaveTime < 100 then
1207 begin
1208 exit(False);
1209 end;
1210 end;
1211 *)
1212 TGtk3Widget(Data).GtkEventMouseEnterLeave(Widget, Event);
1213 end;
1214 // GDK_FOCUS_CHANGE
1215 12:
1216 begin
1217 if wtComboBox in TGtk3Widget(Data).WidgetType then
1218 begin
1219 TGtk3ComboBox(Data).DumpPrivateStructValues('GDK_FOCUS_CHANGE='+IntToStr(Event^.focus_change.in_));
1220 //FIXME: combobox updates popup-shown property too late
1221 // so we dont know yet if its dropped down or not
1222 if TGtk3ComboBox(Data).DroppedDown then
1223 exit;
1224 end;
1225 TGtk3Widget(Data).GtkEventFocus(Widget, Event);
1226 end;
1227 // GDK_CONFIGURE
1228 13:
1229 begin
1230 (* DOES NOT WORK AS DOCUMENTATION SAYS
1231 if Data <> nil then
1232 begin
1233 if wtWindow in TGtk3Widget(Data).WidgetType then
1234 begin
1235 TGtk3Window(Data).Gtk3ActivateWindow(Event);
1236 DebugLn('** WindowState event ',dbgsName(TGtk3Widget(Data).LCLObject),' windowState=',dbgs(TGtk3Window(Data).GetWindowState));
1237 end else
1238 DebugLn('** WindowState event not wtWindow ',dbgsName(TGtk3Widget(Data).LCLObject));
1239 end;
1240 *)
1241 Result := TGtk3Widget(Data).GtkEventResize(Widget, Event);
1242 end;
1243 14: // GDK_MAP
1244 begin
1245 // DebugLn('****** GDK_MAP FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1246 end;
1247 15: // GDK_UNMAP
1248 begin
1249 // DebugLn('****** GDK_UNMAP FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1250 end;
1251 16: // GDK_PROPERTY_NOTIFY
1252 begin
1253 // DebugLn('****** GDK_PROPERTY_NOTIFY FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1254 end;
1255 28: // GDK_CLIENT_EVENT
1256 begin
1257 // DebugLn('****** GDK_CLIENT_EVENT FOR ',dbgsName(TGtk3Widget(Data).LCLObject));
1258 end;
1259 29: // GDK_VISIBILITY_NOTIFY
1260 begin
1261 // ONLY HERE WE CAN CATCH Activate/Deactivate but problem is that
1262 // PGtkWindow does not update active property properly
1263 // so PGtkWindow(Widget)^.is_active returns TRUE even if window isn't active anymore
1264 if wtWindow in TGtk3Widget(Data).WidgetType then
1265 begin
1266 TGtk3Window(Data).Gtk3ActivateWindow(Event);
1267 end;
1268 // Result := TGtk3Widget(Data).GtkEventShowHide(Widget, Event);
1269 // DebugLn('****** GDK_VISIBILITY_NOTIFY FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
1270 end;
1271 31: // GDK_SCROLL
1272 begin
1273 // DebugLn('****** GDK_SCROLL ' + dbgsName(TGtk3Widget(Data).LCLObject));
1274 Result := TGtk3Widget(Data).GtkEventMouseWheel(Widget, Event);
1275 end;
1276 32: // GDK_WINDOW_STATE
1277 begin
1278 // DebugLn('****** GDK_WINDOW_STATE FOR ' + dbgsName(TGtk3Widget(Data).LCLObject));
1279 // this doesn't work as expected ... must use GDK_CONFIGURE to get active status ?!?
1280 end;
1281 35: // GDK_GRAB_BROKEN could be broken eg. because of popupmenu
1282 begin
1283 DebugLn('****** GDK_GRAB_BROKEN (no problem if popupmenu is activated) ' + dbgsName(TGtk3Widget(Data).LCLObject));
1284 end;
1285 otherwise
1286 DebugLn('****** GDK unhandled event type ' + dbgsName(TGtk3Widget(Data).LCLObject));
1287 WriteLn(event^.type_);
1288
1289 end;
1290 end;
1291
Gtk3DrawWidgetnull1292 function Gtk3DrawWidget(AWidget: PGtkWidget; AContext: Pcairo_t; Data: gpointer): gboolean; cdecl;
1293 var
1294 ARect: TGdkRectangle;
1295 begin
1296 Result := False;
1297 if Data <> nil then
1298 begin
1299 gdk_cairo_get_clip_rectangle(AContext, @ARect);
1300 // DebugLn('**** Sending paint event to ',dbgsName(TGtk3Widget(Data).LCLObject),' clip ',dbgs(RectFromGdkRect(ARect)),' w=',dbgs(ARect.Width),' h=',dbgs(ARect.height));
1301 Result := TGtk3Widget(Data).GtkEventPaint(AWidget, AContext);
1302 // workaround for lcl painted widgets until we found why gtk3 sends wrong rect
1303 if (TGtk3Widget(Data).FHasPaint) and
1304 (ARect.height < (TGtk3Widget(Data).GetContainerWidget^.get_allocated_height div 4) ) then
1305 AWidget^.queue_draw;
1306 end;
1307 end;
1308
1309 procedure Gtk3MapWidget(AWidget: PGtkWidget; Data: gPointer); cdecl;
1310 var
1311 Allocation: TGtkAllocation;
1312 ARect: TRect;
1313 AWindow: PGdkWindow;
1314 xx,yy,w,h: Gint;
1315 begin
1316 AWidget^.get_allocation(@Allocation);
1317 {$IFDEF GTK3DEBUGCORE}
1318 DebugLn('**** Gtk3MapWidget ....',dbgsName(TGtk3Widget(Data).LCLObject));
1319 with Allocation do
1320 DebugLn(' Allocation ',Format('x %d y %d w %d h %d',[x,y,width,height]));
1321 {$ENDIF}
1322 ARect := TGtk3Widget(Data).LCLObject.BoundsRect;
1323 {$IFDEF GTK3DEBUGCORE}
1324 with ARect do
1325 DebugLn(' Rect ',Format('x %d y %d w %d h %d',[Left,Top,Right - Left, Bottom - Top]));
1326 {$ENDIF}
1327 AWindow := AWidget^.get_window;
1328 // at least TPanel needs this
1329 if Gtk3IsGdkWindow(AWindow) and (g_object_get_data(AWindow,'lclwidget') = nil) then
1330 g_object_set_data(AWindow,'lclwidget', TGtk3Widget(Data));
1331 if (AWindow <> nil) and AWidget^.get_has_window then
1332 begin
1333 // do resize to lcl size when mapping widget
1334 gdk_window_set_events(AWindow, GDK_ALL_EVENTS_MASK);
1335 if not (wtWindow in TGtk3Widget(Data).WidgetType) then
1336 begin
1337 with TGtk3Widget(Data).LCLObject do
1338 begin
1339 xx := Left;
1340 yy := Top;
1341 w := Width;
1342 h := Height;
1343 end;
1344 TGtk3Widget(Data).BeginUpdate;
1345 AWindow^.move(xx, yy);
1346 AWindow^.resize(w, h);
1347 TGtk3Widget(Data).EndUpdate;
1348 end else
1349 begin
1350 // DebugLn('TGtk3Window is mapped , setting lclwidget property to PGdkWindow ...');
1351 // now we set 'lclwidget' to our window.
1352 // g_object_set_data(AWindow,'lclwidget', TGtk3Widget(Data));
1353 end;
1354 end else
1355 begin
1356 if wtMemo in TGtk3Widget(Data).WidgetType then
1357 begin
1358 // gdk_window_get_geometry(AWindow, @xx,@yy,@w,@h);
1359 // gdk_window_get_position(AWindow, @xx,@yy);
1360 // DebugLn(' ***** Window ',Format('x %d y %d w %d h %d',[xx,yy,w,h]),' lclobject ',dbgsName(TGtk3Widget(Data).LCLObject));
1361 end;
1362 end;
1363 end;
1364
1365 procedure Gtk3SizeAllocate(AWidget: PGtkWidget; AGdkRect: PGdkRectangle; Data: gpointer); cdecl;
1366 var
1367 Msg: TLMSize;
1368 MoveMsg: TLMMove;
1369 NewSize: TSize;
1370 ACtl: TGtk3Widget;
1371 begin
1372 //TODO: Move to TGtk3Widget.GtkResizeEvent
1373 {$IFDEF GTK3DEBUGSIZE}
1374 with AGdkRect^ do
1375 DebugLn('**** Gtk3SizeAllocate **** ....',dbgsName(TGtk3Widget(Data).LCLObject),
1376 ' ',Format('x %d y %d w %d h %d',[x, y, width, height]));
1377 {$ENDIF}
1378
1379 ACtl := TGtk3Widget(Data);
1380
1381 // return size w/o frame
1382 NewSize.cx := AGdkRect^.width;
1383 NewSize.cy := AGdkRect^.height;
1384
1385 if not Assigned(ACtl.LCLObject) then exit;
1386
1387 // do not loop with LCL but do not apply it to TQtMainWindow !
1388 if not (csDesigning in ACtl.LCLObject.ComponentState) then
1389 begin
1390 if ACtl.InUpdate then
1391 exit;
1392 // if not (ClassType = TQtMainWindow) and InUpdate then
1393 // exit;
1394 end;
1395
1396 if ((NewSize.cx <> ACtl.LCLObject.Width) or (NewSize.cy <> ACtl.LCLObject.Height) or
1397 ACtl.LCLObject.ClientRectNeedsInterfaceUpdate) then
1398 begin
1399 ACtl.LCLObject.DoAdjustClientRectChange;
1400 end;
1401
1402 FillChar(Msg, SizeOf(Msg), #0);
1403
1404 Msg.Msg := LM_SIZE;
1405 (*
1406 case getWindowState of
1407 GtkWindowMinimized: Msg.SizeType := SIZE_MINIMIZED;
1408 GtkWindowMaximized: Msg.SizeType := SIZE_MAXIMIZED;
1409 GtkWindowFullScreen: Msg.SizeType := SIZE_FULLSCREEN;
1410 else
1411 Msg.SizeType := SIZE_RESTORED;
1412 end;
1413 *)
1414 Msg.SizeType := SIZE_RESTORED;
1415
1416 Msg.SizeType := Msg.SizeType or Size_SourceIsInterface;
1417 Msg.Width := Word(NewSize.cx);
1418 Msg.Height := Word(NewSize.cy);
1419 ACtl.DeliverMessage(Msg);
1420
1421 if (wtWindow in ACtl.WidgetType) and
1422 ((AGdkRect^.x <> ACtl.LCLObject.Left) or (AGdkRect^.y <> ACtl.LCLObject.Top)) then
1423 begin
1424 FillChar(MoveMsg, SizeOf(MoveMsg), #0);
1425 MoveMsg.Msg := LM_MOVE;
1426 MoveMsg.MoveType := MoveMsg.MoveType or Move_SourceIsInterface;
1427 MoveMsg.XPos := SmallInt(AGdkRect^.x);
1428 MoveMsg.YPos := SmallInt(AGdkRect^.y);
1429 {$IFDEF GTK3DEBUGEVENTS}
1430 DebugLn('SEND MOVE MESSAGE X=',dbgs(AGdkRect^.x),' Y=',dbgs(AGdkRect^.y),' control ',dbgsName(ACtl.LCLObject));
1431 {$ENDIF}
1432 ACtl.DeliverMessage(MoveMsg);
1433 end;
1434 end;
1435
Gtk3ResizeEventnull1436 function Gtk3ResizeEvent(AWidget: PGtkWidget; AEvent: PGdkEvent; Data: gpointer): gboolean; cdecl;
1437 var
1438 ARect: TGdkRectangle;
1439 begin
1440 Result := False;
1441 ARect.X := AEvent^.configure.x;
1442 ARect.Y := AEvent^.configure.y;
1443 ARect.width := AEvent^.configure.width;
1444 ARect.height := AEvent^.configure.height;
1445 // DebugLn('**** Gtk3ResizeEvent(CONFIGURE) **** ....',dbgsName(TGtk3Widget(Data).LCLObject),' ARect ',dbgs(RectFromGdkRect(ARect)));
1446 Gtk3SizeAllocate(AWidget, @ARect, Data);
1447 end;
1448
1449 procedure Gtk3WidgetHide(AWidget: PGtkWidget; AData: gpointer); cdecl;
1450 var
1451 Msg: TLMShowWindow;
1452 Gtk3Widget: TGtk3Widget;
1453 begin
1454 Gtk3Widget := TGtk3Widget(AData);
1455 {do not pass message to LCL if LCL setted up control visibility}
1456 if Gtk3Widget.inUpdate then
1457 exit;
1458 // DebugLn('SEND LM_HIDE FOR ',dbgsName(Gtk3Widget.LCLObject));
1459 FillChar(Msg, SizeOf(Msg), #0);
1460
1461 Msg.Msg := LM_SHOWWINDOW;
1462 Msg.Show := False;
1463
1464 Gtk3Widget.DeliverMessage(Msg);
1465 end;
1466
1467 procedure Gtk3WidgetShow(AWidget: PGtkWidget; AData: gpointer); cdecl;
1468 var
1469 Msg: TLMShowWindow;
1470 Gtk3Widget: TGtk3Widget;
1471 begin
1472 Gtk3Widget := TGtk3Widget(AData);
1473 {do not pass message to LCL if LCL setted up control visibility}
1474 if Gtk3Widget.inUpdate then
1475 exit;
1476 // DebugLn('SEND LM_SHOW FOR ',dbgsName(Gtk3Widget.LCLObject));
1477 FillChar(Msg, SizeOf(Msg), #0);
1478
1479 Msg.Msg := LM_SHOWWINDOW;
1480 Msg.Show := True;
1481
1482 Gtk3Widget.DeliverMessage(Msg);
1483 end;
1484
GtkModifierStateToShiftStatenull1485 function GtkModifierStateToShiftState(AState: TGdkModifierType;
1486 AIsKeyEvent: Boolean): Cardinal;
1487 begin
1488 Result := 0;
1489 if AState and GDK_SHIFT_MASK <> 0 then
1490 Result := Result or MK_SHIFT;
1491 if AState and GDK_CONTROL_MASK <> 0 then
1492 Result := Result or MK_CONTROL;
1493 if AState and GDK_MOD1_MASK <> 0 then
1494 begin
1495 if AIsKeyEvent then
1496 Result := Result or KF_ALTDOWN
1497 else
1498 Result := Result or MK_ALT;
1499 end;
1500 end;
1501
SubtractScrollnull1502 function SubtractScroll(AWidget: PGtkWidget; APosition: TPoint): TPoint;
1503 begin
1504 Result := APosition;
1505 if Gtk3IsScrolledWindow(AWidget) then
1506 begin
1507 with gtk_scrolled_window_get_hadjustment(PGtkScrolledWindow(AWidget))^ do
1508 dec(Result.x, Trunc(value - lower));
1509 with gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(AWidget))^ do
1510 dec(Result.y, Trunc(value - lower));
1511 end;
1512 end;
1513
Gtk3ScrolledWindowScrollEventnull1514 function Gtk3ScrolledWindowScrollEvent(AScrollWindow: PGtkScrolledWindow; AEvent: PGdkEvent; AData: gPointer): gboolean; cdecl;
1515 var
1516 Msg: TLMVScroll;
1517 AValue: Double;
1518 Range: PGtkRange;
1519 begin
1520 {$IFDEF SYNSCROLLDEBUG}
1521 debugln(['Gtk3ScrolledWindowScrollEvent ']);
1522 {$ENDIF}
1523 Result := False;
1524 case AEvent^.scroll.direction of
1525 0, 1{GDK_SCROLL_UP,
1526 GDK_SCROLL_DOWN}: Msg.Msg := LM_VSCROLL;
1527 2, 3{GDK_SCROLL_LEFT,
1528 GDK_SCROLL_RIGHT}: Msg.Msg := LM_HSCROLL;
1529 end;
1530
1531 case Msg.Msg of
1532 LM_VSCROLL: Range := PGtkRange(AScrollWindow^.get_vscrollbar);
1533 LM_HSCROLL: Range := PGtkRange(AScrollWindow^.get_hscrollbar);
1534 end;
1535
1536 AValue := power(Range^.adjustment^.page_size, 2 / 3);
1537
1538 if (AEvent^.scroll.direction = GDK_SCROLL_UP) or
1539 (AEvent^.scroll.direction = GDK_SCROLL_LEFT)
1540 then
1541 AValue := -AValue;
1542
1543 AValue := gtk_range_get_value(Range) + AValue;
1544
1545 AValue := Max(AValue, Range^.adjustment^.lower);
1546 AValue := Min(AValue, Range^.adjustment^.upper - Range^.adjustment^.page_size);
1547
1548 with Msg do
1549 begin
1550 Pos := Round(AValue);
1551 if Pos < High(SmallPos) then
1552 SmallPos := Pos
1553 else
1554 SmallPos := High(SmallPos);
1555
1556 ScrollBar := HWND(PtrUInt(AData));
1557 ScrollCode := SB_THUMBPOSITION;
1558 end;
1559 Result := TGtk3Widget(AData).DeliverMessage(Msg) <> 0;
1560 // DeliverMessage(.LCLObject, Msg) <> 0;
1561 end;
1562
Gtk3ScrollEventnull1563 function Gtk3ScrollEvent(AWidget: PGtkWidget; AEvent: PGdkEvent; AData: GPointer): GBoolean; cdecl;
1564 var
1565 AWinControl: TWinControl;
1566 EventXY: TPoint;
1567 AState: Cardinal;
1568 ShiftState: TShiftState;
1569 MappedXY: TPoint;
1570 MessE : TLMMouseEvent;
1571 begin
1572 Result := False;
1573 AWinControl := TGtk3Widget(AData).LCLObject;
1574
1575 if AEvent^.scroll.send_event = NO_PROPAGATION_TO_PARENT then
1576 exit;
1577
1578 EventXY := Point(TruncToInt(AEvent^.Scroll.X),TruncToInt(AEvent^.scroll.Y));
1579 AState := GtkModifierStateToShiftState(AEvent^.scroll.state, False);
1580 ShiftState := [];
1581 if AState and MK_SHIFT <> 0 then
1582 ShiftState := ShiftState + [ssShift];
1583 if AState and MK_CONTROL <> 0 then
1584 ShiftState := ShiftState + [ssCtrl];
1585 if AState and MK_ALT <> 0 then
1586 ShiftState := ShiftState + [ssAlt];
1587 // MappedXY := TranslateGdkPointToClientArea(AEvent^.scroll.window, EventXY,
1588 // {%H-}TGtk3Widget(AWinControl.Handle).GetContainerWidget);
1589 MappedXY := EventXY;
1590 MappedXY := SubtractScroll(TGtk3Widget(AWinControl.Handle).GetContainerWidget, MappedXY);
1591 //DebugLn('gtkMouseWheelCB ',DbgSName(AWinControl),' Mapped=',dbgs(MappedXY.X),',',dbgs(MappedXY.Y),' Event=',dbgs(EventXY.X),',',dbgs(EventXY.Y));
1592
1593 // this is a mouse wheel event
1594 FillChar(MessE,SizeOf(MessE),0);
1595 MessE.Msg := LM_MOUSEWHEEL;
1596 case AEvent^.scroll.direction of
1597 0 {GDK_SCROLL_UP}: MessE.WheelDelta := 120;
1598 1 {GDK_SCROLL_DOWN}: MessE.WheelDelta := -120;
1599 else
1600 exit;
1601 end;
1602 MessE.X := MappedXY.X;
1603 MessE.Y := MappedXY.Y;
1604 MessE.State := ShiftState;
1605 MessE.UserData := AWinControl;
1606 MessE.Button := 0;
1607
1608 // send the message directly to the LCL
1609 NotifyApplicationUserInput(AWinControl, MessE.Msg);
1610 if DeliverMessage(AWinControl, MessE) <> 0 then
1611 Result := True // message handled by LCL, stop processing
1612 else
1613 AEvent^.scroll.send_event := NO_PROPAGATION_TO_PARENT;
1614
1615 // DebugLn('Gtk3ScrollEvent for ', dbgsName(TGtk3Widget(AData).LCLObject),' Result ',dbgs(Result));
1616 end;
1617
1618 { TGtk3SplitterSide }
1619
TGtk3SplitterSide.CreateWidgetnull1620 function TGtk3SplitterSide.CreateWidget(const Params: TCreateParams): PGtkWidget;
1621 begin
1622 Result:=TGtkScrolledWindow.new(nil, nil);
1623 end;
1624
1625 { TGtk3Paned }
1626
TGtk3Paned.CreateWidgetnull1627 function TGtk3Paned.CreateWidget(const Params: TCreateParams): PGtkWidget;
1628 const
1629 ornt:array[TPairSplitterType] of TGtkOrientation=(
1630 GTK_ORIENTATION_HORIZONTAL,
1631 GTK_ORIENTATION_VERTICAL
1632 );
1633 begin
1634 Result:=TGtkPaned.new(ornt[TPairSplitter(Self.LCLObject).SplitterType]);
1635 end;
1636
1637 { TGtk3Widget }
1638
GtkEventMouseEnterLeavenull1639 function TGtk3Widget.GtkEventMouseEnterLeave(Sender: PGtkWidget; Event: PGdkEvent): Boolean;
1640 cdecl;
1641 var
1642 Msg: TLMessage;
1643 // MouseMsg: TLMMouseMove absolute Msg;
1644 {$IFDEF GTK3DEBUGCORE}
1645 MousePos: TPoint;
1646 {$ENDIF}
1647 begin
1648 Result := False;
1649 FillChar(Msg, SizeOf(Msg), #0);
1650 if Event^.type_ = GDK_ENTER_NOTIFY then
1651 Msg.Msg := LM_MOUSEENTER
1652 else
1653 Msg.Msg := LM_MOUSELEAVE;
1654
1655 NotifyApplicationUserInput(LCLObject, Msg.Msg);
1656 Result := DeliverMessage(Msg, True) <> 0;
1657 {$IFDEF GTK3DEBUGCORE}
1658 MousePos.X := Round(Event^.crossing.x);
1659 MousePos.Y := Round(Event^.crossing.y);
1660 DebugLn('GtkEventMouseEnterLeave: mousePos ',dbgs(MousePos),' Object ',dbgsName(LCLObject),
1661 ' IsEnter ',dbgs(Event^.type_ = GDK_ENTER_NOTIFY),' Result=',dbgs(Result));
1662 {$ENDIF}
1663 end;
1664
GtkEventMouseMovenull1665 function TGtk3Widget.GtkEventMouseMove(Sender: PGtkWidget; Event: PGdkEvent
1666 ): Boolean; cdecl;
1667 var
1668 Msg: TLMMouseMove;
1669 MousePos: TPoint;
1670 begin
1671 Result := False;
1672
1673 {$IFDEF GTK3DEBUGEVENTS}
1674 R := GetClientBounds;
1675 DebugLn(['GtkEventMouseMove: ',dbgsName(LCLObject),' Send=',dbgs(Event^.motion.send_event),
1676 ' state=',dbgs(event^.motion.state),
1677 ' x=',dbgs(Round(event^.motion.x)),
1678 ' y=',dbgs(Round(event^.motion.y)),
1679 ' x_root=',dbgs(Round(event^.motion.x_root)),
1680 ' y_root=',dbgs(Round(event^.motion.y_root)),
1681 ' STOP PROCESSING ? ',dbgs(Event^.motion.send_event = NO_PROPAGATION_TO_PARENT),
1682 ' GtkBounds ',dbgs(R),' LCLBounds ',dbgs(LCLObject.BoundsRect),' W=',dbgs(LCLObject.Width)]
1683 );
1684 {$ENDIF}
1685
1686 if Event^.motion.send_event = NO_PROPAGATION_TO_PARENT then
1687 exit;
1688
1689 FillChar(Msg, SizeOf(Msg), #0);
1690
1691 MousePos.x := Round(Event^.motion.x);
1692 MousePos.y := Round(Event^.motion.y);
1693
1694 OffsetMousePos(@MousePos);
1695
1696 Msg.XPos := SmallInt(MousePos.X);
1697 Msg.YPos := SmallInt(MousePos.Y);
1698
1699 Msg.Keys := GdkModifierStateToLCL(Event^.motion.state, False);
1700
1701 Msg.Msg := LM_MOUSEMOVE;
1702
1703
1704 NotifyApplicationUserInput(LCLObject, Msg.Msg);
1705 if Widget^.get_parent <> nil then
1706 Event^.motion.send_event := NO_PROPAGATION_TO_PARENT;
1707 DeliverMessage(Msg, True);
1708 end;
1709
TGtk3Widget.GtkEventPaintnull1710 function TGtk3Widget.GtkEventPaint(Sender: PGtkWidget; AContext: Pcairo_t
1711 ): Boolean; cdecl;
1712 var
1713 Msg: TLMPaint;
1714 AStruct: TPaintStruct;
1715 P: TPoint;
1716 AClipRect: TGdkRectangle;
1717 localClip:TRect;
1718 begin
1719 Result := False;
1720
1721 if not FHasPaint then
1722 exit;
1723
1724 FillChar(Msg, SizeOf(Msg), #0);
1725
1726 Msg.Msg := LM_PAINT;
1727 //New(AStruct);
1728 FillChar(AStruct, SizeOf(TPaintStruct), 0);
1729 Msg.PaintStruct := @AStruct;
1730
1731 with PaintData do
1732 begin
1733 if GetContainerWidget = nil then
1734 PaintWidget := Widget
1735 else
1736 PaintWidget := GetContainerWidget;
1737 ClipRegion := nil;
1738 // gdk_cairo_region(AContext, ClipRegion);
1739 // Event^.expose.region;
1740 //if ClipRect = nil then
1741 // New(ClipRect);
1742 gdk_cairo_get_clip_rectangle(AContext, @AClipRect);
1743 localClip:=RectFromGdkRect(AClipRect);
1744 ClipRect := @localClip;
1745 end;
1746
1747 FCairoContext := AContext;
1748 Msg.DC := BeginPaint(THandle(Self), AStruct);
1749 FContext := Msg.DC;
1750
1751 Msg.PaintStruct^.rcPaint := PaintData.ClipRect^;
1752 Msg.PaintStruct^.hdc := FContext;
1753
1754 // P := Point(0, 0);
1755
1756 P := Self.getClientOffset;
1757 if wtCustomControl in WidgetType then
1758 begin
1759 // ofsetting
1760 P := Point(0, 0);
1761 //TGtk3DeviceContext(Msg.DC).TranslateCairoToDevice;
1762 //P.X := Round(TGtk3CustomControl(Self).getHorizontalScrollbar^.get_adjustment^.get_value);
1763 //P.Y := Round(TGtk3CustomControl(Self).getVerticalScrollbar^.get_adjustment^.get_value);
1764 end else
1765 if wtScrollingWinControl in WidgetType then
1766 begin
1767 P := Point(0, 0);
1768 //DebugLn('GtkEventPaint Scrollable ScrollX=',dbgs(TGtk3ScrollableWin(Self).ScrollX),
1769 // ' scrollY=',dbgs(TGtk3ScrollableWin(Self).ScrollY),' P=',dbgs(P));
1770 //Inc(P.X, TGtk3ScrollableWin(Self).ScrollX);
1771 //Inc(P.Y, TGtk3ScrollableWin(Self).ScrollY);
1772 // cairo_surface_get_device_offset(cairo_get_target(AContext), @dx, @dy);
1773 // TGtk3DeviceContext(Msg.DC).TranslateCairoToDevice;
1774 end else
1775 if wtGroupBox in WidgetType then
1776 begin
1777 // why is gtk3 so crazy about parent/child relation ?!?
1778 // in this case child PGtkFixed has same top (+top caption) as parent TGtkFrame ... crap
1779 // debugln('groupbox paint offset ',dbgs(p));
1780 TGtk3DeviceContext(Msg.DC).TranslateCairoToDevice;
1781 P := Point(0, 0);
1782 end;
1783
1784 {$NOTE Currently TGtk3DeviceContext(Msg.DC).Translate(P) is creating incorrect offsets inside TPages for TLabel and maybe others}
1785 TGtk3DeviceContext(Msg.DC).Translate(P);
1786
1787 try
1788 try
1789 // DebugLn('**** Sending paint event to ',dbgsName(LCLObject),' clipRect=',dbgs(PaintData.ClipRect^),' P=',dbgs(P));
1790 DoBeforeLCLPaint;
1791 LCLObject.WindowProc(TLMessage(Msg));
1792 finally
1793 FCairoContext := nil;
1794 //Dispose(PaintData.ClipRect);
1795 Fillchar(FPaintData, SizeOf(FPaintData), 0);
1796 FContext := 0;
1797 EndPaint(THandle(Self), AStruct);
1798 //Dispose(AStruct);
1799 end;
1800 except
1801 Application.HandleException(nil);
1802 end;
1803 end;
1804
GtkEventResizenull1805 function TGtk3Widget.GtkEventResize(Sender: PGtkWidget; Event: PGdkEvent
1806 ): Boolean; cdecl;
1807 begin
1808 {$IF DEFINED(GTK3DEBUGEVENTS) OR DEFINED(GTK3DEBUGSIZE)}
1809 DebugLn('GtkEventResize: ',dbgsName(LCLObject),' Send=',dbgs(Event^.configure.send_event),
1810 ' x=',dbgs(Round(event^.configure.x)),
1811 ' y=',dbgs(Round(event^.configure.y)),
1812 ' w=',dbgs(Round(event^.configure.height)),
1813 ' h=',dbgs(Round(event^.configure.width)));
1814 {$ENDIF}
1815 Result := False;
1816 end;
1817
1818 procedure TGtk3Widget.GtkEventFocus(Sender: PGtkWidget; Event: PGdkEvent);
1819 cdecl;
1820 var
1821 Msg: TLMessage;
1822 begin
1823 {$IF DEFINED(GTK3DEBUGEVENTS) OR DEFINED(GTK3DEBUGFOCUS)}
1824 DebugLn('TGtk3Widget.GtkEventFocus ',dbgsName(LCLObject),' FocusIn ',dbgs(Event^.focus_change.in_ <> 0));
1825 {$ENDIF}
1826 FillChar(Msg, SizeOf(Msg), #0);
1827 if Event^.focus_change.in_ <> 0 then
1828 Msg.Msg := LM_SETFOCUS
1829 else
1830 Msg.Msg := LM_KILLFOCUS;
1831 DeliverMessage(Msg);
1832 end;
1833
1834 procedure TGtk3Widget.GtkEventDestroy; cdecl;
1835 var
1836 Msg: TLMessage;
1837 begin
1838 FillChar(Msg, SizeOf(Msg), #0);
1839 Msg.Msg := LM_DESTROY;
1840 DeliverMessage(Msg);
1841 Release;
1842 end;
1843
TGtk3Widget.GtkEventMouseWheelnull1844 function TGtk3Widget.GtkEventMouseWheel(Sender: PGtkWidget; Event: PGdkEvent
1845 ): Boolean; cdecl;
1846 var
1847 Msg: TLMMouseEvent;
1848 EventXY: TPoint;
1849 begin
1850 // gtk3 have ugly bug with scroll-event
1851 // https://bugzilla.gnome.org/show_bug.cgi?id=675959
1852 Result := False;
1853 EventXY := Point(TruncToInt(Event^.scroll.x), TruncToInt(Event^.scroll.y));
1854 FillChar(Msg{%H-},SizeOf(Msg),0);
1855 Msg.Msg := LM_MOUSEWHEEL;
1856 //DebugLn('Scroll ',Format('deltaX %2.2n deltaY %2.2n x %2.2n y %2.2n rootx %2.2n rooty %2.2n',
1857 // [Event^.scroll.delta_x, Event^.scroll.delta_y, Event^.scroll.x, Event^.scroll.y,
1858 // Event^.scroll.x_root, Event^.scroll.y_root]));
1859 if Event^.scroll.direction = GDK_SCROLL_UP then
1860 Msg.WheelDelta := 120
1861 else
1862 if Event^.scroll.direction = GDK_SCROLL_DOWN then
1863 Msg.WheelDelta := -120
1864 else
1865 exit;
1866 Msg.X := EventXY.X;
1867 Msg.Y := EventXY.Y;
1868 Msg.State := GdkModifierStateToShiftState(Event^.scroll.state);
1869 Msg.UserData := LCLObject;
1870 Msg.Button := 0;
1871
1872 NotifyApplicationUserInput(LCLObject, Msg.Msg);
1873 if Widget^.get_parent <> nil then
1874 Event^.motion.send_event := NO_PROPAGATION_TO_PARENT;
1875 if DeliverMessage(Msg, True) <> 0 then
1876 Result := True;
1877 end;
1878
TGtk3Widget.IsValidHandlenull1879 function TGtk3Widget.IsValidHandle: Boolean;
1880 begin
1881 Result := Assigned(FWidget) and Gtk3IsWidget(FWidget) and not FWidget^.in_destruction;
1882 end;
1883
IsWidgetOknull1884 function TGtk3Widget.IsWidgetOk: Boolean;
1885 begin
1886 Result := (FWidget <> nil) and Gtk3IsWidget(FWidget);
1887 end;
1888
TGtk3Widget.IsIconicnull1889 function TGtk3Widget.IsIconic: Boolean;
1890 begin
1891 Result := False;
1892 if IsWidgetOk then
1893 begin
1894 if FWidget^.get_window <> nil then
1895 Result := gdk_window_get_state(FWidget^.get_window) and GDK_WINDOW_STATE_ICONIFIED <> 0;
1896 end;
1897 end;
1898
getTypenull1899 function TGtk3Widget.getType: TGType;
1900 begin
1901 Result := getContainerWidget^.g_type_instance.g_class^.g_type;
1902 end;
1903
getTypeNamenull1904 function TGtk3Widget.getTypeName: PgChar;
1905 begin
1906 Result := g_type_name(getType);
1907 end;
1908
1909 procedure TGtk3Widget.lowerWidget;
1910 begin
1911 if Gtk3IsGdkWindow(FWidget^.window) then
1912 FWidget^.window^.lower;
1913 end;
1914
1915 procedure TGtk3Widget.raiseWidget;
1916 begin
1917 if Gtk3IsGdkWindow(FWidget^.window) then
1918 FWidget^.window^.raise_;
1919 end;
1920
1921 procedure TGtk3Widget.stackUnder(AWidget: PGtkWidget);
1922 begin
1923 // FWidget^.
1924 end;
1925
TGtk3Widget.GetCapturenull1926 function TGtk3Widget.GetCapture: TGtk3Widget;
1927 var
1928 AHandle: HWND;
1929 begin
1930 AHandle := HwndFromGtkWidget(gtk_grab_get_current);
1931 if AHandle <> 0 then
1932 Result := TGtk3Widget(AHandle);
1933 end;
1934
SetCapturenull1935 function TGtk3Widget.SetCapture: HWND;
1936 begin
1937 Result := HWND(GetCapture);
1938 gtk_grab_add(GetContainerWidget);
1939 end;
1940
GtkEventKeynull1941 function TGtk3Widget.GtkEventKey(Sender: PGtkWidget; Event: PGdkEvent; AKeyPress: Boolean): Boolean;
1942 cdecl;
1943 const
1944 CN_KeyDownMsgs: array[Boolean] of UINT = (CN_KEYDOWN, CN_SYSKEYDOWN);
1945 CN_KeyUpMsgs: array[Boolean] of UINT = (CN_KEYUP, CN_SYSKEYUP);
1946 LM_KeyDownMsgs: array[Boolean] of UINT = (LM_KEYDOWN, LM_SYSKEYDOWN);
1947 LM_KeyUpMsgs: array[Boolean] of UINT = (LM_KEYUP, LM_SYSKEYUP);
1948 CN_CharMsg: array[Boolean] of UINT = (CN_CHAR, CN_SYSCHAR);
1949 LM_CharMsg: array[Boolean] of UINT = (LM_CHAR, LM_SYSCHAR);
1950 var
1951 AEvent: TGdkEventKey;
1952 Msg: TLMKey;
1953 CharMsg: TLMChar;
1954 KeyCode: Word;
1955 AShiftState: TShiftState;
1956 AEventString: String;
1957 KeyValue, ACharCode: Word;
1958 LCLModifiers: Word;
1959 IsSysKey: Boolean;
1960 UTF8Char: TUTF8Char;
1961 AChar: Char;
1962 IsArrowKey: Boolean;
1963 begin
1964 //TODO: finish LCL messaging
1965 Result := False;
1966 AEvent := Event^.key;
1967 FillChar(Msg, SizeOf(Msg), 0);
1968 AEventString := AEvent.string_;
1969
1970 if gdk_keyval_is_lower(AEvent.keyval) then
1971 KeyValue := Word(gdk_keyval_to_upper(AEvent.keyval))
1972 else
1973 KeyValue := Word(AEvent.keyval);
1974
1975 // state=16 = numlock= on.
1976
1977 LCLModifiers := GtkModifierStateToShiftState(AEvent.state, True);
1978
1979 if length(AEventString) = 0 then
1980 begin
1981 if KeyValue = GDK_KEY_Alt_L then
1982 LCLModifiers := LCLModifiers or KF_ALTDOWN
1983 else
1984 if (KeyValue = GDK_KEY_Control_L) or (KeyValue = GDK_KEY_Control_R) then
1985 LCLModifiers := LCLModifiers or MK_CONTROL
1986 else
1987 if (KeyValue = GDK_KEY_Shift_L) or (KeyValue = GDK_KEY_Shift_R) then
1988 LCLModifiers := LCLModifiers or MK_SHIFT;
1989 // writeln('MODIFIERS BY KEYS ',LCLModifiers);
1990 end;
1991
1992 IsSysKey := LCLModifiers and KF_ALTDOWN <> 0;
1993
1994 if not AKeyPress then
1995 LCLModifiers := LCLModifiers or KF_UP;
1996
1997 // else
1998 // writeln('KeyRelease: ',dbgsName(LCLObject),' Dump state=',AEvent.state,' hwkey=',KeyCode,' keyvalue=',KeyValue,' modifier=',AEvent.Bitfield0.is_modifier);
1999
2000 // this is just for testing purposes.
2001 ACharCode := GdkKeyToLCLKey(KeyValue);
2002 if KeyValue > VK_UNDEFINED then
2003 KeyValue := ACharCode; // VK_UNKNOWN;
2004
2005 if AKeyPress and (ACharCode = VK_TAB) then
2006 begin
2007
2008 end;
2009
2010 IsArrowKey := ((ACharCode = VK_UP) or (ACharCode = VK_DOWN) or (ACharCode = VK_LEFT) or (ACharCode = VK_RIGHT));
2011
2012 {$IFDEF GTK3DEBUGKEYPRESS}
2013 if AKeyPress then
2014 writeln('EVENT KeyPress: ',dbgsName(LCLObject),' Dump state=',AEvent.state,' keyvalue=',KeyValue,' modifier=',AEvent.Bitfield0.is_modifier,
2015 ' KeyValue ',KeyValue,' MODIFIERS ',LCLModifiers,' CharCode ',ACharCode,' EAT ',EatArrowKeys(ACharCode))
2016 else
2017 writeln('EVENT KeyRelease: ',dbgsName(LCLObject),' Dump state=',AEvent.state,' keyvalue=',KeyValue,' modifier=',AEvent.Bitfield0.is_modifier,
2018 ' KeyValue ',KeyValue,' MODIFIERS ',LCLModifiers,' CharCode ',ACharCode,
2019 ' EAT ',EatArrowKeys(ACharCode));
2020 {$ENDIF}
2021
2022 if (ACharCode <> VK_UNKNOWN) then
2023 begin
2024 if AKeyPress then
2025 Msg.Msg := CN_KeyDownMsgs[IsSysKey]
2026 else
2027 Msg.Msg := CN_KeyUpMsgs[IsSysKey];
2028 Msg.CharCode := ACharCode;
2029 Msg.KeyData := PtrInt((KeyValue shl 16) or (LCLModifiers shl 16) or $0001);
2030
2031 NotifyApplicationUserInput(LCLObject, Msg.Msg);
2032
2033 if not CanSendLCLMessage then
2034 exit;
2035
2036 if (DeliverMessage(Msg, True) <> 0) or (Msg.CharCode = VK_UNKNOWN) or EatArrowKeys(ACharCode) then
2037 begin
2038 {$IFDEF GTK3DEBUGKEYPRESS}
2039 DebugLn('CN_KeyDownMsgs handled ... exiting');
2040 {$ENDIF}
2041 exit(True);
2042 end;
2043
2044 if not CanSendLCLMessage then
2045 exit;
2046
2047 if AKeyPress then
2048 Msg.Msg := LM_KeyDownMsgs[IsSysKey]
2049 else
2050 Msg.Msg := LM_KeyUpMsgs[IsSysKey];
2051 Msg.CharCode := ACharCode;
2052 Msg.KeyData := PtrInt((KeyValue shl 16) or (LCLModifiers shl 16) or $0001);
2053
2054 NotifyApplicationUserInput(LCLObject, Msg.Msg);
2055
2056 if not CanSendLCLMessage then
2057 exit;
2058
2059 {$warning workaround for GtkTreeView key bindings.Must find out what LCL does with
2060 this keys.}
2061 if IsArrowKey and ([wtListBox,wtListView] * WidgetType <> []) then
2062 // let gtk3 select cell for now. Must check what LCL does with arrow keys
2063 // since gtk3 becomes crazy after delivery of this message
2064 else
2065 if (DeliverMessage(Msg, True) <> 0) or (Msg.CharCode = 0) then
2066 begin
2067 Result := Msg.CharCode = 0;
2068 {$IFDEF GTK3DEBUGKEYPRESS}
2069 DebugLn('LM_KeyDownMsgs handled ... exiting ',dbgs(ACharCode),' Result=',dbgs(Result),' AKeyPress=',dbgs(AKeyPress));
2070 {$ENDIF}
2071 exit;
2072 end;
2073
2074 if not CanSendLCLMessage then
2075 exit;
2076
2077 end;
2078
2079 if AKeyPress and (length(AEventString) > 0) then
2080 begin
2081 UTF8Char := AEventString;
2082 // TODO: If not IsControlKey
2083 Result := LCLObject.IntfUTF8KeyPress(UTF8Char, 1, IsSysKey);
2084
2085 if not CanSendLCLMessage then
2086 exit;
2087
2088 if Result then
2089 begin
2090 {$IFDEF GTK3DEBUGKEYPRESS}
2091 DebugLn('LCLObject.IntfUTF8KeyPress handled ... exiting');
2092 {$ENDIF}
2093 exit;
2094 end;
2095
2096 // create the CN_CHAR / CN_SYSCHAR message
2097 FillChar(CharMsg, SizeOf(CharMsg), 0);
2098 CharMsg.Msg := CN_CharMsg[IsSysKey];
2099 CharMsg.KeyData := Msg.KeyData;
2100 AChar := AEventString[1];
2101 CharMsg.CharCode := Word(AChar);
2102 NotifyApplicationUserInput(LCLObject, CharMsg.Msg);
2103
2104 if not CanSendLCLMessage then
2105 exit;
2106
2107 Result := (DeliverMessage(CharMsg, True) <> 0) or (CharMsg.CharCode = VK_UNKNOWN);
2108
2109 if not CanSendLCLMessage then
2110 exit;
2111
2112 if Result then
2113 begin
2114 {$IFDEF GTK3DEBUGKEYPRESS}
2115 DebugLn('CN_CharMsg handled ... exiting');
2116 {$ENDIF}
2117 exit;
2118 end;
2119
2120 //Send a LM_(SYS)CHAR
2121 CharMsg.Msg := LM_CharMsg[IsSysKey];
2122
2123 NotifyApplicationUserInput(LCLObject, CharMsg.Msg);
2124
2125 if not CanSendLCLMessage then
2126 exit;
2127
2128 DeliverMessage(CharMsg, True);
2129
2130 if not CanSendLCLMessage then
2131 exit;
2132 end;
2133 if AKeyPress then
2134 begin
2135 {$IFDEF GTK3DEBUGKEYPRESS}
2136 if Msg.CharCode in FKeysToEat then
2137 begin
2138 DebugLn('EVENT: ******* KeyPress charcode is in keys to eat (FKeysToEat), charcode=',dbgs(Msg.CharCode));
2139 end;
2140 {$ENDIF}
2141 Result := Msg.CharCode in FKeysToEat;
2142 end;
2143 end;
2144
GtkEventMousenull2145 function TGtk3Widget.GtkEventMouse(Sender: PGtkWidget; Event: PGdkEvent): Boolean;
2146 cdecl;
2147 var
2148 Msg: TLMMouse;
2149 MsgPopup : TLMMouse;
2150 MousePos: TPoint;
2151 MButton: guint;
2152 begin
2153 Result := False;
2154 {$IF DEFINED(GTK3DEBUGEVENTS) OR DEFINED(GTK3DEBUGMOUSE)}
2155 DebugLn('TGtk3Widget.GtkEventMouse ',dbgsName(LCLObject),
2156 ' propagate=',dbgs(not (Event^.button.send_event = NO_PROPAGATION_TO_PARENT)));
2157 {$ENDIF}
2158 if Event^.button.send_event = NO_PROPAGATION_TO_PARENT then
2159 exit;
2160
2161 FillChar(Msg, SizeOf(Msg), #0);
2162
2163 MousePos.x := Round(Event^.button.x);
2164 MousePos.y := Round(Event^.button.y);
2165
2166 OffsetMousePos(@MousePos);
2167
2168 Msg.Keys := GdkModifierStateToLCL(Event^.button.state, False);
2169
2170 Msg.XPos := SmallInt(MousePos.X);
2171 Msg.YPos := SmallInt(MousePos.Y);
2172
2173 MButton := Event^.button.button;
2174
2175 case Event^.type_ of
2176 // GDK_BUTTON_PRESS
2177 4:
2178 begin
2179 if MButton = GTK3_LEFT_BUTTON then
2180 Msg.Msg := LM_LBUTTONDOWN
2181 else
2182 if MButton = GTK3_RIGHT_BUTTON then
2183 Msg.Msg := LM_RBUTTONDOWN
2184 else
2185 if MButton = GTK3_MIDDLE_BUTTON then
2186 Msg.Msg := LM_MBUTTONDOWN;
2187 end;
2188 // GDK_BUTTON2_PRESS -> double click
2189 5: Msg.Msg := LM_LBUTTONDBLCLK;
2190 // GDK_BUTTON_RELEASE: TGdkEventType = 7;
2191 7:
2192 begin
2193 if MButton = GTK3_LEFT_BUTTON then
2194 Msg.Msg := LM_LBUTTONUP
2195 else
2196 if MButton = GTK3_RIGHT_BUTTON then
2197 Msg.Msg := LM_RBUTTONUP
2198 else
2199 if MButton = GTK3_MIDDLE_BUTTON then
2200 Msg.Msg := LM_MBUTTONUP;
2201 end;
2202 end;
2203
2204 {$IF DEFINED(GTK3DEBUGEVENTS) OR DEFINED(GTK3DEBUGMOUSE)}
2205 DebugLn('TGtk3Widget.GtkEventMouse ',dbgsName(LCLObject),
2206 ' msg=',dbgs(msg.Msg), ' point=',dbgs(Msg.XPos),',',dbgs(Msg.YPos));
2207 {$ENDIF}
2208 NotifyApplicationUserInput(LCLObject, Msg.Msg);
2209 Event^.button.send_event := NO_PROPAGATION_TO_PARENT;
2210
2211 Result := false;
2212 if Msg.Msg = LM_RBUTTONDOWN then
2213 begin
2214 MsgPopup := Msg;
2215 MsgPopup.Msg := LM_CONTEXTMENU;
2216 MsgPopup.XPos := SmallInt(Round(Event^.button.x_root));
2217 MsgPopup.YPos := SmallInt(Round(Event^.button.y_root));
2218 Result := DeliverMessage(MsgPopup, True) <> 0;
2219 end;
2220 if not Result then
2221 Result := DeliverMessage(Msg, True) <> 0;
2222 if Event^.type_ = GDK_BUTTON_RELEASE then
2223 begin
2224 Msg.Msg := LM_CLICKED;
2225 DeliverMessage(Msg, True);
2226 end;
2227 end;
2228
GetVisiblenull2229 function TGtk3Widget.GetVisible: Boolean;
2230 begin
2231 Result := Assigned(FWidget) and FWidget^.visible;
2232 end;
2233
2234 procedure TGtk3Widget.SetEnabled(AValue: Boolean);
2235 begin
2236 if IsWidgetOK then
2237 FWidget^.set_sensitive(AValue);
2238 end;
2239
2240 procedure TGtk3Widget.SetFont(AValue: PPangoFontDescription);
2241 begin
2242 if IsWidgetOk then
2243 begin
2244 GetContainerWidget^.override_font(AValue);
2245 end;
2246 end;
2247
2248 procedure TGtk3Widget.SetFontColor(AValue: TColor);
2249 var
2250 AColor: TGdkRGBA;
2251 i: TGtkStateType;
2252 begin
2253 if IsWidgetOK then
2254 begin
2255 AColor := TColortoTGdkRGBA(AValue);
2256 if FWidget <> GetContainerWidget then
2257 begin
2258 with FWidget^ do
2259 begin
2260 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2261 override_color(i, @AColor);
2262 end;
2263 end;
2264 with GetContainerWidget^ do
2265 begin
2266 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2267 override_color(i, @AColor);
2268 end;
2269 end;
2270 end;
2271
2272 procedure TGtk3Widget.SetColor(AValue: TColor);
2273 var
2274 AColor: TGdkRGBA;
2275 i: TGtkStateType;
2276 ARgba: TGdkRGBA;
2277 R: Double;
2278 G: Double;
2279 B: Double;
2280 begin
2281 // new way (gtk3) but still buggy
2282 if IsWidgetOK and (0 > 1) then
2283 begin
2284 if AValue = clDefault then
2285 begin
2286 (*
2287 with FDefaultRGBA do
2288 begin
2289 writeln('clDefault ',Format('R %2.2n G %2.2n B %2.2n A %2.2n',[R, G, B , Alpha]));
2290 ARgba.red := R;
2291 ARgba.green := G;
2292 ARgba.blue := B;
2293 ARgba.alpha := Alpha;
2294 end;
2295 *)
2296 end else
2297 begin
2298 ARgba := TColortoTGdkRGBA(AValue);
2299 {$info GTK3: set GdkRGBA.alpah to 1.0?}
2300
2301 {ColorToCairoRGB(ColorToRGB(AValue), R, G, B);
2302 ARgba.red := R;
2303 ARgba.green := G;
2304 ARgba.blue := B;
2305 ARgba.alpha := 1.0;}
2306 end;
2307 if FWidget <> GetContainerWidget then
2308 begin
2309 with FWidget^ do
2310 begin
2311 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2312 begin
2313 if AValue = clDefault then
2314 begin
2315 ARgba.red := FWidgetRGBA[i].R;
2316 ARgba.green := FWidgetRGBA[i].G;
2317 ARgba.blue := FWidgetRGBA[i].B;
2318 ARgba.alpha := FWidgetRGBA[i].Alpha;
2319 end;
2320 FWidget^.override_background_color(i, @ARgba);
2321 end;
2322 end;
2323 end;
2324 with GetContainerWidget^ do
2325 begin
2326 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2327 begin
2328 //if AVAlue = clDefault then
2329 // GetContainerWidget^.get_style_context^.get_background_color(GTK_STATE_NORMAL, @ARgba);
2330 if AValue = clDefault then
2331 begin
2332 ARgba.red := FCentralWidgetRGBA[i].R;
2333 ARgba.green := FCentralWidgetRGBA[i].G;
2334 ARgba.blue := FCentralWidgetRGBA[i].B;
2335 ARgba.alpha := FCentralWidgetRGBA[i].Alpha;
2336 end;
2337 GetContainerWidget^.override_background_color(i, @ARgba);
2338 end;
2339 end;
2340 end;
2341
2342 if IsWidgetOK then
2343 begin
2344 AColor := TColortoTGdkRGBA(AValue);
2345 if FWidget <> GetContainerWidget then
2346 begin
2347 with FWidget^ do
2348 begin
2349 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2350 if AValue = clDefault then
2351 override_background_color(i, nil)
2352 else
2353 override_background_color(i, @AColor);
2354 end;
2355 end;
2356 with GetContainerWidget^ do
2357 begin
2358 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2359 begin
2360 if AValue = clDefault then
2361 override_background_color(i, nil)
2362 else
2363 override_background_color(i, @AColor);
2364 end;
2365 end;
2366 end;
2367 end;
2368
TGtk3Widget.GetStyleContextnull2369 function TGtk3Widget.GetStyleContext: PGtkStyleContext;
2370 begin
2371 Result := nil;
2372 if IsWidgetOK then
2373 Result := GetContainerWidget^.get_style_context;
2374 end;
2375
TGtk3Widget.GetFontnull2376 function TGtk3Widget.GetFont: PPangoFontDescription;
2377 var
2378 AContext: PPangoContext;
2379 begin
2380 Result := nil;
2381 if IsWidgetOK then
2382 begin
2383 AContext := GetContainerWidget^.get_pango_context;
2384 Result := pango_context_get_font_description(AContext);
2385 end;
2386 end;
2387
CanSendLCLMessagenull2388 function TGtk3Widget.CanSendLCLMessage: Boolean;
2389 begin
2390 Result := IsWidgetOk and (LCLObject <> nil);
2391 end;
2392
GetCairoContextnull2393 function TGtk3Widget.GetCairoContext: Pcairo_t;
2394 begin
2395 Result := FCairoContext;
2396 end;
2397
GetEnablednull2398 function TGtk3Widget.GetEnabled: Boolean;
2399 begin
2400 Result := False;
2401 if IsWidgetOK then
2402 Result := FWidget^.get_sensitive;
2403 end;
2404
TGtk3Widget.GetFontColornull2405 function TGtk3Widget.GetFontColor: TColor;
2406 var
2407 AStyle: PGtkStyleContext;
2408 AGdkRGBA: TGdkRGBA;
2409 begin
2410 Result := clDefault;
2411 if IsWidgetOK then
2412 begin
2413 AStyle := GetStyleContext;
2414 AStyle^.get_background_color(GTK_STATE_NORMAL, @AGdkRGBA);
2415 Result := TGdkRGBAToTColor(AGdkRGBA);
2416 end;
2417 end;
2418
GetColornull2419 function TGtk3Widget.GetColor: TColor;
2420 var
2421 AStyle: PGtkStyleContext;
2422 AColor: TGdkRGBA;
2423 begin
2424 Result := clDefault;
2425 if IsWidgetOK then
2426 begin
2427 AStyle := GetStyleContext;
2428 AStyle^.get_background_color(GTK_STATE_NORMAL, @AColor);
2429 Result := TGdkRGBAToTColor(AColor);
2430 end;
2431 end;
2432
2433 procedure TGtk3Widget.SetStyleContext(AValue: PGtkStyleContext);
2434 begin
2435 {$NOTE Gtk3: Find a nice way to assign StyleContext}
2436 {if IsWidgetOK then
2437 GetContainerWidget^.set_style(AValue);}
2438 end;
2439
TGtk3Widget.getTextnull2440 function TGtk3Widget.getText: String;
2441 begin
2442 Result := '';
2443 end;
2444
2445 procedure TGtk3Widget.setText(AValue: String);
2446 begin
2447 // DebugLn('WARNING: ',dbgsName(LCLObject),' self=',dbgsName(Self),' does not implement setText !');
2448 end;
2449
2450 procedure TGtk3Widget.SetVisible(AValue: Boolean);
2451 begin
2452 if IsWidgetOK then
2453 FWidget^.Visible := AValue;
2454 end;
2455
QueryInterfacenull2456 function TGtk3Widget.QueryInterface(constref iid: TGuid; out obj): LongInt;
2457 cdecl;
2458 begin
2459 if GetInterface(iid, obj) then
2460 Result := 0
2461 else
2462 Result := E_NOINTERFACE;
2463 end;
2464
TGtk3Widget._AddRefnull2465 function TGtk3Widget._AddRef: LongInt; cdecl;
2466 begin
2467 Result := -1; // no ref counting
2468 end;
2469
_Releasenull2470 function TGtk3Widget._Release: LongInt; cdecl;
2471 begin
2472 Result := -1;
2473 end;
2474
EatArrowKeysnull2475 function TGtk3Widget.EatArrowKeys(const AKey: Word): Boolean;
2476 begin
2477 Result := AKey in [VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN];
2478 end;
2479
TGtk3Widget.GetContextnull2480 function TGtk3Widget.GetContext: HDC;
2481 begin
2482 Result := FContext;
2483 end;
2484
TGtk3Widget.CreateWidgetnull2485 function TGtk3Widget.CreateWidget(const Params: TCreateParams): PGtkWidget;
2486 begin
2487 Result := PGtkWidget(TGtkWidget.newv(32, 0 ,nil));
2488 end;
2489
2490 procedure TGtk3Widget.DestroyWidget;
2491 begin
2492 if IsWidgetOk and FOwnWidget then
2493 FWidget^.destroy_;
2494 FWidget := nil;
2495 end;
2496
2497 procedure TGtk3Widget.DoBeforeLCLPaint;
2498 begin
2499 //
2500 end;
2501
2502 constructor TGtk3Widget.Create(const AWinControl: TWinControl;
2503 const AParams: TCreateParams);
2504 begin
2505 inherited Create;
2506 FContext := 0;
2507 FHasPaint := False;
2508 FWidget := nil;
2509 FOwner := nil;
2510 FCentralWidget := nil;
2511 FOwnWidget := True;
2512 // Initializes the properties
2513 FProps := nil;
2514 LCLObject := AWinControl;
2515 FKeysToEat := [VK_TAB, VK_RETURN, VK_ESCAPE];
2516 // FHasPaint := False;
2517
2518 FParams := AParams;
2519 InitializeWidget;
2520 end;
2521
2522 constructor TGtk3Widget.CreateFrom(const AWinControl: TWinControl;
2523 AWidget: PGtkWidget);
2524 begin
2525 inherited Create;
2526 FContext := 0;
2527 FHasPaint := False;
2528 FWidget := nil;
2529 FOwner := nil;
2530 FCentralWidget := nil;
2531 FOwnWidget := False;
2532 // Initializes the properties
2533 FProps := nil;
2534 LCLObject := AWinControl;
2535 FWidget := AWidget;
2536 // FKeysToEat := [VK_TAB, VK_RETURN, VK_ESCAPE];
2537 // FHasPaint := False;
2538 end;
2539
2540 procedure TGtk3Widget.InitializeWidget;
2541 var
2542 ARect: TGdkRectangle;
2543 ARgba: TGdkRGBA;
2544 i: TGtkStateType;
2545 begin
2546 FFocusableByMouse := False;
2547 FCentralWidget := nil;
2548 FCairoContext := nil;
2549 FContext := 0;
2550 FEnterLeaveTime := 0;
2551
2552 FWidgetType := [wtWidget];
2553 FWidget := CreateWidget(FParams);
2554
2555 // connect events
2556 if not (wtWindow in FWidgetType) then
2557 begin
2558 FWidget^.show_all;
2559 with ARect do
2560 begin
2561 x := LCLObject.Left;
2562 y := LCLObject.Top;
2563 width := LCLObject.Width;
2564 height := LCLObject.Height;
2565 end;
2566 FWidget^.set_allocation(@ARect);
2567 end;
2568 LCLIntf.SetProp(HWND(Self),'lclwidget',Self);
2569
2570 // move signal connections into attach events
2571 FWidget^.set_events(GDK_ALL_EVENTS_MASK);
2572 g_signal_connect_data(FWidget, 'event', TGCallback(@Gtk3WidgetEvent), Self, nil, 0);
2573
2574
2575 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2576 begin
2577 FWidget^.get_style_context^.get_background_color(i, @ARgba);
2578 with FWidgetRGBA[i] do
2579 begin
2580 R := ARgba.red;
2581 G := ARgba.green;
2582 B := ARgba.blue;
2583 Alpha := ARgba.alpha;
2584 end;
2585 end;
2586
2587
2588 if FCentralWidget <> nil then
2589 begin
2590 FCentralWidget^.set_events(GDK_ALL_EVENTS_MASK);
2591 g_signal_connect_data(FCentralWidget, 'event', TGCallback(@Gtk3WidgetEvent), Self, nil, 0);
2592 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2593 begin
2594 FCentralWidget^.get_style_context^.get_background_color(i, @ARgba);
2595 with FCentralWidgetRGBA[i] do
2596 begin
2597 R := ARgba.red;
2598 G := ARgba.green;
2599 B := ARgba.blue;
2600 Alpha := ARgba.alpha;
2601 end;
2602 end;
2603 end else
2604 begin
2605 for i := GTK_STATE_NORMAL to GTK_STATE_INSENSITIVE do
2606 FCentralWidgetRGBA[i] := FWidgetRGBA[i];
2607 end;
2608 g_signal_connect_data(GetContainerWidget,'draw', TGCallback(@Gtk3DrawWidget), Self, nil, 0);
2609 g_signal_connect_data(GetContainerWidget,'scroll-event', TGCallback(@Gtk3ScrollEvent), Self, nil, 0);
2610
2611 // must hide all by default
2612 FWidget^.hide;
2613
2614 g_signal_connect_data(FWidget,'hide', TGCallback(@Gtk3WidgetHide), Self, nil, 0);
2615 g_signal_connect_data(FWidget,'show', TGCallback(@Gtk3WidgetShow), Self, nil, 0);
2616 g_signal_connect_data(FWidget,'map', TGCallback(@Gtk3MapWidget), Self, nil, 0);
2617 g_signal_connect_data(FWidget,'size-allocate',TGCallback(@Gtk3SizeAllocate), Self, nil, 0);
2618 // g_signal_connect_data(FWidget, 'motion_notify_event', TGCallback(@Gtk3MotionNotifyEvent), LCLObject, nil, 0);
2619 end;
2620
2621 procedure TGtk3Widget.DeInitializeWidget;
2622 begin
2623
2624 end;
2625
2626 procedure TGtk3Widget.RecreateWidget;
2627 begin
2628
2629 end;
2630
2631 procedure TGtk3Widget.DestroyNotify(AWidget: PGtkWidget);
2632 begin
2633
2634 end;
2635
2636 destructor TGtk3Widget.Destroy;
2637 begin
2638 DestroyWidget;
2639 inherited Destroy;
2640 end;
2641
CanFocusnull2642 function TGtk3Widget.CanFocus: Boolean;
2643 begin
2644 Result := False;
2645 if IsWidgetOK then
2646 Result := FWidget^.can_focus or GetContainerWidget^.can_focus;
2647 end;
2648
GetFocusableByMousenull2649 function TGtk3Widget.GetFocusableByMouse: Boolean;
2650 begin
2651 Result := FFocusableByMouse;
2652 end;
2653
getClientOffsetnull2654 function TGtk3Widget.getClientOffset: TPoint;
2655 var
2656 Allocation: TGtkAllocation;
2657 R: TRect;
2658 begin
2659 {offset between inner and outer rect of widget.
2660 It tricky since some widgets have regular offset eg
2661 Parent (FWidget) = (120,80) Child (FCentralWidget) = (2,2)
2662 but some are
2663 Parent (FWidget) = (120,80) Child (FCentralWidget) = (122,82).
2664 Such widgets are usually those with FCentralWidget^.get_has_window}
2665 Result := Point(0, 0);
2666 if Widget <> getContainerWidget then
2667 begin
2668 GetContainerWidget^.get_allocation(@Allocation);
2669 Result.X := Allocation.X;
2670 Result.Y := Allocation.Y;
2671 end else
2672 exit;
2673 R := getClientBounds;
2674 Result := Point(Result.x + R.Left, Result.y + R.Top);
2675 end;
2676
getWidgetPosnull2677 function TGtk3Widget.getWidgetPos: TPoint;
2678 var
2679 Allocation: TGtkAllocation;
2680 begin
2681 Result := Point(0, 0);
2682 if IsWidgetOk then
2683 begin
2684 FWidget^.get_allocation(@Allocation);
2685 Result := Point(Allocation.X, Allocation.Y);
2686 end;
2687 end;
2688
2689 procedure TGtk3Widget.OffsetMousePos(APoint: PPoint);
2690 begin
2691 with getClientOffset do
2692 begin
2693 dec(APoint^.x, x);
2694 dec(APoint^.y, y);
2695 end;
2696 end;
2697
TGtk3Widget.DeliverMessagenull2698 function TGtk3Widget.DeliverMessage(var Msg; const AIsInputEvent: Boolean
2699 ): LRESULT;
2700 begin
2701 Result := LRESULT(AIsInputEvent);
2702 if LCLObject = nil then
2703 Exit;
2704 try
2705 if LCLObject.HandleAllocated then
2706 begin
2707 LCLObject.WindowProc(TLMessage(Msg));
2708 Result := TLMessage(Msg).Result;
2709 end;
2710 except
2711 Application.HandleException(nil);
2712 end;
2713 end;
2714
getClientRectnull2715 function TGtk3Widget.getClientRect: TRect;
2716 var
2717 AAlloc: TGtkAllocation;
2718 begin
2719 Result := Rect(0, 0, 0, 0);
2720 if not IsWidgetOK then
2721 exit;
2722 if GetContainerWidget^.get_realized then
2723 begin
2724 GetContainerWidget^.get_allocation(@AAlloc);
2725 Result := Rect(AAlloc.x, AAlloc.y, AAlloc.width + AAlloc.x,AAlloc.height + AAlloc.y);
2726 end else
2727 if FWidget^.get_realized then
2728 begin
2729 FWidget^.get_allocation(@AAlloc);
2730 Result := Rect(AAlloc.x, AAlloc.y, AAlloc.width + AAlloc.x,AAlloc.height + AAlloc.y);
2731 end;
2732
2733 OffsetRect(Result, -Result.Left, -Result.Top);
2734 end;
2735
getClientBoundsnull2736 function TGtk3Widget.getClientBounds: TRect;
2737 var
2738 AAlloc: TGtkAllocation;
2739 begin
2740 Result := Rect(0, 0, 0, 0);
2741 if IsWidgetOk then
2742 begin
2743 if FWidget^.get_realized then
2744 begin
2745 FWidget^.get_allocation(@AAlloc);
2746 Result := Rect(AAlloc.x, AAlloc.y, AAlloc.width + AAlloc.x,AAlloc.height + AAlloc.y);
2747 end else
2748 if GetContainerWidget^.get_realized then
2749 begin
2750 GetContainerWidget^.get_allocation(@AAlloc);
2751 Result := Rect(AAlloc.x, AAlloc.y, AAlloc.width + AAlloc.x,AAlloc.height + AAlloc.y);
2752 end;
2753 end;
2754 end;
2755
GetContainerWidgetnull2756 function TGtk3Widget.GetContainerWidget: PGtkWidget;
2757 begin
2758 if Assigned(FCentralWidget) then
2759 Result := FCentralWidget
2760 else
2761 Result := FWidget;
2762 end;
2763
TGtk3Widget.GetPositionnull2764 function TGtk3Widget.GetPosition(out APoint: TPoint): Boolean;
2765 var
2766 ALeft, ATop: gint;
2767 begin
2768 APoint := Point(0, 0);
2769 Result := False;
2770 if IsWidgetOk then
2771 begin
2772 if FWidget^.get_realized then
2773 begin
2774 if FWidget^.get_has_window then
2775 begin
2776 gdk_window_get_position(FWidget^.window, @ALeft, @ATop);
2777 APoint.X := ALeft;
2778 APoint.Y := ATop;
2779 Result := True;
2780 end;
2781 end;
2782 if not Result then
2783 begin
2784 APoint := Point(LCLObject.Left, LCLObject.Top);
2785 Result := True;
2786 end;
2787 end;
2788 end;
2789
2790 procedure TGtk3Widget.Release;
2791 begin
2792 LCLObject := nil;
2793 Free;
2794 end;
2795
2796 procedure TGtk3Widget.Hide;
2797 begin
2798 if Assigned(FWidget) then
2799 FWidget^.hide;
2800 end;
2801
TGtk3Widget.getParentnull2802 function TGtk3Widget.getParent: TGtk3Widget;
2803 begin
2804 Result := Gtk3WidgetFromGtkWidget(Widget^.get_parent);
2805 end;
2806
GetWindownull2807 function TGtk3Widget.GetWindow: PGdkWindow;
2808 begin
2809 Result := FWidget^.window;
2810 end;
2811
2812 procedure TGtk3Widget.Move(ALeft, ATop: Integer);
2813 var
2814 AParent: TGtk3Widget;
2815 begin
2816 AParent := getParent;
2817 if (AParent <> nil) then
2818 begin
2819 if (wtContainer in AParent.WidgetType) then
2820 PGtkFixed(AParent.GetContainerWidget)^.move(FWidget, ALeft, ATop)
2821 else
2822 if (wtLayout in AParent.WidgetType) then
2823 PGtkLayout(AParent.GetContainerWidget)^.move(FWidget, ALeft, ATop);
2824 end;
2825 end;
2826
2827 procedure TGtk3Widget.Activate;
2828 begin
2829 if IsWidgetOK then
2830 begin
2831 if not FWidget^.visible then
2832 exit;
2833 if Gtk3IsGdkWindow(FWidget^.window) then
2834 FWidget^.window^.raise_
2835 else
2836 begin
2837 FWidget^.get_parent_window^.raise_;
2838 end;
2839 if FWidget^.can_focus then
2840 FWidget^.grab_focus;
2841 end;
2842 end;
2843
2844 procedure TGtk3Widget.preferredSize(var PreferredWidth,
2845 PreferredHeight: integer; WithThemeSpace: Boolean);
2846 var
2847 AMinH: gint;
2848 AMinW: gint;
2849 begin
2850 if IsWidgetOK then
2851 begin
2852 {$IFDEF GTK3DEBUGPREFERREDSIZE}
2853 Widget^.get_size_request(@AMinW, @AMinH);
2854 DebugLn('>',dbgsName(LCLObject),'.preferredSize W=',dbgs(PreferredWidth),' H=',dbgs(PreferredHeight),' WithThemeSpace ',dbgs(WithThemeSpace),' AMinW=',dbgs(AMinW),' AMinH=',dbgs(AMinH));
2855 {$ENDIF}
2856 GetContainerWidget^.get_preferred_height(@AMinH, @PreferredHeight);
2857 GetContainerWidget^.get_preferred_width(@AMinW, @PreferredWidth);
2858 {$IFDEF GTK3DEBUGPREFERREDSIZE}
2859 if WithThemeSpace then
2860 begin
2861 GetContainerWidget^.get_style_context^.get_margin(GTK_STATE_NORMAL, @ABorder);
2862 with ABorder do
2863 DebugLn('BorderSpaces ',Format('L %d T %d R %d B %d',[Left, Top, Right, Bottom]));
2864 GetContainerWidget^.get_style_context^.get_padding(GTK_STATE_NORMAL, @ABorder);
2865 with ABorder do
2866 DebugLn('Padding ',Format('L %d T %d R %d B %d',[Left, Top, Right, Bottom]));
2867 end;
2868 DebugLn('<',dbgsName(LCLObject),'.preferredSize W=',dbgs(PreferredWidth),' H=',dbgs(PreferredHeight),' WithThemeSpace ',dbgs(WithThemeSpace),' AMinH=',dbgs(AMinH),' AMinW=',dbgs(AMinW));
2869 {$ENDIF}
2870 end;
2871 end;
2872
2873 procedure TGtk3Widget.SetCursor(ACursor: HCURSOR);
2874 begin
2875 if IsWidgetOk then
2876 begin
2877 if GetContainerWidget^.get_has_window and Gtk3IsGdkWindow(GetContainerWidget^.window) then
2878 SetWindowCursor(GetContainerWidget^.window, ACursor, False, True)
2879 else
2880 if Widget^.get_has_window and Gtk3IsGdkWindow(Widget^.window) then
2881 SetWindowCursor(Widget^.window, ACursor, False, True);
2882 end;
2883 end;
2884
2885 procedure TGtk3Widget.SetFocus;
2886 begin
2887 if GetContainerWidget^.can_focus then
2888 GetContainerWidget^.grab_focus
2889 else
2890 if FWidget^.can_focus then
2891 FWidget^.grab_focus;
2892 end;
2893
2894 procedure TGtk3Widget.SetParent(AParent: TGtk3Widget; const ALeft, ATop: Integer
2895 );
2896 begin
2897 if wtLayout in AParent.WidgetType then
2898 PGtkLayout(AParent.GetContainerWidget)^.put(FWidget, ALeft, ATop)
2899 else
2900 if wtContainer in AParent.WidgetType then
2901 PGtkFixed(AParent.GetContainerWidget)^.put(FWidget, ALeft, ATop)
2902 else
2903 if wtNotebook in AParent.WidgetType then
2904 // do nothing !
2905 else
2906 FWidget^.set_parent(AParent.GetContainerWidget);
2907 end;
2908
2909 procedure TGtk3Widget.Show;
2910 begin
2911 if IsValidHandle then
2912 FWidget^.show;
2913 end;
2914
2915 procedure TGtk3Widget.ShowAll;
2916 begin
2917 if IsValidHandle then
2918 FWidget^.show_all;
2919 end;
2920
2921 procedure TGtk3Widget.Update(ARect: PRect);
2922 begin
2923 if IsWidgetOK then
2924 begin
2925 if ARect <> nil then
2926 begin
2927 with ARect^ do
2928 FWidget^.queue_draw_area(Left, Top, Right - Left, Bottom - Top);
2929 if FWidget <> GetContainerWidget then
2930 with ARect^ do
2931 GetContainerWidget^.queue_draw_area(Left, Top, Right - Left, Bottom - Top);
2932 end else
2933 begin
2934 FWidget^.queue_draw;
2935 if FWidget <> GetContainerWidget then
2936 GetContainerWidget^.queue_draw;
2937 end;
2938 end;
2939 end;
2940
2941 { TGtk3StatusBar }
2942
CreateWidgetnull2943 function TGtk3StatusBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
2944 begin
2945 Result := TGtkEventBox.new;
2946 FCentralWidget := TGtkHBox.new(GTK_ORIENTATION_HORIZONTAL, 1);
2947 PGtkBox(FCentralWidget)^.set_homogeneous(True);
2948 PGtkEventBox(Result)^.add(FCentralWidget);
2949 //TODO: add routines to set panels
2950 end;
2951
2952 { TGtk3Panel }
2953
2954 procedure TGtk3Panel.SetColor(AValue: TColor);
2955 var
2956 AGdkRGBA: TGdkRGBA;
2957 AColor: TGdkColor;
2958 begin
2959 inherited SetColor(AValue);
2960 exit;
2961 if (AValue = clDefault) or (AValue = clBackground) then
2962 begin
2963 // this is just to test if we can get transparent panel again
2964 // clDefault must be extracted from style
2965
2966 // nil resets color to gtk default
2967 FWidget^.override_background_color(GTK_STATE_FLAG_NORMAL, nil);
2968 StyleContext^.get_background_color(GTK_STATE_FLAG_NORMAL, @AGdkRGBA);
2969
2970 // writeln('ACOLOR R=',AColor.Red,' G=',AColor.green,' B=',AColor.blue);
2971 // AColor := TColortoTGDKColor(AValue);
2972 {AGdkRGBA.alpha := 0;
2973 AGdkRGBA.red := AColor.red / 65535.00;
2974 AGdkRGBA.blue := AColor.blue / 65535.00;
2975 AGdkRGBA.green := AColor.red / 65535.00;}
2976 FWidget^.override_background_color(GTK_STATE_FLAG_NORMAL, @AGdkRGBA);
2977 FWidget^.override_background_color(GTK_STATE_FLAG_ACTIVE, @AGdkRGBA);
2978 FWidget^.override_background_color(GTK_STATE_FLAG_FOCUSED, @AGdkRGBA);
2979 FWidget^.override_background_color(GTK_STATE_FLAG_PRELIGHT, @AGdkRGBA);
2980 FWidget^.override_background_color(GTK_STATE_FLAG_SELECTED, @AGdkRGBA);
2981 end else
2982 begin
2983 AColor := TColortoTGDKColor(AValue);
2984 // writeln('ACOLOR R=',AColor.Red,' G=',AColor.green,' B=',AColor.blue);
2985 //inherited SetColor(AValue);
2986 end;
2987 end;
2988
CreateWidgetnull2989 function TGtk3Panel.CreateWidget(const Params: TCreateParams): PGtkWidget;
2990 var
2991 AGdkRGBA: TGdkRGBA;
2992 begin
2993 FHasPaint := True;
2994 FBorderStyle := bsNone;
2995 FBevelInner := bvNone;
2996 FBevelOuter := bvNone;
2997 // wtLayout = using GtkLayout
2998 // FWidgetType := [wtWidget, wtLayout];
2999 // Result := TGtkLayout.new(nil, nil);
3000 FWidgetType := [wtWidget, wtContainer];
3001 Result := TGtkFixed.new;
3002 Result^.set_has_window(True);
3003 // AColor := Result^.style^.bg[0];
3004 // writeln('BG COLOR R=',AColor.red,' G=',AColor.green,' B=',AColor.blue);
3005 // now we make panel completely transparent.
3006 // SetColor must usr override_background_color for panel
3007 // we must implement cairo_pattern_t since background can be brush
3008 AGdkRGBA.alpha := 0;
3009 AGdkRGBA.red := 0; // AColor.Red / 65535.00;
3010 AGdkRGBA.blue := 0; // AColor.Blue / 65535.00;
3011 AGdkRGBA.green := 0; // AColor.green / 65535.00;
3012 Result^.override_background_color(GTK_STATE_FLAG_NORMAL, @AGdkRGBA);
3013 Result^.override_background_color(GTK_STATE_FLAG_ACTIVE, @AGdkRGBA);
3014 Result^.override_background_color(GTK_STATE_FLAG_FOCUSED, @AGdkRGBA);
3015 Result^.override_background_color(GTK_STATE_FLAG_PRELIGHT, @AGdkRGBA);
3016 Result^.override_background_color(GTK_STATE_FLAG_SELECTED, @AGdkRGBA);
3017 end;
3018
3019 procedure TGtk3Panel.DoBeforeLCLPaint;
3020 var
3021 DC: TGtk3DeviceContext;
3022 begin
3023 inherited DoBeforeLCLPaint;
3024 // example how to paint borderstyle/bevels of TPanel before we send event to lcl
3025 DC := TGtk3DeviceContext(FContext);
3026 if not Visible then
3027 exit;
3028 if BorderStyle <> bsNone then
3029 DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault);
3030 end;
3031
TGtk3Panel.getTextnull3032 function TGtk3Panel.getText: String;
3033 begin
3034 Result := FText;
3035 end;
3036
3037 procedure TGtk3Panel.setText(AValue: String);
3038 begin
3039 if FText = AValue then
3040 exit;
3041 FText := AValue;
3042 if Self.Visible then
3043 FWidget^.queue_draw;
3044 end;
3045
3046 { TGtk3GroupBox }
3047
TGtk3GroupBox.CreateWidgetnull3048 function TGtk3GroupBox.CreateWidget(const Params: TCreateParams): PGtkWidget;
3049 begin
3050 FHasPaint := True;
3051 //dont use layout for now
3052 FWidgetType := [wtWidget, wtContainer, wtGroupBox];
3053 Result := TGtkFrame.new('');
3054 // FCentralWidget := TGtkLayout.new(nil, nil);
3055 FCentralWidget := TGtkFixed.new;
3056 PGtkBin(Result)^.add(FCentralWidget);
3057 FCentralWidget^.set_has_window(True);
3058 end;
3059
getTextnull3060 function TGtk3GroupBox.getText: String;
3061 begin
3062 Result := '';
3063 if IsWidgetOK then
3064 begin
3065 if PGtkFrame(Widget)^.get_label_widget = nil then
3066 exit;
3067 Result := PGtkFrame(Widget)^.get_label;
3068 end;
3069 end;
3070
3071 procedure TGtk3GroupBox.setText(AValue: String);
3072 begin
3073 if IsWidgetOK then
3074 begin
3075 if AValue = '' then
3076 PGtkFrame(Widget)^.set_label_widget(nil)
3077 // maybe DoAdjustClientRect here
3078 else
3079 begin
3080 if PGtkFrame(Widget)^.get_label_widget = nil then
3081 PGtkFrame(Widget)^.set_label_widget(TGtkLabel.new(''));
3082 PGtkFrame(Widget)^.set_label(PgChar(AValue));
3083 end;
3084 end;
3085 end;
3086
3087
3088 { TGtk3Editable }
3089
gtk3EditableDelayedSelStartnull3090 function gtk3EditableDelayedSelStart(AData: Pointer): gboolean; cdecl;
3091 var
3092 AWidget: PGtkEditable;
3093 AEditable: TGtk3Editable;
3094 begin
3095 Result := False;
3096 AEditable := TGtk3Editable(AData);
3097 AWidget := PGtkEditable(TGtk3Widget(AData).Widget);
3098 if (AEditable.PrivateCursorPos <> -1) and (AEditable.PrivateSelection <> -1) then
3099 begin
3100 gtk_editable_select_region(AWidget,AEditable.PrivateCursorPos, AEditable.PrivateSelection);
3101 // gtk_editable_set_position(AWidget, TGtk3Editable(AData).PrivateCursorPos);
3102 end;
3103 AEditable.PrivateCursorPos := -1;
3104 AEditable.PrivateSelection := -1;
3105 g_idle_remove_by_data(AData);
3106 end;
3107
GetReadOnlynull3108 function TGtk3Editable.GetReadOnly: Boolean;
3109 begin
3110 Result := False;
3111 if IsWidgetOK then
3112 Result := not PGtkEditable(FWidget)^.get_editable;
3113 end;
3114
3115 procedure TGtk3Editable.SetReadOnly(AValue: Boolean);
3116 begin
3117 if IsWidgetOK then
3118 PGtkEditable(FWidget)^.set_editable(not AValue);
3119 end;
3120
TGtk3Editable.getCaretPosnull3121 function TGtk3Editable.getCaretPos: TPoint;
3122 begin
3123 Result := Point(0, 0);
3124 if not IsWidgetOk then
3125 exit;
3126 Result.X := PGtkEditable(FWidget)^.get_position;
3127 end;
3128
3129 procedure TGtk3Editable.SetCaretPos(AValue: TPoint);
3130 begin
3131 if not IsWidgetOk then
3132 exit;
3133 PGtkEditable(FWidget)^.set_position(AValue.X);
3134 end;
3135
getSelStartnull3136 function TGtk3Editable.getSelStart: Integer;
3137 var
3138 AStart: gint;
3139 AStop: gint;
3140 begin
3141 Result := 0;
3142 if not IsWidgetOk then
3143 exit;
3144 if PGtkEditable(FWidget)^.get_selection_bounds(@AStart, @AStop) then
3145 begin
3146 Result := AStart;
3147 end;
3148 end;
3149
TGtk3Editable.getSelLengthnull3150 function TGtk3Editable.getSelLength: Integer;
3151 var
3152 AStart: gint;
3153 AStop: gint;
3154 begin
3155 Result := 0;
3156 if not IsWidgetOk then
3157 exit;
3158 if PGtkEditable(FWidget)^.get_selection_bounds(@AStart, @AStop) then
3159 begin
3160 Result := AStop - AStart;
3161 end;
3162 end;
3163
3164 procedure TGtk3Editable.setSelStart(AValue: Integer);
3165 begin
3166 if not IsWidgetOk then
3167 exit;
3168 CaretPos := Point(AValue, 0);
3169 (*
3170 if InUpdate then
3171 begin
3172 PrivateCursorPos := AValue;
3173 CaretPos := Point(AValue, 0);
3174 // setDelayed when mouse events are finished.
3175 // This is needed to SetSelStart/SetSelLength inside changed event of text edit
3176 // g_idle_add(@gtk3EditableDelayedSelStart, Self);
3177 end else
3178 CaretPos := Point(AValue, 0);
3179 *)
3180 // DebugLn('TGtk3Editable.SetSelStart ',dbgsName(LCLObject),' value=',dbgs(AValue));
3181 (*
3182 PGtkEditable(FWidget)^.get_selection_bounds(@AStart, @AStop);
3183 if AStop < AValue then
3184 AStop := AValue;
3185 PGtkEditable(FWidget)^.select_region(AValue, AStop);
3186 *)
3187 end;
3188
3189 procedure TGtk3Editable.setSelLength(AValue: Integer);
3190 var
3191 AStart: gint;
3192 AStop: gint;
3193 begin
3194 if not IsWidgetOk then
3195 exit;
3196 PGtkEditable(FWidget)^.get_selection_bounds(@AStart, @AStop);
3197 AStart := CaretPos.X;
3198 // DebugLn('TGtk3Editable.SetSelLength ',dbgsName(LCLObject),' value=',dbgs(AValue),' AStart=',dbgs(AStart),' InUpdate ',dbgs(InUpdate));
3199 if InUpdate then
3200 begin
3201 PrivateCursorPos := AStart;
3202 PrivateSelection := AValue;
3203 // g_idle_add(@gtk3EditableDelayedSelStart, Self)
3204 // setDelayed later
3205 PGtkEditable(FWidget)^.select_region(AStart, AStart + AValue)
3206 end else
3207 PGtkEditable(FWidget)^.select_region(AStart, AStart + AValue);
3208 end;
3209
3210 { TGtk3Entry }
3211
3212 procedure Gtk3EntryDeletedText(AEntry: PGtkEntryBuffer; APosition: guint; ANumChars: guint; AData: GPointer); cdecl;
3213 var
3214 Msg: TLMessage;
3215 begin
3216 FillChar(Msg, SizeOf(Msg), 0);
3217 Msg.Msg := CM_TEXTCHANGED;
3218 TGtk3Widget(AData).DeliverMessage(Msg);
3219 end;
3220
3221 procedure Gtk3EntryInsertedText(AEntry: PGtkEntryBuffer; APosition: guint; AChars: PGChar; ANumChars: guint; AData: GPointer); cdecl;
3222 var
3223 Msg: TLMessage;
3224 begin
3225 FillChar(Msg, SizeOf(Msg), 0);
3226 Msg.Msg := CM_TEXTCHANGED;
3227 TGtk3Widget(AData).DeliverMessage(Msg);
3228 end;
3229
3230 procedure Gtk3EntryChanged(AEntry: PGtkEntryBuffer; AData: GPointer); cdecl;
3231 var
3232 Msg: TLMessage;
3233 begin
3234 FillChar(Msg, SizeOf(Msg), 0);
3235 Msg.Msg := CM_TEXTCHANGED;
3236 TGtk3Widget(AData).DeliverMessage(Msg);
3237 end;
3238
GetAlignmentnull3239 function TGtk3Entry.GetAlignment: TAlignment;
3240 var
3241 AFloat: GFloat;
3242 begin
3243 Result := taLeftJustify;
3244 if not IsWidgetOk then
3245 exit;
3246 AFloat := PGtkEntry(FWidget)^.get_alignment;
3247 if AFloat = 1 then
3248 Result := taRightJustify
3249 else
3250 if AFloat = 0.5 then
3251 Result := taCenter;
3252 end;
3253
3254 procedure TGtk3Entry.SetAlignment(AValue: TAlignment);
3255 var
3256 AFloat: GFloat;
3257 begin
3258 AFloat := 0;
3259 if not IsWidgetOk then
3260 exit;
3261 case AValue of
3262 taCenter: AFloat := 0.5;
3263 taRightJustify: AFloat := 1.0;
3264 end;
3265 PGtkEntry(FWidget)^.set_alignment(AFloat);
3266 end;
3267
EatArrowKeysnull3268 function TGtk3Entry.EatArrowKeys(const AKey: Word): Boolean;
3269 begin
3270 Result := AKey in [VK_UP, VK_DOWN];
3271 end;
3272
getTextnull3273 function TGtk3Entry.getText: String;
3274 begin
3275 if IsValidHandle and IsWidgetOk then
3276 Result := StrPas(PGtkEntry(Widget)^.get_text)
3277 else
3278 Result := '';
3279 end;
3280
3281 procedure TGtk3Entry.setText(AValue: String);
3282 begin
3283 if IsValidHandle and IsWidgetOK then
3284 PGtkEntry(Widget)^.set_text(PgChar(AValue));
3285 end;
3286
TGtk3Entry.CreateWidgetnull3287 function TGtk3Entry.CreateWidget(const Params: TCreateParams): PGtkWidget;
3288 begin
3289 Result := PGtkWidget(TGtkEntry.new);
3290 FWidgetType := FWidgetType + [wtEntry];
3291 PrivateCursorPos := -1;
3292 PrivateSelection := -1;
3293 end;
3294
3295 procedure TGtk3Entry.InitializeWidget;
3296 begin
3297 inherited InitializeWidget;
3298 g_signal_connect_data(PGtkEntry(FWidget), 'changed', TGCallback(@Gtk3EntryChanged), Self, nil, 0);
3299 //g_signal_connect_data(PGtkEntry(FWidget)^.get_buffer, 'deleted-text', TGCallback(@Gtk3EntryDeletedText), Self, nil, 0);
3300 //g_signal_connect_data(PGtkEntry(FWidget)^.get_buffer, 'inserted-text', TGCallback(@Gtk3EntryInsertedText), Self, nil, 0);
3301 end;
3302
3303 procedure TGtk3Entry.SetPasswordChar(APasswordChar: Char);
3304 var
3305 PWChar: Integer;
3306 begin
3307 if IsWidgetOK then
3308 begin
3309 PWChar := ord(APasswordChar);
3310 if (PWChar < 192) or (PWChar = ord('*')) then
3311 PWChar := 9679;
3312 PGtkEntry(FWidget)^.set_invisible_char(PWChar);
3313 end;
3314 end;
3315
3316 procedure TGtk3Entry.SetEchoMode(AVisible: Boolean);
3317 begin
3318 if IsWidgetOK then
3319 PGtkEntry(FWidget)^.set_visibility(AVisible);
3320 end;
3321
3322 procedure TGtk3Entry.SetMaxLength(AMaxLength: Integer);
3323 begin
3324 if IsWidgetOK then
3325 PGtkEntry(FWidget)^.set_max_length(AMaxLength);
3326 end;
3327
TGtk3Entry.IsWidgetOknull3328 function TGtk3Entry.IsWidgetOk: Boolean;
3329 begin
3330 Result := (FWidget <> nil) and Gtk3IsEntry(FWidget);
3331 end;
3332
3333 { TGtk3SpinEdit }
3334
GetMaximumnull3335 function TGtk3SpinEdit.GetMaximum: Double;
3336 var
3337 AFloat: gdouble;
3338 begin
3339 Result := 0;
3340 if IsWidgetOk then
3341 PGtkSpinButton(FWidget)^.get_range(@AFloat ,@Result);
3342 end;
3343
TGtk3SpinEdit.GetMinimumnull3344 function TGtk3SpinEdit.GetMinimum: Double;
3345 var
3346 AFloat: gdouble;
3347 begin
3348 Result := 0;
3349 if IsWidgetOk then
3350 PGtkSpinButton(FWidget)^.get_range(@Result ,@AFloat);
3351 end;
3352
TGtk3SpinEdit.GetNumDigitsnull3353 function TGtk3SpinEdit.GetNumDigits: Integer;
3354 begin
3355 Result := 0;
3356 if IsWidgetOk then
3357 Result := Integer(PGtkSpinButton(FWidget)^.get_digits);
3358 end;
3359
TGtk3SpinEdit.GetNumericnull3360 function TGtk3SpinEdit.GetNumeric: Boolean;
3361 begin
3362 Result := False;
3363 if IsWidgetOk then
3364 Result := PGtkSpinButton(FWidget)^.get_numeric;
3365 end;
3366
TGtk3SpinEdit.GetStepnull3367 function TGtk3SpinEdit.GetStep: Double;
3368 var
3369 AFloat: Double;
3370 begin
3371 Result := 0;
3372 if IsWidgetOk then
3373 PGtkSpinButton(FWidget)^.get_increments(@Result, @AFloat);
3374 end;
3375
TGtk3SpinEdit.GetValuenull3376 function TGtk3SpinEdit.GetValue: Double;
3377 begin
3378 Result := 0;
3379 if IsWidgetOk then
3380 Result := PGtkSpinButton(FWidget)^.get_value;
3381 end;
3382
3383 procedure TGtk3SpinEdit.SetNumDigits(AValue: Integer);
3384 begin
3385 if IsWidgetOk then
3386 PGtkSpinButton(FWidget)^.set_digits(GUint(AValue));
3387 end;
3388
3389 procedure TGtk3SpinEdit.SetNumeric(AValue: Boolean);
3390 begin
3391 if IsWidgetOk then
3392 PGtkSpinButton(FWidget)^.set_numeric(AValue);
3393 end;
3394
3395 procedure TGtk3SpinEdit.SetStep(AValue: Double);
3396 var
3397 AStep: gdouble;
3398 APage: gdouble;
3399 begin
3400 if IsWidgetOk then
3401 begin
3402 PGtkSpinButton(FWidget)^.get_increments(@AStep, @APage);
3403 PGtkSpinButton(FWidget)^.set_increments(AValue, APage);
3404 end;
3405 end;
3406
3407 procedure TGtk3SpinEdit.SetValue(AValue: Double);
3408 begin
3409 if IsWidgetOk then
3410 begin
3411 PGtkSpinButton(FWidget)^.set_value(AValue);
3412 end;
3413 end;
3414
CreateWidgetnull3415 function TGtk3SpinEdit.CreateWidget(const Params: TCreateParams): PGtkWidget;
3416 var
3417 ASpin: TCustomSpinEdit;
3418 begin
3419 PrivateCursorPos := -1;
3420 PrivateSelection := -1;
3421 ASpin := TCustomSpinEdit(LCLObject);
3422 FWidgetType := FWidgetType + [wtSpinEdit];
3423 // Adjustment := TGtkAdjustment.new(ASpin.Value, ASpin.MinValue, ASpin.MaxValue, ASpin.Increment,
3424 // ASpin.Increment, ASpin.Increment);
3425 Result := TGtkSpinButton.new_with_range(ASpin.MinValue, ASpin.MaxValue, ASpin.Increment);
3426 end;
3427
EatArrowKeysnull3428 function TGtk3SpinEdit.EatArrowKeys(const AKey: Word): Boolean;
3429 begin
3430 Result := False;
3431 end;
3432
TGtk3SpinEdit.IsWidgetOknull3433 function TGtk3SpinEdit.IsWidgetOk: Boolean;
3434 begin
3435 Result := (FWidget <> nil) and Gtk3IsSpinButton(FWidget);
3436 end;
3437
3438 procedure TGtk3SpinEdit.SetRange(AMin, AMax: Double);
3439 begin
3440 if IsWidgetOk then
3441 PGtkSpinButton(FWidget)^.set_range(AMin, AMax);
3442 end;
3443
3444 { TGtk3Range }
3445
3446 procedure Gtk3RangeChanged(ARange: PGtkRange; AData: gPointer); cdecl;
3447 var
3448 Msg: TLMessage;
3449 begin
3450 if AData <> nil then
3451 begin
3452 if TGtk3Widget(AData).InUpdate then
3453 Exit;
3454 FillChar(Msg, SizeOf(Msg), #0);
3455 Msg.Msg := LM_CHANGED;
3456 TGtk3Widget(AData).DeliverMessage(Msg);
3457 end;
3458 end;
3459
GetPositionnull3460 function TGtk3Range.GetPosition: Integer;
3461 begin
3462 Result := 0;
3463 if IsWidgetOK then
3464 Result := Round(PGtkRange(FWidget)^.get_value);
3465 end;
3466
GetRangenull3467 function TGtk3Range.GetRange: TPoint;
3468 begin
3469 Result := Point(0, 0);
3470 if IsWidgetOK then
3471 PGtkRange(FWidget)^.get_slider_range(@Result.X, @Result.Y);
3472 end;
3473
3474 procedure TGtk3Range.SetPosition(AValue: Integer);
3475 begin
3476 if IsWidgetOK then
3477 PGtkRange(FWidget)^.set_value(gDouble(AValue));
3478 end;
3479
3480 procedure TGtk3Range.SetRange(AValue: TPoint);
3481 var
3482 dx,dy: gdouble;
3483 begin
3484 if IsWidgetOK then
3485 begin
3486 dx := AValue.X;
3487 dy := AValue.Y;
3488 PGtkRange(FWidget)^.set_range(dx, dy);
3489 end;
3490 end;
3491
3492 procedure TGtk3Range.InitializeWidget;
3493 begin
3494 inherited InitializeWidget;
3495 g_signal_connect_data(GetContainerWidget, 'value-changed', TGCallback(@Gtk3RangeChanged), Self, nil, 0);
3496 end;
3497
3498 procedure TGtk3Range.SetStep(AStep: Integer; APageSize: Integer);
3499 begin
3500 if IsWidgetOk then
3501 PGtkRange(FWidget)^.set_increments(gDouble(AStep), gDouble(APageSize));
3502 end;
3503
3504 { TGtk3TrackBar }
3505
GetReversednull3506 function TGtk3TrackBar.GetReversed: Boolean;
3507 begin
3508 Result := False;
3509 if IsWidgetOK then
3510 Result := PGtkScale(FWidget)^.get_inverted;
3511 end;
3512
3513 procedure TGtk3TrackBar.SetReversed(AValue: Boolean);
3514 begin
3515 if IsWidgetOK then
3516 PGtkScale(FWidget)^.set_inverted(AValue);
3517 end;
3518
TGtk3TrackBar.CreateWidgetnull3519 function TGtk3TrackBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
3520 var
3521 ATrack: TCustomTrackBar;
3522 begin
3523 ATrack := TCustomTrackBar(LCLObject);
3524 FWidgetType := FWidgetType + [wtTrackBar];
3525 Result := PGtkWidget(TGtkScale.new(Ord(ATrack.Orientation), nil));
3526 FOrientation := ATrack.Orientation;
3527 if ATrack.Reversed then
3528 PGtkScale(Result)^.set_inverted(True);
3529
3530 PGtkScale(Result)^.set_digits(0);
3531 end;
3532
GetTrackBarOrientationnull3533 function TGtk3TrackBar.GetTrackBarOrientation: TTrackBarOrientation;
3534 begin
3535 Result := FOrientation;
3536 end;
3537
3538 procedure TGtk3TrackBar.SetScalePos(AValue: TTrackBarScalePos);
3539 begin
3540 if IsWidgetOK then
3541 PGtkScale(FWidget)^.set_value_pos(Ord(AValue));
3542 end;
3543
3544 procedure TGtk3TrackBar.SetTickMarks(AValue: TTickMark; ATickStyle: TTickStyle);
3545 var
3546 i: Integer;
3547 begin
3548 if IsWidgetOK then
3549 begin
3550 if ATickStyle = tsNone then
3551 PGtkScale(FWidget)^.clear_marks
3552 else
3553 begin
3554 for i := TCustomTrackbar(LCLObject).Min to TCustomTrackbar(LCLObject).Max do
3555 begin
3556 if TCustomTrackbar(LCLObject).Orientation = trHorizontal then
3557 begin
3558 if AValue in [tmBoth, tmTopLeft] then
3559 PGtkScale(FWidget)^.add_mark(gDouble(i), GTK_POS_TOP, nil);
3560 if AValue in [tmBoth, tmBottomRight] then
3561 PGtkScale(FWidget)^.add_mark(gDouble(i), GTK_POS_BOTTOM, nil);
3562 end else
3563 begin
3564 if AValue in [tmBoth, tmTopLeft] then
3565 PGtkScale(FWidget)^.add_mark(gDouble(i), GTK_POS_LEFT, nil);
3566 if AValue in [tmBoth, tmBottomRight] then
3567 PGtkScale(FWidget)^.add_mark(gDouble(i), GTK_POS_RIGHT, nil);
3568 end;
3569 end;
3570 end;
3571 end;
3572 end;
3573
3574 { TGtk3ScrollBar }
3575
CreateWidgetnull3576 function TGtk3ScrollBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
3577 var
3578 AScrollbar: TCustomScrollBar;
3579 ARange: PGtkRange;
3580 begin
3581 AScrollBar := TCustomScrollBar(LCLObject);
3582 FWidgetType := FWidgetType + [wtScrollBar];
3583 Result := TGtkScrollbar.new(Ord(AScrollBar.Kind), nil);
3584 ARange := PGtkRange(Result);
3585 // ARange^.set_can_focus(True);
3586 with AScrollBar do
3587 begin
3588 ARange^.adjustment^.configure(Position, Min, Max + PageSize,
3589 SmallChange, LargeChange, PageSize);
3590 ARange^.adjustment^.set_value(Position);
3591 end;
3592 end;
3593
3594 procedure TGtk3ScrollBar.SetParams;
3595 var
3596 ARange: PGtkRange;
3597 begin
3598 if not IsWidgetOk then
3599 exit;
3600 ARange := PGtkRange(Widget);
3601 with TCustomScrollbar(LCLObject) do
3602 begin
3603 ARange^.adjustment^.configure(Position, Min, Max + PageSize,
3604 SmallChange, LargeChange, PageSize);
3605 ARange^.adjustment^.set_value(Position);
3606 ARange^.adjustment^.changed;
3607 // gtk_adjustment_changed(Range^.adjustment);
3608 end;
3609 end;
3610
3611 { TGtk3Calendar }
3612
TGtk3Calendar.CreateWidgetnull3613 function TGtk3Calendar.CreateWidget(const Params: TCreateParams): PGtkWidget;
3614 begin
3615 FWidgetType := [wtWidget, wtCalendar];
3616 Result := TGtkFrame.new(nil);
3617 FCentralWidget := TGtkCalendar.new;
3618 PGtkContainer(Result)^.add(FCentralWidget);
3619 FCentralWidget^.set_can_focus(True);
3620 end;
3621
3622 procedure TGtk3Calendar.GetDate(out AYear, AMonth, ADay: Word);
3623 begin
3624 AYear := 0;
3625 AMonth := 0;
3626 ADay := 0;
3627 if IsWidgetOk then
3628 PGtkCalendar(GetContainerWidget)^.get_date(@AYear, @AMonth, @ADay);
3629 end;
3630
3631 procedure TGtk3Calendar.SetDate(const AYear, AMonth, ADay: Word);
3632 begin
3633 if IsWidgetOK then
3634 begin
3635 PGtkCalendar(GetContainerWidget)^.select_month(AMonth, AYear);
3636 PGtkCalendar(GetContainerWidget)^.select_day(ADay);
3637 end;
3638 end;
3639
3640 procedure TGtk3Calendar.SetDisplayOptions(
3641 const ADisplayOptions: TGtkCalendarDisplayOptions);
3642 begin
3643 if IsWidgetOK then
3644 PGtkCalendar(GetContainerWidget)^.set_display_options(ADisplayOptions);
3645 end;
3646
3647 { TGtk3StaticText }
3648
TGtk3StaticText.GetAlignmentnull3649 function TGtk3StaticText.GetAlignment: TAlignment;
3650 var
3651 X: gfloat;
3652 Y: gfloat;
3653 begin
3654 Result := taLeftJustify;
3655 if IsWidgetOK then
3656 begin
3657 PGtkLabel(GetContainerWidget)^.get_alignment(@X, @Y);
3658 if X = 1 then
3659 Result := taRightJustify
3660 else
3661 if X = 0.5 then
3662 Result := taCenter;
3663 end;
3664 end;
3665
TGtk3StaticText.GetStaticBorderStylenull3666 function TGtk3StaticText.GetStaticBorderStyle: TStaticBorderStyle;
3667 var
3668 AShadowType: TGtkShadowType;
3669 begin
3670 Result := sbsNone;
3671 if IsWidgetOK then
3672 begin
3673 AShadowType := PGtkFrame(Widget)^.get_shadow_type;
3674 if AShadowType = GTK_SHADOW_ETCHED_IN then
3675 Result := sbsSingle
3676 else
3677 if AShadowType = GTK_SHADOW_IN then
3678 Result := sbsSunken;
3679 end;
3680 end;
3681
3682 procedure TGtk3StaticText.SetAlignment(AValue: TAlignment);
3683 begin
3684 if IsWidgetOk then
3685 PGtkLabel(GetContainerWidget)^.set_alignment(AGtkJustificationF[AValue], 0);
3686 end;
3687
3688 procedure TGtk3StaticText.SetStaticBorderStyle(AValue: TStaticBorderStyle);
3689 begin
3690 if IsWidgetOK then
3691 PGtkFrame(Widget)^.set_shadow_type(StaticBorderShadowMap[AValue]);
3692 end;
3693
TGtk3StaticText.getTextnull3694 function TGtk3StaticText.getText: String;
3695 begin
3696 Result := '';
3697 if IsWidgetOk then
3698 Result := PGtkLabel(getContainerWidget)^.get_text;
3699 end;
3700
3701 procedure TGtk3StaticText.setText(AValue: String);
3702 begin
3703 if IsWidgetOk then
3704 PGtkLabel(getContainerWidget)^.set_text(PgChar(AValue));
3705 end;
3706
CreateWidgetnull3707 function TGtk3StaticText.CreateWidget(const Params: TCreateParams): PGtkWidget;
3708 var
3709 AStaticText: TCustomStaticText;
3710 begin
3711 FWidgetType := FWidgetType + [wtStaticText];
3712 AStaticText := TCustomStaticText(LCLObject);
3713 Result := TGtkFrame.new('');
3714 PGtkFrame(Result)^.set_shadow_type(StaticBorderShadowMap[AStaticText.BorderStyle]);
3715 FCentralWidget := TGtkLabel.new('');
3716 FCentralWidget^.set_has_window(True);
3717 PGtkFrame(Result)^.set_label_widget(nil);
3718 PGtkFrame(Result)^.add(FCentralWidget);
3719 PGtkLabel(FCentralWidget)^.set_alignment(AGtkJustificationF[AStaticText.Alignment], 0.0);
3720 end;
3721
3722 { TGtk3ProgressBar }
3723
TGtk3ProgressBar.GetOrientationnull3724 function TGtk3ProgressBar.GetOrientation: TProgressBarOrientation;
3725 var
3726 AOrientation: TGtkOrientation;
3727 begin
3728 Result := pbHorizontal;
3729 if IsWidgetOk then
3730 begin
3731 AOrientation := PGtkOrientable(getContainerWidget)^.get_orientation;
3732 if AOrientation = GTK_ORIENTATION_HORIZONTAL then
3733 begin
3734 if PGtkProgressBar(getContainerWidget)^.get_inverted then
3735 Result := pbRightToLeft
3736 else
3737 Result := pbHorizontal;
3738 end else
3739 begin
3740 if PGtkProgressBar(getContainerWidget)^.get_inverted then
3741 Result := pbTopDown
3742 else
3743 Result := pbVertical;
3744 end;
3745 end;
3746 end;
3747
GetPositionnull3748 function TGtk3ProgressBar.GetPosition: Integer;
3749 begin
3750 Result := 0;
3751 if IsWidgetOk then
3752 Result := Round(PGtkProgressBar(GetContainerWidget)^.get_fraction);
3753 end;
3754
GetShowTextnull3755 function TGtk3ProgressBar.GetShowText: Boolean;
3756 begin
3757 Result := False;
3758 if IsWidgetOK then
3759 Result := PGtkProgressBar(GetContainerWidget)^.get_show_text;
3760 end;
3761
GetStylenull3762 function TGtk3ProgressBar.GetStyle: TProgressBarStyle;
3763 begin
3764 Result := pbstNormal;
3765 if Assigned(LCLObject) and IsWidgetOk then
3766 Result := TCustomProgressBar(LCLObject).Style;
3767 end;
3768
3769 procedure TGtk3ProgressBar.SetOrientation(AValue: TProgressBarOrientation);
3770 begin
3771 if IsWidgetOk then
3772 begin
3773 case AValue of
3774 pbHorizontal,pbRightToLeft:
3775 begin
3776 PGtkOrientable(GetContainerWidget)^.set_orientation(GTK_ORIENTATION_HORIZONTAL);
3777 PGtkProgressBar(GetContainerWidget)^.set_inverted(AValue = pbRightToLeft);
3778 end;
3779 pbVertical, pbTopDown:
3780 begin
3781 PGtkOrientable(GetContainerWidget)^.set_orientation(GTK_ORIENTATION_VERTICAL);
3782 PGtkProgressBar(GetContainerWidget)^.set_inverted(AValue = pbVertical);
3783 end;
3784 end;
3785 end;
3786 end;
3787
3788 procedure TGtk3ProgressBar.SetPosition(AValue: Integer);
3789 var
3790 ABar: TCustomProgressBar;
3791 fraction: gDouble;
3792 begin
3793 if not Assigned(LCLObject) or not IsWidgetOK then
3794 exit;
3795 ABar := TCustomProgressBar(LCLObject);
3796 if ((ABar.Max - ABar.Min) <> 0) then
3797 fraction := (AValue - ABar.Min) / (ABar.Max - ABar.Min)
3798 else
3799 fraction := 0;
3800 PGtkProgressBar(GetContainerWidget)^.set_fraction(fraction);
3801 end;
3802
3803 procedure TGtk3ProgressBar.SetShowText(AValue: Boolean);
3804 begin
3805 if IsWidgetOK then
3806 PGtkProgressBar(GetContainerWidget)^.set_show_text(AValue);
3807 end;
3808
ProgressPulseTimeoutnull3809 function ProgressPulseTimeout(data: gpointer): gboolean; cdecl;
3810 begin
3811 Result := {%H-}PtrUInt(g_object_get_data(data, 'lclprogressbarstyle')) = 1;
3812 if Result then
3813 PGtkProgressBar(Data)^.pulse;
3814 end;
3815
3816 procedure ProgressDestroy(data: gpointer); cdecl;
3817 begin
3818 g_source_remove({%H-}PtrUInt(data));
3819 end;
3820
3821 procedure TGtk3ProgressBar.SetStyle(AValue: TProgressBarStyle);
3822 begin
3823 if IsWidgetOk then
3824 begin
3825 g_object_set_data(GetContainerWidget,'lclprogressbarstyle', Pointer(PtrUInt(Ord(AValue))));
3826 if AValue = pbstNormal then
3827 begin
3828 Position := TCustomProgressBar(LCLObject).Position;
3829 end else
3830 begin
3831 g_object_set_data_full(GetContainerWidget, 'timeout',
3832 {%H-}Pointer(PtrUInt(g_timeout_add(100, @ProgressPulseTimeout, GetContainerWidget))), @ProgressDestroy);
3833 PGtkProgressBar(GetContainerWidget)^.pulse;
3834 end;
3835 end;
3836 end;
3837
3838 {we must override preferred width since gtk3 have strange opinion about minimum width of progress bar}
3839 procedure get_progress_preferred_width(widget: PGtkWidget; minimum_width: Pgint; natural_width: Pgint); cdecl;
3840 var
3841 Handle: HWND;
3842 begin
3843 Handle := HwndFromGtkWidget(Widget);
3844 if Handle <> 0 then
3845 begin
3846 minimum_width^ := TGtk3Widget(Handle).LCLObject.Width;
3847 natural_width^ := TGtk3Widget(Handle).LCLObject.Width;
3848 end else
3849 begin
3850 minimum_width^ := 0;
3851 natural_width^ := 0;
3852 DebugLn('ERROR: get_progress_preferred_width cannot find GtkWidget LCL Handle ....');
3853 end;
3854 end;
3855
3856 {we must override preferred height since gtk3 have strange opinion about height of progress bar}
3857 procedure get_progress_preferred_height(widget: PGtkWidget; minimum_height: Pgint; natural_height: Pgint); cdecl;
3858 var
3859 Handle: HWND;
3860 begin
3861 Handle := HwndFromGtkWidget(Widget);
3862 if Handle <> 0 then
3863 begin
3864 minimum_height^ := TGtk3Widget(Handle).LCLObject.Height;
3865 natural_height^ := TGtk3Widget(Handle).LCLObject.Height;
3866 // TODO: get spacing from style property
3867 // Widget^.get_style_context^.get_style_property();
3868 end else
3869 begin
3870 minimum_height^ := 0;
3871 natural_height^ := 0;
3872 DebugLn('ERROR: get_progress_preferred_height cannot find GtkWidget LCL Handle ....');
3873 end;
3874 end;
3875
TGtk3ProgressBar.CreateWidgetnull3876 function TGtk3ProgressBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
3877 var
3878 AProgres: TCustomProgressBar;
3879 begin
3880 AProgres := TCustomProgressBar(LCLObject);
3881 FWidgetType := FWidgetType + [wtProgressBar];
3882 Result := TGtkEventBox.new;
3883 FCentralWidget := TGtkProgressBar.new;
3884 PGtkEventBox(Result)^.add(FCentralWidget);
3885 FCentralWidget^.set_can_focus(True);
3886 end;
3887
3888 var
3889 AProgressClassHookInitialized: Boolean = False;
3890
3891 procedure TGtk3ProgressBar.InitializeWidget;
3892 var
3893 AClass: PGTypeClass;
3894 begin
3895 inherited InitializeWidget;
3896 //TODO: move hookers check variable code into Gtk3WidgetSet.
3897 if not AProgressClassHookInitialized then
3898 begin
3899 AProgressClassHookInitialized := True;
3900 AClass := g_type_class_ref(gtk_progress_bar_get_type);
3901 PGtkWidgetClass(AClass)^.get_preferred_width := @get_progress_preferred_width;
3902 PGtkWidgetClass(AClass)^.get_preferred_height := @get_progress_preferred_height;
3903 g_type_class_unref(AClass);
3904 end;
3905 end;
3906
3907 { TGtk3Container }
3908
3909 procedure TGtk3Container.AddChild(AWidget: PGtkWidget; const ALeft, ATop: Integer);
3910 begin
3911 if Assigned(FCentralWidget) then
3912 PGtkFixed(PGtkScrolledWindow(FCentralWidget)^.get_child)^.put(AWidget, ALeft, ATop)
3913 else
3914 PGtkContainer(FWidget)^.add(AWidget);
3915 end;
3916
3917 { TGtk3ToolBar }
3918
TGtk3ToolBar.CreateWidgetnull3919 function TGtk3ToolBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
3920 var
3921 AToolBar: TToolBar;
3922 begin
3923 AToolBar := TToolBar(LCLObject);
3924 FHasPaint := False;
3925 FWidgetType := [wtWidget, wtContainer];
3926 Result:=PGtkWidget(TGtkToolbar.new);
3927 end;
3928
3929 { TGtk3Page }
3930
3931 procedure TGtk3Page.setText(AValue: String);
3932 begin
3933 if Assigned(FPageLabel) then
3934 FPageLabel^.set_text(PChar(AValue));
3935 end;
3936
TGtk3Page.getTextnull3937 function TGtk3Page.getText: String;
3938 begin
3939 if Assigned(FPageLabel) then
3940 Result := FPageLabel^.get_text
3941 else
3942 Result := '';
3943 end;
3944
CreateWidgetnull3945 function TGtk3Page.CreateWidget(const Params: TCreateParams): PGtkWidget;
3946 begin
3947 FWidgetType := FWidgetType + [wtContainer];
3948 FPageLabel:= TGtkLabel.new(PChar(Params.Caption));
3949 // ref it to save it in case TabVisble is set to false
3950 FPageLabel^.ref;
3951 Result := TGtkHBox.new(GTK_ORIENTATION_HORIZONTAL, 0);
3952 FCentralWidget := TGtkFixed.new;
3953 PGtkHBox(Result)^.pack_start(FCentralWidget, True , True, 0);
3954 PGtkFixed(FCentralWidget)^.set_has_window(True);
3955 // PGtkFixed(FCentralWidget)^.set_can_focus(True);
3956 end;
3957
3958 procedure TGtk3Page.DestroyWidget;
3959 begin
3960 inherited DestroyWidget;
3961 // unref it to allow it to be destroyed
3962 FPageLabel^.unref;
3963 end;
3964
getClientRectnull3965 function TGtk3Page.getClientRect: TRect;
3966 var
3967 AParent: PGtkWidget;
3968 AParentObject: TGtk3Widget;
3969 begin
3970 if not getContainerWidget^.get_realized then
3971 begin
3972 AParent := FWidget^.get_parent;
3973 AParentObject := TGtk3Widget(HwndFromGtkWidget(AParent));
3974 if AParentObject <> nil then
3975 Result := AParentObject.getClientRect
3976 else
3977 Result := inherited getClientRect;
3978 end else
3979 Result := inherited getClientRect;
3980 // DebugLn('TGtk3Page.GetClientRect Result=',dbgs(Result),' Realized ',dbgs(getContainerWidget^.get_realized));
3981 end;
3982
3983 { TGtk3NoteBook }
3984
NotebookPageRealToLCLIndexnull3985 function NotebookPageRealToLCLIndex(const ATabControl: TCustomTabControl; AIndex: integer): integer;
3986 var
3987 I: Integer;
3988 begin
3989 Result := AIndex;
3990 if csDesigning in ATabControl.ComponentState then exit;
3991 I := 0;
3992 while (I < ATabControl.PageCount) and (I <= Result) do
3993 begin
3994 if not ATabControl.Page[I].TabVisible then Inc(Result);
3995 Inc(I);
3996 end;
3997 end;
3998
GtkNotebookAfterSwitchPagenull3999 // function GtkNotebookAfterSwitchPage(widget: PGtkWidget; pagenum: integer; data: gPointer): GBoolean; cdecl;
4000 procedure GtkNotebookAfterSwitchPage(widget: PGtkWidget; {%H-}page: PGtkWidget; pagenum: integer; data: gPointer); cdecl;
4001 var
4002 Mess: TLMNotify;
4003 NMHdr: tagNMHDR;
4004 LCLPageIndex: Integer;
4005 begin
4006 if TGtk3Widget(Data).InUpdate then
4007 exit;
4008 {page is deleted}
4009 DebugLn('GtkNotebookAfterSwitchPage ');
4010 if TGtk3NoteBook(Data).getPagesCount < TCustomTabControl(TGtk3NoteBook(Data).LCLObject).PageCount then
4011 begin
4012 DebugLn('GtkNotebookAfterSwitchPage PageIsDeleted');
4013 exit;
4014 end;
4015 FillChar(Mess{%H-}, SizeOf(Mess), 0);
4016 Mess.Msg := LM_NOTIFY;
4017 FillChar(NMHdr{%H-}, SizeOf(NMHdr), 0);
4018 NMHdr.code := TCN_SELCHANGE;
4019 NMHdr.hwndFrom := HWND(TGtk3Widget(Data));
4020 LCLPageIndex := NotebookPageRealToLCLIndex(TCustomTabControl(TGtk3Widget(Data).LCLObject), pagenum); //use this to set pageindex to the correct page.
4021 NMHdr.idFrom := LCLPageIndex;
4022 Mess.NMHdr := @NMHdr;
4023 TGtk3Widget(Data).DeliverMessage(Mess);
4024 end;
4025
BackNoteBookSignalnull4026 function BackNoteBookSignal(AData: Pointer): gboolean; cdecl;
4027 var
4028 AWidget: PGtkNotebook;
4029 APageNum: PtrInt;
4030 ACurrentPage: gint;
4031 begin
4032 Result := False;
4033 AWidget := AData;
4034 if not Gtk3IsWidget(AWidget) then
4035 exit;
4036 if g_object_get_data(AWidget,'switch-page-signal-stopped') <> nil then
4037 begin
4038 Result := True;
4039 APageNum := PtrInt(g_object_get_data(AWidget,'switch-page-signal-stopped'));
4040 ACurrentPage := AWidget^.get_current_page;
4041 g_object_set_data(AWidget,'switch-page-signal-stopped', nil);
4042 DebugLn('BackNoteBookSignal back notebook switch-page signal currpage=',dbgs(AWidget^.get_current_page),' blockedPage ',dbgs(APageNum));
4043 // must hook into notebook^.priv to unlock APageNum
4044 // AWidget^.set_current_page(AWidget^.get_current_page);
4045 // g_object_thaw_notify(AWidget^.get_nth_page(AWidget^.get_current_page));
4046 // PGtkFixed(AWidget^.get_nth_page(AWidget^.get_current_page))^.
4047 // g_signal_emit_by_name(AWidget,'switch-page',[AWidget^.get_nth_page(APageNum), APageNum, gPointer(HwndFromGtkWidget(AWidget)), nil{AWidget, True, gPointer(HwndFromGtkWidget(AWidget))}]);
4048 // AWidget^.notify('page');
4049 // g_signal_stop_emission_by_name(AWidget, 'switch-page');
4050 // g_signal_emit_by_name(AWidget,'switch-page',[G_TYPE_NONE, AWidget, AWidget^.get_nth_page(AWidget^.get_current_page), AWidget^.get_current_page, gPointer(HwndFromGtkWidget(AWidget))]);
4051 end;
4052 g_idle_remove_by_data(AData);
4053 end;
4054
4055 procedure GtkNotebookSwitchPage(widget: PGtkWidget; {%H-}page: PGtkWidget; pagenum: integer; data: gPointer); cdecl;
4056 var
4057 Mess: TLMNotify;
4058 NMHdr: tagNMHDR;
4059 begin
4060 if TGtk3Widget(Data).InUpdate then
4061 exit;
4062
4063 DebugLn('GtkNotebookSwitchPage Data ',dbgHex(PtrUInt(Data)),' Realized ',dbgs(Widget^.get_realized),' pageNum=',dbgs(pageNum));
4064
4065 {page is deleted}
4066 if TGtk3NoteBook(Data).getPagesCount < TCustomTabControl(TGtk3NoteBook(Data).LCLObject).PageCount then
4067 begin
4068 DebugLn('GtkNotebookSwitchPage PageIsDeleted ');
4069 exit;
4070 end;
4071
4072 FillChar(Mess{%H-}, SizeOf(Mess), 0);
4073 Mess.Msg := LM_NOTIFY;
4074 FillChar(NMHdr{%H-}, SizeOf(NMHdr), 0);
4075 NMHdr.code := TCN_SELCHANGING;
4076 NMHdr.hwndFrom := HWND(TGtk3Widget(Data));
4077 NMHdr.idFrom := NotebookPageRealToLCLIndex(TCustomTabControl(TGtk3Widget(Data).LCLObject), pagenum); //use this to set pageindex to the correct page.
4078 // DebugLn('LCLObject ',dbgsName(TGtk3Widget(Data).LCLObject),' IdFrom ',dbgs(NMHdr.idFrom));
4079 Mess.NMHdr := @NMHdr;
4080 Mess.Result := 0;
4081 // DebugLn('LCLObject ',dbgsName(TGtk3Widget(Data).LCLObject),' sending message ....');
4082 TGtk3Widget(Data).DeliverMessage(Mess);
4083 if Mess.Result <> 0 then
4084 begin
4085 g_object_set_data(Widget,'switch-page-signal-stopped', GPointer(pageNum));
4086 g_signal_stop_emission_by_name(PGObject(Widget), 'switch-page');
4087 // GtkNotebookAfterSwitchPage(Widget, page, pagenum, data);
4088 g_idle_add(@BackNoteBookSignal, Widget);
4089 Exit;
4090 end;
4091 end;
4092
GtkNotebookSelectPagenull4093 function GtkNotebookSelectPage(ANoteBook: PGtkNotebook; p1: gboolean; Data: gPointer): GBoolean; cdecl;
4094 begin
4095 // does not trigger for some reason
4096 DebugLn('GtkNotebookSelectPage ');
4097 end;
4098
CreateWidgetnull4099 function TGtk3NoteBook.CreateWidget(const Params: TCreateParams): PGtkWidget;
4100 begin
4101 FWidgetType := FWidgetType + [wtNotebook];
4102 Result := TGtkEventBox.new;
4103 PGtkEventBox(Result)^.set_has_window(True);
4104 FCentralWidget := TGtkNotebook.new;
4105 PGtkEventBox(Result)^.add(FCentralWidget);
4106 PGtkNoteBook(FCentralWidget)^.set_scrollable(True);
4107 if (nboHidePageListPopup in TCustomTabControl(LCLObject).Options) then
4108 PGtkNoteBook(FCentralWidget)^.popup_disable;
4109 PGtkNoteBook(FCentralWidget)^.show;
4110
4111 g_signal_connect_data(FCentralWidget,'switch-page', TGCallback(@GtkNotebookSwitchPage), Self, nil, 0);
4112 // this one triggers after above switch-page
4113 g_signal_connect_data(FCentralWidget,'switch-page', TGCallback(@GtkNotebookAfterSwitchPage), Self, nil, 0);
4114
4115 // those signals doesn't trigger with gtk3-3.6
4116 // g_signal_connect_data(FCentralWidget,'change-current-page', TGCallback(@GtkNotebookAfterSwitchPage), Self, nil, 0);
4117 // g_signal_connect_data(FCentralWidget,'select-page', TGCallback(@GtkNotebookSelectPage), Self, nil, 0);
4118 end;
4119
getClientRectnull4120 function TGtk3NoteBook.getClientRect: TRect;
4121 var
4122 AAlloc: TGtkAllocation;
4123 ACurrentPage: gint;
4124 APage: PGtkWidget;
4125 begin
4126 Result := Rect(0, 0, 0, 0);
4127 if PGtkNoteBook(GetContainerWidget)^.get_n_pages = 0 then
4128 begin
4129 GetContainerWidget^.get_allocation(@AAlloc);
4130 Result := RectFromGtkAllocation(AAlloc);
4131 OffsetRect(Result, -Result.Left, -Result.Top);
4132 end else
4133 begin
4134 ACurrentPage := PGtkNoteBook(GetContainerWidget)^.get_current_page;
4135 if (ACurrentPage >= 0) then
4136 begin
4137 APage := PGtkNoteBook(GetContainerWidget)^.get_nth_page(ACurrentPage);
4138 if APage^.get_realized then
4139 APage^.get_allocation(@AAlloc)
4140 else
4141 GetContainerWidget^.get_allocation(@AAlloc);
4142 Result := RectFromGtkAllocation(AAlloc);
4143 OffsetRect(Result, -Result.Left, -Result.Top);
4144 end;
4145 end;
4146 // DebugLn('TGtk3NoteBook.getClientRect Result ',dbgs(Result));
4147 end;
4148
getPagesCountnull4149 function TGtk3NoteBook.getPagesCount: integer;
4150 begin
4151 Result := 0;
4152 if IsWidgetOk then
4153 Result := PGtkNoteBook(GetContainerWidget)^.get_n_pages;
4154 end;
4155
4156 procedure EnumerateChildren(ANotebook: PGtkNoteBook);
4157 var
4158 AList: PGList;
4159 i: Integer;
4160 AWidget: PGtkWidget;
4161 AMinimumH, ANaturalH, ANaturalW, AMinimumW: gint;
4162 AChild: PGtkWidget;
4163 begin
4164 AList := ANoteBook^.get_children;
4165 for i := 0 to g_list_length(AList) - 1 do
4166 begin
4167 AWidget := PGtkWidget(g_list_nth_data(AList, I));
4168 AWidget^.get_preferred_height(@AMinimumH, @ANaturalH);
4169 AWidget^.get_preferred_width(@AMinimumW, @ANaturalW);
4170 AChild := nil;
4171 DebugLn(Format('Child[%d] MinH %d NatH %d MinW %d NatW %d ALLOCW %d ALLOCH %d child_type %s',
4172 [I, AMinimumH, ANaturalH, AMinimumW, ANaturalW,
4173 AWidget^.get_allocated_width, AWidget^.get_allocated_height, g_type_name(ANotebook^.child_type)]));
4174 end;
4175 g_list_free(AList);
4176 end;
4177
4178 procedure TGtk3NoteBook.InsertPage(ACustomPage: TCustomPage; AIndex: Integer);
4179 var
4180 Gtk3Page: TGtk3Page;
4181 AMinSize, ANaturalSize: gint;
4182 begin
4183 if IsWidgetOK then
4184 begin
4185 Gtk3Page := TGtk3Page(ACustomPage.Handle);
4186 PGtkNoteBook(GetContainerWidget)^.insert_page(Gtk3Page.Widget, Gtk3Page.FPageLabel, AIndex);
4187 PGtkNoteBook(GetContainerWidget)^.get_preferred_width(@AMinSize, @ANaturalSize);
4188 PGtkNoteBook(GetContainerWidget)^.get_preferred_height(@AMinSize, @ANaturalSize);
4189 if gtk_notebook_get_n_pages(PGtkNoteBook(GetContainerWidget)) > 1 then
4190 PGtkNoteBook(GetContainerWidget)^.resize_children;
4191 end;
4192 end;
4193
4194 procedure TGtk3NoteBook.MovePage(ACustomPage: TCustomPage; ANewIndex: Integer);
4195 begin
4196 if IsWidgetOK then
4197 PGtkNoteBook(GetContainerWidget)^.reorder_child(TGtk3Widget(ACustomPage.Handle).Widget, ANewIndex);
4198 end;
4199
4200 procedure TGtk3NoteBook.RemovePage(AIndex: Integer);
4201 var
4202 AMinSizeW, AMinSizeH, ANaturalSizeW, ANaturalSizeH: gint;
4203 begin
4204 if IsWidgetOK then
4205 begin
4206 PGtkNotebook(GetContainerWidget)^.remove_page(AIndex);
4207 PGtkNoteBook(GetContainerWidget)^.get_preferred_width(@AMinSizeW, @ANaturalSizeW);
4208 PGtkNoteBook(GetContainerWidget)^.get_preferred_height(@AMinSizeH, @ANaturalSizeH);
4209 PGtkNoteBook(GetContainerWidget)^.resize_children;
4210 end;
4211 end;
4212
4213 procedure TGtk3NoteBook.SetPageIndex(AIndex: Integer);
4214 begin
4215 if IsWidgetOK then
4216 begin
4217 PGtkNotebook(GetContainerWidget)^.set_current_page(AIndex);
4218 end;
4219 end;
4220
4221 procedure TGtk3NoteBook.SetShowTabs(const AShowTabs: Boolean);
4222 begin
4223 if IsWidgetOK then
4224 PGtkNoteBook(GetContainerWidget)^.set_show_tabs(AShowTabs);
4225 end;
4226
4227 procedure TGtk3NoteBook.SetTabPosition(const ATabPosition: TTabPosition);
4228 const
4229 GtkPositionTypeMap: array[TTabPosition] of TGtkPositionType =
4230 (
4231 2, // { tpTop } GTK_POS_TOP,
4232 3, // { tpBottom } GTK_POS_BOTTOM,
4233 0, // { tpLeft } GTK_POS_LEFT,
4234 1 // { tpRight } GTK_POS_RIGHT
4235 );
4236 begin
4237 if IsWidgetOK then
4238 PGtkNoteBook(GetContainerWidget)^.set_tab_pos(GtkPositionTypeMap[ATabPosition]);
4239 end;
4240
4241 procedure TGtk3NoteBook.SetTabLabelText(AChild: TCustomPage; AText: String);
4242 begin
4243 if IsWidgetOK then
4244 TGtk3Widget(AChild.Handle).setText(AText);
4245 end;
4246
GetTabLabelTextnull4247 function TGtk3NoteBook.GetTabLabelText(AChild: TCustomPage): String;
4248 begin
4249 if IsWidgetOK then
4250 Result := TGtk3Widget(AChild.Handle).getText
4251 else
4252 Result := '';
4253 end;
4254
4255 { TGtk3MenuShell }
4256
4257 procedure TGtk3MenuShell.Insert(AMenuShell: PGtkMenuShell; APosition: Integer);
4258 begin
4259 if IsWidgetOK then
4260 PGtkMenuShell(Widget)^.insert(AMenuShell, APosition);
4261 end;
4262
4263 constructor TGtk3MenuShell.Create(const AMenu: TMenu; AMenuBar: PGtkMenuBar);
4264 begin
4265 inherited Create;
4266 MenuObject := AMenu;
4267 FContext := 0;
4268 FHasPaint := False;
4269 FWidget := nil;
4270 FOwner := nil;
4271 FCentralWidget := nil;
4272 if AMenuBar <> nil then
4273 begin
4274 FOwnWidget := False;
4275 FWidget := AMenuBar;
4276 end else
4277 FOwnWidget := True;
4278 // Initializes the properties
4279 FProps := nil;
4280 LCLObject := nil;
4281 // FKeysToEat := [VK_TAB, VK_RETURN, VK_ESCAPE];
4282 // FHasPaint := False;
4283
4284 // FParams := AParams;
4285 InitializeWidget;
4286 end;
4287
4288 procedure TGtk3MenuShell.InitializeWidget;
4289 begin
4290 FCentralWidget := nil;
4291 FCairoContext := nil;
4292 FContext := 0;
4293 FEnterLeaveTime := 0;
4294 if FOwnWidget then
4295 FWidget := CreateWidget(FParams);
4296
4297 LCLIntf.SetProp(HWND(Self),'lclwidget',Self);
4298 end;
4299
4300
4301 { TGtk3MenuBar }
4302
CreateWidgetnull4303 function TGtk3MenuBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
4304 begin
4305 FWidgetType := [wtWidget, wtMenuBar];
4306 Result := TGtkMenuBar.new;
4307 PGtkMenuBar(Result)^.set_pack_direction(MenuDirection[TMenu(MenuObject).UseRightToLeftAlignment]);
4308 end;
4309
4310 { TGtk3Menu }
4311
CreateWidgetnull4312 function TGtk3Menu.CreateWidget(const Params: TCreateParams): PGtkWidget;
4313 begin
4314 FWidgetType := [wtWidget, wtMenu];
4315 Result := TGtkMenu.new;
4316 end;
4317
4318 constructor TGtk3Menu.CreateFromMenuItem(const AMenuItem: TMenuItem);
4319 begin
4320 inherited Create(AMenuItem.GetParentMenu, nil);
4321 end;
4322
4323 { TGtk3MenuItem }
4324
GetCaptionnull4325 function TGtk3MenuItem.GetCaption: string;
4326 begin
4327 Result := '';
4328 if IsWidgetOK then
4329 Result := PGtkMenuItem(FWidget)^.get_label;
4330 end;
4331
4332 procedure TGtk3MenuItem.SetCaption(AValue: string);
4333 begin
4334 if IsWidgetOK then
4335 PGtkMenuItem(FWidget)^.set_label(PgChar(AValue));
4336 end;
4337
CreateWidgetnull4338 function TGtk3MenuItem.CreateWidget(const Params: TCreateParams): PGtkWidget;
4339 var
4340 ndx:integer;
4341 pmenu:TMenuItem;
4342 pl:PGsList;
4343 begin
4344 FWidgetType := [wtWidget, wtMenuItem];
4345 if MenuItem.Caption = cLineCaption then
4346 Result := TGtkSeparatorMenuItem.new
4347 else
4348 if MenuItem.RadioItem and not MenuItem.HasIcon then
4349 begin
4350 Result := TGtkRadioMenuItem.new(nil);
4351 if Assigned(menuItem.Parent) then
4352 begin
4353 ndx:=menuItem.Parent.IndexOf(MenuItem);
4354 if (ndx>0) then
4355 begin
4356 pMenu:=menuItem.Parent.Items[ndx-1];
4357 if (MenuItem.GroupIndex>0) and (pMenu.GroupIndex=MenuItem.GroupIndex) then
4358 begin
4359 pl:=PGtkRadioMenuItem(TGtk3MenuItem(pMenu.Handle).Widget)^.get_group;
4360 PGtkRadioMenuItem(Result)^.set_group(pl);
4361 end;
4362 end;
4363 end;
4364 end
4365 else
4366 if MenuItem.IsCheckItem or MenuItem.HasIcon then
4367 Result := TGtkCheckMenuItem.new
4368 else
4369 Result := TGtkMenuItem.new;
4370
4371 if MenuItem.Caption <> cLineCaption then
4372 begin
4373 PGtkMenuItem(Result)^.set_label(PgChar(MenuItem.Caption));
4374 PGtkMenuItem(Result)^.set_sensitive(MenuItem.Enabled);
4375 // there's nothing like this in Gtk3
4376 // if MenuItem.RightJustify then
4377 // gtk_menu_item_right_justify(PGtkMenuItem(Widget));
4378
4379 end;
4380 end;
4381
4382 constructor TGtk3MenuItem.Create(const AMenuItem: TMenuItem);
4383 begin
4384 inherited Create;
4385 MenuItem := AMenuItem;
4386 FContext := 0;
4387 FHasPaint := False;
4388 FWidget := nil;
4389 FOwner := nil;
4390 FCentralWidget := nil;
4391 FOwnWidget := True;
4392 // Initializes the properties
4393 FProps := nil;
4394 LCLObject := nil;
4395 // FKeysToEat := [VK_TAB, VK_RETURN, VK_ESCAPE];
4396 // FHasPaint := False;
4397
4398 // FParams := AParams;
4399 InitializeWidget;
4400 end;
4401
4402 procedure Gtk3MenuItemActivated(AItem: PGtkMenuItem; AData: GPointer); cdecl;
4403 var
4404 Msg: TLMessage;
4405 begin
4406 // DebugLn('Gtk3MenuItemActivated ',dbgsName(TGtk3MenuItem(Adata)));
4407 FillChar(Msg, SizeOf(Msg), #0);
4408 Msg.Msg := LM_ACTIVATE;
4409 if Assigned(TGtk3MenuItem(AData).MenuItem) then
4410 TGtk3MenuItem(AData).MenuItem.Dispatch(Msg);
4411 end;
4412
4413 procedure TGtk3MenuItem.InitializeWidget;
4414 begin
4415 FCentralWidget := nil;
4416 FCairoContext := nil;
4417 FContext := 0;
4418 FEnterLeaveTime := 0;
4419
4420 FWidget := CreateWidget(FParams);
4421 LCLIntf.SetProp(HWND(Self),'lclwidget',Self);
4422
4423 // move signal connections into attach events
4424 FWidget^.set_events(GDK_ALL_EVENTS_MASK);
4425 g_signal_connect_data(FWidget, 'event', TGCallback(@Gtk3MenuItemEvent), Self, nil, 0);
4426 g_signal_connect_data(FWidget,'activate',TGCallBack(@Gtk3MenuItemActivated), Self, nil, 0);
4427 // must hide all by default
4428 // FWidget^.hide;
4429 end;
4430
4431
4432 { TGtk3ScrollableWin}
4433
TGtk3ScrollableWin.GetHScrollBarPolicynull4434 function TGtk3ScrollableWin.GetHScrollBarPolicy: TGtkPolicyType;
4435 var
4436 AScrollWin: PGtkScrolledWindow;
4437 APolicy: TGtkPolicyType;
4438 begin
4439 Result := GTK_POLICY_AUTOMATIC;
4440 AScrollWin := getScrolledWindow;
4441 if not Gtk3IsScrolledWindow(AScrollWin) then
4442 exit;
4443 AScrollWin^.get_policy(@Result, @APolicy);
4444 end;
4445
TGtk3ScrollableWin.GetVScrollBarPolicynull4446 function TGtk3ScrollableWin.GetVScrollBarPolicy: TGtkPolicyType;
4447 var
4448 AScrollWin: PGtkScrolledWindow;
4449 APolicy: TGtkPolicyType;
4450 begin
4451 Result := GTK_POLICY_AUTOMATIC;
4452 AScrollWin := getScrolledWindow;
4453 if not Gtk3IsScrolledWindow(AScrollWin) then
4454 exit;
4455 AScrollWin^.get_policy(@APolicy, @Result);
4456 end;
4457
4458 procedure TGtk3ScrollableWin.SetBorderStyle(AValue: TBorderStyle);
4459 begin
4460 if FBorderStyle=AValue then Exit;
4461 FBorderStyle:=AValue;
4462 if IsWidgetOK then
4463 begin
4464 if AValue = bsNone then
4465 getScrolledWindow^.set_shadow_type(GTK_SHADOW_NONE)
4466 else
4467 getScrolledWindow^.set_shadow_type(GTK_SHADOW_ETCHED_IN);
4468 end;
4469 end;
4470
4471 procedure TGtk3ScrollableWin.SetHScrollBarPolicy(AValue: TGtkPolicyType);
4472 var
4473 AScrollWin: PGtkScrolledWindow;
4474 APolicyH, APolicyV: TGtkPolicyType;
4475 begin
4476 AScrollWin := getScrolledWindow;
4477 if not Gtk3IsScrolledWindow(AScrollWin) then
4478 exit;
4479 AScrollWin^.get_policy(@APolicyH, @APolicyV);
4480 AScrollWin^.set_policy(AValue, APolicyV);
4481 end;
4482
4483 procedure TGtk3ScrollableWin.SetVScrollBarPolicy(AValue: TGtkPolicyType);
4484 var
4485 AScrollWin: PGtkScrolledWindow;
4486 APolicyH, APolicyV: TGtkPolicyType;
4487 begin
4488 AScrollWin := getScrolledWindow;
4489 if not Gtk3IsScrolledWindow(AScrollWin) then
4490 exit;
4491 AScrollWin^.get_policy(@APolicyH, @APolicyV);
4492 AScrollWin^.set_policy(APolicyH, AValue);
4493 end;
4494
Gtk3RangeScrollCBnull4495 function Gtk3RangeScrollCB(ARange: PGtkRange; AScrollType: TGtkScrollType;
4496 AValue: gdouble; AData: TGtk3Widget): gboolean; cdecl;
4497 var
4498 Msg: TLMVScroll;
4499 MaxValue: gdouble;
4500 Widget: PGtkWidget;
4501 begin
4502 Result := False;
4503
4504 Widget := PGTKWidget(ARange);
4505 {$IFDEF SYNSCROLLDEBUG}
4506 DebugLn(Format('Trace:[Gtk3RangeScrollCB] Value: %d', [RoundToInt(AValue)]),' IsHScrollBar ',dbgs(PGtkOrientable(ARange)^.get_orientation = GTK_ORIENTATION_HORIZONTAL));
4507 {$ENDIF}
4508 if PGtkOrientable(ARange)^.get_orientation = GTK_ORIENTATION_HORIZONTAL then
4509 Msg.Msg := LM_HSCROLL
4510 else
4511 Msg.Msg := LM_VSCROLL;
4512
4513 if ARange^.adjustment^.page_size > 0 then
4514 MaxValue := ARange^.adjustment^.upper - ARange^.adjustment^.page_size
4515 else
4516 MaxValue := ARange^.adjustment^.upper;
4517
4518 if (AValue > MaxValue) then
4519 AValue := MaxValue
4520 else if (AValue < ARange^.adjustment^.lower) then
4521 AValue := ARange^.adjustment^.lower;
4522
4523 with Msg do
4524 begin
4525 Pos := Round(AValue);
4526 if Pos < High(SmallPos) then
4527 SmallPos := Pos
4528 else
4529 SmallPos := High(SmallPos);
4530 {$note to get this correct we must use TQtWidget.CreateFrom() for scrollbars}
4531 ScrollBar := HWND(AData); // HWND({%H-}PtrUInt(ARange));
4532 ScrollCode := Gtk3ScrollTypeToScrollCode(AScrollType);
4533 end;
4534 DeliverMessage(AData.LCLObject, Msg);
4535
4536 if Msg.Scrollcode = SB_THUMBTRACK then
4537 begin
4538 if Widget^.get_state_flags = GTK_STATE_NORMAL then
4539 begin
4540 Msg.ScrollCode := SB_THUMBPOSITION;
4541 DeliverMessage(AData.LCLObject, Msg);
4542 Msg.ScrollCode := SB_ENDSCROLL;
4543 DeliverMessage(AData.LCLObject, Msg);
4544 end;
4545 end else
4546 Widget^.set_state_flags(GTK_STATE_FLAG_ACTIVE, True);
4547
4548 if (AData.LCLObject is TScrollingWinControl) and
4549 ((Msg.ScrollCode=SB_LINEUP) or (Msg.ScrollCode=SB_LINEDOWN)) then
4550 Result:=True;
4551 end;
4552
4553 procedure TGtk3ScrollableWin.SetScrollBarsSignalHandlers;
4554 begin
4555 {TODO: create real instances for scrollbars via TGtk3Widget.CreateFrom() ?}
4556 FBorderStyle := bsNone;
4557 g_signal_connect_data(getHorizontalScrollbar, 'change-value',
4558 TGCallback(@Gtk3RangeScrollCB), Self, nil, 0);
4559 g_signal_connect_data(getVerticalScrollbar, 'change-value',
4560 TGCallback(@Gtk3RangeScrollCB), Self, nil, 0);
4561 end;
4562
getClientBoundsnull4563 function TGtk3ScrollableWin.getClientBounds: TRect;
4564 var
4565 Allocation: TGtkAllocation;
4566 begin
4567 Result := Rect(0, 0, 0, 0);
4568 if IsWidgetOK then
4569 begin
4570 getContainerWidget^.get_allocation(@Allocation);
4571 Result := RectFromGtkAllocation(Allocation);
4572 end;
4573 // DebugLn('TGtk3ScrollableWin.getClientBounds result ',dbgs(Result));
4574 end;
4575
4576 { TGtk3Memo }
4577
CreateWidgetnull4578 function TGtk3Memo.CreateWidget(const Params: TCreateParams): PGtkWidget;
4579 var
4580 AMemo: TCustomMemo;
4581 ABuffer: PGtkTextBuffer;
4582 AScrollStyle: TPoint;
4583 begin
4584 FScrollX := 0;
4585 FScrollY := 0;
4586
4587 FKeysToEat := [];
4588 AMemo := TCustomMemo(LCLObject);
4589
4590 FWidgetType := FWidgetType + [wtMemo, wtScrollingWin];
4591 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
4592
4593 FCentralWidget := PGtkTextView(TGtkTextView.new);
4594
4595 FCentralWidget^.set_has_window(True);
4596
4597 if AMemo.WordWrap then
4598 PGtkTextView(FCentralWidget)^.set_wrap_mode(GTK_WRAP_WORD)
4599 else
4600 PGtkTextView(FCentralWidget)^.set_wrap_mode(GTK_WRAP_NONE);
4601
4602 ABuffer := PGtkTextBuffer^.new(PGtkTextTagTable^.new);
4603 ABuffer^.set_text(PgChar(AMemo.Text), -1);
4604 PGtkTextView(FCentralWidget)^.set_buffer(ABuffer);
4605
4606 PGtkScrolledWindow(Result)^.add(FCentralWidget);
4607
4608 // PGtkScrolledWindow(Result)^.set_focus_child(FCentralWidget);
4609
4610 AScrollStyle := Gtk3TranslateScrollStyle(AMemo.ScrollBars);
4611
4612 // Gtk3 GtkTextView is weird. When scrollbars policy is GTK_POLICY_NONE
4613 // then GtkTextView resizes itself (resizes parent) while adding text,
4614 // so our TMemo size grows.
4615 // http://stackoverflow.com/questions/2695843/gtktextview-automatically-resizing/16881764#16881764
4616 // http://stackoverflow.com/questions/15534475/how-can-i-create-a-fixed-size-gtk-textview-in-gtk3
4617 // https://bugzilla.gnome.org/show_bug.cgi?id=690099
4618 // seem to be fixed in 3.8.2
4619
4620
4621 if (gtk_get_major_version = 3) and (gtk_get_minor_version <= 8) then
4622 begin
4623 if AScrollStyle.X = GTK_POLICY_NEVER then
4624 AScrollStyle.X := GTK_POLICY_AUTOMATIC;
4625 if AScrollStyle.Y = GTK_POLICY_NEVER then
4626 AScrollStyle.Y := GTK_POLICY_AUTOMATIC;
4627 end;
4628
4629
4630 PGtkScrolledWindow(Result)^.set_policy(AScrollStyle.X, AScrollStyle.Y);
4631
4632 PGtkScrolledWindow(Result)^.set_shadow_type(BorderStyleShadowMap[AMemo.BorderStyle]);
4633 PGtkScrolledWindow(Result)^.get_vscrollbar^.set_can_focus(False);
4634 PGtkScrolledWindow(Result)^.get_hscrollbar^.set_can_focus(False);
4635
4636 FCentralWidget^.set_can_focus(True);
4637 PGtkScrolledWindow(Result)^.set_can_focus(False);
4638 end;
4639
EatArrowKeysnull4640 function TGtk3Memo.EatArrowKeys(const AKey: Word): Boolean;
4641 begin
4642 Result := False;
4643 end;
4644
TGtk3Memo.getHorizontalScrollbarnull4645 function TGtk3Memo.getHorizontalScrollbar: PGtkScrollbar;
4646 begin
4647 Result := nil;
4648 if not IsWidgetOk then
4649 exit;
4650 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_hscrollbar);
4651 end;
4652
getVerticalScrollbarnull4653 function TGtk3Memo.getVerticalScrollbar: PGtkScrollbar;
4654 begin
4655 Result := nil;
4656 if not IsWidgetOk then
4657 exit;
4658 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_vscrollbar);
4659 end;
4660
TGtk3Memo.GetScrolledWindownull4661 function TGtk3Memo.GetScrolledWindow: PGtkScrolledWindow;
4662 begin
4663 if IsWidgetOK then
4664 Result := PGtkScrolledWindow(Widget)
4665 else
4666 Result := nil;
4667 end;
4668
GetAlignmentnull4669 function TGtk3Memo.GetAlignment: TAlignment;
4670 var
4671 AJustification: TGtkJustification;
4672 begin
4673 Result := taLeftJustify;
4674 if IsWidgetOk then
4675 begin
4676 AJustification := PGtkTextView(GetContainerWidget)^.get_justification;
4677 if AJustification = GTK_JUSTIFY_RIGHT then
4678 Result := taRightJustify
4679 else
4680 if AJustification = GTK_JUSTIFY_CENTER then
4681 Result := taCenter;
4682 end;
4683 end;
4684
TGtk3Memo.GetReadOnlynull4685 function TGtk3Memo.GetReadOnly: Boolean;
4686 begin
4687 Result := True;
4688 if IsWidgetOk then
4689 Result := not PGtkTextView(GetContainerWidget)^.get_editable;
4690 end;
4691
TGtk3Memo.GetWantTabsnull4692 function TGtk3Memo.GetWantTabs: Boolean;
4693 begin
4694 Result := False;
4695 if IsWidgetOK then
4696 Result := PGtkTextView(GetContainerWidget)^.get_accepts_tab;
4697 end;
4698
TGtk3Memo.GetWordWrapnull4699 function TGtk3Memo.GetWordWrap: Boolean;
4700 begin
4701 Result := True;
4702 if IsWidgetOk then
4703 Result := PGtkTextView(GetContainerWidget)^.get_wrap_mode = GTK_WRAP_WORD;
4704 end;
4705
4706 procedure TGtk3Memo.SetAlignment(AValue: TAlignment);
4707 begin
4708 if IsWidgetOk then
4709 PGtkTextView(GetContainerWidget)^.set_justification(AGtkJustification[AValue]);
4710 end;
4711
4712 procedure TGtk3Memo.SetReadOnly(AValue: Boolean);
4713 begin
4714 if IsWidgetOk then
4715 PGtkTextView(GetContainerWidget)^.set_editable(not AValue);
4716 end;
4717
4718 procedure TGtk3Memo.SetWantTabs(AValue: Boolean);
4719 begin
4720 if IsWidgetOK then
4721 PGtkTextView(GetContainerWidget)^.set_accepts_tab(AValue);
4722 end;
4723
4724 procedure TGtk3Memo.SetWordWrap(AValue: Boolean);
4725 begin
4726 if IsWidgetOk then
4727 begin
4728 if AValue then
4729 PGtkTextView(GetContainerWidget)^.set_wrap_mode(GTK_WRAP_WORD)
4730 else
4731 PGtkTextView(GetContainerWidget)^.set_wrap_mode(GTK_WRAP_NONE);
4732 end;
4733 end;
4734
getTextnull4735 function TGtk3Memo.getText: String;
4736 var
4737 ABuffer: PGtkTextBuffer;
4738 AIter: TGtkTextIter;
4739 ALastIter: TGtkTextIter;
4740 begin
4741 Result := '';
4742 if IsWidgetOk then
4743 begin
4744 ABuffer := PGtkTextView(FCentralWidget)^.get_buffer;
4745 ABuffer^.get_start_iter(@AIter);
4746 ABuffer^.get_end_iter(@ALastIter);
4747 Result := ABuffer^.get_text(@AIter, @ALastIter, False);
4748 end;
4749 // DebugLn('TGtk3Memo.getText Result=',Result);
4750 end;
4751
4752 procedure TGtk3Memo.setText(AValue: String);
4753 var
4754 ABuffer: PGtkTextBuffer;
4755 AIter: PGtkTextIter;
4756 begin
4757 // DebugLn('TGtk3Memo.setText AValue=',AValue);
4758 if IsWidgetOk then
4759 begin
4760 ABuffer := PGtkTextView(FCentralWidget)^.get_buffer;
4761 ABuffer^.set_text(PgChar(AValue), -1);
4762 ABuffer^.get_start_iter(AIter);
4763 ABuffer^.place_cursor(AIter);
4764 end;
4765 end;
4766
4767 { TGtk3ListBox }
4768
4769 procedure Gtk3ListBoxSelectionChanged(ASelection: PGtkTreeSelection; AData: GPointer); cdecl;
4770 var
4771 Msg: TLMessage;
4772 begin
4773 // DebugLn('Gtk3ListBoxSelectionChanged ');
4774 FillChar(Msg, SizeOf(Msg), #0);
4775 Msg.Msg := LM_SELCHANGE;
4776 if not TGtk3Widget(AData).InUpdate then
4777 TGtk3Widget(AData).DeliverMessage(Msg, False);
4778 end;
4779
CreateWidgetnull4780 function TGtk3ListBox.CreateWidget(const Params: TCreateParams): PGtkWidget;
4781 var
4782 AListBox: TCustomListBox;
4783 ListStore: PGtkListStore;
4784 ItemList: TGtkListStoreStringList;
4785 AColumn: PGtkTreeViewColumn;
4786 Renderer : PGtkCellRenderer;
4787 begin
4788 FScrollX := 0;
4789 FScrollY := 0;
4790 FListBoxStyle := lbStandard;
4791
4792 FWidgetType := FWidgetType + [wtTreeModel, wtListBox, wtScrollingWin];
4793 AListBox := TCustomListBox(LCLObject);
4794
4795
4796 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
4797 Result^.show;
4798
4799 ListStore := gtk_list_store_new (2, [G_TYPE_STRING, G_TYPE_POINTER, nil]);
4800 FCentralWidget := TGtkTreeView.new_with_model(PGtkTreeModel(ListStore));
4801 PGtkTreeView(FCentralWidget)^.set_headers_visible(False);
4802 g_object_unref (liststore);
4803
4804 ItemList := TGtkListStoreStringList.Create(PGtkListStore(PGtkTreeView(FCentralWidget)^.get_model), 0, LCLObject);
4805 g_object_set_data(PGObject(FCentralWidget),GtkListItemLCLListTag, ItemList);
4806
4807 Renderer := LCLIntfCellRenderer_New();
4808
4809 g_object_set_data(PGObject(renderer), 'lclwidget', Self);
4810
4811 AColumn := gtk_tree_view_column_new_with_attributes ('LISTITEMS', renderer,
4812 ['text', 0, nil]);
4813
4814 g_object_set_data(PGObject(AColumn), 'lclwidget', Self);
4815
4816 // maybe create GtkCellLayout class with our implementation and set that layout
4817 // to AColumn
4818 // PGtkCellLayout(AColumn)^.set_cell_data_func()
4819 // PGtkCellLayout(AColumn)^.set_cell_data_func(renderer, @LCLIntfRenderer_GtkCellLayoutDataFunc, Self, nil);
4820 AColumn^.set_cell_data_func(renderer, @LCLIntfRenderer_ColumnCellDataFunc, Self, nil);
4821
4822 PGtkTreeView(FCentralWidget)^.append_column(AColumn);
4823
4824 AColumn^.set_clickable(True);
4825
4826 // AColumn^set_cell_data_func(AColumn, renderer, @LCLIntfRenderer_ColumnCellDataFunc, Self, nil);
4827
4828 PGtkScrolledWindow(Result)^.add(FCentralWidget);
4829
4830 PGtkScrolledWindow(Result)^.get_vscrollbar^.set_can_focus(False);
4831 PGtkScrolledWindow(Result)^.get_hscrollbar^.set_can_focus(False);
4832 PGtkScrolledWindow(Result)^.set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
4833 FListBoxStyle := AListBox.Style;
4834 if FListBoxStyle <> lbOwnerDrawVariable then
4835 begin
4836 AColumn^.set_sizing(GTK_TREE_VIEW_COLUMN_FIXED);
4837 PGtkTreeView(FCentralWidget)^.set_fixed_height_mode(True);
4838 end;
4839
4840 end;
4841
EatArrowKeysnull4842 function TGtk3ListBox.EatArrowKeys(const AKey: Word): Boolean;
4843 begin
4844 Result := False;
4845 end;
4846
4847 procedure TGtk3ListBox.InitializeWidget;
4848 begin
4849 inherited InitializeWidget;
4850 g_signal_connect_data(GetSelection, 'changed', TGCallback(@Gtk3ListBoxSelectionChanged), Self, nil, 0);
4851 end;
4852
TGtk3ListBox.getHorizontalScrollbarnull4853 function TGtk3ListBox.getHorizontalScrollbar: PGtkScrollbar;
4854 begin
4855 Result := nil;
4856 if not IsWidgetOk then
4857 exit;
4858 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_hscrollbar);
4859 end;
4860
TGtk3ListBox.getVerticalScrollbarnull4861 function TGtk3ListBox.getVerticalScrollbar: PGtkScrollbar;
4862 begin
4863 Result := nil;
4864 if not IsWidgetOk then
4865 exit;
4866 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_vscrollbar);
4867 end;
4868
TGtk3ListBox.GetScrolledWindownull4869 function TGtk3ListBox.GetScrolledWindow: PGtkScrolledWindow;
4870 begin
4871 if IsWidgetOK then
4872 Result := PGtkScrolledWindow(Widget)
4873 else
4874 Result := nil;
4875 end;
4876
GetItemIndexnull4877 function TGtk3ListBox.GetItemIndex: Integer;
4878 var
4879 TreeView: PGtkTreeView;
4880 Path: PGtkTreePath;
4881 Column: PGtkTreeViewColumn;
4882 Selection: PGtkTreeSelection;
4883 begin
4884 Result := -1;
4885 if Gtk3IsWidget(FWidget) then
4886 begin
4887 Path := nil;
4888 Column := nil;
4889 TreeView := PGtkTreeView(GetContainerWidget);
4890 TreeView^.get_cursor(@Path, @Column);
4891 if Path <> nil then
4892 begin
4893 Result := gtk_tree_path_get_indices(Path)^;
4894 if Result = 0 then
4895 begin
4896 Selection := TreeView^.get_selection;
4897 if not Selection^.path_is_selected(Path) then
4898 Result := -1;
4899 end;
4900 end;
4901 end;
4902 end;
4903
TGtk3ListBox.GetMultiSelectnull4904 function TGtk3ListBox.GetMultiSelect: Boolean;
4905 var
4906 Selection: PGtkTreeSelection;
4907 begin
4908 if IsWidgetOk then
4909 begin
4910 Selection := GetSelection;
4911 if Selection <> nil then
4912 Result := Selection^.get_mode <> GTK_SELECTION_SINGLE;
4913 end;
4914 end;
4915
4916 procedure TGtk3ListBox.SetItemIndex(AValue: Integer);
4917 var
4918 TreeView: PGtkTreeView;
4919 Selection: PGtkTreeSelection;
4920 Path: PGtkTreePath;
4921 begin
4922 if Gtk3IsWidget(FWidget) then
4923 begin
4924 TreeView := PGtkTreeView(GetContainerWidget);
4925 Selection := GetSelection;
4926 if (AValue < 0) then
4927 Path := nil
4928 else
4929 Path := gtk_tree_path_new_from_indices(AValue, [-1]);
4930
4931 // if singleselection mode then selection = itemindex
4932 if Path <> nil then
4933 begin
4934 gtk_tree_view_set_cursor(TreeView, Path, nil, False);
4935 end else
4936 begin
4937 Path := gtk_tree_path_new_from_indices(0, [-1]);
4938 gtk_tree_view_set_cursor(TreeView, Path, nil, False);
4939 gtk_tree_selection_unselect_all(Selection);
4940 end;
4941
4942 if Path <> nil then
4943 gtk_tree_path_free(Path);
4944 end;
4945 end;
4946
4947 procedure TGtk3ListBox.SetListBoxStyle(AValue: TListBoxStyle);
4948 begin
4949 if FListBoxStyle=AValue then Exit;
4950 FListBoxStyle:=AValue;
4951 end;
4952
4953 procedure TGtk3ListBox.SetMultiSelect(AValue: Boolean);
4954 var
4955 Selection: PGtkTreeSelection;
4956 begin
4957 if IsWidgetOk then
4958 begin
4959 Selection := GetSelection;
4960 if Selection <> nil then
4961 begin
4962 if AValue then
4963 Selection^.set_mode(GTK_SELECTION_MULTIPLE)
4964 else
4965 Selection^.set_mode(GTK_SELECTION_SINGLE);
4966 end;
4967 end;
4968 end;
4969
GetSelCountnull4970 function TGtk3ListBox.GetSelCount: Integer;
4971 var
4972 Selection: PGtkTreeSelection;
4973 Rows: PGList;
4974 ListStoreModel: PGtkTreeModel;
4975 begin
4976 Result := 0;
4977 if not Gtk3IsWidget(FWidget) then
4978 exit;
4979 Selection := GetSelection;
4980 if Selection = nil then
4981 exit;
4982 Rows := Selection^.get_selected_rows(@ListStoreModel);
4983 Result := g_list_length(Rows);
4984 g_list_free(Rows);
4985 end;
4986
GetSelectionnull4987 function TGtk3ListBox.GetSelection: PGtkTreeSelection;
4988 begin
4989 if not IsWidgetOk then
4990 exit(nil);
4991 Result := PGtkTreeView(GetContainerWidget)^.get_selection;
4992 end;
4993
GetItemSelectednull4994 function TGtk3ListBox.GetItemSelected(const AIndex: Integer): Boolean;
4995 var
4996 ASelection: PGtkTreeSelection;
4997 AModel: PGtkTreeModel;
4998 Item: TGtkTreeIter;
4999 begin
5000 Result := False;
5001
5002 if not IsWidgetOK then
5003 exit;
5004
5005 AModel := PGtkTreeView(GetContainerWidget)^.model;
5006
5007 if AModel = nil then
5008 exit;
5009
5010 ASelection := GetSelection;
5011
5012 if ASelection = nil then
5013 exit;
5014
5015 if AModel^.iter_nth_child(@Item, nil, AIndex) then
5016 Result := ASelection^.iter_is_selected(@Item);
5017 end;
5018
5019 procedure TGtk3ListBox.SelectItem(const AIndex: Integer; ASelected: Boolean);
5020 var
5021 ASelection: PGtkTreeSelection;
5022 AModel: PGtkTreeModel;
5023 Iter: TGtkTreeIter;
5024 begin
5025 if not IsWidgetOK then
5026 exit;
5027
5028 AModel := PGtkTreeView(getContainerWidget)^.model;
5029
5030 if AModel = nil then
5031 exit;
5032
5033 ASelection := GetSelection;
5034
5035 if AModel^.iter_nth_child(@Iter, nil, AIndex) then
5036 begin
5037 case ASelected of
5038 True:
5039 if not ASelection^.iter_is_selected(@Iter) then
5040 ASelection^.select_iter(@Iter);
5041 False:
5042 if ASelection^.iter_is_selected(@Iter) then
5043 ASelection^.unselect_iter(@Iter);
5044 end;
5045 end;
5046 end;
5047
5048 procedure TGtk3ListBox.SetTopIndex(const AIndex: Integer);
5049 var
5050 AModel: PGtkTreeModel;
5051 Iter: TGtkTreeIter;
5052 APath: PGtkTreePath;
5053 begin
5054 AModel := PGtkTreeView(getContainerWidget)^.model;
5055
5056 if not AModel^.iter_nth_child(@Iter, nil, AIndex) then
5057 exit;
5058 APath := AModel^.get_path(@Iter);
5059 PGtkTreeView(getContainerWidget)^.scroll_to_cell(APath, nil, False, 0.0, 0.0);
5060 APath^.free;
5061 end;
5062
5063 { TGtk3CheckListBox }
5064
5065 procedure Gtk3WS_CheckListBoxDataFunc({%H-}tree_column: PGtkTreeViewColumn;
5066 cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; {%H-}data: Pointer); cdecl;
5067 var
5068 b: byte;
5069 ADisabled: gboolean;
5070 AValue: TCheckBoxState;
5071 begin
5072 B := 0;
5073 ADisabled := False;
5074 gtk_tree_model_get(tree_model, iter, [gtk3CLBState, @b, -1]);
5075 gtk_tree_model_get(tree_model, iter, [gtk3CLBDisabled, @ADisabled, -1]);
5076 AValue := TCheckBoxState(b); // TCheckBoxState is 4 byte
5077 g_object_set(cell, 'inconsistent', [gboolean(AValue = cbGrayed), nil]);
5078 if AValue <> cbGrayed then
5079 gtk_cell_renderer_toggle_set_active(PGtkCellRendererToggle(cell), AValue = cbChecked);
5080
5081 g_object_set(cell, 'activatable', [gboolean(not ADisabled), nil]);
5082 end;
5083
5084 procedure Gtk3WS_CheckListBoxToggle({%H-}cellrenderertoggle : PGtkCellRendererToggle;
5085 arg1 : PGChar; AData: GPointer); cdecl;
5086 var
5087 Mess: TLMessage;
5088 Param: PtrInt;
5089 Iter : TGtkTreeIter;
5090 TreeView: PGtkTreeView;
5091 ListStore: PGtkTreeModel;
5092 Path: PGtkTreePath;
5093 AState: TCheckBoxState;
5094 begin
5095 Val(arg1, Param);
5096
5097 TreeView := PGtkTreeView(TGtk3CheckListBox(AData).GetContainerWidget);
5098 ListStore := gtk_tree_view_get_model(TreeView);
5099 if gtk_tree_model_iter_nth_child(ListStore, @Iter, nil, Param) then
5100 begin
5101 TCustomCheckListBox(TGtk3Widget(AData).LCLObject).Toggle(Param);
5102 AState := TCustomCheckListBox(TGtk3Widget(AData).LCLObject).State[Param];
5103 gtk_list_store_set(PGtkListStore(ListStore), @Iter, [gtk3CLBState,
5104 Byte(AState), -1]);
5105 end;
5106
5107
5108 Path := gtk_tree_path_new_from_indices(Param, [-1]);
5109 if Path <> nil then
5110 begin
5111 gtk_tree_view_set_cursor(TreeView, Path, nil, False);
5112 gtk_tree_path_free(Path);
5113 end;
5114
5115 FillChar(Mess{%H-}, SizeOf(Mess), #0);
5116 Mess.Msg := LM_CHANGED;
5117
5118 Mess.Result := 0;
5119 Mess.WParam := Param;
5120 DeliverMessage(TGtk3Widget(AData).LCLObject, Mess);
5121
5122 end;
5123
CreateWidgetnull5124 function TGtk3CheckListBox.CreateWidget(const Params: TCreateParams
5125 ): PGtkWidget;
5126 var
5127 ACheckListBox: TCustomCheckListBox;
5128 ListStore: PGtkListStore;
5129 ItemList: TGtkListStoreStringList;
5130 AColumn: PGtkTreeViewColumn;
5131 Toggle: PGtkCellRendererToggle;
5132 Renderer : PGtkCellRenderer;
5133 begin
5134 FScrollX := 0;
5135 FScrollY := 0;
5136 FWidgetType := FWidgetType + [wtTreeModel, wtListBox, wtCheckListBox, wtScrollingWin];
5137 ACheckListBox := TCustomCheckListBox(LCLObject);
5138 FListBoxStyle := lbStandard;
5139
5140 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
5141 Result^.show;
5142
5143 ListStore := gtk_list_store_new (4, [G_TYPE_UCHAR, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, nil]);
5144 FCentralWidget := TGtkTreeView.new_with_model(PGtkTreeModel(ListStore));
5145 PGtkTreeView(FCentralWidget)^.set_headers_visible(False);
5146 g_object_unref (liststore);
5147
5148 AColumn := gtk_tree_view_column_new;
5149
5150 // checkable column
5151 Toggle := gtk_cell_renderer_toggle_new;
5152 g_object_set_data(PGObject(Toggle), 'lclwidget', Self);
5153
5154 AColumn^.set_title('CHECKBINS');
5155 AColumn^.pack_start(Toggle, True);
5156 AColumn^.set_cell_data_func(Toggle, @Gtk3WS_CheckListBoxDataFunc, Self, nil);
5157 Toggle^.set_active(True);
5158 PGtkTreeView(FCentralWidget)^.append_column(AColumn);
5159 AColumn^.set_clickable(True);
5160
5161 g_signal_connect_data(Toggle, 'toggled', TGCallback(@Gtk3WS_CheckListBoxToggle), Self, nil, 0);
5162
5163 Renderer := LCLIntfCellRenderer_New(); // gtk_cell_renderer_text_new;
5164
5165 g_object_set_data(PGObject(Renderer), 'lclwidget', Self);
5166
5167 AColumn := gtk_tree_view_column_new_with_attributes ('LISTITEMS', Renderer,
5168 ['text', 1, nil]);
5169
5170 g_object_set_data(PGObject(AColumn), 'lclwidget', Self);
5171
5172 // AColumn^.pack_start(Renderer, True);
5173
5174 AColumn^.set_cell_data_func(Renderer, @LCLIntfRenderer_ColumnCellDataFunc, Self, nil);
5175
5176 PGtkTreeView(FCentralWidget)^.append_column(AColumn);
5177
5178 ItemList := TGtkListStoreStringList.Create(PGtkListStore(PGtkTreeView(FCentralWidget)^.get_model), 1, LCLObject);
5179 g_object_set_data(PGObject(FCentralWidget),GtkListItemLCLListTag, ItemList);
5180
5181
5182 AColumn^.set_clickable(True);
5183
5184 // AColumn^set_cell_data_func(AColumn, renderer, @LCLIntfRenderer_ColumnCellDataFunc, Self, nil);
5185
5186 PGtkScrolledWindow(Result)^.add(FCentralWidget);
5187
5188
5189 PGtkScrolledWindow(Result)^.get_vscrollbar^.set_can_focus(False);
5190 PGtkScrolledWindow(Result)^.get_hscrollbar^.set_can_focus(False);
5191 PGtkScrolledWindow(Result)^.set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
5192 FListBoxStyle := ACheckListBox.Style;
5193 if ACheckListBox.MultiSelect then
5194 PGtkTreeView(FCentralWidget)^.get_selection^.set_mode(GTK_SELECTION_MULTIPLE)
5195 else
5196 PGtkTreeView(FCentralWidget)^.get_selection^.set_mode(GTK_SELECTION_SINGLE);
5197 // AListBox.Style;
5198 if FListBoxStyle <> lbOwnerDrawVariable then
5199 begin
5200 //AColumn^.set_sizing(GTK_TREE_VIEW_COLUMN_FIXED);
5201 //PGtkTreeView(FCentralWidget)^.set_fixed_height_mode(True);
5202 end;
5203
5204 end;
5205
5206 { TGtk3ListView }
5207
Gtk3WS_ListViewItemPreSelectednull5208 function Gtk3WS_ListViewItemPreSelected({%H-}selection: PGtkTreeSelection; {%H-}model: PGtkTreeModel;
5209 path: PGtkTreePath; path_is_currently_selected: GBoolean; AData: GPointer): GBoolean; cdecl;
5210 begin
5211 // DebugLn('Gtk3WS_ListViewItemSelected ,path selected ',dbgs(path_is_currently_selected));
isnull5212 // this function is called *before* the item is selected
5213 // The result should be True to allow the Item to change selection
5214 Result := True;
5215
5216 if (AData = nil) or TGtk3Widget(AData).InUpdate then
5217 exit;
5218
5219 if not Assigned(TGtk3ListView(AData).FPreselectedIndices) then
5220 TGtk3ListView(AData).FPreselectedIndices := TFPList.Create;
5221
5222 if TGtk3ListView(AData).FPreselectedIndices.IndexOf(Pointer(PtrInt(gtk_tree_path_get_indices(path)^))) = -1 then
5223 TGtk3ListView(AData).FPreselectedIndices.Add(Pointer(PtrInt(gtk_tree_path_get_indices(path)^)));
5224 end;
5225
5226 procedure Gtk3WS_ListViewItemSelected(ASelection: PGtkTreeSelection; AData: GPointer); cdecl;
5227 var
5228 ATreeView: PGtkTreeView;
5229 AList: PGList;
5230 Msg: TLMNotify;
5231 NM: TNMListView;
5232 Path: PGtkTreePath;
5233 Indices: Integer;
5234 i, j: Integer;
5235 B: Boolean;
5236 begin
5237 if (AData = nil) or TGtk3Widget(AData).InUpdate then
5238 exit;
5239 if not Assigned(TGtk3ListView(AData).FPreselectedIndices) then
5240 exit;
5241 ATreeView := gtk_tree_selection_get_tree_view(ASelection);
5242 AList := gtk_tree_selection_get_selected_rows(ASelection, nil);
5243 TGtk3Widget(AData).BeginUpdate; // dissalow entering Gtk3WS_ListViewItemPreSelected
5244 try
5245 for i := 0 to TGtk3ListView(AData).FPreselectedIndices.Count - 1 do
5246 begin
5247 FillChar(Msg{%H-}, SizeOf(Msg), 0);
5248 Msg.Msg := CN_NOTIFY;
5249 FillChar(NM{%H-}, SizeOf(NM), 0);
5250 NM.hdr.hwndfrom := HWND(TGtk3Widget(AData));
5251 NM.hdr.code := LVN_ITEMCHANGED;
5252 NM.iItem := PtrInt(TGtk3ListView(AData).FPreselectedIndices.Items[i]);
5253 NM.iSubItem := 0;
5254 B := False;
5255 for j := 0 to g_list_length(AList) - 1 do
5256 begin
5257 Path := g_list_nth_data(AList, guint(j));
5258 if Path <> nil then
5259 begin
5260 Indices := gtk_tree_path_get_indices(Path)^;
5261 B := Indices = PtrInt(TGtk3ListView(AData).FPreselectedIndices.Items[i]);
5262 if B then
5263 break;
5264 end;
5265 end;
5266 if not B then
5267 NM.uOldState := LVIS_SELECTED
5268 else
5269 NM.uNewState := LVIS_SELECTED;
5270 NM.uChanged := LVIF_STATE;
5271 Msg.NMHdr := @NM.hdr;
5272 DeliverMessage(TGtk3Widget(AData).LCLObject, Msg);
5273 end;
5274 finally
5275 FreeAndNil(TGtk3ListView(AData).FPreselectedIndices);
5276 if AList <> nil then
5277 g_list_free(AList);
5278 TGtk3Widget(AData).EndUpdate;
5279 end;
5280 end;
5281
TGtk3ListView.CreateWidgetnull5282 function TGtk3ListView.CreateWidget(const Params: TCreateParams): PGtkWidget;
5283 var
5284 AListView: TCustomListView;
5285 AScrollStyle: TPoint;
5286 PtrType: GType;
5287 TreeModel: PGtkTreeModel;
5288 begin
5289 FImages := nil;
5290 FScrollX := 0;
5291 FScrollY := 0;
5292 FPreselectedIndices := nil;
5293 FWidgetType := FWidgetType + [wtTreeModel, wtListView, wtScrollingWin];
5294 AListView := TCustomListView(LCLObject);
5295 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
5296
5297 PtrType := G_TYPE_POINTER;
5298
5299 TreeModel := PGtkTreeModel(gtk_list_store_newv(1, @PtrType));
5300
5301 if TListView(AListView).ViewStyle in [vsIcon,vsSmallIcon] then
5302 FCentralWidget := TGtkIconView.new_with_model(TreeModel)
5303 else
5304 FCentralWidget := TGtkTreeView.new_with_model(TreeModel);
5305
5306 FIsTreeView := not (TListView(AListView).ViewStyle in [vsIcon,vsSmallIcon]);
5307
5308 FCentralWidget^.set_has_window(True);
5309 FCentralWidget^.show;
5310
5311 PGtkScrolledWindow(Result)^.add(FCentralWidget);
5312 //PGtkScrolledWindow(Result)^.set_focus_child(FCentralWidget);
5313
5314 AScrollStyle := Gtk3TranslateScrollStyle(TListView(AListView).ScrollBars);
5315 // gtk3 scrolled window hates GTK_POLICY_NONE
5316 PGtkScrolledWindow(Result)^.set_policy(AScrollStyle.X, AScrollStyle.Y);
5317 PGtkScrolledWindow(Result)^.set_shadow_type(BorderStyleShadowMap[AListView.BorderStyle]);
5318 PGtkScrolledWindow(Result)^.get_vscrollbar^.set_can_focus(False);
5319 PGtkScrolledWindow(Result)^.get_hscrollbar^.set_can_focus(False);
5320 g_object_unref (PGObject(TreeModel));
5321 PGtkScrolledWindow(Result)^.set_can_focus(False);
5322 PGtkTreeView(FCentralWidget)^.set_can_focus(True);
5323 if FIsTreeView then
5324 begin
GtkTreeViewnull5325 gtk_tree_selection_set_select_function(PGtkTreeView(FCentralWidget)^.get_selection, TGtkTreeSelectionFunc(@Gtk3WS_ListViewItemPreSelected),
5326 Self, nil);
5327 g_signal_connect_data(PGtkTreeView(FCentralWidget)^.get_selection, 'changed', TGCallback(@Gtk3WS_ListViewItemSelected), Self, nil, 0);
5328 end;
5329 // if FIsTreeView then
5330 // PGtkTreeView(FCentralWidget)^.set_search_column(0);
5331 end;
5332
TGtk3ListView.EatArrowKeysnull5333 function TGtk3ListView.EatArrowKeys(const AKey: Word): Boolean;
5334 begin
5335 Result := False;
5336 end;
5337
5338 destructor TGtk3ListView.Destroy;
5339 begin
5340 ClearImages;
5341 FreeAndNil(FImages);
5342 FreeAndNil(FPreselectedIndices);
5343 inherited Destroy;
5344 end;
5345
getHorizontalScrollbarnull5346 function TGtk3ListView.getHorizontalScrollbar: PGtkScrollbar;
5347 begin
5348 Result := nil;
5349 if not IsWidgetOk then
5350 exit;
5351 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_hscrollbar);
5352 end;
5353
TGtk3ListView.getVerticalScrollbarnull5354 function TGtk3ListView.getVerticalScrollbar: PGtkScrollbar;
5355 begin
5356 Result := nil;
5357 if not IsWidgetOk then
5358 exit;
5359 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_vscrollbar);
5360 end;
5361
TGtk3ListView.GetScrolledWindownull5362 function TGtk3ListView.GetScrolledWindow: PGtkScrolledWindow;
5363 begin
5364 if IsWidgetOK then
5365 Result := PGtkScrolledWindow(Widget)
5366 else
5367 Result := nil;
5368 end;
5369
5370 procedure TGtk3ListView.ClearImages;
5371 var
5372 i: Integer;
5373 begin
5374 if Assigned(FImages) then
5375 begin
5376 for i := FImages.Count - 1 downto 0 do
5377 if FImages[i] <> nil then
5378 TGtk3Object(FImages[i]).Free;
5379 FImages.Clear;
5380 end;
5381 end;
5382
5383 procedure TGtk3ListView.ColumnDelete(AIndex: Integer);
5384 var
5385 AColumn: PGtkTreeViewColumn;
5386 begin
5387 if IsWidgetOK and IsTreeView then
5388 begin
5389 AColumn := PGtkTreeView(GetContainerWidget)^.get_column(AIndex);
5390 if (AColumn<>nil) then
5391 PGtkTreeView(GetContainerWidget)^.remove_column(AColumn);
5392 end;
5393 end;
5394
ColumnGetWidthnull5395 function TGtk3ListView.ColumnGetWidth(AIndex: Integer): Integer;
5396 var
5397 AColumn: PGtkTreeViewColumn;
5398 begin
5399 Result := 0;
5400 if IsWidgetOK and IsTreeView then
5401 begin
5402 AColumn := PGtkTreeView(GetContainerWidget)^.get_column(AIndex);
5403 if (AColumn<>nil) then
5404 Result := AColumn^.get_width;
5405 end;
5406 end;
5407
5408 procedure Gtk3WSLV_ListViewGetPixbufDataFuncForColumn(tree_column: PGtkTreeViewColumn;
5409 cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; AData: GPointer); cdecl;
5410 var
5411 ListItem: TListItem;
5412 Images: TFPList;
5413 // Widgets: PTVWidgets;
5414 ListColumn: TListColumn;
5415 ImageIndex: Integer;
5416 ColumnIndex: Integer;
5417 APath: PGtkTreePath;
5418 begin
5419 // TODO: set_property('pixbuf', TGValue);
5420 // PGtkCellRendererPixbuf(cell)^.pixbuf := nil;
5421 gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]);
5422
5423 ListColumn := TListColumn(g_object_get_data(tree_column, 'TListColumn'));
5424 if ListColumn = nil then
5425 Exit;
5426 ColumnIndex := ListColumn.Index;
5427 // Images := Widgets^.Images;
5428 Images := TGtk3ListView(AData).Images;
5429 if Images = nil then
5430 Exit;
5431 ImageIndex := -1;
5432
5433 if (ListItem = nil) and TCustomListView(TGtk3Widget(AData).LCLObject).OwnerData then
5434 begin
5435 APath := gtk_tree_model_get_path(tree_model,iter);
5436 ListItem := TCustomListView(TGtk3Widget(AData).LCLObject).Items[gtk_tree_path_get_indices(APath)^];
5437 gtk_tree_path_free(APath);
5438 end;
5439
5440 if ListItem = nil then
5441 Exit;
5442
5443 if ColumnIndex = 0 then
5444 ImageIndex := ListItem.ImageIndex
5445 else
5446 if ColumnIndex -1 <= ListItem.SubItems.Count-1 then
5447 ImageIndex := ListItem.SubItemImages[ColumnIndex-1];
5448
5449 (* TODO: set property
5450 if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then
5451 PGtkCellRendererPixbuf(cell)^.pixbuf := PGdkPixbuf(Images.Items[ImageIndex])
5452 else
5453 PGtkCellRendererPixbuf(cell)^.pixbuf := nil;
5454 *)
5455 end;
5456
5457 procedure Gtk3WS_ListViewColumnClicked(column: PGtkTreeViewColumn; AData: GPointer); cdecl;
5458 var
5459 AColumn: TListColumn;
5460 Msg: TLMNotify;
5461 NM: TNMListView;
5462 begin
5463 AColumn := TListColumn(g_object_get_data(PGObject(column), 'TListColumn'));
5464
5465 if (AColumn = nil) or (AData = nil) then
5466 exit;
5467
5468 FillChar(Msg{%H-}, SizeOf(Msg), 0);
5469 Msg.Msg := CN_NOTIFY;
5470
5471 FillChar(NM{%H-}, SizeOf(NM), 0);
5472 NM.hdr.hwndfrom := {%H-}PtrUInt(AData);
5473 NM.hdr.code := LVN_COLUMNCLICK;
5474 NM.iItem := -1;
5475 NM.iSubItem := AColumn.Index;
5476 Msg.NMHdr := @NM.hdr;
5477 DeliverMessage(TGtk3Widget(AData).LCLObject, Msg);
5478 end;
5479
5480 procedure TGtk3ListView.ColumnInsert(AIndex: Integer; AColumn: TListColumn);
5481 var
5482 AGtkColumn: PGtkTreeViewColumn;
5483 PixRenderer,
5484 TextRenderer: PGtkCellRenderer;
5485 begin
5486 if not IsWidgetOK or not IsTreeView then
5487 exit;
5488 AGtkColumn := TGtkTreeViewColumn.new;
5489
5490 PixRenderer := gtk_cell_renderer_pixbuf_new();
5491 TextRenderer := LCLIntfCellRenderer_New;
5492
5493 AGtkColumn^.pack_start(PixRenderer, False);
5494 AGtkColumn^.pack_start(TextRenderer, True);
5495
5496 // gtk_tree_view_column_set_cell_data_func(column, pixrenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetPixbufDataFuncForColumn), WidgetInfo, nil);
5497 // gtk_tree_view_column_set_cell_data_func(column, textrenderer, TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), Self, nil);
5498 AGtkColumn^.set_cell_data_func(PixRenderer, @Gtk3WSLV_ListViewGetPixbufDataFuncForColumn, Self, nil);
5499
5500
5501 AGtkColumn^.set_cell_data_func(PGtkCellRenderer(TextRenderer), TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), Self, nil);
5502
5503 //store the TColumn in the column data for callbacks
5504 g_object_set_data(AGtkColumn, PgChar('TListColumn'), gpointer(AColumn));
5505
5506 g_signal_connect_data(AGtkColumn,'clicked', TGCallback(@Gtk3WS_ListViewColumnClicked), Self, nil, 0);
5507 PGtkTreeView(GetContainerWidget)^.insert_column(AGtkColumn, AIndex);
5508 AGtkColumn^.set_clickable(True);
5509
5510 end;
5511
5512 procedure TGtk3ListView.SetAlignment(AIndex: Integer; AColumn: TListColumn;
5513 AAlignment: TAlignment);
5514 var
5515 AGtkColumn: PGtkTreeViewColumn;
5516 AFloat: Double;
5517 AList: PGList;
5518 textrenderer: PGtkCellRenderer;
5519 Value: TGValue;
5520 begin
5521 if not IsWidgetOK or not IsTreeView then
5522 exit;
5523 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5524 if AGtkColumn = nil then
5525 exit;
5526
5527 AFloat := 0;
5528 case AAlignment of
5529 taRightJustify: AFloat := 1;
5530 taCenter: AFloat := 0.5;
5531 end;
5532
5533
5534 AList := PGtkCellLayout(AGtkColumn)^.get_cells;
5535 // AList := gtk_tree_view_column_get_cell_renderers(AColumn);
5536 textrenderer := PGtkCellRenderer(g_list_last(AList)^.data);
5537 g_list_free(AList);
5538
5539 Value.g_type := G_TYPE_FLOAT;
5540 Value.set_float(AFloat);
5541 g_object_set_property(textrenderer, PChar('xalign'), @Value);
5542
5543 {now we call set alignment because it calls update over visible rows in col}
5544 AGtkColumn^.set_alignment(AFloat);
5545 end;
5546
5547 procedure TGtk3ListView.SetColumnAutoSize(AIndex: Integer;
5548 AColumn: TListColumn; AAutoSize: Boolean);
5549 const
5550 SizingMap: array[Boolean] of TGtkTreeViewColumnSizing = (
5551 2 {GTK_TREE_VIEW_COLUMN_FIXED},
5552 1 {GTK_TREE_VIEW_COLUMN_AUTOSIZE}
5553 );
5554 var
5555 AGtkColumn: PGtkTreeViewColumn;
5556 begin
5557 if not IsWidgetOK or not IsTreeView then
5558 exit;
5559 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5560 if AGtkColumn <> nil then
5561 begin
5562 AGtkColumn^.set_resizable(True);
5563 AGtkColumn^.set_sizing(SizingMap[AAutoSize]);
5564 end;
5565 end;
5566
5567 procedure TGtk3ListView.SetColumnCaption(AIndex: Integer; AColumn: TListColumn;
5568 const ACaption: String);
5569 var
5570 AGtkColumn: PGtkTreeViewColumn;
5571 begin
5572 if not IsWidgetOK or not IsTreeView then
5573 exit;
5574 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5575 if AGtkColumn <> nil then
5576 begin
5577 AGtkColumn^.set_title(PgChar(ACaption));
5578 end;
5579 end;
5580
5581 procedure TGtk3ListView.SetColumnMaxWidth(AIndex: Integer;
5582 AColumn: TListColumn; AMaxWidth: Integer);
5583 var
5584 AGtkColumn: PGtkTreeViewColumn;
5585 begin
5586 if not IsWidgetOK or not IsTreeView then
5587 exit;
5588 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5589 if AGtkColumn <> nil then
5590 begin
5591 if AMaxWidth <= 0 then
5592 AGtkColumn^.set_max_width(10000)
5593 else
5594 AGtkColumn^.set_max_width(AMaxWidth);
5595 end;
5596 end;
5597
5598 procedure TGtk3ListView.SetColumnMinWidth(AIndex: Integer;
5599 AColumn: TListColumn; AMinWidth: Integer);
5600 var
5601 AGtkColumn: PGtkTreeViewColumn;
5602 begin
5603 if not IsWidgetOK or not IsTreeView then
5604 exit;
5605 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5606 if AGtkColumn <> nil then
5607 AGtkColumn^.set_min_width(AMinWidth);
5608 end;
5609
5610 procedure TGtk3ListView.SetColumnWidth(AIndex: Integer; AColumn: TListColumn;
5611 AWidth: Integer);
5612 var
5613 AGtkColumn: PGtkTreeViewColumn;
5614 begin
5615 if not IsWidgetOK or not IsTreeView then
5616 exit;
5617 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5618 if AGtkColumn <> nil then
5619 begin
5620 AGtkColumn^.set_fixed_width(AWidth + Ord(AWidth < 1));
5621 end;
5622 // AGtkColumn^.set_widget();
5623 end;
5624
5625 procedure TGtk3ListView.SetColumnVisible(AIndex: Integer; AColumn: TListColumn;
5626 AVisible: Boolean);
5627 var
5628 AGtkColumn: PGtkTreeViewColumn;
5629 begin
5630 if not IsWidgetOK or not IsTreeView then
5631 exit;
5632 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5633 if AGtkColumn <> nil then
5634 begin
5635 AGtkColumn^.set_visible(AVisible and (TListView(LCLObject).ViewStyle in [vsList, vsReport]));
5636 end;
5637 end;
5638
5639 procedure TGtk3ListView.ColumnSetSortIndicator(const AIndex: Integer;
5640 const AColumn: TListColumn; const ASortIndicator: TSortIndicator);
5641 const
5642 GtkOrder : array [ TSortIndicator] of TGtkSortType = (0, {GTK_SORT_ASCENDING}0, {GTK_SORT_DESCENDING}1);
5643 var
5644 AGtkColumn: PGtkTreeViewColumn;
5645 begin
5646 AGtkColumn := PGtkTreeView(getContainerWidget)^.get_column(AIndex);
5647
5648 if AGtkColumn <> nil then
5649 begin
5650 if ASortIndicator = siNone then
5651 AGtkColumn^.set_sort_indicator(false)
5652 else
5653 begin
5654 AGtkColumn^.set_sort_indicator(true);
5655 AgtkColumn^.set_sort_order(GtkOrder[ASortIndicator]);
5656 end;
5657 end;
5658 end;
5659
5660 procedure TGtk3ListView.ItemDelete(AIndex: Integer);
5661 var
5662 AModel: PGtkTreeModel;
5663 Iter: TGtkTreeIter;
5664 begin
5665 if IsTreeView then
5666 AModel := PGtkTreeView(getContainerWidget)^.get_model
5667 else
5668 AModel := PGtkIconView(getContainerWidget)^.get_model;
5669 if gtk_tree_model_iter_nth_child(AModel, @Iter, nil, AIndex) then
5670 gtk_list_store_remove(PGtkListStore(AModel), @Iter);
5671 end;
5672
5673 procedure TGtk3ListView.ItemInsert(AIndex: Integer; AItem: TListItem);
5674 var
5675 AModel: PGtkTreeModel;
5676 Iter: TGtkTreeIter;
5677 NewIndex: Integer;
5678 begin
5679 if not IsWidgetOK then
5680 exit;
5681 if IsTreeView then
5682 AModel := PGtkTreeView(getContainerWidget)^.get_model
5683 else
5684 AModel := PGtkIconView(getContainerWidget)^.get_model;
5685
5686 if AIndex = -1 then
5687 NewIndex := AModel^.iter_n_children(nil)
5688 else
5689 NewIndex := AIndex;
5690 // AGValue.g_type := G_TYPE_POINTER;
5691 // AGValue.set_pointer(AItem);
5692 gtk_list_store_insert_with_values(PGtkListStore(AModel), @Iter, NewIndex, [0, Pointer(AItem), -1]);
5693 // PGtkListStore(AModel)^.insert_with_valuesv(@Iter, NewIndex, @AColumns, @AGValue, 1);
5694 end;
5695
5696 procedure TGtk3ListView.ItemSetText(AIndex, ASubIndex: Integer;
5697 AItem: TListItem; const AText: String);
5698 var
5699 Path: PGtkTreePath;
5700 ItemRect: TGdkRectangle;
5701 begin
5702 if not IsWidgetOK then
5703 exit;
5704 if not getContainerWidget^.get_realized then
5705 exit;
5706 if IsTreeView then
5707 begin
5708 Path := gtk_tree_path_new_from_indices(AIndex, [-1]);
5709 PGtkTreeView(GetContainerWidget)^.get_cell_area(Path, nil, @ItemRect);
5710 gtk_tree_path_free(Path);
5711 end else
5712 ItemRect.Height := 1;
5713 if GetContainerWidget^.get_visible and (ItemRect.height <> 0) then // item is visible
5714 GetContainerWidget^.queue_draw;
5715 end;
5716
5717 procedure TGtk3ListView.ItemSetState(const AIndex: Integer;
5718 const AItem: TListItem; const AState: TListItemState; const AIsSet: Boolean);
5719 var
5720 Path: PGtkTreePath;
5721 ATreeSelection: PGtkTreeSelection;
5722 begin
5723 if not IsWidgetOK then
5724 exit;
5725
5726 case AState of
5727 lisCut,
5728 lisDropTarget:
5729 begin
5730 //TODO: do something with the rowcolor ?
5731 end;
5732
5733 lisFocused:
5734 begin
5735 Path := gtk_tree_path_new_from_string(PgChar(IntToStr(AIndex)));
5736 if IsTreeView then
5737 begin
5738 if AIsSet then
5739 PGtkTreeView(getContainerWidget)^.set_cursor(Path, nil, False)
5740 else
5741 PGtkTreeView(GetContainerWidget)^.set_cursor(Path, nil, False);
5742 end else
5743 PGtkIconView(GetContainerWidget)^.set_cursor(Path, nil, False);
5744 if Path <> nil then
5745 gtk_tree_path_free(Path);
5746 end;
5747
5748 lisSelected:
5749 begin
5750 Path := gtk_tree_path_new_from_string(PgChar(IntToStr(AIndex)));
5751 if IsTreeView then
5752 begin
5753 ATreeSelection := PGtkTreeView(GetContainerWidget)^.get_selection;
5754 if AIsSet and not ATreeSelection^.path_is_selected(Path) then
5755 begin
5756 ATreeSelection^.select_path(Path);
5757 // BroadcastMsg := True;
5758 end else
5759 if not AIsSet and ATreeSelection^.path_is_selected(Path) then
5760 begin
5761 ATreeSelection^.unselect_path(Path);
5762 // BroadcastMsg := True;
5763 end;
5764 end else
5765 begin
5766 if AIsSet and not PGtkIconView(GetContainerWidget)^.path_is_selected(Path) then
5767 begin
5768 PGtkIconView(GetContainerWidget)^.select_path(Path);
5769 // BroadCastMsg := True;
5770 end else
5771 if not AIsSet and PGtkIconView(GetContainerWidget)^.path_is_selected(Path) then
5772 begin
5773 PGtkIconView(GetContainerWidget)^.unselect_path(Path);
5774 // BroadCastMsg := True;
5775 end;
5776 end;
5777 if Path <> nil then
5778 gtk_tree_path_free(Path);
5779 // if BroadcastMsg then
5780 // BroadCastListSelection(ALV, {%H-}PtrUInt(MainView), AIndex, not AIsSet);
5781 end;
5782 end;
5783
5784 end;
5785
ItemGetStatenull5786 function TGtk3ListView.ItemGetState(const AIndex: Integer;
5787 const AItem: TListItem; const AState: TListItemState; out AIsSet: Boolean
5788 ): Boolean;
5789 var
5790 Path: PGtkTreePath;
5791 Column: PPGtkTreeViewColumn;
5792 Cell: PPGtkCellRenderer;
5793 APath: PGtkTreePath;
5794 AStr: PChar;
5795 begin
5796 Result := False;
5797 AIsSet := False;
5798 if not IsWidgetOK then
5799 exit;
5800 case AState of
5801 lisCut,
5802 lisDropTarget:
5803 begin
5804 //TODO: do something with the rowcolor ?
5805 end;
5806 lisFocused:
5807 begin
5808 Path := nil;
5809 Column := nil;
5810 if IsTreeView then
5811 PGtkTreeView(GetContainerWidget)^.get_cursor(@Path, Column)
5812 else
5813 PGtkIconView(GetContainerWidget)^.get_cursor(@Path, Cell);
5814 if Assigned(Path) then
5815 begin
5816 AStr := gtk_tree_path_to_string(Path);
5817 AIsSet := (StrToIntDef(AStr,-1) = AIndex);
5818 if AStr <> nil then
5819 g_free(AStr);
5820 gtk_tree_path_free(Path);
5821 Result := True;
5822 end;
5823 end;
5824
5825 lisSelected:
5826 begin
5827 APath := gtk_tree_path_new_from_string(PChar(IntToStr(AIndex)));
5828 if IsTreeView then
5829 AIsSet := PGtkTreeView(GetContainerWidget)^.get_selection^.path_is_selected(APath)
5830 else
5831 AIsSet := PGtkIconView(GetContainerWidget)^.path_is_selected(APath);
5832
5833 if APath <> nil then
5834 gtk_tree_path_free(APath);
5835 Result := True;
5836 end;
5837 end;
5838 end;
5839
5840 procedure TGtk3ListView.UpdateImageCellsSize;
5841 begin
5842 // must get renderer via property
5843 // gtk_tree_view_column_get_cell_renderers
5844 end;
5845
5846 { TGtk3ComboBox }
5847
GetItemIndexnull5848 function TGtk3ComboBox.GetItemIndex: Integer;
5849 begin
5850 Result := -1;
5851 if Assigned(FWidget) and Gtk3IsComboBox(GetContainerWidget) then
5852 Result := PGtkComboBox(GetContainerWidget)^.get_active;
5853 end;
5854
5855 procedure TGtk3ComboBox.SetDroppedDown(AValue: boolean);
5856 begin
5857 if Assigned(FWidget) and Gtk3IsComboBox(GetContainerWidget) then
5858 begin
5859 if AValue then
5860 PGtkComboBox(GetContainerWidget)^.popup
5861 else
5862 PGtkComboBox(GetContainerWidget)^.popdown;
5863 end;
5864 end;
5865
5866 procedure TGtk3ComboBox.SetItemIndex(AValue: Integer);
5867 begin
5868 if IsWidgetOK and Gtk3IsComboBox(GetContainerWidget) then
5869 PGtkComboBox(GetContainerWidget)^.set_active(AValue);
5870 end;
5871
TGtk3ComboBox.GetCellViewnull5872 function TGtk3ComboBox.GetCellView: PGtkCellView;
5873 var
5874 AList: PGList;
5875 i: Integer;
5876 begin
5877 if FCellView = nil then
5878 begin
5879 AList := PGtkComboBox(getContainerWidget)^.get_children;
5880 for i := 0 to g_list_length(AList) -1 do
5881 begin
5882 if Gtk3IsCellView(g_list_nth(AList, i)^.data) then
5883 begin
5884 FCellView := PGtkCellView(g_list_first(AList)^.data);
5885 break;
5886 end;
5887 end;
5888 g_list_free(AList);
5889 end;
5890 Result := FCellView;
5891 end;
5892
GetPopupWidgetnull5893 function TGtk3ComboBox.GetPopupWidget: PGtkWidget;
5894 begin
5895 Result := nil;
5896 if not IsWidgetOk then
5897 exit;
5898 if PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget <> nil then
5899 Result := PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget
5900 else
5901 if PGtkComboBox(GetContainerWidget)^.priv3^.tree_view <> nil then
5902 Result := PGtkComboBox(GetContainerWidget)^.priv3^.tree_view;
5903 end;
5904
GetButtonWidgetnull5905 function TGtk3ComboBox.GetButtonWidget: PGtkWidget;
5906 begin
5907 Result := nil;
5908 if not IsWidgetOk then
5909 exit;
5910 if PGtkComboBox(GetContainerWidget)^.priv3^.button <> nil then
5911 Result := PGtkComboBox(GetContainerWidget)^.priv3^.button;
5912 end;
5913
GetCellViewFramenull5914 function TGtk3ComboBox.GetCellViewFrame: PGtkWidget;
5915 begin
5916 Result := nil;
5917 if not IsWidgetOk then
5918 exit;
5919 if PGtkComboBox(GetContainerWidget)^.priv3^.cell_view_frame <> nil then
5920 Result := PGtkComboBox(GetContainerWidget)^.priv3^.cell_view_frame;
5921 end;
5922
CreateWidgetnull5923 function TGtk3ComboBox.CreateWidget(const Params: TCreateParams): PGtkWidget;
5924 var
5925 ACombo: TCustomComboBox;
5926 ListStore: PGtkListStore;
5927 ItemList: TGtkListStoreStringList;
5928 Renderer : PGtkCellRenderer;
5929 begin
5930 FWidgetType := FWidgetType + [wtTreeModel, wtComboBox];
5931 ACombo := TCustomComboBox(LCLObject);
5932 ListStore := gtk_list_store_new (2, [G_TYPE_STRING, G_TYPE_POINTER, nil]);
5933 if ACombo.Style in [csDropDown, csSimple] then
5934 Result := PGtkWidget(TGtkComboBox.new_with_model_and_entry(PGtkTreeModel(ListStore)))
5935 else
5936 Result := PGtkWidget(TGtkComboBox.new_with_model(PGtkTreeModel(ListStore)));
5937
5938 if ACombo.Style in [csDropDown, csSimple] then
5939 begin
5940 ItemList := TGtkListStoreStringList.Create(PGtkListStore(PGtkComboBox(Result)^.get_model), 0, LCLObject);
5941 g_object_set_data(PGObject(Result), GtkListItemLCLListTag, ItemList);
5942
5943 PGtkComboBox(Result)^.set_entry_text_column(0);
5944 if ACombo.Style = csDropDownList then
5945 PGtkEditable(PGtkComboBox(Result)^.get_child)^.set_editable(False);
5946 // do not allow combo button to get focus, entry should take focus
5947 if PGtkComboBox(Result)^.priv3^.button <> nil then
5948 PGtkComboBox(Result)^.priv3^.button^.set_can_focus(False);
5949 // set lclwidget data to entry
5950 g_object_set_data(PGtkComboBox(Result)^.get_child, 'lclwidget', Self);
5951 // when we scroll with mouse wheel over entry our scrollevent doesn't catch entry
5952 // but parent control with window (eg. form), so we are settint all events mask to
5953 // catch all mouse events on gtkentry.
5954 PGtkEntry(PGtkComboBox(Result)^.get_child)^.set_events(GDK_ALL_EVENTS_MASK);
5955 end else
5956 begin
5957 // FCentralWidget := PGtkWidget(TGtkComboBox.new_with_model(PGtkTreeModel(ListStore)));
5958 FCentralWidget := Result;
5959
5960 ItemList := TGtkListStoreStringList.Create(PGtkListStore(PGtkComboBox(FCentralWidget)^.get_model), 0, LCLObject);
5961 g_object_set_data(PGObject(FCentralWidget), GtkListItemLCLListTag, ItemList);
5962
5963 renderer := LCLIntfCellRenderer_New();
5964 g_object_set_data(PGObject(renderer), 'lclwidget', Self);
5965
5966 gtk_cell_layout_clear(PGtkCellLayout(FCentralWidget));
5967 gtk_cell_layout_pack_start(PGtkCellLayout(FCentralWidget), renderer, True);
5968 if not (ACombo.Style in [csOwnerDrawFixed, csOwnerDrawVariable, csOwnerDrawEditableFixed, csOwnerDrawEditableVariable]) then
5969 gtk_cell_layout_set_attributes(PGtkCellLayout(FCentralWidget), renderer, ['text', 0, nil]);
5970 gtk_cell_layout_set_cell_data_func(PGtkCellLayout(FCentralWidget), renderer,
5971 @LCLIntfCellRenderer_CellDataFunc, Self, nil);
5972
5973 FCentralWidget := nil; //FWidget will be returned from getContainerWidget
5974 // we need cell renderer, but we need f***g GtkEventBox too
5975 // maybe an workaround is possible for csDropDownList (use entry with readonly param).
5976 // if we have GtkEventBox, then ComboBox becomes FCentralWidget.
5977 // Maybe the best thing would be to organize complete combo around GtkEntry
5978 // Anyway , I dont see any mouse button event in this case, only when entry_set_above_child is used.
5979 // FCentralWidget := PGtkComboBox(TGtkComboBox.new_with_model(PGtkTreeModel(ListStore)));
5980 // PGtkEventBox(Result)^.add(FCentralWidget);
5981 // ItemList := TGtkListStoreStringList.Create(PGtkListStore(PGtkComboBox(FCentralWidget)^.get_model), 0, LCLObject);
5982 // g_object_set_data(PGObject(FCentralWidget), GtkListItemLCLListTag, ItemList);
5983 // PGtkEventBox(Result)^.set_visible_window(True);
5984 end;
5985 g_object_unref(ListStore);
5986
5987 end;
5988
EatArrowKeysnull5989 function TGtk3ComboBox.EatArrowKeys(const AKey: Word): Boolean;
5990 begin
5991 Result := AKey in [VK_UP, VK_DOWN];
5992 end;
5993
getTextnull5994 function TGtk3ComboBox.getText: String;
5995 begin
5996 Result := inherited getText;
5997 if Gtk3IsComboBox(GetContainerWidget) then
5998 Result := StrPas(PGtkComboBox(GetContainerWidget)^.get_title);
5999 end;
6000
6001 procedure TGtk3ComboBox.setText(AValue: String);
6002 begin
6003 if Gtk3IsComboBox(FWidget) then
6004 PGtkComboBox(GetContainerWidget)^.set_title(PgChar(AValue));
6005 end;
6006
6007 procedure TGtk3ComboBox.DumpPrivateStructValues(ADbgEvent: String);
6008 var
6009 AComboWidget: PGtkComboBox;
6010 APrivate: PGtkComboBoxPrivate;
6011 begin
6012 exit;
6013 AComboWidget := PGtkComboBox(GetContainerWidget);
6014 APrivate := PGtkComboBoxPrivate(AComboWidget^.priv3);
6015 DebugLn('** COMBO DUMP OF PGtkComboBoxPrivate struct EVENT=',ADbgEvent);
6016 DebugLn('BUTTON=',dbgHex(PtrUInt(APrivate^.button)),' ARROW=',dbgHex(PtrUInt(APrivate^.arrow)),
6017 ' SCROLLEDWINDOW=',dbgHex(PtrUInt(APrivate^.scrolled_window)),
6018 ' CELLVIEW=',dbgHex(PtrUInt(APrivate^.cell_view)),
6019 ' CELLAREA=',dbgHex(PtrUInt(APrivate^.area)));
6020 DebugLn(' PrivatePopupW ',dbgHex(PtrUInt(APrivate^.popup_widget)),
6021 ' PrivatePopupWin ',dbgHex(PtrUInt(APrivate^.popup_window)),' TreeView ',dbgHex(PtrUInt(APrivate^.tree_view)));
6022 if Gtk3IsWidget(APrivate^.popup_widget) then
6023 begin
6024 DebugLn('POPUPWIDGET VISIBLE ',dbgs(APrivate^.popup_widget^.get_visible),
6025 ' PopupInProgress=',dbgs(APrivate^.popup_in_progress),' POPUPSHOWN=',
6026 dbgs(APrivate^.popup_shown),' POPUPIDLE_ID=',dbgs(APrivate^.popup_idle_id));
6027 if Gtk3IsMenu(APrivate^.popup_widget) then
6028 DebugLn('POPUPWIDGET IS MENU ')
6029 else
6030 if Gtk3IsMenuItem(APrivate^.popup_widget) then
6031 DebugLn('POPUPWIDGET IS MENUITEM ');
6032 end;
6033 end;
6034
CanFocusnull6035 function TGtk3ComboBox.CanFocus: Boolean;
6036 begin
6037 Result := False;
6038 if IsWidgetOK then
6039 begin
6040 if PGtkComboBox(FWidget)^.has_entry then
6041 Result := PGtkComboBox(FWidget)^.get_child^.can_focus
6042 else
6043 if GetButtonWidget <> nil then
6044 Result := GetButtonWidget^.can_focus;
6045 end;
6046 end;
6047
6048 procedure TGtk3ComboBox.SetFocus;
6049 begin
6050 {$IFDEF GTK3DEBUGFOCUS}
6051 DebugLn('TGtk3ComboBox.SetFocus LCLObject ',dbgsName(LCLObject),' WidgetOK ',dbgs(IsWidgetOK),
6052 ' FWidget <> GetContainerWidget ',dbgs(FWidget <> GetContainerWidget));
6053 {$ENDIF}
6054 if Assigned(LCLObject) then
6055 begin
6056 if IsWidgetOK then // and (FWidget <> GetContainerWidget) then
6057 begin
6058 if PGtkComboBox(FWidget)^.has_entry then
6059 FWidget^.grab_focus
6060 else
6061 if GetButtonWidget <> nil then
6062 GetButtonWidget^.grab_focus;
6063 end else
6064 inherited SetFocus;
6065 end else
6066 inherited SetFocus;
6067 end;
6068
6069 procedure Gtk3ComboBoxChanged(ACombo: PGtkComboBox; AData: gpointer); cdecl;
6070 var
6071 Msg: TLMessage;
6072 begin
6073 if AData <> nil then
6074 begin
6075 if TGtk3Widget(AData).InUpdate then
6076 Exit;
6077 FillChar(Msg, SizeOf(Msg), #0);
6078 Msg.Msg := LM_CHANGED;
6079 TGtk3Widget(AData).DeliverMessage(Msg);
6080 end;
6081 end;
6082
6083 function GtkPopupCloseUp(AData: Pointer): gboolean; cdecl;
6084 var
6085 ComboBox: TCustomComboBox;
6086 begin
6087 ComboBox := TCustomComboBox(TGtk3Widget(AData).LCLObject);
6088 LCLSendCloseUpMsg(TGtk3Widget(AData).LCLObject);
6089 Result := False;// stop the timer
6090 end;
6091
6092 procedure GtkNotifyCombo(AObject: PGObject; pspec: PGParamSpec; AData: GPointer); cdecl;
6093 var
6094 AValue: TGValue;
6095 ComboBox: TCustomComboBox;
6096 begin
6097 if pspec^.name = 'popup-shown' then
6098 begin
6099 ComboBox := TCustomComboBox(TGtk3Widget(AData).LCLObject);
6100 AValue.g_type := G_TYPE_BOOLEAN;
6101 g_object_get_property(AObject, pspec^.name, @AValue); // get property value
6102 if AValue.data[0].v_int = 0 then // if 0 = False then it is close up
6103 g_timeout_add(0,@GtkPopupCloseUp, AData)
6104 else // in other case it is drop down
6105 begin
6106 ComboBox.IntfGetItems;
6107 LCLSendDropDownMsg(ComboBox);
6108 end;
6109 end;
6110 end;
6111
6112 procedure Gtk3ComboMenuRealized(AWidget: PGtkWidget; AData: gPointer); cdecl;
6113 begin
6114 DebugLn('Gtk3ComboMenuRealized *****',dbgsName(TGtk3ComboBox(AData).LCLObject));
6115 end;
6116
6117 procedure TGtk3ComboBox.InitializeWidget;
6118 begin
6119 inherited InitializeWidget;
6120 // appears-as-list make it appear as list ... no way, its read only property.
6121 //OnChange
6122 g_signal_connect_data(GetContainerWidget, 'changed', TGCallback(@Gtk3ComboBoxChanged), Self, nil, 0);
6123 //OnCloseUp
6124 g_signal_connect_data(GetContainerWidget, 'notify', TGCallback(@GtkNotifyCombo), Self, nil, 0);
6125
6126 //TODO: if we have an entry then use CreateFrom() to create TGtk3Entry
6127 if Gtk3IsEntry(PGtkComboBox(FWidget)^.get_child) then
6128 begin
6129 g_object_set_data(PGtkComboBox(FWidget)^.get_child, 'lclwidget', Self);
6130 g_signal_connect_data(PGtkComboBox(FWidget)^.get_child, 'event', TGCallback(@Gtk3WidgetEvent), Self, nil, 0);
6131 end;
6132 if GetCellView <> nil then
6133 begin
6134 gtk_widget_set_events(FCellView, GDK_ALL_EVENTS_MASK);
6135 g_object_set_data(FCellView, 'lclwidget', Self);
6136 g_signal_connect_data(FCellView, 'event', TGCallback(@Gtk3WidgetEvent), Self, nil, 0);
6137 end;
6138 // set to all combo widgets lclwidget data, so we will easy find TGtk3ComboBox in events.
6139 if PGtkComboBox(GetContainerWidget)^.priv3^.button <> nil then
6140 begin
6141 g_object_set_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.button), 'lclwidget', Self);
6142 g_signal_connect_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.button), 'event', TGCallback(@Gtk3WidgetEvent), Self, nil, 0);
6143 end;
6144 if PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget <> nil then
6145 begin
6146 g_object_set_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget), 'lclwidget', Self);
6147 g_signal_connect_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget), 'event', TGCallback(@Gtk3WidgetEvent), Self, nil, 0);
6148 PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget^.set_has_window(True);
6149 PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget^.set_can_focus(True);
6150 // g_signal_connect_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.popup_widget), 'map', TGCallback(@Gtk3ComboMenuRealized), Self, nil, 0);
6151 end;
6152 if PGtkComboBox(GetContainerWidget)^.priv3^.area <> nil then
6153 g_object_set_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.area), 'lclwidget', Self);
6154 // if combo doesnt use menu
6155 if PGtkComboBox(GetContainerWidget)^.priv3^.tree_view <> nil then
6156 g_object_set_data(PGObject(PGtkComboBox(GetContainerWidget)^.priv3^.tree_view), 'lclwidget', Self);
6157 end;
6158
GetDroppedDownnull6159 function TGtk3ComboBox.GetDroppedDown: boolean;
6160 var
6161 AValue: TGValue;
6162 begin
6163 Result := False;
6164 if Assigned(FWidget) and Gtk3IsComboBox(GetContainerWidget) then
6165 begin
6166 AValue.g_type := G_TYPE_BOOLEAN;
6167 g_object_get_property(PGObject(GetContainerWidget), 'popup-shown', @AValue);
6168 Result := AValue.data[0].v_int <> 0;
6169 end;
6170 end;
6171
6172 { TGtk3Button }
6173
getLayoutnull6174 function TGtk3Button.getLayout: Integer;
6175 begin
6176 Result := FLayout;
6177 // PGtkButton(FWidget)^.get_image_position;
6178 end;
6179
getMarginnull6180 function TGtk3Button.getMargin: Integer;
6181 begin
6182 Result := FMargin;
6183 end;
6184
6185 procedure TGtk3Button.SetLayout(AValue: Integer);
6186 begin
6187 FLayout := AValue;
6188 if IsWidgetOk then
6189 begin
6190 PGtkButton(FWidget)^.set_image_position(AValue);
6191 // set margin and spacing when layout is changed
6192 SetMargin(FMargin);
6193 end;
6194 end;
6195
6196 procedure TGtk3Button.SetMargin(AValue: Integer);
6197 begin
6198 FMargin := AValue;
6199 if not IsWidgetOK then
6200 exit;
6201 if FMargin = -1 then
6202 PGtkButton(FWidget)^.set_alignment(0.5, 0.5)
6203 else
6204 begin
6205 case FLayout of
6206 0 {GTK_POS_LEFT}: PGtkButton(FWidget)^.set_alignment(0, 0.5);
6207 1 {GTK_POS_RIGHT}: PGtkButton(FWidget)^.set_alignment(1.0, 0.5);
6208 2 {GTK_POS_TOP}: PGtkButton(FWidget)^.set_alignment(0.5, 0);
6209 3 {GTK_POS_BOTTOM}: PGtkButton(FWidget)^.set_alignment(0.5, 1);
6210 end;
6211 end;
6212 end;
6213
6214 procedure TGtk3Button.SetSpacing(AValue: Integer);
6215 var
6216 ATGValue: TGValue;
6217 AImage: PGtkWidget;
6218 begin
6219 // if FSpacing=AValue then Exit;
6220 FSpacing:=AValue;
6221 if AValue < 0 then
6222 FSpacing := 2;
6223 ATGValue.g_type := G_TYPE_INT;
6224 ATGValue.set_int(AValue);
6225
6226 // no way under gtk3 ... we cannot set style property image-spacing
6227 // so we are using cheat
6228 AImage := PGtkButton(FWidget)^.get_image;
6229 if AImage <> nil then
6230 begin
6231 if AValue < 0 then
6232 AVAlue := 0;
6233 //TODO: margin depends on layout ! This is ok for left (default) layout
6234 PGtkImage(AImage)^.set_margin_right(AValue);
6235 end;
6236 end;
6237
getTextnull6238 function TGtk3Button.getText: String;
6239 begin
6240 if IsWidgetOK then
6241 Result := PGtkButton(FWidget)^.get_label
6242 else
6243 Result := '';
6244 end;
6245
6246 procedure TGtk3Button.setText(AValue: String);
6247 begin
6248 if IsWidgetOk then
6249 PGtkButton(FWidget)^.set_label(PgChar(AValue));
6250 end;
6251
CreateWidgetnull6252 function TGtk3Button.CreateWidget(const Params: TCreateParams): PGtkWidget;
6253 begin
6254 Result := PGtkWidget(TGtkButton.new);
6255 FMargin := -1;
6256 FLayout := GTK_POS_LEFT;
6257 FSpacing := 2; // default gtk3 spacing is 2
6258 end;
6259
IsWidgetOknull6260 function TGtk3Button.IsWidgetOk: Boolean;
6261 begin
6262 Result := (FWidget <> nil) and Gtk3IsButton(FWidget);
6263 end;
6264
6265 procedure TGtk3Button.SetDefault(const ADefault: Boolean);
6266 begin
6267 if IsWidgetOk then
6268 GetContainerWidget^.set_can_default(ADefault);
6269 end;
6270
6271 { TGtk3ToggleButton }
6272 procedure Gtk3Toggled(AWidget: PGtkToggleButton; AData: gPointer); cdecl;
6273 var
6274 Msg: TLMessage;
6275 begin
6276 FillChar(Msg, SizeOf(Msg), 0);
6277 Msg.Msg := LM_CHANGED;
6278 if (TGtk3Widget(AData).LCLObject <> nil) and not TGtk3Widget(AData).InUpdate then
6279 TGtk3Widget(AData).DeliverMessage(Msg, False);
6280 end;
6281
6282 procedure TGtk3ToggleButton.InitializeWidget;
6283 begin
6284 inherited InitializeWidget;
6285 g_signal_connect_data(FWidget, 'toggled', TGCallback(@Gtk3Toggled), Self, nil, 0);
6286 end;
6287
CreateWidgetnull6288 function TGtk3ToggleButton.CreateWidget(const Params: TCreateParams
6289 ): PGtkWidget;
6290 begin
6291 Result := PGtkWidget(TGtkToggleButton.new);
6292 end;
6293
6294 { TGtk3CheckBox }
6295
GetStatenull6296 function TGtk3CheckBox.GetState: TCheckBoxState;
6297 begin
6298 Result := cbUnchecked;
6299 if IsWidgetOk then
6300 begin
6301 if PGtkCheckButton(FWidget)^.get_inconsistent then
6302 Result := cbGrayed
6303 else
6304 if PGtkCheckButton(FWidget)^.get_active then
6305 Result := cbChecked;
6306 end;
6307 end;
6308
6309 procedure TGtk3CheckBox.SetState(AValue: TCheckBoxState);
6310 begin
6311 if IsWidgetOK then
6312 begin
6313 if AValue = cbGrayed then
6314 PGtkCheckButton(FWidget)^.set_inconsistent(True)
6315 else
6316 PGtkCheckButton(FWidget)^.set_active(AValue = cbChecked);
6317 end;
6318 end;
6319
CreateWidgetnull6320 function TGtk3CheckBox.CreateWidget(const Params: TCreateParams): PGtkWidget;
6321 begin
6322 Result := PGtkWidget(TGtkCheckButton.new);
6323 end;
6324
6325 { TGtk3RadioButton }
6326
CreateWidgetnull6327 function TGtk3RadioButton.CreateWidget(const Params: TCreateParams): PGtkWidget;
6328 var
6329 w: PGtkWidget;
6330 ctl, Parent: TWinControl;
6331 rb: TRadioButton;
6332 pl: PGsList;
6333 begin
6334 if Self.LCLObject.Name='HiddenRadioButton' then
6335 exit;
6336 Result := PGtkWidget(TGtkRadioButton.new(nil));
6337 ctl := Self.LCLObject;
6338 if Assigned(ctl) then
6339 begin
6340 Parent := ctl.Parent;
6341 if (Parent is TRadioGroup) and (TRadioGroup(Parent).Items.Count>0) then
6342 begin
6343 rb := TRadioButton(Parent.Controls[0]);
6344 if rb<>ctl then
6345 begin
6346 w := TGtk3RadioButton(rb.Handle).Widget;
6347 pl := PGtkRadioButton(w)^.get_group;
6348 PGtkRadioButton(Result)^.set_group(pl);
6349 end;
6350 end;
6351 end;
6352 end;
6353
6354 procedure TGtk3RadioButton.InitializeWidget;
6355 begin
6356 if Self.LCLObject.Name='HiddenRadioButton' then
6357 begin
6358 exit;
6359 { PGtkRadioButton(Self.Widget)^.set_group(nil);
6360 // PGtkRadioButton(Self.Widget)^.set_inconsistent(true);
6361 PGtkRadioButton(Self.Widget)^.set_visible(false);}
6362 end;
6363 inherited InitializeWidget;
6364 end;
6365
6366 { TGtk3CustomControl }
6367
CreateWidgetnull6368 function TGtk3CustomControl.CreateWidget(const Params: TCreateParams
6369 ): PGtkWidget;
6370 var
6371 FUseLayout: Boolean;
6372 begin
6373 FScrollX := 0;
6374 FScrollY := 0;
6375 FHasPaint := True;
6376 FUseLayout := False;
6377 if FUseLayout then
6378 FWidgetType := [wtWidget, wtLayout, wtScrollingWin, wtCustomControl]
6379 else
6380 FWidgetType := [wtWidget, wtContainer, wtTabControl, wtScrollingWin, wtCustomControl];
6381 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
6382
6383 if FUseLayout then
6384 FCentralWidget := TGtkLayout.new(nil, nil)
6385 else
6386 FCentralWidget := TGtkFixed.new;
6387
6388 FCentralWidget^.set_has_window(True);
6389
6390 // this is deprecated since 3.8 .add() should be used
6391 // in this case viewport should be blocked somehow.....
6392 //if FUseLayout or (gtk_get_major_version > 3 or gtk_get_minor_version >=8 )then
6393 // PGtkScrolledWindow(Result)^.add(FCentralWidget)
6394 //else
6395 // PGtkScrolledWindow(Result)^.add_with_viewport(FCentralWidget);
6396
6397 // gtk_container_add() will now automatically add a GtkViewport if the child doesn't implement GtkScrollable.
6398
6399 PGtkScrolledWindow(Result)^.add(FCentralWidget);
6400
6401 // PGtkViewport(PGtkScrolledWindow(Result)^.get_child)^.;
6402 // also works fine with 3.6 but raises asserts
6403 // PGtkScrolledWindow(Result)^.add(FCentralWidget);
6404 Result^.set_can_focus(False);
6405 FCentralWidget^.set_can_focus(True);
6406 end;
6407
EatArrowKeysnull6408 function TGtk3CustomControl.EatArrowKeys(const AKey: Word): Boolean;
6409 begin
6410 Result := False;
6411 end;
6412
6413 procedure TGtk3CustomControl.InitializeWidget;
6414 begin
6415 inherited InitializeWidget;
6416 SetScrollBarsSignalHandlers;
6417 g_signal_connect_data(GetScrolledWindow,'scroll-event', TGCallback(@Gtk3ScrolledWindowScrollEvent), Self, nil, 0);
6418 end;
6419
getClientRectnull6420 function TGtk3CustomControl.getClientRect: TRect;
6421 var
6422 Allocation: TGtkAllocation;
6423 R: TRect;
6424 w: gint;
6425 h: gint;
6426 x: gint;
6427 y: gint;
6428 AViewPort: PGtkViewport;
6429 begin
6430 // Result := inherited getClientRect;
6431 AViewPort := PGtkViewPort(FCentralWidget^.get_parent);
6432 if Gtk3IsViewPort(AViewPort) and Gtk3IsGdkWindow(AViewPort^.get_view_window) then
6433 begin
6434 AViewPort^.get_view_window^.get_geometry(@x, @y, @w, @h);
6435 Result := Rect(0, 0, AViewPort^.get_view_window^.get_width, AViewPort^.get_view_window^.get_height);
6436 // DebugLn('TGtk3CustomControl.GetClientRect via Viewport ',dbgsName(LCLObject),' Result ',dbgs(Result),' X=',dbgs(X),' Y=',dbgs(Y));
6437 exit;
6438 end else
6439 FCentralWidget^.get_allocation(@Allocation);
6440
6441 with Allocation do
6442 R := Rect(x, y, width + x, height + y);
6443
6444 if IsRectEmpty(R) then
6445 R := Rect(0, 0, 0, 0);
6446
6447 Result := R;
6448 // DebugLn('TGtk3CustomControl.GetClientRect normal ',dbgsName(LCLObject),' Result ',dbgs(Result));
6449 OffsetRect(Result, -Result.Left, -Result.Top);
6450 end;
6451
getHorizontalScrollbarnull6452 function TGtk3CustomControl.getHorizontalScrollbar: PGtkScrollbar;
6453 begin
6454 Result := nil;
6455 if not IsWidgetOk then
6456 exit;
6457 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_hscrollbar);
6458 g_object_set_data(Result,'lclwidget',Self);
6459 end;
6460
getVerticalScrollbarnull6461 function TGtk3CustomControl.getVerticalScrollbar: PGtkScrollbar;
6462 begin
6463 Result := nil;
6464 if not IsWidgetOk then
6465 exit;
6466 Result := PGtkScrollBar(PGtkScrolledWindow(Widget)^.get_vscrollbar);
6467 g_object_set_data(Result,'lclwidget',Self);
6468 end;
6469
TGtk3CustomControl.GetScrolledWindownull6470 function TGtk3CustomControl.GetScrolledWindow: PGtkScrolledWindow;
6471 begin
6472 if IsWidgetOK then
6473 Result := PGtkScrolledWindow(Widget)
6474 else
6475 Result := nil;
6476 end;
6477
6478 { TGtk3ScrollingWinControl }
6479
CreateWidgetnull6480 function TGtk3ScrollingWinControl.CreateWidget(const Params: TCreateParams
6481 ): PGtkWidget;
6482 begin
6483 FHasPaint := True;
6484 FScrollX := 0;
6485 FScrollY := 0;
6486 // layout is crap under gtk3
6487 (*
6488 FWidgetType := [wtWidget, wtLayout, wtScrollingWin];
6489 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
6490 FCentralWidget := TGtkLayout.new(nil, nil);
6491 FCentralWidget^.set_has_window(True);
6492 FCentralWidget^.show;
6493
6494 PGtkScrolledWindow(Result)^.add(FCentralWidget);
6495 *)
6496 FWidgetType := [wtWidget, wtContainer, wtScrollingWin, wtScrollingWinControl];
6497 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
6498 FCentralWidget := TGtkFixed.new;
6499 FCentralWidget^.set_has_window(True);
6500 FCentralWidget^.show;
6501
6502 PGtkScrolledWindow(Result)^.add_with_viewport(FCentralWidget);
6503 // PGtkScrolledWindow(Result)^.add(FCentralWidget);
6504
6505 PGtkViewport(PGtkScrolledWindow(Result)^.get_child)^.set_shadow_type(BorderStyleShadowMap[bsNone]);
6506 PGtkScrolledWindow(Result)^.set_shadow_type(BorderStyleShadowMap[TScrollingWinControl(LCLObject).BorderStyle]);
6507 PGtkScrolledWindow(Result)^.get_vscrollbar^.set_can_focus(False);
6508 PGtkScrolledWindow(Result)^.get_hscrollbar^.set_can_focus(False);
6509 PGtkScrolledWindow(Result)^.set_policy(GTK_POLICY_NEVER, GTK_POLICY_NEVER);
6510
6511 // this is very important
6512 PGtkScrolledWindow(Result)^.set_can_focus(False);
6513 FCentralWidget^.set_can_focus(True);
6514 end;
6515
6516 { TGtk3Window }
6517
TGtk3Window.GetTitlenull6518 function TGtk3Window.GetTitle: String;
6519 begin
6520 Result:=PGtkWindow(FWidget)^.get_title();
6521 end;
6522
6523 procedure TGtk3Window.SetIcon(AValue: PGdkPixBuf);
6524 begin
6525 // if FIcon=AValue then Exit;
6526 if Assigned(FIcon) then
6527 begin
6528 FIcon^.unref;
6529 FIcon := nil;
6530 end;
6531 if Gtk3IsGdkPixbuf(AValue) then
6532 FIcon := PGdkPixbuf(AValue)^.copy
6533 else
6534 FIcon := nil;
6535 // DebugLn('Setting icon ',dbgHex(PtrUInt(FIcon)),' AppIcon ',dbgHex(PtrUInt(GTK3WidgetSet.AppIcon)));
6536 PGtkWindow(Widget)^.set_icon(FIcon);
6537 end;
6538
GetSkipTaskBarHintnull6539 function TGtk3Window.GetSkipTaskBarHint: Boolean;
6540 begin
6541 Result := False;
6542 if IsWidgetOK then
6543 Result := PGtkWindow(Widget)^.get_skip_taskbar_hint;
6544 end;
6545
6546 procedure TGtk3Window.SetSkipTaskBarHint(AValue: Boolean);
6547 begin
6548 if IsWidgetOK then
6549 PGtkWindow(Widget)^.set_skip_taskbar_hint(AValue);
6550 end;
6551
6552 procedure TGtk3Window.SetTitle(AValue: String);
6553 begin
6554 PGtkWindow(FWidget)^.set_title(PGChar(AValue));
6555 end;
6556
Gtk3WindowStatenull6557 function Gtk3WindowState(AWidget: PGtkWidget; AEvent: PGdkEvent; AData: gPointer): GBoolean; cdecl;
6558 var
6559 Msg: TLMSize;
6560 AState: TGdkWindowState;
6561 AScreen: PGdkScreen;
6562 ActiveWindow: PGdkWindow;
6563 begin
6564 Result := False;
6565 FillChar(Msg, SizeOf(Msg), #0);
6566
6567 AScreen := AWidget^.window^.get_screen;
6568 ActiveWindow := AScreen^.get_active_window;
6569 (*
6570 if ActiveWindow <> AWidget^.window then
6571 TGtk3Window(AData).Gtk3ActivateWindow(nil)
6572 else
6573 TGtk3Window(AData).Gtk3ActivateWindow(AEvent);
6574 *)
6575 // window state isn't changed on activate/deactivate, so must provide another solution
6576 // DebugLn('Gtk3WindowState ',dbgsName(TGtk3Widget(AData).LCLObject),' changedmask=',dbgs(AEvent^.window_state.changed_mask),
6577 // ' newstate ',dbgs(AEvent^.window_state.new_window_state),' currentState ', dbgs(TGtk3Window(AData).GetWindowState),
6578 // ' WITHDRAWN ? ',dbgs(TGtk3Window(AData).getWindowState and GDK_WINDOW_STATE_WITHDRAWN));
6579
6580 Msg.Msg := LM_SIZE;
6581 Msg.SizeType := SIZE_RESTORED;
6582
6583 AState := AEvent^.window_state.new_window_state AND NOT GDK_WINDOW_STATE_FOCUSED;
6584
6585 if AState = 0 then
6586 begin
6587 if (AEvent^.window_state.changed_mask = GDK_WINDOW_STATE_ICONIFIED) or
6588 (AEvent^.window_state.changed_mask = GDK_WINDOW_STATE_MAXIMIZED) or
6589 (AEvent^.window_state.changed_mask = GDK_WINDOW_STATE_FULLSCREEN) then
6590 // restore win
6591 else
6592 exit;
6593 end;
6594 // PGtkWindow(nil)^.window^.get_state;
6595 if AState and GDK_WINDOW_STATE_ICONIFIED <> 0 then
6596 Msg.SizeType := SIZE_MINIMIZED
6597 else
6598 if AState and GDK_WINDOW_STATE_FULLSCREEN <> 0 then
6599 Msg.SizeType := SIZE_FULLSCREEN
6600 else
6601 if AState and GDK_WINDOW_STATE_MAXIMIZED <> 0 then
6602 Msg.SizeType := SIZE_MAXIMIZED;
6603
6604 Msg.SizeType := Msg.SizeType or Size_SourceIsInterface;
6605
6606 Msg.Width := Word(AWidget^.window^.get_width);
6607 Msg.Height := Word(AWidget^.window^.get_height);
6608 // DebugLn('GetWindowState SizeType=',dbgs(Msg.SizeType),' realized ',dbgs(AWidget^.get_realized));
6609 TGtk3Window(AData).DeliverMessage(Msg);
6610 // DeliverMessage(Msg);
6611 end;
6612
CreateWidgetnull6613 function TGtk3Window.CreateWidget(const Params: TCreateParams): PGtkWidget;
6614 var
6615 AForm: TCustomForm;
6616 begin
6617 FIcon := nil;
6618 FScrollX := 0;
6619 FScrollY := 0;
6620
6621 FHasPaint := True;
6622 AForm := TCustomForm(LCLObject);
6623
6624 if not Assigned(LCLObject.Parent) then
6625 begin
6626 Result := TGtkWindow.new(GTK_WINDOW_TOPLEVEL);
6627 FWidgetType := [wtWidget, wtLayout, wtScrollingWin, wtWindow];
6628 end else
6629 begin
6630 Result := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
6631 FWidgetType := [wtWidget, wtLayout, wtScrollingWin, wtCustomControl]
6632 end;
6633
6634 FBox := TGtkVBox.new(GTK_ORIENTATION_VERTICAL, 0);
6635
6636 //TODO: when menu is added dynamically to the form create FMenuBar
6637 if (AForm.Menu <> nil) then
6638 begin
6639 FMenuBar := TGtkMenuBar.new; // our menubar (needed for main menu)
6640 // MenuBar
6641 // -> Menu Menu2
6642 // Item 1 Item 3
6643 // Item 2
6644 g_object_set_data(Result,'lclmenubar',GPointer(1));
6645 FBox^.pack_start(FMenuBar, False, False, 0);
6646 end;
6647
6648 FScrollWin := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
6649 g_object_set_data(FScrollWin,'lclscrollingwindow',GPointer(1));
6650 g_object_set_data(PGObject(FScrollWin), 'lclwidget', Self);
6651
6652
6653 FCentralWidget := TGtkLayout.new(nil, nil);
6654 FCentralWidget^.set_has_window(True);
6655
6656 if AForm.AutoScroll then
6657 FScrollWin^.add(FCentralWidget)
6658 else
6659 FScrollWin^.add_with_viewport(FCentralWidget);
6660
6661 FScrollWin^.show;
6662 FBox^.pack_end(FScrollWin, True, True, 0);
6663 FBox^.show;
6664
6665 FScrollWin^.get_vscrollbar^.set_can_focus(False);
6666 FScrollWin^.get_hscrollbar^.set_can_focus(False);
6667 FScrollWin^.set_policy(GTK_POLICY_NEVER, GTK_POLICY_NEVER);
6668 PGtkContainer(Result)^.add(FBox);
6669 g_signal_connect_data(Result,'window-state-event', TGCallback(@Gtk3WindowState), Self, nil, 0);
6670
6671 //REMOVE THIS, USED TO TRACK MOUSE MOVE OVER WIDGET TO SEE SIZE OF FIXED !
6672 //g_object_set_data(PGObject(FScrollWin), 'lcldebugscrollwin', Self);
6673 //g_object_set_data(PGObject(FCentralWidget), 'lcldebugfixed', Self);
6674 //g_object_set_data(PGObject(Result), 'lcldebugwindow', Self);
6675 end;
6676
EatArrowKeysnull6677 function TGtk3Window.EatArrowKeys(const AKey: Word): Boolean;
6678 begin
6679 Result := False;
6680 end;
6681
getTextnull6682 function TGtk3Window.getText: String;
6683 begin
6684 Result := Title;
6685 end;
6686
6687 procedure TGtk3Window.setText(AValue: String);
6688 begin
6689 Title := AValue;
6690 end;
6691
getClientRectnull6692 function TGtk3Window.getClientRect: TRect;
6693 var
6694 Allocation: TGtkAllocation;
6695 R: TRect;
6696 w: gint;
6697 h: gint;
6698 x: gint;
6699 y: gint;
6700 AViewPort: PGtkViewport;
6701 begin
6702 AViewPort := PGtkViewPort(FCentralWidget^.get_parent);
6703 if Gtk3IsViewPort(AViewPort) and Gtk3IsGdkWindow(AViewPort^.get_view_window) then
6704 begin
6705 AViewPort^.get_view_window^.get_geometry(@x, @y, @w, @h);
6706 Result := Rect(0, 0, AViewPort^.get_view_window^.get_width, AViewPort^.get_view_window^.get_height);
6707 // DebugLn('GetClientRect via Viewport ',dbgsName(LCLObject),' Result ',dbgs(Result));
6708 exit;
6709 end else
6710 FCentralWidget^.get_allocation(@Allocation);
6711
6712 with Allocation do
6713 R := Rect(x, y, width + x, height + y);
6714
6715 if IsRectEmpty(R) then
6716 R := Rect(0, 0, 0, 0);
6717
6718 Result := R;
6719 OffsetRect(Result, -Result.Left, -Result.Top);
6720
6721 // DebugLn('GetClientRect ',dbgsName(LCLObject),' Result ',dbgs(Result));
6722 end;
6723
getHorizontalScrollbarnull6724 function TGtk3Window.getHorizontalScrollbar: PGtkScrollbar;
6725 begin
6726 Result := nil;
6727 if not IsWidgetOk then
6728 exit;
6729 Result := PGtkScrollBar(FScrollWin^.get_hscrollbar);
6730 end;
6731
getVerticalScrollbarnull6732 function TGtk3Window.getVerticalScrollbar: PGtkScrollbar;
6733 begin
6734 Result := nil;
6735 if not IsWidgetOk then
6736 exit;
6737 Result := PGtkScrollBar(FScrollWin^.get_vscrollbar);
6738 end;
6739
GetScrolledWindownull6740 function TGtk3Window.GetScrolledWindow: PGtkScrolledWindow;
6741 begin
6742 if IsWidgetOK then
6743 Result := FScrollWin
6744 else
6745 Result := nil;
6746 end;
6747
6748 destructor TGtk3Window.Destroy;
6749 begin
6750 // DebugLn('TGtk3Window.Destroy AWidget ',dbgs(IsWidgetOK));
6751 if Gtk3IsGdkPixbuf(FIcon) then
6752 begin
6753 FIcon^.unref;
6754 FIcon := nil;
6755 end;
6756 inherited Destroy;
6757 end;
6758
6759 procedure TGtk3Window.Activate;
6760 begin
6761 if IsWidgetOk then
6762 begin
6763 if Gtk3IsGdkWindow(PGtkWindow(FWidget)^.window) then
6764 begin
6765 PGtkWindow(FWidget)^.window^.raise_;
6766 PGtkWindow(FWidget)^.present;
6767 PGtkWindow(FWidget)^.activate;
6768 end;
6769 end;
6770 end;
6771
6772 procedure TGtk3Window.Gtk3ActivateWindow(AEvent: PGdkEvent);
6773 var
6774 MsgActivate: TLMActivate;
6775 FIsActivated: Boolean;
6776 begin
6777 //gtk3 does not handle activate/deactivate at all
6778 //even cannot catch it via GDK_FOCUS event ?!?
6779 FillChar(MsgActivate, SizeOf(MsgActivate), #0);
6780 MsgActivate.Msg := LM_ACTIVATE;
6781
6782 if (AEvent <> nil) and PGtkWindow(Widget)^.is_active then
6783 MsgActivate.Active := WA_ACTIVE
6784 else
6785 MsgActivate.Active := WA_INACTIVE;
6786 MsgActivate.ActiveWindow := HWND(Self);
6787
6788 // DebugLn('TGtk3Window.Gtk3ActivateWindow ',dbgsName(LCLObject),' Active ',dbgs(PGtkWindow(Widget)^.is_active),
6789 // ' CustomFormActive ',dbgs(TCustomForm(LCLObject).Active));
6790 FIsActivated := TCustomForm(LCLObject).Active;
6791 {do not send activate if form is already activated,
6792 also do not send activate if TCustomForm.Parent is assigned
6793 since it's form embedded into another control or form}
6794 if (Boolean(MsgActivate.Active) = FIsActivated) or (LCLObject.Parent <> nil) then
6795 else
6796 begin
6797 // DebugLn('TGtk3Window.Gtk3ActivateWindow Active ',dbgs(MsgActivate.Active = WA_ACTIVE),
6798 // ' Message delivery to lcl ',dbgs(MsgActivate.Active));
6799 DeliverMessage(MsgActivate);
6800 end;
6801 end;
6802
Gtk3CloseQuerynull6803 function TGtk3Window.Gtk3CloseQuery: Boolean;
6804 var
6805 Msg : TLMessage;
6806 begin
6807 {$IFDEF GTK3DEBUGCORE}
6808 DebugLn('TGtk3Window.Gtk3CloseQuery');
6809 {$ENDIF}
6810 FillChar(Msg, SizeOf(Msg), 0);
6811
6812 Msg.Msg := LM_CLOSEQUERY;
6813
6814 DeliverMessage(Msg);
6815
6816 Result := False;
6817 end;
6818
TGtk3Window.GetWindownull6819 function TGtk3Window.GetWindow: PGdkWindow;
6820 begin
6821 Result := FWidget^.window;
6822 end;
6823
TGtk3Window.GetMenuBarnull6824 function TGtk3Window.GetMenuBar: PGtkMenuBar;
6825 begin
6826 Result := FMenuBar;
6827 end;
6828
GetBoxnull6829 function TGtk3Window.GetBox: PGtkBox;
6830 begin
6831 Result := FBox;
6832 end;
6833
GetWindowStatenull6834 function TGtk3Window.GetWindowState: TGdkWindowState;
6835 begin
6836 Result := 0;
6837 if IsWidgetOK and (FWidget^.get_realized) then
6838 Result := FWidget^.window^.get_state;
6839 end;
6840
6841 { TGtk3HintWindow }
6842
getTextnull6843 function TGtk3HintWindow.getText: String;
6844 begin
6845 Result := FText;
6846 end;
6847
6848 procedure TGtk3HintWindow.setText(AValue: String);
6849 begin
6850 FText := AValue;
6851 end;
6852
TGtk3HintWindow.CreateWidgetnull6853 function TGtk3HintWindow.CreateWidget(const Params: TCreateParams): PGtkWidget;
6854 var
6855 AForm: THintWindow;
6856 begin
6857 FText := '';
6858 FHasPaint := True;
6859 AForm := THintWindow(LCLObject);
6860
6861 FWidgetType := [wtWidget, wtContainer, wtScrollingWin, wtWindow, wtHintWindow];
6862
6863 Result := TGtkWindow.new(GTK_WINDOW_POPUP);
6864
6865 FBox := TGtkVBox.new(GTK_ORIENTATION_VERTICAL, 0);
6866
6867 if (AForm.Menu <> nil) then
6868 begin
6869 FMenuBar := TGtkMenuBar.new; // our menubar (needed for main menu)
6870 // MenuBar
6871 // -> Menu Menu2
6872 // Item 1 Item 3
6873 // Item 2
6874 g_object_set_data(Result,'lclmenubar',GPointer(1));
6875 FBox^.pack_start(FMenuBar, False, False, 0);
6876 end;
6877
6878 FScrollWin := PGtkScrolledWindow(TGtkScrolledWindow.new(nil, nil));
6879 g_object_set_data(FScrollWin,'lclscrollingwindow',GPointer(1));
6880 g_object_set_data(PGObject(FScrollWin), 'lclwidget', Self);
6881
6882
6883 //FCentralWidget := TGtkLayout.new(nil, nil);
6884 FCentralWidget := TGtkFixed.new;
6885 FCentralWidget^.set_has_window(True);
6886 FCentralWidget^.show;
6887
6888 FScrollWin^.add_with_viewport(FCentralWidget);
6889 // FScrollWin^.add(FCentralWidget);
6890 FScrollWin^.show;
6891 FBox^.pack_end(FScrollWin, True, True, 0);
6892 FBox^.show;
6893
6894 FScrollWin^.get_vscrollbar^.set_can_focus(False);
6895 FScrollWin^.get_hscrollbar^.set_can_focus(False);
6896 FScrollWin^.set_policy(GTK_POLICY_NEVER, GTK_POLICY_NEVER);
6897 PGtkContainer(Result)^.add(FBox);
6898 // FWidgetType := FWidgetType + [wtContainer, wtWindow];
6899 // Result := TGtkWindow.new(GTK_WINDOW_POPUP);
6900 // FCentralWidget := TGtkFixed.new;
6901 // PGtkWindow(Result)^.add(FCentralWidget);
6902 end;
6903
6904 { TGtk3Dialog }
6905
TGtk3Dialog.CreateWidgetnull6906 function TGtk3Dialog.CreateWidget(const Params: TCreateParams): PGtkWidget;
6907 begin
6908 FWidgetType := [wtWidget, wtDialog];
6909 Result := TGtkDialog.new;
6910 DebugLn('WARNING: TGtk3Dialog.CreateWidget should be used in real dialog constructor .');
6911 end;
6912
6913 procedure TGtk3Dialog.InitializeWidget;
6914 begin
6915 g_object_set_data(FWidget,'lclwidget', Self);
6916 end;
6917
6918
6919 { TGtk3FileDialog }
6920
CreateWidgetnull6921 function TGtk3FileDialog.CreateWidget(const Params: TCreateParams): PGtkWidget;
6922 begin
6923 DebugLn('ERROR: TGtk3FileDialog.CreateWidget error.');
6924 // Result := nil;
6925 Result := TGtkFileChooserDialog.new;
6926 // gtk_file_chooser_dialog_new();
6927 end;
6928
6929 constructor TGtk3FileDialog.Create(const ACommonDialog: TCommonDialog);
6930
6931 var
6932 FileDialog: TFileDialog absolute ACommonDialog;
6933 Action: TGtkFileChooserAction;
6934 Button1: String;
6935 AFileDialog: PGtkFileChooserDialog;
6936 begin
6937 inherited Create;
6938 FContext := 0;
6939 FHasPaint := False;
6940 FWidget := nil;
6941 FOwner := nil;
6942 FCentralWidget := nil;
6943 FOwnWidget := True;
6944 // Initializes the properties
6945 FProps := nil;
6946 LCLObject := nil;
6947 FKeysToEat := [VK_TAB, VK_RETURN, VK_ESCAPE];
6948 FWidgetType := [wtWidget, wtDialog];
6949
6950 // FHasPaint := False;
6951 CommonDialog := ACommonDialog;
6952 // Defines an action for the dialog and creates it
6953 Action := GTK_FILE_CHOOSER_ACTION_OPEN;
6954 Button1 := GTK_STOCK_OPEN;
6955
6956 if (FileDialog is TSaveDialog) or (FileDialog is TSavePictureDialog) then
6957 begin
6958 Action := GTK_FILE_CHOOSER_ACTION_SAVE;
6959 Button1 := GTK_STOCK_SAVE;
6960 end
6961 else
6962 if FileDialog is TSelectDirectoryDialog then
6963 begin
6964 Action := GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
6965 Button1 := GTK_STOCK_OPEN;
6966 end;
6967
6968 FWidget := gtk_file_chooser_dialog_new(PgChar(FileDialog.Title), nil,
6969 Action, PChar(GTK_STOCK_CANCEL),
6970 [GTK_RESPONSE_CANCEL, PChar(Button1), GTK_RESPONSE_OK, nil]);
6971
6972 AFileDialog := PGtkFileChooserDialog(FWidget);
6973 if FileDialog is TSaveDialog then
6974 begin
6975 gtk_file_chooser_set_do_overwrite_confirmation(PGtkFileChooser(AFileDialog),
6976 ofOverwritePrompt in TOpenDialog(FileDialog).Options);
6977 end;
6978
6979 if FileDialog.InitialDir <> '' then
6980 gtk_file_chooser_set_current_folder(PGtkFileChooser(AFileDialog), Pgchar(FileDialog.InitialDir));
6981
6982 if gtk_file_chooser_get_action(PGtkFileChooser(AFileDialog)) in
6983 [GTK_FILE_CHOOSER_ACTION_SAVE, GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER]
6984 then
6985 gtk_file_chooser_set_current_name(PGtkFileChooser(AFileDialog), Pgchar(FileDialog.FileName));
6986
6987 InitializeWidget;
6988 end;
6989
6990 { TGtk3FontSelectionDialog }
6991
TGtk3FontSelectionDialog.CreateWidgetnull6992 function TGtk3FontSelectionDialog.CreateWidget(const Params: TCreateParams
6993 ): PGtkWidget;
6994 begin
6995 Result := TGtkFontSelectionDialog.new;
6996 end;
6997
6998 constructor TGtk3FontSelectionDialog.Create(const ACommonDialog: TCommonDialog);
6999 begin
7000 inherited Create;
7001 FContext := 0;
7002 FHasPaint := False;
7003 FWidget := nil;
7004 FOwner := nil;
7005 FCentralWidget := nil;
7006 FOwnWidget := True;
7007 // Initializes the properties
7008 FProps := nil;
7009 LCLObject := nil;
7010 FKeysToEat := [VK_TAB, VK_RETURN, VK_ESCAPE];
7011 FWidgetType := [wtWidget, wtDialog];
7012
7013 // FHasPaint := False;
7014 CommonDialog := ACommonDialog;
7015 end;
7016
7017
7018 end.
7019
7020