mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-17 00:09:32 +02:00
1239 lines
35 KiB
ObjectPascal
1239 lines
35 KiB
ObjectPascal
unit MenuTemplates;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, types, fgl,
|
|
Buttons, Controls, Dialogs, StdCtrls, ExtCtrls, Menus,
|
|
ComCtrls, Forms, Graphics, Themes, LCLType, LCLIntf, LCLProc,
|
|
// LazUtils
|
|
LazFileUtils, Laz2_XMLCfg,
|
|
// IdeIntf
|
|
IDEDialogs,
|
|
// IDE
|
|
LazarusIDEStrConsts, MenuShortcuts;
|
|
|
|
type
|
|
{ TMenuTemplate }
|
|
|
|
TMenuTemplate = class(TObject)
|
|
strict private
|
|
FDescription: string;
|
|
FIsStandardTemplate: boolean;
|
|
FPrimaryItem: string;
|
|
FSubList: TStringList;
|
|
function GetShortcut(index: integer): TShortCut;
|
|
function GetSubItem(index: integer): string;
|
|
function GetSubItemCount: integer;
|
|
public
|
|
class function MenuItemToString(aMenuItem: TMenuItem; aDescription: string): string;
|
|
constructor CreateFromString(const aMenuString: string);
|
|
destructor Destroy; override;
|
|
function ReadFromString(const aString: string): boolean;
|
|
property Description: string read FDescription write FDescription;
|
|
property IsStandardTemplate: boolean read FIsStandardTemplate write FIsStandardTemplate;
|
|
property PrimaryItem: string read FPrimaryItem;
|
|
property Shortcut[index: integer]: TShortCut read GetShortcut;
|
|
property SubItem[index: integer]: string read GetSubItem;
|
|
property SubItemCount: integer read GetSubItemCount;
|
|
end;
|
|
|
|
TDialogMode = (dmInsert, dmSave, dmDelete);
|
|
TMenuTemplateList = specialize TFPGObjectList<TMenuTemplate>;
|
|
|
|
{ TMenuTemplates }
|
|
|
|
TMenuTemplates = class(TObject)
|
|
strict private
|
|
FTemplateList: TMenuTemplateList;
|
|
function GetDescription(index: integer): string;
|
|
function GetMenu(index: integer): TMenuItem;
|
|
function GetMenuCount: integer;
|
|
function GetMenuTemplate(index: integer): TMenuTemplate;
|
|
function GetPrimaryItem(index: integer): string;
|
|
procedure CheckIndex(anIndex: integer);
|
|
procedure LoadDefaultTemplates;
|
|
procedure LoadSavedTemplates;
|
|
public
|
|
constructor CreateForMode(aDialogMode: TDialogMode=dmInsert);
|
|
destructor Destroy; override;
|
|
function GetIndexOfTemplate(aMT: TMenuTemplate): integer;
|
|
procedure AddTemplate(const aTemplateText: string; isStandard: boolean=True);
|
|
procedure SaveTemplateToConfig(aMenuTemplate: TMenuTemplate);
|
|
property Description[index: integer]: string read GetDescription;
|
|
property Menu[index: integer]: TMenuItem read GetMenu;
|
|
property MenuCount: integer read GetMenuCount;
|
|
property MenuTemplate[index: integer]: TMenuTemplate read GetMenuTemplate;
|
|
property PrimaryItem[index: integer]: string read GetPrimaryItem;
|
|
end;
|
|
|
|
{ TPreview }
|
|
|
|
TPreview = class(TGraphicControl)
|
|
strict private
|
|
FDisplayAsPopup: boolean;
|
|
FTemplate: TMenuTemplate;
|
|
function GetSize: TSize;
|
|
procedure SetDisplayAsPopup(AValue: boolean);
|
|
protected
|
|
procedure Paint; override;
|
|
procedure SetParent(NewParent: TWinControl); override;
|
|
public
|
|
property DisplayAsPopup: boolean read FDisplayAsPopup write SetDisplayAsPopup;
|
|
procedure Clear;
|
|
procedure LoadTemplate(aMenuTemplate: tmenuTemplate);
|
|
end;
|
|
|
|
{ TMenuTemplateDialog }
|
|
|
|
TMenuTemplateDialog = class(TForm)
|
|
strict private
|
|
// GUI
|
|
FBCancel: TBitBtn;
|
|
FBExecute: TBitBtn;
|
|
FCBDisplay: TCheckBox;
|
|
FEDescription: TEdit;
|
|
FGChoose: TGroupBox;
|
|
FLDescription: TLabel;
|
|
FMenuToSave: TMenuItem;
|
|
FPButtons: TCustomPanel;
|
|
FPDescription: TPanel;
|
|
FPreview: TPreview;
|
|
FPRight: TCustomPanel;
|
|
FScrollBoxPreview: TScrollBox;
|
|
FSplitter: TSplitter;
|
|
FTVTemplates: TTreeView;
|
|
// data
|
|
FDialogMode: TDialogMode;
|
|
FMenuToInsert: TMenuItem;
|
|
FNewMenuTemplate: TMenuTemplate;
|
|
FNoneSavedNode: TTreeNode;
|
|
FSavedNode: TTreeNode;
|
|
FStandardNode: TTreeNode;
|
|
FTemplates: TMenuTemplates;
|
|
FMenu: TMenu;
|
|
procedure BExecuteDeleteClick(Sender: TObject);
|
|
procedure BExecuteInsertClick(Sender: TObject);
|
|
procedure BExecuteSaveClick(Sender: TObject);
|
|
procedure CancelButtonClick(Sender: TObject);
|
|
procedure CBDisplayChange(Sender: TObject);
|
|
procedure DeleteSelectedFromConfigFile;
|
|
procedure DeleteSelectedTemplate;
|
|
procedure EDescriptionChange(Sender: TObject);
|
|
procedure PopulateTreeView;
|
|
procedure SaveMenuAsTemplate;
|
|
procedure SetupGUI;
|
|
procedure ShowPreview(aMenuTemplate: TMenuTemplate);
|
|
procedure TVAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
|
|
State: TCustomDrawState; Stage: TCustomDrawStage;
|
|
var {%H-}PaintImages, DefaultDraw: Boolean);
|
|
procedure TVEditing(Sender: TObject; {%H-}Node: TTreeNode; var AllowEdit: Boolean);
|
|
procedure TVSelectionChanged(Sender: TObject);
|
|
protected
|
|
procedure DoShowWindow; override;
|
|
public
|
|
constructor CreateWithMode(aMenu: TMenu; aDialogMode: TDialogMode);
|
|
destructor Destroy; override;
|
|
property MenuToInsert: TMenuItem read FMenuToInsert;
|
|
property MenuToSave: TMenuItem read FMenuToSave write FMenuToSave;
|
|
end;
|
|
|
|
function SavedTemplatesExist: boolean;
|
|
function GetSavedTemplatesCount: integer;
|
|
function InsertMenuTemplateDlg(ParentMenuForInsert: TMenu): TMenuItem;
|
|
function DeleteMenuTemplateDlg: boolean;
|
|
function GetCfgPath: string;
|
|
procedure InitMenuBaseSizes;
|
|
|
|
const
|
|
MenuTemplatesFilename = 'menutemplates.xml';
|
|
|
|
var
|
|
MenuBar_Height: Integer = 20;
|
|
Separator_Height: Integer = 7;
|
|
Separator_Centre: Integer = 3;
|
|
DropDown_Height: Integer = 24;
|
|
MenuBar_Text_Offset: Integer = 7;
|
|
Double_MenuBar_Text_Offset: Integer = 14;
|
|
DropDown_Text_Offset: Integer = 35;
|
|
Double_DropDown_Text_Offset: Integer = 70;
|
|
Gutter_Offset: Integer = 6;
|
|
Gutter_X: Integer = 29;
|
|
Add_Icon_Width: Integer = 16;
|
|
|
|
implementation
|
|
|
|
function InvalidXML(aTemplateCfgName: string): boolean;
|
|
// perform a quick check, far from a full validation
|
|
var
|
|
sl: TStringList;
|
|
tr0, s: string;
|
|
begin
|
|
sl:=TStringList.Create;
|
|
try
|
|
sl.LoadFromFile(aTemplateCfgName);
|
|
if (sl.Count < 3) then
|
|
Exit(True);
|
|
tr0:=Trim(sl[0]);
|
|
s:=Copy(tr0, 1, 15);
|
|
if not SameText(s, '<?xml version="') then
|
|
Exit(True);
|
|
s:=Copy(tr0, Length(tr0) - 17, 18);
|
|
if not SameText(s, 'encoding="UTF-8"?>') then
|
|
Exit(True);
|
|
if not SameText(Trim(sl[1]), '<CONFIG>') then
|
|
Exit(True);
|
|
if not SameText(Trim(sl[Pred(sl.Count)]), '</CONFIG>') then
|
|
Exit(True);
|
|
Result:=False;
|
|
finally
|
|
sl.Free;
|
|
end;
|
|
end;
|
|
|
|
function SavedTemplatesExist: boolean;
|
|
var
|
|
XMLConfig: TXMLConfig;
|
|
cfgPath, s, templateCfgName: string;
|
|
begin
|
|
cfgPath:=GetCfgPath;
|
|
templateCfgName:=cfgPath + DirectorySeparator + MenuTemplatesFilename;
|
|
if not FileExistsUTF8(templateCfgName) then
|
|
Exit(False);
|
|
if InvalidXML(templateCfgName) then
|
|
// file is corrupted or not XML, so discard to prevent exception
|
|
DeleteFile(templateCfgName);
|
|
XMLConfig:=TXMLConfig.Create(templateCfgName);
|
|
try
|
|
s:=XMLConfig.GetValue('menu_1/Name/Value', 'missing_Menu_1_Name');
|
|
Result:=CompareText(s, 'missing_Menu_1_Name') <> 0;
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
end;
|
|
|
|
function GetSavedTemplatesCount: integer;
|
|
var
|
|
mt: TMenuTemplates;
|
|
begin
|
|
mt:=TMenuTemplates.CreateForMode(dmDelete);
|
|
try
|
|
Result:=mt.MenuCount;
|
|
finally
|
|
mt.Free;
|
|
end;
|
|
end;
|
|
{
|
|
procedure SaveMenuTemplateDlg(aMenuItem: TMenuItem);
|
|
var
|
|
dlg: TMenuTemplateDialog;
|
|
begin
|
|
dlg:=TMenuTemplateDialog.CreateWithMode(nil, dmSave);
|
|
try
|
|
dlg.MenuToSave:=aMenuItem;
|
|
dlg.ShowModal;
|
|
finally
|
|
dlg.Free;
|
|
end;
|
|
end;
|
|
}
|
|
function InsertMenuTemplateDlg(ParentMenuForInsert: TMenu): TMenuItem;
|
|
var
|
|
dlg: TMenuTemplateDialog;
|
|
begin
|
|
dlg:=TMenuTemplateDialog.CreateWithMode(ParentMenuForInsert, dmInsert);
|
|
try
|
|
if (dlg.ShowModal = mrOK) then
|
|
Result:=dlg.MenuToInsert
|
|
else
|
|
Result:=nil;
|
|
finally
|
|
dlg.Free;
|
|
end;
|
|
end;
|
|
|
|
function DeleteMenuTemplateDlg: boolean;
|
|
var
|
|
dlg: TMenuTemplateDialog;
|
|
mr: TModalResult;
|
|
begin
|
|
dlg:=TMenuTemplateDialog.CreateWithMode(nil, dmDelete);
|
|
try
|
|
mr:=dlg.ShowModal;
|
|
Result:=(mr = mrOK);
|
|
finally
|
|
dlg.Free;
|
|
end;
|
|
end;
|
|
|
|
function GetCfgPath: string;
|
|
begin
|
|
Result:=ExtractFilePath(ChompPathDelim(GetAppConfigDirUTF8(False)))+'lazarus';
|
|
end;
|
|
|
|
procedure InitMenuBaseSizes;
|
|
begin
|
|
MenuBar_Height := ScaleY(20, 96);
|
|
Separator_Height := ScaleY(7, 96);
|
|
Separator_Centre := ScaleY(3, 96);
|
|
DropDown_Height := ScaleY(24, 96);
|
|
MenuBar_Text_Offset := ScaleX(7, 96);
|
|
Double_MenuBar_Text_Offset := MenuBar_Text_Offset shl 1;
|
|
DropDown_Text_Offset := ScaleX(35, 96);
|
|
Double_DropDown_Text_Offset := DropDown_Text_Offset shl 1;
|
|
Gutter_Offset := ScaleX(6, 96);
|
|
Gutter_X := DropDown_Text_Offset - Gutter_Offset;
|
|
Add_Icon_Width := ScaleX(16, 96);
|
|
end;
|
|
|
|
{ TMenuTemplate }
|
|
|
|
function TMenuTemplate.GetShortcut(index: integer): TShortCut;
|
|
begin
|
|
Result:=TShortCut(PtrUInt(FSubList.Objects[index]));
|
|
end;
|
|
|
|
function TMenuTemplate.GetSubItem(index: integer): string;
|
|
begin
|
|
Result:=FSubList[index];
|
|
end;
|
|
|
|
function TMenuTemplate.GetSubItemCount: integer;
|
|
begin
|
|
Result:=FSubList.Count;
|
|
end;
|
|
|
|
class function TMenuTemplate.MenuItemToString(aMenuItem: TMenuItem;
|
|
aDescription: string): string;
|
|
var
|
|
sc: TShortCut;
|
|
scStr: string;
|
|
i: integer;
|
|
mi: TMenuItem;
|
|
begin
|
|
if (aMenuItem = nil) then
|
|
Exit('');
|
|
Result:=Format('%s,%s,',[aMenuItem.Caption, aDescription]);
|
|
for i:=0 to aMenuItem.Count-1 do
|
|
begin
|
|
mi:=aMenuItem.Items[i];
|
|
sc:=mi.ShortCut;
|
|
if (sc = 0) then
|
|
begin
|
|
if (mi.ShortCutKey2 = 0) then
|
|
scStr:=''
|
|
else
|
|
scStr:=ShortCutToText(mi.ShortCutKey2);
|
|
end
|
|
else
|
|
scStr:=ShortCutToText(sc);
|
|
AppendStr(Result, Format('%s,%s,',[mi.Caption, scStr]));
|
|
end;
|
|
end;
|
|
|
|
constructor TMenuTemplate.CreateFromString(const aMenuString: string);
|
|
begin
|
|
FSubList:=TStringList.Create;
|
|
if not ReadFromString(aMenuString) then
|
|
Assert(False,'TMenuTemplate.CreateFromString: Attempt to read invalid menu template');
|
|
end;
|
|
|
|
destructor TMenuTemplate.Destroy;
|
|
begin
|
|
FSubList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TMenuTemplate.ReadFromString(const aString: string): boolean;
|
|
var
|
|
sl: TStringList;
|
|
s: string;
|
|
i: integer;
|
|
begin
|
|
Result:=True;
|
|
sl:=TStringList.Create;
|
|
try
|
|
sl.StrictDelimiter:=True;
|
|
sl.CommaText:=aString;
|
|
case sl.Count of
|
|
0: Result:=False;
|
|
1: FPrimaryItem:=sl[0];
|
|
2: begin
|
|
FPrimaryItem:=sl[0];
|
|
FDescription:=sl[1];
|
|
end;
|
|
else begin
|
|
FPrimaryItem:=sl[0];
|
|
FDescription:=sl[1];
|
|
for i:=2 to sl.Count-1 do
|
|
begin
|
|
if not Odd(i) then
|
|
s:=sl[i]
|
|
else
|
|
FSubList.AddObject(s, TObject(PtrUInt(TextToShortCut(sl[i]))));
|
|
end;
|
|
end;
|
|
end; // case
|
|
finally
|
|
sl.Free;
|
|
end;
|
|
end;
|
|
|
|
{ TMenuTemplates }
|
|
|
|
function TMenuTemplates.GetDescription(index: integer): string;
|
|
begin
|
|
CheckIndex(index);
|
|
Result:=FTemplateList[index].Description;
|
|
end;
|
|
|
|
function TMenuTemplates.GetMenu(index: integer): TMenuItem;
|
|
var
|
|
mt: TMenuTemplate;
|
|
submi, mi: TMenuItem;
|
|
i: integer;
|
|
begin
|
|
CheckIndex(index);
|
|
mt:=FTemplateList[index];
|
|
mi:=TMenuItem.Create(nil);
|
|
mi.Caption:=mt.PrimaryItem;
|
|
for i:=0 to mt.SubItemCount-1 do
|
|
begin
|
|
submi:=TMenuItem.Create(nil);
|
|
submi.Caption:=mt.SubItem[i];
|
|
submi.ShortCut:=mt.Shortcut[i];
|
|
mi.Insert(i, submi);
|
|
end;
|
|
Result:=mi;
|
|
end;
|
|
|
|
function TMenuTemplates.GetMenuCount: integer;
|
|
begin
|
|
Result:=FTemplateList.Count;
|
|
end;
|
|
|
|
function TMenuTemplates.GetMenuTemplate(index: integer): TMenuTemplate;
|
|
begin
|
|
CheckIndex(index);
|
|
Result:=FTemplateList[index];
|
|
end;
|
|
|
|
function TMenuTemplates.GetPrimaryItem(index: integer): string;
|
|
begin
|
|
CheckIndex(index);
|
|
Result:=FTemplateList[index].PrimaryItem;
|
|
end;
|
|
|
|
procedure TMenuTemplates.CheckIndex(anIndex: integer);
|
|
begin
|
|
Assert((anIndex > -1) and (anIndex < FTemplateList.Count),
|
|
Format('TMenuTemplates.CheckIndex: index (%d) out of bounds[0-%d]',
|
|
[anIndex, Pred(FTemplateList.Count)]));
|
|
end;
|
|
|
|
procedure TMenuTemplates.LoadDefaultTemplates;
|
|
begin
|
|
AddTemplate(lisMenuEditorBasicEditMenuTemplate);
|
|
AddTemplate(lisMenuEditorBasicFileMenuTemplate);
|
|
AddTemplate(lisMenuEditorBasicWindowMenuTemplate);
|
|
AddTemplate(lisMenuEditorBasicHelpMenuTemplate);
|
|
end;
|
|
|
|
procedure TMenuTemplates.LoadSavedTemplates;
|
|
var
|
|
XMLConfig: TXMLConfig;
|
|
i, j: integer;
|
|
cfgPath, s, sc, sText, tmp: string;
|
|
begin
|
|
cfgPath:=GetCfgPath;
|
|
XMLConfig:=TXMLConfig.Create(cfgPath + DirectorySeparator + MenuTemplatesFilename);
|
|
try
|
|
i:=1;
|
|
s:=XMLConfig.GetValue(Format('menu_%d/Name/Value',[i]), 'missing Name');
|
|
while (s <> 'missing Name') do
|
|
begin
|
|
tmp:=XMLConfig.GetValue(Format('menu_%d/Description/Value',[i]),
|
|
'missing Description');
|
|
sText:=Format('%s,%s,',[s, tmp]);
|
|
s:=XMLConfig.GetValue(Format('menu_%d/SubItems/Value',[i]), '');
|
|
if (s = 'true') then
|
|
begin
|
|
j:=0;
|
|
s:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Name/Value',[i,j]), 'nonexistent subitem');
|
|
sc:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Shortcut/Value',[i,j]), 'nonexistent shortcut');
|
|
while (s <> 'nonexistent subitem') do
|
|
begin
|
|
if (CompareText(sc, 'nonexistent shortcut') = 0) then
|
|
sc := '';
|
|
AppendStr(sText, s + ',' + sc + ',');
|
|
Inc(j);
|
|
s:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Name/Value',[i,j]), 'nonexistent subitem');
|
|
sc:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Shortcut/Value',[i,j]), 'nonexistent shortcut');
|
|
end;
|
|
end;
|
|
Inc(i);
|
|
s:=XMLConfig.GetValue(Format('menu_%d/Name/Value',[i]), 'missing Name');
|
|
AddTemplate(sText, False);
|
|
end;
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
end;
|
|
|
|
constructor TMenuTemplates.CreateForMode(aDialogMode: TDialogMode);
|
|
begin
|
|
inherited Create;
|
|
FTemplateList:=TMenuTemplateList.Create;
|
|
if (aDialogMode = dmInsert) then
|
|
LoadDefaultTemplates;
|
|
LoadSavedTemplates;
|
|
end;
|
|
|
|
destructor TMenuTemplates.Destroy;
|
|
begin
|
|
FreeAndNil(FTemplateList);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TMenuTemplates.GetIndexOfTemplate(aMT: TMenuTemplate): integer;
|
|
begin
|
|
if (aMT = nil) then
|
|
Result:= -1
|
|
else
|
|
Result:=FTemplateList.IndexOf(aMT);
|
|
end;
|
|
|
|
procedure TMenuTemplates.AddTemplate(const aTemplateText: string;
|
|
isStandard: boolean);
|
|
var
|
|
mt: TMenuTemplate;
|
|
begin
|
|
if (aTemplateText = '') then
|
|
Exit;
|
|
mt:=TMenuTemplate.CreateFromString(aTemplateText);
|
|
mt.IsStandardTemplate:=isStandard;
|
|
FTemplateList.Add(mt);
|
|
end;
|
|
|
|
procedure TMenuTemplates.SaveTemplateToConfig(aMenuTemplate: TMenuTemplate);
|
|
var
|
|
XMLConfig: TXMLConfig;
|
|
i, j: integer;
|
|
cfgPath, s: string;
|
|
begin
|
|
cfgPath:=GetCfgPath;
|
|
XMLConfig:=TXMLConfig.Create(cfgPath + DirectorySeparator + MenuTemplatesFilename);
|
|
try
|
|
i:=1;
|
|
s:=XMLConfig.GetValue(Format('menu_%d/Name/Value',[i]), 'missing');
|
|
while not SameText(s, 'missing') do
|
|
begin
|
|
Inc(i);
|
|
s:=XMLConfig.GetValue(Format('menu_%d/Name/Value',[i]), 'missing');
|
|
end;
|
|
XMLConfig.SetValue(Format('menu_%d/Name/Value',[i]), aMenuTemplate.PrimaryItem);
|
|
XMLConfig.SetValue(format('menu_%d/Description/Value',[i]), aMenuTemplate.Description);
|
|
if (aMenuTemplate.SubItemCount > 0) then
|
|
XMLConfig.SetValue(Format('menu_%d/SubItems/Value', [i]), 'true');
|
|
for j:=0 to aMenuTemplate.SubItemCount-1 do
|
|
begin
|
|
XMLConfig.SetValue(Format('menu_%d/subitem_%d/Name/Value',[i,j]), aMenuTemplate.SubItem[j]);
|
|
XMLConfig.SetValue(Format('menu_%d/subitem_%d/Shortcut/Value',[i,j]), ShortCutToText(aMenuTemplate.Shortcut[j]));
|
|
end;
|
|
InvalidateFileStateCache;
|
|
XMLConfig.Flush;
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
end;
|
|
|
|
{ TPreview }
|
|
|
|
function TPreview.GetSize: TSize;
|
|
var
|
|
w, h: integer;
|
|
i, tmp: integer;
|
|
s: string;
|
|
begin
|
|
if (FTemplate = nil) then
|
|
begin
|
|
FillChar(Result{%H-}, SizeOf(Result), 0);
|
|
SetBounds(0,0,0,0);
|
|
end
|
|
else
|
|
case FDisplayAsPopup of
|
|
|
|
True: begin
|
|
w:=5;
|
|
h:=10;
|
|
for i:=0 to FTemplate.SubItemCount-1 do
|
|
begin
|
|
s:=FTemplate.SubItem[i];
|
|
if (s = '-') then
|
|
Inc(h, Separator_Height)
|
|
else begin
|
|
Inc(h, DropDown_Height);
|
|
tmp:=Canvas.TextWidth(s);
|
|
if (FTemplate.Shortcut[i] <> 0) then
|
|
Inc(tmp, Canvas.TextWidth(ShortCutToText(FTemplate.Shortcut[i])) + Double_MenuBar_Text_Offset);
|
|
if (tmp > w) then
|
|
w:=tmp;
|
|
end;
|
|
end;
|
|
Result.cx:=w + 2*Double_DropDown_Text_Offset + Canvas.TextWidth(FTemplate.PrimaryItem);
|
|
Result.cy:=h + 2;
|
|
end;
|
|
|
|
False: begin
|
|
w:=0;
|
|
h:=MenuBar_Height;
|
|
for i:=0 to FTemplate.SubItemCount-1 do
|
|
begin
|
|
s:=FTemplate.SubItem[i];
|
|
if (s = '-') then
|
|
Inc(h, Separator_Height)
|
|
else begin
|
|
Inc(h, DropDown_Height);
|
|
tmp:=Canvas.TextWidth(s);
|
|
if (FTemplate.Shortcut[i] <> 0) then
|
|
Inc(tmp, Canvas.TextWidth(ShortCutToText(FTemplate.Shortcut[i])) + Double_MenuBar_Text_Offset);
|
|
if (tmp > w) then
|
|
w:=tmp;
|
|
end;
|
|
end;
|
|
Result.cx:=w + Double_DropDown_Text_Offset;
|
|
Result.cy:=h + 2;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TPreview.SetDisplayAsPopup(AValue: boolean);
|
|
var
|
|
sz: TSize;
|
|
begin
|
|
if FDisplayAsPopup=AValue then Exit;
|
|
FDisplayAsPopup:=AValue;
|
|
SetBounds(0,0,0,0);
|
|
sz:=GetSize;
|
|
SetBounds(0, 0, sz.cx, sz.cy);
|
|
end;
|
|
|
|
procedure TPreview.Paint;
|
|
var
|
|
r, rBar, rDrop: TRect;
|
|
dets: TThemedElementDetails;
|
|
textFlags: integer = DT_VCENTER or DT_SINGLELINE or DT_EXPANDTABS;
|
|
i, t, h, w, l: integer;
|
|
txt: string;
|
|
separator: boolean;
|
|
szB: TSize;
|
|
begin
|
|
r:=ClientRect;
|
|
Canvas.FillRect(r);
|
|
Canvas.Frame(r);
|
|
InflateRect(r, -1, -1);
|
|
rBar:=r;
|
|
if FDisplayAsPopup then
|
|
begin
|
|
rBar.Top:=rBar.Top+5;
|
|
rBar.Left:=rBar.Left+5;
|
|
rBar.Bottom:=rBar.Top + DropDown_Height;
|
|
rBar.Right:=rBar.Left + DropDown_Text_Offset - Gutter_Offset;
|
|
dets:=ThemeServices.GetElementDetails(tmPopupGutter);
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rBar);
|
|
w:=Canvas.TextWidth(FTemplate.PrimaryItem);
|
|
rBar.Right:=rBar.Left + w + Double_DropDown_Text_Offset;
|
|
rBar.Left:=rBar.Left + DropDown_Text_Offset;
|
|
dets:=ThemeServices.GetElementDetails(tmPopupItemNormal);
|
|
ThemeServices.DrawText(Canvas, dets, FTemplate.PrimaryItem, rBar, textFlags, 0);
|
|
rBar.Left:=r.Left+5;
|
|
Canvas.Pen.Color:=clLtGray;
|
|
Canvas.Frame(rBar);
|
|
if (FTemplate.SubItemCount > 0) then
|
|
begin
|
|
rDrop:=rBar;
|
|
dets:=ThemeServices.GetElementDetails(tmPopupSubmenuNormal);
|
|
rDrop.Left:=rDrop.Right - DropDown_Text_Offset;
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rDrop);
|
|
end;
|
|
rDrop:=rBar;
|
|
szB:=Size(rBar);
|
|
OffsetRect(rDrop, szB.cx + 1, 2);
|
|
rDrop.Right:=r.Right-1;
|
|
rDrop.Bottom:=r.Bottom-1;
|
|
Canvas.Frame(rDrop);
|
|
l:=rDrop.Left+1;
|
|
w:=r.Right-2;
|
|
t:=rDrop.Top+1;
|
|
for i:=0 to Pred(FTemplate.SubItemCount) do
|
|
begin
|
|
txt:=FTemplate.SubItem[i];
|
|
separator:=(txt = '-');
|
|
if separator then
|
|
h:=Separator_Height
|
|
else
|
|
h:=DropDown_Height;
|
|
rDrop:=Rect(l, t, w, t+h);
|
|
Inc(t, h);
|
|
rBar:=rDrop;
|
|
rBar.Right:=rBar.Left + DropDown_Text_Offset - Gutter_Offset;
|
|
dets:=ThemeServices.GetElementDetails(tmPopupGutter);
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rBar);
|
|
if separator then
|
|
begin
|
|
dets:=ThemeServices.GetElementDetails(tmPopupSeparator);
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rDrop);
|
|
end
|
|
else
|
|
begin
|
|
rDrop.Left:=rDrop.Left + DropDown_Text_Offset;
|
|
dets:=ThemeServices.GetElementDetails(tmPopupItemNormal);
|
|
ThemeServices.DrawText(Canvas, dets, txt, rDrop, textFlags, 0);
|
|
if (FTemplate.Shortcut[i] <> 0) then
|
|
begin
|
|
txt:=ShortCutToText(FTemplate.Shortcut[i]);
|
|
rDrop.Left:=r.Right - Canvas.TextWidth(txt) - Double_MenuBar_Text_Offset;
|
|
ThemeServices.DrawText(Canvas, dets, txt, rDrop, textFlags, 0);
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
rBar.Bottom:=rBar.Top + MenuBar_Height;
|
|
dets:=ThemeServices.GetElementDetails(tmBarBackgroundActive);
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rBar);
|
|
rBar.Left:=rBar.Left + MenuBar_Text_Offset;
|
|
ThemeServices.DrawText(Canvas, dets, FTemplate.PrimaryItem, rBar, textFlags, 0);
|
|
t:=MenuBar_Height + 1;
|
|
for i:=0 to Pred(FTemplate.SubItemCount) do
|
|
begin
|
|
rBar:=r;
|
|
rBar.Top:=t;
|
|
txt:=FTemplate.SubItem[i];
|
|
separator:=(txt = '-');
|
|
if separator then
|
|
h:=Separator_Height
|
|
else
|
|
h:=DropDown_Height;
|
|
rBar.Bottom:=rBar.Top + h;
|
|
rBar.Right:=DropDown_Text_Offset - Gutter_Offset;
|
|
dets:=ThemeServices.GetElementDetails(tmPopupGutter);
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rBar);
|
|
rBar.Left:=rBar.Left + DropDown_Text_Offset;
|
|
rBar.Right:=r.Right;
|
|
if separator then
|
|
begin
|
|
dets:=ThemeServices.GetElementDetails(tmPopupSeparator);
|
|
ThemeServices.DrawElement(Canvas.Handle, dets, rBar);
|
|
end
|
|
else
|
|
begin
|
|
dets:=ThemeServices.GetElementDetails(tmPopupItemNormal);
|
|
ThemeServices.DrawText(Canvas, dets, txt, rBar, textFlags, 0);
|
|
if (FTemplate.Shortcut[i] <> 0) then
|
|
begin
|
|
txt:=ShortCutToText(FTemplate.Shortcut[i]);
|
|
rBar.Left:=r.Right - Canvas.TextWidth(txt) - Double_MenuBar_Text_Offset;
|
|
ThemeServices.DrawText(Canvas, dets, txt, rBar, textFlags, 0);
|
|
end;
|
|
end;
|
|
inc(t, h);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TPreview.SetParent(NewParent: TWinControl);
|
|
var
|
|
sz: TSize;
|
|
begin
|
|
inherited SetParent(NewParent);
|
|
if (NewParent <> nil) then
|
|
begin
|
|
sz:=GetSize;
|
|
SetBounds(0, 0, sz.cx, sz.cy);
|
|
Canvas.Pen.Color:=clLtGray;
|
|
Canvas.Brush.Color:=clBtnFace;
|
|
end;
|
|
end;
|
|
|
|
procedure TPreview.Clear;
|
|
var
|
|
sz: TSize;
|
|
begin
|
|
FTemplate:=nil;
|
|
sz:=GetSize;
|
|
SetBounds(0, 0, sz.cx, sz.cy);
|
|
end;
|
|
|
|
procedure TPreview.LoadTemplate(aMenuTemplate: tmenuTemplate);
|
|
var
|
|
sz: TSize;
|
|
begin
|
|
FTemplate:=aMenuTemplate;
|
|
sz:=GetSize;
|
|
SetBounds(0, 0, sz.cx, sz.cy);
|
|
end;
|
|
|
|
{ TMenuTemplateDialog }
|
|
|
|
constructor TMenuTemplateDialog.CreateWithMode(aMenu: TMenu; aDialogMode: TDialogMode);
|
|
begin
|
|
inherited CreateNew(Nil);
|
|
FMenu:=aMenu;
|
|
FDialogMode:=aDialogMode;
|
|
BorderStyle:=bsSizeable;
|
|
SetInitialBounds(0, 0, 530, 380);
|
|
Position:=poScreenCenter;
|
|
case aDialogMode of
|
|
dmSave: Caption:=lisMenuEditorSaveMenuAsTemplate;
|
|
dmInsert: Caption:=Format(lisMenuEditorInsertMenuTemplateIntoRootOfS, [FMenu.Name]);
|
|
dmDelete: Caption:=lisMenuEditorDeleteSavedMenuTemplate;
|
|
end;
|
|
FTemplates:=TMenuTemplates.CreateForMode(FDialogMode);
|
|
SetupGUI;
|
|
PopulateTreeView;
|
|
end;
|
|
|
|
destructor TMenuTemplateDialog.Destroy;
|
|
begin
|
|
FreeAndNil(FNewMenuTemplate);
|
|
FreeAndNil(FTemplates);
|
|
FreeAndNil(FPreview);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.BExecuteDeleteClick(Sender: TObject);
|
|
begin
|
|
DeleteSelectedFromConfigFile;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.BExecuteInsertClick(Sender: TObject);
|
|
var
|
|
mt: TMenuTemplate;
|
|
begin
|
|
Assert(FTVTemplates.Selected<>nil,'TMenuTemplateDialog.BExecuteInsertClick: FTVTemplates.Selected is nil');
|
|
mt:=TMenuTemplate(FTVTemplates.Selected.Data);
|
|
FMenuToInsert:=FTemplates.Menu[FTemplates.GetIndexOfTemplate(mt)];
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.BExecuteSaveClick(Sender: TObject);
|
|
var
|
|
trimmed: string;
|
|
begin
|
|
trimmed:=Trim(FEDescription.Text);
|
|
if (Length(trimmed) < 4) then
|
|
begin
|
|
IDEMessageDialogAb(lisMenuEditorInadequateDescription,
|
|
Format(lisMenuEditorSIsNotASufficientDescriptionPleaseExpand,[trimmed]),
|
|
mtWarning, [mbOK], False);
|
|
FEDescription.SelectAll;
|
|
FEDescription.SetFocus;
|
|
end
|
|
else
|
|
begin
|
|
FNewMenuTemplate.Description:=trimmed;
|
|
FTemplates.AddTemplate(TMenuTemplate.MenuItemToString(FMenuToSave, trimmed), False);
|
|
FEDescription.ReadOnly:=True;
|
|
SaveMenuAsTemplate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.CancelButtonClick(Sender: TObject);
|
|
begin
|
|
Close;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.CBDisplayChange(Sender: TObject);
|
|
begin
|
|
FPreview.DisplayAsPopup:=FCBDisplay.Checked;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.DeleteSelectedFromConfigFile;
|
|
var
|
|
XMLConfig: TXMLConfig;
|
|
|
|
procedure ExchangeConfigTemplates(aLower, aHigher: integer);
|
|
var
|
|
j: integer;
|
|
valueN, valueS: string;
|
|
begin
|
|
j:=1;
|
|
while not SameText(XMLConfig.GetValue(Format('menu_%d/subitem_%d/Name/Value',
|
|
[aLower, j]), 'nonexistent'), 'nonexistent') do
|
|
begin
|
|
XMLConfig.DeletePath(Format('menu_%d/subitem_%d',[aLower, j]));
|
|
Inc(j);
|
|
end;
|
|
|
|
j:=1;
|
|
valueN:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Name/Value',
|
|
[aHigher, j]), 'nonexistent');
|
|
while not SameText(valueN, 'nonexistent') do
|
|
begin
|
|
XMLConfig.SetValue(Format('menu_%d/subitem_%d/Name/Value',[aLower, j]), valueN);
|
|
valueS:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Shortcut/Value',
|
|
[aHigher, j]), 'nonexistent');
|
|
if not SameText(valueS, 'nonexistent') then
|
|
XMLConfig.SetValue(Format('menu_%d/subitem_%d/Shortcut/Value',[aLower, j]), valueS);
|
|
Inc(j);
|
|
valueN:=XMLConfig.GetValue(Format('menu_%d/subitem_%d/Name/Value',
|
|
[aHigher, j]), 'nonexistent');
|
|
end;
|
|
|
|
valueN:=XMLConfig.GetValue(Format('menu_%d/Name/Value',[aHigher]), 'nonexistent');
|
|
if not SameText(valueN, 'nonexistent') then
|
|
XMLConfig.SetValue(Format('menu_%d/Name/Value',[aLower]), valueN);
|
|
|
|
valueN:=XMLConfig.GetValue(Format('menu_%d/Description/Value',[aHigher]), 'nonexistent');
|
|
if not SameText(valueN, 'nonexistent') then
|
|
XMLConfig.SetValue(Format('menu_%d/Description/Value',[aLower]), valueN);
|
|
end;
|
|
|
|
var
|
|
highestOldIdx, i, idxToDelete: integer;
|
|
cfgPath, s, desc, currDesc: string;
|
|
begin
|
|
desc:=TMenuTemplate(FTVTemplates.Selected.Data).Description;
|
|
cfgPath:=GetCfgPath;
|
|
XMLConfig:=TXMLConfig.Create(cfgPath + DirectorySeparator + MenuTemplatesFilename);
|
|
try
|
|
i:=0;
|
|
idxToDelete:= -1;
|
|
repeat
|
|
Inc(i);
|
|
s:=XMLConfig.GetValue(Format('menu_%d/Name/Value',[i]), 'nonexistent');
|
|
currDesc:=XMLConfig.GetValue(Format('menu_%d/Description/Value',[i]), 'noDescription');
|
|
if (CompareText(desc, currDesc) = 0) then
|
|
idxToDelete:=i;
|
|
until CompareText(s, 'nonexistent') = 0;
|
|
highestOldIdx:=Pred(i);
|
|
Assert(idxToDelete>-1,'TMenuTemplateDialog.DeleteSelectedFromConfigFile: nonexistent template index');
|
|
if (idxToDelete < highestOldIdx) then
|
|
ExchangeConfigTemplates(idxToDelete, highestOldIdx);
|
|
XMLConfig.DeletePath(Format('menu_%d',[highestOldIdx]));
|
|
InvalidateFileStateCache;
|
|
XMLConfig.Flush;
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.DeleteSelectedTemplate;
|
|
begin
|
|
Assert(FTVTemplates.Selected<>nil,'TMenuTemplateDialog.DeleteSelectedTemplate: FTVTemplates.Selected is nil');
|
|
DeleteSelectedFromConfigFile;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.EDescriptionChange(Sender: TObject);
|
|
begin
|
|
if (Length(FEDescription.Text) > 3) and not FBExecute.Enabled then
|
|
FBExecute.Enabled:=True;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.PopulateTreeView;
|
|
var
|
|
mt: TMenuTemplate;
|
|
i: integer;
|
|
processed: string;
|
|
begin
|
|
for i:=0 to FTemplates.MenuCount-1 do
|
|
begin
|
|
mt:=FTemplates.MenuTemplate[i];
|
|
processed:=AmpersandStripped(mt.PrimaryItem);
|
|
if mt.IsStandardTemplate then
|
|
FTVTemplates.Items.AddChildObject(FStandardNode, processed, mt)
|
|
else begin
|
|
AppendStr(processed, Format(' [%s]',[mt.Description]));
|
|
FTVTemplates.Items.AddChildObject(FSavedNode, processed, mt);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.SaveMenuAsTemplate;
|
|
var
|
|
s: string;
|
|
begin
|
|
Assert(FMenuToSave<>nil,'TInsertTemplateDialog.SaveMenuAsTemplate: FMenuToSave is nil');
|
|
Assert(FNewMenuTemplate<>nil,'TInsertTemplateDialog.SaveMenuAsTemplate: FNewMenuTemplate is nil');
|
|
FTemplates.SaveTemplateToConfig(FNewMenuTemplate);
|
|
s:=AmpersandStripped(FNewMenuTemplate.PrimaryItem);
|
|
IDEMessageDialogAb(lisMenuEditorTemplateSaved, Format(
|
|
lisMenuEditorANewMenuTemplateHasBeenSaved,
|
|
[FNewMenuTemplate.Description, s, FNewMenuTemplate.SubItemCount]),
|
|
mtInformation, [mbOK], False);
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.SetupGUI;
|
|
begin
|
|
FPButtons:=TCustomPanel.Create(Self);
|
|
with FPButtons do begin
|
|
ControlStyle:=ControlStyle - [csSetCaption];
|
|
BevelInner:=bvNone;
|
|
BevelOuter:=bvNone;
|
|
BorderSpacing.Around:=Margin;
|
|
Align:=alBottom;
|
|
AutoSize:=True;
|
|
Parent:=Self;
|
|
end;
|
|
|
|
FBCancel:=TBitBtn.Create(Self);
|
|
with FBCancel do begin
|
|
Kind:=bkCancel;
|
|
AutoSize:=True;
|
|
BorderSpacing.Left:=2*Spacing;
|
|
Align:=alRight;
|
|
Left:=1;
|
|
OnClick:=@CancelButtonClick;
|
|
Parent:=FPButtons;
|
|
end;
|
|
|
|
FBExecute:=TBitBtn.Create(Self);
|
|
with FBExecute do begin
|
|
Kind:=bkOK;
|
|
case FDialogMode of
|
|
dmSave: begin
|
|
Caption:=lisMenuEditorSaveMenuShownAsANewTemplate;
|
|
OnClick:=@BExecuteSaveClick;
|
|
end;
|
|
dmInsert: begin
|
|
Caption:=lisMenuEditorInsertSelectedMenuTemplate;
|
|
OnClick:=@BExecuteInsertClick;
|
|
end;
|
|
dmDelete: begin
|
|
Caption:=lisMenuEditorDeleteSelectedMenuTemplate;
|
|
OnClick:=@BExecuteDeleteClick;
|
|
end;
|
|
end;
|
|
AutoSize:=True;
|
|
Align:=alRight;
|
|
Left:=0;
|
|
Enabled:=False;
|
|
Parent:=FPButtons;
|
|
end;
|
|
|
|
FGChoose:=TGroupBox.Create(Self);
|
|
with FGChoose do begin
|
|
Align:=alClient;
|
|
BorderSpacing.Around:=Margin;
|
|
Parent:=Self;
|
|
end;
|
|
|
|
FPDescription:=TPanel.Create(Self);
|
|
with FPDescription do begin
|
|
Align:=alTop;
|
|
BevelInner:=bvNone;
|
|
BevelOuter:=bvNone;
|
|
BorderSpacing.Bottom:=Margin;
|
|
BorderSpacing.Top:=Margin;
|
|
AutoSize:=True;
|
|
Parent:=FGChoose;
|
|
end;
|
|
|
|
FEDescription:=TEdit.Create(Self);
|
|
with FEDescription do begin
|
|
Align:=alClient;
|
|
BorderSpacing.Right:=Margin;
|
|
Parent:=FPDescription;
|
|
end;
|
|
|
|
FLDescription:=TLabel.Create(Self);
|
|
with FLDescription do begin
|
|
AutoSize:=True;
|
|
BorderSpacing.Around:=Margin;
|
|
Align:=alLeft;
|
|
Parent:=FPDescription;
|
|
end;
|
|
|
|
FTVTemplates:=TTreeView.Create(Self);
|
|
with FTVTemplates do begin
|
|
Align:=alLeft;
|
|
Width:=200;
|
|
Align:=alLeft;
|
|
Indent:=Margin;
|
|
Options:=[tvoAutoExpand, tvoAutoItemHeight, tvoKeepCollapsedNodes,
|
|
tvoShowRoot, tvoNoDoubleClickExpand];
|
|
BorderSpacing.Bottom:=Margin;
|
|
BorderSpacing.Left:=Margin;
|
|
OnAdvancedCustomDrawItem:=@TVAdvancedCustomDrawItem;
|
|
OnEditing:=@TVEditing;
|
|
Parent:=FGChoose;
|
|
end;
|
|
|
|
FSplitter:=TSplitter.Create(Self);
|
|
FSplitter.Left:=FTVTemplates.BoundsRect.Right;
|
|
FSplitter.Parent:=FGChoose;
|
|
|
|
FPRight:=TCustomPanel.Create(Self);
|
|
with FPRight do begin
|
|
Width:=200;
|
|
BevelInner:=bvNone;
|
|
BevelOuter:=bvNone;
|
|
BorderSpacing.Bottom:=Margin;
|
|
BorderSpacing.Right:=Margin;
|
|
Align:=alClient;
|
|
Parent:=FGChoose;
|
|
end;
|
|
|
|
FCBDisplay:=TCheckBox.Create(Self);
|
|
with FCBDisplay do begin
|
|
Align:=alTop;
|
|
Alignment:=taLeftJustify;
|
|
BorderSpacing.Bottom:=Margin;
|
|
BorderSpacing.Left:=Margin;
|
|
AutoSize:=True;
|
|
Caption:=lisMenuEditorDisplayPreviewAsPopupMenu;
|
|
OnChange:=@CBDisplayChange;
|
|
Parent:=FPRight;
|
|
end;
|
|
|
|
FScrollBoxPreview:=TScrollBox.Create(Self);
|
|
with FScrollBoxPreview do begin
|
|
Align:=alClient;
|
|
TabStop:=False;
|
|
Parent:=FPRight;
|
|
end;
|
|
FPreview:=TPreview.Create(Self);
|
|
FPreview.Parent:=FScrollBoxPreview;
|
|
|
|
case FDialogMode of
|
|
dmSave: begin
|
|
FSavedNode:=FTVTemplates.Items.AddFirst(nil, lisMenuEditorExistingSavedTemplates);
|
|
FGChoose.Caption:=lisMenuEditorSaveMenuAsTemplateForFutureUse;
|
|
FLDescription.Caption:=lisMenuEditorEnterAMenuDescription;
|
|
FLDescription.FocusControl:=FEDescription;
|
|
end;
|
|
dmInsert: begin
|
|
FStandardNode:=FTVTemplates.Items.AddFirst(nil, lisMenuEditorStandardTemplates);
|
|
FSavedNode:=FTVTemplates.Items.Add(FStandardNode, lisMenuEditorSavedTemplates);
|
|
FGChoose.Caption:=lisMenuEditorChooseTemplateToInsert;
|
|
FLDescription.Caption:=lisMenuEditorTemplateDescription;
|
|
FTVTemplates.OnSelectionChanged:=@TVSelectionChanged;
|
|
FEDescription.ReadOnly:=True;
|
|
end;
|
|
dmDelete: begin
|
|
FStandardNode:=nil;
|
|
FSavedNode:=FTVTemplates.Items.AddFirst(nil, lisMenuEditorExistingSavedTemplates);
|
|
FGChoose.Caption:=lisMenuEditorChooseTemplateToDelete;
|
|
FLDescription.Caption:=lisMenuEditorTemplateDescription;
|
|
FTVTemplates.OnSelectionChanged:=@TVSelectionChanged;
|
|
FEDescription.ReadOnly:=True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.ShowPreview(aMenuTemplate: TMenuTemplate);
|
|
begin
|
|
FPreview.Clear;
|
|
if (aMenuTemplate <> nil) then
|
|
FPreview.LoadTemplate(aMenuTemplate);
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.TVAdvancedCustomDrawItem(Sender: TCustomTreeView;
|
|
Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;
|
|
var PaintImages, DefaultDraw: Boolean);
|
|
var
|
|
nodeR, textR: TRect;
|
|
begin
|
|
DefaultDraw:=(Stage <> cdPrePaint);
|
|
if DefaultDraw then Exit;
|
|
|
|
nodeR:=Node.DisplayRect(False);
|
|
textR:=Node.DisplayRect(True);
|
|
if (Node.Level = 0) then begin
|
|
Sender.Canvas.Font.Color:=clGray;
|
|
Sender.Canvas.Font.Style:=[fsBold];
|
|
end
|
|
else begin
|
|
Sender.Canvas.Font.Color:=clBlack;
|
|
Sender.Canvas.Font.Style:=[];
|
|
end;
|
|
if (cdsSelected in State) and (Node.Level > 0) then
|
|
Sender.Canvas.Brush.Color:=Sender.SelectionColor
|
|
else Sender.Canvas.Brush.Color:=Sender.Color;
|
|
Sender.Canvas.FillRect(nodeR);
|
|
Sender.Canvas.TextOut(textR.Left, textR.Top, Node.Text);
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.TVEditing(Sender: TObject; Node: TTreeNode;
|
|
var AllowEdit: Boolean);
|
|
begin
|
|
AllowEdit:=False;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.TVSelectionChanged(Sender: TObject);
|
|
var
|
|
tv: TTreeView absolute Sender;
|
|
node: TTreeNode;
|
|
mt: TMenuTemplate;
|
|
begin
|
|
if not (Sender is TTreeView) then
|
|
Exit;
|
|
|
|
node:=tv.Selected;
|
|
if (node = nil) or (node = FStandardNode) or (node = FSavedNode) or
|
|
(node = FNoneSavedNode) or (node.Data = nil) then
|
|
begin
|
|
FBExecute.Enabled:=False;
|
|
FEDescription.Text:='';
|
|
ShowPreview(nil);
|
|
end
|
|
else begin
|
|
Assert(node.Data<>nil,'TMenuTemplateDialog.TVSelectionChanged: node.Data is nil');
|
|
mt:=TMenuTemplate(node.Data);
|
|
FEDescription.Text:=mt.Description;
|
|
ShowPreview(mt);
|
|
if FDialogMode in [dmInsert, dmDelete] then
|
|
FBExecute.Enabled:=True;
|
|
end;
|
|
end;
|
|
|
|
procedure TMenuTemplateDialog.DoShowWindow;
|
|
var
|
|
menuString: string;
|
|
noneSaved: boolean;
|
|
begin
|
|
inherited DoShowWindow;
|
|
noneSaved:=not SavedTemplatesExist;
|
|
case FDialogMode of
|
|
|
|
dmSave: begin
|
|
menuString:=TMenuTemplate.MenuItemToString(FMenuToSave, '');
|
|
FNewMenuTemplate:=TMenuTemplate.CreateFromString(menuString);
|
|
FPreview.LoadTemplate(FNewMenuTemplate);
|
|
if noneSaved then
|
|
FNoneSavedNode:=FTVTemplates.Items.AddChild(FSavedNode,lisMenuEditorNone);
|
|
FEDescription.SetFocus;
|
|
FEDescription.OnChange:=@EDescriptionChange;
|
|
end;
|
|
|
|
dmInsert: begin
|
|
if noneSaved then
|
|
FNoneSavedNode:=FTVTemplates.Items.AddChild(FSavedNode,lisMenuEditorNone);
|
|
TVSelectionChanged(FTVTemplates);
|
|
FTVTemplates.Selected:=FTVTemplates.Items[1];
|
|
FTVTemplates.SetFocus;
|
|
end;
|
|
|
|
dmDelete: begin
|
|
if noneSaved then begin
|
|
IDEMessageDialogAb(lisMenuEditorNoUserSavedTemplates, lisMenuEditorThereAreNoUserSavedMenuTemplates,
|
|
mtInformation, [mbOK], False);
|
|
ModalResult:=mrCancel;
|
|
end
|
|
else begin
|
|
TVSelectionChanged(FTVTemplates);
|
|
FTVTemplates.Selected:=FTVTemplates.Items[1];
|
|
FTVTemplates.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|