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