PageRenderTime 17ms CodeModel.GetById 1ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/components/editortoolbar/editortoolbar_impl.pas

http://github.com/graemeg/lazarus
Pascal | 606 lines | 496 code | 74 blank | 36 comment | 32 complexity | da5b53e5057108d17f5f1ef98b6b41d5 MD5 | raw file
  1{
  2  Copyright (C) 2007 Graeme Geldenhuys (graemeg@gmail.com)
  3
  4  This library is free software; you can redistribute it and/or modify it
  5  under the terms of the GNU Library General Public License as published by
  6  the Free Software Foundation; either version 2 of the License, or (at your
  7  option) any later version.
  8
  9  This program is distributed in the hope that it will be useful, but WITHOUT
 10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
 12  for more details.
 13
 14  You should have received a copy of the GNU Library General Public License
 15  along with this library; if not, write to the Free Software Foundation,
 16  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 17}
 18
 19unit editortoolbar_impl;
 20
 21{$mode objfpc}{$H+}
 22
 23interface
 24
 25uses
 26  Classes
 27  ,jumpto_impl
 28  ,Forms
 29  ,ComCtrls
 30  ,Controls
 31  ,ExtCtrls
 32  ,Menus
 33  ,MenuIntf
 34  ,IDEImagesIntf
 35  ,SrcEditorIntf
 36  ,editortoolbar_str
 37  ,IDECommands;
 38
 39
 40const
 41  cSettingsFile = 'editortoolbar.xml';
 42  cDivider      = '---------------';
 43  iAll          = 15;
 44  iDesign       = 1;
 45  iDebug        = 2;
 46  iHTML         = 4;
 47  iCustom       = 8;
 48
 49type
 50
 51  { TEditorToolbar }
 52
 53  TEditorToolbar = class(TComponent)
 54  private
 55    FJumpHandler: TJumpHandler;
 56    FWindow: TSourceEditorWindowInterface;
 57    TB: TToolbar;
 58    PM: TPopupMenu;
 59    PPUP: TPopupMenu;
 60    CfgButton: TToolButton;
 61    FButtonList: TList;
 62    UpdateTimer: TTimer;
 63    procedure   CreateEditorToolbar(AW: TForm; var ATB: TToolbar);
 64    function    CreateJumpItem(AJumpType: TJumpType; O: TComponent): TMenuItem;
 65    function    CreateProfileItem(ProfIndx: Integer; O: TComponent): TMenuItem;
 66    procedure   DoConfigureToolbar(Sender: TObject);
 67    procedure   UpdateBar(Sender: TObject);
 68  protected
 69    procedure   MenuItemClick (Sender: TObject);
 70    procedure   AddButton(AMenuItem: TIDEMenuItem);
 71    procedure   PositionAtEnd(AToolbar: TToolbar; AButton: TToolButton);
 72    procedure   Reload;
 73  public
 74    constructor Create(AOwner: TComponent); override;
 75    destructor  Destroy; override;
 76    procedure   InitEditorToolBar;
 77    procedure   AddCustomItems;
 78    procedure   AddDivider;
 79    procedure   AddStaticItems;
 80    procedure   ClearToolbar;
 81    property    OwnerWindow: TSourceEditorWindowInterface read FWindow;
 82  end;
 83  
 84
 85  { TEditorToolbarList }
 86
 87  TEditorToolbarList = class
 88  private
 89    FToolBarList: TFPList;
 90  protected
 91    procedure SourceWindowCreated(Sender: TObject);
 92    procedure SourceWindowDestroyed(Sender: TObject);
 93    procedure AddBar(ABar: TEditorToolbar);
 94    procedure DelBar(ABar: TEditorToolbar);
 95    procedure ReloadAll;
 96  public
 97    constructor Create;
 98    destructor Destroy; override;
 99  end;
100
101function GetShortcut(AMenuItem: TIDEMenuItem): string;
102function GetProfileIndex (aMask: Integer): Integer;
103
104procedure Register;
105
106var
107  sToolbarPos: string;
108  bToolBarShow: boolean;
109  EditorMenuCommand:TIDEMenuCommand;
110  ProfileMask: array [0..4] of Integer = (iAll,iDesign,iDebug,iHTML,iCustom);
111  sLocalizedProfileNames: array[0..4] of string;
112
113implementation
114
115{$R toolbar.res}    // all required images
116
117uses
118  Dialogs
119  ,SysUtils
120  ,LResources
121  ,EdtTbConfigFrm
122  ,LazConfigStorage
123  ,BaseIDEIntf
124  ,LCLProc;
125
126type
127
128  { TEditToolBarToolButton }
129
130  TEditToolBarToolButton = class(TToolButton)
131  private
132    FMenuItem: TIDEMenuItem;
133  public
134    procedure Click; override;
135    property IdeMenuItem: TIDEMenuItem read FMenuItem write FMenuItem;
136  end;
137
138var
139  uEditorToolbarList: TEditorToolbarList;
140
141procedure ConfigureToolbar (Sender:TObject);
142begin
143  if TEdtTbConfigForm.Execute then
144    uEditorToolbarList.ReloadAll;
145end;
146
147procedure ToggleToolbar (Sender:TObject);
148var
149  ToolBarVisible: Boolean;
150begin
151  ToolBarVisible:= not bToolBarShow;
152  EditorMenuCommand.Checked:= ToolBarVisible;
153  bToolBarShow:= ToolBarVisible;
154  TEdtTbConfigForm.UpdateVisible(ToolBarVisible);
155  uEditorToolbarList.ReloadAll;
156end;
157
158procedure TEditToolBarToolButton.Click;
159begin
160  inherited Click;
161  if assigned(FMenuItem) then
162    FMenuItem.TriggerClick;
163end;
164
165{ TEditorToolbarList }
166
167procedure TEditorToolbarList.SourceWindowCreated(Sender: TObject);
168begin
169  TEditorToolbar.Create(Sender as TSourceEditorWindowInterface);
170end;
171
172procedure TEditorToolbarList.SourceWindowDestroyed(Sender: TObject);
173var
174  i: integer;
175  aBar: TEditorToolbar;
176begin
177  // Let's remove from our list the destroyed window and then destroy the ToolBar
178  for i:= 0 to FToolBarList.Count -1 do begin
179    aBar := TEditorToolbar(FToolBarList[i]);
180    if aBar.OwnerWindow = TSourceEditorWindowInterface(Sender) then begin
181      DelBar(aBar);
182      aBar.Free;
183      exit;
184    end;
185  end;
186end;
187
188procedure TEditorToolbarList.AddBar(ABar: TEditorToolbar);
189begin
190  FToolBarList.Add(ABar);
191end;
192
193procedure TEditorToolbarList.DelBar(ABar: TEditorToolbar);
194begin
195  FToolBarList.Remove(ABar);
196end;
197
198procedure TEditorToolbarList.ReloadAll;
199var
200  i: Integer;
201begin
202  for i := 0 to FToolBarList.Count - 1 do
203    TEditorToolbar(FToolBarList[i]).Reload
204end;
205
206constructor TEditorToolbarList.Create;
207begin
208  inherited;
209  uEditorToolbarList := self;
210  FToolBarList := TFPList.Create;
211
212  if SourceEditorManagerIntf <> nil then begin
213    SourceEditorManagerIntf.RegisterChangeEvent(semWindowCreate, @SourceWindowCreated);
214    SourceEditorManagerIntf.RegisterChangeEvent(semWindowDestroy,@SourceWindowDestroyed);
215  end;
216
217end;
218
219destructor TEditorToolbarList.Destroy;
220begin
221  while FToolBarList.Count > 0 do
222    TEditorToolbar(FToolBarList[0]).Free;
223  FreeAndNil(FToolBarList);
224  inherited Destroy;
225end;
226
227{ TEditorToolbar }
228
229procedure TEditorToolbar.CreateEditorToolbar(AW: TForm; var ATB: TToolbar);
230begin
231  { It must be created with Align = alTop, so that the first positioning
232  of buttons is correct. }
233  ATB := TToolbar.Create(AW);
234  ATB.Parent   := AW;
235  ATB.Height   := 26;
236  ATB.Align    := alTop;
237  ATB.Flat     := True;
238  ATB.Images   := IDEImages.Images_16;
239  ATB.ShowHint := True;
240  ATB.Hint     := rsHint;
241  ATB.PopupMenu := PPUP;
242end;
243
244function TEditorToolbar.CreateJumpItem(AJumpType: TJumpType; O: TComponent): TMenuItem;
245begin
246  Result := TMenuItem.Create(O);
247  Result.Tag      := Ord(AJumpType);
248  Result.OnClick  := @FJumpHandler.DoJump;
249  Result.Caption  := cJumpNames[AJumpType];
250end;
251
252function TEditorToolbar.CreateProfileItem(ProfIndx: Integer; O: TComponent
253  ): TMenuItem;
254begin
255  Result            := TMenuItem.Create(O);
256  Result.Tag        := ProfIndx;
257  Result.Caption    := sLocalizedProfileNames[ProfIndx];
258  Result.GroupIndex := 1;
259  Result.RadioItem  := True;
260  //Result.AutoCheck  := True;
261  Result.OnClick    := @MenuItemClick;
262end;
263
264procedure TEditorToolbar.DoConfigureToolbar(Sender: TObject);
265begin
266  if TEdtTbConfigForm.Execute then
267    uEditorToolbarList.ReloadAll;
268end;
269
270procedure TEditorToolbar.UpdateBar(Sender: TObject);
271var
272  i,j: integer;
273  mi: TIDEMenuItem;
274begin
275  TB.BeginUpdate;
276  try
277    for i := TB.ButtonCount - 1 downto 0 do begin
278      if TB.Buttons[I].tag <> 0 then begin
279        j := TB.Buttons[I].tag-1;
280        mi := TIDEMenuItem(FButtonList.Items[j]);
281        if mi <> nil then begin
282            TB.Buttons[I].Enabled := mi.Enabled;
283            end;
284          end;
285      end;
286  finally
287    TB.EndUpdate;
288  end;
289end;
290
291procedure TEditorToolbar.MenuItemClick(Sender: TObject);
292var
293  cfg: TConfigStorage;
294  Value: Integer;
295begin
296  if (Sender <> nil ) and (Sender is TMenuItem) then begin
297    TMenuItem(Sender).Checked:= True;
298    Value:= TMenuItem(Sender).Tag;
299    CurrProfile := ProfileMask[Value];
300    cfg := GetIDEConfigStorage(cSettingsFile,True);
301    try
302      cfg.SetDeleteValue('Profile',CurrProfile,iAll);
303      cfg.WriteToDisk;
304    finally
305      cfg.Free;
306    end;
307    Reload;
308  end;
309end;
310
311constructor TEditorToolbar.Create(AOwner: TComponent);
312var
313  T: TJumpType;
314  c: integer;
315  cfg: TConfigStorage;
316begin
317  uEditorToolbarList.AddBar(Self);
318  if assigned(TB) then exit;
319
320  FButtonList := TList.Create;
321
322  sLocalizedProfileNames[0] := rsAll;
323  sLocalizedProfileNames[1] := rsDesign;
324  sLocalizedProfileNames[2] := rsDebug;
325  sLocalizedProfileNames[3] := rsHTML;
326  sLocalizedProfileNames[4] := rsCustom;
327
328  FJumpHandler := TJumpHandler.Create(nil);
329  FWindow := TSourceEditorWindowInterface(AOwner);
330
331  PPUP := TPopupMenu.Create(FWindow);
332  for c := 0 to High(sLocalizedProfileNames) do begin
333    PPUP.Items.Add(CreateProfileItem(c,FWindow));
334  end;
335
336  CreateEditorToolBar(FWindow, TB);
337
338  PM := TPopupMenu.Create(FWindow);
339  for T := Low(TJumpType) to High(TJumpType) do
340    PM.Items.Add(CreateJumpItem(T, FWindow));
341
342  AddStaticItems;
343  // Let's verify if it's a first start
344  c:= 0; // Just in case...
345  cfg := GetIDEConfigStorage(cSettingsFile, True);
346  try
347    c := cfg.GetValue('Count', 0);
348  finally
349    cfg.Free;
350  end;
351  if c = 0 then
352    TEdtTbConfigForm.Setup;
353
354  AddCustomItems;
355  UpdateTimer := TTimer.Create(Self);
356  UpdateTimer.Interval := 500;
357  UpdateTimer.OnTimer := @UpdateBar;
358  UpdateTimer.Enabled := True;
359end;
360
361destructor TEditorToolbar.Destroy;
362begin
363  uEditorToolbarList.DelBar(Self);
364  FJumpHandler.Free;
365  FButtonList.Free;
366  inherited Destroy;
367end;
368
369procedure TEditorToolbar.InitEditorToolBar;
370begin
371  TB := nil;
372  CfgButton := nil;
373end;
374
375procedure TEditorToolbar.AddButton(AMenuItem: TIDEMenuItem);
376var
377  B: TEditToolBarToolButton;
378  ACaption: string;
379  iPos: Integer;
380begin
381  B := TEditToolBarToolButton.Create(TB);
382  ACaption      := AMenuItem.Caption;
383  DeleteAmpersands(ACaption);
384  B.Caption     := ACaption;
385  // Get Shortcut, if any, and append to Hint
386  ACaption:= ACaption + GetShortcut(AMenuItem);
387  B.Hint        := ACaption;
388  // If we have a image, us it. Otherwise supply a default.
389  if AMenuItem.ImageIndex <> -1 then
390    B.ImageIndex := AMenuItem.ImageIndex
391  else
392    B.ImageIndex  := IDEImages.LoadImage(16, 'execute16');
393
394  B.Style       := tbsButton;
395  B.IdeMenuItem := AMenuItem;
396  iPos := FButtonList.Add(AMenuItem);
397  B.Tag:= iPos+1;
398  //B.OnClick     := AMenuItem.OnClick;
399  PositionAtEnd(TB, B);
400end;
401
402// position the button next to the last button
403procedure TEditorToolbar.PositionAtEnd(AToolbar: TToolbar; AButton: TToolButton);
404var
405  SiblingButton: TToolButton;
406begin
407  if AToolbar.ButtonCount > 0 then
408  begin
409    SiblingButton := AToolbar.Buttons[AToolbar.ButtonCount-1];
410    AButton.SetBounds(SiblingButton.Left + SiblingButton.Width,
411      SiblingButton.Top, AButton.Width, AButton.Height);
412  end;
413  AButton.Parent := AToolbar;
414end;
415
416procedure TEditorToolbar.Reload;
417begin
418  ClearToolbar;
419  AddStaticItems;
420  AddCustomItems;
421end;
422
423procedure TEditorToolbar.AddCustomItems;
424var
425  i: integer;
426  c: integer;
427  cfg: TConfigStorage;
428  value: string;
429  profile: Integer;
430  mi: TIDEMenuItem;
431  ShowItem: Boolean;
432
433procedure SetTbPos;
434begin
435case sToolbarPos of
436    'Top': begin
437      TB.Align:= alTop;
438      TB.Height:= 26;
439      end;
440    'Bottom': begin
441      TB.Align:= alBottom;
442      TB.Height:= 26;
443      end;
444    'Left': begin
445      TB.Align:= alLeft;
446      TB.Width:= 26;
447      end;
448    'Right': begin
449      TB.Align:= alRight;
450      TB.Width:= 26;
451      end;
452  end;
453end;
454
455begin
456  cfg := GetIDEConfigStorage(cSettingsFile, True);
457  TB.BeginUpdate;
458  try
459    c:= cfg.GetValue('Profile',iAll);
460    CurrProfile := c;
461    c := GetProfileIndex(CurrProfile);
462    PPUP.Items[c].Checked:= True;
463    c := cfg.GetValue('Count', 0);
464    for i := 1 to c do
465    begin
466      value := cfg.GetValue('Button' + Format('%2.2d', [i]) + '/Value', '');
467      profile := cfg.GetValue('Button' + Format('%2.2d', [i]) + '/Profile', iall);
468      ShowItem := (CurrProfile = iAll) or ((profile and CurrProfile) <> 0);
469      if (value <> '') and ShowItem then
470       begin
471        if value = cDivider then
472          AddDivider
473        else
474        begin
475          mi := IDEMenuRoots.FindByPath(value,false);
476          if Assigned(mi) then
477            AddButton(mi);
478        end;
479       end;
480    end;
481    sToolbarPos := cfg.GetValue('Position','Top');
482    bToolBarShow:= cfg.GetValue('Visible',true);
483    EditorMenuCommand.Checked:= bToolBarShow;
484    SetTbPos;
485  finally
486    cfg.Free;
487    TB.EndUpdate;
488  end;
489  TB.Visible:= bToolBarShow;
490end;
491
492procedure TEditorToolbar.AddDivider;
493var
494  B: TToolButton;
495begin
496  B := TToolbutton.Create(TB);
497  B.Style := tbsDivider;
498  PositionAtEnd(TB, B);
499end;
500
501procedure TEditorToolbar.AddStaticItems;
502var
503  B: TToolButton;  
504begin
505  TB.BeginUpdate;
506  try
507    // Config Button
508    if CfgButton = nil then
509      CfgButton := TToolbutton.Create(TB);
510    CfgButton.Caption     := rsConfigureToo;
511    CfgButton.Hint        := CfgButton.Caption;
512    CfgButton.ImageIndex  := IDEImages.LoadImage(16, 'preferences16');
513    CfgButton.Style       := tbsButton;
514    CfgButton.OnClick     := @DoConfigureToolbar;
515    PositionAtEnd(TB, CfgButton);
516    AddDivider;
517
518    // JumpTo Button
519    B := TToolbutton.Create(TB);
520    B.Caption       := rsJumpTo;
521    B.Hint          := B.Caption;
522    B.ImageIndex    := IDEImages.LoadImage(16, 'jumpto16');
523    B.Style         := tbsDropDown;
524    B.OnClick       := @FJumpHandler.DoJumpToImplementation;
525    B.DropdownMenu  := PM;
526    PositionAtEnd(TB, B);
527
528    if TB.ButtonCount <> 0 then
529      AddDivider;
530  finally
531    TB.EndUpdate;
532  end;
533end;
534
535procedure TEditorToolbar.ClearToolbar;
536var
537  i: integer;
538begin
539  TB.BeginUpdate;
540  try
541    for i := TB.ButtonCount - 1 downto 0 do
542      if TB.Buttons[i] <> CfgButton then
543        TB.Buttons[i].Free
544      else
545        TB.Buttons[i].Parent := nil;
546  finally
547    TB.EndUpdate;
548  end;
549end;
550
551function GetShortcut(AMenuItem: TIDEMenuItem): string;
552var
553  ACommand: TIDECommand;
554  AShortcut: string;
555begin
556  Result := '';
557  AShortcut:= '';
558  if AMenuItem is TIDEMenuCommand then begin
559   ACommand := TIDEMenuCommand(AMenuItem).Command;
560   if Assigned(ACommand) then  AShortcut:= ShortCutToText(ACommand.AsShortCut);
561   if AShortcut <> '' then Result:= ' (' + AShortcut +')';
562 end;
563end;
564
565function GetProfileIndex(aMask: Integer): Integer;
566var
567  I: Integer;
568begin
569  for I:= 0 to High(ProfileMask) do begin
570    if aMask = ProfileMask[I] then begin
571      Result := I;
572      Exit;
573    end;
574  end;
575  Result := 0;
576end;
577
578procedure Register;
579var
580  MenuIcon: string;
581begin
582  if uEditorToolbarList = nil then begin
583    TEditorToolbarList.Create;
584    EditorMenuCommand:= RegisterIDEMenuCommand(itmViewSecondaryWindows,'EditorToolBar',
585      rsEditorToolbar,nil,@ToggleToolbar);
586    EditorMenuCommand.Checked:= True;
587    EditorMenuCommand.Enabled:= True;
588    MenuIcon:= 'menu_editor_options';
589    //MenuIcon:= 'menu_editor_toolbar'; TODO!
590    EditorMenuCommand.ImageIndex := IDEImages.LoadImage(16, MenuIcon);
591  end;
592
593end;
594
595
596initialization
597  uEditorToolbarList := nil;
598  sToolbarPos:= 'Top';
599  bToolBarShow:= True;
600  CurrProfile:= iAll;
601
602finalization
603  uEditorToolbarList.Free;
604
605end.
606