From 2faa5bdf050476535626c5bafbeeb17883d7c3bd Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 15 Dec 2024 12:21:51 +0100 Subject: [PATCH 1/7] LCL: Allow TToolbar to show a TMainMenu. Patch by FerDeLance See MR !393 --- lcl/comctrls.pp | 26 +++++++ lcl/include/mainmenu.inc | 1 + lcl/include/menuitem.inc | 2 + lcl/include/toolbar.inc | 152 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+) diff --git a/lcl/comctrls.pp b/lcl/comctrls.pp index b02105f087..f96785d066 100644 --- a/lcl/comctrls.pp +++ b/lcl/comctrls.pp @@ -2263,6 +2263,26 @@ type TToolBar = class(TToolWindow) private + type + { TTMPObserver } + + TTMPObserver = class(TObject, IFPObserver) + private + FDoOnChange: TNotifyEvent; + FDoOnFree: TNotifyEvent; + procedure FPOObservedChanged(ASender : TObject; Operation : TFPObservedOperation; Data : Pointer); + procedure SetDoOnChange(AValue: TNotifyEvent); + procedure SetDoOnFree(AValue: TNotifyEvent); + public + property DoOnChange: TNotifyEvent read FDoOnChange write SetDoOnChange; + property DoOnFree: TNotifyEvent read FDoOnFree write SetDoOnFree; + end; + private + FMenuObserver: TTMPObserver; + FMenu: TMainMenu; + FSubMenu: TPopupMenu; + FSubMenuItems: TList; + FMenuButtons: TList; FOnPaint: TNotifyEvent; FOnPaintButton: TToolBarOnPaintButton; FButtonHeight: Integer; @@ -2315,6 +2335,7 @@ type procedure SetImagesWidth(const aImagesWidth: Integer); procedure SetIndent(const AValue: Integer); procedure SetList(const AValue: Boolean); + procedure SetMenu(AValue: TMainMenu); procedure SetOrientation(AValue: TToolBarOrientation); procedure SetShowCaptions(const AValue: Boolean); procedure SetTransparent(const AValue: Boolean); @@ -2326,6 +2347,10 @@ type procedure MoveSubMenuItems(SrcMenuItem, DestMenuItem: TMenuItem); procedure AddButton(Button: TToolButton); procedure RemoveButton(Button: TToolButton); + procedure UpdateMenuItem(Sender: TObject); + procedure RemoveMenu(Sender: TObject); + procedure SubMenuItemClick(Sender: TObject); + procedure MenuButtonClick(Sender: TObject); protected const cDefButtonWidth = 23; cDefButtonHeight = 22; @@ -2401,6 +2426,7 @@ type property ImagesWidth: Integer read FImagesWidth write SetImagesWidth default 0; property Indent: Integer read FIndent write SetIndent default 1; property List: Boolean read FList write SetList default False; + property Menu: TMainMenu read FMenu write SetMenu; property ParentColor; property ParentFont; property ParentShowHint; diff --git a/lcl/include/mainmenu.inc b/lcl/include/mainmenu.inc index 45dc15ec91..a63d4d8c08 100644 --- a/lcl/include/mainmenu.inc +++ b/lcl/include/mainmenu.inc @@ -47,6 +47,7 @@ begin // pass CM_MENUCANGED to the form which own the menu if WindowHandle <> 0 then SendMessage(WindowHandle, CM_MENUCHANGED, 0, 0); + Self.FPONotifyObservers(Sender, ooChange, nil); inherited MenuChanged(Sender, Source, Rebuild); end; diff --git a/lcl/include/menuitem.inc b/lcl/include/menuitem.inc index 023b82dbb1..6f4d731d2e 100644 --- a/lcl/include/menuitem.inc +++ b/lcl/include/menuitem.inc @@ -1269,6 +1269,7 @@ begin FCaption := AValue; if HandleAllocated and ((Parent <> nil) or (FMenu = nil)) then TWSMenuItemClass(WidgetSetClass).SetCaption(Self, AValue); + MenuChanged(False); OwnerFormDesignerModified(Self); end; @@ -1620,6 +1621,7 @@ begin if MergedParent<>nil then MergedParent.InvalidateMergedItems; end; + MenuChanged(False); end; procedure TMenuItem.UpdateImage(forced: Boolean); diff --git a/lcl/include/toolbar.inc b/lcl/include/toolbar.inc index 6f7de63a00..06e81b4514 100644 --- a/lcl/include/toolbar.inc +++ b/lcl/include/toolbar.inc @@ -100,6 +100,12 @@ begin FNewStyle := True; FWrapable := True; FButtons := TList.Create; + FMenuButtons := TList.Create; + FSubMenuItems := TList.Create; + FSubMenu := TPopupMenu.Create(Self); + FMenuObserver := TTMPObserver.Create; + FMenuObserver.DoOnChange := @UpdateMenuItem; + FMenuObserver.DoOnFree := @RemoveMenu; FIndent := 1; FList := False; FImageChangeLink := TChangeLink.Create; @@ -122,7 +128,16 @@ begin if TControl(FButtons[I]) is TToolButton then TToolButton(FButtons[I]).FToolBar := nil; + for I := 0 to FMenuButtons.Count - 1 do + if TControl(FMenuButtons[I]) is TSpeedButton then + TSpeedButton(FMenuButtons[I]).Free; + + if Assigned(FMenu) then FMenu.FPODetachObserver(FMenuObserver); FreeThenNil(FButtons); + FreeThenNil(FMenuButtons); + FreeAndNil(FSubMenu); + FreeThenNil(FSubMenuItems); + FreeAndNil(FMenuObserver); FreeThenNil(FHotImageChangeLink); FreeThenNil(FImageChangeLink); FreeThenNil(FDisabledImageChangeLink); @@ -242,6 +257,104 @@ begin FButtons.Remove(Button); end; +procedure TToolBar.UpdateMenuItem(Sender: TObject); +var + i, xpos, wglyph: Integer; + tmpMenuButton: TSpeedButton; +begin + xpos := 0; + while (FMenuButtons.Count > 0) do + begin + i := FMenuButtons.Count - 1; + tmpMenuButton := TSpeedButton(FMenuButtons.Items[i]); + FMenuButtons.Delete(i); + FreeAndNil(tmpMenuButton); + end; + + if not Assigned(FMenu) then Exit; + + for i := 0 to FMenu.Items.Count-1 do + if FMenu.Items[i].Visible then + begin + tmpMenuButton := TSpeedButton.Create(Self); + tmpMenuButton.AutoSize := False; + tmpMenuButton.Align := alNone; + tmpMenuButton.Alignment := taCenter; + tmpMenuButton.Height := FMenu.Height; + tmpMenuButton.Left := xpos; + tmpMenuButton.Flat := True; + tmpMenuButton.ParentFont := True; + tmpMenuButton.Color := Self.Color; + tmpMenuButton.ShowCaption := True; + tmpMenuButton.Caption := FMenu.Items[i].Caption; + tmpMenuButton.Enabled := FMenu.Items[i].Enabled; + tmpMenuButton.Visible := FMenu.Items[i].Visible; + tmpMenuButton.Margin := -1; + tmpMenuButton.Spacing := 7; + tmpMenuButton.Tag := i; + wglyph := 0; + tmpMenuButton.Images := nil; + if Assigned(FMenu.Images) and (FMenu.Items[i].ImageIndex >= 0) then + if FMenu.Items[i].ImageIndex < FMenu.Images.Count then + begin + FMenu.Images.GetBitmap(FMenu.Items[i].ImageIndex, tmpMenuButton.Glyph); + wglyph := tmpMenuButton.Glyph.Width + 5; + end; + tmpMenuButton.OnClick := @MenuButtonClick; + tmpMenuButton.Parent := Self; + if FMenu.Items[i].Default then tmpMenuButton.Font.Style := [fsBold]; + tmpMenuButton.Width := Self.Canvas.TextWidth(FMenu.Items[i].Caption) + wglyph + 14; + tmpMenuButton.Constraints.MinWidth := tmpMenuButton.Width; + tmpMenuButton.Constraints.MaxWidth := tmpMenuButton.Width; + tmpMenuButton.Update; + Inc(xpos, tmpMenuButton.Width); + FMenuButtons.Add(tmpMenuButton); + end; +end; + +procedure TToolBar.RemoveMenu(Sender: TObject); +begin + FMenu.FPODetachObserver(FMenuObserver); + FMenu := nil; +end; + +procedure TToolBar.SubMenuItemClick(Sender: TObject); +var + tmpMI: TMenuItem; +begin + tmpMI := TMenuItem(FSubMenuItems.Items[TMenuItem(Sender).Tag]); + if Assigned(tmpMI) then tmpMI.Click; +end; + +procedure TToolBar.MenuButtonClick(Sender: TObject); +var + MenuButton: TSpeedButton; + SubMenuPos: TPoint; + + procedure PrepSubMenuItem(SubMenuItemIn, SubMenuItemOut: TMenuItem); + var + i: Integer; + begin + for i := 0 to SubMenuItemIn.Count - 1 do + begin + FSubMenuItems.Add(SubMenuItemIn.Items[i]); + SubMenuItemOut.Items[i].Tag := FSubMenuItems.Count - 1; + SubMenuItemOut.Items[i].OnClick := @SubMenuItemClick; + if SubMenuItemIn.Items[i].Count > 0 then PrepSubMenuItem(SubMenuItemIn.Items[i], SubMenuItemOut.Items[i]); + end; + end; + +begin + MenuButton := TSpeedButton(Sender); + if Assigned(FMenu.Items[MenuButton.Tag].OnClick) then FMenu.Items[MenuButton.Tag].Click; + if FMenu.Items[MenuButton.Tag].Count = 0 then Exit; + FSubMenu.Items.Assign(FMenu.Items[MenuButton.Tag]); + FSubMenuItems.Clear; + PrepSubMenuItem(FMenu.Items[MenuButton.Tag], FSubMenu.Items); + SubMenuPos := ClientToScreen(TPoint.Create(MenuButton.Left, MenuButton.Top + MenuButton.Height)); + FSubMenu.PopUp(SubMenuPos.X, SubMenuPos.Y); +end; + function TToolBar.IsVertical: Boolean; begin case FOrientation of @@ -304,6 +417,18 @@ begin UpdateVisibleBar; end; +procedure TToolBar.SetMenu(AValue: TMainMenu); +begin + if FMenu = AValue then Exit; + if Assigned(FMenu) then + begin + FMenu.FPODetachObserver(FMenuObserver); + end; + FMenu := AValue; + if Assigned(FMenu) then FMenu.FPOAttachObserver(FMenuObserver); + UpdateVisibleBar; +end; + procedure TToolBar.SetOrientation(AValue: TToolBarOrientation); begin if FOrientation = AValue then Exit; @@ -341,6 +466,7 @@ begin inherited Notification(AComponent, Operation); if Operation = opRemove then begin + if AComponent = FMenu then Menu := nil; if AComponent = FImages then Images := nil; if AComponent = FHotImages then HotImages := nil; if AComponent = FDisabledImages then DisabledImages := nil; @@ -434,6 +560,7 @@ begin Include(FToolBarFlags,tbfUpdateVisibleBarNeeded); Exit; end; + UpdateMenuItem(Self); for i := 0 to FButtons.Count - 1 do begin TControl(FButtons[i]).InvalidatePreferredSize; @@ -472,6 +599,9 @@ begin end; procedure TToolBar.EndUpdate; +var + i: Integer; + tmpMenuItem: TMenuItem; begin inherited EndUpdate; if FUpdateCount=0 then begin @@ -1130,3 +1260,25 @@ begin Button.Click; end; +{ TToolBar.TTMPObserver } + +procedure TToolBar.TTMPObserver.FPOObservedChanged(ASender: TObject; + Operation: TFPObservedOperation; Data: Pointer); +begin + case Operation of + ooFree: if Assigned(DoOnFree) then DoOnFree(ASender); + ooChange: if Assigned(DoOnChange) then DoOnChange(ASender); + end; +end; + +procedure TToolBar.TTMPObserver.SetDoOnChange(AValue: TNotifyEvent); +begin + if FDoOnChange = AValue then Exit; + FDoOnChange := AValue; +end; + +procedure TToolBar.TTMPObserver.SetDoOnFree(AValue: TNotifyEvent); +begin + if FDoOnFree = AValue then Exit; + FDoOnFree := AValue; +end; From e63194a5f22ab48ae418676e8ca0e5883e44bdad Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Dec 2024 10:47:29 +0100 Subject: [PATCH 2/7] DockedFormEditor: add menu preview via TToolbar.Menu. Patch by FerDeLance See MR !393 --- .../dockedformeditor/source/dockedgrip.pas | 10 ++-- .../source/dockedresizecontrol.pas | 58 +++++++------------ lcl/include/toolbar.inc | 37 +++++++++--- 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/components/dockedformeditor/source/dockedgrip.pas b/components/dockedformeditor/source/dockedgrip.pas index a042da8875..4e553030c4 100644 --- a/components/dockedformeditor/source/dockedgrip.pas +++ b/components/dockedformeditor/source/dockedgrip.pas @@ -40,7 +40,7 @@ uses // RTL, FCL Classes, SysUtils, math, // LCL - Controls, ExtCtrls, Graphics, Menus; + Controls, ComCtrls, ExtCtrls, Graphics, Menus; type @@ -193,7 +193,7 @@ type private FAnchorContainer: TWinControl; FBoundsRect: TRect; - FFakeMenu: TCustomControl; + FFakeMenu: TToolBar; FFormClient: TWinControl; FFormContainer: TResizeFormContainer; FParent: TWinControl; @@ -208,7 +208,7 @@ type public property AnchorContainer: TWinControl read FAnchorContainer; property BoundsRect: TRect read FBoundsRect; - property FakeMenu: TCustomControl read FFakeMenu; + property FakeMenu: TToolBar read FFakeMenu; property FormClient: TWinControl read FFormClient; property FormContainer: TResizeFormContainer read FFormContainer; property Parent: TWinControl read FParent; @@ -605,9 +605,11 @@ begin FResizeBars := TResizeBars.Create; FResizeBars.Parent := Parent; - FFakeMenu := TCustomControl.Create(Parent); + FFakeMenu := TToolBar.Create(Parent); FFakeMenu.Height := 0; FFakeMenu.Parent := Parent; + FFakeMenu.Align := alNone; + FFakeMenu.Indent := 0; FFormClient := TWinControl.Create(Parent); FFormClient.ControlStyle:= FFormClient.ControlStyle + [csOpaque]; diff --git a/components/dockedformeditor/source/dockedresizecontrol.pas b/components/dockedformeditor/source/dockedresizecontrol.pas index d405ba899b..b3b6196249 100644 --- a/components/dockedformeditor/source/dockedresizecontrol.pas +++ b/components/dockedformeditor/source/dockedresizecontrol.pas @@ -20,8 +20,8 @@ uses // RTL Classes, Types, SysUtils, FPCanvas, // LCL - Forms, ExtCtrls, StdCtrls, Controls, LCLType, Menus, Graphics, LCLIntf, - LMessages, LCLProc, + Forms, ExtCtrls, StdCtrls, Controls, ComCtrls, LCLType, Menus, Graphics, LCLIntf, + LMessages, LCLProc, Buttons, // DockedFormEditor DockedOptionsIDE, DockedDesignForm, DockedGrip; @@ -55,10 +55,9 @@ type procedure FakeKeyUp(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState); procedure FakeMenuEnter(Sender: TObject); function FakeMenuNeeded: Boolean; - procedure FakeMenuPaint(Sender: TObject); procedure FakeUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); function GetAnchorContainer: TWinControl; - function GetFakeMenu: TCustomControl; + function GetFakeMenu: TToolBar; function GetFormClient: TWinControl; function GetFormContainer: TResizeFormContainer; function GetSizerGripSize: Integer; @@ -80,7 +79,7 @@ type public property AnchorContainer: TWinControl read GetAnchorContainer; property DesignForm: TDesignForm read FDesignForm write SetDesignForm; - property FakeMenu: TCustomControl read GetFakeMenu; + property FakeMenu: TToolBar read GetFakeMenu; property FormClient: TWinControl read GetFormClient; property FormContainer: TResizeFormContainer read GetFormContainer; property NewFormSize: TPoint read FNewFormSize; @@ -128,7 +127,7 @@ begin Application.NotifyUserInputHandler(Self, 0); // force repaint invisible components end else if LFakeMenuNeeded then - FakeMenu.Invalidate; // always repaint menu on modification + TryBoundDesignForm; // always repaint menu on modification RefreshAnchorDesigner; FDesignerModified := False; end; @@ -221,33 +220,7 @@ begin Result := False; if not Assigned(FDesignForm) then Exit; Result := FDesignForm.MainMenuFaked; -end; - -procedure TResizeControl.FakeMenuPaint(Sender: TObject); -var - MenuRect: Types.TRect; - Menu: TMainMenu; - X, Y, I: Integer; - LCanvas: TCanvas; -begin - if not FakeMenuNeeded then Exit; - - MenuRect := FakeMenu.ClientRect; - LCanvas := FakeMenu.Canvas; - LCanvas.Brush.Color := clMenuBar; - LCanvas.FillRect(MenuRect); - - Menu := FDesignForm.Form.Menu; - LCanvas.Font.Color := clMenuText; - - X := 5; - Y := (MenuRect.Top+MenuRect.Bottom-LCanvas.TextHeight('Hg')) div 2; - for I := 0 to Menu.Items.Count-1 do - if Menu.Items[I].Visible then - begin - LCanvas.TextOut(X, Y, Menu.Items[I].Caption); - Inc(X, LCanvas.TextWidth(Menu.Items[I].Caption) + 10); - end; + if Result then FakeMenu.Menu := FDesignForm.Form.Menu else FakeMenu.Menu := nil; end; procedure TResizeControl.FakeUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char); @@ -265,7 +238,7 @@ begin Result := FResizeContainer.AnchorContainer; end; -function TResizeControl.GetFakeMenu: TCustomControl; +function TResizeControl.GetFakeMenu: TToolBar; begin Result := FResizeContainer.FakeMenu; end; @@ -370,12 +343,20 @@ begin end; procedure TResizeControl.TryBoundDesignForm; +var + i, t: Integer; begin if DesignForm = nil then Exit; if FakeMenuNeeded then - FakeMenu.Height := DesignForm.MainMenuHeight - else - FakeMenu.Height := 0; + begin + FakeMenu.ButtonHeight := DesignForm.MainMenuHeight; + t := 0; + for i := 0 to FakeMenu.ComponentCount - 1 do //For multi-line MainMenu + if FakeMenu.Components[i] is TSpeedButton then + if t < TSpeedButton(FakeMenu.Components[i]).Top then t := TSpeedButton(FakeMenu.Components[i]).Top; + FakeMenu.Height := t + FakeMenu.ButtonHeight; + FakeMenu.Update; + end else FakeMenu.Height := 0; end; constructor TResizeControl.Create(TheOwner: TComponent); @@ -403,7 +384,6 @@ begin CreateBarBitmaps; - FakeMenu.OnPaint := @FakeMenuPaint; FormClient.OnChangeBounds := @ClientChangeBounds; AnchorContainer.OnChangeBounds := @ClientChangeBounds; AdjustBounds(Point(0, 0)); @@ -422,6 +402,7 @@ var LWidth, LHeight: Integer; begin if FDesignForm = nil then Exit; + TryBoundDesignForm; LWidth := FDesignForm.Width + 2 * SizerGripSize; LHeight := FDesignForm.Height + 2 * SizerGripSize + FakeMenu.Height; {$IFDEF DEBUGDOCKEDFORMEDITOR} DebugLn('TResizeControl.AdjustBounds: New ResizeControl Width:', DbgS(Width), ' Height: ', DbgS(Height)); {$ENDIF} @@ -434,6 +415,7 @@ begin if (DesignForm = nil) then Exit; if not DockedOptions.ForceRefreshing and Resizing then Exit; {$IFDEF DEBUGDOCKEDFORMEDITOR} DebugLn('TResizeControl.ClientChangeBounds Form Width:', DbgS(FormClient.Width), ' Height: ', DbgS(FormClient.Height)); {$ENDIF} + TryBoundDesignForm; if FormClient.Visible then begin FNewFormSize.X := FormClient.Width; diff --git a/lcl/include/toolbar.inc b/lcl/include/toolbar.inc index 06e81b4514..19a60da0fe 100644 --- a/lcl/include/toolbar.inc +++ b/lcl/include/toolbar.inc @@ -330,6 +330,7 @@ procedure TToolBar.MenuButtonClick(Sender: TObject); var MenuButton: TSpeedButton; SubMenuPos: TPoint; + tmpMI: TMenuItem; procedure PrepSubMenuItem(SubMenuItemIn, SubMenuItemOut: TMenuItem); var @@ -337,20 +338,40 @@ var begin for i := 0 to SubMenuItemIn.Count - 1 do begin - FSubMenuItems.Add(SubMenuItemIn.Items[i]); - SubMenuItemOut.Items[i].Tag := FSubMenuItems.Count - 1; - SubMenuItemOut.Items[i].OnClick := @SubMenuItemClick; + SubMenuItemOut.Add(NewItem(SubMenuItemIn.Items[i].Caption, + SubMenuItemIn.Items[i].ShortCut, + SubMenuItemIn.Items[i].Checked, + SubMenuItemIn.Items[i].Visible, + @SubMenuItemClick, + SubMenuItemIn.Items[i].HelpContext, + '')); + SubMenuItemOut.Items[i].AutoCheck := SubMenuItemIn.Items[i].AutoCheck; + SubMenuItemOut.Items[i].AutoLineReduction := SubMenuItemIn.Items[i].AutoLineReduction; + SubMenuItemOut.Items[i].Default := SubMenuItemIn.Items[i].Default; + SubMenuItemOut.Items[i].GlyphShowMode := SubMenuItemIn.Items[i].GlyphShowMode; + SubMenuItemOut.Items[i].GroupIndex := SubMenuItemIn.Items[i].GroupIndex; + SubMenuItemOut.Items[i].Hint := SubMenuItemIn.Items[i].Hint; + SubMenuItemOut.Items[i].ImageIndex := SubMenuItemIn.Items[i].ImageIndex; + SubMenuItemOut.Items[i].RadioItem := SubMenuItemIn.Items[i].RadioItem; + SubMenuItemOut.Items[i].RightJustify := SubMenuItemIn.Items[i].RightJustify; + SubMenuItemOut.Items[i].ShortCutKey2 := SubMenuItemIn.Items[i].ShortCutKey2; + SubMenuItemOut.Items[i].ShowAlwaysCheckable := SubMenuItemIn.Items[i].ShowAlwaysCheckable; + SubMenuItemOut.Items[i].SubMenuImages := SubMenuItemIn.Items[i].SubMenuImages; + SubMenuItemOut.Items[i].SubMenuImagesWidth := SubMenuItemIn.Items[i].SubMenuImagesWidth; + SubMenuItemOut.Items[i].Tag := PtrInt(Pointer(SubMenuItemIn.Items[i])); if SubMenuItemIn.Items[i].Count > 0 then PrepSubMenuItem(SubMenuItemIn.Items[i], SubMenuItemOut.Items[i]); end; end; begin MenuButton := TSpeedButton(Sender); - if Assigned(FMenu.Items[MenuButton.Tag].OnClick) then FMenu.Items[MenuButton.Tag].Click; - if FMenu.Items[MenuButton.Tag].Count = 0 then Exit; - FSubMenu.Items.Assign(FMenu.Items[MenuButton.Tag]); - FSubMenuItems.Clear; - PrepSubMenuItem(FMenu.Items[MenuButton.Tag], FSubMenu.Items); + tmpMI := FMenu.Items[MenuButton.Tag]; + if not Assigned(tmpMI) then Exit; + tmpMI.Click; + FSubMenu.Items.Clear; + if tmpMI.Count = 0 then Exit; + FSubMenu.Images := tmpMI.GetImageList; + PrepSubMenuItem(tmpMI, FSubMenu.Items); SubMenuPos := ClientToScreen(TPoint.Create(MenuButton.Left, MenuButton.Top + MenuButton.Height)); FSubMenu.PopUp(SubMenuPos.X, SubMenuPos.Y); end; From 99bd81369489db94757585522ca5d7c9ab3c28cb Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 4 Jan 2025 13:13:00 +0100 Subject: [PATCH 3/7] Add Contributor for Toolbar Menu --- docs/Contributors.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Contributors.txt b/docs/Contributors.txt index aa71984f59..b56ee95a20 100644 --- a/docs/Contributors.txt +++ b/docs/Contributors.txt @@ -127,6 +127,7 @@ Karl Brandt Keith Bowes Kevin Jesshope Khaled Shagrouni +Konstantin Manakov Kostas Michalopoulos Krzysztof Dibowski Ladislav Michl From ed082bc3ecd6ceb6e0b127c59ca7b5fdb06a7812 Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 28 Dec 2024 11:54:33 +0100 Subject: [PATCH 4/7] LCL: Toolbar with menu, use sub-class / Fix menu sorting --- lcl/comctrls.pp | 1 - lcl/include/toolbar.inc | 88 ++++++++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/lcl/comctrls.pp b/lcl/comctrls.pp index f96785d066..048c505d7a 100644 --- a/lcl/comctrls.pp +++ b/lcl/comctrls.pp @@ -2349,7 +2349,6 @@ type procedure RemoveButton(Button: TToolButton); procedure UpdateMenuItem(Sender: TObject); procedure RemoveMenu(Sender: TObject); - procedure SubMenuItemClick(Sender: TObject); procedure MenuButtonClick(Sender: TObject); protected const cDefButtonWidth = 23; diff --git a/lcl/include/toolbar.inc b/lcl/include/toolbar.inc index 19a60da0fe..9419ae470a 100644 --- a/lcl/include/toolbar.inc +++ b/lcl/include/toolbar.inc @@ -13,6 +13,30 @@ } +type + + TToolBarSpeedButton = class(TSpeedButton) + private + FMenuItemIndex: integer; + end; + + { TToolBarMenuItem } + + TToolBarMenuItem = class(TMenuItem) + private + FOrigItem: TMenuItem; + protected + procedure DoClicked(var msg); message LM_ACTIVATE; + end; + +{ TToolBarMenuItem } + +procedure TToolBarMenuItem.DoClicked(var msg); +begin + if FOrigItem <> nil then + FOrigItem.Dispatch(msg); +end; + function CompareToolBarControlHorz(Control1, Control2: TControl): integer; var ToolBar: TToolBar; @@ -23,6 +47,16 @@ begin Result := 0; if not (Control1.Parent is TToolBar) then Exit; + if Control1 is TToolBarSpeedButton then begin + if Control2 is TToolBarSpeedButton then + exit(TToolBarSpeedButton(Control1).FMenuItemIndex - TToolBarSpeedButton(Control2).FMenuItemIndex) + else + exit(-1); + end + else + if Control2 is TToolBarSpeedButton then + exit(1); + ToolBar := TToolBar(Control1.Parent); BtnHeight := ToolBar.ButtonHeight; if BtnHeight <= 0 then BtnHeight := 1; @@ -55,6 +89,16 @@ begin Result := 0; if not (Control1.Parent is TToolBar) then Exit; + if Control1 is TToolBarSpeedButton then begin + if Control2 is TToolBarSpeedButton then + exit(TToolBarSpeedButton(Control1).FMenuItemIndex - TToolBarSpeedButton(Control2).FMenuItemIndex) + else + exit(-1); + end + else + if Control2 is TToolBarSpeedButton then + exit(1); + ToolBar := TToolBar(Control1.Parent); BtnWidth := ToolBar.ButtonWidth; if BtnWidth <= 0 then BtnWidth := 1; @@ -129,8 +173,8 @@ begin TToolButton(FButtons[I]).FToolBar := nil; for I := 0 to FMenuButtons.Count - 1 do - if TControl(FMenuButtons[I]) is TSpeedButton then - TSpeedButton(FMenuButtons[I]).Free; + if TControl(FMenuButtons[I]) is TToolBarSpeedButton then + TToolBarSpeedButton(FMenuButtons[I]).Free; if Assigned(FMenu) then FMenu.FPODetachObserver(FMenuObserver); FreeThenNil(FButtons); @@ -260,13 +304,13 @@ end; procedure TToolBar.UpdateMenuItem(Sender: TObject); var i, xpos, wglyph: Integer; - tmpMenuButton: TSpeedButton; + tmpMenuButton: TToolBarSpeedButton; begin xpos := 0; while (FMenuButtons.Count > 0) do begin i := FMenuButtons.Count - 1; - tmpMenuButton := TSpeedButton(FMenuButtons.Items[i]); + tmpMenuButton := TToolBarSpeedButton(FMenuButtons.Items[i]); FMenuButtons.Delete(i); FreeAndNil(tmpMenuButton); end; @@ -276,7 +320,7 @@ begin for i := 0 to FMenu.Items.Count-1 do if FMenu.Items[i].Visible then begin - tmpMenuButton := TSpeedButton.Create(Self); + tmpMenuButton := TToolBarSpeedButton.Create(Self); tmpMenuButton.AutoSize := False; tmpMenuButton.Align := alNone; tmpMenuButton.Alignment := taCenter; @@ -291,7 +335,7 @@ begin tmpMenuButton.Visible := FMenu.Items[i].Visible; tmpMenuButton.Margin := -1; tmpMenuButton.Spacing := 7; - tmpMenuButton.Tag := i; + tmpMenuButton.FMenuItemIndex:= i; wglyph := 0; tmpMenuButton.Images := nil; if Assigned(FMenu.Images) and (FMenu.Items[i].ImageIndex >= 0) then @@ -318,20 +362,27 @@ begin FMenu := nil; end; -procedure TToolBar.SubMenuItemClick(Sender: TObject); -var - tmpMI: TMenuItem; -begin - tmpMI := TMenuItem(FSubMenuItems.Items[TMenuItem(Sender).Tag]); - if Assigned(tmpMI) then tmpMI.Click; -end; - procedure TToolBar.MenuButtonClick(Sender: TObject); var - MenuButton: TSpeedButton; + MenuButton: TToolBarSpeedButton; SubMenuPos: TPoint; tmpMI: TMenuItem; + function NewItem(const ACaption: string; AShortCut: TShortCut; AChecked, + TheEnabled: Boolean; hCtx: THelpContext; + const AName: string): TMenuItem; + begin + Result:=TToolBarMenuItem.Create(nil); + with Result do begin + Caption:=ACaption; + ShortCut:=AShortCut; + HelpContext:=hCtx; + Checked:=AChecked; + Enabled:=TheEnabled; + Name:=AName; + end; + end; + procedure PrepSubMenuItem(SubMenuItemIn, SubMenuItemOut: TMenuItem); var i: Integer; @@ -342,7 +393,6 @@ var SubMenuItemIn.Items[i].ShortCut, SubMenuItemIn.Items[i].Checked, SubMenuItemIn.Items[i].Visible, - @SubMenuItemClick, SubMenuItemIn.Items[i].HelpContext, '')); SubMenuItemOut.Items[i].AutoCheck := SubMenuItemIn.Items[i].AutoCheck; @@ -358,14 +408,14 @@ var SubMenuItemOut.Items[i].ShowAlwaysCheckable := SubMenuItemIn.Items[i].ShowAlwaysCheckable; SubMenuItemOut.Items[i].SubMenuImages := SubMenuItemIn.Items[i].SubMenuImages; SubMenuItemOut.Items[i].SubMenuImagesWidth := SubMenuItemIn.Items[i].SubMenuImagesWidth; - SubMenuItemOut.Items[i].Tag := PtrInt(Pointer(SubMenuItemIn.Items[i])); + TToolBarMenuItem(SubMenuItemOut.Items[i]).FOrigItem := SubMenuItemIn.Items[i]; if SubMenuItemIn.Items[i].Count > 0 then PrepSubMenuItem(SubMenuItemIn.Items[i], SubMenuItemOut.Items[i]); end; end; begin - MenuButton := TSpeedButton(Sender); - tmpMI := FMenu.Items[MenuButton.Tag]; + MenuButton := TToolBarSpeedButton(Sender); + tmpMI := FMenu.Items[MenuButton.FMenuItemIndex]; if not Assigned(tmpMI) then Exit; tmpMI.Click; FSubMenu.Items.Clear; From 99e2074a2d9d14072a7cfaadcfdf590198ee77b4 Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 4 Jan 2025 13:07:06 +0100 Subject: [PATCH 5/7] LCL: Toolbar with menu, use MenuItem.Bitmap --- lcl/include/toolbar.inc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lcl/include/toolbar.inc b/lcl/include/toolbar.inc index 9419ae470a..77c04b1a68 100644 --- a/lcl/include/toolbar.inc +++ b/lcl/include/toolbar.inc @@ -338,12 +338,18 @@ begin tmpMenuButton.FMenuItemIndex:= i; wglyph := 0; tmpMenuButton.Images := nil; - if Assigned(FMenu.Images) and (FMenu.Items[i].ImageIndex >= 0) then + if Assigned(FMenu.Images) and (FMenu.Items[i].ImageIndex >= 0) then begin if FMenu.Items[i].ImageIndex < FMenu.Images.Count then begin FMenu.Images.GetBitmap(FMenu.Items[i].ImageIndex, tmpMenuButton.Glyph); wglyph := tmpMenuButton.Glyph.Width + 5; end; + end + else + if Assigned(FMenu.Items[i].Bitmap) then begin + tmpMenuButton.Glyph := FMenu.Items[i].Bitmap; + wglyph := tmpMenuButton.Glyph.Width + 5; + end; tmpMenuButton.OnClick := @MenuButtonClick; tmpMenuButton.Parent := Self; if FMenu.Items[i].Default then tmpMenuButton.Font.Style := [fsBold]; @@ -401,6 +407,7 @@ var SubMenuItemOut.Items[i].GlyphShowMode := SubMenuItemIn.Items[i].GlyphShowMode; SubMenuItemOut.Items[i].GroupIndex := SubMenuItemIn.Items[i].GroupIndex; SubMenuItemOut.Items[i].Hint := SubMenuItemIn.Items[i].Hint; + SubMenuItemOut.Items[i].Bitmap := SubMenuItemIn.Items[i].Bitmap; SubMenuItemOut.Items[i].ImageIndex := SubMenuItemIn.Items[i].ImageIndex; SubMenuItemOut.Items[i].RadioItem := SubMenuItemIn.Items[i].RadioItem; SubMenuItemOut.Items[i].RightJustify := SubMenuItemIn.Items[i].RightJustify; From ce20675a1b9e6fa2d9237f33254c3a72cc4631f6 Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 4 Jan 2025 13:06:41 +0100 Subject: [PATCH 6/7] LCL: MenuItem, SetBitmap did not trigger change when old Bitmap existed, and was only re-assigned --- lcl/include/menuitem.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/lcl/include/menuitem.inc b/lcl/include/menuitem.inc index 6f4d731d2e..0f8b4e389e 100644 --- a/lcl/include/menuitem.inc +++ b/lcl/include/menuitem.inc @@ -1770,6 +1770,7 @@ end; procedure TMenuItem.BitmapChange(Sender: TObject); begin UpdateImage; + MenuChanged(False); end; function TMenuItem.GetAutoLineReduction: Boolean; From afe87b6e8c1dc4c92d9930a0783419a013066628 Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 28 Dec 2024 17:21:32 +0100 Subject: [PATCH 7/7] LCL: Docked-Designer, FakeMenu-Toolbar, layout --- .../dockedformeditor/source/dockedgrip.pas | 17 +++++++++++++++-- .../source/dockedresizecontrol.pas | 16 +++++----------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/components/dockedformeditor/source/dockedgrip.pas b/components/dockedformeditor/source/dockedgrip.pas index 4e553030c4..f0d176799c 100644 --- a/components/dockedformeditor/source/dockedgrip.pas +++ b/components/dockedformeditor/source/dockedgrip.pas @@ -40,7 +40,7 @@ uses // RTL, FCL Classes, SysUtils, math, // LCL - Controls, ComCtrls, ExtCtrls, Graphics, Menus; + Controls, ComCtrls, ExtCtrls, Graphics, Menus, Toolwin; type @@ -606,9 +606,15 @@ begin FResizeBars.Parent := Parent; FFakeMenu := TToolBar.Create(Parent); + FFakeMenu.ParentFont := False; + FFakeMenu.Orientation := tboHorizontal; + FFakeMenu.EdgeBorders := []; + FFakeMenu.EdgeInner := esNone; + FFakeMenu.EdgeOuter := esNone; FFakeMenu.Height := 0; FFakeMenu.Parent := Parent; FFakeMenu.Align := alNone; + FFakeMenu.AutoSize := True; FFakeMenu.Indent := 0; FFormClient := TWinControl.Create(Parent); @@ -647,11 +653,18 @@ begin end; procedure TResizeContainer.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); +var + w: Integer; begin FBoundsRect := Rect(ALeft, ATop, ALeft + AWidth, ATop + AHeight); FResizeGrips.SetBounds(FBoundsRect); FResizeBars.SetBounds(FBoundsRect); - FFakeMenu.SetBounds(ALeft + FResizeBars.BarSize, ATop + FResizeBars.BarSize, AWidth - FResizeBars.BarSize * 2, FFakeMenu.Height); + w := Max(0, AWidth - FResizeBars.BarSize * 2); + FFakeMenu.Visible := w > 0; + FFakeMenu.Constraints.MinWidth := w; + FFakeMenu.Constraints.MaxWidth := w; + FFakeMenu.Top := ATop + FResizeBars.BarSize; + FFakeMenu.Left := ALeft + FResizeBars.BarSize; FFormClient.SetBounds(ALeft + FResizeBars.BarSize, ATop + FResizeBars.BarSize + FFakeMenu.Height, AWidth - FResizeBars.BarSize * 2, AHeight - FResizeBars.BarSize * 2 - FFakeMenu.Height); FAnchorContainer.SetBounds(ALeft + FResizeBars.BarSize, ATop + FResizeBars.BarSize + FFakeMenu.Height, AWidth - FResizeBars.BarSize * 2, AHeight - FResizeBars.BarSize * 2 - FFakeMenu.Height); end; diff --git a/components/dockedformeditor/source/dockedresizecontrol.pas b/components/dockedformeditor/source/dockedresizecontrol.pas index b3b6196249..ce76c2d920 100644 --- a/components/dockedformeditor/source/dockedresizecontrol.pas +++ b/components/dockedformeditor/source/dockedresizecontrol.pas @@ -344,19 +344,13 @@ end; procedure TResizeControl.TryBoundDesignForm; var - i, t: Integer; + f: Boolean; begin if DesignForm = nil then Exit; - if FakeMenuNeeded then - begin - FakeMenu.ButtonHeight := DesignForm.MainMenuHeight; - t := 0; - for i := 0 to FakeMenu.ComponentCount - 1 do //For multi-line MainMenu - if FakeMenu.Components[i] is TSpeedButton then - if t < TSpeedButton(FakeMenu.Components[i]).Top then t := TSpeedButton(FakeMenu.Components[i]).Top; - FakeMenu.Height := t + FakeMenu.ButtonHeight; - FakeMenu.Update; - end else FakeMenu.Height := 0; + f := FakeMenuNeeded; + FakeMenu.AutoSize := f; + if not f then + FakeMenu.Height := 0; end; constructor TResizeControl.Create(TheOwner: TComponent);