lazarus/components/editortoolbar/editortoolbar_impl.pas
2014-12-03 17:56:53 +00:00

607 lines
14 KiB
ObjectPascal

{
Copyright (C) 2007 Graeme Geldenhuys (graemeg@gmail.com)
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
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. See the GNU Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
}
unit editortoolbar_impl;
{$mode objfpc}{$H+}
interface
uses
Classes
,jumpto_impl
,Forms
,ComCtrls
,Controls
,ExtCtrls
,Menus
,MenuIntf
,IDEImagesIntf
,SrcEditorIntf
,editortoolbar_str
,IDECommands;
const
cSettingsFile = 'editortoolbar.xml';
cDivider = '---------------';
iAll = 15;
iDesign = 1;
iDebug = 2;
iHTML = 4;
iCustom = 8;
type
{ TEditorToolbar }
TEditorToolbar = class(TComponent)
private
FJumpHandler: TJumpHandler;
FWindow: TSourceEditorWindowInterface;
TB: TToolbar;
PM: TPopupMenu;
PPUP: TPopupMenu;
CfgButton: TToolButton;
FButtonList: TList;
UpdateTimer: TTimer;
procedure CreateEditorToolbar(AW: TForm; var ATB: TToolbar);
function CreateJumpItem(AJumpType: TJumpType; O: TComponent): TMenuItem;
function CreateProfileItem(ProfIndx: Integer; O: TComponent): TMenuItem;
procedure DoConfigureToolbar(Sender: TObject);
procedure UpdateBar(Sender: TObject);
protected
procedure MenuItemClick (Sender: TObject);
procedure AddButton(AMenuItem: TIDEMenuItem);
procedure PositionAtEnd(AToolbar: TToolbar; AButton: TToolButton);
procedure Reload;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure InitEditorToolBar;
procedure AddCustomItems;
procedure AddDivider;
procedure AddStaticItems;
procedure ClearToolbar;
property OwnerWindow: TSourceEditorWindowInterface read FWindow;
end;
{ TEditorToolbarList }
TEditorToolbarList = class
private
FToolBarList: TFPList;
protected
procedure SourceWindowCreated(Sender: TObject);
procedure SourceWindowDestroyed(Sender: TObject);
procedure AddBar(ABar: TEditorToolbar);
procedure DelBar(ABar: TEditorToolbar);
procedure ReloadAll;
public
constructor Create;
destructor Destroy; override;
end;
function GetShortcut(AMenuItem: TIDEMenuItem): string;
function GetProfileIndex (aMask: Integer): Integer;
procedure Register;
var
sToolbarPos: string;
bToolBarShow: boolean;
EditorMenuCommand:TIDEMenuCommand;
ProfileMask: array [0..4] of Integer = (iAll,iDesign,iDebug,iHTML,iCustom);
sLocalizedProfileNames: array[0..4] of string;
implementation
{$R toolbar.res} // all required images
uses
Dialogs
,SysUtils
,LResources
,EdtTbConfigFrm
,LazConfigStorage
,BaseIDEIntf
,LCLProc;
type
{ TEditToolBarToolButton }
TEditToolBarToolButton = class(TToolButton)
private
FMenuItem: TIDEMenuItem;
public
procedure Click; override;
property IdeMenuItem: TIDEMenuItem read FMenuItem write FMenuItem;
end;
var
uEditorToolbarList: TEditorToolbarList;
procedure ConfigureToolbar (Sender:TObject);
begin
if TEdtTbConfigForm.Execute then
uEditorToolbarList.ReloadAll;
end;
procedure ToggleToolbar (Sender:TObject);
var
ToolBarVisible: Boolean;
begin
ToolBarVisible:= not bToolBarShow;
EditorMenuCommand.Checked:= ToolBarVisible;
bToolBarShow:= ToolBarVisible;
TEdtTbConfigForm.UpdateVisible(ToolBarVisible);
uEditorToolbarList.ReloadAll;
end;
procedure TEditToolBarToolButton.Click;
begin
inherited Click;
if assigned(FMenuItem) then
FMenuItem.TriggerClick;
end;
{ TEditorToolbarList }
procedure TEditorToolbarList.SourceWindowCreated(Sender: TObject);
begin
TEditorToolbar.Create(Sender as TSourceEditorWindowInterface);
end;
procedure TEditorToolbarList.SourceWindowDestroyed(Sender: TObject);
var
i: integer;
aBar: TEditorToolbar;
begin
// Let's remove from our list the destroyed window and then destroy the ToolBar
for i:= 0 to FToolBarList.Count -1 do begin
aBar := TEditorToolbar(FToolBarList[i]);
if aBar.OwnerWindow = TSourceEditorWindowInterface(Sender) then begin
DelBar(aBar);
aBar.Free;
exit;
end;
end;
end;
procedure TEditorToolbarList.AddBar(ABar: TEditorToolbar);
begin
FToolBarList.Add(ABar);
end;
procedure TEditorToolbarList.DelBar(ABar: TEditorToolbar);
begin
FToolBarList.Remove(ABar);
end;
procedure TEditorToolbarList.ReloadAll;
var
i: Integer;
begin
for i := 0 to FToolBarList.Count - 1 do
TEditorToolbar(FToolBarList[i]).Reload
end;
constructor TEditorToolbarList.Create;
begin
inherited;
uEditorToolbarList := self;
FToolBarList := TFPList.Create;
if SourceEditorManagerIntf <> nil then begin
SourceEditorManagerIntf.RegisterChangeEvent(semWindowCreate, @SourceWindowCreated);
SourceEditorManagerIntf.RegisterChangeEvent(semWindowDestroy,@SourceWindowDestroyed);
end;
end;
destructor TEditorToolbarList.Destroy;
begin
while FToolBarList.Count > 0 do
TEditorToolbar(FToolBarList[0]).Free;
FreeAndNil(FToolBarList);
inherited Destroy;
end;
{ TEditorToolbar }
procedure TEditorToolbar.CreateEditorToolbar(AW: TForm; var ATB: TToolbar);
begin
{ It must be created with Align = alTop, so that the first positioning
of buttons is correct. }
ATB := TToolbar.Create(AW);
ATB.Parent := AW;
ATB.Height := 26;
ATB.Align := alTop;
ATB.Flat := True;
ATB.Images := IDEImages.Images_16;
ATB.ShowHint := True;
ATB.Hint := rsHint;
ATB.PopupMenu := PPUP;
end;
function TEditorToolbar.CreateJumpItem(AJumpType: TJumpType; O: TComponent): TMenuItem;
begin
Result := TMenuItem.Create(O);
Result.Tag := Ord(AJumpType);
Result.OnClick := @FJumpHandler.DoJump;
Result.Caption := cJumpNames[AJumpType];
end;
function TEditorToolbar.CreateProfileItem(ProfIndx: Integer; O: TComponent
): TMenuItem;
begin
Result := TMenuItem.Create(O);
Result.Tag := ProfIndx;
Result.Caption := sLocalizedProfileNames[ProfIndx];
Result.GroupIndex := 1;
Result.RadioItem := True;
//Result.AutoCheck := True;
Result.OnClick := @MenuItemClick;
end;
procedure TEditorToolbar.DoConfigureToolbar(Sender: TObject);
begin
if TEdtTbConfigForm.Execute then
uEditorToolbarList.ReloadAll;
end;
procedure TEditorToolbar.UpdateBar(Sender: TObject);
var
i,j: integer;
mi: TIDEMenuItem;
begin
TB.BeginUpdate;
try
for i := TB.ButtonCount - 1 downto 0 do begin
if TB.Buttons[I].tag <> 0 then begin
j := TB.Buttons[I].tag-1;
mi := TIDEMenuItem(FButtonList.Items[j]);
if mi <> nil then begin
TB.Buttons[I].Enabled := mi.Enabled;
end;
end;
end;
finally
TB.EndUpdate;
end;
end;
procedure TEditorToolbar.MenuItemClick(Sender: TObject);
var
cfg: TConfigStorage;
Value: Integer;
begin
if (Sender <> nil ) and (Sender is TMenuItem) then begin
TMenuItem(Sender).Checked:= True;
Value:= TMenuItem(Sender).Tag;
CurrProfile := ProfileMask[Value];
cfg := GetIDEConfigStorage(cSettingsFile,True);
try
cfg.SetDeleteValue('Profile',CurrProfile,iAll);
cfg.WriteToDisk;
finally
cfg.Free;
end;
Reload;
end;
end;
constructor TEditorToolbar.Create(AOwner: TComponent);
var
T: TJumpType;
c: integer;
cfg: TConfigStorage;
begin
uEditorToolbarList.AddBar(Self);
if assigned(TB) then exit;
FButtonList := TList.Create;
sLocalizedProfileNames[0] := rsAll;
sLocalizedProfileNames[1] := rsDesign;
sLocalizedProfileNames[2] := rsDebug;
sLocalizedProfileNames[3] := rsHTML;
sLocalizedProfileNames[4] := rsCustom;
FJumpHandler := TJumpHandler.Create(nil);
FWindow := TSourceEditorWindowInterface(AOwner);
PPUP := TPopupMenu.Create(FWindow);
for c := 0 to High(sLocalizedProfileNames) do begin
PPUP.Items.Add(CreateProfileItem(c,FWindow));
end;
CreateEditorToolBar(FWindow, TB);
PM := TPopupMenu.Create(FWindow);
for T := Low(TJumpType) to High(TJumpType) do
PM.Items.Add(CreateJumpItem(T, FWindow));
AddStaticItems;
// Let's verify if it's a first start
c:= 0; // Just in case...
cfg := GetIDEConfigStorage(cSettingsFile, True);
try
c := cfg.GetValue('Count', 0);
finally
cfg.Free;
end;
if c = 0 then
TEdtTbConfigForm.Setup;
AddCustomItems;
UpdateTimer := TTimer.Create(Self);
UpdateTimer.Interval := 500;
UpdateTimer.OnTimer := @UpdateBar;
UpdateTimer.Enabled := True;
end;
destructor TEditorToolbar.Destroy;
begin
uEditorToolbarList.DelBar(Self);
FJumpHandler.Free;
FButtonList.Free;
inherited Destroy;
end;
procedure TEditorToolbar.InitEditorToolBar;
begin
TB := nil;
CfgButton := nil;
end;
procedure TEditorToolbar.AddButton(AMenuItem: TIDEMenuItem);
var
B: TEditToolBarToolButton;
ACaption: string;
iPos: Integer;
begin
B := TEditToolBarToolButton.Create(TB);
ACaption := AMenuItem.Caption;
DeleteAmpersands(ACaption);
B.Caption := ACaption;
// Get Shortcut, if any, and append to Hint
ACaption:= ACaption + GetShortcut(AMenuItem);
B.Hint := ACaption;
// If we have a image, us it. Otherwise supply a default.
if AMenuItem.ImageIndex <> -1 then
B.ImageIndex := AMenuItem.ImageIndex
else
B.ImageIndex := IDEImages.LoadImage(16, 'execute16');
B.Style := tbsButton;
B.IdeMenuItem := AMenuItem;
iPos := FButtonList.Add(AMenuItem);
B.Tag:= iPos+1;
//B.OnClick := AMenuItem.OnClick;
PositionAtEnd(TB, B);
end;
// position the button next to the last button
procedure TEditorToolbar.PositionAtEnd(AToolbar: TToolbar; AButton: TToolButton);
var
SiblingButton: TToolButton;
begin
if AToolbar.ButtonCount > 0 then
begin
SiblingButton := AToolbar.Buttons[AToolbar.ButtonCount-1];
AButton.SetBounds(SiblingButton.Left + SiblingButton.Width,
SiblingButton.Top, AButton.Width, AButton.Height);
end;
AButton.Parent := AToolbar;
end;
procedure TEditorToolbar.Reload;
begin
ClearToolbar;
AddStaticItems;
AddCustomItems;
end;
procedure TEditorToolbar.AddCustomItems;
var
i: integer;
c: integer;
cfg: TConfigStorage;
value: string;
profile: Integer;
mi: TIDEMenuItem;
ShowItem: Boolean;
procedure SetTbPos;
begin
case sToolbarPos of
'Top': begin
TB.Align:= alTop;
TB.Height:= 26;
end;
'Bottom': begin
TB.Align:= alBottom;
TB.Height:= 26;
end;
'Left': begin
TB.Align:= alLeft;
TB.Width:= 26;
end;
'Right': begin
TB.Align:= alRight;
TB.Width:= 26;
end;
end;
end;
begin
cfg := GetIDEConfigStorage(cSettingsFile, True);
TB.BeginUpdate;
try
c:= cfg.GetValue('Profile',iAll);
CurrProfile := c;
c := GetProfileIndex(CurrProfile);
PPUP.Items[c].Checked:= True;
c := cfg.GetValue('Count', 0);
for i := 1 to c do
begin
value := cfg.GetValue('Button' + Format('%2.2d', [i]) + '/Value', '');
profile := cfg.GetValue('Button' + Format('%2.2d', [i]) + '/Profile', iall);
ShowItem := (CurrProfile = iAll) or ((profile and CurrProfile) <> 0);
if (value <> '') and ShowItem then
begin
if value = cDivider then
AddDivider
else
begin
mi := IDEMenuRoots.FindByPath(value,false);
if Assigned(mi) then
AddButton(mi);
end;
end;
end;
sToolbarPos := cfg.GetValue('Position','Top');
bToolBarShow:= cfg.GetValue('Visible',true);
EditorMenuCommand.Checked:= bToolBarShow;
SetTbPos;
finally
cfg.Free;
TB.EndUpdate;
end;
TB.Visible:= bToolBarShow;
end;
procedure TEditorToolbar.AddDivider;
var
B: TToolButton;
begin
B := TToolbutton.Create(TB);
B.Style := tbsDivider;
PositionAtEnd(TB, B);
end;
procedure TEditorToolbar.AddStaticItems;
var
B: TToolButton;
begin
TB.BeginUpdate;
try
// Config Button
if CfgButton = nil then
CfgButton := TToolbutton.Create(TB);
CfgButton.Caption := rsConfigureToo;
CfgButton.Hint := CfgButton.Caption;
CfgButton.ImageIndex := IDEImages.LoadImage(16, 'preferences16');
CfgButton.Style := tbsButton;
CfgButton.OnClick := @DoConfigureToolbar;
PositionAtEnd(TB, CfgButton);
AddDivider;
// JumpTo Button
B := TToolbutton.Create(TB);
B.Caption := rsJumpTo;
B.Hint := B.Caption;
B.ImageIndex := IDEImages.LoadImage(16, 'jumpto16');
B.Style := tbsDropDown;
B.OnClick := @FJumpHandler.DoJumpToImplementation;
B.DropdownMenu := PM;
PositionAtEnd(TB, B);
if TB.ButtonCount <> 0 then
AddDivider;
finally
TB.EndUpdate;
end;
end;
procedure TEditorToolbar.ClearToolbar;
var
i: integer;
begin
TB.BeginUpdate;
try
for i := TB.ButtonCount - 1 downto 0 do
if TB.Buttons[i] <> CfgButton then
TB.Buttons[i].Free
else
TB.Buttons[i].Parent := nil;
finally
TB.EndUpdate;
end;
end;
function GetShortcut(AMenuItem: TIDEMenuItem): string;
var
ACommand: TIDECommand;
AShortcut: string;
begin
Result := '';
AShortcut:= '';
if AMenuItem is TIDEMenuCommand then begin
ACommand := TIDEMenuCommand(AMenuItem).Command;
if Assigned(ACommand) then AShortcut:= ShortCutToText(ACommand.AsShortCut);
if AShortcut <> '' then Result:= ' (' + AShortcut +')';
end;
end;
function GetProfileIndex(aMask: Integer): Integer;
var
I: Integer;
begin
for I:= 0 to High(ProfileMask) do begin
if aMask = ProfileMask[I] then begin
Result := I;
Exit;
end;
end;
Result := 0;
end;
procedure Register;
var
MenuIcon: string;
begin
if uEditorToolbarList = nil then begin
TEditorToolbarList.Create;
EditorMenuCommand:= RegisterIDEMenuCommand(itmViewSecondaryWindows,'EditorToolBar',
rsEditorToolbar,nil,@ToggleToolbar);
EditorMenuCommand.Checked:= True;
EditorMenuCommand.Enabled:= True;
MenuIcon:= 'menu_editor_options';
//MenuIcon:= 'menu_editor_toolbar'; TODO!
EditorMenuCommand.ImageIndex := IDEImages.LoadImage(16, MenuIcon);
end;
end;
initialization
uEditorToolbarList := nil;
sToolbarPos:= 'Top';
bToolBarShow:= True;
CurrProfile:= iAll;
finalization
uEditorToolbarList.Free;
end.