226
GtkPositionTypeMap: array[TTabPosition] of TGtkPositionType =
228
{ tpTop } GTK_POS_TOP,
229
{ tpBottom } GTK_POS_BOTTOM,
230
{ tpLeft } GTK_POS_LEFT,
231
{ tpRight } GTK_POS_RIGHT
234
LCL_NotebookManualPageSwitchKey = 'lcl_manual_page_switch';
238
GtkNotebookPressEventProc = function (widget:PGtkWidget; event:PGdkEventButton):gboolean; cdecl;
241
OldNoteBookButtonPress: GtkNotebookPressEventProc = nil;
243
// this was created as a workaround of a tnotebook eating rightclick of custom controls
244
function Notebook_Button_Press(widget:PGtkWidget; event:PGdkEventButton):gboolean; cdecl;
247
if gtk_get_event_widget(PGdkEvent(event)) <> widget then exit;
248
if OldNoteBookButtonPress = nil then exit;
249
Result := OldNoteBookButtonPress(widget, event);
252
procedure HookNoteBookClass;
254
WidgetClass: PGtkWidgetClass;
256
WidgetClass := GTK_WIDGET_CLASS(gtk_type_class(gtk_notebook_get_type));
258
OldNoteBookButtonPress := GtkNotebookPressEventProc(WidgetClass^.button_press_event);
259
WidgetClass^.button_press_event := @Notebook_Button_Press;
262
{ TGtk2WSCustomNotebook }
265
function NotebookPageRealToLCLIndex(const ANotebook: TCustomNotebook; AIndex: integer): integer;
270
if csDesigning in ANotebook.ComponentState then exit;
272
while (I < ANotebook.PageCount) and (I <= Result) do
274
if not ANotebook.Page[I].TabVisible then Inc(Result);
280
function GtkWSNotebook_SwitchPage(widget: PGtkWidget; page: Pgtkwidget; pagenum: integer; data: gPointer): GBoolean; cdecl;
286
Result := CallBackDefaultReturn;
287
EventTrace('switch-page', data);
288
UpdateNoteBookClientWidget(TObject(Data));
291
IsManual := gtk_object_get_data(PGtkObject(Widget), LCL_NotebookManualPageSwitchKey) <> nil;
293
gtk_object_set_data(PGtkObject(Widget), LCL_NotebookManualPageSwitchKey, nil);
294
if PGtkNotebook(Widget)^.cur_page = nil then // for windows compatibility
297
// gtkswitchpage is called before the switch
300
// send first the TCN_SELCHANGING to ask if switch is allowed
301
FillChar(Mess, SizeOf(Mess), 0);
302
Mess.Msg := LM_NOTIFY;
303
FillChar(NMHdr, SizeOf(NMHdr), 0);
304
NMHdr.code := TCN_SELCHANGING;
305
NMHdr.hwndFrom := PtrUInt(widget);
306
NMHdr.idFrom := NotebookPageRealToLCLIndex(TCustomNotebook(Data), pagenum); //use this to set pageindex to the correct page.
307
Mess.NMHdr := @NMHdr;
309
DeliverMessage(Data, Mess);
310
if Mess.Result <> 0 then
312
g_signal_stop_emission_by_name(PGtkObject(Widget), 'switch-page');
313
Result := not CallBackDefaultReturn;
318
// then send the new page
319
FillChar(Mess, SizeOf(Mess), 0);
320
Mess.Msg := LM_NOTIFY;
321
FillChar(NMHdr, SizeOf(NMHdr), 0);
322
NMHdr.code := TCN_SELCHANGE;
323
NMHdr.hwndFrom := PtrUInt(widget);
324
NMHdr.idFrom := NotebookPageRealToLCLIndex(TCustomNotebook(Data), pagenum); //use this to set pageindex to the correct page.
325
Mess.NMHdr := @NMHdr;
326
DeliverMessage(Data, Mess);
329
class procedure TGtk2WSCustomNotebook.SetCallbacks(
330
const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo);
332
TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
333
ConnectSignal(PGtkObject(AGtkWidget), 'switch_page', @GtkWSNotebook_SwitchPage, AWidgetInfo^.LCLObject);
336
class function TGtk2WSCustomNotebook.CreateHandle(const AWinControl: TWinControl;
337
const AParams: TCreateParams): HWND;
339
AWidget: PGtkNoteBook;
340
WidgetInfo: PWidgetInfo;
342
if OldNoteBookButtonPress = nil then
344
//DebugLn(['TGtk2WSCustomNotebook.CreateHandle ',DbgSName(AWinControl)]);
346
AWidget := PGtkNoteBook(gtk_notebook_new());
347
WidgetInfo := CreateWidgetInfo(AWidget, AWinControl, AParams);
348
{$IFDEF DebugLCLComponents}
349
DebugGtkWidgets.MarkCreated(Pointer(AWidget), dbgsName(AWinControl));
351
gtk_notebook_set_scrollable(AWidget, True);
353
if not (nboHidePageListPopup in TCustomNotebook(AWinControl).Options) then
354
gtk_notebook_popup_enable(AWidget);
356
if TCustomNotebook(AWinControl).PageCount=0 then
357
// a gtk notebook needs a page -> add dummy page
358
Gtk2WidgetSet.AddDummyNoteBookPage(AWidget);
360
gtk_notebook_set_tab_pos(AWidget, GtkPositionTypeMap[TCustomNotebook(AWinControl).TabPosition]);
361
Result := HWND(TLCLIntfHandle(PtrUInt(AWidget)));
362
Set_RC_Name(AWinControl, PGtkWidget(AWidget));
363
SetCallBacks(PGtkWidget(AWidget), WidgetInfo);
366
class function TGtk2WSCustomNotebook.GetDefaultClientRect(
367
const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer;
368
var aClientRect: TRect): boolean;
373
//DebugLn(['TGtk2WSCustomNotebook.GetDefaultClientRect ',DbgSName(AWinControl),' ',aWidth,'x',aHeight]);
374
if AWinControl.HandleAllocated then begin
377
FrameBorders:=GetStyleNotebookFrameBorders;
378
aClientRect:=Rect(0,0,
379
Max(0,aWidth-FrameBorders.Left-FrameBorders.Right),
380
Max(0,aHeight-FrameBorders.Top-FrameBorders.Bottom));
383
{$IFDEF VerboseSizeMsg}
384
if Result then DebugLn(['TGtk2WSCustomNotebook.GetDefaultClientRect END FrameBorders=',dbgs(FrameBorders),' aClientRect=',dbgs(aClientRect)]);
388
class procedure TGtk2WSCustomNotebook.AddPage(const ANotebook: TCustomNotebook;
389
const AChild: TCustomPage; const AIndex: integer);
391
Inserts a new page to a notebook at position Index. The ANotebook is a
392
TCustomNoteBook, the AChild one of its TCustomPage. Both handles must already
393
be created. ANoteBook Handle is a PGtkNoteBook and APage handle is a
395
This procedure creates a new tab with an optional image, the page caption and
396
an optional close button. The image and the caption will also be added to the
400
NoteBookWidget: PGtkWidget; // the notebook
401
PageWidget: PGtkWidget; // the page (content widget)
402
TabWidget: PGtkWidget; // the tab (hbox containing a pixmap, a label
403
// and a close button)
404
TabLabelWidget: PGtkWidget; // the label in the tab
405
MenuWidget: PGtkWidget; // the popup menu (hbox containing a pixmap and
407
MenuLabelWidget: PGtkWidget; // the label in the popup menu item
409
{$IFDEF NOTEBOOK_DEBUG}
410
DebugLn(['TGtkWSCustomNotebook.AddPage ',dbgsName(ANoteBook),' ',ANotebook.HandleAllocated,' AChild=',dbgsName(AChild),' ',AChild.HandleAllocated,' Child.TabVisible=',AChild.TabVisible]);
412
NoteBookWidget := PGtkWidget(ANoteBook.Handle);
413
PageWidget := PGtkWidget(AChild.Handle);
416
AChild.SetBounds(AChild.Left, AChild.Top, ANotebook.ClientWidth, ANotebook.ClientHeight);
418
if AChild.TabVisible then
419
gtk_widget_show(PageWidget);
421
// Check if already created. if so just show it because it is invisible
422
if gtk_notebook_get_tab_label(PGtkNoteBook(NoteBookWidget), PageWidget) <> nil
424
{$IFDEF NOTEBOOK_DEBUG}
425
DebugLn(['TGtkWSCustomNotebook.AddPage already added']);
430
// create the tab (hbox container)
431
TabWidget := gtk_hbox_new(false, 1);
432
gtk_object_set_data(PGtkObject(TabWidget), 'TabImage', nil);
433
gtk_object_set_data(PGtkObject(TabWidget), 'TabCloseBtn', nil);
434
// put a label into the tab
435
TabLabelWidget := gtk_label_new('');
436
gtk_object_set_data(PGtkObject(TabWidget), 'TabLabel', TabLabelWidget);
437
gtk_widget_show(TabLabelWidget);
438
gtk_box_pack_start_defaults(PGtkBox(TabWidget), TabLabelWidget);
440
if AChild.TabVisible then
441
gtk_widget_show(TabWidget);
443
// create popup menu item
444
MenuWidget := gtk_hbox_new(false, 2);
445
// set icon widget to nil
446
gtk_object_set_data(PGtkObject(MenuWidget), 'TabImage', nil);
447
// put a label into the menu
448
MenuLabelWidget := gtk_label_new('');
449
gtk_object_set_data(PGtkObject(MenuWidget), 'TabLabel', MenuLabelWidget);
450
gtk_widget_show(MenuLabelWidget);
451
gtk_box_pack_start_defaults(PGtkBox(MenuWidget), MenuLabelWidget);
453
if AChild.TabVisible then
454
gtk_widget_show(MenuWidget);
456
// remove the dummy page (a gtk_notebook needs at least one page)
457
RemoveDummyNoteBookPage(PGtkNotebook(NoteBookWidget));
459
gtk_notebook_insert_page_menu(PGtkNotebook(NotebookWidget), PageWidget,
460
TabWidget, MenuWidget, AIndex);
462
UpdateNotebookPageTab(ANoteBook, AChild);
463
UpdateNoteBookClientWidget(ANoteBook);
465
// init the size of the page widget
466
//DebugLn(['TGtkWSCustomNotebook.AddPage ',DbgSName(ANoteBook),' ',dbgs(ANoteBook.BoundsRect)]);
467
{$IFDEF VerboseSizeMsg}
468
DebugLn(['TGtkWSCustomNotebook.AddPage PageWidget^.allocation=',dbgs(PageWidget^.allocation),' NotebookWidget=',dbgs(NotebookWidget^.allocation)]);
472
class procedure TGtk2WSCustomNotebook.MovePage(const ANotebook: TCustomNotebook;
473
const AChild: TCustomPage; const NewIndex: integer);
475
NoteBookWidget: PGtkNotebook;
477
NoteBookWidget:=PGtkNotebook(ANoteBook.Handle);
478
gtk_notebook_reorder_child(NoteBookWidget, PGtkWidget(AChild.Handle), NewIndex);
479
UpdateNoteBookClientWidget(ANoteBook);
482
class procedure TGtk2WSCustomNotebook.RemovePage(const ANotebook: TCustomNotebook;
483
const AIndex: integer);
485
PageWidget: PGtkWidget;
488
// The gtk does not provide a function to remove a page without destroying it.
489
// Luckily the LCL destroys the Handle, when a page is removed, so this
490
// function is not needed.
491
{$IFDEF NOTEBOOK_DEBUG}
492
DebugLn(['TGtkWSCustomNotebook.RemovePage AIndex=',AIndex,' ',DbgSName(ANotebook.Page[AIndex])]);
494
Page:=ANotebook.Page[AIndex];
495
if not Page.HandleAllocated then exit;
496
PageWidget := PGtkWidget(Page.Handle);
497
gtk_widget_hide(PageWidget);
500
class function TGtk2WSCustomNotebook.GetCapabilities: TNoteBookCapabilities;
502
Result:=[nbcPageListPopup, nbcShowCloseButtons];
505
class function TGtk2WSCustomNotebook.GetNotebookMinTabHeight(
506
const AWinControl: TWinControl): integer;
508
NBWidget: PGTKWidget;
509
BorderWidth: Integer;
510
Page: PGtkNotebookPage;
512
Result:=inherited GetNotebookMinTabHeight(AWinControl);
513
//debugln('TGtkWSCustomNotebook.GetNotebookMinTabHeight A ',dbgs(Result));
516
debugln('TGtkWSCustomNotebook.GetNotebookMinTabHeight A ',dbgs(AWinControl.HandleAllocated));
517
if AWinControl.HandleAllocated then
518
NBWidget:=PGTKWidget(AWinControl.Handle)
520
NBWidget:=GetStyleWidget(lgsNotebook);
522
// ToDo: find out how to create a fully working hidden Notebook style widget
524
if (NBWidget=nil) then begin
525
Result:=TWSCustomNotebook.GetNotebookMinTabHeight(AWinControl);
528
debugln('TGtkWSCustomNotebook.GetNotebookMinTabHeight NBWidget: ',GetWidgetDebugReport(NBWidget),
529
' ',dbgs(NBWidget^.allocation.width),'x',dbgs(NBWidget^.allocation.height));
531
BorderWidth:=(PGtkContainer(NBWidget)^.flag0 and bm_TGtkContainer_border_width)
532
shr bp_TGtkContainer_border_width;
533
if PGtkNoteBook(NBWidget)^.first_tab<>nil then
534
Page:=PGtkNoteBook(NBWidget)^.cur_page;
537
if (Page<>nil) then begin
538
debugln('TGtkWSCustomNotebook.RemovePage TODO');
540
debugln('TGtkWSCustomNotebook.GetNotebookMinTabHeight END ',dbgs(Result),' ',
541
GetWidgetDebugReport(NBWidget));
544
class function TGtk2WSCustomNotebook.GetNotebookMinTabWidth(
545
const AWinControl: TWinControl): integer;
547
Result:=TWSCustomNotebook.GetNotebookMinTabWidth(AWinControl);
550
class function TGtk2WSCustomNotebook.GetTabIndexAtPos(
551
const ANotebook: TCustomNotebook; const AClientPos: TPoint): integer;
553
NoteBookWidget: PGtkNotebook;
555
TabWidget: PGtkWidget;
556
PageWidget: PGtkWidget;
559
WindowOrg,ClientOrg: TPoint;
563
NoteBookWidget:=PGtkNotebook(ANotebook.Handle);
564
if (NotebookWidget=nil) then exit;
565
//DebugLn(['TGtkWSCustomNotebook.GetTabIndexAtPos ',GetWidgetDebugReport(PGtkWidget(NotebookWidget))]);
566
Window := GetControlWindow(NoteBookWidget);
567
gdk_window_get_origin(Window,@WindowOrg.X,@WindowOrg.Y);
568
ClientOrg:=GetWidgetClientOrigin(PGtkWidget(NotebookWidget));
569
NotebookPos.X:= AClientPos.X + (ClientOrg.X-WindowOrg.X);
570
NotebookPos.Y:= AClientPos.Y + (ClientOrg.Y-WindowOrg.Y);
571
// go through all tabs
572
Count:=g_list_length(NoteBookWidget^.Children);
573
for i:=0 to Count-1 do
575
PageWidget:=gtk_notebook_get_nth_page(NoteBookWidget,i);
576
if PageWidget<>nil then
578
TabWidget:=gtk_notebook_get_tab_label(NoteBookWidget, PageWidget);
579
if (TabWidget<>nil) and GTK_WIDGET_MAPPED(TabWidget) then
581
// test if position is in tabwidget
582
if (TabWidget^.Allocation.X<=NoteBookPos.X)
583
and (TabWidget^.Allocation.Y<=NoteBookPos.Y)
584
and (TabWidget^.Allocation.X+TabWidget^.Allocation.Width>NoteBookPos.X)
585
and (TabWidget^.Allocation.Y+TabWidget^.Allocation.Height>NoteBookPos.Y)
595
class function TGtk2WSCustomNotebook.GetTabRect(const ANotebook: TCustomNotebook;
596
const AIndex: Integer): TRect;
598
NoteBookWidget: PGtkNotebook;
599
TabWidget: PGtkWidget;
600
PageWidget: PGtkWidget;
604
NoteBookWidget:=PGtkNotebook(ANotebook.Handle);
605
if (NotebookWidget=nil) then exit;
607
Count := g_list_length(NoteBookWidget^.Children);
608
PageWidget := gtk_notebook_get_nth_page(NoteBookWidget, AIndex);
609
if (PageWidget<>nil) and (AIndex < Count) then
611
TabWidget := gtk_notebook_get_tab_label(NoteBookWidget, PageWidget);
612
if TabWidget <> nil then
613
Result := RectFromGdkRect(TabWidget^.allocation);
617
class procedure TGtk2WSCustomNotebook.SetPageIndex(
618
const ANotebook: TCustomNotebook; const AIndex: integer);
620
GtkNotebook: PGtkNotebook;
622
if not WSCheckHandleAllocated(ANotebook, 'SetPageIndex') then
625
GtkNotebook := PGtkNoteBook(ANotebook.Handle);
626
if gtk_notebook_get_current_page(GtkNotebook) <> AIndex then
628
gtk_object_set_data(PGtkObject(GtkNotebook), LCL_NotebookManualPageSwitchKey, ANotebook);
629
gtk_notebook_set_page(GtkNotebook, AIndex);
631
UpdateNoteBookClientWidget(ANotebook);
634
class procedure TGtk2WSCustomNotebook.SetTabPosition(
635
const ANotebook: TCustomNotebook; const ATabPosition: TTabPosition);
637
gtk_notebook_set_tab_pos(PGtkNotebook(ANotebook.Handle),
638
GtkPositionTypeMap[ATabPosition]);
641
class procedure TGtk2WSCustomNotebook.ShowTabs(const ANotebook: TCustomNotebook;
644
gtk_notebook_set_show_tabs(PGtkNotebook(ANotebook.Handle), AShowTabs);
647
class procedure TGtk2WSCustomNotebook.UpdateProperties(const ANotebook: TCustomNotebook);
649
if (nboHidePageListPopup in ANoteBook.Options) then
650
gtk_notebook_popup_disable(PGtkNotebook(ANoteBook.Handle))
652
gtk_notebook_popup_enable(PGtkNotebook(ANoteBook.Handle));
657
{ TGtk2WSCustomPage }
659
class procedure TGtk2WSCustomPage.SetCallbacks(const AGtkWidget: PGtkWidget;
660
const AWidgetInfo: PWidgetInfo);
662
TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject));
665
class function TGtk2WSCustomPage.CreateHandle(const AWinControl: TWinControl;
666
const AParams: TCreateParams): TLCLIntfHandle;
669
WidgetInfo: PWidgetInfo;
671
Widget := Gtk2Widgetset.CreateSimpleClientAreaWidget(AWinControl, True);
672
{$IFDEF DebugLCLComponents}
673
DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl));
675
Result := TLCLIntfHandle(PtrUInt(Widget));
677
WidgetInfo := GetWidgetInfo(Widget);
678
WidgetInfo^.LCLObject := AWinControl;
679
WidgetInfo^.Style := AParams.Style;
680
WidgetInfo^.ExStyle := AParams.ExStyle;
681
WidgetInfo^.WndProc := PtrUInt(AParams.WindowClass.lpfnWndProc);
683
Set_RC_Name(AWinControl, Widget);
684
SetCallBacks(Widget, WidgetInfo);
687
class procedure TGtk2WSCustomPage.UpdateProperties(const ACustomPage: TCustomPage);
689
NoteBook: PGtkWidget;
690
PageWidget: PGtkWidget;
691
TabWidget: PGtkWidget;
692
TabImageWidget: PGtkWidget;
694
UpdateNotebookPageTab(nil, ACustomPage);
695
{we must update our icon (if exists) otherwise it will be updated only
696
when our tab reach focus}
697
if not (csDesigning in ACustomPage.ComponentState)
698
and not ACustomPage.TabVisible
699
or not ACustomPage.HandleAllocated
700
or not Assigned(ACustomPage.Parent)
704
PageWidget := PGtkWidget(ACustomPage.Handle);
705
NoteBook := PGtkWidget(ACustomPage.Parent.Handle);
706
if (NoteBook = nil) or not GTK_IS_NOTEBOOK(NoteBook) then
709
TabWidget := gtk_notebook_get_tab_label(PGtkNoteBook(Notebook), PageWidget);
710
if (TabWidget = nil) or not GTK_WIDGET_VISIBLE(TabWidget) then
713
TabImageWidget := gtk_object_get_data(PGtkObject(TabWidget), 'TabImage');
714
if TabImageWidget <> nil then
715
gtk_widget_queue_draw(TabImageWidget);
718
class procedure TGtk2WSCustomPage.SetBounds(const AWinControl: TWinControl;
719
const ALeft, ATop, AWidth, AHeight: Integer);
721
// ignore resizes from the LCL
724
class procedure TGtk2WSCustomPage.ShowHide(const AWinControl: TWinControl);
726
if (csDesigning in AWinControl.ComponentState) then
727
TGtk2WidgetSet(WidgetSet).SetVisible(AWinControl,
728
AWinControl.HandleObjectShouldBeVisible)
730
TGtk2WidgetSet(WidgetSet).SetVisible(AWinControl,
731
TCustomPage(AWinControl).TabVisible);
734
class function TGtk2WSCustomPage.GetDefaultClientRect(
735
const AWinControl: TWinControl; const aLeft, aTop, aWidth, aHeight: integer;
736
var aClientRect: TRect): boolean;
739
if AWinControl.Parent=nil then exit;
740
if AWinControl.HandleAllocated and AWinControl.Parent.HandleAllocated
741
and (PGtkWidget(AWinControl.Handle)^.parent<>nil) then
746
aClientRect:=AWinControl.Parent.ClientRect;
747
//DebugLn(['TGtk2WSCustomPage.GetDefaultClientRect ',DbgSName(AWinControl),' Parent=',DbgSName(AWinControl.Parent),' ParentBounds=',dbgs(AWinControl.Parent.BoundsRect),' ParentClient=',dbgs(AWinControl.Parent.ClientRect)]);
749
{$IFDEF VerboseSizeMsg}
750
if Result then DebugLn(['TGtk2WSCustomPage.GetDefaultClientRect ',DbgSName(AWinControl),' aClientRect=',dbgs(aClientRect)]);
754
181
{ TGtk2WSCustomPanel }
756
183
class procedure TGtk2WSCustomPanel.SetCallbacks(const AGtkWidget: PGtkWidget;