From f54bea2fc598ad8359a570af4b5d2ff265dd6881 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Wed, 16 Apr 2008 00:22:08 +0000 Subject: [PATCH] Separates gtk1 and gtk2 menu item code. Started implementing shortcuts for gtk2 menu items, but was unable to finish it. It didn't work before, so commited anyway because the new code is at least cleaner. git-svn-id: trunk@14842 - --- lcl/interfaces/gtk/gtkwsmenus.pp | 16 +- lcl/interfaces/gtk2/gtk2int.pas | 2 +- lcl/interfaces/gtk2/gtk2wsmenus.pp | 286 +++++++++++++++++++++++++++-- 3 files changed, 284 insertions(+), 20 deletions(-) diff --git a/lcl/interfaces/gtk/gtkwsmenus.pp b/lcl/interfaces/gtk/gtkwsmenus.pp index 2490598efb..875304cb9c 100644 --- a/lcl/interfaces/gtk/gtkwsmenus.pp +++ b/lcl/interfaces/gtk/gtkwsmenus.pp @@ -43,6 +43,7 @@ type private protected public + {$IFDEF GTK1} class procedure AttachMenu(const AMenuItem: TMenuItem); override; class function CreateHandle(const AMenuItem: TMenuItem): HMENU; override; class procedure DestroyHandle(const AMenuItem: TMenuItem); override; @@ -54,6 +55,7 @@ type class function SetRadioItem(const AMenuItem: TMenuItem; const RadioItem: boolean): boolean; override; class function SetRightJustify(const AMenuItem: TMenuItem; const Justified: boolean): boolean; override; class procedure UpdateMenuIcon(const AMenuItem: TMenuItem; const HasIcon: Boolean; const AIcon: TBitmap); override; + {$ENDIF} end; { TGtkWSMenu } @@ -91,6 +93,7 @@ uses Controls; { TGtkWSMenuItem } +{$IFDEF GTK1} class procedure TGtkWSMenuItem.AttachMenu(const AMenuItem: TMenuItem); var //AccelKey: Integer; @@ -183,16 +186,10 @@ begin // set 'Checked' gtk_check_menu_item_set_active(PGtkCheckMenuItem(Widget), AMenuItem.Checked); - {$ifdef GTK2} - if (OldCheckMenuItemToggleSize=0) then - begin - gtk_menu_item_toggle_size_request(GTK_MENU_ITEM(Widget), @OldCheckMenuItemToggleSize); - OldCheckMenuItemToggleSize := GTK_MENU_ITEM(Widget)^.toggle_size; - end; - {$else} + if (OldCheckMenuItemToggleSize=0) then OldCheckMenuItemToggleSize := MENU_ITEM_CLASS(Widget)^.toggle_size; - {$endif} + g_signal_connect_after(PGTKObject(Widget), 'toggled', TGTKSignalFunc(@GTKCheckMenuToggeledCB), Pointer(AMenuItem)); end; @@ -329,6 +326,7 @@ begin Exit; // TODO end; +{$ENDIF} { TGtkWSMenu } @@ -457,7 +455,9 @@ initialization // To improve speed, register only classes // which actually implement something //////////////////////////////////////////////////// +{$IFDEF GTK1} RegisterWSComponent(TMenuItem, TGtkWSMenuItem); +{$ENDIF} RegisterWSComponent(TMenu, TGtkWSMenu); // RegisterWSComponent(TMainMenu, TGtkWSMainMenu); RegisterWSComponent(TPopupMenu, TGtkWSPopupMenu); diff --git a/lcl/interfaces/gtk2/gtk2int.pas b/lcl/interfaces/gtk2/gtk2int.pas index 43ae803339..9923e05e16 100644 --- a/lcl/interfaces/gtk2/gtk2int.pas +++ b/lcl/interfaces/gtk2/gtk2int.pas @@ -160,7 +160,7 @@ uses // Gtk2WSGrids, // Gtk2WSImgList, // Gtk2WSMaskEdit, -// Gtk2WSMenus, + Gtk2WSMenus, // Gtk2WSPairSplitter, // Gtk2WSSpin, Gtk2WSStdCtrls, diff --git a/lcl/interfaces/gtk2/gtk2wsmenus.pp b/lcl/interfaces/gtk2/gtk2wsmenus.pp index c41c79b8e3..0b9f0f4168 100644 --- a/lcl/interfaces/gtk2/gtk2wsmenus.pp +++ b/lcl/interfaces/gtk2/gtk2wsmenus.pp @@ -27,15 +27,10 @@ unit Gtk2WSMenus; interface uses -//////////////////////////////////////////////////// -// I M P O R T A N T -//////////////////////////////////////////////////// -// To get as little as posible circles, -// uncomment only when needed for registration -//////////////////////////////////////////////////// -// Menus, -//////////////////////////////////////////////////// - WSMenus, WSLCLClasses; + glib2, gdk2pixbuf, gdk2, gtk2, Pango, + GtkInt, GtkProc, GtkGlobals, GtkDef, GtkExtra, + Classes, InterfaceBase, Types, LCLProc, LCLType, WSMenus, WSLCLClasses, + Graphics, Menus, Forms, LCLIntf; type @@ -45,6 +40,17 @@ type private protected public + class procedure AttachMenu(const AMenuItem: TMenuItem); override; + class function CreateHandle(const AMenuItem: TMenuItem): HMENU; override; + class procedure DestroyHandle(const AMenuItem: TMenuItem); override; + class procedure SetCaption(const AMenuItem: TMenuItem; const ACaption: string); override; + class procedure SetShortCut(const AMenuItem: TMenuItem; const OldShortCut, NewShortCut: TShortCut); override; + class procedure SetVisible(const AMenuItem: TMenuItem; const Visible: boolean); override; + class function SetCheck(const AMenuItem: TMenuItem; const Checked: boolean): boolean; override; + class function SetEnable(const AMenuItem: TMenuItem; const Enabled: boolean): boolean; override; + class function SetRadioItem(const AMenuItem: TMenuItem; const RadioItem: boolean): boolean; override; + class function SetRightJustify(const AMenuItem: TMenuItem; const Justified: boolean): boolean; override; + class procedure UpdateMenuIcon(const AMenuItem: TMenuItem; const HasIcon: Boolean; const AIcon: TBitmap); override; end; { TGtk2WSMenu } @@ -74,6 +80,264 @@ type implementation +{ TGtk2WSMenuItem } + +class procedure TGtk2WSMenuItem.AttachMenu(const AMenuItem: TMenuItem); +var + //AccelKey: Integer; + //AccelGroup: PGTKAccelGroup; + MenuItem, ParentMenuWidget, ContainerMenu: PGtkWidget; + + procedure SetContainerMenuToggleSize; + var MenuClass: PGtkWidgetClass; + begin + if GtkWidgetIsA(ContainerMenu,GTK_TYPE_MENU) then begin + MenuClass:=GTK_WIDGET_CLASS(gtk_object_get_class(ContainerMenu)); + if OldMenuSizeRequestProc=nil then begin + OldMenuSizeRequestProc:=MenuClass^.size_request; + end; + MenuClass^.size_request:=@MenuSizeRequest; + end; + end; + +begin + //DebugLn('TGtkWidgetSet.AttachMenu START ',AMenuItem.Name,':',AMenuItem.ClassName,' Parent=',AMenuItem.Parent.Name,':',AMenuItem.Parent.ClassName); + with AMenuItem do + begin + MenuItem := PGtkWidget(Handle); + if MenuItem=nil then + RaiseGDBException('TGtkWidgetSet.AttachMenu Handle=0'); + ParentMenuWidget := PGtkWidget(Parent.Handle); + if ParentMenuWidget=nil then + RaiseGDBException('TGtkWidgetSet.AttachMenu ParentMenuWidget=nil'); + + if GtkWidgetIsA(ParentMenuWidget,GTK_TYPE_MENU_BAR) then begin + // mainmenu (= a menu bar) + ContainerMenu:=ParentMenuWidget; + gtk_menu_bar_insert(ParentMenuWidget,MenuItem, AMenuItem.MenuVisibleIndex); + end + else begin + // menu item + + // find the menu container + ContainerMenu := PGtkWidget(gtk_object_get_data( + PGtkObject(ParentMenuWidget), + 'ContainerMenu')); + if ContainerMenu = nil then begin + if (GetParentMenu is TPopupMenu) and (Parent.Parent=nil) then begin + ContainerMenu:=PGtkWidget(GetParentMenu.Handle); + gtk_object_set_data(PGtkObject(ContainerMenu), 'ContainerMenu', + ContainerMenu); + end else begin + ContainerMenu := gtk_menu_new; + gtk_object_set_data(PGtkObject(ParentMenuWidget), 'ContainerMenu', + ContainerMenu); + gtk_menu_item_set_submenu(PGTKMenuItem(ParentMenuWidget),ContainerMenu); + end; + end; + gtk_menu_insert(ContainerMenu, MenuItem, AMenuItem.MenuVisibleIndex); + end; + + SetContainerMenuToggleSize; + + if GtkWidgetIsA(MenuItem, GTK_TYPE_RADIO_MENU_ITEM) then + TGtkWidgetSet(WidgetSet).RegroupMenuItem(HMENU(PtrUInt(MenuItem)),GroupIndex); + end; + //DebugLn('TGtkWidgetSet.AttachMenu END ',AMenuItem.Name,':',AMenuItem.ClassName); +end; + +class function TGtk2WSMenuItem.CreateHandle(const AMenuItem: TMenuItem): HMENU; +var + Widget: PGtkWidget; + WidgetInfo: PWidgetInfo; +begin + // create the menuitem widget (normal, check or radio) + if AMenuItem.Caption='-' then // create separator + Widget := gtk_menu_item_new + else + if AMenuItem.RadioItem and not AMenuItem.HasIcon then + Widget := gtk_radio_menu_item_new(nil) + else + if AMenuItem.IsCheckItem or AMenuItem.HasIcon then + Widget := gtk_check_menu_item_new + else + Widget := gtk_menu_item_new; + + WidgetInfo := CreateWidgetInfo(Widget); + WidgetInfo^.LCLObject := AMenuItem; + + if GtkWidgetIsA(Widget, GTK_TYPE_CHECK_MENU_ITEM) then + begin + // set 'ShowAlwaysCheckable' + gtk_check_menu_item_set_show_toggle(PGtkCheckMenuItem(Widget), + AMenuItem.ShowAlwaysCheckable); + // set 'Checked' + gtk_check_menu_item_set_active(PGtkCheckMenuItem(Widget), + AMenuItem.Checked); + + if (OldCheckMenuItemToggleSize=0) then + begin + gtk_menu_item_toggle_size_request(GTK_MENU_ITEM(Widget), @OldCheckMenuItemToggleSize); + OldCheckMenuItemToggleSize := GTK_MENU_ITEM(Widget)^.toggle_size; + end; + + g_signal_connect_after(PGTKObject(Widget), 'toggled', + TGTKSignalFunc(@GTKCheckMenuToggeledCB), Pointer(AMenuItem)); + end; + + // set attributes (enabled and rightjustify) + gtk_widget_set_sensitive(Widget, + AMenuItem.Enabled and (AMenuItem.Caption<>'-')); + if AMenuItem.RightJustify then + gtk_menu_item_right_justify(PGtkMenuItem(Widget)); + + // create the hbox containing the label and the icon + UpdateInnerMenuItem(AMenuItem, Widget); + + // connect activate signal (i.e. clicked) + g_signal_connect(PGTKObject(Widget), 'activate', + TGTKSignalFunc(@gtkactivateCB), AMenuItem); + + gtk_widget_show(Widget); + {$IFDEF DebugLCLComponents} + DebugGtkWidgets.MarkCreated(Widget, dbgsName(AMenuItem)); + {$ENDIF} + Result := HMENU(PtrUInt(Widget)); +end; + +class procedure TGtk2WSMenuItem.DestroyHandle(const AMenuItem: TMenuItem); +begin + { TODO: cleanup } + TGtkWidgetSet(WidgetSet).DestroyLCLComponent(AMenuItem); +end; + +class procedure TGtk2WSMenuItem.SetCaption(const AMenuItem: TMenuItem; + const ACaption: string); +var + MenuItemWidget: PGtkWidget; +begin + if not WSCheckMenuItem(AMenuItem, 'SetCaption') then + Exit; + MenuItemWidget:=PGtkWidget(AMenuItem.Handle); + UpdateInnerMenuItem(AMenuItem,MenuItemWidget); +end; + +class procedure TGtk2WSMenuItem.SetShortCut(const AMenuItem: TMenuItem; + const OldShortCut, NewShortCut: TShortCut); +var + MenuWidget: PGtkMenuItem; + accel_path: String; + CurKey: Word; + CurShift: TShiftState; +begin + if not WSCheckMenuItem(AMenuItem, 'SetShortCut') then Exit; + + //DebugLn(['TGtkWSMenuItem.SetShortCut ',dbgsName(AMenuItem),' ',ShortCutToText(NewShortCut)]); + + // Gets the inner widgets. They should already be created by now + + MenuWidget := PGtkMenuItem(AMenuItem.Handle); + + if (MenuWidget=nil) then Exit; + + // Converts the shortcut to a gtk friendly format and sets it + +{ ShortCutToKey(NewShortCut, CurKey, CurShift); + + accel_path := 'LCLApp/Menu/' + GetAcceleratorString(CurKey, CurShift); + + gtk_accel_map_add_entry(accel_path, CurKey, ShiftToGdkModifierType); + + gtk_menu_item_set_accel_path(); } +end; + +class procedure TGtk2WSMenuItem.SetVisible(const AMenuItem: TMenuItem; + const Visible: boolean); +var + MenuItemWidget: PGtkWidget; +begin + if not WSCheckMenuItem(AMenuItem, 'SetVisible') then + Exit; + MenuItemWidget := PGtkWidget(AMenuItem.Handle); + if gtk_widget_visible(MenuItemWidget) = Visible then + Exit; + if Visible then + gtk_widget_show(MenuItemWidget) + else + gtk_widget_hide(MenuItemWidget); +end; + +class function TGtk2WSMenuItem.SetCheck(const AMenuItem: TMenuItem; + const Checked: boolean): boolean; +var + IsRadio: Boolean; + Group: PGSList; + Item: Pointer; +begin + if not WSCheckMenuItem(AMenuItem, 'SetCheck') then + Exit; + Item := Pointer(AMenuItem.Handle); + IsRadio := gtk_is_radio_menu_item(Item); + if IsRadio or gtk_is_check_menu_item(Item) + then begin + if IsRadio + then begin + Group := gtk_radio_menu_item_group(Item); + LockRadioGroupOnChange(Group, +1); + end + else LockOnChange(Item, +1); + gtk_check_menu_item_set_active(Item, Checked); + if IsRadio + then LockRadioGroupOnChange(Group, -1) + else LockOnChange(Item, -1); + Result := True; + end + else begin + AMenuItem.RecreateHandle; + Result := True; + end; +end; + +class function TGtk2WSMenuItem.SetEnable(const AMenuItem: TMenuItem; + const Enabled: boolean): boolean; +begin + Result := False; + if not WSCheckMenuItem(AMenuItem, 'SetEnable') then + Exit; + gtk_widget_set_sensitive(PGtkWidget(AMenuItem.Handle), + Enabled and (AMenuItem.Caption<>'-')); + Result := True; +end; + +class function TGtk2WSMenuItem.SetRadioItem(const AMenuItem: TMenuItem; + const RadioItem: boolean): boolean; +begin + AMenuItem.RecreateHandle; + Result := True; +end; + +class function TGtk2WSMenuItem.SetRightJustify(const AMenuItem: TMenuItem; + const Justified: boolean): boolean; +var + MenuItemWidget: PGtkMenuItem; +begin + Result := False; + if not WSCheckMenuItem(AMenuItem, 'SetRightJustify') then + Exit; + MenuItemWidget := PGtkMenuItem(AMenuItem.Handle); + gtk_menu_item_set_right_justified(MenuItemWidget, Justified); + gtk_widget_queue_resize(GTK_WIDGET(MenuItemWidget)); + Result := True; +end; + +class procedure TGtk2WSMenuItem.UpdateMenuIcon(const AMenuItem: TMenuItem; + const HasIcon: Boolean; const AIcon: TBitmap); +begin + if not WSCheckMenuItem(AMenuItem, 'UpdateMenuIcon') then + Exit; + // TODO +end; + initialization //////////////////////////////////////////////////// @@ -82,9 +346,9 @@ initialization // To improve speed, register only classes // which actually implement something //////////////////////////////////////////////////// -// RegisterWSComponent(TMenuItem, TGtk2WSMenuItem); + RegisterWSComponent(TMenuItem, TGtk2WSMenuItem); // RegisterWSComponent(TMenu, TGtk2WSMenu); // RegisterWSComponent(TMainMenu, TGtk2WSMainMenu); // RegisterWSComponent(TPopupMenu, TGtk2WSPopupMenu); //////////////////////////////////////////////////// -end. \ No newline at end of file +end.