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