lazarus/ideintf/menuintf.pas
mattias cc5784c6eb started MenuIntf for Source Editor
git-svn-id: trunk@7458 -
2005-07-30 17:26:22 +00:00

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.