1{ 2 ***************************************************************************** 3 * Gtk2WSStdCtrls.pp * 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} 16unit Gtk2WSStdCtrls; 17 18{$mode objfpc}{$H+} 19{$PACKRECORDS c} 20 21interface 22 23uses 24 // RTL 25 glib2, gdk2, gtk2, 26 Classes, SysUtils, Math, 27 // LazUtils 28 LazLoggerBase, LazTracer, 29 // LCL 30 Controls, Graphics, StdCtrls, LMessages, LCLType, LazUtf8Classes, LazUTF8, 31 // Widgetset 32 WSControls, WSProc, WSStdCtrls, Gtk2Int, Gtk2Def, 33 Gtk2CellRenderer, Gtk2Globals, Gtk2Proc, InterfaceBase, 34 Gtk2WSControls, Gtk2Extra; 35 36type 37 38 { !!! Both are used: TGtkComboBoxEntry (with entry) and TGtkComboBox (without entry), 39 but not the old TGtkCombo !!! } 40 41 PGtkComboBoxPrivate = ^TGtkComboBoxPrivate; 42 TGtkComboBoxPrivate = record 43 model: PGtkTreeModel; 44 col_column, 45 row_column: gint; 46 wrap_width: gint; 47 active_row: PGtkTreeRowReference; 48 tree_view: PGtkWidget; 49 column: PGtkTreeViewColumn; 50 cell_view: PGtkWidget; 51 cell_view_frame: PGtkWidget; 52 button: PGtkwidget; 53 box: PGtkWidget; 54 arrow: PGtkWidget; 55 serarator: PGtkWidget; 56 popup_widget: PGtkWidget; 57 popup_window: PGtkWidget; 58 popup_frame: PGtkWidget; 59 scrolled_window: PGtkwidget; 60 end; 61 62 63 64 { TGtk2WSScrollBar } 65 66 TGtk2WSScrollBar = class(TWSScrollBar) 67 protected 68 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 69 published 70 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 71 class procedure SetKind(const AScrollBar: TCustomScrollBar; const {%H-}AIsHorizontal: Boolean); override; 72 class procedure SetParams(const AScrollBar: TCustomScrollBar); override; 73 class procedure ShowHide(const AWinControl: TWinControl); override; 74 end; 75 76 { TGtk2WSCustomGroupBox } 77 78 TGtk2WSCustomGroupBox = class(TWSCustomGroupBox) 79 protected 80 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 81 class procedure SetLabel(AFrame: PGtkFrame; AText: String); 82 class function GetFrameWidget(AEventBox: PGtkEventBox): PGtkFrame; 83 published 84 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 85 class procedure SetColor(const AWinControl: TWinControl); override; 86 class function GetDefaultClientRect(const AWinControl: TWinControl; 87 const {%H-}aLeft, {%H-}aTop, aWidth, aHeight: integer; var aClientRect: TRect 88 ): boolean; override; 89 class procedure GetPreferredSize(const AWinControl: TWinControl; 90 var PreferredWidth, PreferredHeight: integer; 91 WithThemeSpace: Boolean); override; 92 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 93 class procedure SetText(const AWinControl: TWinControl; const AText: string); override; 94 end; 95 96 { TGtk2WSGroupBox } 97 98 TGtk2WSGroupBox = class(TWSGroupBox) 99 published 100 end; 101 102 { TGtk2WSCustomComboBox } 103 { !!! Both are used: TGtkComboBoxEntry (with entry) and TGtkComboBox (without entry), 104 but not the old TGtkCombo !!! } 105 106 TGtk2WSCustomComboBox = class(TWSCustomComboBox) 107 protected 108 class procedure ReCreateCombo(const ACustomComboBox: TCustomComboBox; const AWithEntry: Boolean; const AWidgetInfo: PWidgetInfo); virtual; 109 class procedure SetRenderer(const ACustomComboBox: TCustomComboBox; AWidget: PGtkWidget; AWidgetInfo: PWidgetInfo); virtual; 110 class procedure SetCallbacks(const AWinControl: tWinControl; const AWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 111 class procedure SetSensitivity(AWinControl: TWinControl; AWidget: PGtkWidget); 112 published 113 class procedure GetPreferredSize(const AWinControl: TWinControl; 114 var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; 115 116 class function GetDroppedDown(const ACustomComboBox: TCustomComboBox): Boolean; override; 117 class function GetSelStart(const ACustomComboBox: TCustomComboBox): integer; override; 118 class function GetSelLength(const ACustomComboBox: TCustomComboBox): integer; override; 119 class function GetItemIndex(const ACustomComboBox: TCustomComboBox): integer; override; 120 class function GetMaxLength(const ACustomComboBox: TCustomComboBox): integer; override; 121 class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override; 122 123 class procedure SetArrowKeysTraverseList(const {%H-}ACustomComboBox: TCustomComboBox; 124 {%H-}NewTraverseList: boolean); override; 125 class procedure SetDroppedDown(const ACustomComboBox: TCustomComboBox; ADroppedDown: Boolean); override; 126 class procedure SetSelStart(const ACustomComboBox: TCustomComboBox; NewStart: integer); override; 127 class procedure SetSelLength(const ACustomComboBox: TCustomComboBox; NewLength: integer); override; 128 class procedure SetItemIndex(const ACustomComboBox: TCustomComboBox; NewIndex: integer); override; 129 class procedure SetMaxLength(const ACustomComboBox: TCustomComboBox; NewLength: integer); override; 130 class procedure SetStyle(const ACustomComboBox: TCustomComboBox; NewStyle: TComboBoxStyle); override; 131 132 class function GetItems(const ACustomComboBox: TCustomComboBox): TStrings; override; 133 class procedure Sort(const ACustomComboBox: TCustomComboBox; {%H-}AList: TStrings; IsSorted: boolean); override; 134 class procedure SetColor(const AWinControl: TWinControl); override; 135 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 136 class procedure SetText(const AWinControl: TWinControl; const AText: String); override; 137 138 class procedure ShowHide(const AWinControl: TWinControl); override; 139 140 class function CanFocus(const AWinControl: TWinControl): boolean; override; 141 142 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 143 class procedure DestroyHandle(const AWinControl: TWinControl); override; 144 end; 145 146 { TGtk2WSComboBox } 147 148 TGtk2WSComboBox = class(TWSComboBox) 149 published 150 end; 151 152 { TGtk2WSCustomListBox } 153 154 TGtk2WSCustomListBox = class(TWSCustomListBox) 155 protected 156 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 157 published 158 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 159 class function GetIndexAtXY(const ACustomListBox: TCustomListBox; {%H-}X, Y: integer): integer; override; 160 class function GetItemIndex(const ACustomListBox: TCustomListBox): integer; override; 161 class function GetItemRect(const ACustomListBox: TCustomListBox; Index: integer; var ARect: TRect): boolean; override; 162 class function GetScrollWidth(const ACustomListBox: TCustomListBox): Integer; override; 163 class function GetSelCount(const ACustomListBox: TCustomListBox): integer; override; 164 class function GetSelected(const ACustomListBox: TCustomListBox; const AIndex: integer): boolean; override; 165 class function GetStrings(const ACustomListBox: TCustomListBox): TStrings; override; 166 class function GetTopIndex(const ACustomListBox: TCustomListBox): integer; override; 167 168 class procedure SelectItem(const ACustomListBox: TCustomListBox; AnIndex: integer; ASelected: boolean); override; 169 class procedure SetBorder(const ACustomListBox: TCustomListBox); override; 170 class procedure SetColor(const AWinControl: TWinControl); override; 171 class procedure SetItemIndex(const ACustomListBox: TCustomListBox; const AIndex: integer); override; 172 class procedure SetScrollWidth(const ACustomListBox: TCustomListBox; const AScrollWidth: Integer); override; 173 class procedure SetSelectionMode(const ACustomListBox: TCustomListBox; const {%H-}AExtendedSelect, 174 AMultiSelect: boolean); override; 175 class procedure SetStyle(const ACustomListBox: TCustomListBox); override; 176 class procedure SetSorted(const {%H-}ACustomListBox: TCustomListBox; AList: TStrings; ASorted: boolean); override; 177 class procedure SetTopIndex(const ACustomListBox: TCustomListBox; const NewTopIndex: integer); override; 178 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 179 class procedure ShowHide(const AWinControl: TWinControl); override; 180 end; 181 182 { TGtk2WSListBox } 183 184 TGtk2WSListBox = class(TWSListBox) 185 published 186 end; 187 188 { TGtk2WSCustomEdit } 189 190 TGtk2WSCustomEdit = class(TWSCustomEdit) 191 published 192 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 193 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 194 class function GetCaretPos(const ACustomEdit: TCustomEdit): TPoint; override; 195 class function GetSelStart(const ACustomEdit: TCustomEdit): integer; override; 196 class function GetSelLength(const ACustomEdit: TCustomEdit): integer; override; 197 198 class procedure SetCaretPos(const ACustomEdit: TCustomEdit; const NewPos: TPoint); override; 199 class procedure SetCharCase(const {%H-}ACustomEdit: TCustomEdit; {%H-}NewCase: TEditCharCase); override; 200 class procedure SetEchoMode(const ACustomEdit: TCustomEdit; NewMode: TEchoMode); override; 201 class procedure SetMaxLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; 202 class procedure SetPasswordChar(const ACustomEdit: TCustomEdit; {%H-}NewChar: char); override; 203 class procedure SetReadOnly(const ACustomEdit: TCustomEdit; NewReadOnly: boolean); override; 204 class procedure SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); override; 205 class procedure SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; 206 class procedure SetText(const AWinControl: TWinControl; const AText: string); override; 207 class procedure SetSelText(const ACustomEdit: TCustomEdit; const NewSelText: string); override; 208 209 class procedure GetPreferredSize(const AWinControl: TWinControl; 210 var PreferredWidth, PreferredHeight: integer; 211 WithThemeSpace: Boolean); override; 212 class procedure SetColor(const AWinControl: TWinControl); override; 213 214 class procedure SetAlignment(const ACustomEdit: TCustomEdit; const AAlignment: TAlignment); override; 215 216 class procedure Cut(const ACustomEdit: TCustomEdit); override; 217 class procedure Copy(const ACustomEdit: TCustomEdit); override; 218 class procedure Paste(const ACustomEdit: TCustomEdit); override; 219 class procedure Undo(const ACustomEdit: TCustomEdit); override; 220 end; 221 222 { TGtk2WSCustomMemo } 223 224 TGtk2WSCustomMemo = class(TWSCustomMemo) 225 protected 226 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 227 published 228 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 229 230 class function GetSelStart(const ACustomEdit: TCustomEdit): integer; override; 231 class function GetSelLength(const ACustomEdit: TCustomEdit): integer; override; 232 class function GetStrings(const ACustomMemo: TCustomMemo): TStrings; override; 233 234 class procedure SetAlignment(const ACustomEdit: TCustomEdit; const AAlignment: TAlignment); override; 235 class procedure SetColor(const AWinControl: TWinControl); override; 236 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 237 class procedure SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); override; 238 class procedure SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; 239 class procedure SetWantTabs(const ACustomMemo: TCustomMemo; const NewWantTabs: boolean); override; 240 class procedure SetEchoMode(const {%H-}ACustomEdit: TCustomEdit; {%H-}NewMode: TEchoMode); override; 241 class procedure SetPasswordChar(const {%H-}ACustomEdit: TCustomEdit; {%H-}NewChar: char); override; 242 class procedure SetWordWrap(const ACustomMemo: TCustomMemo; const NewWordWrap: boolean); override; 243 244 class procedure SetCharCase(const {%H-}ACustomEdit: TCustomEdit; {%H-}NewCase: TEditCharCase); override; 245 class procedure SetMaxLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; 246 class procedure SetReadOnly(const ACustomEdit: TCustomEdit; NewReadOnly: boolean); override; 247 class procedure SetSelText(const ACustomEdit: TCustomEdit; const NewSelText: string); override; 248 class procedure SetText(const AWinControl: TWinControl; const AText: string); override; 249 class procedure SetScrollbars(const ACustomMemo: TCustomMemo; const NewScrollbars: TScrollStyle); override; 250 251 class procedure GetPreferredSize(const AWinControl: TWinControl; 252 var PreferredWidth, PreferredHeight: integer; 253 WithThemeSpace: Boolean); override; 254 255 class function GetCaretPos(const ACustomEdit: TCustomEdit): TPoint; override; 256 class procedure SetCaretPos(const ACustomEdit: TCustomEdit; const NewPos: TPoint); override; 257 end; 258 259 { TGtk2WSEdit } 260 261 TGtk2WSEdit = class(TWSEdit) 262 published 263 end; 264 265 { TGtk2WSMemo } 266 267 TGtk2WSMemo = class(TWSMemo) 268 published 269 end; 270 271 { TGtk2WSCustomLabel } 272 273 { 274 TGtk2WSCustomLabel = class(TWSCustomLabel) 275 private 276 protected 277 public 278 end; 279 } 280 { TGtk2WSLabel } 281 282 { 283 TGtk2WSLabel = class(TWSLabel) 284 private 285 protected 286 public 287 end; 288 } 289 290 { TGtk2WSButtonControl } 291 292 TGtk2WSButtonControl = class(TWSButtonControl) 293 published 294 end; 295 296 { TGtk2WSButton } 297 298 TGtk2WSButton = class(TWSButton) 299 protected 300 class function GetButtonWidget(AEventBox: PGtkEventBox): PGtkButton; 301 class function GetLabelWidget(AEventBox: PGtkEventBox): PGtkLabel; 302 public 303 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 304 published 305 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 306 class procedure GetPreferredSize(const AWinControl: TWinControl; 307 var PreferredWidth, PreferredHeight: integer; 308 WithThemeSpace: Boolean); override; 309 class function GetText(const {%H-}AWinControl: TWinControl; var {%H-}AText: String): Boolean; override; 310 311 class procedure SetColor(const AWinControl: TWinControl); override; 312 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 313 class procedure SetDefault(const AButton: TCustomButton; ADefault: Boolean); override; 314 class procedure SetShortcut(const AButton: TCustomButton; const {%H-}ShortCutK1, {%H-}ShortCutK2: TShortcut); override; 315 class procedure SetText(const AWinControl: TWinControl; const AText: String); override; 316 end; 317 318 { TGtk2WSCustomCheckBox } 319 320 TGtk2WSCustomCheckBox = class(TWSCustomCheckBox) 321 protected 322 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 323 published 324 class function CreateHandle(const AWinControl: TWinControl; 325 const AParams: TCreateParams): TLCLIntfHandle; override; 326 class procedure GetPreferredSize(const AWinControl: TWinControl; 327 var PreferredWidth, PreferredHeight: integer; 328 WithThemeSpace: Boolean); override; 329 class function RetrieveState(const ACustomCheckBox: TCustomCheckBox): TCheckBoxState; override; 330 class procedure SetShortCut(const ACustomCheckBox: TCustomCheckBox; const ShortCutK1, {%H-}ShortCutK2: TShortCut); override; 331 class procedure SetState(const ACustomCheckBox: TCustomCheckBox; 332 const NewState: TCheckBoxState); override; 333 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 334 class procedure SetText(const AWinControl: TWinControl; const AText: String); override; 335 class procedure ShowHide(const AWinControl: TWinControl); override; 336 end; 337 338 { TGtk2WSCheckBox } 339 340 TGtk2WSCheckBox = class(TWSCheckBox) 341 published 342 end; 343 344 { TGtk2WSToggleBox } 345 346 TGtk2WSToggleBox = class(TWSToggleBox) 347 published 348 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 349 end; 350 351 { TGtk2WSRadioButton } 352 353 TGtk2WSRadioButton = class(TWSRadioButton) 354 published 355 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 356 end; 357 358 { TGtk2WSCustomStaticText } 359 360 TGtk2WSCustomStaticText = class(TWSCustomStaticText) 361 protected 362 class function GetLabelWidget(AFrame: PGtkFrame): PGtkLabel; 363 class function GetBoxWidget(AFrame: PGtkFrame): PGtkEventBox; 364 published 365 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; 366 class procedure SetAlignment(const ACustomStaticText: TCustomStaticText; 367 const NewAlignment: TAlignment); override; 368 class procedure GetPreferredSize(const AWinControl: TWinControl; 369 var PreferredWidth, PreferredHeight: integer; 370 WithThemeSpace: Boolean); override; 371 class function GetText(const {%H-}AWinControl: TWinControl; var {%H-}AText: String): Boolean; override; 372 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); 373 class procedure SetColor(const AWinControl: TWinControl); override; 374 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 375 class procedure SetStaticBorderStyle(const ACustomStaticText: TCustomStaticText; const NewBorderStyle: TStaticBorderStyle); override; 376 class procedure SetText(const AWinControl: TWinControl; const AText: String); override; 377 end; 378 379 { TGtk2WSStaticText } 380 381 TGtk2WSStaticText = class(TWSStaticText) 382 published 383 end; 384 385{$DEFINE MEMOHEADER} 386{$I gtk2memostrings.inc} 387{$UNDEF MEMOHEADER} 388 389function GetComboBoxEntry(Widget: PGtkWidget): PGtkEntry; 390 391implementation 392 393uses 394 LCLMessageGlue, Forms; 395 396const 397 StaticBorderShadowMap: array[TStaticBorderStyle] of TGtkShadowType = 398 ( 399 GTK_SHADOW_NONE, 400 GTK_SHADOW_ETCHED_IN, 401 GTK_SHADOW_IN 402 ); 403 404 405function GetComboBoxEntry(Widget: PGtkWidget): PGtkEntry; 406begin 407 if GtkWidgetIsA(Widget, GTK_TYPE_COMBO_BOX_ENTRY) then 408 Result := PGtkEntry(GTK_BIN(Widget)^.child) 409 else 410 Result := nil; 411end; 412 413procedure gtkDefaultPopupMenuDeactivate(Widget: PGtkWidget; data: gPointer); cdecl; 414begin 415 LastMouse.Button := 0; 416 LastMouse.ClickCount := 0; 417 LastMouse.Down := False; 418 LastMouse.MousePos := Point(0, 0); 419 LastMouse.Time := 0; 420 LastMouse.WinControl := nil; 421end; 422 423function gtkDefaultPopupMenuCloseFix(Widget: PGtkWidget; Menu: PGtkMenu; 424 data: gPointer): gboolean; cdecl; 425begin 426 // needed because closing popup menu without clicking on any menu item 427 // freezes various controls, eg SpeedButton 428 g_signal_connect(PGtkObject(Menu), 'deactivate', 429 gtk_signal_func(@gtkDefaultPopupMenuDeactivate), nil); 430end; 431 432{$I gtk2memostrings.inc} 433 434{ TGtk2WSCustomListBox } 435 436procedure StoreFirstSelectedPath({%H-}model:PGtkTreeModel; path:PGtkTreePath; 437 {%H-}iter:PGtkTreeIter; data:gpointer); cdecl; 438begin 439 //DebugLn(['StoreFirstSelectedPath ',PInteger(Data)^,' ',gtk_tree_path_get_indices(Path)^]); 440 if PInteger(Data)^ < 0 then 441 PInteger(Data)^ := gtk_tree_path_get_indices(Path)^; 442end; 443 444class function TGtk2WSCustomListBox.GetItemIndex( 445 const ACustomListBox: TCustomListBox): integer; 446var 447 Widget: PGtkWidget; 448 Path: PGtkTreePath; 449 Column: PGtkTreeViewColumn; 450 Selection: PGtkTreeSelection; 451begin 452 Result := -1; 453 if not WSCheckHandleAllocated(ACustomListBox, 'GetItemIndex') then 454 Exit; 455 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 456 if GtkWidgetIsA(Widget, gtk_tree_view_get_type) then 457 begin 458 Path:=nil; 459 Column:=nil; 460 gtk_tree_view_get_cursor(PGtkTreeView(Widget), Path, column); 461 462 if Path <> nil then 463 begin 464 Result := gtk_tree_path_get_indices(Path)^; 465 if Result = 0 then 466 begin 467 Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); 468 if not gtk_tree_selection_path_is_selected(Selection, Path) then 469 Result := -1; 470 end; 471 end else 472 Result := -1; 473 end; 474end; 475 476class function TGtk2WSCustomListBox.GetItemRect( 477 const ACustomListBox: TCustomListBox; Index: integer; var ARect: TRect 478 ): boolean; 479var 480 Widget: PGtkWidget; 481 Column: PGtkTreeViewColumn; 482 Path: PGtkTreePath; 483 AGdkRect: TGdkRectangle; 484begin 485 Result := False; 486 FillChar(ARect, SizeOf(ARect), 0); 487 if not WSCheckHandleAllocated(ACustomListBox, 'GetItemIndex') then 488 Exit; 489 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 490 if GtkWidgetIsA(Widget, gtk_tree_view_get_type) and (Index >= 0) then 491 begin 492 Path := gtk_tree_path_new_from_indices(Index, -1); 493 Column := gtk_tree_view_get_column(PGtkTreeView(Widget), 0); 494 FillChar(AGdkRect{%H-}, SizeOf(AGdkRect), 0); 495 gtk_tree_view_get_cell_area(PGtkTreeView(Widget), Path, Column, @AGdkRect); 496 ARect := Rect(AGdkRect.x, AGdkRect.y, AGdkRect.x + AGdkRect.width, AGdkRect.y + AGdkRect.height); 497 gtk_tree_path_free(Path); 498 Result := True; 499 end; 500end; 501 502class function TGtk2WSCustomListBox.GetScrollWidth(const ACustomListBox: TCustomListBox): Integer; 503var 504 Adjustment: PGtkAdjustment; 505begin 506 Adjustment := gtk_scrolled_window_get_hadjustment({%H-}PGtkScrolledWindow(ACustomListBox.Handle)); 507 Result := Trunc(Adjustment^.upper); 508end; 509 510class function TGtk2WSCustomListBox.GetTopIndex(const ACustomListBox: TCustomListBox): integer; 511begin 512 Result := GetIndexAtXY(ACustomListBox, 0, 1); 513end; 514 515class procedure TGtk2WSCustomListBox.SelectItem( 516 const ACustomListBox: TCustomListBox; AnIndex: integer; ASelected: boolean); 517var 518 Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) 519 Selection: PGtkTreeSelection; 520 ListStoreModel: PGtkTreeModel; 521 Iter : TGtkTreeIter; 522begin 523 if not WSCheckHandleAllocated(ACustomListBox, 'SelectItem') then 524 Exit; 525 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 526 ListStoreModel := gtk_tree_view_get_model(PGtkTreeView(Widget)); 527 Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); 528 529 if gtk_tree_model_iter_nth_child(ListStoreModel, @Iter, nil, AnIndex) then 530 begin 531 if gtk_tree_view_get_model(PGtkTreeView(Widget)) = nil then 532 Exit; // we are in the midst of a begin update end update pair and the following will fail and cause gtk debug messages 533 case ASelected of 534 True: 535 if not gtk_tree_selection_iter_is_selected(Selection, @Iter) then 536 gtk_tree_selection_select_iter(Selection, @Iter); 537 False: 538 if gtk_tree_selection_iter_is_selected(Selection, @Iter) then 539 gtk_tree_selection_unselect_iter(Selection, @Iter); 540 end; 541 end; 542end; 543 544class procedure TGtk2WSCustomListBox.SetBorder( 545 const ACustomListBox: TCustomListBox); 546begin 547 gtk_scrolled_window_set_shadow_type({%H-}PGtkScrolledWindow(ACustomListBox.Handle), 548 BorderStyleShadowMap[ACustomListBox.BorderStyle]); 549end; 550 551class procedure TGtk2WSCustomListBox.SetColor(const AWinControl: TWinControl); 552var 553 AWidget: PGTKWidget; 554begin 555 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then 556 Exit; 557 AWidget := {%H-}PGtkWidget(AWinControl.Handle); 558 AWidget := GetWidgetInfo(AWidget, True)^.CoreWidget; 559 Gtk2WidgetSet.SetWidgetColor(AWidget, 560 AWinControl.Font.Color, 561 AWinControl.Color, 562 [GTK_STATE_NORMAL, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT, GTK_STYLE_BASE]); 563end; 564 565class procedure TGtk2WSCustomListBox.SetItemIndex( 566 const ACustomListBox: TCustomListBox; const AIndex: integer); 567var 568 Widget: PGtkWidget; 569 WidgetInfo: PWidgetInfo; 570 Selection: PGtkTreeSelection; 571 Path: PGtkTreePath; 572begin 573 if not WSCheckHandleAllocated(ACustomListBox, 'SetItemIndex') then 574 Exit; 575 576 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True); 577 Widget := WidgetInfo^.CoreWidget; 578 if not GtkWidgetIsA(Widget, gtk_tree_view_get_type) then 579 raise Exception.Create(''); 580 581 Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); 582 583 Inc(WidgetInfo^.ChangeLock); 584 if (AIndex < 0) then 585 Path := nil 586 else 587 Path := gtk_tree_path_new_from_indices(AIndex, -1); 588 589 // if singleselection mode then selection = itemindex 590 if Path <> nil then 591 begin 592 if PGtkTreeView(Widget)^.priv^.tree <> nil then 593 gtk_tree_view_set_cursor(PGtkTreeView(Widget), Path, nil, False); 594 end 595 else 596 begin 597 Path := gtk_tree_path_new_from_indices(0, -1); 598 if PGtkTreeView(Widget)^.priv^.tree <> nil then 599 gtk_tree_view_set_cursor(PGtkTreeView(Widget), Path, nil, False); 600 gtk_tree_selection_unselect_all(Selection); 601 end; 602 603 if Path <> nil then 604 gtk_tree_path_free(Path); 605 606 Dec(WidgetInfo^.ChangeLock); 607end; 608 609class procedure TGtk2WSCustomListBox.SetScrollWidth( 610 const ACustomListBox: TCustomListBox; const AScrollWidth: Integer); 611const 612 BoolToPolicy: array[Boolean] of TGtkPolicyType = (GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); 613var 614 Adjustment: PGtkAdjustment; 615 ScrolledWindow: PGtkScrolledWindow; 616begin 617 ScrolledWindow := {%H-}PGtkScrolledWindow(ACustomListBox.Handle); 618 gtk_scrolled_window_set_policy(ScrolledWindow, BoolToPolicy[AScrollWidth > PgtkWidget(ScrolledWindow)^.allocation.width], GTK_POLICY_AUTOMATIC); 619 Adjustment := gtk_scrolled_window_get_hadjustment(ScrolledWindow); 620 Adjustment^.upper := AScrollWidth; 621 gtk_adjustment_changed(Adjustment); 622end; 623 624class procedure TGtk2WSCustomListBox.SetSelectionMode( 625 const ACustomListBox: TCustomListBox; const AExtendedSelect, 626 AMultiSelect: boolean); 627var 628 Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) 629 Selection: PGtkTreeSelection; 630begin 631 if not WSCheckHandleAllocated(ACustomListBox, 'SetSelectionMode') then 632 Exit; 633 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle),True)^.CoreWidget; 634 Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); 635 636 case AMultiSelect of 637 True : gtk_tree_selection_set_mode(Selection, GTK_SELECTION_MULTIPLE); 638 False: gtk_tree_selection_set_mode(Selection, GTK_SELECTION_SINGLE); 639 //GTK_SELECTION_NONE, 640 //GTK_SELECTION_SINGLE, 641 //GTK_SELECTION_BROWSE, 642 //GTK_SELECTION_MULTIPLE 643 end; 644end; 645 646class procedure TGtk2WSCustomListBox.SetStyle( 647 const ACustomListBox: TCustomListBox); 648var 649 AStyle: PtrInt; 650 Widget: PGtkWidget; 651begin 652 if not WSCheckHandleAllocated(ACustomListBox, 'SetStyle') then 653 Exit; 654 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 655 AStyle := {%H-}PtrInt(g_object_get_data(PGObject(Widget), 'lclcustomlistboxstyle')); 656 if (AStyle <> Ord(ACustomListBox.Style)) then 657 RecreateWnd(ACustomListBox); 658end; 659 660class procedure TGtk2WSCustomListBox.SetSorted(const ACustomListBox: TCustomListBox; 661 AList: TStrings; ASorted: boolean); 662begin 663 if AList is TGtkListStoreStringList then 664 TGtkListStoreStringList(AList).Sorted := ASorted 665 //else if AList is TGtkCListStringList then 666 // TGtkCListStringList(AList).Sorted := ASorted 667 else 668 raise Exception.Create(''); 669end; 670 671class procedure TGtk2WSCustomListBox.SetTopIndex( 672 const ACustomListBox: TCustomListBox; const NewTopIndex: integer); 673var 674 Widget: PGtkWidget; 675 ListStoreModel: PGtkTreeModel; 676 Iter: TGtkTreeIter; 677 TreeView: PGtkTreeView; 678 APath: Pointer; 679begin 680 if not WSCheckHandleAllocated(ACustomListBox, 'SetTopIndex') then 681 Exit; 682 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 683 TreeView := PGtkTreeView(Widget); 684 ListStoreModel := gtk_tree_view_get_model(TreeView); 685 686 if not gtk_tree_model_iter_nth_child(ListStoreModel, @Iter, nil, NewTopIndex) 687 then exit; 688 689 APath := gtk_tree_model_get_path(ListStoreModel, @Iter); 690 gtk_tree_view_scroll_to_cell(TreeView, APath, NULL, true, 0.0, 0.0); 691 gtk_tree_path_free(APath); 692end; 693 694class procedure TGtk2WSCustomListBox.SetFont(const AWinControl: TWinControl; 695 const AFont: TFont); 696var 697 Widget: PGtkWidget; 698begin 699 if not WSCheckHandleAllocated(AWinControl, 'SetFont') then 700 Exit; 701 Widget := GetWidgetInfo({%H-}Pointer(AWinControl.Handle))^.CoreWidget; 702 703 Gtk2WidgetSet.SetWidgetColor(Widget, AFont.Color, clNone, 704 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED, 705 GTK_STYLE_TEXT]); 706 Gtk2WidgetSet.SetWidgetFont(Widget, AFont); 707end; 708 709class procedure TGtk2WSCustomListBox.ShowHide(const AWinControl: TWinControl); 710begin 711 // issue #27276 712 if AWinControl.HandleAllocated and AWinControl.HandleObjectShouldBeVisible and 713 (TCustomListBox(AWinControl).ItemIndex = -1) then 714 SetItemIndex(TCustomListBox(AWinControl), TCustomListBox(AWinControl).ItemIndex); 715 // issue #28341 716 if AWinControl.HandleObjectShouldBeVisible then 717 SetFont(AWinControl, AWinControl.Font); 718 Gtk2WidgetSet.SetVisible(AWinControl, AWinControl.HandleObjectShouldBeVisible); 719 InvalidateLastWFPResult(AWinControl, AWinControl.BoundsRect); 720end; 721 722function gtk2ListBoxSelectionChangedAfter({%H-}Widget: PGtkWidget; 723 WidgetInfo: PWidgetInfo): gboolean; cdecl; 724var 725 Mess: TLMessage; 726begin 727 Result := CallBackDefaultReturn; 728 if WidgetInfo^.ChangeLock > 0 then 729 Exit; 730 {$IFDEF EventTrace} 731 EventTrace('gtk2ListSelectionChangedAfter', WidgetInfo^.LCLObject); 732 {$ENDIF} 733 FillChar(Mess{%H-},SizeOf(Mess),0); 734 Mess.msg := LM_SelChange; 735 DeliverMessage(WidgetInfo^.LCLObject, Mess); 736end; 737 738class function TGtk2WSCustomListBox.CreateHandle(const AWinControl: TWinControl; 739 const AParams: TCreateParams): TLCLIntfHandle; 740var 741 TVWidget: PGtkWidget; 742 p: PGtkWidget; // ptr to the newly created GtkWidget 743 liststore : PGtkListStore; 744 Selection: PGtkTreeSelection; 745 renderer : PGtkCellRenderer; 746 column : PGtkTreeViewColumn; 747 WidgetInfo: PWidgetInfo; 748begin 749 Result := TGtk2WSBaseScrollingWinControl.CreateHandle(AWinControl, AParams); 750 p := {%H-}PGtkWidget(Result); 751 752 if Result = 0 then exit; 753 {$IFDEF DebugLCLComponents} 754 DebugGtkWidgets.MarkCreated(p,dbgsName(AWinControl)); 755 {$ENDIF} 756 757 GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.hscrollbar, GTK_CAN_FOCUS); 758 GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.vscrollbar, GTK_CAN_FOCUS); 759 // by default horz scrollbar is invisible. it is set by SetScrollWidth 760 gtk_scrolled_window_set_policy(PGtkScrolledWindow(p), 761 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); 762 //Set BorderStyle according to the provided Params 763 if (AParams.ExStyle and WS_EX_CLIENTEDGE) > 0 then 764 gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(p), GTK_SHADOW_ETCHED_IN) 765 else 766 gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(p), GTK_SHADOW_NONE); 767 768 gtk_widget_show(p); 769 770 liststore := gtk_list_store_new (2, [G_TYPE_STRING, G_TYPE_POINTER, nil]); 771 772 TVWidget:= gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); 773 g_object_unref (G_OBJECT (liststore)); 774 775 renderer := LCLIntfCellRenderer_New(); 776 column := gtk_tree_view_column_new_with_attributes ('LISTITEMS', renderer, 777 ['text', 0, nil]); 778 gtk_cell_layout_set_cell_data_func(PGtkCellLayout(column), renderer, 779 @LCLIntfCellRenderer_CellDataFunc, nil, nil); 780 gtk_tree_view_append_column (GTK_TREE_VIEW (TVWidget), column); 781 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); 782 783 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (TVWidget), False); 784 785 gtk_container_add(GTK_CONTAINER(p), TVWidget); 786 gtk_widget_show(TVWidget); 787 788 SetMainWidget(p, TVWidget); 789 WidgetInfo := GetWidgetInfo(p, false); 790 WidgetInfo^.CoreWidget := TVWidget; 791 792 Selection := gtk_tree_view_get_selection(PGtkTreeView(TVWidget)); 793 794 case TCustomListBox(AWinControl).MultiSelect of 795 True : gtk_tree_selection_set_mode(Selection, GTK_SELECTION_MULTIPLE); 796 False: gtk_tree_selection_set_mode(Selection, GTK_SELECTION_SINGLE); 797 end; 798 799 if TListBox(AWinControl).Style = lbOwnerDrawFixed then 800 begin 801 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); 802 gtk_tree_view_set_fixed_height_mode(PGtkTreeView(TVWidget), True); 803 end; 804 805 806 g_signal_connect_after(Selection, 'changed', 807 G_CALLBACK(@gtk2ListBoxSelectionChangedAfter), WidgetInfo); 808 809 g_object_set_data(PGObject(TVWidget), 'lclcustomlistboxstyle', {%H-}gPointer(Ord(TListBox(AWinControl).Style))); 810 811 // Sets the callbacks 812 if not AWinControl.HandleObjectShouldBeVisible and not (csDesigning in AWinControl.ComponentState) then 813 gtk_widget_hide(p); 814 SetCallbacks(p, WidgetInfo); 815end; 816 817class procedure TGtk2WSCustomListBox.SetCallbacks(const AGtkWidget: PGtkWidget; 818 const AWidgetInfo: PWidgetInfo); 819begin 820 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 821end; 822 823class function TGtk2WSCustomListBox.GetIndexAtXY( 824 const ACustomListBox: TCustomListBox; X, Y: integer): integer; 825var 826 aTreeView: PGtkTreeView; 827 aTreeColumn: PGtkTreeViewColumn; 828 aTreePath: PGtkTreePath; 829begin 830 Result := -1; 831 if not WSCheckHandleAllocated(ACustomListBox, 'GetIndexAtXY') then 832 Exit; 833 case ACustomListBox.fCompStyle of 834 csListBox, csCheckListBox: 835 begin 836 aTreeView := 837 GTK_TREE_VIEW(GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget); 838 839 aTreePath:=nil; 840 aTreeColumn:=nil; 841 if gtk_tree_view_get_path_at_pos(aTreeView, 0, Y, aTreePath, aTreeColumn, 842 nil, nil) 843 then begin 844 Result := gtk_tree_path_get_indices(aTreePath)[0]; 845 gtk_tree_path_free(aTreePath); 846 exit; 847 end; 848 end; 849 end; 850end; 851 852class function TGtk2WSCustomListBox.GetSelCount( 853 const ACustomListBox: TCustomListBox): integer; 854var 855 Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) 856 Selection: PGtkTreeSelection; 857 ListStoreModel: PGtkTreeModel; 858 Rows: PGList; 859begin 860 Result := 0; 861 if not WSCheckHandleAllocated(ACustomListBox, 'GetSelCount') then 862 Exit; 863 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 864 Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); 865 866 Rows := gtk_tree_selection_get_selected_rows(Selection, @ListStoreModel); 867 Result := g_list_length(Rows); 868 g_list_free(Rows); 869end; 870 871class function TGtk2WSCustomListBox.GetSelected( 872 const ACustomListBox: TCustomListBox; const AIndex: integer): boolean; 873var 874 Widget: PGtkWidget; // pointer to gtk-widget (local use when neccessary) 875 Selection: PGtkTreeSelection; 876 ListStoreModel: PGtkTreeModel; 877 Item : TGtkTreeIter; 878begin 879 Result := False; { assume: nothing found } 880 if not WSCheckHandleAllocated(ACustomListBox, 'GetSelected') then 881 Exit; 882 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 883 ListStoreModel := gtk_tree_view_get_model(PGtkTreeView(Widget)); 884 Selection := gtk_tree_view_get_selection(PGtkTreeView(Widget)); 885 886 if gtk_tree_view_get_model(PGtkTreeView(Widget)) = nil then 887 Exit; 888 if gtk_tree_model_iter_nth_child(ListStoreModel, @Item, nil, AIndex) then 889 begin 890 Result := gtk_tree_selection_iter_is_selected(Selection, @Item); 891 end; 892end; 893 894class function TGtk2WSCustomListBox.GetStrings( 895 const ACustomListBox: TCustomListBox): TStrings; 896var 897 Widget: PGtkWidget;// pointer to gtk-widget 898begin 899 Result:=nil; 900 if not WSCheckHandleAllocated(ACustomListBox, 'GetStrings') then 901 Exit; 902 case ACustomListBox.fCompStyle of 903 {csCListBox: 904 begin 905 Widget:= GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; 906 907 Result := TGtkCListStringList.Create(PGtkCList(Widget)); 908 if ACustomListBox is TCustomListBox then 909 TGtkCListStringList(Result).Sorted := 910 TCustomListBox(ACustomListBox).Sorted; 911 end; 912 } 913 csCheckListBox, csListBox: 914 begin 915 Widget := GetWidgetInfo({%H-}Pointer(ACustomListBox.Handle), True)^.CoreWidget; 916 Result := TGtkListStoreStringList.Create( 917 gtk_tree_view_get_model(PGtkTreeView(Widget)), 918 Ord(ACustomListBox.fCompStyle = csCheckListBox), 919 ACustomListBox); 920 TGtkListStoreStringList(Result).Sorted := ACustomListBox.Sorted; 921 end; 922 else 923 raise Exception.Create('TGtk2WSCustomListBox.GetStrings'); 924 end; 925end; 926 927{ TGtk2WSCustomCheckBox } 928 929class procedure TGtk2WSCustomCheckBox.SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); 930begin 931 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 932 TGtk2Widgetset(WidgetSet).SetCallback(LM_CHANGED, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject); 933end; 934 935 936class function TGtk2WSCustomCheckBox.CreateHandle( 937 const AWinControl: TWinControl; const AParams: TCreateParams 938 ): TLCLIntfHandle; 939var 940 Widget: PGtkWidget; 941 WidgetInfo: PWidgetInfo; 942 Allocation: TGTKAllocation; 943begin 944 { ToDo verify if the check box has correct z-order and disable GTK_WIDGET_NO_WINDOW if not.} 945 Widget := gtk_check_button_new_with_label(AParams.Caption); 946 {$IFDEF DebugLCLComponents} 947 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 948 {$ENDIF} 949 Result := THandle({%H-}PtrUInt(Widget)); 950 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), AWinControl, AParams); 951 952 Allocation.X := AParams.X; 953 Allocation.Y := AParams.Y; 954 Allocation.Width := AParams.Width; 955 Allocation.Height := AParams.Height; 956 gtk_widget_size_allocate({%H-}PGtkWidget(Result), @Allocation); 957 if AParams.Style and WS_VISIBLE = 0 then 958 gtk_widget_hide({%H-}PGtkWidget(Result)) 959 else 960 gtk_widget_show({%H-}PGtkWidget(Result)); 961 962 Set_RC_Name(AWinControl, {%H-}PGtkWidget(Result)); 963 SetCallbacks({%H-}PGtkWidget(Result), WidgetInfo); 964end; 965 966class procedure TGtk2WSCustomCheckBox.GetPreferredSize( 967 const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; 968 WithThemeSpace: Boolean); 969begin 970 GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight, 971 WithThemeSpace); 972end; 973 974class function TGtk2WSCustomCheckBox.RetrieveState( 975 const ACustomCheckBox: TCustomCheckBox): TCheckBoxState; 976var 977 ToggleButton: PGtkToggleButton; 978begin 979 ToggleButton:={%H-}PGtkToggleButton(ACustomCheckBox.Handle); 980 if gtk_toggle_button_get_inconsistent(ToggleButton) then 981 Result := cbGrayed 982 else 983 if gtk_toggle_button_get_active(ToggleButton) then 984 Result := cbChecked 985 else 986 Result := cbUnchecked; 987end; 988 989class procedure TGtk2WSCustomCheckBox.SetShortCut(const ACustomCheckBox: TCustomCheckBox; 990 const ShortCutK1, ShortCutK2: TShortCut); 991begin 992 Accelerate(ACustomCheckBox, {%H-}PGtkWidget(ACustomCheckBox.Handle), ShortcutK1, 993 'clicked' 994 //'activate_item' 995 ); 996end; 997 998class procedure TGtk2WSCustomCheckBox.SetState( 999 const ACustomCheckBox: TCustomCheckBox; const NewState: TCheckBoxState); 1000var 1001 GtkObject: PGtkObject; 1002 ToggleButton: PGtkToggleButton; 1003begin 1004 //debugln('TGtk2WSCustomCheckBox.SetState A ',DbgSName(ACustomCheckBox),' State=',dbgs(ord(ACustomCheckBox.State))); 1005 GtkObject := {%H-}PGtkObject(ACustomCheckBox.Handle); 1006 LockOnChange(GtkObject,1); 1007 ToggleButton:=PGtkToggleButton(GtkObject); 1008 gtk_toggle_button_set_inconsistent(ToggleButton, NewState=cbGrayed); 1009 gtk_toggle_button_set_active(ToggleButton, NewState=cbChecked); 1010 LockOnChange(GtkObject,-1); 1011end; 1012 1013class procedure TGtk2WSCustomCheckBox.SetFont(const AWinControl: TWinControl; 1014 const AFont: TFont); 1015var 1016 Widget: PGTKWidget; 1017 LblWidget: PGtkWidget; 1018begin 1019 if not AWinControl.HandleAllocated then exit; 1020 1021 Widget := {%H-}PGtkWidget(AWinControl.Handle); 1022 LblWidget := (pGtkBin(Widget)^.Child); 1023 if LblWidget <> nil then 1024 begin 1025 Gtk2WidgetSet.SetWidgetFont(LblWidget, AFont); 1026 Gtk2WidgetSet.SetWidgetColor(LblWidget, AFont.Color, clNone, 1027 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 1028 end; 1029end; 1030 1031class procedure TGtk2WSCustomCheckBox.SetText(const AWinControl: TWinControl; 1032 const AText: String); 1033var 1034 BoxWidget: PGtkWidget; 1035 B: Boolean; 1036 P: PGChar; 1037begin 1038 if not WSCheckHandleAllocated(AWincontrol, 'SetText') then Exit; 1039 BoxWidget := {%H-}PGtkWidget(AWinControl.Handle); 1040 if AText = '' then 1041 begin 1042 gtk_button_set_label(PGtkButton(BoxWidget), ''); 1043 gtk_widget_hide(PGtkBin(BoxWidget)^.child); 1044 end else 1045 begin 1046 P := gtk_label_get_text(PGtkLabel(PGtkBin(BoxWidget)^.child)); 1047 B := (StrPas(P) <> AText); 1048 gtk_widget_show(PGtkBin(BoxWidget)^.child); 1049 gtk_button_set_label(PGtkButton(BoxWidget), PChar(Ampersands2Underscore(AText))); 1050 gtk_button_set_use_underline(PGtkButton(BoxWidget), True); 1051 if B then 1052 begin 1053 SetColor(AWinControl); 1054 SetFont(AWinControl, AWinControl.Font); 1055 end; 1056 end; 1057end; 1058 1059class procedure TGtk2WSCustomCheckBox.ShowHide(const AWinControl: TWinControl); 1060begin 1061 // gtk2 doesn't set font properly 1062 // so we are doing it one more time before showing. Issues #21172, #23152 1063 if AWinControl.HandleObjectShouldBeVisible then 1064 begin 1065 SetFont(AWinControl, AWinControl.Font); 1066 AWinControl.InvalidatePreferredSize(); 1067 AWinControl.AdjustSize(); 1068 end; 1069 TGtk2WSWinControl.ShowHide(AWinControl); 1070end; 1071 1072{$I gtk2wscustommemo.inc} 1073 1074{ TGtk2WSCustomEdit } 1075 1076class procedure TGtk2WSCustomEdit.SetCallbacks(const AGtkWidget: PGtkWidget; 1077 const AWidgetInfo: PWidgetInfo); 1078begin 1079 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 1080 1081 with TGtk2Widgetset(Widgetset) do 1082 begin 1083 SetCallback(LM_CHANGED, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject); 1084 SetCallback(LM_ACTIVATE, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject); 1085 SetCallback(LM_CUT, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject); 1086 SetCallback(LM_COPY, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject); 1087 SetCallback(LM_PASTE, PGtkObject(AGtkWidget), AWidgetInfo^.LCLObject); 1088 end; 1089 1090 g_signal_connect_after(PGtkObject(AGtkWidget), 'populate-popup', 1091 gtk_signal_func(@gtkDefaultPopupMenuCloseFix), AWidgetInfo); 1092end; 1093 1094class procedure TGtk2WSCustomEdit.GetPreferredSize(const AWinControl: TWinControl; 1095 var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); 1096begin 1097 GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight, 1098 WithThemeSpace); 1099 //debugln('TGtkWSCustomEdit.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight)); 1100end; 1101 1102class procedure TGtk2WSCustomEdit.SetColor(const AWinControl: TWinControl); 1103var 1104 AWidget: PGTKWidget; 1105begin 1106 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit; 1107 AWidget := {%H-}PGtkWidget(AWinControl.Handle); 1108 // don't change selected state 1109 Gtk2WidgetSet.SetWidgetColor(AWidget, clNone, AWinControl.Color, 1110 [GTK_STATE_NORMAL, GTK_STYLE_BASE]); 1111end; 1112 1113 1114class procedure TGtk2WSCustomEdit.SetText(const AWinControl: TWinControl; 1115 const AText: string); 1116var 1117 Widget: PGtkWidget; 1118 Mess : TLMessage; 1119begin 1120 if not WSCheckHandleAllocated(AWinControl, 'SetText') then 1121 Exit; 1122 {$IFDEF VerboseTWinControlRealText} 1123 DebugLn(['TGtkWSCustomEdit.SetText START ',DbgSName(AWinControl),' AText="',AText,'"']); 1124 {$ENDIF} 1125 Widget:={%H-}PGtkWidget(AWinControl.Handle); 1126 // some gtk2 versions fire the change event twice 1127 // lock the event and send the message afterwards 1128 // see bug http://bugs.freepascal.org/view.php?id=14615 1129 LockOnChange(PgtkObject(Widget), +1); 1130 try 1131 if GTK_IS_SPIN_BUTTON(Widget) then 1132 gtk_entry_set_text(@PGtkSpinButton(Widget)^.entry, PChar(AText)) 1133 else 1134 gtk_entry_set_text(PGtkEntry(Widget), PChar(AText)); 1135 finally 1136 LockOnChange(PgtkObject(Widget), -1); 1137 end; 1138 SetSelStart(TCustomEdit(AWinControl), 0); 1139 {$IFDEF VerboseTWinControlRealText} 1140 DebugLn(['TGtkWSCustomEdit.SetText SEND TEXTCHANGED message ',DbgSName(AWinControl),' New="',gtk_entry_get_text(PGtkEntry(AWinControl.Handle)),'"']); 1141 {$ENDIF} 1142 FillByte(Mess{%H-},SizeOf(Mess),0); 1143 Mess.Msg := CM_TEXTCHANGED; 1144 DeliverMessage(AWinControl, Mess); 1145 1146 {$IFDEF VerboseTWinControlRealText} 1147 DebugLn(['TGtkWSCustomEdit.SetText END ',DbgSName(AWinControl),' New="',gtk_entry_get_text(PGtkEntry(AWinControl.Handle)),'"']); 1148 {$ENDIF} 1149end; 1150 1151class procedure TGtk2WSCustomEdit.SetSelText(const ACustomEdit: TCustomEdit; 1152 const NewSelText: string); 1153var 1154 Widget: PGtkWidget; 1155 Entry: PGtkEntry; 1156 Text: string; 1157 SelStart: Integer; 1158 Mess : TLMessage; 1159begin 1160 if not WSCheckHandleAllocated(ACustomEdit, 'SetSelText') then 1161 Exit; 1162 Widget:={%H-}PGtkWidget(ACustomEdit.Handle); 1163 if GTK_IS_SPIN_BUTTON(Widget) then 1164 Entry := @PGtkSpinButton(Widget)^.entry 1165 else 1166 Entry := PGtkEntry(Widget); 1167 Text := gtk_entry_get_text(Entry); 1168 SelStart := GetSelStart(ACustomEdit); 1169 Text := UTF8Copy(Text, 1, SelStart) + NewSelText + 1170 UTF8Copy(Text, SelStart + GetSelLength(ACustomEdit) + 1, MaxInt); 1171 SelStart := SelStart + UTF8Length(NewSelText); 1172 // some gtk2 versions fire the change event twice 1173 // lock the event and send the message afterwards 1174 // see bug http://bugs.freepascal.org/view.php?id=14615 1175 LockOnChange(PgtkObject(Widget), +1); 1176 try 1177 gtk_entry_set_text(Entry, PChar(Text)); 1178 finally 1179 LockOnChange(PgtkObject(Widget), -1); 1180 end; 1181 SetSelStart(ACustomEdit, SelStart); 1182 FillByte(Mess{%H-},SizeOf(Mess),0); 1183 Mess.Msg := CM_TEXTCHANGED; 1184 DeliverMessage(ACustomEdit, Mess); 1185end; 1186 1187class procedure TGtk2WSCustomEdit.SetCharCase(const ACustomEdit: TCustomEdit; 1188 NewCase: TEditCharCase); 1189begin 1190 // TODO: TGtk2WSCustomEdit.SetCharCase: implement me! 1191end; 1192 1193class procedure TGtk2WSCustomEdit.SetMaxLength(const ACustomEdit: TCustomEdit; 1194 NewLength: integer); 1195var 1196 Widget: PGtkWidget; 1197begin 1198 Widget:={%H-}PGtkWidget(ACustomEdit.Handle); 1199 if GtkWidgetIsA(Widget, GTK_TYPE_ENTRY) then 1200 gtk_entry_set_max_length(GTK_ENTRY(Widget), guint16(NewLength)); 1201end; 1202 1203function CellEntryKeyDown({%H-}Widget: PGtkWidget; Event : pgdkeventkey; 1204 {%H-}Data: gPointer) : GBoolean; cdecl; 1205begin 1206 Result := (Event^.keyval = GDK_KEY_UP) or (Event^.keyval = GDK_KEY_DOWN); 1207end; 1208 1209class function TGtk2WSCustomEdit.CreateHandle(const AWinControl: TWinControl; 1210 const AParams: TCreateParams): TLCLIntfHandle; 1211var 1212 Widget: PGtkWidget; // ptr to the newly created GtkWidget 1213 WidgetInfo: PWidgetInfo; 1214 CellEditable: PGtkCellEditable; 1215begin 1216 Widget := gtk_entry_new(); 1217 gtk_editable_set_editable(PGtkEditable(Widget), not TCustomEdit(AWinControl).ReadOnly); 1218 if AParams.Style and WS_VISIBLE = 0 then 1219 gtk_widget_hide(Widget) 1220 else 1221 gtk_widget_show(Widget); 1222 Result := TLCLIntfHandle({%H-}PtrUInt(Widget)); 1223 {$IFDEF DebugLCLComponents} 1224 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 1225 {$ENDIF} 1226 if Result = 0 then 1227 Exit; 1228 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), AWinControl, AParams); 1229 Set_RC_Name(AWinControl, Widget); 1230 SetCallbacks(Widget, WidgetInfo); 1231 1232 if Result <> 0 then 1233 begin 1234 // hook into GtkEntry interface, so it won't focus another control 1235 // by pressing VK_UP or VK_DOWN. issue #11115 1236 CellEditable := GTK_CELL_EDITABLE(Widget); 1237 g_signal_connect(CellEditable, 'key_press_event', 1238 TGTKSignalFunc(@CellEntryKeyDown), AWinControl); 1239 1240 gtk_entry_set_has_frame({%H-}PGtkEntry(Result), 1241 TCustomEdit(AWinControl).BorderStyle <> bsNone); 1242 // don't select it on focus since LCL do this itself 1243 g_object_set(gtk_widget_get_settings({%H-}PGtkWidget(Result)), 1244 'gtk-entry-select-on-focus', [0, nil]); 1245 end; 1246end; 1247 1248class function TGtk2WSCustomEdit.GetCaretPos(const ACustomEdit: TCustomEdit 1249 ): TPoint; 1250var 1251 Entry: PGtkEntry; 1252 AInfo: PWidgetInfo; 1253begin 1254 Result := Point(0,0); 1255 if not WSCheckHandleAllocated(ACustomEdit, 'GetCaretPos') then 1256 Exit; 1257 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1258 if gtk_widget_has_focus(PGtkWidget(Entry)) then 1259 Result.X := Max(Entry^.current_pos, Entry^.selection_bound) 1260 else begin 1261 AInfo := GetWidgetInfo(PGtkWidget(Entry)); 1262 if AInfo <> nil then 1263 Result.X := AInfo^.CursorPos + AInfo^.SelLength; 1264 end; 1265end; 1266 1267class function TGtk2WSCustomEdit.GetSelStart(const ACustomEdit: TCustomEdit 1268 ): integer; 1269var 1270 Entry: PGtkEntry; 1271 AInfo: PWidgetInfo; 1272begin 1273 Result := 0; 1274 if not WSCheckHandleAllocated(ACustomEdit, 'GetSelStart') then 1275 Exit; 1276 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1277 if gtk_widget_has_focus(PGtkWidget(Entry)) then 1278 Result := Min(Entry^.current_pos, Entry^.selection_bound) 1279 else begin 1280 AInfo := GetWidgetInfo(PGtkWidget(Entry)); 1281 if AInfo <> nil then 1282 Result := AInfo^.CursorPos; 1283 end; 1284end; 1285 1286class function TGtk2WSCustomEdit.GetSelLength(const ACustomEdit: TCustomEdit 1287 ): integer; 1288var 1289 Entry: PGtkEntry; 1290 AInfo: PWidgetInfo; 1291begin 1292 Result := 0; 1293 if not WSCheckHandleAllocated(ACustomEdit, 'GetSelLength') then 1294 Exit; 1295 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1296 if gtk_widget_has_focus(PGtkWidget(Entry)) then 1297 Result := ABS(Entry^.current_pos - Entry^.selection_bound) 1298 else begin 1299 AInfo := GetWidgetInfo(PGtkWidget(Entry)); 1300 if AInfo <> nil then 1301 Result := AInfo^.SelLength; 1302 end; 1303end; 1304 1305function gtk2WSDelayedSelStart(Data: Pointer): gboolean; cdecl; 1306var 1307 Entry: PGtkEntry; 1308begin 1309 Result := False; 1310 Entry := PGtkEntry(PWidgetInfo(Data)^.CoreWidget); 1311 gtk_editable_set_position(PGtkEditable(Entry), PWidgetInfo(Data)^.CursorPos); 1312 g_idle_remove_by_data(Data); 1313end; 1314 1315function gtk2WSDelayedSetSelLength(Data: Pointer): gboolean; cdecl; 1316var 1317 Entry: PGtkEntry; 1318begin 1319 Result := False; 1320 Entry := PGtkEntry(PWidgetInfo(Data)^.CoreWidget); 1321 gtk_entry_select_region(Entry, 1322 PWidgetInfo(Data)^.CursorPos, 1323 PWidgetInfo(Data)^.CursorPos + PWidgetInfo(Data)^.SelLength); 1324 g_idle_remove_by_data(Data); 1325end; 1326 1327class procedure TGtk2WSCustomEdit.SetCaretPos(const ACustomEdit: TCustomEdit; 1328 const NewPos: TPoint); 1329var 1330 NewStart: Integer; 1331 Entry: PGtkEntry; 1332 WidgetInfo: PWidgetInfo; 1333begin 1334 if not WSCheckHandleAllocated(ACustomEdit, 'SetCaretPos') then 1335 Exit; 1336 SetSelLength(ACustomEdit, 0); 1337 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1338 // make gtk2 consistent with others. issue #11802 1339 // if GetCaretPos(ACustomEdit).X = NewPos.X then exit; 1340 1341 if Entry^.text_max_length > 0 then 1342 NewStart := Min(NewPos.X, Entry^.text_max_length) 1343 else 1344 NewStart := Min(NewPos.X, Entry^.text_length); 1345 WidgetInfo := GetWidgetInfo(Entry); 1346 WidgetInfo^.CursorPos := NewStart; 1347 if LockOnChange(PgtkObject(Entry),0) > 0 then 1348 begin 1349 // postpone 1350 g_idle_add(@gtk2WSDelayedSelStart, WidgetInfo); 1351 end else 1352 gtk_editable_set_position(PGtkEditable(Entry), NewStart); 1353end; 1354 1355class procedure TGtk2WSCustomEdit.SetEchoMode(const ACustomEdit: TCustomEdit; 1356 NewMode: TEchoMode); 1357var 1358 Entry: PGtkEntry; 1359begin 1360 if not WSCheckHandleAllocated(ACustomEdit, 'SetEchoMode') then 1361 Exit; 1362 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1363 if NewMode in [emNone,emPassword] then begin 1364 gtk_entry_set_visibility(Entry,false); 1365 SetPasswordChar(ACustomEdit,ACustomEdit.PasswordChar); 1366 end else begin 1367 gtk_entry_set_visibility(Entry,true); 1368 end; 1369end; 1370 1371class procedure TGtk2WSCustomEdit.SetPasswordChar( 1372 const ACustomEdit: TCustomEdit; NewChar: char); 1373var 1374 PWChar: Integer; 1375 Entry: PGtkEntry; 1376begin 1377 if not WSCheckHandleAllocated(ACustomEdit, 'SetPasswordChar') then 1378 Exit; 1379 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1380 if ACustomEdit.EchoMode=emNone then 1381 PWChar:=0 1382 else begin 1383 PWChar:=ord(ACustomEdit.PasswordChar); 1384 if (PWChar<192) or (PWChar=ord('*')) then 1385 PWChar:=9679; 1386 end; 1387 gtk_entry_set_invisible_char(Entry,PWChar); 1388end; 1389 1390class procedure TGtk2WSCustomEdit.SetReadOnly(const ACustomEdit: TCustomEdit; 1391 NewReadOnly: boolean); 1392var 1393 Widget: PGtkWidget; 1394begin 1395 Widget := {%H-}PGtkWidget(ACustomEdit.Handle); 1396 if GTK_IS_EDITABLE(Widget) then 1397 gtk_editable_set_editable(PGtkEditable(Widget), not NewReadOnly); 1398end; 1399 1400class procedure TGtk2WSCustomEdit.SetSelStart(const ACustomEdit: TCustomEdit; 1401 NewStart: integer); 1402var 1403 NewPos: Integer; 1404 Entry: PGtkEntry; 1405 WidgetInfo: PWidgetInfo; 1406begin 1407 if not WSCheckHandleAllocated(ACustomEdit, 'SetSelStart') then 1408 Exit; 1409 SetSelLength(ACustomEdit, 0); 1410 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1411 // make gtk2 consistent with others. issue #11802 1412 // if GetSelStart(ACustomEdit) = NewStart then exit; 1413 1414 if Entry^.text_max_length > 0 then 1415 NewPos := Min(NewStart, Entry^.text_max_length) 1416 else 1417 NewPos := Min(NewStart, Entry^.text_length); 1418 WidgetInfo := GetWidgetInfo(Entry); 1419 WidgetInfo^.CursorPos := NewPos; 1420 if LockOnChange(PgtkObject(Entry),0) > 0 then 1421 begin 1422 // postpone 1423 g_idle_add(@gtk2WSDelayedSelStart, WidgetInfo); 1424 end else 1425 gtk_editable_set_position(PGtkEditable(Entry), NewPos); 1426end; 1427 1428class procedure TGtk2WSCustomEdit.SetSelLength( 1429 const ACustomEdit: TCustomEdit; NewLength: integer); 1430var 1431 Entry: PGtkEntry; 1432 SelStart: Integer; 1433 WidgetInfo: PWidgetInfo; 1434begin 1435 if not WSCheckHandleAllocated(ACustomEdit, 'SetSelLength') then 1436 Exit; 1437 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1438 SelStart := GetSelStart(ACustomEdit); 1439 1440 WidgetInfo := GetWidgetInfo(Entry); 1441 if WidgetInfo^.CursorPos = 0 then 1442 WidgetInfo^.CursorPos := SelStart; 1443 WidgetInfo^.SelLength := NewLength; 1444 if LockOnChange(PgtkObject(Entry),0) > 0 then 1445 // delay setting of selection length. issue #20890 1446 g_idle_add(@gtk2WSDelayedSetSelLength, WidgetInfo) 1447 else 1448 gtk_entry_select_region(Entry, 1449 SelStart, 1450 SelStart + NewLength); 1451end; 1452 1453class procedure TGtk2WSCustomEdit.SetAlignment(const ACustomEdit: TCustomEdit; 1454 const AAlignment: TAlignment); 1455var 1456 Entry: PGtkEntry; 1457 Alignment: GFloat; 1458begin 1459 Entry := {%H-}PGtkEntry(ACustomEdit.Handle); 1460 case AAlignment of 1461 taLeftJustify: Alignment := 0; 1462 taRightJustify: Alignment := 1; 1463 taCenter: Alignment := 0.5; 1464 end; 1465 gtk_entry_set_alignment(Entry, Alignment); 1466end; 1467 1468class procedure TGtk2WSCustomEdit.Cut(const ACustomEdit: TCustomEdit); 1469var 1470 ATextView: PGtkTextView; 1471 ABuffer: PGtkTextBuffer; 1472 AStart, AStop: PGtkTextIter; 1473begin 1474 if not WSCheckHandleAllocated(ACustomEdit, 'Cut') then 1475 Exit; 1476 1477 if ACustomEdit.FCompStyle = csMemo then 1478 begin 1479 ATextView := GTK_TEXT_VIEW(GetWidgetInfo({%H-}PGtkWidget(ACustomEdit.Handle))^.CoreWidget); 1480 ABuffer := gtk_text_view_get_buffer(ATextView); 1481 if ABuffer <> nil then 1482 begin 1483 AStart := nil; 1484 AStop := nil; 1485 if gtk_text_buffer_get_selection_bounds(ABuffer, AStart, AStop) then 1486 gtk_text_buffer_cut_clipboard(ABuffer, gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), not ACustomEdit.ReadOnly); 1487 end; 1488 end else 1489 gtk_editable_cut_clipboard({%H-}PGtkEditable(ACustomEdit.Handle)); 1490end; 1491 1492class procedure TGtk2WSCustomEdit.Copy(const ACustomEdit: TCustomEdit); 1493var 1494 ATextView: PGtkTextView; 1495 ABuffer: PGtkTextBuffer; 1496 AStart, AStop: PGtkTextIter; 1497begin 1498 if not WSCheckHandleAllocated(ACustomEdit, 'Copy') then 1499 Exit; 1500 if ACustomEdit.FCompStyle = csMemo then 1501 begin 1502 ATextView := GTK_TEXT_VIEW(GetWidgetInfo({%H-}PGtkWidget(ACustomEdit.Handle))^.CoreWidget); 1503 ABuffer := gtk_text_view_get_buffer(ATextView); 1504 if ABuffer <> nil then 1505 begin 1506 AStart := nil; 1507 AStop := nil; 1508 if gtk_text_buffer_get_selection_bounds(ABuffer, AStart, AStop) then 1509 gtk_text_buffer_copy_clipboard(ABuffer, gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); 1510 end; 1511 end else 1512 gtk_editable_copy_clipboard({%H-}PGtkEditable(ACustomEdit.Handle)); 1513end; 1514 1515class procedure TGtk2WSCustomEdit.Paste(const ACustomEdit: TCustomEdit); 1516var 1517 ATextView: PGtkTextView; 1518 ABuffer: PGtkTextBuffer; 1519begin 1520 if not WSCheckHandleAllocated(ACustomEdit, 'Paste') then 1521 Exit; 1522 if ACustomEdit.FCompStyle = csMemo then 1523 begin 1524 ATextView := GTK_TEXT_VIEW(GetWidgetInfo({%H-}PGtkWidget(ACustomEdit.Handle))^.CoreWidget); 1525 ABuffer := gtk_text_view_get_buffer(ATextView); 1526 if ABuffer <> nil then 1527 gtk_text_buffer_paste_clipboard(ABuffer, 1528 gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), nil, not ACustomEdit.ReadOnly); 1529 end else 1530 gtk_editable_paste_clipboard({%H-}PGtkEditable(ACustomEdit.Handle)); 1531end; 1532 1533class procedure TGtk2WSCustomEdit.Undo(const ACustomEdit: TCustomEdit); 1534begin 1535 if not WSCheckHandleAllocated(ACustomEdit, 'Undo') then 1536 Exit; 1537 //TODO: I cannot find anything usefull in gtk2 to do this, seem 1538 //that we have to make our own implementation. 1539end; 1540 1541class procedure TGtk2WSCustomComboBox.ReCreateCombo( 1542 const ACustomComboBox: TCustomComboBox; const AWithEntry: Boolean; 1543 const AWidgetInfo: PWidgetInfo); 1544var 1545 ComboWidget: PGtkWidget; 1546 Model: PGtkTreeModel; 1547 Index: Integer; 1548 Box: PGtkWidget; 1549 ItemList: TGtkListStoreStringList; 1550 LCLIndex: PLongint; 1551begin 1552 Box:={%H-}PGtkWidget(ACustomComboBox.Handle); 1553 ComboWidget := AWidgetInfo^.CoreWidget; 1554 1555 // keep the model (increase ref count) 1556 Model := gtk_combo_box_get_model(PGtkComboBox(ComboWidget)); 1557 g_object_ref(G_OBJECT(Model)); 1558 // keep items 1559 ItemList := ACustomComboBox.Items as TGtkListStoreStringList; 1560 1561 LCLIndex := AWidgetInfo^.UserData; 1562 if not Assigned(LCLIndex) then begin 1563 //debugln('Gtk2WSCustomComboBox ReCreateCombo: LCLIndex unassigned!'); 1564 LCLIndex := New(PLongint); 1565 LCLIndex^ := -1; 1566 AWidgetInfo^.UserData := LCLIndex; 1567 AWidgetInfo^.DataOwner := True; 1568 end; 1569 1570 Index := GetItemIndex(ACustomComboBox); 1571 1572 if PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button <> nil then 1573 FreeWidgetInfo(PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button); 1574 1575 gtk_event_box_set_above_child(PGtkEventBox(Box), false); 1576 // don't remove Combo from Box, just destroy it and during destroy it will 1577 // be removed by gtk code. Removing from Box and then destroyng can lead to 1578 // double destroying since removing decrease reference and it can be the 1579 // last reference 1580 gtk_widget_destroy(ComboWidget); 1581 1582 // create the new widget with the old model 1583 case AWithEntry of 1584 True : ComboWidget := gtk_combo_box_entry_new_with_model(Model, 0); 1585 False: ComboWidget := gtk_combo_box_new_with_model(Model); 1586 end; 1587 SetSensitivity(ACustomCombobox, ComboWidget); 1588 // undone the above increase of the ref count 1589 g_object_set_data(PGObject(ComboWidget),GtkListItemLCLListTag,ItemList); 1590 g_object_unref (G_OBJECT(Model)); 1591 1592 SetMainWidget(Box, GTK_BIN(ComboWidget)^.child); 1593 AWidgetInfo^.CoreWidget := ComboWidget; 1594 g_object_set_data(Pointer(ComboWidget), 'widgetinfo', AWidgetInfo); 1595 1596 SetItemIndex(ACustomComboBox, Index); 1597 1598 if AWithEntry then begin 1599 SetMaxLength(ACustomComboBox, TComboBox(ACustomComboBox).MaxLength); 1600 end; 1601 1602 SetRenderer(ACustomComboBox, ComboWidget, AWidgetInfo); 1603 1604 gtk_container_add(PGtkContainer(Box), ComboWidget); 1605 gtk_widget_show_all(Box); 1606 if ACustomComboBox.HandleObjectShouldBeVisible then 1607 gtk_widget_show(Box) 1608 else 1609 gtk_widget_hide(Box); 1610 if csDesigning in ACustomComboBox.ComponentState then 1611 gtk_event_box_set_above_child(PGtkEventBox(Box), true); 1612 1613 SetCallbacks(ACustomComboBox, Box, AWidgetInfo); 1614end; 1615 1616class procedure TGtk2WSCustomComboBox.SetRenderer( 1617 const ACustomComboBox: TCustomComboBox; AWidget: PGtkWidget; AWidgetInfo: PWidgetInfo); 1618var 1619 renderer : PGtkCellRenderer; 1620begin 1621 renderer := LCLIntfCellRenderer_New(); 1622 g_object_set_data(G_OBJECT(renderer), 'widgetinfo', AWidgetInfo); 1623 gtk_cell_layout_clear(PGtkCellLayout(AWidget)); 1624 gtk_cell_layout_pack_start(PGtkCellLayout(AWidget), renderer, True); 1625 if not (ACustomComboBox.Style in [csOwnerDrawFixed, csOwnerDrawVariable, csOwnerDrawEditableFixed, csOwnerDrawEditableVariable]) then 1626 gtk_cell_layout_set_attributes(PGtkCellLayout(AWidget), renderer, ['text', 0, nil]); 1627 gtk_cell_layout_set_cell_data_func(PGtkCellLayout(AWidget), renderer, 1628 @LCLIntfCellRenderer_CellDataFunc, AWidgetInfo, nil); 1629end; 1630 1631procedure GtkComboFocus({%H-}AWidget: PGtkWidget; WidgetInfo: PWidgetInfo); cdecl; 1632begin 1633 LCLSendSetFocusMsg(TControl(WidgetInfo^.LCLObject)); 1634end; 1635 1636{used only for gtk2 < 2.10 } 1637procedure GtkPopupShowCB({%H-}AMenu: PGtkMenuShell; WidgetInfo: PWidgetInfo); cdecl; 1638begin 1639 g_object_set_data(PGObject(WidgetInfo^.CoreWidget), 1640 'popup-shown-compat',GPointer(PtrUInt(1))); 1641 LCLSendSetFocusMsg(TControl(WidgetInfo^.LCLObject)); 1642 // let the LCL change the items on the fly: 1643 LCLSendDropDownMsg(TControl(WidgetInfo^.LCLObject)); 1644end; 1645 1646{used only for gtk2 < 2.10 } 1647procedure GtkPopupHideCB({%H-}AMenu: PGtkMenuShell; WidgetInfo: PWidgetInfo); cdecl; 1648begin 1649 g_object_set_data(PGObject(WidgetInfo^.CoreWidget), 1650 'popup-shown-compat',GPointer(PtrUInt(0))); 1651 LCLSendCloseUpMsg(TControl(WidgetInfo^.LCLObject)); 1652end; 1653 1654function GtkPopupCloseUp(WidgetInfo: Pointer): gboolean; cdecl; 1655begin 1656 LCLSendCloseUpMsg(TControl(PWidgetInfo(WidgetInfo)^.LCLObject)); 1657 Result := gtk_False;// stop the timer 1658end; 1659 1660procedure GtkNotifyCB(AObject: PGObject; pspec: PGParamSpec; WidgetInfo: PWidgetInfo); cdecl; 1661var 1662 AValue: TGValue; 1663 AMenu: PGtkWidget; 1664 ComboBox: TCustomComboBox; 1665begin 1666 if pspec^.name = 'popup-shown' then 1667 begin 1668 LCLSendSetFocusMsg(TControl(WidgetInfo^.LCLObject)); 1669 FillChar(AValue{%H-}, SizeOf(AValue), 0); // fill by zeros 1670 g_value_init(@AValue, G_TYPE_BOOLEAN); // initialize for boolean 1671 g_object_get_property(AObject, pspec^.name, @AValue); // get property value 1672 if AValue.data[0].v_int = 0 then // if 0 = False then it is close up 1673 gtk_timeout_add(0,@GtkPopupCloseUp, WidgetInfo) 1674 else // in other case it is drop down 1675 begin 1676 ComboBox:=WidgetInfo^.LCLObject as TCustomComboBox; 1677 ComboBox.IntfGetItems; 1678 LCLSendDropDownMsg(ComboBox); 1679 AMenu := PGtkComboBoxPrivate(PGtkComboBox(WidgetInfo^.CoreWidget)^.priv)^.popup_widget; 1680 if GTK_IS_MENU(AMenu) then 1681 gtk_menu_reposition(PGtkMenu(AMenu)); 1682 end; 1683 end; 1684end; 1685 1686procedure GtkChangedCB({%H-}AWidget: PGtkWidget; WidgetInfo: PWidgetInfo); cdecl; 1687var 1688 LCLIndex: PLongint; 1689 Index, GtkIndex: Integer; 1690begin 1691 if WidgetInfo^.ChangeLock > 0 then Exit; 1692 LCLSendChangedMsg(TControl(WidgetInfo^.LCLObject)); 1693 1694 Index := -1; 1695 LCLIndex := WidgetInfo^.UserData; 1696 if Assigned(LCLIndex) then 1697 Index := LCLIndex^ 1698 else 1699 debugln('Gtk2WSCustomComboBox GtkChangedCB: LCLIndex unassigned!'); 1700 1701 GtkIndex := gtk_combo_box_get_active(GTK_COMBO_BOX(WidgetInfo^.CoreWidget)); 1702 if Index <> GtkIndex then begin 1703 LCLSendSelectionChangedMsg(TControl(WidgetInfo^.LCLObject)); 1704 if Assigned(LCLIndex) then 1705 LCLIndex^ := GtkIndex; 1706 end; 1707end; 1708 1709{procedure GtkSelectedCB(AWidget: PGtkWidget; WidgetInfo: PWidgetInfo); cdecl; 1710begin 1711 if WidgetInfo^.UserData <> nil then Exit; 1712 LCLSendSelectionChangedMsg(TControl(WidgetInfo^.LCLObject)); 1713end;} 1714 1715class procedure TGtk2WSCustomComboBox.SetCallbacks( 1716 const AWinControl: TWinControl; const AWidget: PGtkWidget; 1717 const AWidgetInfo: PWidgetInfo); 1718var 1719 AGtkObject: PGtkObject; 1720 AEntry: PGtkObject; 1721 AButton: PGtkObject; 1722 APrivate: PGtkComboBoxPrivate; 1723 AMenu: PGtkObject; 1724 BtnPressID: guint; 1725 HandlerID: guint; 1726 ComboWidget: PGtkComboBox; 1727 InputObject: PGtkObject; 1728begin 1729 ComboWidget:=PGtkComboBox(AWidgetInfo^.CoreWidget); 1730 AGtkObject := PGtkObject(AWidget); 1731 AEntry := PGtkObject(GetComboBoxEntry(PGtkWidget(ComboWidget))); 1732 APrivate := PGtkComboBoxPrivate(ComboWidget^.priv); 1733 AButton := PGtkObject(APrivate^.button); 1734 //DebugLn(['TGtk2WSCustomComboBox.SetCallbacks ',dbgsName(AWinControl),' AButton=',GetWidgetClassName(PGtkWidget(AButton)),' ComboWidget=',GetWidgetClassName(PGtkWidget(ComboWidget))]); 1735 1736 // we have to remove the handler gtk sets up to get the mouse down messages 1737 if AButton <> nil then 1738 begin 1739 BtnPressID := g_signal_lookup('button_press_event', GTK_TYPE_COMBO_BOX); 1740 HandlerID := g_signal_handler_find(AButton, G_SIGNAL_MATCH_ID, BtnPressID, 0, nil, nil, nil); 1741 if HandlerID > 0 then 1742 g_signal_handler_disconnect(AButton, HandlerID); 1743 end; 1744 1745 g_signal_connect(ComboWidget, 'changed', TGCallback(@GtkChangedCB), AWidgetInfo); 1746 1747 // First the combo (or the entry) 1748 if gtk_is_combo_box_entry(ComboWidget) then 1749 InputObject := AEntry 1750 else 1751 InputObject := AGtkObject; 1752 1753 if TCustomComboBox(AWinControl).Style in [csDropDownList, csOwnerDrawFixed, csOwnerDrawVariable] then 1754 begin 1755 // Just a combobox without a edit should handle its own keys. Issue #32458 1756 Gtk2WidgetSet.SetCallbackDirect(LM_KEYDOWN, InputObject, AWinControl); 1757 Gtk2WidgetSet.SetCallbackDirect(LM_KEYUP, InputObject, AWinControl); 1758 Gtk2WidgetSet.SetCallbackDirect(LM_CHAR, InputObject, AWinControl); 1759 end; 1760 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEMOVE, InputObject, AWinControl); 1761 Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONDOWN, InputObject, AWinControl); 1762 Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONUP, InputObject, AWinControl); 1763 Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONDBLCLK, InputObject, AWinControl); 1764 Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONDBLCLK, InputObject, AWinControl); 1765 Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONDBLCLK, InputObject, AWinControl); 1766 Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONDOWN, InputObject, AWinControl); 1767 Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONUP, InputObject, AWinControl); 1768 Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONDOWN, InputObject, AWinControl); 1769 Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONUP, InputObject, AWinControl); 1770 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEWHEEL, InputObject, AWinControl); 1771 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEHWHEEL, InputObject, AWinControl); 1772 Gtk2WidgetSet.SetCallbackDirect(LM_PAINT, InputObject, AWinControl); 1773 Gtk2WidgetSet.SetCallbackDirect(LM_FOCUS, InputObject, AWinControl); 1774 1775 // And now the same for the Button in the combo 1776 if AButton<>nil then begin 1777 if TCustomComboBox(AWinControl).Style in [csDropDownList, csOwnerDrawFixed, csOwnerDrawVariable] then 1778 begin 1779 // Just a combobox without a edit should handle its own keys. Issue #32458 1780 Gtk2WidgetSet.SetCallbackDirect(LM_KEYDOWN, AButton, AWinControl); 1781 Gtk2WidgetSet.SetCallbackDirect(LM_KEYUP, AButton, AWinControl); 1782 Gtk2WidgetSet.SetCallbackDirect(LM_CHAR, AButton, AWinControl); 1783 end; 1784 if not GtkWidgetIsA(PGtkWidget(AButton),GTK_TYPE_CELL_VIEW) then begin 1785 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEENTER, AButton, AWinControl); 1786 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSELEAVE, AButton, AWinControl); 1787 end; 1788 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEMOVE, AButton, AWinControl); 1789 Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONDOWN, AButton, AWinControl); 1790 Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONUP, AButton, AWinControl); 1791 Gtk2WidgetSet.SetCallbackDirect(LM_LBUTTONUP, AButton, AWinControl); 1792 Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONDOWN, AButton, AWinControl); 1793 Gtk2WidgetSet.SetCallbackDirect(LM_RBUTTONUP, AButton, AWinControl); 1794 Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONDOWN, AButton, AWinControl); 1795 Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONUP, AButton, AWinControl); 1796 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEWHEEL, AButton, AWinControl); 1797 Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEHWHEEL, AButton, AWinControl); 1798 Gtk2WidgetSet.SetCallbackDirect(LM_PAINT, AButton, AWinControl); 1799 Gtk2WidgetSet.SetCallbackDirect(LM_FOCUS, AButton, AWinControl); 1800 end; 1801 1802 // if we are a GtkComboBoxEntry 1803 if not GtkWidgetIsA(PGtkWidget(AEntry), GTK_TYPE_ENTRY) then 1804 g_signal_connect(Combowidget, 'grab-focus', TGCallback(@GtkComboFocus), AWidgetInfo); 1805 1806 AMenu := nil; 1807 if (APrivate^.popup_widget <> nil) 1808 and (GTK_IS_MENU(APrivate^.popup_widget)) then 1809 AMenu := GTK_OBJECT(APrivate^.popup_widget) 1810 else if (APrivate^.popup_window <> nil) 1811 and (GTK_IS_MENU(APrivate^.popup_window)) then 1812 AMenu := GTK_OBJECT(APrivate^.popup_window); 1813 1814 if Assigned(AMenu) and 1815 (gtk_major_version = 2) and (gtk_minor_version < 10) then 1816 begin 1817 g_signal_connect(AMenu, 'show', G_CALLBACK(@GtkPopupShowCB), AWidgetInfo); 1818 g_signal_connect_after(AMenu, 'selection-done', G_CALLBACK(@GtkPopupHideCB), AWidgetInfo); 1819 end; 1820 1821 g_signal_connect_after(PGtkObject(GTK_BIN(ComboWidget)^.child), 'populate-popup', 1822 gtk_signal_func(@gtkDefaultPopupMenuCloseFix), AWidgetInfo); 1823 1824 if (gtk_major_version >= 2) and (gtk_minor_version >= 10) then 1825 g_signal_connect(ComboWidget, 'notify', TGCallback(@GtkNotifyCB), AWidgetInfo); 1826 1827 1828 // g_signal_connect(ComboWidget, 'set-focus-child', TGCallback(@GtkPopupShowCB), AWidgetInfo); 1829 g_object_set_data(G_OBJECT(AWidget), 'Menu', APrivate^.popup_widget); 1830end; 1831 1832class procedure TGtk2WSCustomComboBox.SetSensitivity(AWinControl: TWinControl; AWidget: PGtkWidget); 1833var 1834 Value: TGValue; 1835begin 1836 if ((gtk_major_version = 2) and (gtk_minor_version < 14)) or 1837 (csDesigning in AWinControl.ComponentState) then 1838 Exit; 1839 Value.g_type := G_TYPE_BOOLEAN; 1840 Value.data[0].v_int := longint(gTRUE); 1841 1842 g_object_set_property(PGObject(AWidget), 'button-sensitivity', @Value); 1843end; 1844 1845class procedure TGtk2WSCustomComboBox.GetPreferredSize( 1846 const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; 1847 WithThemeSpace: Boolean); 1848var 1849 Ignore: Integer; 1850begin 1851 Ignore:=0; 1852 GetGTKDefaultWidgetSize(AWinControl, Ignore, PreferredHeight, WithThemeSpace); 1853 PreferredWidth := 0; 1854end; 1855 1856class function TGtk2WSCustomComboBox.GetDroppedDown( 1857 const ACustomComboBox: TCustomComboBox): Boolean; 1858var 1859 WidgetInfo: PWidgetInfo; 1860 Combo: PGtkComboBox; 1861 AValue: TGValue; 1862begin 1863 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle), False); 1864 Combo := PGtkComboBox(WidgetInfo^.CoreWidget); 1865 1866 FillChar(AValue{%H-}, SizeOf(AValue), 0); 1867 g_value_init(@AValue, G_TYPE_BOOLEAN); 1868 if (gtk_major_version = 2) and (gtk_minor_version < 10) then 1869 begin 1870 if g_object_get_data(PGObject(Combo),'popup-shown-compat') <> nil then 1871 AValue.data[0].v_int := 1 1872 else 1873 AValue.data[0].v_int := 0; 1874 end else 1875 g_object_get_property(PGObject(Combo), 'popup-shown', @AValue); 1876 Result := AValue.data[0].v_int <> 0; 1877end; 1878 1879class function TGtk2WSCustomComboBox.GetSelStart( 1880 const ACustomComboBox: TCustomComboBox): integer; 1881var 1882 WidgetInfo: PWidgetInfo; 1883 Entry: PGtkEntry; 1884 AStart, AEnd: gint; 1885begin 1886 Result := 0; 1887 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 1888 1889 // if the combo is an editable ... 1890 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 1891 if Entry<>nil then begin 1892 if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then 1893 Result := gtk_editable_get_position(PGtkEditable(Entry)) 1894 else 1895 Result := Min(AStart, AEnd); 1896 end; 1897end; 1898 1899class function TGtk2WSCustomComboBox.GetSelLength( 1900 const ACustomComboBox: TCustomComboBox): integer; 1901var 1902 WidgetInfo: PWidgetInfo; 1903 Entry: PGtkEntry; 1904 AStart, AEnd: gint; 1905begin 1906 Result := 0; 1907 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 1908 1909 // if the combo is an editable ... 1910 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 1911 if Entry<>nil then 1912 begin 1913 if not gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) then 1914 Exit(0); 1915 Result := ABS(AStart - AEnd); 1916 end; 1917end; 1918 1919class function TGtk2WSCustomComboBox.GetItemIndex( 1920 const ACustomComboBox: TCustomComboBox): integer; 1921var 1922 WidgetInfo: PWidgetInfo; 1923begin 1924 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 1925 1926 Result := gtk_combo_box_get_active(PGtkComboBox(WidgetInfo^.CoreWidget)); 1927end; 1928 1929class function TGtk2WSCustomComboBox.GetMaxLength( 1930 const ACustomComboBox: TCustomComboBox): integer; 1931var 1932 WidgetInfo: PWidgetInfo; 1933 Entry: PGtkEntry; 1934begin 1935 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 1936 1937 // if the combo is an editable ... 1938 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 1939 if Entry<>nil then begin 1940 Result := gtk_entry_get_max_length(Entry); 1941 end 1942 else begin 1943 Result := integer({%H-}PtrUInt(g_object_get_data(PGObject(WidgetInfo^.CoreWidget), 'max-length'))); 1944 end; 1945end; 1946 1947class function TGtk2WSCustomComboBox.GetText(const AWinControl: TWinControl; 1948 var AText: String): Boolean; 1949var 1950 WidgetInfo: PWidgetInfo; 1951 Entry: PGtkEntry; 1952 Index: Integer; 1953begin 1954 Result := True; 1955 WidgetInfo := GetWidgetInfo({%H-}Pointer(AWinControl.Handle)); 1956 1957 // if the combo is an editable ... 1958 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 1959 if Entry<>nil then begin 1960 AText := gtk_entry_get_text(Entry); 1961 exit; 1962 end; 1963 1964 // if we are a fixed un-editable combo then ... 1965 Index := GetItemIndex(TCustomComboBox(AWinControl)); 1966 if Index > -1 then AText := TCustomComboBox(AWinControl).Items.Strings[Index]; 1967end; 1968 1969class procedure TGtk2WSCustomComboBox.SetArrowKeysTraverseList( 1970 const ACustomComboBox: TCustomComboBox; NewTraverseList: boolean); 1971begin 1972 // TODO: TGtk2WSCustomComboBox.SetArrowKeysTraverseList: not supported 1973 // This is not an option that is available for this widget 1974 // we will have to eat the keystrokes to set this to false 1975end; 1976 1977class procedure TGtk2WSCustomComboBox.SetDroppedDown( 1978 const ACustomComboBox: TCustomComboBox; ADroppedDown: Boolean); 1979var 1980 WidgetInfo: PWidgetInfo; 1981 Combo: PGtkComboBox; 1982begin 1983 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle), False); 1984 Combo := PGtkComboBox(WidgetInfo^.CoreWidget); 1985 1986 case ADroppedDown of 1987 True : gtk_combo_box_popup(Combo); 1988 False: gtk_combo_box_popdown(Combo); 1989 end; 1990end; 1991 1992class procedure TGtk2WSCustomComboBox.SetSelStart( 1993 const ACustomComboBox: TCustomComboBox; NewStart: integer); 1994var 1995 WidgetInfo: PWidgetInfo; 1996 Entry: PGtkEntry; 1997begin 1998 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 1999 2000 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 2001 if Entry<>nil then begin 2002 //gtk_entry_select_region(Entry, NewStart, NewStart); 2003 gtk_editable_set_position(PGtkEditable(Entry), NewStart); 2004 end; 2005end; 2006 2007class procedure TGtk2WSCustomComboBox.SetSelLength( 2008 const ACustomComboBox: TCustomComboBox; NewLength: integer); 2009var 2010 WidgetInfo: PWidgetInfo; 2011 Entry: PGtkEntry; 2012 Start: Integer; 2013begin 2014 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 2015 2016 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 2017 if Entry<>nil then begin 2018 Start := GetSelStart(ACustomComboBox); 2019 gtk_editable_select_region(PGtkEditable(Entry), Start, Start + NewLength); 2020 end; 2021end; 2022 2023class procedure TGtk2WSCustomComboBox.SetItemIndex( 2024 const ACustomComboBox: TCustomComboBox; NewIndex: integer); 2025var 2026 P: PGtkWidget; 2027 WidgetInfo: PWidgetInfo; 2028 LCLIndex: PLongint; 2029begin 2030 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 2031 p := WidgetInfo^.CoreWidget; 2032 if gtk_combo_box_get_active(PGtkComboBox(p)) = NewIndex then exit; 2033 // to be delphi compatible OnChange only fires in response to user actions not program actions 2034 // so we use WidgetInfo^.ChangeLock as a flag to not signal the OnChange Event 2035 Inc(WidgetInfo^.ChangeLock); 2036 gtk_combo_box_set_active(PGtkComboBox(p), NewIndex); 2037 2038 if (NewIndex = -1) and gtk_is_combo_box_entry(p) then 2039 gtk_entry_set_text(PGtkEntry(GTK_BIN(p)^.child), PChar('')); 2040 2041 LCLIndex := WidgetInfo^.UserData; 2042 if not Assigned(LCLIndex) then 2043 begin 2044 LCLIndex := New(PLongint); 2045 WidgetInfo^.UserData := LCLIndex; 2046 WidgetInfo^.DataOwner := True; 2047 end; 2048 LCLIndex^ := NewIndex; 2049 2050 Dec(WidgetInfo^.ChangeLock); 2051end; 2052 2053class procedure TGtk2WSCustomComboBox.SetMaxLength( 2054 const ACustomComboBox: TCustomComboBox; NewLength: integer); 2055var 2056 WidgetInfo: PWidgetInfo; 2057 Entry: PGtkEntry; 2058begin 2059 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 2060 2061 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 2062 if Entry<>nil then begin 2063 gtk_entry_set_max_length(Entry, NewLength); 2064 end; 2065 // We save this in the CoreWidget for when the Entry Changes styles 2066 g_object_set_data(PGObject(WidgetInfo^.CoreWidget), 'max-length', {%H-}Pointer(PtrInt(NewLength))); 2067end; 2068 2069class procedure TGtk2WSCustomComboBox.SetStyle( 2070 const ACustomComboBox: TCustomComboBox; NewStyle: TComboBoxStyle); 2071var 2072 WidgetInfo: PWidgetInfo; 2073 p: PGtkWidget; 2074 NeedEntry: Boolean; 2075begin 2076 WidgetInfo := GetWidgetInfo({%H-}Pointer(ACustomComboBox.Handle)); 2077 p := WidgetInfo^.CoreWidget; 2078 case NewStyle of 2079 csDropDown, 2080 csSimple, 2081 csOwnerDrawEditableFixed, 2082 csOwnerDrawEditableVariable: 2083 NeedEntry := True; 2084 csDropDownList, 2085 csOwnerDrawFixed, 2086 csOwnerDrawVariable: 2087 NeedEntry := False; 2088 end; 2089 if gtk_is_combo_box_entry(p) = NeedEntry then Exit; 2090 ReCreateCombo(ACustomComboBox, NeedEntry, WidgetInfo); 2091end; 2092 2093class function TGtk2WSCustomComboBox.GetItems( 2094 const ACustomComboBox: TCustomComboBox): TStrings; 2095var 2096 ComboWidget: PGtkWidget; 2097 Handle: HWND; 2098begin 2099 Handle := ACustomComboBox.Handle; 2100 ComboWidget := GetWidgetInfo({%H-}Pointer(Handle), True)^.CoreWidget; 2101 Result := TGtkListStoreStringList(g_object_get_data(PGObject(ComboWidget), 2102 GtkListItemLCLListTag)); 2103end; 2104 2105class procedure TGtk2WSCustomComboBox.Sort(const ACustomComboBox: TCustomComboBox; 2106 AList: TStrings; IsSorted: boolean); 2107var 2108 ComboWidget: PGtkWidget; 2109 Handle: HWND; 2110begin 2111 Handle := ACustomComboBox.Handle; 2112 ComboWidget := GetWidgetInfo({%H-}Pointer(Handle), True)^.CoreWidget; 2113 TGtkListStoreStringList(g_object_get_data(PGObject(ComboWidget), 2114 GtkListItemLCLListTag)).Sorted := IsSorted; 2115end; 2116 2117class procedure TGtk2WSCustomComboBox.SetColor(const AWinControl: TWinControl); 2118var 2119 WidgetInfo: PWidgetInfo; 2120 Child: PGtkWidget; // can be GtkCellRenderer or GtkEntry 2121begin 2122 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then 2123 Exit; 2124 WidgetInfo := GetWidgetInfo({%H-}Pointer(AWinControl.Handle)); 2125 2126 Child := GTK_BIN(WidgetInfo^.CoreWidget)^.child; 2127 Gtk2WidgetSet.SetWidgetColor(Child, AWinControl.Font.Color, AWinControl.Color, 2128 [GTK_STATE_NORMAL,GTK_STYLE_BASE]); 2129end; 2130 2131class procedure TGtk2WSCustomComboBox.SetFont(const AWinControl: TWinControl; 2132 const AFont: TFont); 2133var 2134 Entry: PGtkEntry; 2135 WidgetInfo: PWidgetInfo; 2136 W: PGtkWidget; 2137begin 2138 if not AWinControl.HandleAllocated then exit; 2139 2140 WidgetInfo := GetWidgetInfo({%H-}Pointer(AWinControl.Handle)); 2141 Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget); 2142 2143 if Entry <> nil then 2144 begin 2145 Gtk2WidgetSet.SetWidgetColor(PGtkWidget(Entry), AFont.Color, clNone, 2146 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,GTK_STYLE_TEXT]); 2147 Gtk2WidgetSet.SetWidgetFont(PGtkWidget(Entry), AFont); 2148 end else 2149 begin 2150 W := GTK_BIN(WidgetInfo^.CoreWidget)^.child; 2151 if W <> nil then 2152 begin 2153 Gtk2WidgetSet.SetWidgetColor(W, AFont.Color, clNone, 2154 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED,GTK_STYLE_TEXT]); 2155 Gtk2WidgetSet.SetWidgetFont(W, AFont); 2156 end; 2157 end; 2158end; 2159 2160class procedure TGtk2WSCustomComboBox.SetText(const AWinControl: TWinControl; 2161 const AText: String); 2162var 2163 WidgetInfo: PWidgetInfo; 2164 Entry: PGtkWidget; 2165begin 2166 WidgetInfo := GetWidgetInfo({%H-}Pointer(AWinControl.Handle)); 2167 // we use user ChangeLock to not signal onchange 2168 Inc(WidgetInfo^.ChangeLock); 2169 if gtk_is_combo_box_entry(WidgetInfo^.CoreWidget) then 2170 begin 2171 Entry := GTK_BIN(WidgetInfo^.CoreWidget)^.child; 2172 gtk_entry_set_text(PGtkEntry(Entry), PChar(AText)); 2173 end; 2174 Dec(WidgetInfo^.ChangeLock); 2175end; 2176 2177class procedure TGtk2WSCustomComboBox.ShowHide(const AWinControl: TWinControl); 2178begin 2179 Gtk2WidgetSet.SetVisible(AWinControl, AWinControl.HandleObjectShouldBeVisible); 2180 InvalidateLastWFPResult(AWinControl, AWinControl.BoundsRect); 2181end; 2182 2183class function TGtk2WSCustomComboBox.CanFocus(const AWinControl: TWinControl 2184 ): boolean; 2185var 2186 WidgetInfo: PWidgetInfo; 2187 Entry: PGtkWidget; 2188begin 2189 if not AWinControl.HandleAllocated then exit(false); 2190 WidgetInfo := GetWidgetInfo({%H-}Pointer(AWinControl.Handle)); 2191 if gtk_is_combo_box_entry(WidgetInfo^.CoreWidget) then begin 2192 Entry := GTK_BIN(WidgetInfo^.CoreWidget)^.child; 2193 Result:=GTK_WIDGET_CAN_FOCUS(Entry); 2194 end else begin 2195 Result:=inherited CanFocus(AWinControl); 2196 end; 2197 //DebugLn(['TGtk2WSCustomComboBox.CanFocus ',dbgsName(AWinControl),' ',gtk_is_combo_box_entry(WidgetInfo^.CoreWidget),' Result=',Result]); 2198end; 2199 2200class function TGtk2WSCustomComboBox.CreateHandle(const AWinControl: TWinControl; 2201 const AParams: TCreateParams): TLCLIntfHandle; 2202var 2203 Box, // this makes it easy to switch between GtkComBox and GtkComboBoxEntry 2204 ComboWidget: PGtkWidget; // ptr to the newly created GtkWidget 2205 ListStore : PGtkListStore; 2206 WidgetInfo: PWidgetInfo; 2207 ACustomComboBox: TCustomComboBox; 2208 ItemList: TGtkListStoreStringList; 2209 LCLIndex: PLongint; 2210 NeedEntry: Boolean; 2211begin 2212 ACustomComboBox := TCustomComboBox(AWinControl); 2213 2214 Box := gtk_event_box_new; 2215 {$IFDEF DebugLCLComponents} 2216 DebugGtkWidgets.MarkCreated(Box,dbgsName(AWinControl)); 2217 {$ENDIF} 2218 2219 WidgetInfo := CreateWidgetInfo(Box, AWinControl, AParams); 2220 2221 ListStore := gtk_list_store_new (2, [G_TYPE_STRING, G_TYPE_POINTER, nil]); 2222 2223 case ACustomComboBox.Style of 2224 csDropDown, 2225 csSimple, 2226 csOwnerDrawEditableFixed, 2227 csOwnerDrawEditableVariable: 2228 NeedEntry := True; 2229 csDropDownList, 2230 csOwnerDrawFixed, 2231 csOwnerDrawVariable: 2232 NeedEntry := False; 2233 end; 2234 if NeedEntry then 2235 ComboWidget := gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL (ListStore), 0) 2236 else 2237 ComboWidget := gtk_combo_box_new_with_model(GTK_TREE_MODEL (ListStore)); 2238 2239 SetSensitivity(AWinControl, ComboWidget); 2240 2241 g_object_unref (G_OBJECT (liststore)); 2242 2243 gtk_container_add(PGtkContainer(Box), ComboWidget); 2244 gtk_widget_show_all(Box); 2245 if csDesigning in AWinControl.ComponentState then 2246 gtk_event_box_set_above_child(PGtkEventBox(Box), true); 2247 2248 SetRenderer(ACustomComboBox, ComboWidget, WidgetInfo); 2249 2250 SetMainWidget(Box, ComboWidget); 2251 SetMainWidget(Box, GTK_BIN(ComboWidget)^.child); 2252 if PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button <> nil then 2253 SetMainWidget(Box, PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button); 2254 2255 LCLIndex := New(PLongint); 2256 //Should not set the ItemIndex value here? 2257 LCLIndex^ := -1; 2258 WidgetInfo^.CoreWidget := ComboWidget; 2259 WidgetInfo^.ClientWidget := Box; 2260 WidgetInfo^.UserData := LCLIndex; 2261 WidgetInfo^.DataOwner := True; 2262 2263 //gtk_widget_add_events(Box, GDK_ALL_EVENTS_MASK); 2264 2265 SetCallbacks(AWinControl, Box, WidgetInfo); 2266 2267 // Items 2268 ItemList:= TGtkListStoreStringList.Create( 2269 gtk_combo_box_get_model(PGtkComboBox(ComboWidget)),0,ACustomComboBox); 2270 g_object_set_data(PGObject(ComboWidget),GtkListItemLCLListTag,ItemList); 2271 // This is done in InitializeWnd: ItemList.Assign(ACustomComboBox.Items); 2272 if ACustomComboBox.Items is TStringList then 2273 ItemList.Sorted:=TStringList(ACustomComboBox.Items).Sorted; 2274 2275 if AParams.Style and WS_VISIBLE = 0 then 2276 gtk_widget_hide(Box) 2277 else 2278 gtk_widget_show(Box); 2279 2280 Result := TLCLIntfHandle({%H-}PtrUInt(Box)); 2281end; 2282 2283class procedure TGtk2WSCustomComboBox.DestroyHandle( 2284 const AWinControl: TWinControl); 2285var 2286 Handle: HWND; 2287 ComboWidget: PGtkWidget; 2288begin 2289 Handle := AWinControl.Handle; 2290 ComboWidget := GetWidgetInfo({%H-}Pointer(Handle), True)^.CoreWidget; 2291 2292 if PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button <> nil then 2293 FreeWidgetInfo(PGtkComboBoxPrivate(PGtkComboBox(ComboWidget)^.priv)^.button); 2294 //DebugLn(['TGtk2WSCustomComboBox.DestroyHandle ',dbgsName(AWinControl),' ClassParent=',ClassParent.ClassName]); 2295 2296 // inherited DestroyHandle doesn't work, because that is determined at 2297 // compile time, while the WS class hierarchy is created at runtime 2298 TWSWinControlClass(Classparent).DestroyHandle(AWinControl); 2299end; 2300 2301{ TGtk2WSCustomGroupBox } 2302 2303class procedure TGtk2WSCustomGroupBox.SetCallbacks(const AGtkWidget: PGtkWidget; 2304 const AWidgetInfo: PWidgetInfo); 2305begin 2306 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 2307end; 2308 2309class procedure TGtk2WSCustomGroupBox.SetLabel(AFrame: PGtkFrame; AText: String); 2310var 2311 Lbl: PGtkWidget; 2312begin 2313 Lbl := gtk_frame_get_label_widget(AFrame); 2314 if (AText = '') then 2315 begin 2316 if Lbl <> nil then 2317 gtk_widget_destroy(Lbl); 2318 end 2319 else 2320 begin 2321 if Lbl = nil then 2322 begin 2323 Lbl := gtk_label_new(nil); 2324 gtk_widget_show(Lbl); 2325 gtk_frame_set_label_widget(AFrame, Lbl); 2326 end; 2327 Gtk2Widgetset.SetLabelCaption(PGtkLabel(Lbl), AText); 2328 end; 2329end; 2330 2331class function TGtk2WSCustomGroupBox.GetFrameWidget(AEventBox: PGtkEventBox): PGtkFrame; 2332var 2333 GBWidget: PGTKWidget; 2334begin 2335 GBWidget := PGTKWidget(AEventBox); 2336 Result:=PGtkFrame(PGtkBin(GBWidget)^.child); 2337end; 2338 2339class function TGtk2WSCustomGroupBox.CreateHandle( 2340 const AWinControl: TWinControl; const AParams: TCreateParams 2341 ): TLCLIntfHandle; 2342var 2343{$if not defined(GtkFixedWithWindow)} 2344 EventBox: PGtkWidget; 2345{$endif} 2346 FrameBox: PGTKWidget; 2347 TempWidget: PGTKWidget; // pointer to gtk-widget (local use when neccessary) 2348 p : pointer; // ptr to the newly created GtkWidget 2349 Allocation: TGTKAllocation; 2350 WidgetInfo: PWidgetInfo; 2351begin 2352 P := gtk_frame_new(nil); 2353 SetLabel(P, AParams.Caption); 2354 WidgetInfo := CreateWidgetInfo(P, AWinControl, AParams); 2355 {$if defined(GtkFixedWithWindow)} 2356 TempWidget := CreateFixedClientWidget; 2357 gtk_container_add(GTK_CONTAINER(p), TempWidget); 2358 WidgetInfo^.ClientWidget := TempWidget; 2359 WidgetInfo^.CoreWidget := TempWidget; 2360 g_object_set_data(PGObject(TempWidget), 'widgetinfo', WidgetInfo); 2361 {$else} 2362 EventBox := gtk_event_box_new; 2363 gtk_event_box_set_visible_window(PGtkEventBox(EventBox), False); 2364 TempWidget := CreateFixedClientWidget(False); 2365 gtk_container_add(GTK_CONTAINER(EventBox), TempWidget); 2366 gtk_container_add(GTK_CONTAINER(p), EventBox); 2367 gtk_widget_show(EventBox); 2368 WidgetInfo^.ClientWidget := TempWidget; 2369 WidgetInfo^.CoreWidget := EventBox; 2370 g_object_set_data(PGObject(TempWidget), 'widgetinfo', WidgetInfo); 2371 g_object_set_data(PGObject(EventBox), 'widgetinfo', WidgetInfo); 2372 {$endif} 2373 FrameBox := gtk_event_box_new; 2374 gtk_event_box_set_visible_window(PGtkEventBox(FrameBox), True); 2375 gtk_container_add(GTK_CONTAINER(FrameBox), p); 2376 g_object_set_data(PGObject(FrameBox), 'widgetinfo', WidgetInfo); 2377 gtk_widget_show(TempWidget); 2378 gtk_widget_show(P); 2379 if AWinControl.HandleObjectShouldBeVisible then 2380 gtk_widget_show(FrameBox); 2381 2382 Result := TLCLIntfHandle({%H-}PtrUInt(FrameBox)); 2383 2384 Allocation.X := AParams.X; 2385 Allocation.Y := AParams.Y; 2386 Allocation.Width := AParams.Width; 2387 Allocation.Height := AParams.Height; 2388 gtk_widget_size_allocate(FrameBox, @Allocation); 2389 2390 Set_RC_Name(AWinControl, FrameBox); 2391 SetCallbacks(FrameBox, WidgetInfo); 2392end; 2393 2394class procedure TGtk2WSCustomGroupBox.SetColor(const AWinControl: TWinControl); 2395var 2396 GBWidget: PGTKWidget; 2397begin 2398 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then 2399 Exit; 2400 GBWidget:={%H-}PGTKWidget(AWinControl.Handle); 2401 2402 {$if defined(GtkFixedWithWindow)} 2403 Gtk2WidgetSet.SetWidgetColor(GetFixedWidget(GBWidget), clNone, AWinControl.Color, 2404 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 2405 {$endif} 2406 Gtk2WidgetSet.SetWidgetColor(GBWidget, clNone, AWinControl.Color, 2407 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 2408end; 2409 2410class function TGtk2WSCustomGroupBox.GetDefaultClientRect( 2411 const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer; 2412 var aClientRect: TRect): boolean; 2413var 2414 FrameBorders: TRect; 2415 Widget: PGtkWidget; 2416 FixedWidget: PGtkWidget; 2417begin 2418 Result:=false; 2419 //DebugLn(['TGtk2WSCustomGroupBox.GetDefaultClientRect ',DbgSName(AWinControl),' ',aWidth,'x',aHeight]); 2420 if AWinControl.HandleAllocated then begin 2421 Widget:={%H-}PGtkWidget(AWinControl.Handle); 2422 FixedWidget:=PGtkWidget(GetFixedWidget(Widget)); 2423 //DebugLn(['TGtk2WSCustomGroupBox.GetDefaultClientRect Flags=',WidgetFlagsToString(Widget),' FixedFlags=',WidgetFlagsToString(FixedWidget),' FixedSize=',FixedWidget^.allocation.width,'x',FixedWidget^.allocation.height]); 2424 if not GTK_WIDGET_RC_STYLE(FixedWidget) then 2425 Result:=true; 2426 end else begin 2427 Result:=true; 2428 end; 2429 if Result then begin 2430 FrameBorders:=GetStyleGroupboxFrameBorders; 2431 aClientRect:=Rect(0,0, 2432 Max(0,aWidth-FrameBorders.Left-FrameBorders.Right), 2433 Max(0,aHeight-FrameBorders.Top-FrameBorders.Bottom)); 2434 end; 2435 //if Result then DebugLn(['TGtk2WSCustomGroupBox.GetDefaultClientRect END FrameBorders=',dbgs(FrameBorders),' aClientRect=',dbgs(aClientRect)]); 2436end; 2437 2438class procedure TGtk2WSCustomGroupBox.GetPreferredSize( 2439 const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; 2440 WithThemeSpace: Boolean); 2441begin 2442 // ToDo: compute the minimum size ignoring LCL child controls 2443 GetGTKDefaultWidgetSize(AWinControl, PreferredWidth, PreferredHeight, 2444 WithThemeSpace); 2445end; 2446 2447class procedure TGtk2WSCustomGroupBox.SetFont(const AWinControl: TWinControl; 2448 const AFont: TFont); 2449var 2450 Frame: PGtkFrame; 2451 Lbl: PGtkWidget; 2452begin 2453 Frame := GetFrameWidget({%H-}PGTKEventBox(AWinControl.Handle)); 2454 Lbl := gtk_frame_get_label_widget(Frame); 2455 2456 if Lbl <> nil then 2457 begin 2458 Gtk2WidgetSet.SetWidgetColor(Lbl, AFont.Color, clNone, 2459 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 2460 Gtk2WidgetSet.SetWidgetFont(Lbl, AFont); 2461 end; 2462 inherited SetFont(AWinControl, AFont); 2463end; 2464 2465class procedure TGtk2WSCustomGroupBox.SetText(const AWinControl: TWinControl; 2466 const AText: string); 2467begin 2468 if not WSCheckHandleAllocated(AWinControl, 'SetText') then Exit; 2469 SetLabel(GetFrameWidget({%H-}PGtkEventBox(AWinControl.Handle)), AText); 2470end; 2471 2472function Gtk2WSButton_Clicked(AWidget: PGtkWidget; AInfo: PWidgetInfo): GBoolean; cdecl; 2473var 2474 Msg: TLMessage; 2475begin 2476 Result := CallBackDefaultReturn; 2477 if AInfo^.ChangeLock > 0 then Exit; 2478 2479 // do not send LM_CLICKED. issue #21483 2480 if g_object_get_data(PGObject(AWidget),'lcl-button-stop-clicked') = AWidget then 2481 begin 2482 g_object_set_data(PGObject(AWidget),'lcl-button-stop-clicked', nil); 2483 exit; 2484 end; 2485 Msg.Msg := LM_CLICKED; 2486 Result := DeliverMessage(AInfo^.LCLObject, Msg) = 0; 2487end; 2488 2489function Gtk2WSButtonPressedEvent(widget: PGtkWidget; {%H-}event: pgdkEventButton; {%H-}data: gPointer): GBoolean; cdecl; 2490begin 2491 Result := CallBackDefaultReturn; 2492 // set to nil data if we pressed return before, 2493 // otherwise LM_CLICKED won't trigger. issue #21483 2494 g_object_set_data(PGObject(Widget),'lcl-button-stop-clicked', nil); 2495end; 2496 2497procedure Gtk2WSButton_SizeAllocate(widget: PGtkWidget; {%H-}allocation: PGtkAllocation; {%H-}user_data: gpointer); cdecl; 2498var 2499 xthickness, ythickness: gint; 2500 inner_border: PGtkBorder; 2501begin 2502 //the default GtkButton size_allocate handler takes into account 2503 //*thickness and inner_border properties to position the child (label) 2504 //see gtk_button_size_allocate in gtkbutton.c 2505 //here this is reverted so the child is not padded 2506 xthickness := widget^.style^.xthickness; 2507 ythickness := widget^.style^.ythickness; 2508 with PGtkBin(widget)^.child^.allocation do 2509 begin 2510 y := y - ythickness; 2511 height := height + 2 * ythickness; 2512 x := x - xthickness; 2513 width := width + 2 * xthickness; 2514 inner_border := nil; 2515 if gtk_minor_version > 8 then 2516 gtk_widget_style_get (widget, 'inner-border', @inner_border, nil); 2517 if inner_border <> nil then 2518 begin 2519 x := x - inner_border^.left; 2520 width := width + inner_border^.left + inner_border^.right; 2521 y := y - inner_border^.top; 2522 height := height + inner_border^.top + inner_border^.bottom; 2523 end 2524 else 2525 begin 2526 //if no inner-border is set, GtkButton uses a default border = (1,1,1,1) 2527 dec(x); 2528 dec(y); 2529 inc(width, 2); 2530 inc(height, 2); 2531 end; 2532 end; 2533end; 2534 2535{ TGtk2WSButton } 2536 2537class function TGtk2WSButton.GetButtonWidget(AEventBox: PGtkEventBox): PGtkButton; 2538begin 2539 Result := PGtkButton(PGtkBin(AEventBox)^.child); 2540end; 2541 2542class function TGtk2WSButton.GetLabelWidget(AEventBox: PGtkEventBox): PGtkLabel; 2543begin 2544 Result := PGtkLabel(PGtkBin(GetButtonWidget(AEventBox))^.child); 2545end; 2546 2547class procedure TGtk2WSButton.SetCallbacks(const AGtkWidget: PGtkWidget; 2548 const AWidgetInfo: PWidgetInfo); 2549begin 2550 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 2551 SignalConnect(AWidgetInfo^.CoreWidget, 'clicked', @Gtk2WSButton_Clicked, AWidgetInfo); 2552 SignalConnect(AWidgetInfo^.CoreWidget, 'button-press-event', @Gtk2WSButtonPressedEvent, AWidgetInfo); 2553 SignalConnect(AWidgetInfo^.CoreWidget, 'size-allocate', @Gtk2WSButton_SizeAllocate, AWidgetInfo); 2554end; 2555 2556{ 2557 Under Gtk 2 we need to put a GtkEventBox under the GtkButton, because a 2558 GtkButton has no window and that causes the Z-Order to be wrong. 2559} 2560class function TGtk2WSButton.CreateHandle(const AWinControl: TWinControl; 2561 const AParams: TCreateParams): TLCLIntfHandle; 2562var 2563 Button: TCustomButton; 2564 WidgetInfo: PWidgetInfo; 2565 Allocation: TGTKAllocation; 2566 EventBox, BtnWidget: PGtkWidget; 2567begin 2568 Button := AWinControl as TCustomButton; 2569 //DebugLn(['TGtk2WSButton.CreateHandle ',dbgsName(Button)]); 2570 2571 { Creates the container control for the button, the EventBox } 2572 EventBox := gtk_event_box_new; 2573 Result := TLCLIntfHandle({%H-}PtrUInt(EventBox)); 2574 {$IFDEF DebugLCLComponents} 2575 DebugGtkWidgets.MarkCreated(EventBox,'button'); 2576 {$ENDIF} 2577 2578 { Creates the button and inserts it into the EventBox } 2579 BtnWidget := gtk_button_new_with_label('button'); 2580 gtk_container_add(PGtkContainer(EventBox), BtnWidget); 2581 gtk_widget_show_all(EventBox); 2582 2583 { This commented commands can be used if we have event-related 2584 problems because of the EventBox } 2585// gtk_widget_add_events(EventBox, GDK_ALL_EVENTS_MASK); 2586// gtk_event_box_set_above_child(PGtkEventBox(EventBox), True); 2587 2588 { The WidgetInfo is important for the form designer } 2589 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), Button, AParams); 2590 WidgetInfo^.CoreWidget := BtnWidget; 2591 WidgetInfo^.ClientWidget := EventBox; 2592 //DebugLn(['TGtk2WSButton.CreateHandle ',GetWidgetInfo(EventBox)=WidgetInfo,' ',GetWidgetInfo(EventBox)^.ClientWidget=BtnWidget]); 2593// g_object_set_data(PGObject(Result), 'widgetinfo', WidgetInfo); 2594 SetMainWidget(EventBox, BtnWidget); 2595 2596 Allocation.X := AParams.X; 2597 Allocation.Y := AParams.Y; 2598 Allocation.Width := AParams.Width; 2599 Allocation.Height := AParams.Height; 2600 gtk_widget_size_allocate(EventBox, @Allocation); 2601 2602 Set_RC_Name(AWinControl, EventBox); 2603 SetCallbacks(EventBox, WidgetInfo); 2604 2605 if AParams.Style and WS_VISIBLE = 0 then 2606 gtk_widget_hide(EventBox) 2607 else 2608 gtk_widget_show(EventBox); 2609end; 2610 2611class function TGtk2WSButton.GetText(const AWinControl: TWinControl; var AText: String): Boolean; 2612begin 2613 // The button text is static, so let the LCL fallback to FCaption 2614 Result := False; 2615end; 2616 2617class procedure TGtk2WSButton.SetDefault(const AButton: TCustomButton; ADefault: Boolean); 2618begin 2619 if not WSCheckHandleAllocated(AButton, 'SetDefault') 2620 then Exit; 2621 2622 if ADefault 2623 and (GTK_WIDGET_CAN_DEFAULT({%H-}pgtkwidget(AButton.Handle))) then 2624 //gtk_widget_grab_default(pgtkwidget(handle)) 2625 else begin 2626 {DebugLn('LM_BTNDEFAULT_CHANGED ',TCustomButton(Sender).Name,':',Sender.ClassName,' widget can not grab default ', 2627 ' visible=',GTK_WIDGET_VISIBLE(PGtkWidget(Handle)), 2628 ' realized=',GTK_WIDGET_REALIZED(PGtkWidget(Handle)), 2629 ' mapped=',GTK_WIDGET_MAPPED(PGtkWidget(Handle)), 2630 '');} 2631 // gtk_widget_Draw_Default(pgtkwidget(Handle)); //this isn't right but I'm not sure what to call 2632 end; 2633end; 2634 2635class procedure TGtk2WSButton.SetShortcut(const AButton: TCustomButton; 2636 const ShortCutK1, ShortCutK2: TShortcut); 2637begin 2638 if not WSCheckHandleAllocated(AButton, 'SetShortcut') 2639 then Exit; 2640 // gtk2: shortcuts are handled by the LCL 2641end; 2642 2643class procedure TGtk2WSButton.SetText(const AWinControl: TWinControl; const AText: String); 2644var 2645 BtnWidget: PGtkButton; 2646 LblWidget: PGtkLabel; 2647begin 2648 if not WSCheckHandleAllocated(AWincontrol, 'SetText') 2649 then Exit; 2650 2651 BtnWidget := GetButtonWidget({%H-}PGtkEventBox(AWinControl.Handle)); 2652 LblWidget := PGtkLabel(PGtkBin(BtnWidget)^.Child); 2653 2654 if LblWidget = nil 2655 then begin 2656 //DebugLn(Format('trace: [WARNING] Button %s(%s) has no label', [AWinControl.Name, AWinControl.ClassName])); 2657 LblWidget := PGtkLabel(gtk_label_new('')); 2658 gtk_container_add(PGtkContainer(BtnWidget), PGtkWidget(LblWidget)); 2659 end; 2660 2661 Gtk2WidgetSet.SetLabelCaption(LblWidget, AText); 2662end; 2663 2664class procedure TGtk2WSButton.SetColor(const AWinControl: TWinControl); 2665var 2666 BtnWidget: PGTKWidget; 2667begin 2668 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then 2669 Exit; 2670 BtnWidget := PGTKWidget(GetButtonWidget({%H-}PGtkEventBox(AWinControl.Handle))); 2671 Gtk2WidgetSet.SetWidgetColor(BtnWidget, clNone, AWinControl.Color, 2672 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 2673end; 2674 2675class procedure TGtk2WSButton.SetFont(const AWinControl: TWinControl; 2676 const AFont: TFont); 2677var 2678 LblWidget: PGtkWidget; 2679begin 2680 if not AWinControl.HandleAllocated then exit; 2681 2682 LblWidget := PGtkWidget(GetLabelWidget({%H-}PGtkEventBox(AWinControl.Handle))); 2683 2684 if (LblWidget <> nil) then 2685 begin 2686 Gtk2WidgetSet.SetWidgetColor(LblWidget, AFont.Color, clNone, 2687 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 2688 Gtk2WidgetSet.SetWidgetFont(LblWidget, AFont); 2689 end; 2690end; 2691 2692class procedure TGtk2WSButton.GetPreferredSize(const AWinControl: TWinControl; 2693 var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); 2694begin 2695 GetGTKDefaultWidgetSize(AWinControl,PreferredWidth,PreferredHeight, 2696 WithThemeSpace); 2697 //debugln('TGtkWSButton.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight)); 2698end; 2699 2700{ TGtk2WSScrollBar } 2701 2702class procedure TGtk2WSScrollBar.SetCallbacks(const AGtkWidget: PGtkWidget; 2703 const AWidgetInfo: PWidgetInfo); 2704begin 2705 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 2706 2707 g_signal_connect(AGtkWidget, 'change-value', TGCallback(@Gtk2RangeScrollCB), AWidgetInfo); 2708 g_signal_connect(AGtkWidget, 'button-press-event', 2709 TGCallback(@Gtk2RangeScrollPressCB), AWidgetInfo); 2710 g_signal_connect(AGtkWidget, 'button-release-event', 2711 TGCallback(@Gtk2RangeScrollReleaseCB), AWidgetInfo); 2712end; 2713 2714class function TGtk2WSScrollBar.CreateHandle(const AWinControl: TWinControl; 2715 const AParams: TCreateParams): TLCLIntfHandle; 2716var 2717 Adjustment: PGtkAdjustment = nil; 2718 Widget: PGtkWidget; 2719 WidgetInfo: PWidgetInfo; 2720begin 2721 with TScrollBar(AWinControl) do 2722 begin 2723 {We use Max + PageSize because the GTK scrollbar is meant to scroll from 2724 min to max-pagesize which would be different from the behaviour on other 2725 widgetsets.} 2726 Adjustment := PGtkAdjustment(gtk_adjustment_new(Position, Min, 2727 Max, SmallChange, LargeChange, PageSize)); 2728 2729 if (Kind = sbHorizontal) then 2730 Widget := gtk_hscrollbar_new(Adjustment) 2731 else 2732 Widget := gtk_vscrollbar_new(Adjustment); 2733 gtk_range_set_update_policy(PGtkRange(Widget), GTK_UPDATE_CONTINUOUS); 2734 end; 2735 2736 Result := TLCLIntfHandle({%H-}PtrUInt(Widget)); 2737 {$IFDEF DebugLCLComponents} 2738 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 2739 {$ENDIF} 2740 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), AWinControl, AParams); 2741 2742 Set_RC_Name(AWinControl, Widget); 2743 SetCallbacks(Widget, WidgetInfo); 2744end; 2745 2746class procedure TGtk2WSScrollBar.SetKind(const AScrollBar: TCustomScrollBar; 2747 const AIsHorizontal: Boolean); 2748begin 2749 if not AScrollBar.HandleAllocated then 2750 exit; 2751 RecreateWnd(AScrollBar); 2752end; 2753 2754class procedure TGtk2WSScrollBar.SetParams(const AScrollBar: TCustomScrollBar); 2755var 2756 Range: PGtkRange; 2757begin 2758 if not AScrollBar.HandleAllocated then 2759 exit; 2760 with AScrollBar do 2761 begin 2762 Range := GTK_RANGE({%H-}Pointer(Handle)); 2763 {for gtk >= 2.14 use gtk_adjustment_configure} 2764 if (gtk_major_version >= 2) and (gtk_minor_version >= 14) then 2765 gtk_adjustment_configure(Range^.adjustment, Position, Min, Max, SmallChange, LargeChange, PageSize) 2766 else 2767 begin 2768 with Range^.adjustment^ do 2769 begin 2770 value := Position; 2771 lower := Min; 2772 upper := Max; 2773 step_increment := SmallChange; 2774 page_increment := LargeChange; 2775 page_size := PageSize; 2776 end; 2777 gtk_adjustment_changed(Range^.adjustment); 2778 end; 2779 end; 2780end; 2781 2782class procedure TGtk2WSScrollBar.ShowHide(const AWinControl: TWinControl); 2783begin 2784 if not AWinControl.HandleAllocated then 2785 exit; 2786 if AWinControl.HandleObjectShouldBeVisible then 2787 SetParams(TCustomScrollBar(AWinControl)); 2788 Gtk2WidgetSet.SetVisible(AWinControl, 2789 AWinControl.HandleObjectShouldBeVisible); 2790end; 2791 2792{ TGtk2WSRadioButton } 2793 2794class function TGtk2WSRadioButton.CreateHandle(const AWinControl: TWinControl; 2795 const AParams: TCreateParams): TLCLIntfHandle; 2796var 2797 Widget, TempWidget: PGtkWidget; 2798 LabelWidget: PGtkLabel; 2799 TempInt: Integer; 2800 WidgetInfo: PWidgetInfo; 2801 Allocation: TGTKAllocation; 2802begin 2803 with TRadioButton(AWinControl) do 2804 begin 2805 // Look for our parent's control and use the first radio we find for grouping 2806 TempWidget := nil; 2807 if (Parent <> nil) then 2808 begin 2809 for TempInt := 0 to Parent.ControlCount - 1 do 2810 begin 2811 if (Parent.Controls[TempInt] is TRadioButton) and 2812 TWinControl(Parent.Controls[TempInt]).HandleAllocated then 2813 begin 2814 TempWidget := {%H-}PGtkWidget(TWinControl(Parent.Controls[TempInt]).Handle); 2815 Break; 2816 end; 2817 end; 2818 end; 2819 2820 if TempWidget <> nil then 2821 Widget := gtk_radio_button_new_with_label(PGtkRadioButton(TempWidget)^.group,'') 2822 else 2823 Widget := gtk_radio_button_new_with_label(nil, ''); 2824 2825 LabelWidget := PGtkLabel(gtk_bin_get_child(PGtkBin(@PGTKToggleButton(Widget)^.Button))); 2826 Gtk2WidgetSet.SetLabelCaption(LabelWidget, AParams.Caption); 2827 end; 2828 2829 {$IFDEF DebugLCLComponents} 2830 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 2831 {$ENDIF} 2832 Result := THandle({%H-}PtrUInt(Widget)); 2833 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), AWinControl, AParams); 2834 2835 Allocation.X := AParams.X; 2836 Allocation.Y := AParams.Y; 2837 Allocation.Width := AParams.Width; 2838 Allocation.Height := AParams.Height; 2839 gtk_widget_size_allocate(Widget, @Allocation); 2840 2841 Set_RC_Name(AWinControl, Widget); 2842 TGtk2WSCustomCheckBox.SetCallbacks(Widget, WidgetInfo); 2843end; 2844 2845{ TGtk2WSToggleBox } 2846 2847class function TGtk2WSToggleBox.CreateHandle(const AWinControl: TWinControl; 2848 const AParams: TCreateParams): TLCLIntfHandle; 2849var 2850 Widget: PGtkWidget; 2851 WidgetInfo: PWidgetInfo; 2852 Allocation: TGTKAllocation; 2853begin 2854 Widget := gtk_toggle_button_new_with_label(AParams.Caption); 2855 {$IFDEF DebugLCLComponents} 2856 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 2857 {$ENDIF} 2858 Result := THandle({%H-}PtrUInt(Widget)); 2859 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), AWinControl, AParams); 2860 2861 Allocation.X := AParams.X; 2862 Allocation.Y := AParams.Y; 2863 Allocation.Width := AParams.Width; 2864 Allocation.Height := AParams.Height; 2865 gtk_widget_size_allocate(Widget, @Allocation); 2866 2867 Set_RC_Name(AWinControl, Widget); 2868 TGtk2WSCustomCheckBox.SetCallbacks(Widget, WidgetInfo); 2869end; 2870 2871{ TGtk2WSCustomStaticText } 2872 2873class function TGtk2WSCustomStaticText.GetLabelWidget(AFrame: PGtkFrame): PGtkLabel; 2874begin 2875 Result := PGtkLabel(PGtkBin(GetBoxWidget(AFrame))^.child); 2876end; 2877 2878class function TGtk2WSCustomStaticText.GetBoxWidget(AFrame: PGtkFrame): PGtkEventBox; 2879begin 2880 Result := PGtkEventBox(PGtkBin(AFrame)^.child); 2881end; 2882 2883class function TGtk2WSCustomStaticText.CreateHandle( 2884 const AWinControl: TWinControl; const AParams: TCreateParams 2885 ): TLCLIntfHandle; 2886var 2887 AStaticText: TCustomStaticText; 2888 WidgetInfo: PWidgetInfo; 2889 Allocation: TGTKAllocation; 2890 EventBox, LblWidget: PGtkWidget; 2891begin 2892 // TStaticText control is a Text area with frame around. Both Text and Area around 2893 // text can have their own color 2894 2895 // To implement that in gtk we need: 2896 // 1. GtkLabel to handle Text 2897 // 2. GtkEventBox to draw color area around GtkLabel (since GtkLabel have no window) 2898 // 3. GtkFrame to draw frame around Text area 2899 // GtkFrame is our main widget - it is container and it contains GtkEventBox 2900 // GtkEventBox is also containter and it contains GtkLabel 2901 2902 AStaticText := AWinControl as TCustomStaticText; 2903 Result := TLCLIntfHandle({%H-}PtrUInt(gtk_frame_new(nil))); // frame is the main container - to decorate label 2904 if Result = 0 then Exit; 2905 2906 gtk_frame_set_shadow_type({%H-}PGtkFrame(Result), StaticBorderShadowMap[AStaticText.BorderStyle]); 2907 2908 EventBox := gtk_event_box_new; // our area 2909 LblWidget := gtk_label_new(PChar(TCustomStaticText(AWinControl).Caption)); // our text widget 2910 gtk_container_add(PGtkContainer(EventBox), LblWidget); 2911 SetLabelAlignment(PGtkLabel(LblWidget), AStaticText.Alignment); 2912 gtk_widget_show(LblWidget); 2913 gtk_widget_show(EventBox); 2914 gtk_container_add({%H-}PGtkContainer(Result), EventBox); 2915 2916 {$IFDEF DebugLCLComponents} 2917 DebugGtkWidgets.MarkCreated(Pointer(Result), dbgsName(AWinControl)); 2918 {$ENDIF} 2919 2920 WidgetInfo := CreateWidgetInfo({%H-}Pointer(Result), AStaticText, AParams); 2921 WidgetInfo^.CoreWidget := EventBox; 2922 g_object_set_data(PGObject(EventBox), 'widgetinfo', WidgetInfo); 2923 2924 Allocation.X := AParams.X; 2925 Allocation.Y := AParams.Y; 2926 Allocation.Width := AParams.Width; 2927 Allocation.Height := AParams.Height; 2928 gtk_widget_size_allocate({%H-}PGtkWidget(Result), @Allocation); 2929 2930 Set_RC_Name(AWinControl, {%H-}PGtkWidget(Result)); 2931 SetCallbacks({%H-}PGtkWidget(Result), WidgetInfo); 2932end; 2933 2934class procedure TGtk2WSCustomStaticText.SetAlignment(const ACustomStaticText: TCustomStaticText; 2935 const NewAlignment: TAlignment); 2936var 2937 LblWidget: PGtkLabel; 2938begin 2939 if not WSCheckHandleAllocated(ACustomStaticText, 'SetAlignment') 2940 then Exit; 2941 2942 LblWidget := GetLabelWidget({%H-}PGtkFrame(ACustomStaticText.Handle)); 2943 SetLabelAlignment(LblWidget, NewAlignment); 2944end; 2945 2946class procedure TGtk2WSCustomStaticText.GetPreferredSize(const AWinControl: TWinControl; 2947 var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); 2948begin 2949 GetGTKDefaultWidgetSize(AWinControl, PreferredWidth, PreferredHeight, 2950 WithThemeSpace); 2951 //debugln('TGtkWSCustomStaticText.GetPreferredSize ',DbgSName(AWinControl),' PreferredWidth=',dbgs(PreferredWidth),' PreferredHeight=',dbgs(PreferredHeight)); 2952end; 2953 2954class function TGtk2WSCustomStaticText.GetText(const AWinControl: TWinControl; 2955 var AText: String): Boolean; 2956begin 2957 // The text is static, so let the LCL fallback to FCaption 2958 Result := False; 2959end; 2960 2961class procedure TGtk2WSCustomStaticText.SetText(const AWinControl: TWinControl; 2962 const AText: String); 2963var 2964 FrameWidget: PGtkFrame; 2965 LblWidget: PGtkLabel; 2966begin 2967 if not WSCheckHandleAllocated(AWincontrol, 'SetText') 2968 then Exit; 2969 2970 FrameWidget := {%H-}PGtkFrame(AWinControl.Handle); 2971 LblWidget := GetLabelWidget(FrameWidget); 2972 2973 if TStaticText(AWinControl).ShowAccelChar and (AText <> '') then 2974 Gtk2WidgetSet.SetLabelCaption(LblWidget, AText) 2975 else 2976 begin 2977 gtk_label_set_text(LblWidget, PChar(AText)); 2978 gtk_label_set_pattern(LblWidget, nil); 2979 end; 2980end; 2981 2982class procedure TGtk2WSCustomStaticText.SetStaticBorderStyle( 2983 const ACustomStaticText: TCustomStaticText; 2984 const NewBorderStyle: TStaticBorderStyle); 2985begin 2986 if not WSCheckHandleAllocated(ACustomStaticText, 'SetStaticBorderStyle') 2987 then Exit; 2988 gtk_frame_set_shadow_type({%H-}PGtkFrame(ACustomStaticText.Handle), StaticBorderShadowMap[NewBorderStyle]); 2989end; 2990 2991class procedure TGtk2WSCustomStaticText.SetCallbacks( 2992 const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); 2993begin 2994 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 2995 2996 SignalConnect(AGtkWidget, 'grab_focus', @gtkActivateCB, AWidgetInfo); 2997end; 2998 2999class procedure TGtk2WSCustomStaticText.SetColor(const AWinControl: TWinControl); 3000begin 3001 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then Exit; 3002 3003 Gtk2WidgetSet.SetWidgetColor(PGtkWidget(GetBoxWidget({%H-}PGtkFrame(AWinControl.Handle))), 3004 clNone, AWinControl.Color, 3005 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE, 3006 GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 3007end; 3008 3009class procedure TGtk2WSCustomStaticText.SetFont(const AWinControl: TWinControl; 3010 const AFont: TFont); 3011var 3012 Widget: PGtkWidget; 3013begin 3014 if not WSCheckHandleAllocated(AWinControl, 'SetFont') 3015 then Exit; 3016 3017 Widget := PGtkWidget(GetLabelWidget({%H-}PGtkFrame(AWinControl.Handle))); 3018 3019 Gtk2WidgetSet.SetWidgetColor(Widget, AFont.Color, clNone, 3020 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE,GTK_STATE_PRELIGHT,GTK_STATE_SELECTED]); 3021 Gtk2WidgetSet.SetWidgetFont(Widget, AFont); 3022end; 3023 3024end. 3025