kastoolbar.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343
  1. {
  2. Double Commander components
  3. -------------------------------------------------------------------------
  4. Toolbar panel class
  5. Copyright (C) 2006-2023 Alexander Koblov ([email protected])
  6. contributors:
  7. 2012 Przemyslaw Nagay ([email protected])
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation; either version 2 of the
  11. License, or (at your option) any later version.
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. in a file called COPYING along with this program; if not, write to
  18. the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
  19. 02139, USA.
  20. }
  21. unit KASToolBar;
  22. {$mode objfpc}{$H+}
  23. interface
  24. uses
  25. Classes, SysUtils, LResources, Forms, Controls, ComCtrls,
  26. Graphics, Dialogs, ExtCtrls, Buttons, FileUtil, Menus,
  27. DCXmlConfig, KASToolItems, LCLVersion, LMessages;
  28. type
  29. TOnToolButtonClick = procedure (Sender: TObject) of object;
  30. TOnToolButtonMouseUpDown = procedure (Sender: TObject; Button: TMouseButton; Shift:TShiftState; X,Y:Integer) of object;
  31. TOnToolButtonMouseMove = procedure (Sender: TObject; Shift:TShiftState; X,Y:Integer; NumberOfButton: Integer) of object;
  32. TOnToolButtonDragOver = procedure(Sender, Source: TObject; X,Y: Integer;
  33. State: TDragState; var Accept: Boolean; NumberOfButton: Integer) of object;
  34. TOnToolButtonDragDrop = procedure(Sender, Source: TObject; X, Y: Integer) of object;
  35. TOnToolButtonEndDrag = procedure(Sender, Target: TObject; X,Y: Integer) of object;
  36. TOnLoadButtonGlyph = function (ToolItem: TKASToolItem; iIconSize: Integer; clBackColor: TColor): TBitmap of object;
  37. TOnToolItemExecute = procedure (ToolItem: TKASToolItem) of object;
  38. TOnConfigLoadItem = function (Config: TXmlConfig; Node: TXmlNode): TKASToolItem of object;
  39. TOnToolItemShortcutsHint = function (Sender: TObject; ToolItem: TKASNormalItem): String of object;
  40. TTypeOfConfigurationLoad = (tocl_FlushCurrentToolbarContent, tocl_AddToCurrentToolbarContent);
  41. TKASToolBar = class;
  42. { TKASToolButton }
  43. TKASToolButton = class(TSpeedButton)
  44. private
  45. FOverlay: TBitmap;
  46. FToolItem: TKASToolItem;
  47. function GetToolBar: TKASToolBar;
  48. function GetGlyphBitmap: TBitmap;
  49. procedure SetGlyphBitmap(bitmap: TBitmap);
  50. protected
  51. procedure CalculatePreferredSize(var PreferredWidth,
  52. PreferredHeight: integer; WithThemeSpace: Boolean); override;
  53. function DrawGlyph(ACanvas: TCanvas; const AClient: TRect; const AOffset: TPoint;
  54. AState: TButtonState; ATransparent: Boolean; BiDiFlags: Longint): TRect; override;
  55. procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
  56. procedure CMHintShow(var Message: TLMessage); message CM_HINTSHOW;
  57. public
  58. constructor Create(AOwner: TComponent; Item: TKASToolItem); reintroduce; virtual;
  59. destructor Destroy; override;
  60. procedure Click; override;
  61. public
  62. property ToolBar: TKASToolBar read GetToolBar;
  63. property ToolItem: TKASToolItem read FToolItem;
  64. property Glyph: TBitmap read GetGlyphBitmap write SetGlyphBitmap;
  65. end;
  66. { TKASToolDivider }
  67. TKASToolDivider = class(TKASToolButton)
  68. protected
  69. procedure CalculatePreferredSize(var PreferredWidth,
  70. PreferredHeight: integer; WithThemeSpace: Boolean); override;
  71. procedure Paint; override;
  72. public
  73. constructor Create(AOwner: TComponent; Item: TKASToolItem); override;
  74. end;
  75. { TKASToolLabel }
  76. TKASToolLabel = class(TKASToolButton)
  77. protected
  78. procedure Paint; override;
  79. public
  80. constructor Create(AOwner: TComponent; Item: TKASToolItem); override;
  81. end;
  82. { TKASToolBar }
  83. TKASToolBar = class(TToolBar, IToolOwner)
  84. private
  85. FButtonHeight: Integer;
  86. FButtonWidth: Integer;
  87. FFlat: Boolean;
  88. FGlyphSize: Integer;
  89. FRadioToolBar: Boolean;
  90. FRowHeight, FRowWidth: Integer;
  91. FShowDividerAsButton: Boolean;
  92. FToolItemExecutors: TFPList;
  93. FToolItems: TKASToolBarItems;
  94. FToolPopupMenu: TPopupMenu;
  95. FOwnsToolItems: Boolean;
  96. {$if lcl_fullversion < 1010000}
  97. FUpdateCount: Integer;
  98. {$endif}
  99. FOnToolButtonClick: TOnToolButtonClick;
  100. FOnToolButtonMouseDown: TOnToolButtonMouseUpDown;
  101. FOnToolButtonMouseUp: TOnToolButtonMouseUpDown;
  102. FOnToolButtonMouseMove: TOnToolButtonMouseMove;
  103. FOnToolButtonDragOver: TOnToolButtonDragOver;
  104. FOnToolButtonDragDrop: TOnToolButtonDragDrop;
  105. FOnToolButtonEndDrag: TOnToolButtonEndDrag;
  106. FOnLoadButtonGlyph: TOnLoadButtonGlyph;
  107. FOnLoadButtonOverlay: TOnLoadButtonGlyph;
  108. FOnToolItemExecute: TOnToolItemExecute;
  109. FOnToolItemShortcutsHint: TOnToolItemShortcutsHint;
  110. FKASToolBarFlags: TToolBarFlags;
  111. FResizeButtonsNeeded: Boolean;
  112. procedure AssignToolButtonProperties(ToolButton: TKASToolButton);
  113. procedure ClearExecutors;
  114. function CreateButton(Item: TKASToolItem): TKASToolButton;
  115. function ExecuteToolItem(Item: TKASToolItem): Boolean;
  116. function FindButton(Button: TKASToolButton): Integer;
  117. function GetToolItemShortcutsHint(Item: TKASToolItem): String;
  118. function LoadBtnIcon(IconPath: String): TBitMap;
  119. function GetButton(Index: Integer): TKASToolButton;
  120. procedure InsertButton(InsertAt: Integer; ToolButton: TKASToolButton);
  121. procedure SetButtonHeight(const AValue: Integer);
  122. procedure SetButtonWidth(const AValue: Integer);
  123. procedure SetChangePath(const {%H-}AValue: String);
  124. procedure SetEnvVar(const {%H-}AValue: String);
  125. procedure SetFlat(const AValue: Boolean);
  126. procedure SetGlyphSize(const AValue: Integer);
  127. procedure ShowMenu(ToolButton: TKASToolButton);
  128. procedure ToolButtonClick(Sender: TObject);
  129. procedure ToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift:TShiftState; X,Y:Integer);
  130. procedure ToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift:TShiftState; X,Y:Integer);
  131. procedure ToolButtonMouseMove(Sender: TObject; Shift:TShiftState; X,Y:Integer);
  132. procedure ToolButtonDragOver(Sender, Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean);
  133. procedure ToolButtonDragDrop(Sender, Source: TObject; X,Y: Integer);
  134. procedure ToolButtonEndDrag(Sender, Target: TObject; X, Y: Integer);
  135. procedure ToolItemLoaded(Item: TKASToolItem);
  136. procedure ToolMenuClicked(Sender: TObject);
  137. procedure UpdateButtonsTags;
  138. protected
  139. procedure CalculatePreferredSize(var PreferredWidth,
  140. PreferredHeight: Integer; WithThemeSpace: Boolean); override;
  141. procedure AlignControls(AControl: TControl; var RemainingClientRect: TRect); override;
  142. procedure FontChanged(Sender: TObject); override;
  143. function WrapButtons(UseWidth: integer;
  144. out NewWidth, NewHeight: Integer; Simulate: boolean): Boolean;
  145. procedure ResizeButtons;
  146. public
  147. constructor Create(TheOwner: TComponent); override;
  148. destructor Destroy; override;
  149. function AddButton(Item: TKASToolItem): TKASToolButton;
  150. procedure AddToolItemExecutor(ToolItemClass: TKASToolItemClass;
  151. ExecuteFunction: TOnToolItemExecute);
  152. procedure Clear;
  153. procedure ClickItem(ToolItemID: String); overload;
  154. function InsertButton(InsertAt: Integer; Item: TKASToolItem): TKASToolButton;
  155. function InsertButton(InsertAt: TKASToolButton; Item: TKASToolItem): TKASToolButton;
  156. procedure MoveButton(ButtonIndex, MovePosition: Integer);
  157. procedure MoveButton(SourceButton: TKASToolButton; TargetToolBar: TKASToolBar; InsertAt: TKASToolButton);
  158. procedure RemoveButton(Index: Integer);
  159. procedure RemoveButton(Button: TKASToolButton);
  160. procedure RemoveToolItemExecutor(ExecuteFunction: TOnToolItemExecute);
  161. procedure UncheckAllButtons;
  162. function GlyphBitmapSize: Integer;
  163. procedure UpdateIcon(ToolButton: TKASToolButton);
  164. procedure UpdateIconWithBitmap(ToolButton: TKASToolButton; bitmap: TBitmap);
  165. procedure UseItems(AItems: TKASToolBarItems);
  166. procedure LoadConfiguration(Config: TXmlConfig; RootNode: TXmlNode;
  167. Loader: TKASToolBarLoader; ConfigurationLoadType:TTypeOfConfigurationLoad);
  168. procedure SaveConfiguration(Config: TXmlConfig; RootNode: TXmlNode);
  169. procedure BeginUpdate; override;
  170. procedure EndUpdate; override;
  171. procedure SetButtonSize(NewButtonWidth, NewButtonHeight: Integer);
  172. function PublicExecuteToolItem(Item: TKASToolItem): Boolean;
  173. property Buttons[Index: Integer]: TKASToolButton read GetButton;
  174. published
  175. property OnLoadButtonGlyph : TOnLoadButtonGlyph read FOnLoadButtonGlyph write FOnLoadButtonGlyph;
  176. property OnToolButtonClick: TOnToolButtonClick read FOnToolButtonClick write FOnToolButtonClick;
  177. property OnLoadButtonOverlay: TOnLoadButtonGlyph read FOnLoadButtonOverlay write FOnLoadButtonOverlay;
  178. property OnToolButtonMouseDown: TOnToolButtonMouseUpDown read FOnToolButtonMouseDown write FOnToolButtonMouseDown;
  179. property OnToolButtonMouseUp: TOnToolButtonMouseUpDown read FOnToolButtonMouseUp write FOnToolButtonMouseUp;
  180. property OnToolButtonMouseMove: TOnToolButtonMouseMove read FOnToolButtonMouseMove write FOnToolButtonMouseMove;
  181. property OnToolButtonDragDrop: TOnToolButtonDragDrop read FOnToolButtonDragDrop write FOnToolButtonDragDrop;
  182. property OnToolButtonEndDrag: TOnToolButtonEndDrag read FOnToolButtonEndDrag write FOnToolButtonEndDrag;
  183. property OnToolButtonDragOver: TOnToolButtonDragOver read FOnToolButtonDragOver write FOnToolButtonDragOver;
  184. property OnToolItemExecute: TOnToolItemExecute read FOnToolItemExecute write FOnToolItemExecute;
  185. property OnToolItemShortcutsHint: TOnToolItemShortcutsHint read FOnToolItemShortcutsHint write FOnToolItemShortcutsHint;
  186. property RadioToolBar: Boolean read FRadioToolBar write FRadioToolBar default False;
  187. property Flat: Boolean read FFlat write SetFlat default False;
  188. property GlyphSize: Integer read FGlyphSize write SetGlyphSize;
  189. property ButtonHeight: Integer read FButtonHeight write SetButtonHeight default 22;
  190. property ButtonWidth: Integer read FButtonWidth write SetButtonWidth default 23;
  191. property ShowDividerAsButton: Boolean read FShowDividerAsButton write FShowDividerAsButton default False;
  192. end;
  193. procedure Register;
  194. implementation
  195. uses
  196. Themes, Types, Math, ActnList, LCLType, LCLIntf, DCOSUtils;
  197. type
  198. PToolItemExecutor = ^TToolItemExecutor;
  199. TToolItemExecutor = record
  200. ToolItemClass: TKASToolItemClass;
  201. ToolItemExecute: TOnToolItemExecute;
  202. end;
  203. procedure Register;
  204. begin
  205. RegisterComponents('KASComponents',[TKASToolBar]);
  206. end;
  207. function findScaleFactorByFirstForm: Double;
  208. begin
  209. Result:= 1;
  210. if Screen.FormCount > 0 then
  211. Result:= Screen.Forms[0].GetCanvasScaleFactor();
  212. end;
  213. function findScaleFactorByControl( control: TControl ): Double;
  214. var
  215. topParent: TControl;
  216. begin
  217. if Assigned(control) then begin
  218. topParent:= control.GetTopParent;
  219. if Assigned(topParent) then
  220. control:= topParent;
  221. if (control is TWinControl) and TWinControl(control).HandleAllocated then begin
  222. Result:= control.GetCanvasScaleFactor;
  223. Exit;
  224. end;
  225. end;
  226. Result:= findScaleFactorByFirstForm();
  227. end;
  228. { TKASToolBar }
  229. procedure TKASToolBar.InsertButton(InsertAt: Integer; ToolButton: TKASToolButton);
  230. begin
  231. if InsertAt < 0 then
  232. InsertAt:= 0;
  233. if InsertAt > ButtonList.Count then
  234. InsertAt:= ButtonList.Count;
  235. ButtonList.Insert(InsertAt, ToolButton);
  236. FToolItems.Insert(InsertAt, ToolButton.ToolItem);
  237. UpdateButtonsTags;
  238. ResizeButtons;
  239. end;
  240. function TKASToolBar.InsertButton(InsertAt: TKASToolButton; Item: TKASToolItem): TKASToolButton;
  241. var
  242. Index: Integer;
  243. begin
  244. Index := ButtonList.IndexOf(InsertAt);
  245. if Index < 0 then
  246. Index := ButtonCount;
  247. Result := InsertButton(Index, Item);
  248. end;
  249. procedure TKASToolBar.CalculatePreferredSize(var PreferredWidth,
  250. PreferredHeight: Integer; WithThemeSpace: Boolean);
  251. begin
  252. WrapButtons(Width, PreferredWidth, PreferredHeight, True);
  253. end;
  254. procedure TKASToolBar.AlignControls(AControl: TControl; var RemainingClientRect: TRect);
  255. var
  256. NewWidth, NewHeight: integer;
  257. begin
  258. if tbfPlacingControls in FKASToolBarFlags then exit;
  259. Include(FKASToolBarFlags, tbfPlacingControls);
  260. DisableAlign;
  261. try
  262. AdjustClientRect(RemainingClientRect);
  263. if IsVertical then
  264. WrapButtons(Height, NewWidth, NewHeight, False)
  265. else
  266. WrapButtons(Width, NewWidth, NewHeight, False);
  267. finally
  268. Exclude(FKASToolBarFlags, tbfPlacingControls);
  269. EnableAlign;
  270. end;
  271. end;
  272. procedure TKASToolBar.FontChanged(Sender: TObject);
  273. begin
  274. inherited FontChanged(Sender);
  275. ResizeButtons;
  276. end;
  277. function TKASToolBar.WrapButtons(UseWidth: integer;
  278. out NewWidth, NewHeight: Integer; Simulate: boolean): Boolean;
  279. var
  280. ARect: TRect;
  281. x: Integer;
  282. y: Integer;
  283. CurControl: TControl;
  284. StartX, StartY: Integer;
  285. procedure CalculatePosition;
  286. var
  287. NewBounds: TRect;
  288. ALineBreak: Boolean;
  289. begin
  290. ALineBreak:= (CurControl is TKASToolDivider) and (not FShowDividerAsButton) and
  291. (TKASToolDivider(CurControl).FToolItem is TKASSeparatorItem) and
  292. (TKASSeparatorItem(TKASToolDivider(CurControl).FToolItem).Style = kssLineBreak);
  293. if IsVertical then
  294. begin
  295. NewBounds := Bounds(x, y, FRowWidth, CurControl.Height);
  296. repeat
  297. if (not Wrapable) or
  298. (NewBounds.Top = StartY) or
  299. ((NewBounds.Bottom <= ARect.Bottom) and not ALineBreak) then
  300. begin
  301. // control fits into the column
  302. x := NewBounds.Left;
  303. y := NewBounds.Top;
  304. break;
  305. end;
  306. // try next column
  307. NewBounds.Top := StartY;
  308. NewBounds.Bottom := NewBounds.Top + CurControl.Height;
  309. inc(NewBounds.Left, FRowWidth);
  310. inc(NewBounds.Right, FRowWidth);
  311. until false;
  312. end
  313. else begin
  314. NewBounds := Bounds(x, y, CurControl.Width, FRowHeight);
  315. repeat
  316. if (not Wrapable) or
  317. (NewBounds.Left = StartX) or
  318. ((NewBounds.Right <= ARect.Right) and not ALineBreak) then
  319. begin
  320. // control fits into the row
  321. x := NewBounds.Left;
  322. y := NewBounds.Top;
  323. break;
  324. end;
  325. // try next row
  326. NewBounds.Left := StartX;
  327. NewBounds.Right := NewBounds.Left + CurControl.Width;
  328. inc(NewBounds.Top, FRowHeight);
  329. inc(NewBounds.Bottom, FRowHeight);
  330. until false;
  331. end;
  332. end;
  333. var
  334. CurClientRect: TRect;
  335. AdjustClientFrame: TRect;
  336. i: Integer;
  337. w, h: Longint;
  338. begin
  339. Result := True;
  340. NewWidth := 0;
  341. NewHeight := 0;
  342. DisableAlign;
  343. BeginUpdate;
  344. try
  345. CurClientRect := ClientRect;
  346. inc(CurClientRect.Right, UseWidth - Width);
  347. ARect := CurClientRect;
  348. AdjustClientRect(ARect);
  349. AdjustClientFrame.Left := ARect.Left - CurClientRect.Left;
  350. AdjustClientFrame.Top := ARect.Top - CurClientRect.Top;
  351. AdjustClientFrame.Right := CurClientRect.Right - ARect.Right;
  352. AdjustClientFrame.Bottom := CurClientRect.Bottom - ARect.Bottom;
  353. //DebugLn(['TToolBar.WrapButtons ',DbgSName(Self),' ARect=',dbgs(ARect)]);
  354. // important: top, left button must start in the AdjustClientRect top, left
  355. // otherwise Toolbar.AutoSize=true will create an endless loop
  356. StartX := ARect.Left;
  357. StartY := ARect.Top;
  358. x := StartX;
  359. y := StartY;
  360. for i := 0 to ButtonList.Count - 1 do
  361. begin
  362. CurControl := TControl(ButtonList[i]);
  363. if not CurControl.IsControlVisible then
  364. Continue;
  365. CalculatePosition;
  366. w := CurControl.Width;
  367. h := CurControl.Height;
  368. if (not Simulate) and ((CurControl.Left <> x) or (CurControl.Top <> y)) then
  369. begin
  370. CurControl.SetBounds(x,y,w,h); // Note: do not use SetBoundsKeepBase
  371. end;
  372. // adjust NewWidth, NewHeight
  373. NewWidth := Max(NewWidth, x + w + AdjustClientFrame.Right);
  374. NewHeight := Max(NewHeight, y + h + AdjustClientFrame.Bottom);
  375. // step to next position
  376. if IsVertical then
  377. Inc(y, h)
  378. else
  379. Inc(x, w);
  380. end;
  381. finally
  382. EndUpdate;
  383. EnableAlign;
  384. end;
  385. end;
  386. procedure TKASToolBar.ResizeButtons;
  387. var
  388. w, h: LongInt;
  389. i: Integer;
  390. CurControl: TControl;
  391. begin
  392. if FUpdateCount > 0 then
  393. begin
  394. FResizeButtonsNeeded := True;
  395. Exit;
  396. end;
  397. InvalidatePreferredChildSizes;
  398. FRowWidth := ButtonWidth;
  399. FRowHeight := ButtonHeight; // Row height is at least initial button height
  400. // First recalculate RowWidth & RowHeight
  401. for i := 0 to ButtonList.Count - 1 do
  402. begin
  403. CurControl := TControl(ButtonList[i]);
  404. w := ButtonWidth;
  405. h := ButtonHeight;
  406. CurControl.GetPreferredSize(w, h);
  407. if FRowWidth < w then
  408. FRowWidth := w;
  409. if FRowHeight < h then
  410. FRowHeight := h;
  411. end;
  412. FResizeButtonsNeeded := False;
  413. // Now resize buttons.
  414. DisableAlign;
  415. BeginUpdate;
  416. try
  417. for i := 0 to ButtonList.Count - 1 do
  418. begin
  419. CurControl := TControl(ButtonList[i]);
  420. if IsVertical then
  421. begin
  422. w := FRowWidth;
  423. h := ButtonHeight;
  424. end
  425. else begin
  426. w := ButtonWidth;
  427. h := FRowHeight;
  428. end;
  429. CurControl.GetPreferredSize(w, h);
  430. if (CurControl.Width <> w) or (CurControl.Height <> h) then
  431. CurControl.SetBounds(CurControl.Left, CurControl.Top, w, h);
  432. end;
  433. InvalidatePreferredSize;
  434. AdjustSize;
  435. finally
  436. EndUpdate;
  437. EnableAlign;
  438. end;
  439. end;
  440. procedure TKASToolBar.SaveConfiguration(Config: TXmlConfig; RootNode: TXmlNode);
  441. var
  442. Node: TXmlNode;
  443. Item: TKASToolItem;
  444. i: Integer;
  445. begin
  446. if ButtonCount > 0 then
  447. begin
  448. Node := Config.AddNode(RootNode, 'Row');
  449. for i := 0 to ButtonCount - 1 do
  450. begin
  451. Item := TKASToolButton(Buttons[i]).ToolItem;
  452. Item.Save(Config, Node);
  453. end;
  454. end;
  455. end;
  456. function TKASToolBar.LoadBtnIcon(IconPath: String): TBitMap;
  457. var
  458. picture: TPicture;
  459. begin
  460. if (IconPath = '') or (not mbFileExists(IconPath)) then Exit(nil);
  461. Picture := TPicture.Create;
  462. try
  463. Picture.LoadFromFile(IconPath);
  464. Result := TBitmap.Create;
  465. Result.Assign(Picture.Bitmap);
  466. finally
  467. FreeAndNil(Picture);
  468. end;
  469. end;
  470. procedure TKASToolBar.LoadConfiguration(Config: TXmlConfig; RootNode: TXmlNode;
  471. Loader: TKASToolBarLoader; ConfigurationLoadType:TTypeOfConfigurationLoad);
  472. var
  473. Node: TXmlNode;
  474. begin
  475. BeginUpdate;
  476. if ConfigurationLoadType=tocl_FlushCurrentToolbarContent then
  477. begin
  478. Clear;
  479. end;
  480. try
  481. Node := Config.FindNode(RootNode, 'Row', False);
  482. if Assigned(Node) then
  483. Loader.Load(Config, Node, @ToolItemLoaded);
  484. finally
  485. EndUpdate;
  486. end;
  487. end;
  488. procedure TKASToolBar.AssignToolButtonProperties(ToolButton: TKASToolButton);
  489. begin
  490. ToolButton.OnClick:= @ToolButtonClick;
  491. ToolButton.OnMouseDown:= @ToolButtonMouseDown;
  492. ToolButton.OnMouseUp:= @ToolButtonMouseUp;
  493. ToolButton.OnMouseMove:= @ToolButtonMouseMove;
  494. ToolButton.OnDragDrop:= @ToolButtonDragDrop;
  495. ToolButton.OnDragOver:= @ToolButtonDragOver;
  496. ToolButton.OnEndDrag:= @ToolButtonEndDrag;
  497. end;
  498. function TKASToolBar.GetToolItemShortcutsHint(Item: TKASToolItem): String;
  499. begin
  500. Result := '';
  501. if Assigned(FOnToolItemShortcutsHint) and (Item is TKASNormalItem) then
  502. Result := FOnToolItemShortcutsHint(Self, TKASNormalItem(Item));
  503. end;
  504. function TKASToolBar.GetButton(Index: Integer): TKASToolButton;
  505. begin
  506. Result:= TKASToolButton(ButtonList.Items[Index]);
  507. end;
  508. procedure TKASToolBar.SetChangePath(const AValue: String);
  509. begin
  510. end;
  511. procedure TKASToolBar.SetEnvVar(const AValue: String);
  512. begin
  513. end;
  514. procedure TKASToolBar.SetFlat(const AValue: Boolean);
  515. var
  516. I: Integer;
  517. begin
  518. FFlat:= AValue;
  519. for I:= 0 to ButtonList.Count - 1 do
  520. TKASToolButton(ButtonList.Items[I]).Flat:= FFlat;
  521. end;
  522. procedure TKASToolBar.SetGlyphSize(const AValue: Integer);
  523. var
  524. I: Integer;
  525. begin
  526. if FGlyphSize = AValue then Exit;
  527. FGlyphSize:= AValue;
  528. self.Images.Clear;
  529. self.images.Width:= GlyphBitmapSize;
  530. self.images.Height:= GlyphBitmapSize;
  531. self.ImagesWidth:= FGlyphSize;
  532. Self.Images.Scaled := (findScaleFactorByControl(Self) > 1.0);
  533. BeginUpdate;
  534. try
  535. for I := 0 to ButtonList.Count - 1 do begin
  536. TKASToolButton(ButtonList[i]).ImageIndex:= -1;
  537. UpdateIcon(TKASToolButton(ButtonList[i]));
  538. end;
  539. finally
  540. EndUpdate;
  541. end;
  542. end;
  543. procedure TKASToolBar.ShowMenu(ToolButton: TKASToolButton);
  544. procedure MakeMenu(PopupMenu: TMenuItem; MenuItem: TKASMenuItem);
  545. var
  546. I: Integer;
  547. Item: TKASToolItem;
  548. PopupMenuItem: TMenuItem;
  549. BitmapTmp: TBitmap = nil;
  550. sText: String;
  551. begin
  552. for I := 0 to MenuItem.SubItems.Count - 1 do
  553. begin
  554. Item := MenuItem.SubItems.Items[I];
  555. if Item is TKASSeparatorItem then
  556. begin
  557. PopupMenu.AddSeparator;
  558. end
  559. else
  560. begin
  561. PopupMenuItem := TMenuItem.Create(PopupMenu);
  562. sText := Item.GetEffectiveText;
  563. if sText = '' then
  564. sText := Item.GetEffectiveHint;
  565. PopupMenuItem.Caption := StringReplace(StringReplace(sText, #$0A, ' | ', [rfReplaceAll]), ' | ----', '', [rfReplaceAll]);
  566. if Item is TKASNormalItem then
  567. begin
  568. if Assigned(FOnLoadButtonGlyph) then
  569. BitmapTmp := FOnLoadButtonGlyph(Item, 16, clMenu);
  570. if not Assigned(BitmapTmp) then
  571. BitmapTmp := LoadBtnIcon(TKASNormalItem(Item).Icon);
  572. PopupMenuItem.Bitmap := BitmapTmp;
  573. FreeAndNil(BitmapTmp);
  574. end;
  575. PopupMenuItem.Tag := PtrInt(Item);
  576. PopupMenuItem.OnClick := TNotifyEvent(@ToolMenuClicked);
  577. PopupMenu.Add(PopupMenuItem);
  578. if Item is TKASMenuItem then
  579. MakeMenu(PopupMenuItem, TKASMenuItem(Item));
  580. end;
  581. end;
  582. end;
  583. var
  584. Point: TPoint;
  585. begin
  586. FToolPopupMenu.Free;
  587. FToolPopupMenu := TPopupMenu.Create(Self);
  588. MakeMenu(FToolPopupMenu.Items, ToolButton.ToolItem as TKASMenuItem);
  589. Point.x := ToolButton.Left;
  590. Point.y := ToolButton.Top + ToolButton.Height;
  591. Point := Self.ClientToScreen(Point);
  592. FToolPopupMenu.PopUp(Point.x, Point.y);
  593. end;
  594. procedure TKASToolBar.ToolButtonClick(Sender: TObject);
  595. var
  596. Button: TKASToolButton;
  597. begin
  598. Button := Sender as TKASToolButton;
  599. // Do not allow depressing down buttons.
  600. if FRadioToolBar and not Button.Down then
  601. Button.Down := True;
  602. if not ExecuteToolItem(Button.ToolItem) then
  603. begin
  604. if Assigned(FOnToolButtonClick) then
  605. FOnToolButtonClick(Button)
  606. else if Button.ToolItem is TKASMenuItem then
  607. begin
  608. ShowMenu(Button);
  609. end;
  610. end;
  611. end;
  612. procedure TKASToolBar.ToolButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift:TShiftState; X,Y:Integer);
  613. begin
  614. if Assigned(FOnToolButtonMouseDown) then
  615. FOnToolButtonMouseDown(Sender, Button, Shift, X,Y);
  616. end;
  617. procedure TKASToolBar.ToolButtonMouseUp(Sender: TObject; Button: TMouseButton; Shift:TShiftState; X,Y:Integer);
  618. begin
  619. if Assigned(FOnToolButtonMouseUp) then
  620. FOnToolButtonMouseUp(Sender, Button, Shift, X,Y);
  621. end;
  622. procedure TKASToolBar.ToolItemLoaded(Item: TKASToolItem);
  623. begin
  624. AddButton(Item);
  625. end;
  626. procedure TKASToolBar.ToolMenuClicked(Sender: TObject);
  627. begin
  628. ExecuteToolItem(TKASToolItem((Sender as TMenuItem).Tag));
  629. end;
  630. procedure TKASToolBar.ToolButtonMouseMove(Sender: TObject; Shift:TShiftState; X,Y:Integer);
  631. begin
  632. if Assigned(FOnToolButtonMouseMove) then
  633. FOnToolButtonMouseMove(Sender, Shift, X,Y, (Sender as TSpeedButton).Tag);
  634. end;
  635. procedure TKASToolBar.ToolButtonDragOver(Sender, Source: TObject; X,Y: Integer; State: TDragState; var Accept: Boolean);
  636. begin
  637. if Assigned(FOnToolButtonDragOver) then
  638. FOnToolButtonDragOver(Sender, Source, X,Y, State, Accept, (Sender as TSpeedButton).Tag);
  639. end;
  640. procedure TKASToolBar.ToolButtonDragDrop(Sender, Source: TObject; X,Y: Integer);
  641. begin
  642. if Assigned(FOnToolButtonDragDrop) then
  643. FOnToolButtonDragDrop(Sender, Source, X, Y);
  644. end;
  645. procedure TKASToolBar.ToolButtonEndDrag(Sender, Target: TObject; X, Y: Integer);
  646. begin
  647. if Assigned(FOnToolButtonEndDrag) then
  648. FOnToolButtonEndDrag(Sender, Target, X, Y);
  649. end;
  650. procedure TKASToolBar.MoveButton(ButtonIndex, MovePosition: Integer);
  651. begin
  652. ButtonList.Move(ButtonIndex, MovePosition);
  653. FToolItems.Move(ButtonIndex, MovePosition);
  654. UpdateButtonsTags;
  655. ResizeButtons;
  656. end;
  657. procedure TKASToolBar.MoveButton(SourceButton: TKASToolButton; TargetToolBar: TKASToolBar; InsertAt: TKASToolButton);
  658. var
  659. Index: Integer;
  660. begin
  661. Index := FindButton(SourceButton);
  662. if (Index <> -1) and (FToolItems[Index] = SourceButton.ToolItem) then
  663. begin
  664. SourceButton.FToolItem := nil;
  665. TargetToolBar.InsertButton(InsertAt, FToolItems.ReleaseItem(Index));
  666. ButtonList.Delete(Index);
  667. Application.ReleaseComponent(SourceButton); // Free later
  668. UpdateButtonsTags;
  669. Resize;
  670. end;
  671. end;
  672. procedure TKASToolBar.UpdateButtonsTags;
  673. var
  674. I: Integer;
  675. begin
  676. for I:= 0 to ButtonList.Count - 1 do
  677. TKASToolButton(ButtonList.Items[I]).Tag:= I;
  678. end;
  679. procedure TKASToolBar.UpdateIcon(ToolButton: TKASToolButton);
  680. var
  681. Bitmap: TBitmap = nil;
  682. begin
  683. try
  684. if Assigned(FOnLoadButtonGlyph) then
  685. Bitmap := FOnLoadButtonGlyph(ToolButton.ToolItem, FGlyphSize, clBtnFace);
  686. if not Assigned(Bitmap) and (ToolButton.ToolItem is TKASNormalItem) then
  687. Bitmap := LoadBtnIcon(TKASNormalItem(ToolButton.ToolItem).Icon);
  688. try
  689. if Assigned(Bitmap) and Assigned(FOnLoadButtonOverlay) and (not (ToolButton.ToolItem is TKASSeparatorItem)) then
  690. begin
  691. FreeAndNil(ToolButton.FOverlay);
  692. ToolButton.FOverlay := FOnLoadButtonOverlay(ToolButton.ToolItem, FGlyphSize div 2, clBtnFace);
  693. end;
  694. if Assigned(Bitmap) then
  695. self.UpdateIconWithBitmap(ToolButton, Bitmap);
  696. finally
  697. Bitmap.Free;
  698. end;
  699. except
  700. // Ignore
  701. end;
  702. end;
  703. procedure TKASToolBar.UpdateIconWithBitmap(ToolButton: TKASToolButton;
  704. bitmap: TBitmap);
  705. begin
  706. if ToolButton.ImageIndex < 0 then begin
  707. ToolButton.Images:= self.Images;
  708. ToolButton.ImageIndex:= self.Images.Add( bitmap, nil );
  709. ToolButton.ImageWidth:= self.ImagesWidth;
  710. end else begin
  711. self.Images.Replace( ToolButton.ImageIndex, bitmap, nil );
  712. end;
  713. end;
  714. procedure TKASToolBar.UseItems(AItems: TKASToolBarItems);
  715. var
  716. i: Integer;
  717. Button: TKASToolButton;
  718. begin
  719. if Assigned(AItems) then
  720. begin
  721. BeginUpdate;
  722. Clear;
  723. if FOwnsToolItems then
  724. FToolItems.Free;
  725. FToolItems := AItems;
  726. FOwnsToolItems := False;
  727. // Insert the existing items as buttons.
  728. for i := 0 to FToolItems.Count - 1 do
  729. begin
  730. Button := CreateButton(FToolItems.Items[i]);
  731. if Assigned(Button) then
  732. ButtonList.Insert(ButtonCount, Button);
  733. end;
  734. UpdateButtonsTags;
  735. ResizeButtons;
  736. EndUpdate;
  737. end;
  738. end;
  739. procedure TKASToolBar.Clear;
  740. var
  741. I: Integer;
  742. begin
  743. BeginUpdate;
  744. for I := 0 to ButtonList.Count - 1 do
  745. TKASToolButton(ButtonList.Items[I]).Free;
  746. ButtonList.Clear;
  747. if Assigned(FToolItems) then
  748. FToolItems.Clear;
  749. EndUpdate;
  750. end;
  751. procedure TKASToolBar.ClearExecutors;
  752. var
  753. I: Integer;
  754. begin
  755. for I := 0 to FToolItemExecutors.Count - 1 do
  756. Dispose(PToolItemExecutor(FToolItemExecutors[I]));
  757. FToolItemExecutors.Clear;
  758. end;
  759. procedure TKASToolBar.ClickItem(ToolItemID: String);
  760. var
  761. I: Integer;
  762. Button: TKASToolButton;
  763. NormalItem: TKASNormalItem;
  764. begin
  765. for I := 0 to ButtonList.Count - 1 do
  766. begin
  767. Button := TKASToolButton(ButtonList.Items[I]);
  768. if Button.ToolItem is TKASNormalItem then
  769. begin
  770. NormalItem := TKASNormalItem(Button.ToolItem);
  771. if NormalItem.ID = ToolItemID then
  772. begin
  773. Button.Click;
  774. Break;
  775. end;
  776. if Button.ToolItem.CheckExecute(ToolItemID) then
  777. Break;
  778. end;
  779. end;
  780. end;
  781. procedure TKASToolBar.SetButtonHeight(const AValue: Integer);
  782. begin
  783. SetButtonSize(ButtonWidth, AValue);
  784. end;
  785. procedure TKASToolBar.SetButtonWidth(const AValue: Integer);
  786. begin
  787. SetButtonSize(AValue, ButtonHeight);
  788. end;
  789. constructor TKASToolBar.Create(TheOwner: TComponent);
  790. begin
  791. inherited Create(TheOwner);
  792. self.images:= TImageList.Create(self);
  793. self.GlyphSize:= 16; // by default
  794. FUpdateCount:= 0;
  795. FButtonWidth := 23;
  796. FButtonHeight := 22;
  797. FKASToolBarFlags := [];
  798. FToolItemExecutors := TFPList.Create;
  799. FToolItems := TKASToolBarItems.Create;
  800. FOwnsToolItems := True;
  801. end;
  802. function TKASToolBar.CreateButton(Item: TKASToolItem): TKASToolButton;
  803. begin
  804. if Assigned(Item) then
  805. begin
  806. if FOwnsToolItems then
  807. Item.SetToolOwner(Self);
  808. if Item is TKASSeparatorItem then
  809. begin
  810. Result := TKASToolDivider.Create(Self, Item);
  811. end
  812. else if Item is TKASLabelItem then
  813. begin
  814. Result := TKASToolLabel.Create(Self, Item);
  815. end
  816. else
  817. begin
  818. Result := TKASToolButton.Create(Self, Item);
  819. Result.ShowHint := True;
  820. Result.Caption := Item.GetEffectiveText;
  821. Result.Hint := Item.GetEffectiveHint;
  822. if ShowCaptions and (Result.Caption = '') then
  823. Result.Caption := Result.Hint;
  824. if Assigned(Item.Action) then
  825. begin
  826. Result.AllowAllUp := True;
  827. Result.Action := Item.Action;
  828. end;
  829. end;
  830. Result.Flat := FFlat;
  831. if FRadioToolBar then
  832. begin
  833. Result.GroupIndex := 1;
  834. Result.AllowAllUp := True;
  835. end;
  836. Result.ShowCaption := ShowCaptions;
  837. UpdateIcon(Result);
  838. AssignToolButtonProperties(Result);
  839. Result.Parent := Self;
  840. end
  841. else
  842. Result := nil;
  843. end;
  844. destructor TKASToolBar.Destroy;
  845. begin
  846. if not FOwnsToolItems then
  847. FToolItems := nil; // Unassign before Clear so that items are not cleared.
  848. Clear;
  849. inherited Destroy;
  850. ClearExecutors;
  851. FToolItemExecutors.Free;
  852. if FOwnsToolItems then
  853. FToolItems.Free;
  854. end;
  855. function TKASToolBar.ExecuteToolItem(Item: TKASToolItem): Boolean;
  856. var
  857. I: Integer;
  858. Executor: PToolItemExecutor;
  859. BestMatch: PToolItemExecutor = nil;
  860. begin
  861. for I := 0 to FToolItemExecutors.Count - 1 do
  862. begin
  863. Executor := PToolItemExecutor(FToolItemExecutors[I]);
  864. if Assigned(Executor^.ToolItemExecute) and
  865. Item.InheritsFrom(Executor^.ToolItemClass) and
  866. (not Assigned(BestMatch) or
  867. (Executor^.ToolItemClass.InheritsFrom(BestMatch^.ToolItemClass))) then
  868. begin
  869. BestMatch := Executor;
  870. end;
  871. end;
  872. Result := Assigned(BestMatch);
  873. if Result then
  874. BestMatch^.ToolItemExecute(Item);
  875. end;
  876. { TKASToolBar.PublicExecuteToolItem }
  877. function TKASToolBar.PublicExecuteToolItem(Item: TKASToolItem): Boolean;
  878. begin
  879. result:=ExecuteToolItem(Item);
  880. end;
  881. procedure TKASToolBar.BeginUpdate;
  882. begin
  883. {$if lcl_fullversion < 1010000}
  884. Inc(FUpdateCount);
  885. {$endif}
  886. inherited BeginUpdate;
  887. DisableAutoSizing;
  888. end;
  889. procedure TKASToolBar.EndUpdate;
  890. begin
  891. EnableAutoSizing;
  892. inherited EndUpdate;
  893. {$if lcl_fullversion < 1010000}
  894. Dec(FUpdateCount);
  895. {$endif}
  896. if (FUpdateCount = 0) and FResizeButtonsNeeded then
  897. ResizeButtons;
  898. end;
  899. function TKASToolBar.FindButton(Button: TKASToolButton): Integer;
  900. var
  901. I: Integer;
  902. begin
  903. for I := 0 to ButtonList.Count - 1 do
  904. if TKASToolButton(ButtonList[I]) = Button then
  905. Exit(I);
  906. Result := -1;
  907. end;
  908. procedure TKASToolBar.SetButtonSize(NewButtonWidth, NewButtonHeight: Integer);
  909. begin
  910. FButtonWidth := NewButtonWidth;
  911. FButtonHeight := NewButtonHeight;
  912. ResizeButtons;
  913. end;
  914. function TKASToolBar.AddButton(Item: TKASToolItem): TKASToolButton;
  915. begin
  916. Result := InsertButton(ButtonCount, Item);
  917. end;
  918. procedure TKASToolBar.AddToolItemExecutor(ToolItemClass: TKASToolItemClass; ExecuteFunction: TOnToolItemExecute);
  919. var
  920. Executor: PToolItemExecutor;
  921. begin
  922. New(Executor);
  923. FToolItemExecutors.Add(Executor);
  924. Executor^.ToolItemClass := ToolItemClass;
  925. Executor^.ToolItemExecute := ExecuteFunction;
  926. end;
  927. function TKASToolBar.InsertButton(InsertAt: Integer; Item: TKASToolItem): TKASToolButton;
  928. begin
  929. Result := CreateButton(Item);
  930. if Assigned(Result) then
  931. InsertButton(InsertAt, Result);
  932. end;
  933. procedure TKASToolBar.RemoveButton(Index: Integer);
  934. var
  935. Button: TKASToolButton;
  936. begin
  937. Button := TKASToolButton(ButtonList.Items[Index]);
  938. ButtonList.Delete(Index);
  939. Button.Free;
  940. FToolItems.Remove(Index);
  941. UpdateButtonsTags;
  942. Resize;
  943. end;
  944. procedure TKASToolBar.RemoveButton(Button: TKASToolButton);
  945. var
  946. Index: Integer;
  947. begin
  948. Index := FindButton(Button);
  949. if Index <> -1 then
  950. RemoveButton(Index);
  951. end;
  952. procedure TKASToolBar.RemoveToolItemExecutor(ExecuteFunction: TOnToolItemExecute);
  953. var
  954. Executor: PToolItemExecutor;
  955. I: Integer;
  956. begin
  957. for I := FToolItemExecutors.Count - 1 downto 0 do
  958. begin
  959. Executor := PToolItemExecutor(FToolItemExecutors[I]);
  960. if (TMethod(Executor^.ToolItemExecute).Code = TMethod(ExecuteFunction).Code) and
  961. (TMethod(Executor^.ToolItemExecute).Data = TMethod(ExecuteFunction).Data) then
  962. begin
  963. Dispose(Executor);
  964. FToolItemExecutors.Delete(I);
  965. end;
  966. end;
  967. end;
  968. procedure TKASToolBar.UncheckAllButtons;
  969. var
  970. I: Integer;
  971. begin
  972. for I:= 0 to ButtonCount - 1 do
  973. Buttons[I].Down:= False;
  974. end;
  975. function TKASToolBar.GlyphBitmapSize: Integer;
  976. begin
  977. Result:= Round(FGlyphSize * findScaleFactorByControl(self));
  978. end;
  979. { TKASToolButton }
  980. procedure TKASToolButton.CalculatePreferredSize(var PreferredWidth,
  981. PreferredHeight: integer; WithThemeSpace: Boolean);
  982. var
  983. TextSize: TSize;
  984. iconWidth: Integer;
  985. begin
  986. if (Parent = nil) then
  987. inherited
  988. else begin
  989. if ToolBar.IsVertical then
  990. begin
  991. PreferredWidth := ToolBar.FRowWidth;
  992. PreferredHeight := ToolBar.ButtonHeight;
  993. end
  994. else begin
  995. PreferredWidth := ToolBar.ButtonWidth;
  996. PreferredHeight := ToolBar.FRowHeight;
  997. end;
  998. if ShowCaption and (Caption <> EmptyStr) then
  999. begin
  1000. // Size to extent of the icon + caption.
  1001. TextSize := Canvas.TextExtent(Caption);
  1002. iconWidth := self.ImageWidth;
  1003. if iconWidth = 0 then
  1004. iconWidth := Glyph.Width;
  1005. PreferredWidth := Max(TextSize.cx + iconWidth + 16, PreferredWidth);
  1006. PreferredHeight := Max(TextSize.cy + 4, PreferredHeight);
  1007. end;
  1008. end;
  1009. end;
  1010. function TKASToolButton.DrawGlyph(ACanvas: TCanvas; const AClient: TRect;
  1011. const AOffset: TPoint; AState: TButtonState; ATransparent: Boolean;
  1012. BiDiFlags: Longint): TRect;
  1013. var
  1014. X, Y: Integer;
  1015. AWidth : Integer;
  1016. begin
  1017. Result := inherited DrawGlyph(ACanvas, AClient, AOffset, AState, ATransparent, BiDiFlags);
  1018. if Assigned(FOverlay) then
  1019. begin
  1020. AWidth := FOverlay.Width;
  1021. X := AClient.Left + AOffset.X + ToolBar.FGlyphSize - AWidth;
  1022. Y := AClient.Top + AOffset.Y + ToolBar.FGlyphSize - AWidth;
  1023. Canvas.Draw(X, Y, FOverlay);
  1024. end;
  1025. end;
  1026. procedure TKASToolButton.ActionChange(Sender: TObject; CheckDefaults: Boolean);
  1027. begin
  1028. if Sender is TCustomAction then
  1029. begin
  1030. with TCustomAction(Sender) do
  1031. begin
  1032. if CheckDefaults or (Self.GroupIndex = 0) then
  1033. Self.GroupIndex := GroupIndex;
  1034. if not CheckDefaults or Enabled then
  1035. Self.Enabled := Enabled;
  1036. if not CheckDefaults or Visible then
  1037. Self.Visible := Visible;
  1038. if not CheckDefaults or Checked then
  1039. Self.Down := Checked;
  1040. end;
  1041. end;
  1042. end;
  1043. procedure TKASToolButton.CMHintShow(var Message: TLMessage);
  1044. begin
  1045. if (ActionLink <> nil) and FToolItem.ActionHint then
  1046. begin
  1047. inherited CMHintShow(Message);
  1048. end
  1049. else begin
  1050. DoOnShowHint(TCMHintShow(Message).HintInfo);
  1051. end;
  1052. end;
  1053. constructor TKASToolButton.Create(AOwner: TComponent; Item: TKASToolItem);
  1054. begin
  1055. inherited Create(AOwner);
  1056. FToolItem := Item;
  1057. end;
  1058. destructor TKASToolButton.Destroy;
  1059. begin
  1060. inherited Destroy;
  1061. FOverlay.Free;
  1062. end;
  1063. procedure TKASToolButton.Click;
  1064. begin
  1065. if Assigned(OnClick) then OnClick(Self);
  1066. end;
  1067. function TKASToolButton.GetToolBar: TKASToolBar;
  1068. begin
  1069. Result := Parent as TKASToolBar;
  1070. end;
  1071. function TKASToolButton.GetGlyphBitmap: TBitmap;
  1072. begin
  1073. Result:= Inherited Glyph;
  1074. end;
  1075. procedure TKASToolButton.SetGlyphBitmap(bitmap: TBitmap);
  1076. begin
  1077. self.ToolBar.UpdateIconWithBitmap(self, bitmap);
  1078. end;
  1079. { TKASToolDivider }
  1080. procedure TKASToolDivider.CalculatePreferredSize(var PreferredWidth,
  1081. PreferredHeight: integer; WithThemeSpace: Boolean);
  1082. var
  1083. ASize: Integer;
  1084. begin
  1085. if Assigned(Parent) and (Parent is TKASToolBar) and
  1086. (not TKASToolBar(Parent).FShowDividerAsButton) then
  1087. begin
  1088. if (TKASSeparatorItem(FToolItem).Style = kssSeparator) then
  1089. ASize:= 5
  1090. else if (TKASSeparatorItem(FToolItem).Style = kssLineBreak) then
  1091. ASize:= 0
  1092. else begin
  1093. ASize:= -1;
  1094. end;
  1095. if ASize < 0 then
  1096. begin
  1097. inherited;
  1098. end
  1099. else if ToolBar.IsVertical then
  1100. begin
  1101. PreferredHeight := ASize;
  1102. PreferredWidth := ToolBar.FRowWidth;
  1103. end
  1104. else begin
  1105. PreferredWidth := ASize;
  1106. PreferredHeight := ToolBar.FRowHeight;
  1107. end;
  1108. end
  1109. else
  1110. inherited;
  1111. end;
  1112. procedure TKASToolDivider.Paint;
  1113. var
  1114. DividerRect: TRect;
  1115. Details: TThemedElementDetails;
  1116. begin
  1117. if Assigned(Parent) and (Parent is TKASToolBar) and
  1118. not TKASToolBar(Parent).FShowDividerAsButton then
  1119. begin
  1120. if TKASSeparatorItem(FToolItem).Style > kssSeparator then Exit;
  1121. DividerRect:= ClientRect;
  1122. if ToolBar.IsVertical then
  1123. begin
  1124. Details:= ThemeServices.GetElementDetails(ttbSeparatorVertNormal);
  1125. // Theme services have no strict rule to draw divider in the center,
  1126. // so we should calculate rectangle here
  1127. // on windows 7 divider can't be less than 4 pixels
  1128. if (DividerRect.Bottom - DividerRect.Top) > 5 then
  1129. begin
  1130. DividerRect.Top := (DividerRect.Top + DividerRect.Bottom) div 2 - 3;
  1131. DividerRect.Bottom := DividerRect.Top + 5;
  1132. end;
  1133. if not ThemeServices.ThemesEnabled then
  1134. begin
  1135. InflateRect(DividerRect, -2, 0);
  1136. Canvas.Pen.Color := clBtnShadow;
  1137. Canvas.Line(DividerRect.Left, DividerRect.Top + 1, DividerRect.Right, DividerRect.Top + 1);
  1138. Canvas.Pen.Color := clBtnHighlight;
  1139. Canvas.Line(DividerRect.Left, DividerRect.Top + 2, DividerRect.Right, DividerRect.Top + 2);
  1140. Exit;
  1141. end;
  1142. end
  1143. else begin
  1144. Details:= ThemeServices.GetElementDetails(ttbSeparatorNormal);
  1145. // Theme services have no strict rule to draw divider in the center,
  1146. // so we should calculate rectangle here
  1147. // on windows 7 divider can't be less than 4 pixels
  1148. if (DividerRect.Right - DividerRect.Left) > 5 then
  1149. begin
  1150. DividerRect.Left := (DividerRect.Left + DividerRect.Right) div 2 - 3;
  1151. DividerRect.Right := DividerRect.Left + 5;
  1152. end;
  1153. end;
  1154. ThemeServices.DrawElement(Canvas.GetUpdatedHandle([csBrushValid, csPenValid]), Details, DividerRect);
  1155. end
  1156. else
  1157. inherited Paint;
  1158. end;
  1159. constructor TKASToolDivider.Create(AOwner: TComponent; Item: TKASToolItem);
  1160. begin
  1161. inherited Create(AOwner, Item);
  1162. ControlStyle:= ControlStyle + [csAutoSize0x0];
  1163. end;
  1164. { TKASToolLabel }
  1165. procedure TKASToolLabel.Paint;
  1166. const
  1167. cAlignment: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);
  1168. var
  1169. R: TRect;
  1170. Flags: Longint;
  1171. LabelText: String;
  1172. begin
  1173. R:= ClientRect;
  1174. Canvas.Font:= Font;
  1175. LabelText:= Caption;
  1176. InflateRect(R, -8, 0);
  1177. Canvas.Brush.Color:= Color;
  1178. Canvas.Brush.Style:= bsClear;
  1179. Flags:= DT_EXPANDTABS or DT_VCENTER;
  1180. Flags:= Flags or DT_SINGLELINE or DT_NOPREFIX;
  1181. if UseRightToLeftReading then
  1182. begin
  1183. Flags:= Flags or DT_RTLREADING;
  1184. end;
  1185. Flags:= Flags or cAlignment[BidiFlipAlignment(Self.Alignment, UseRightToLeftAlignment)];
  1186. DrawText(Canvas.Handle, PAnsiChar(LabelText), Length(LabelText), R, Flags or DT_NOCLIP);
  1187. end;
  1188. constructor TKASToolLabel.Create(AOwner: TComponent; Item: TKASToolItem);
  1189. begin
  1190. inherited Create(AOwner, Item);
  1191. AutoSize:= True;
  1192. end;
  1193. end.