1{%MainUnit gtk2wscomctrls.pp} 2{ 3 ***************************************************************************** 4 This file is part of the Lazarus Component Library (LCL) 5 6 See the file COPYING.modifiedLGPL.txt, included in this distribution, 7 for details about the license. 8 ***************************************************************************** 9} 10 11const 12 GtkPositionTypeMap: array[TTabPosition] of TGtkPositionType = 13 ( 14{ tpTop } GTK_POS_TOP, 15{ tpBottom } GTK_POS_BOTTOM, 16{ tpLeft } GTK_POS_LEFT, 17{ tpRight } GTK_POS_RIGHT 18 ); 19 20 LCL_NotebookManualPageSwitchKey = 'lcl_manual_page_switch'; 21 22 23type 24 GtkNotebookButtonPressEventProc = function (widget:PGtkWidget; event:PGdkEventButton):gboolean; cdecl; 25 GtkNotebookKeyPressEventProc = function (widget:PGtkWidget; event:PGdkEventKey):gboolean; cdecl; 26 27var 28 OldNoteBookButtonPress: GtkNotebookButtonPressEventProc = nil; 29 OldNoteBookKeyPress: GtkNotebookKeyPressEventProc = nil; 30 31// this was created as a workaround of a tnotebook eating rightclick of custom controls 32function Notebook_Button_Press(widget:PGtkWidget; event:PGdkEventButton):gboolean; cdecl; 33begin 34 Result := True; 35 if gtk_get_event_widget(PGdkEvent(event)) <> widget then exit; 36 if OldNoteBookButtonPress = nil then exit; 37 Result := OldNoteBookButtonPress(widget, event); 38end; 39 40// Allow switching tabs per key. Issue #31986 41function Notebook_Key_Press(widget:PGtkWidget; event:PGdkEventKey):gboolean; cdecl; 42begin 43 Result := True; 44 if OldNoteBookKeyPress = nil then exit; 45 case event^.hardware_keycode of 46 113: gtk_notebook_prev_page(PGtkNotebook(widget)); 47 114: gtk_notebook_next_page(PGtkNotebook(widget)); 48 else 49 Result := OldNoteBookKeyPress(widget, event); 50 end; 51end; 52 53procedure HookNoteBookClass; 54var 55 WidgetClass: PGtkWidgetClass; 56begin 57 WidgetClass := GTK_WIDGET_CLASS(gtk_type_class(gtk_notebook_get_type)); 58 59 OldNoteBookButtonPress := GtkNotebookButtonPressEventProc(WidgetClass^.button_press_event); 60 WidgetClass^.button_press_event := @Notebook_Button_Press; 61 OldNoteBookKeyPress := GtkNotebookKeyPressEventProc(WidgetClass^.key_press_event); 62 WidgetClass^.key_press_event := @Notebook_Key_Press; 63end; 64 65{ TGtk2WSCustomTabControl } 66 67function NotebookPageRealToLCLIndex(const ATabControl: TCustomTabControl; AIndex: integer): integer; 68var 69 I: Integer; 70begin 71 Result := AIndex; 72 if csDesigning in ATabControl.ComponentState then exit; 73 I := 0; 74 while (I < ATabControl.PageCount) and (I <= Result) do 75 begin 76 if not ATabControl.Page[I].TabVisible then Inc(Result); 77 Inc(I); 78 end; 79end; 80 81function GtkRestoreFocusFix(AGtkWidget: Pointer): gboolean; cdecl; 82begin 83 Result := AGtkWidget <> nil; 84 if AGtkWidget <> nil then 85 begin 86 GTK_WIDGET_SET_FLAGS(PGtkWidget(AGtkWidget), GTK_CAN_FOCUS); 87 g_idle_remove_by_data(AGtkWidget); 88 end; 89end; 90 91function GtkWSNotebook_AfterSwitchPage(widget: PGtkWidget; {%H-}page: Pgtkwidget; pagenum: integer; data: gPointer): GBoolean; cdecl; 92var 93 Mess: TLMNotify; 94 NMHdr: tagNMHDR; 95 Info: PWidgetInfo; 96 ACtl: TWinControl; 97 AParentForm: TCustomForm; 98 i: Integer; 99 LCLPageIndex: Integer; 100 Pg: TCustomPage; 101 ChildWidget: PGtkWidget; 102begin 103 Result := CallBackDefaultReturn; 104 // then send the new page 105 FillChar(Mess{%H-}, SizeOf(Mess), 0); 106 Mess.Msg := LM_NOTIFY; 107 FillChar(NMHdr{%H-}, SizeOf(NMHdr), 0); 108 NMHdr.code := TCN_SELCHANGE; 109 NMHdr.hwndFrom := {%H-}PtrUInt(widget); 110 LCLPageIndex := NotebookPageRealToLCLIndex(TCustomTabControl(Data), pagenum); //use this to set pageindex to the correct page. 111 NMHdr.idFrom := LCLPageIndex; 112 Mess.NMHdr := @NMHdr; 113 DeliverMessage(Data, Mess); 114 115 // code below is fix for issue #20493 116 Info := GetWidgetInfo(Widget); 117 if wwiTabWidgetFocusCheck in Info^.Flags then 118 begin 119 Exclude(Info^.Flags, wwiTabWidgetFocusCheck); 120 121 if LCLPageIndex = -1 then 122 exit; 123 124 ACtl := TWinControl(Data); 125 AParentForm := GetParentForm(ACtl); 126 if Assigned(AParentForm) then 127 begin 128 // 1st we must find focused control (if any) 129 ACtl := nil; 130 if (LCLPageIndex >= 0) and (LCLPageIndex < TCustomTabControl(Data).PageCount) then 131 Pg := TCustomTabControl(Data).Page[LCLPageIndex] 132 else 133 Pg := nil; 134 if Assigned(Pg) then 135 begin 136 for i := 0 to Pg.ControlCount - 1 do 137 begin 138 if (pg.Controls[i] is TWinControl) and 139 (TWinControl(pg.Controls[i]).Focused) then 140 begin 141 ACtl := TWinControl(pg.Controls[i]); 142 break; 143 end; 144 end; 145 end; 146 if (ACtl = nil) and (Pg <> nil) then 147 ACtl := AParentForm.ActiveControl; 148 end else 149 ACtl := nil; 150 151 if (ACtl <> nil) and (ACtl <> TWinControl(Data)) then 152 begin 153 // DebugLn('ActiveCtl is ',ACtl.ClassName,':',ACtl.Name); 154 // do not focus tab by mouse click if we already have active control 155 GTK_WIDGET_UNSET_FLAGS(Widget, GTK_CAN_FOCUS); 156 Pg := TCustomTabControl(Data).Page[LCLPageIndex]; 157 for i := 0 to Pg.ControlCount - 1 do 158 begin 159 // we must prevent gtkWidget to acquire focus by gtk (eg. GtkButton) 160 if (Pg.Controls[i] is TWinControl) and (Pg.Controls[i] <> ACtl) then 161 begin 162 Info := GetWidgetInfo({%H-}PGtkWidget(TWinControl(Pg.Controls[i]).Handle)); 163 if Info <> nil then 164 begin 165 if Info^.CoreWidget <> nil then 166 ChildWidget := Info^.CoreWidget 167 else 168 ChildWidget := Info^.ClientWidget; 169 GTK_WIDGET_UNSET_FLAGS(ChildWidget, GTK_CAN_FOCUS); 170 g_idle_add(@GtkRestoreFocusFix, ChildWidget); 171 end; 172 end; 173 end; 174 g_idle_add(@GtkRestoreFocusFix, Widget); 175 end; 176 end; 177end; 178 179function GtkWSNotebook_SwitchPage(widget: PGtkWidget; {%H-}page: Pgtkwidget; pagenum: integer; data: gPointer): GBoolean; cdecl; 180var 181 Mess: TLMNotify; 182 NMHdr: tagNMHDR; 183 IsManual: Boolean; 184begin 185 Result := CallBackDefaultReturn; 186 EventTrace('switch-page', data); 187 UpdateNoteBookClientWidget(TObject(Data)); 188 189 // remove flag 190 IsManual := g_object_get_data(PGObject(Widget), LCL_NotebookManualPageSwitchKey) <> nil; 191 if IsManual then 192 g_object_set_data(PGObject(Widget), LCL_NotebookManualPageSwitchKey, nil); 193 if PGtkNotebook(Widget)^.cur_page = nil then // for windows compatibility 194 Exit; 195 196 // gtkswitchpage is called before the switch 197 if not IsManual then 198 begin 199 // send first the TCN_SELCHANGING to ask if switch is allowed 200 FillChar(Mess{%H-}, SizeOf(Mess), 0); 201 Mess.Msg := LM_NOTIFY; 202 FillChar(NMHdr{%H-}, SizeOf(NMHdr), 0); 203 NMHdr.code := TCN_SELCHANGING; 204 NMHdr.hwndFrom := {%H-}PtrUInt(widget); 205 NMHdr.idFrom := NotebookPageRealToLCLIndex(TCustomTabControl(Data), pagenum); //use this to set pageindex to the correct page. 206 Mess.NMHdr := @NMHdr; 207 Mess.Result := 0; 208 DeliverMessage(Data, Mess); 209 if Mess.Result <> 0 then 210 begin 211 g_signal_stop_emission_by_name(PGObject(Widget), 'switch-page'); 212 Result := not CallBackDefaultReturn; 213 Exit; 214 end; 215 end; 216 217end; 218 219class procedure TGtk2WSCustomTabControl.SetCallbacks( 220 const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); 221begin 222 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 223 ConnectSignal(PGtkObject(AGtkWidget), 'switch_page', @GtkWSNotebook_SwitchPage, AWidgetInfo^.LCLObject); 224 ConnectSignalAfter(PGtkObject(AGtkWidget), 'switch_page', @GtkWSNotebook_AfterSwitchPage, AWidgetInfo^.LCLObject); 225end; 226 227class function TGtk2WSCustomTabControl.CreateTTabControlHandle( 228 const AWinControl: TWinControl; const AParams: TCreateParams): HWND; 229var 230 Widget: PGtkWidget; 231 WidgetInfo: PWidgetInfo; 232 Allocation: TGTKAllocation; 233begin 234 Widget := GTK2WidgetSet.CreateAPIWidget(AWinControl); 235 {$IFDEF DebugLCLComponents} 236 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 237 {$ENDIF} 238 239 Result := HWND({%H-}PtrUInt(Widget)); 240 if Result = 0 then Exit; 241 242 WidgetInfo := GetWidgetInfo(Widget); // Widget info already created in CreateAPIWidget 243 WidgetInfo^.Style := AParams.Style; 244 WidgetInfo^.ExStyle := AParams.ExStyle; 245 WidgetInfo^.WndProc := {%H-}PtrUInt(AParams.WindowClass.lpfnWndProc); 246 247 // set allocation 248 Allocation.X := AParams.X; 249 Allocation.Y := AParams.Y; 250 Allocation.Width := AParams.Width; 251 Allocation.Height := AParams.Height; 252 gtk_widget_size_allocate(Widget, @Allocation); 253 254 Set_RC_Name(AWinControl, Widget); 255 256 g_object_set_data(PGObject(WidgetInfo^.CoreWidget),'lcl_ttabcontrol', WidgetInfo^.CoreWidget); 257 258 TGtk2WSWinControl.SetCallbacks(GTK_OBJECT(Widget), AWinControl); 259 260 g_signal_connect_after(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'change-value', 261 TGCallback(@Gtk2RangeScrollCB), WidgetInfo); 262 g_signal_connect_after(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'change-value', 263 TGCallback(@Gtk2RangeScrollCB), WidgetInfo); 264 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'button-press-event', 265 TGCallback(@Gtk2RangeScrollPressCB), WidgetInfo); 266 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'button-release-event', 267 TGCallback(@Gtk2RangeScrollReleaseCB), WidgetInfo); 268 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'button-press-event', 269 TGCallback(@Gtk2RangeScrollPressCB), WidgetInfo); 270 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'button-release-event', 271 TGCallback(@Gtk2RangeScrollReleaseCB), WidgetInfo); 272 273 g_signal_connect(Widget, 'scroll-event', TGCallback(@Gtk2ScrolledWindowScrollCB), WidgetInfo); 274end; 275 276class function TGtk2WSCustomTabControl.CreateHandle(const AWinControl: TWinControl; 277 const AParams: TCreateParams): HWND; 278var 279 AWidget: PGtkNoteBook; 280 WidgetInfo: PWidgetInfo; 281begin 282 283 if (AWinControl is TTabControl) then 284 begin 285 {$IFDEF NOTEBOOK_DEBUG} 286 DebugLn(['TGtk2WSCustomTabControl.CreateHandle CREATING TTABCONTROL !!! ',DbgSName(AWinControl)]); 287 {$ENDIF} 288 Result := CreateTTabControlHandle(AWinControl, AParams); 289 exit; 290 end; 291 292 {$IFDEF NOTEBOOK_DEBUG} 293 DebugLn(['TGtk2WSCustomTabControl.CreateHandle ',DbgSName(AWinControl)]); 294 {$ENDIF} 295 if OldNoteBookButtonPress = nil then 296 HookNoteBookClass; 297 298 AWidget := PGtkNoteBook(gtk_notebook_new()); 299 WidgetInfo := CreateWidgetInfo(AWidget, AWinControl, AParams); 300 {$IFDEF DebugLCLComponents} 301 DebugGtkWidgets.MarkCreated(Pointer(AWidget), dbgsName(AWinControl)); 302 {$ENDIF} 303 gtk_notebook_set_scrollable(AWidget, True); 304 305 if not (nboHidePageListPopup in TCustomTabControl(AWinControl).Options) then 306 gtk_notebook_popup_enable(AWidget); 307 308 gtk_notebook_set_tab_pos(AWidget, GtkPositionTypeMap[TCustomTabControl(AWinControl).TabPosition]); 309 Result := HWND(TLCLIntfHandle({%H-}PtrUInt(AWidget))); 310 Set_RC_Name(AWinControl, PGtkWidget(AWidget)); 311 SetCallBacks(PGtkWidget(AWidget), WidgetInfo); 312end; 313 314class function TGtk2WSCustomTabControl.GetDefaultClientRect( 315 const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer; 316 var aClientRect: TRect): boolean; 317var 318 FrameBorders: TRect; 319begin 320 Result:=false; 321 if (AWinControl is TTabControl) then 322 begin 323 // use normal ClientRect 324 end else begin 325 // handle is a gtknotebook 326 //DebugLn(['TGtk2WSCustomTabControl.GetDefaultClientRect ',DbgSName(AWinControl),' ',aWidth,'x',aHeight]); 327 if AWinControl.HandleAllocated 328 and (gtk_notebook_get_nth_page({%H-}PGtkNotebook(AWinControl.Handle),0)<>nil) 329 then begin 330 // notebook handle allocated and has one page 331 // => normal GetClientRect will retrieve the right ClientRect 332 end else begin 333 FrameBorders:=GetStyleNotebookFrameBorders; 334 aClientRect:=Rect(0,0, 335 Max(0,aWidth-FrameBorders.Left-FrameBorders.Right), 336 Max(0,aHeight-FrameBorders.Top-FrameBorders.Bottom)); 337 Result:=true; 338 {$IFDEF VerboseSizeMsg} 339 DebugLn(['TGtk2WSCustomTabControl.GetDefaultClientRect END FrameBorders=',dbgs(FrameBorders),' aClientRect=',dbgs(aClientRect)]); 340 {$ENDIF} 341 end; 342 end; 343end; 344 345class procedure TGtk2WSCustomTabControl.AddPage(const ATabControl: TCustomTabControl; 346 const AChild: TCustomPage; const AIndex: integer); 347{ 348 Inserts a new page to a notebook at position Index. The ATabControl is a 349 TCustomTabControl, the AChild one of its TCustomPage. Both handles must already 350 be created. ATabControl Handle is a PGtkNoteBook and APage handle is a 351 PGtkHBox. 352 This procedure creates a new tab with an optional image, the page caption and 353 an optional close button. The image and the caption will also be added to the 354 tab popup menu. 355} 356var 357 NoteBookWidget: PGtkWidget; // the notebook 358 PageWidget: PGtkWidget; // the page (content widget) 359 TabWidget: PGtkWidget; // the tab (hbox containing a pixmap, a label 360 // and a close button) 361 TabLabelWidget: PGtkWidget; // the label in the tab 362 MenuWidget: PGtkWidget; // the popup menu (hbox containing a pixmap and 363 // a label) 364 MenuLabelWidget: PGtkWidget; // the label in the popup menu item 365begin 366 {$IFDEF NOTEBOOK_DEBUG} 367 DebugLn(['TGtkWSCustomTabControl.AddPage ',dbgsName(ATabControl),' ',ATabControl.HandleAllocated,' AChild=',dbgsName(AChild),' ',AChild.HandleAllocated,' Child.TabVisible=',AChild.TabVisible]); 368 {$ENDIF} 369 NoteBookWidget := {%H-}PGtkWidget(ATabControl.Handle); 370 PageWidget := {%H-}PGtkWidget(AChild.Handle); 371 372 // set LCL size 373 AChild.SetBounds(AChild.Left, AChild.Top, ATabControl.ClientWidth, ATabControl.ClientHeight); 374 375 if (ATabControl is TTabControl) then begin 376 if AChild.HandleObjectShouldBeVisible then 377 gtk_widget_show(PageWidget); 378 exit; 379 end; 380 381 382 // For a PageNotebook the widget must be visible 383 // If not the page control will not use it. It may not even show the tab 384 gtk_widget_show(PageWidget); 385 386 // Check if already created. if so just show it because it is invisible 387 if gtk_notebook_get_tab_label(PGtkNoteBook(NoteBookWidget), PageWidget) <> nil 388 then begin 389 {$IFDEF NOTEBOOK_DEBUG} 390 DebugLn(['TGtkWSCustomTabControl.AddPage already added']); 391 {$ENDIF} 392 exit; 393 end; 394 395 // create the tab (hbox container) 396 TabWidget := gtk_hbox_new(false, 1); 397 g_object_set_data(PGObject(TabWidget), 'TabImage', nil); 398 g_object_set_data(PGObject(TabWidget), 'TabCloseBtn', nil); 399 // put a label into the tab 400 TabLabelWidget := gtk_label_new(''); 401 g_object_set_data(PGObject(TabWidget), 'TabLabel', TabLabelWidget); 402 gtk_widget_show(TabLabelWidget); 403 gtk_box_pack_start_defaults(PGtkBox(TabWidget), TabLabelWidget); 404 405 if AChild.TabVisible then 406 gtk_widget_show(TabWidget); 407 408 // create popup menu item 409 MenuWidget := gtk_hbox_new(false, 2); 410 // set icon widget to nil 411 g_object_set_data(PGObject(MenuWidget), 'TabImage', nil); 412 // put a label into the menu 413 MenuLabelWidget := gtk_label_new(''); 414 g_object_set_data(PGObject(MenuWidget), 'TabMenuLabel', MenuLabelWidget); 415 gtk_widget_show(MenuLabelWidget); 416 gtk_box_pack_start_defaults(PGtkBox(MenuWidget), MenuLabelWidget); 417 418 if AChild.TabVisible then 419 gtk_widget_show(MenuWidget); 420 421 // insert the page 422 gtk_notebook_insert_page_menu(PGtkNotebook(NotebookWidget), PageWidget, 423 TabWidget, MenuWidget, AIndex); 424 425 UpdateNotebookPageTab(ATabControl, AChild); 426 UpdateNoteBookClientWidget(ATabControl); 427 UpdateNotebookTabFont(AChild, AChild.Font); 428 429 // init the size of the page widget 430 //DebugLn(['TGtkWSCustomTabControl.AddPage ',DbgSName(ATabControl),' ',dbgs(ATabControl.BoundsRect)]); 431 {$IFDEF VerboseSizeMsg} 432 DebugLn(['TGtkWSCustomTabControl.AddPage PageWidget^.allocation=',dbgs(PageWidget^.allocation),' NotebookWidget=',dbgs(NotebookWidget^.allocation)]); 433 {$ENDIF} 434end; 435 436class procedure TGtk2WSCustomTabControl.MovePage(const ATabControl: TCustomTabControl; 437 const AChild: TCustomPage; const NewIndex: integer); 438var 439 NoteBookWidget: PGtkNotebook; 440begin 441 if (ATabControl is TTabControl) then 442 exit; 443 444 NoteBookWidget:={%H-}PGtkNotebook(ATabControl.Handle); 445 gtk_notebook_reorder_child(NoteBookWidget, {%H-}PGtkWidget(AChild.Handle), NewIndex); 446 UpdateNoteBookClientWidget(ATabControl); 447end; 448 449class function TGtk2WSCustomTabControl.GetCapabilities: TCTabControlCapabilities; 450begin 451 Result:=[nbcPageListPopup, nbcShowCloseButtons]; 452end; 453 454class function TGtk2WSCustomTabControl.GetNotebookMinTabHeight( 455 const AWinControl: TWinControl): integer; 456var 457 FrameBorders: TRect; 458begin 459 FrameBorders:=GetStyleNotebookFrameBorders; 460 Result := FrameBorders.Top; // +1 for getting size, +1 to see border line 461 if Result<=0 then 462 Result:=inherited GetNotebookMinTabHeight(AWinControl); 463 //debugln('TGtkWSCustomTabControl.GetNotebookMinTabHeight A ',dbgs(Result)); 464end; 465 466class function TGtk2WSCustomTabControl.GetNotebookMinTabWidth( 467 const AWinControl: TWinControl): integer; 468begin 469 Result:=TWSCustomTabControl.GetNotebookMinTabWidth(AWinControl); 470end; 471 472class function TGtk2WSCustomTabControl.GetTabIndexAtPos( 473 const ATabControl: TCustomTabControl; const AClientPos: TPoint): integer; 474var 475 NoteBookWidget: PGtkNotebook; 476 i: integer; 477 TabWidget: PGtkWidget; 478 PageWidget: PGtkWidget; 479 NotebookPos: TPoint; 480 Window: PGdkWindow; 481 WindowOrg,ClientOrg: TPoint; 482 Count: guint; 483begin 484 Result:=-1; 485 if (ATabControl is TTabControl) then 486 exit; 487 488 NoteBookWidget:={%H-}PGtkNotebook(ATabControl.Handle); 489 if (NotebookWidget=nil) then exit; 490 //DebugLn(['TGtkWSCustomTabControl.GetTabIndexAtPos ',GetWidgetDebugReport(PGtkWidget(NotebookWidget))]); 491 Window := GetControlWindow(NoteBookWidget); 492 gdk_window_get_origin(Window,@WindowOrg.X,@WindowOrg.Y); 493 ClientOrg:=GetWidgetClientOrigin(PGtkWidget(NotebookWidget)); 494 NotebookPos.X:= AClientPos.X + (ClientOrg.X-WindowOrg.X); 495 NotebookPos.Y:= AClientPos.Y + (ClientOrg.Y-WindowOrg.Y); 496 // go through all tabs 497 Count:=g_list_length(NoteBookWidget^.Children); 498 for i:=0 to Count-1 do 499 begin 500 PageWidget:=gtk_notebook_get_nth_page(NoteBookWidget,i); 501 if PageWidget<>nil then 502 begin 503 TabWidget:=gtk_notebook_get_tab_label(NoteBookWidget, PageWidget); 504 if (TabWidget<>nil) and GTK_WIDGET_MAPPED(TabWidget) then 505 begin 506 // test if position is in tabwidget 507 if (TabWidget^.Allocation.X<=NoteBookPos.X) 508 and (TabWidget^.Allocation.Y<=NoteBookPos.Y) 509 and (TabWidget^.Allocation.X+TabWidget^.Allocation.Width>NoteBookPos.X) 510 and (TabWidget^.Allocation.Y+TabWidget^.Allocation.Height>NoteBookPos.Y) 511 then begin 512 Result:=i; 513 exit; 514 end; 515 end; 516 end; 517 end; 518end; 519 520class function TGtk2WSCustomTabControl.GetTabRect(const ATabControl: TCustomTabControl; 521 const AIndex: Integer): TRect; 522var 523 NoteBookWidget: PGtkNotebook; 524 TabWidget: PGtkWidget; 525 PageWidget: PGtkWidget; 526 Count: guint; 527 OffsetPage: TRect; 528begin 529 Result := inherited; 530 if (ATabControl is TTabControl) then 531 exit; 532 533 NoteBookWidget:={%H-}PGtkNotebook(ATabControl.Handle); 534 if (NotebookWidget=nil) then exit; 535 536 Count := g_list_length(NoteBookWidget^.Children); 537 PageWidget := gtk_notebook_get_nth_page(NoteBookWidget, AIndex); 538 if (PageWidget<>nil) and (AIndex < Count) then 539 begin 540 TabWidget := gtk_notebook_get_tab_label(NoteBookWidget, PageWidget); 541 if TabWidget <> nil then 542 begin 543 OffsetPage := RectFromGdkRect(PageWidget^.allocation); 544 Result := RectFromGdkRect(TabWidget^.allocation); 545 OffsetRect(Result, -OffsetPage.Left, -OffsetPage.Top); 546 end; 547 end; 548end; 549 550class procedure TGtk2WSCustomTabControl.SetPageIndex( 551 const ATabControl: TCustomTabControl; const AIndex: integer); 552var 553 GtkNotebook: PGtkNotebook; 554 ANewIndex: Integer; 555 Page: PGtkWidget; 556begin 557 if (ATabControl is TTabControl) then 558 exit; 559 560 if not WSCheckHandleAllocated(ATabControl, 'SetPageIndex') then 561 Exit; 562 if (AIndex < 0) or (AIndex > ATabControl.PageCount - 1) then 563 exit; 564 ANewIndex:=ATabControl.PageToTabIndex(AIndex); 565 if (ANewIndex < 0) then 566 exit; 567 GtkNotebook := {%H-}PGtkNoteBook(ATabControl.Handle); 568 if gtk_notebook_get_current_page(GtkNotebook) <> AIndex then 569 begin 570 // gtk2 cannot set page if some tab in between tabvisible=false, so 571 // we must compare page handles. 572 if ATabControl.Page[AIndex].HandleAllocated then 573 begin 574 Page := {%H-}PGtkWidget(ATabControl.Page[AIndex].Handle); 575 ANewIndex := gtk_notebook_page_num(GtkNoteBook, Page); 576 g_object_set_data(PGObject(GtkNotebook), LCL_NotebookManualPageSwitchKey, ATabControl); 577 gtk_notebook_set_page(GtkNotebook, ANewIndex); 578 end; 579 end; 580 UpdateNoteBookClientWidget(ATabControl); 581end; 582 583class procedure TGtk2WSCustomTabControl.SetTabPosition( 584 const ATabControl: TCustomTabControl; const ATabPosition: TTabPosition); 585begin 586 if (ATabControl is TTabControl) then 587 exit; 588 589 gtk_notebook_set_tab_pos({%H-}PGtkNotebook(ATabControl.Handle), 590 GtkPositionTypeMap[ATabPosition]); 591end; 592 593class procedure TGtk2WSCustomTabControl.ShowTabs(const ATabControl: TCustomTabControl; 594 AShowTabs: boolean); 595begin 596 if IsTTabControl({%H-}PGtkWidget(ATabControl.Handle)) then 597 {$IFDEF NOTEBOOK_DEBUG} 598 writeln('**** TGtk2WSCustomTabControl.ShowTabs DO NOT SHOW TABS ON CUSTOM CONTROL !') 599 {$ENDIF} 600 else 601 gtk_notebook_set_show_tabs({%H-}PGtkNotebook(ATabControl.Handle), AShowTabs); 602end; 603 604class procedure TGtk2WSCustomTabControl.UpdateProperties(const ATabControl: TCustomTabControl); 605begin 606 if (ATabControl is TTabControl) then 607 exit; 608 609 if (nboHidePageListPopup in ATabControl.Options) then 610 gtk_notebook_popup_disable({%H-}PGtkNotebook(ATabControl.Handle)) 611 else 612 gtk_notebook_popup_enable({%H-}PGtkNotebook(ATabControl.Handle)); 613end; 614 615 616 617{ TGtk2WSCustomPage } 618 619class procedure TGtk2WSCustomPage.SetCallbacks(const AGtkWidget: PGtkWidget; 620 const AWidgetInfo: PWidgetInfo); 621begin 622 TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); 623end; 624 625class function TGtk2WSCustomPage.CreateHandle(const AWinControl: TWinControl; 626 const AParams: TCreateParams): TLCLIntfHandle; 627var 628 Widget: PGtkWidget; 629 WidgetInfo: PWidgetInfo; 630begin 631 Widget := Gtk2Widgetset.CreateSimpleClientAreaWidget(AWinControl, True); 632 {$IFDEF DebugLCLComponents} 633 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 634 {$ENDIF} 635 Result := TLCLIntfHandle({%H-}PtrUInt(Widget)); 636 637 WidgetInfo := GetWidgetInfo(Widget); 638 WidgetInfo^.LCLObject := AWinControl; 639 WidgetInfo^.Style := AParams.Style; 640 WidgetInfo^.ExStyle := AParams.ExStyle; 641 WidgetInfo^.WndProc := {%H-}PtrUInt(AParams.WindowClass.lpfnWndProc); 642 643 Set_RC_Name(AWinControl, Widget); 644 SetCallBacks(Widget, WidgetInfo); 645end; 646 647class procedure TGtk2WSCustomPage.UpdateProperties(const ACustomPage: TCustomPage); 648var 649 NoteBook: PGtkWidget; 650 PageWidget: PGtkWidget; 651 TabWidget: PGtkWidget; 652 TabImageWidget: PGtkWidget; 653begin 654 if (ACustomPage.Parent <> nil) and (ACustomPage.Parent is TTabControl) then 655 exit; 656 657 UpdateNotebookPageTab(nil, ACustomPage); 658 {we must update our icon (if exists) otherwise it will be updated only 659 when our tab reach focus} 660 if not (csDesigning in ACustomPage.ComponentState) 661 and not ACustomPage.TabVisible 662 or not ACustomPage.HandleAllocated 663 or not Assigned(ACustomPage.Parent) 664 then 665 exit; 666 667 PageWidget := {%H-}PGtkWidget(ACustomPage.Handle); 668 NoteBook := {%H-}PGtkWidget(ACustomPage.Parent.Handle); 669 if (NoteBook = nil) or not GTK_IS_NOTEBOOK(NoteBook) then 670 exit; 671 672 TabWidget := gtk_notebook_get_tab_label(PGtkNoteBook(Notebook), PageWidget); 673 if (TabWidget = nil) or not GTK_WIDGET_VISIBLE(TabWidget) then 674 exit; 675 676 TabImageWidget := g_object_get_data(PGObject(TabWidget), 'TabImage'); 677 if TabImageWidget <> nil then 678 gtk_widget_queue_draw(TabImageWidget); 679end; 680 681class procedure TGtk2WSCustomPage.SetBounds(const AWinControl: TWinControl; 682 const ALeft, ATop, AWidth, AHeight: Integer); 683begin 684 if (AWinControl.Parent <> nil) and (AWinControl.Parent is TTabControl) then begin 685 // call inherited; need to do it this way, 686 // because the compile time ancestor class is TWSCustomListView 687 TWSWinControlClass(ClassParent).SetBounds(AWinControl, ALeft, ATop, AWidth, AHeight); 688 inherited; 689 exit; 690 end; 691 692 // ignore resizes from the LCL 693end; 694 695class procedure TGtk2WSCustomPage.SetFont(const AWinControl: TWinControl; 696 const AFont: TFont); 697begin 698 if (AWinControl.Parent <> nil) and (AWinControl.Parent is TTabControl) then begin 699 // runtime inherited 700 TWSWinControlClass(ClassParent).SetFont(AWinControl, AFont); 701 exit; 702 end; 703 704 if not WSCheckHandleAllocated(AWinControl, 'SetFont') then 705 exit; 706 UpdateNotebookTabFont(AWinControl, AFont); 707end; 708 709class procedure TGtk2WSCustomPage.ShowHide(const AWinControl: TWinControl); 710begin 711 if not WSCheckHandleAllocated(AWinControl, 'ShowHide') then 712 exit; 713 714 // In a PageNoteBook, the child widget must always be visible 715 // it will be controlled by gtk_notebook_set_page 716 // Making a page invisible, also hides the tab. 717 if (AWinControl.Parent = nil) or (AWinControl.Parent is TCustomTabControl) then 718 exit; 719 720 TGtk2WidgetSet(WidgetSet).SetVisible(AWinControl, AWinControl.HandleObjectShouldBeVisible); 721end; 722 723class function TGtk2WSCustomPage.GetDefaultClientRect( 724 const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer; 725 var aClientRect: TRect): boolean; 726begin 727 if (AWinControl.Parent <> nil) and (AWinControl.Parent is TTabControl) then begin 728 // runtime inherited 729 Result := TWSWinControlClass(ClassParent).GetDefaultClientRect( 730 AWinControl, aLeft, aTop, aWidth, aHeight, aClientRect); 731 exit; 732 end; 733 734 Result:=false; 735 if AWinControl.Parent=nil then exit; 736 if AWinControl.HandleAllocated and AWinControl.Parent.HandleAllocated 737 and ({%H-}PGtkWidget(AWinControl.Handle)^.parent<>nil) then 738 begin 739 740 end else begin 741 Result:=true; 742 aClientRect:=AWinControl.Parent.ClientRect; 743 //DebugLn(['TGtk2WSCustomPage.GetDefaultClientRect ',DbgSName(AWinControl),' Parent=',DbgSName(AWinControl.Parent),' ParentBounds=',dbgs(AWinControl.Parent.BoundsRect),' ParentClient=',dbgs(AWinControl.Parent.ClientRect)]); 744 end; 745 {$IFDEF VerboseSizeMsg} 746 if Result then DebugLn(['TGtk2WSCustomPage.GetDefaultClientRect ',DbgSName(AWinControl),' aClientRect=',dbgs(aClientRect)]); 747 {$ENDIF} 748end; 749 750