mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 07:03:39 +02:00
893 lines
25 KiB
ObjectPascal
893 lines
25 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
* *
|
|
* See the file COPYING.modifiedLGPL, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
Interface to the IDE menus.
|
|
|
|
ToDo:
|
|
- Create MainBar menu with the menu interface
|
|
- Create Source Editor Popupmenu with the menu interface
|
|
- Create CodeExplorer Popupmenu with the menu interface
|
|
- Create Project Inspector Popupmenu with the menu interface
|
|
- Create Messages Popupmenu with the menu interface
|
|
}
|
|
unit MenuIntf;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LCLProc, Menus, ImgList, Graphics, TextTools, HelpIntf,
|
|
IDECommands;
|
|
|
|
type
|
|
TAddMenuItemProc =
|
|
function (const NewCaption: string; const NewEnabled: boolean;
|
|
const NewOnClick: TNotifyEvent): TMenuItem of object;
|
|
|
|
TIDEMenuSection = class;
|
|
TNotifyProcedure = procedure(Sender: TObject);
|
|
|
|
{ TIDEMenuItem
|
|
A menu item in one of the IDE's menus.
|
|
This is only the base class for TIDEMenuSection and TIDEMenuCommand }
|
|
|
|
TIDEMenuItem = class(TPersistent)
|
|
private
|
|
FBitmap: TBitmap;
|
|
FCaption: string;
|
|
FEnabled: Boolean;
|
|
FImageIndex: Integer;
|
|
FMenuItem: TMenuItem;
|
|
FMenuItemClass: TMenuItemClass;
|
|
FName: string;
|
|
FOnClickMethod: TNotifyEvent;
|
|
FOnClickProc: TNotifyProcedure;
|
|
FSection: TIDEMenuSection;
|
|
FVisible: Boolean;
|
|
FHint: string;
|
|
procedure MenuItemClick(Sender: TObject);
|
|
protected
|
|
function GetBitmap: TBitmap; virtual;
|
|
function GetCaption: string; virtual;
|
|
function GetHint: String; virtual;
|
|
procedure SetBitmap(const AValue: TBitmap); virtual;
|
|
procedure SetCaption(const AValue: string); virtual;
|
|
procedure SetEnabled(const AValue: Boolean); virtual;
|
|
procedure SetHint(const AValue: String); virtual;
|
|
procedure SetImageIndex(const AValue: Integer); virtual;
|
|
procedure SetMenuItem(const AValue: TMenuItem); virtual;
|
|
procedure SetName(const AValue: string); virtual;
|
|
procedure SetSection(const AValue: TIDEMenuSection); virtual;
|
|
procedure SetVisible(const AValue: Boolean); virtual;
|
|
procedure ClearMenuItems; virtual;
|
|
public
|
|
constructor Create(const TheName: string); virtual;
|
|
destructor Destroy; override;
|
|
function HasBitmap: Boolean;
|
|
procedure CreateMenuItem; virtual;
|
|
function Size: Integer; virtual;
|
|
function GetPath: string;
|
|
public
|
|
property Name: string read FName write SetName;
|
|
property Bitmap: TBitmap read GetBitmap write SetBitmap;
|
|
property Hint: String read GetHint write SetHint;
|
|
property ImageIndex: Integer read FImageIndex write SetImageIndex;
|
|
property Visible: Boolean read FVisible write SetVisible;
|
|
property OnClickMethod: TNotifyEvent read FOnClickMethod write FOnClickMethod;
|
|
property OnClickProc: TNotifyProcedure read FOnClickProc write FOnClickProc;
|
|
property Caption: string read GetCaption write SetCaption;
|
|
property Section: TIDEMenuSection read FSection write SetSection;
|
|
property Enabled: Boolean read FEnabled write SetEnabled;
|
|
property MenuItem: TMenuItem read FMenuItem write SetMenuItem;
|
|
property MenuItemClass: TMenuItemClass read FMenuItemClass write FMenuItemClass;
|
|
end;
|
|
TIDEMenuItemClass = class of TIDEMenuItem;
|
|
|
|
|
|
{ TIDEMenuSection
|
|
An TIDEMenuItem with childs, either in a sub menu or separated with
|
|
separators. }
|
|
|
|
TIDEMenuSection = class(TIDEMenuItem)
|
|
private
|
|
FBottomSeparator: TMenuItem;
|
|
FChildsAsSubMenu: boolean;
|
|
FSubMenuImages: TCustomImageList;
|
|
FItems: TFPList;
|
|
FTopSeparator: TMenuItem;
|
|
function GetItems(Index: Integer): TIDEMenuItem;
|
|
protected
|
|
procedure SetMenuItem(const AValue: TMenuItem); override;
|
|
procedure SetChildsAsSubMenu(const AValue: boolean); virtual;
|
|
procedure SetSubMenuImages(const AValue: TCustomImageList); virtual;
|
|
procedure ClearMenuItems; override;
|
|
public
|
|
constructor Create(const TheName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
function Count: Integer;
|
|
procedure AddFirst(AnItem: TIDEMenuItem);
|
|
procedure AddLast(AnItem: TIDEMenuItem);
|
|
procedure Insert(Index: Integer; AnItem: TIDEMenuItem);
|
|
procedure CreateChildMenuItem(Index: Integer); virtual;
|
|
function GetChildsStartIndex: Integer;
|
|
function Size: Integer; override;
|
|
function IndexOf(AnItem: TIDEMenuItem): Integer;
|
|
function NeedTopSeparator: Boolean;
|
|
function NeedBottomSeparator: Boolean;
|
|
function GetContainerMenuItem: TMenuItem;
|
|
function IndexByName(const AName: string): Integer;
|
|
function FindByName(const AName: string): TIDEMenuItem;
|
|
function CreateUniqueName(const AName: string): string;
|
|
public
|
|
property ChildsAsSubMenu: boolean read FChildsAsSubMenu
|
|
write SetChildsAsSubMenu default true;
|
|
property SubMenuImages: TCustomImageList read FSubMenuImages
|
|
write SetSubMenuImages;
|
|
property Items[Index: Integer]: TIDEMenuItem read GetItems; default;
|
|
property TopSeparator: TMenuItem read FTopSeparator;
|
|
property BottomSeparator: TMenuItem read FBottomSeparator;
|
|
end;
|
|
TIDEMenuSectionClass = class of TIDEMenuSection;
|
|
|
|
|
|
{ TIDEMenuCommand
|
|
A leaf menu item. No childs.
|
|
Hint: The shortcut is defined via the Command property.
|
|
}
|
|
TIDEMenuCommand = class(TIDEMenuItem)
|
|
private
|
|
FAutoCheck: boolean;
|
|
FChecked: Boolean;
|
|
FCommand: TIDECommandKeys;
|
|
FDefault: Boolean;
|
|
FGroupIndex: Byte;
|
|
FRadioItem: Boolean;
|
|
FRightJustify: boolean;
|
|
FShowAlwaysCheckable: boolean;
|
|
protected
|
|
procedure SetAutoCheck(const AValue: boolean); virtual;
|
|
procedure SetChecked(const AValue: Boolean); virtual;
|
|
procedure SetDefault(const AValue: Boolean); virtual;
|
|
procedure SetGroupIndex(const AValue: Byte); virtual;
|
|
procedure SetRadioItem(const AValue: Boolean); virtual;
|
|
procedure SetRightJustify(const AValue: boolean); virtual;
|
|
procedure SetShowAlwaysCheckable(const AValue: boolean); virtual;
|
|
procedure SetCommand(const AValue: TIDECommandKeys); virtual;
|
|
procedure SetMenuItem(const AValue: TMenuItem); override;
|
|
public
|
|
property Command: TIDECommandKeys read FCommand write SetCommand;
|
|
property AutoCheck: boolean read FAutoCheck write SetAutoCheck default False;
|
|
property Checked: Boolean read FChecked write SetChecked default False;
|
|
property Default: Boolean read FDefault write SetDefault default False;
|
|
property GroupIndex: Byte read FGroupIndex write SetGroupIndex default 0;
|
|
property RadioItem: Boolean read FRadioItem write SetRadioItem;
|
|
property RightJustify: boolean read FRightJustify write SetRightJustify;
|
|
property ShowAlwaysCheckable: boolean read FShowAlwaysCheckable
|
|
write SetShowAlwaysCheckable;
|
|
end;
|
|
TIDEMenuCommandClass = class of TIDEMenuCommand;
|
|
|
|
|
|
{ TIDEMenuRoots
|
|
These are the top level menu items of the IDE. }
|
|
|
|
TIDEMenuRoots = class(TPersistent)
|
|
private
|
|
FItems: TFPList;// list of TIDEMenuSection
|
|
function GetItems(Index: integer): TIDEMenuSection;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure RegisterMenuRoot(Section: TIDEMenuSection);
|
|
procedure UnregisterMenuRoot(Section: TIDEMenuSection);
|
|
function Count: Integer;
|
|
procedure Clear;
|
|
procedure Delete(Index: Integer);
|
|
function IndexByName(const Name: string): Integer;
|
|
function FindByName(const Name: string): TIDEMenuSection;
|
|
function CreateUniqueName(const Name: string): string;
|
|
function FindByPath(const Path: string;
|
|
ErrorOnNotFound: boolean): TIDEMenuItem;
|
|
public
|
|
property Items[Index: integer]: TIDEMenuSection read GetItems; default;
|
|
end;
|
|
|
|
var
|
|
IDEMenuRoots: TIDEMenuRoots = nil;// created by the IDE
|
|
// Popupmenu of the SourceEditor:
|
|
SourceEditorMenuRoot: TIDEMenuSection;
|
|
// Source Editor: First dynamic section for often used context sensitive stuff
|
|
SrcEditMenuSectionFirstDynamic: TIDEMenuSection;
|
|
// Source Editor: First static section (e.g. Find Declaration)
|
|
SrcEditMenuSectionFirstStatic: TIDEMenuSection;
|
|
// Source Editor: Clipboard section (e.g. cut, copy, paste)
|
|
SrcEditMenuSectionClipboard: TIDEMenuSection;
|
|
// Source Editor: register the File Specific dynamic section
|
|
SrcEditMenuSectionFileDynamic: TIDEMenuSection;
|
|
// Source Editor: register the marks section
|
|
SrcEditMenuSectionMarks: TIDEMenuSection;
|
|
// Source Editor: register the Goto Bookmarks Submenu
|
|
SrcEditSubMenuGotoBookmarks: TIDEMenuSection;
|
|
// Source Editor: register the Set Bookmarks Submenu
|
|
SrcEditSubMenuSetBookmarks: TIDEMenuSection;
|
|
|
|
MessagesMenuRoot: TIDEMenuSection;
|
|
CodeExplorerMenuRoot: TIDEMenuSection;
|
|
|
|
function RegisterIDEMenuRoot(const Name: string; MenuItem: TMenuItem = nil
|
|
): TIDEMenuSection;
|
|
function RegisterIDEMenuSection(const Path, Name: string): TIDEMenuSection;
|
|
function RegisterIDESubMenu(const Path, Name, Caption: string;
|
|
const OnClickMethod: TNotifyEvent = nil;
|
|
const OnClickProc: TNotifyProcedure = nil
|
|
): TIDEMenuSection;
|
|
function RegisterIDEMenuCommand(const Path, Name, Caption: string;
|
|
const OnClickMethod: TNotifyEvent = nil;
|
|
const OnClickProc: TNotifyProcedure = nil;
|
|
const Command: TIDECommandKeys = nil
|
|
): TIDEMenuCommand;
|
|
|
|
implementation
|
|
|
|
function RegisterIDEMenuRoot(const Name: string; MenuItem: TMenuItem
|
|
): TIDEMenuSection;
|
|
begin
|
|
{$IFDEF VerboseMenuIntf}
|
|
debugln('RegisterIDEMenuRoot Name="',Name,'"');
|
|
{$ENDIF}
|
|
Result:=TIDEMenuSection.Create(Name);
|
|
IDEMenuRoots.RegisterMenuRoot(Result);
|
|
Result.MenuItem:=MenuItem;
|
|
end;
|
|
|
|
function RegisterIDEMenuSection(const Path, Name: string): TIDEMenuSection;
|
|
var
|
|
Parent: TIDEMenuSection;
|
|
begin
|
|
{$IFDEF VerboseMenuIntf}
|
|
debugln('RegisterIDEMenuSection Path="',Path,'" Name="',Name,'"');
|
|
{$ENDIF}
|
|
Parent:=IDEMenuRoots.FindByPath(Path,true) as TIDEMenuSection;
|
|
Result:=TIDEMenuSection.Create(Name);
|
|
Result.ChildsAsSubMenu:=false;
|
|
Parent.AddLast(Result);
|
|
end;
|
|
|
|
function RegisterIDESubMenu(const Path, Name, Caption: string;
|
|
const OnClickMethod: TNotifyEvent; const OnClickProc: TNotifyProcedure
|
|
): TIDEMenuSection;
|
|
var
|
|
Parent: TIDEMenuSection;
|
|
begin
|
|
{$IFDEF VerboseMenuIntf}
|
|
debugln('RegisterIDESubMenu Path="',Path,'" Name="',Name,'"');
|
|
{$ENDIF}
|
|
Parent:=IDEMenuRoots.FindByPath(Path,true) as TIDEMenuSection;
|
|
Result:=TIDEMenuSection.Create(Name);
|
|
Result.ChildsAsSubMenu:=true;
|
|
Result.Caption:=Caption;
|
|
Result.OnClickMethod:=OnClickMethod;
|
|
Result.OnClickProc:=OnClickProc;
|
|
Parent.AddLast(Result);
|
|
end;
|
|
|
|
function RegisterIDEMenuCommand(const Path, Name, Caption: string;
|
|
const OnClickMethod: TNotifyEvent; const OnClickProc: TNotifyProcedure;
|
|
const Command: TIDECommandKeys): TIDEMenuCommand;
|
|
var
|
|
Parent: TIDEMenuSection;
|
|
begin
|
|
{$IFDEF VerboseMenuIntf}
|
|
debugln('RegisterIDEMenuCommand Path="',Path,'" Name="',Name,'"');
|
|
{$ENDIF}
|
|
Parent:=IDEMenuRoots.FindByPath(Path,true) as TIDEMenuSection;
|
|
Result:=TIDEMenuCommand.Create(Name);
|
|
Result.Caption:=Caption;
|
|
Result.OnClickMethod:=OnClickMethod;
|
|
Result.OnClickProc:=OnClickProc;
|
|
Result.Command:=Command;
|
|
Parent.AddLast(Result);
|
|
end;
|
|
|
|
{ TIDEMenuItem }
|
|
|
|
procedure TIDEMenuItem.MenuItemClick(Sender: TObject);
|
|
begin
|
|
if Assigned(OnClickMethod) then OnClickMethod(Sender);
|
|
if Assigned(OnClickProc) then OnClickProc(Sender);
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetEnabled(const AValue: Boolean);
|
|
begin
|
|
if FEnabled=AValue then exit;
|
|
FEnabled:=AValue;
|
|
end;
|
|
|
|
function TIDEMenuItem.GetBitmap: TBitmap;
|
|
begin
|
|
if FBitmap=nil then
|
|
FBitmap:=TBitmap.Create;
|
|
FBitmap.Transparent:=True;
|
|
Result:=FBitmap;
|
|
end;
|
|
|
|
function TIDEMenuItem.GetCaption: string;
|
|
begin
|
|
if FCaption<>'' then
|
|
Result:=FCaption
|
|
else
|
|
Result:=FName;
|
|
end;
|
|
|
|
function TIDEMenuItem.GetHint: String;
|
|
begin
|
|
Result:=FHint;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetBitmap(const AValue: TBitmap);
|
|
begin
|
|
if FBitmap=AValue then exit;
|
|
if AValue<>nil then
|
|
Bitmap.Assign(AValue)
|
|
else
|
|
FBitmap.Free;
|
|
if MenuItem<>nil then
|
|
MenuItem.Bitmap:=FBitmap;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetCaption(const AValue: string);
|
|
begin
|
|
FCaption:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.Caption:=Caption;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetHint(const AValue: String);
|
|
begin
|
|
FHint:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.Hint:=Hint;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetImageIndex(const AValue: Integer);
|
|
begin
|
|
if FImageIndex=AValue then exit;
|
|
FImageIndex:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.ImageIndex:=ImageIndex;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetMenuItem(const AValue: TMenuItem);
|
|
begin
|
|
if FMenuItem=AValue then exit;
|
|
if FMenuItem<>nil then ClearMenuItems;
|
|
FMenuItem:=AValue;
|
|
if MenuItem<>nil then begin
|
|
MenuItem.Caption:=Caption;
|
|
MenuItem.Bitmap:=FBitmap;
|
|
MenuItem.Hint:=Hint;
|
|
MenuItem.ImageIndex:=ImageIndex;
|
|
MenuItem.Visible:=Visible;
|
|
MenuItem.OnClick:=@MenuItemClick;
|
|
end;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetName(const AValue: string);
|
|
begin
|
|
if FName=AValue then exit;
|
|
FName:=AValue;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetSection(const AValue: TIDEMenuSection);
|
|
begin
|
|
if FSection=AValue then exit;
|
|
ClearMenuItems;
|
|
FSection:=AValue;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.SetVisible(const AValue: Boolean);
|
|
begin
|
|
if FVisible=AValue then exit;
|
|
FVisible:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.Visible:=Visible;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.ClearMenuItems;
|
|
begin
|
|
FMenuItem:=nil;
|
|
end;
|
|
|
|
constructor TIDEMenuItem.Create(const TheName: string);
|
|
begin
|
|
inherited Create;
|
|
FName:=TheName;
|
|
FEnabled:=true;
|
|
FVisible:=true;
|
|
FMenuItemClass:=TMenuItem;
|
|
{$IFDEF VerboseMenuIntf}
|
|
debugln('TIDEMenuItem.Create ',dbgsName(Self),' Name="',Name,'"');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
destructor TIDEMenuItem.Destroy;
|
|
begin
|
|
FreeAndNil(FBitmap);
|
|
FreeAndNil(FMenuItem);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TIDEMenuItem.HasBitmap: Boolean;
|
|
begin
|
|
Result:=FBitmap<>nil;
|
|
end;
|
|
|
|
procedure TIDEMenuItem.CreateMenuItem;
|
|
begin
|
|
if FMenuItem<>nil then exit;
|
|
MenuItem:=MenuItemClass.Create(nil);
|
|
end;
|
|
|
|
function TIDEMenuItem.Size: Integer;
|
|
begin
|
|
if Visible then
|
|
Result:=1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function TIDEMenuItem.GetPath: string;
|
|
var
|
|
Item: TIDEMenuItem;
|
|
begin
|
|
Result:=Name;
|
|
Item:=Section;
|
|
while Item<>nil do begin
|
|
Result:=Item.Name+'/'+Result;
|
|
Item:=Item.Section;
|
|
end;
|
|
end;
|
|
|
|
{ TIDEMenuSection }
|
|
|
|
procedure TIDEMenuSection.SetSubMenuImages(const AValue: TCustomImageList);
|
|
begin
|
|
if FSubMenuImages=AValue then exit;
|
|
FSubMenuImages:=AValue;
|
|
end;
|
|
|
|
procedure TIDEMenuSection.ClearMenuItems;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited ClearMenuItems;
|
|
for i:=0 to Count-1 do Items[i].MenuItem:=nil;
|
|
end;
|
|
|
|
constructor TIDEMenuSection.Create(const TheName: string);
|
|
begin
|
|
inherited Create(TheName);
|
|
FChildsAsSubMenu:=true;
|
|
FItems:=TFPList.Create;
|
|
end;
|
|
|
|
destructor TIDEMenuSection.Destroy;
|
|
begin
|
|
Clear;
|
|
FItems.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TIDEMenuSection.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=FItems.Count-1 downto 0 do TObject(FItems[i]).Free;
|
|
FItems.Clear;
|
|
end;
|
|
|
|
function TIDEMenuSection.Count: Integer;
|
|
begin
|
|
Result:=FItems.Count;
|
|
end;
|
|
|
|
procedure TIDEMenuSection.AddFirst(AnItem: TIDEMenuItem);
|
|
begin
|
|
Insert(0,AnItem);
|
|
end;
|
|
|
|
procedure TIDEMenuSection.AddLast(AnItem: TIDEMenuItem);
|
|
begin
|
|
Insert(Count,AnItem);
|
|
end;
|
|
|
|
procedure TIDEMenuSection.Insert(Index: Integer; AnItem: TIDEMenuItem);
|
|
begin
|
|
AnItem.fName:=CreateUniqueName(AnItem.Name);
|
|
FItems.Insert(Index,AnItem);
|
|
AnItem.FSection:=Self;
|
|
CreateChildMenuItem(Index);
|
|
end;
|
|
|
|
procedure TIDEMenuSection.CreateChildMenuItem(Index: Integer);
|
|
var
|
|
Item: TIDEMenuItem;
|
|
SubSection: TIDEMenuSection;
|
|
i: Integer;
|
|
ContainerMenuItem: TMenuItem;
|
|
MenuIndex: Integer;
|
|
begin
|
|
ContainerMenuItem:=GetContainerMenuItem;
|
|
if (ContainerMenuItem=nil) then exit;
|
|
|
|
Item:=Items[Index];
|
|
{$IFDEF VerboseMenuIntf}
|
|
debugln('TIDEMenuSection.CreateChildMenuItem ',dbgsName(Self),' Name=',Name,' Index=',dbgs(Index),' Item=',Item.Name,' Container=',ContainerMenuItem.Name);
|
|
{$ENDIF}
|
|
|
|
MenuIndex:=GetChildsStartIndex+Index;
|
|
|
|
if NeedTopSeparator then begin
|
|
if (TopSeparator=nil) then begin
|
|
// create TopSeparator
|
|
FTopSeparator:=MenuItemClass.Create(nil);
|
|
FTopSeparator.Caption:='-';
|
|
MenuItem.Insert(GetChildsStartIndex,FTopSeparator);
|
|
end;
|
|
inc(MenuIndex);
|
|
end;
|
|
|
|
// create the child TMenuItem
|
|
Item.CreateMenuItem;
|
|
MenuItem.Insert(MenuIndex,Item.MenuItem);
|
|
// create the subsections
|
|
if Item is TIDEMenuSection then begin
|
|
SubSection:=TIDEMenuSection(Item);
|
|
for i:=0 to SubSection.Count-1 do
|
|
SubSection.CreateChildMenuItem(i);
|
|
end;
|
|
|
|
if (Index=Count-1) and NeedBottomSeparator and (BottomSeparator=nil) then
|
|
begin
|
|
// create bottom separator
|
|
FBottomSeparator:=MenuItemClass.Create(nil);
|
|
FBottomSeparator.Caption:='-';
|
|
MenuItem.Insert(MenuIndex+1,FBottomSeparator);
|
|
end;
|
|
end;
|
|
|
|
function TIDEMenuSection.GetChildsStartIndex: Integer;
|
|
var
|
|
SiblingIndex: Integer;
|
|
begin
|
|
Result:=0;
|
|
if ChildsAsSubMenu or (Section=nil) then exit;
|
|
SiblingIndex:=0;
|
|
while (Section[SiblingIndex]<>Self) do begin
|
|
inc(Result,Section[SiblingIndex].Size);
|
|
inc(SiblingIndex);
|
|
end;
|
|
if not Section.ChildsAsSubMenu then
|
|
inc(Result,Section.GetChildsStartIndex);
|
|
end;
|
|
|
|
function TIDEMenuSection.Size: Integer;
|
|
begin
|
|
if Visible then begin
|
|
Result:=1;
|
|
if (Section<>nil) and (not ChildsAsSubMenu) then begin
|
|
// childs are not in a submenu but directly added to parents menuitem
|
|
Result:=Count;
|
|
if NeedTopSeparator then inc(Result);
|
|
if NeedBottomSeparator then inc(Result);
|
|
end;
|
|
end else begin
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
function TIDEMenuSection.IndexOf(AnItem: TIDEMenuItem): Integer;
|
|
begin
|
|
Result:=FItems.IndexOf(AnItem);
|
|
end;
|
|
|
|
function TIDEMenuSection.NeedTopSeparator: Boolean;
|
|
begin
|
|
if (not ChildsAsSubMenu) and (Section<>nil) and (Section.Items[0]<>Self) then
|
|
Result:=true
|
|
else
|
|
Result:=false;
|
|
end;
|
|
|
|
function TIDEMenuSection.NeedBottomSeparator: Boolean;
|
|
var
|
|
SelfIndex: LongInt;
|
|
NextSibling: TIDEMenuItem;
|
|
begin
|
|
Result:=false;
|
|
if (not ChildsAsSubMenu) and (Section<>nil)
|
|
and (Section.Items[Section.Count-1]<>Self) then begin
|
|
SelfIndex:=Section.IndexOf(Self);
|
|
NextSibling:=Section[SelfIndex-1];
|
|
if (not (NextSibling is TIDEMenuSection))
|
|
or (not TIDEMenuSection(NextSibling).ChildsAsSubMenu) then begin
|
|
// a bottom separator is needed
|
|
Result:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TIDEMenuSection.GetContainerMenuItem: TMenuItem;
|
|
var
|
|
IDEMenuItem: TIDEMenuSection;
|
|
begin
|
|
IDEMenuItem:=Self;
|
|
while (IDEMenuItem<>nil) and (not IDEMenuItem.ChildsAsSubMenu) do
|
|
IDEMenuItem:=IDEMenuItem.Section;
|
|
if (IDEMenuItem<>nil) then
|
|
Result:=IDEMenuItem.MenuItem;
|
|
end;
|
|
|
|
function TIDEMenuSection.IndexByName(const AName: string): Integer;
|
|
begin
|
|
Result:=Count-1;
|
|
while (Result>=0) and (CompareText(AName,Items[Result].Name)<>0) do
|
|
dec(Result);
|
|
end;
|
|
|
|
function TIDEMenuSection.FindByName(const AName: string): TIDEMenuItem;
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
i:=IndexByName(AName);
|
|
if i>=0 then
|
|
Result:=Items[i]
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TIDEMenuSection.CreateUniqueName(const AName: string): string;
|
|
begin
|
|
Result:=AName;
|
|
if IndexByName(Result)<0 then exit;
|
|
Result:=CreateFirstIdentifier(Result);
|
|
while IndexByName(Result)>=0 do
|
|
Result:=CreateNextIdentifier(Result);
|
|
end;
|
|
|
|
function TIDEMenuSection.GetItems(Index: Integer): TIDEMenuItem;
|
|
begin
|
|
Result:=TIDEMenuItem(FItems[Index]);
|
|
end;
|
|
|
|
procedure TIDEMenuSection.SetMenuItem(const AValue: TMenuItem);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if MenuItem=AValue then exit;
|
|
inherited SetMenuItem(AValue);
|
|
if MenuItem<>nil then begin
|
|
for i:=0 to Count-1 do CreateChildMenuItem(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TIDEMenuSection.SetChildsAsSubMenu(const AValue: boolean);
|
|
begin
|
|
if FChildsAsSubMenu=AValue then exit;
|
|
FChildsAsSubMenu:=AValue;
|
|
end;
|
|
|
|
{ TIDEMenuCommand }
|
|
|
|
procedure TIDEMenuCommand.SetAutoCheck(const AValue: boolean);
|
|
begin
|
|
if FAutoCheck=AValue then exit;
|
|
FAutoCheck:=AValue;
|
|
if MenuItem<>nil then MenuItem.AutoCheck:=AutoCheck;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetChecked(const AValue: Boolean);
|
|
begin
|
|
if FChecked=AValue then exit;
|
|
FChecked:=AValue;
|
|
if MenuItem<>nil then MenuItem.Checked:=Checked;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetDefault(const AValue: Boolean);
|
|
begin
|
|
if FDefault=AValue then exit;
|
|
FDefault:=AValue;
|
|
if MenuItem<>nil then MenuItem.Default:=Default;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetGroupIndex(const AValue: Byte);
|
|
begin
|
|
if FGroupIndex=AValue then exit;
|
|
FGroupIndex:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.GroupIndex:=GroupIndex;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetRadioItem(const AValue: Boolean);
|
|
begin
|
|
if FRadioItem=AValue then exit;
|
|
FRadioItem:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.RadioItem:=RadioItem;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetRightJustify(const AValue: boolean);
|
|
begin
|
|
if FRightJustify=AValue then exit;
|
|
FRightJustify:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.RightJustify:=RightJustify;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetShowAlwaysCheckable(const AValue: boolean);
|
|
begin
|
|
if FShowAlwaysCheckable=AValue then exit;
|
|
FShowAlwaysCheckable:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.ShowAlwaysCheckable:=ShowAlwaysCheckable;
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetCommand(const AValue: TIDECommandKeys);
|
|
begin
|
|
if FCommand=AValue then exit;
|
|
FCommand:=AValue;
|
|
if MenuItem<>nil then
|
|
MenuItem.ShortCut:=IDEShortCutToMenuShortCut(AValue.KeyA);
|
|
end;
|
|
|
|
procedure TIDEMenuCommand.SetMenuItem(const AValue: TMenuItem);
|
|
begin
|
|
inherited SetMenuItem(AValue);
|
|
if MenuItem<>nil then begin
|
|
MenuItem.AutoCheck:=AutoCheck;
|
|
MenuItem.Checked:=Checked;
|
|
MenuItem.Default:=Default;
|
|
MenuItem.RadioItem:=RadioItem;
|
|
MenuItem.RightJustify:=RightJustify;
|
|
MenuItem.ShowAlwaysCheckable:=ShowAlwaysCheckable;
|
|
if Command<>nil then
|
|
MenuItem.ShortCut:=IDEShortCutToMenuShortCut(Command.KeyA)
|
|
else
|
|
MenuItem.ShortCut:=ShortCut(0,[]);
|
|
MenuItem.GroupIndex:=GroupIndex;
|
|
end;
|
|
end;
|
|
|
|
{ TIDEMenuRoots }
|
|
|
|
function TIDEMenuRoots.GetItems(Index: integer): TIDEMenuSection;
|
|
begin
|
|
Result:=TIDEMenuSection(FItems[Index]);
|
|
end;
|
|
|
|
constructor TIDEMenuRoots.Create;
|
|
begin
|
|
FItems:=TFPList.Create;
|
|
end;
|
|
|
|
destructor TIDEMenuRoots.Destroy;
|
|
begin
|
|
Clear;
|
|
FItems.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TIDEMenuRoots.RegisterMenuRoot(Section: TIDEMenuSection);
|
|
begin
|
|
Section.FName:=CreateUniqueName(Section.Name);
|
|
FItems.Add(Section);
|
|
end;
|
|
|
|
procedure TIDEMenuRoots.UnregisterMenuRoot(Section: TIDEMenuSection);
|
|
begin
|
|
FItems.Remove(Section);
|
|
end;
|
|
|
|
function TIDEMenuRoots.Count: Integer;
|
|
begin
|
|
Result:=FItems.Count;
|
|
end;
|
|
|
|
procedure TIDEMenuRoots.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=FItems.Count-1 downto 0 do begin
|
|
Items[i].ClearMenuItems;
|
|
Items[i].Free;
|
|
end;
|
|
FItems.Clear;
|
|
end;
|
|
|
|
procedure TIDEMenuRoots.Delete(Index: Integer);
|
|
var
|
|
OldItem: TIDEMenuSection;
|
|
begin
|
|
OldItem:=Items[Index];
|
|
UnregisterMenuRoot(OldItem);
|
|
OldItem.Free;
|
|
end;
|
|
|
|
function TIDEMenuRoots.IndexByName(const Name: string): Integer;
|
|
begin
|
|
Result:=Count-1;
|
|
while (Result>=0) and (CompareText(Name,Items[Result].Name)<>0) do
|
|
dec(Result);
|
|
end;
|
|
|
|
function TIDEMenuRoots.FindByName(const Name: string): TIDEMenuSection;
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
i:=IndexByName(Name);
|
|
if i>=0 then
|
|
Result:=Items[i]
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TIDEMenuRoots.CreateUniqueName(const Name: string): string;
|
|
begin
|
|
Result:=Name;
|
|
if IndexByName(Result)<0 then exit;
|
|
Result:=CreateFirstIdentifier(Result);
|
|
while IndexByName(Result)>=0 do
|
|
Result:=CreateNextIdentifier(Result);
|
|
end;
|
|
|
|
function TIDEMenuRoots.FindByPath(const Path: string;
|
|
ErrorOnNotFound: boolean): TIDEMenuItem;
|
|
var
|
|
StartPos: Integer;
|
|
EndPos: LongInt;
|
|
Name: String;
|
|
begin
|
|
Result:=nil;
|
|
StartPos:=1;
|
|
while StartPos<=length(Path) do begin
|
|
EndPos:=StartPos;
|
|
while (EndPos<=length(Path)) and (Path[EndPos]<>'/') do inc(EndPos);
|
|
if EndPos>StartPos then begin
|
|
Name:=copy(Path,StartPos,EndPos-StartPos);
|
|
if Result=nil then
|
|
// search root
|
|
Result:=FindByName(Name)
|
|
else if Result is TIDEMenuSection then
|
|
// search child
|
|
Result:=TIDEMenuSection(Result).FindByName(Name)
|
|
else
|
|
// path too long -> we are already at a leaf
|
|
Result:=nil;
|
|
if Result=nil then break;
|
|
end;
|
|
StartPos:=EndPos+1;
|
|
end;
|
|
if Result=nil then begin
|
|
if ErrorOnNotFound then begin
|
|
raise Exception.Create('IDE Menu path not found: '+Path);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|