TB2Toolbar.pas 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718
  1. unit TB2Toolbar;
  2. {
  3. Toolbar2000
  4. Copyright (C) 1998-2005 by Jordan Russell
  5. All rights reserved.
  6. The contents of this file are subject to the "Toolbar2000 License"; you may
  7. not use or distribute this file except in compliance with the
  8. "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
  9. TB2k-LICENSE.txt or at:
  10. https://jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
  11. Alternatively, the contents of this file may be used under the terms of the
  12. GNU General Public License (the "GPL"), in which case the provisions of the
  13. GPL are applicable instead of those in the "Toolbar2000 License". A copy of
  14. the GPL may be found in GPL-LICENSE.txt or at:
  15. https://jrsoftware.org/files/tb2k/GPL-LICENSE.txt
  16. If you wish to allow use of your version of this file only under the terms of
  17. the GPL and not to allow others to use your version of this file under the
  18. "Toolbar2000 License", indicate your decision by deleting the provisions
  19. above and replace them with the notice and other provisions required by the
  20. GPL. If you do not delete the provisions above, a recipient may use your
  21. version of this file under either the "Toolbar2000 License" or the GPL.
  22. $jrsoftware: tb2k/Source/TB2Toolbar.pas,v 1.108 2005/07/30 18:17:20 jr Exp $
  23. }
  24. interface
  25. {$I TB2Ver.inc}
  26. uses
  27. Types,
  28. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ImgList,
  29. Menus, ActnList,
  30. TB2Item, TB2Dock;
  31. type
  32. TTBCustomToolbar = class;
  33. TTBChevronItem = class;
  34. TTBChevronItemClass = class of TTBChevronItem;
  35. TTBToolbarViewClass = class of TTBToolbarView;
  36. TTBToolbarView = class(TTBView)
  37. private
  38. FToolbar: TTBCustomToolbar;
  39. protected
  40. procedure AutoSize(AWidth, AHeight: Integer); override;
  41. procedure DoUpdatePositions(var ASize: TPoint); override;
  42. function GetChevronItem: TTBCustomItem; override;
  43. function GetMDIButtonsItem: TTBCustomItem; override;
  44. function GetMDISystemMenuItem: TTBCustomItem; override;
  45. public
  46. constructor Create(AOwner: TComponent); override;
  47. function GetFont: TFont; override;
  48. procedure InvalidatePositions; override;
  49. procedure EnterToolbarLoop(Options: TTBEnterToolbarLoopOptions); override;
  50. end;
  51. TTBChevronPriorityForNewItems = (tbcpHighest, tbcpLowest);
  52. { MP }
  53. TToolbarGetBaseSizeEvent = procedure(Toolbar: TTBCustomToolbar; var ASize: TPoint) of object;
  54. TTBCustomToolbar = class(TTBCustomDockableWindow, ITBItems)
  55. private
  56. FBaseSize: TPoint;
  57. FChevronItem: TTBChevronItem;
  58. FChevronMoveItems: Boolean;
  59. FChevronPriorityForNewItems: TTBChevronPriorityForNewItems;
  60. FDisableAlignArrange: Integer;
  61. FFloatingWidth: Integer;
  62. FIgnoreMouseLeave: Boolean;
  63. FItem: TTBRootItem;
  64. FLastWrappedLines: Integer;
  65. FMenuBar: Boolean;
  66. FOnShortCut: TShortCutEvent;
  67. FProcessShortCuts: Boolean;
  68. FMainWindowHookInstalled: Boolean;
  69. FShrinkMode: TTBShrinkMode;
  70. FSizeData: Pointer;
  71. FSystemFont: Boolean;
  72. FUpdateActions: Boolean;
  73. { MP }
  74. FOnGetBaseSize: TToolbarGetBaseSizeEvent;
  75. FOnEndModal: TNotifyEvent;
  76. procedure CancelHover;
  77. function CalcChevronOffset(const ADock: TTBDock;
  78. const AOrientation: TTBViewOrientation): Integer;
  79. function CalcWrapOffset(const ADock: TTBDock): Integer;
  80. function CreateWrapper(Index: Integer; Ctl: TControl): TTBControlItem;
  81. function FindWrapper(Ctl: TControl): TTBControlItem;
  82. function GetChevronHint: String;
  83. function GetImages: TCustomImageList;
  84. function GetItems: TTBCustomItem;
  85. function GetLinkSubitems: TTBCustomItem;
  86. function GetOptions: TTBItemOptions;
  87. procedure InstallMainWindowHook;
  88. function IsChevronHintStored: Boolean;
  89. class function MainWindowHook(var Message: TMessage): Boolean;
  90. procedure SetChevronHint(const Value: String);
  91. procedure SetChevronMoveItems(Value: Boolean);
  92. procedure SetChevronPriorityForNewItems(Value: TTBChevronPriorityForNewItems);
  93. procedure SetFloatingWidth(Value: Integer);
  94. procedure SetImages(Value: TCustomImageList);
  95. procedure SetLinkSubitems(Value: TTBCustomItem);
  96. procedure SetMainWindowHook;
  97. procedure SetMenuBar(Value: Boolean);
  98. procedure SetOptions(Value: TTBItemOptions);
  99. procedure SetProcessShortCuts(Value: Boolean);
  100. procedure SetShrinkMode(Value: TTBShrinkMode);
  101. procedure SetSystemFont(Value: Boolean);
  102. procedure UninstallMainWindowHook;
  103. procedure UpdateViewProperties;
  104. procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
  105. procedure CMControlChange(var Message: TCMControlChange); message CM_CONTROLCHANGE;
  106. procedure CMControlListChange(var Message: TCMControlListChange); message CM_CONTROLLISTCHANGE;
  107. procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  108. procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  109. procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
  110. procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
  111. procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  112. procedure CMShowHintChanged(var Message: TMessage); message CM_SHOWHINTCHANGED;
  113. procedure CMWinIniChange(var Message: TWMSettingChange); message CM_WININICHANGE;
  114. procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE;
  115. procedure WMGetObject(var Message: TMessage); message WM_GETOBJECT;
  116. procedure WMMouseLeave(var Message: TMessage); message WM_MOUSELEAVE;
  117. procedure WMNCMouseMove(var Message: TWMNCMouseMove); message WM_NCMOUSEMOVE;
  118. procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
  119. procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
  120. protected
  121. FMDIButtonsItem: TTBCustomItem;
  122. FMDISystemMenuItem: TTBCustomItem;
  123. FView: TTBToolbarView;
  124. procedure AlignControls(AControl: TControl; var Rect: TRect); override;
  125. procedure BuildPotentialSizesList(SizesList: TList); dynamic;
  126. procedure ControlExistsAtPos(const P: TPoint; var ControlExists: Boolean);
  127. override;
  128. function DoArrange(CanMoveControls: Boolean; PreviousDockType: TTBDockType;
  129. NewFloating: Boolean; NewDock: TTBDock): TPoint; override;
  130. procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
  131. procedure GetBaseSize(var ASize: TPoint); override;
  132. procedure GetMinBarSize(var MinimumSize: TPoint);
  133. procedure GetMinShrinkSize(var AMinimumSize: Integer); override;
  134. function GetShrinkMode: TTBShrinkMode; override;
  135. function GetChevronItemClass: TTBChevronItemClass; dynamic;
  136. function GetItemClass: TTBRootItemClass; dynamic;
  137. function GetViewClass: TTBToolbarViewClass; dynamic;
  138. procedure Loaded; override;
  139. procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  140. X, Y: Integer); override;
  141. procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  142. procedure Paint; override;
  143. procedure ResizeBegin(ASizeHandle: TTBSizeHandle); override;
  144. procedure ResizeTrack(var Rect: TRect; const OrigRect: TRect); override;
  145. procedure ResizeTrackAccept; override;
  146. procedure ResizeEnd; override;
  147. procedure SetChildOrder(Child: TComponent; Order: Integer); override;
  148. procedure ChangeScale(M, D: Integer); override;
  149. property SystemFont: Boolean read FSystemFont write SetSystemFont default True;
  150. property OnShortCut: TShortCutEvent read FOnShortCut write FOnShortCut;
  151. public
  152. constructor Create(AOwner: TComponent); override;
  153. destructor Destroy; override;
  154. procedure BeginUpdate;
  155. procedure EndUpdate;
  156. procedure CreateWrappersForAllControls;
  157. procedure GetTabOrderList(List: TList); override;
  158. procedure InitiateAction; override;
  159. function IsShortCut(var Message: TWMKey): Boolean;
  160. function KeyboardOpen(Key: Char; RequirePrimaryAccel: Boolean): Boolean;
  161. procedure ReadPositionData(var S: string); override;
  162. function WritePositionData: string; override;
  163. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  164. property ChevronHint: String read GetChevronHint write SetChevronHint stored IsChevronHintStored;
  165. property ChevronMoveItems: Boolean read FChevronMoveItems write SetChevronMoveItems default True;
  166. property ChevronPriorityForNewItems: TTBChevronPriorityForNewItems read FChevronPriorityForNewItems
  167. write SetChevronPriorityForNewItems default tbcpHighest;
  168. property FloatingWidth: Integer read FFloatingWidth write SetFloatingWidth default 0;
  169. property Images: TCustomImageList read GetImages write SetImages;
  170. property Items: TTBRootItem read FItem;
  171. property LinkSubitems: TTBCustomItem read GetLinkSubitems write SetLinkSubitems;
  172. property Options: TTBItemOptions read GetOptions write SetOptions default [];
  173. property MenuBar: Boolean read FMenuBar write SetMenuBar default False;
  174. property ProcessShortCuts: Boolean read FProcessShortCuts write SetProcessShortCuts default False;
  175. property ShrinkMode: TTBShrinkMode read FShrinkMode write SetShrinkMode default tbsmChevron;
  176. property UpdateActions: Boolean read FUpdateActions write FUpdateActions default True;
  177. property View: TTBToolbarView read FView;
  178. { MP }
  179. property OnGetBaseSize: TToolbarGetBaseSizeEvent read FOnGetBaseSize write FOnGetBaseSize;
  180. property OnEndModal: TNotifyEvent read FOnEndModal write FOnEndModal;
  181. published
  182. property Hint stored False; { Hint is set dynamically; don't save it }
  183. end;
  184. TTBToolbar = class(TTBCustomToolbar)
  185. published
  186. property ActivateParent;
  187. property Align;
  188. property Anchors;
  189. property AutoResize;
  190. property BorderStyle;
  191. property Caption;
  192. property ChevronHint;
  193. property ChevronMoveItems;
  194. property ChevronPriorityForNewItems;
  195. property CloseButton;
  196. property CloseButtonWhenDocked;
  197. property Color;
  198. property CurrentDock;
  199. property DefaultDock;
  200. property DockableTo;
  201. property DockMode;
  202. property DockPos;
  203. property DockRow;
  204. property DragHandleStyle;
  205. property FloatingMode;
  206. property FloatingWidth;
  207. property Font;
  208. property FullSize;
  209. property HideWhenInactive;
  210. property Images;
  211. property Items;
  212. property LastDock;
  213. property LinkSubitems;
  214. property MenuBar;
  215. property Options;
  216. property ParentFont;
  217. property ParentShowHint;
  218. property PopupMenu;
  219. property ProcessShortCuts;
  220. property Resizable;
  221. property ShowCaption;
  222. property ShowHint;
  223. property ShrinkMode;
  224. property SmoothDrag;
  225. property Stretch;
  226. property SystemFont;
  227. property TabOrder;
  228. property UpdateActions;
  229. property UseLastDock;
  230. property Visible;
  231. property OnClose;
  232. property OnCloseQuery;
  233. {$IFDEF JR_D5}
  234. property OnContextPopup;
  235. {$ENDIF}
  236. property OnDragDrop;
  237. property OnDragOver;
  238. property OnMouseDown;
  239. property OnMouseMove;
  240. property OnMouseUp;
  241. property OnMove;
  242. property OnRecreated;
  243. property OnRecreating;
  244. property OnDockChanged;
  245. property OnDockChanging;
  246. property OnDockChangingHidden;
  247. property OnResize;
  248. property OnShortCut;
  249. property OnVisibleChanged;
  250. { MP }
  251. property OnGetBaseSize;
  252. property OnEndModal;
  253. end;
  254. { TTBChevronItem & TTBChevronItemViewer }
  255. TTBChevronItem = class(TTBCustomItem)
  256. private
  257. FToolbar: TTBCustomToolbar;
  258. function GetDefaultHint: String;
  259. public
  260. constructor Create(AOwner: TComponent); override;
  261. function GetChevronParentView: TTBView; override;
  262. function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; override;
  263. end;
  264. TTBChevronItemViewer = class(TTBItemViewer)
  265. protected
  266. procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect;
  267. IsSelected, IsPushed, UseDisabledShadow: Boolean); override;
  268. function CaptionShown: Boolean; override;
  269. end;
  270. const
  271. tbChevronSize = 12;
  272. implementation
  273. uses
  274. TB2Consts, TB2Common, TB2Hook, PasTools;
  275. const
  276. { Constants for TTBCustomToolbar-specific registry values. Do not localize! }
  277. rvFloatRightX = 'FloatRightX';
  278. DockTypeToOrientation: array[TTBDockType] of TTBViewOrientation =
  279. (tbvoHorizontal, tbvoFloating, tbvoHorizontal, tbvoVertical);
  280. type
  281. { Used internally by the TCustomToolbar97.Resize* procedures }
  282. PToolbar97SizeData = ^TToolbar97SizeData;
  283. TToolbar97SizeData = record
  284. SizeHandle: TTBSizeHandle;
  285. NewSizes: TList; { List of valid new sizes. Items are casted into TSmallPoints }
  286. OrigLeft, OrigTop, OrigWidth, OrigHeight, NCXDiff: Integer;
  287. CurRightX: Integer;
  288. DisableSensCheck, OpSide: Boolean;
  289. SizeSens: Integer;
  290. end;
  291. procedure HookProc(Code: THookProcCode; Wnd: HWND; WParam: WPARAM;
  292. LParam: LPARAM);
  293. var
  294. Msg: PMsg;
  295. MainForm: TForm;
  296. begin
  297. { Work around an annoying Windows or VCL bug. If you close all MDI child
  298. windows, the MDI client window gets the focus, and when it has the focus,
  299. pressing Alt+[char] doesn't send a WM_SYSCOMMAND message to the form for
  300. some reason. It seems silly to have to use a hook for this, but I don't
  301. see a better workaround.
  302. Also, route Alt+- to the main form so that when an MDI child form is
  303. maximized, Alt+- brings up the TB2k MDI system menu instead of the
  304. system's. }
  305. if (Code = hpGetMessage) and (WParam = PM_REMOVE) then begin
  306. Msg := PMsg(LParam);
  307. if (Msg.message = WM_SYSCHAR) and (Msg.hwnd <> 0) then begin
  308. { Note: On Windows NT/2000/XP, even though we install the hook using
  309. SetWindowsHookExW, Msg.wParam may either be an ANSI character or a
  310. Unicode character, due to an apparent bug on these platforms. It is
  311. an ANSI character when the message passes through a separate
  312. SetWindowsHookExA-installed WH_GETMESSAGE hook first, and that hook
  313. calls us via CallNextHookEx. Windows apparently "forgets" to convert
  314. the character from ANSI back to Unicode in this case.
  315. We can't convert the character code because there seems to be no way
  316. to detect whether it is ANSI or Unicode. So we can't really do much
  317. with Msg.wParam, apart from comparing it against character codes that
  318. are the same between ANSI and Unicode, such as '-'. }
  319. MainForm := Application.MainForm;
  320. if Assigned(MainForm) and MainForm.HandleAllocated and (GetCapture = 0) and
  321. ((Msg.hwnd = MainForm.ClientHandle) or
  322. ((Msg.wParam = Ord('-')) and (MainForm.ClientHandle <> 0) and
  323. IsChild(MainForm.ClientHandle, Msg.hwnd))) then begin
  324. { Redirect the message to the main form.
  325. Note: Unfortunately, due to a bug in Windows NT 4.0 (and not
  326. 2000/XP/9x/Me), modifications to the message don't take effect if
  327. another WH_GETMESSAGE hook has been installed above this one.
  328. (The bug is that CallNextHookEx copies lParam^ to a local buffer, but
  329. does not propogate the changes made by the hook back to lParam^ when
  330. it returns.) I don't know of any clean workaround, other than to
  331. ensure other WH_GETMESSAGE hooks are installed *before*
  332. Toolbar2000's. }
  333. Msg.hwnd := MainForm.Handle;
  334. end;
  335. end;
  336. end;
  337. end;
  338. constructor TTBChevronItem.Create(AOwner: TComponent);
  339. begin
  340. inherited;
  341. FToolbar := AOwner as TTBCustomToolbar;
  342. ItemStyle := ItemStyle + [tbisSubMenu, tbisNoAutoOpen];
  343. Hint := GetDefaultHint;
  344. Caption := EscapeAmpersands(GetShortHint(Hint));
  345. end;
  346. function TTBChevronItem.GetChevronParentView: TTBView;
  347. begin
  348. Result := FToolbar.FView;
  349. end;
  350. function TTBChevronItem.GetDefaultHint: String;
  351. begin
  352. Result := STBChevronItemMoreButtonsHint;
  353. end;
  354. function TTBChevronItem.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
  355. begin
  356. Result := TTBChevronItemViewer;
  357. end;
  358. procedure TTBChevronItemViewer.Paint(const Canvas: TCanvas;
  359. const ClientAreaRect: TRect; IsSelected, IsPushed, UseDisabledShadow: Boolean);
  360. const
  361. Pattern: array[Boolean, 0..15] of Byte = (
  362. ($CC, 0, $66, 0, $33, 0, $66, 0, $CC, 0, 0, 0, 0, 0, 0, 0),
  363. ($88, 0, $D8, 0, $70, 0, $20, 0, $88, 0, $D8, 0, $70, 0, $20, 0));
  364. var
  365. DC: HDC;
  366. R2: TRect;
  367. TempBmp: TBitmap;
  368. procedure DrawPattern(const Color, Offset: Integer);
  369. begin
  370. SelectObject(DC, GetSysColorBrush(Color));
  371. BitBlt(DC, R2.Left, R2.Top + Offset, R2.Right - R2.Left,
  372. R2.Bottom - R2.Top, TempBmp.Canvas.Handle, 0, 0, $00E20746 {ROP_DSPDxax});
  373. end;
  374. begin
  375. DC := Canvas.Handle;
  376. R2 := ClientAreaRect;
  377. if Item.Enabled then begin
  378. if IsPushed then
  379. DrawEdge(DC, R2, BDR_SUNKENOUTER, BF_RECT)
  380. else if IsSelected and not(csDesigning in Item.ComponentState) then
  381. DrawEdge(DC, R2, BDR_RAISEDINNER, BF_RECT);
  382. end;
  383. if View.Orientation <> tbvoVertical then begin
  384. R2.Top := 4;
  385. R2.Bottom := R2.Top + 5;
  386. Inc(R2.Left, 2);
  387. R2.Right := R2.Left + 8;
  388. end
  389. else begin
  390. R2.Left := R2.Right - 9;
  391. R2.Right := R2.Left + 5;
  392. Inc(R2.Top, 2);
  393. R2.Bottom := R2.Top + 8;
  394. end;
  395. if IsPushed then
  396. OffsetRect(R2, 1, 1);
  397. TempBmp := TBitmap.Create;
  398. try
  399. TempBmp.Handle := CreateBitmap(8, 8, 1, 1,
  400. @Pattern[View.Orientation = tbvoVertical]);
  401. SetTextColor(DC, clBlack);
  402. SetBkColor(DC, clWhite);
  403. if Item.Enabled then
  404. DrawPattern(COLOR_BTNTEXT, 0)
  405. else begin
  406. DrawPattern(COLOR_BTNHIGHLIGHT, 1);
  407. DrawPattern(COLOR_BTNSHADOW, 0);
  408. end;
  409. finally
  410. TempBmp.Free;
  411. end;
  412. end;
  413. function TTBChevronItemViewer.CaptionShown: Boolean;
  414. begin
  415. Result := False;
  416. end;
  417. { TTBToolbarView }
  418. constructor TTBToolbarView.Create(AOwner: TComponent);
  419. begin
  420. FToolbar := AOwner as TTBCustomToolbar;
  421. inherited;
  422. end;
  423. procedure TTBToolbarView.AutoSize(AWidth, AHeight: Integer);
  424. begin
  425. FToolbar.FBaseSize := BaseSize;
  426. if FToolbar.IsAutoResized then
  427. FToolbar.ChangeSize(AWidth, AHeight);
  428. end;
  429. procedure TTBToolbarView.DoUpdatePositions(var ASize: TPoint);
  430. begin
  431. { Reset CurrentSize because it probably won't be valid after positions
  432. are recalculated [2001-06-24] }
  433. FToolbar.CurrentSize := 0;
  434. FToolbar.GetMinBarSize(ASize);
  435. { On FullSize toolbars, increase ASize.X/Y to WrapOffset so that
  436. right-aligned items always appear at the right edge even when the toolbar
  437. isn't wrapping }
  438. if FToolbar.FullSize then begin
  439. if (Orientation = tbvoHorizontal) and (ASize.X < WrapOffset) then
  440. ASize.X := WrapOffset
  441. else if (Orientation = tbvoVertical) and (ASize.Y < WrapOffset) then
  442. ASize.Y := WrapOffset;
  443. end;
  444. { Increment FDisableAlignArrange so that we don't recursively arrange when
  445. CalculatePositions moves controls }
  446. Inc(FToolbar.FDisableAlignArrange);
  447. try
  448. inherited;
  449. finally
  450. Dec(FToolbar.FDisableAlignArrange);
  451. end;
  452. end;
  453. procedure TTBToolbarView.InvalidatePositions;
  454. begin
  455. { Reset CurrentSize because it probably won't be valid after positions
  456. are recalculated [2001-06-04] }
  457. FToolbar.CurrentSize := 0;
  458. inherited;
  459. end;
  460. function TTBToolbarView.GetFont: TFont;
  461. begin
  462. if not FToolbar.SystemFont then
  463. Result := FToolbar.Font
  464. else
  465. Result := inherited GetFont;
  466. end;
  467. function TTBToolbarView.GetChevronItem: TTBCustomItem;
  468. begin
  469. Result := FToolbar.FChevronItem;
  470. end;
  471. function TTBToolbarView.GetMDIButtonsItem: TTBCustomItem;
  472. begin
  473. Result := FToolbar.FMDIButtonsItem;
  474. end;
  475. function TTBToolbarView.GetMDISystemMenuItem: TTBCustomItem;
  476. begin
  477. Result := FToolbar.FMDISystemMenuItem;
  478. end;
  479. procedure TTBToolbarView.EnterToolbarLoop(Options: TTBEnterToolbarLoopOptions);
  480. begin
  481. inherited;
  482. if Assigned(FToolbar.OnEndModal) then
  483. FToolbar.OnEndModal(FToolbar);
  484. end;
  485. { TTBCustomToolbar }
  486. type
  487. {}TTBCustomItemAccess = class(TTBCustomItem);
  488. TTBItemViewerAccess = class(TTBItemViewer);
  489. constructor TTBCustomToolbar.Create(AOwner: TComponent);
  490. begin
  491. inherited;
  492. ControlStyle := ControlStyle + [csAcceptsControls, csActionClient] -
  493. [csCaptureMouse];
  494. DockableWindowStyles := DockableWindowStyles - [tbdsResizeEightCorner,
  495. tbdsResizeClipCursor];
  496. FItem := GetItemClass.Create(Self);
  497. FItem.ParentComponent := Self;
  498. FChevronItem := GetChevronItemClass.Create(Self);
  499. FChevronItem.LinkSubitems := FItem;
  500. FChevronMoveItems := True;
  501. FView := GetViewClass.CreateView(Self, nil, FItem, Self, True, False,
  502. not(csDesigning in ComponentState));
  503. // This might as well go to TTBToolbarView.Create
  504. FView.Style := FView.Style + [vsUseHiddenAccels];
  505. FView.BackgroundColor := clBtnFace;
  506. FUpdateActions := True;
  507. FShrinkMode := tbsmChevron;
  508. FSystemFont := True;
  509. Color := clBtnFace;
  510. SetBounds(Left, Top, 23, 22);{}
  511. { MP }
  512. FOnGetBaseSize := nil;
  513. FOnEndModal := nil;
  514. end;
  515. destructor TTBCustomToolbar.Destroy;
  516. begin
  517. { Call Destroying to ensure csDestroying is in ComponentState now. Only
  518. needed for Delphi 4 and earlier since Delphi 5 calls Destroying in
  519. TComponent.BeforeDestruction }
  520. Destroying;
  521. UninstallHookProc(Self, HookProc);
  522. UninstallMainWindowHook;
  523. FreeAndNil(FView);
  524. FreeAndNil(FChevronItem);
  525. FreeAndNil(FItem);
  526. inherited;
  527. end;
  528. function TTBCustomToolbar.GetItems: TTBCustomItem;
  529. begin
  530. Result := FItem;
  531. end;
  532. function TTBCustomToolbar.GetItemClass: TTBRootItemClass;
  533. begin
  534. Result := TTBRootItem;
  535. end;
  536. function TTBCustomToolbar.GetViewClass: TTBToolbarViewClass;
  537. begin
  538. Result := TTBToolbarView;
  539. end;
  540. function TTBCustomToolbar.GetChevronItemClass: TTBChevronItemClass;
  541. begin
  542. Result := TTBChevronItem;
  543. end;
  544. procedure TTBCustomToolbar.CreateWrappersForAllControls;
  545. { Create wrappers for any controls that don't already have them }
  546. var
  547. L: TList;
  548. I, J, C: Integer;
  549. begin
  550. if ControlCount = 0 then
  551. Exit;
  552. L := TList.Create;
  553. try
  554. L.Capacity := ControlCount;
  555. for I := 0 to ControlCount-1 do
  556. L.Add(Controls[I]);
  557. C := FItem.Count-1;
  558. for I := 0 to C do
  559. if FItem[I] is TTBControlItem then begin
  560. J := L.IndexOf(TTBControlItem(FItem[I]).Control);
  561. if J <> -1 then
  562. L[J] := nil;
  563. end;
  564. for I := 0 to L.Count-1 do
  565. if Assigned(L[I]) then
  566. CreateWrapper(FItem.Count, L[I]);
  567. finally
  568. L.Free;
  569. end;
  570. end;
  571. procedure TTBCustomToolbar.Loaded;
  572. begin
  573. CreateWrappersForAllControls;
  574. inherited;
  575. end;
  576. procedure TTBCustomToolbar.GetChildren(Proc: TGetChildProc; Root: TComponent);
  577. begin
  578. TTBCustomItemAccess(FItem).GetChildren(Proc, Root);
  579. inherited;
  580. end;
  581. procedure TTBCustomToolbar.SetChildOrder(Child: TComponent; Order: Integer);
  582. begin
  583. if Child is TTBCustomItem then
  584. TTBCustomItemAccess(FItem).SetChildOrder(Child, Order);
  585. end;
  586. procedure TTBCustomToolbar.AlignControls(AControl: TControl; var Rect: TRect);
  587. { VCL calls this whenever any child controls in the toolbar are moved, sized,
  588. inserted, etc., and also when the toolbar is resized. }
  589. begin
  590. if FDisableAlignArrange = 0 then
  591. Arrange;
  592. end;
  593. procedure TTBCustomToolbar.InitiateAction;
  594. begin
  595. inherited;
  596. {}{ also add this to popupmenu(?) }
  597. { Update visible top-level items }
  598. if FUpdateActions then
  599. FView.InitiateActions;
  600. end;
  601. procedure TTBCustomToolbar.CMColorChanged(var Message: TMessage);
  602. begin
  603. { Synchronize FView.BackgroundColor with the new color }
  604. if Assigned(FView) then
  605. FView.BackgroundColor := Color;
  606. inherited;
  607. end;
  608. function TTBCustomToolbar.CreateWrapper(Index: Integer;
  609. Ctl: TControl): TTBControlItem;
  610. var
  611. I: Integer;
  612. S: String;
  613. begin
  614. Result := TTBControlItem.CreateControlItem(Owner, Ctl);
  615. if (csDesigning in ComponentState) and Assigned(Owner) then begin
  616. { Needs a name for compatibility with form inheritance }
  617. I := 1;
  618. while True do begin
  619. S := Format('TBControlItem%d', [I]);
  620. if Owner.FindComponent(S) = nil then
  621. Break;
  622. Inc(I);
  623. end;
  624. Result.Name := S;
  625. end;
  626. FItem.Insert(Index, Result);
  627. end;
  628. function TTBCustomToolbar.FindWrapper(Ctl: TControl): TTBControlItem;
  629. var
  630. I: Integer;
  631. Item: TTBCustomItem;
  632. begin
  633. Result := nil;
  634. for I := 0 to FItem.Count-1 do begin
  635. Item := FItem[I];
  636. if (Item is TTBControlItem) and
  637. (TTBControlItem(Item).Control = Ctl) then begin
  638. Result := TTBControlItem(Item);
  639. Break;
  640. end;
  641. end;
  642. end;
  643. procedure TTBCustomToolbar.CMControlChange(var Message: TCMControlChange);
  644. { A CM_CONTROLCHANGE handler must be used instead of a CM_CONTROLLISTCHANGE
  645. handler because when a CM_CONTROLLISTCHANGE message is sent it is relayed to
  646. *all* parents. CM_CONTROLCHANGE messages are only sent to the immediate
  647. parent. }
  648. begin
  649. inherited;
  650. { Don't automatically create TTBControlItem wrappers if the component
  651. is loading or being updated to reflect changes in an ancestor form,
  652. because wrappers will be streamed in }
  653. if Message.Inserting and not(csLoading in ComponentState) and
  654. not(csUpdating in ComponentState) and
  655. (FindWrapper(Message.Control) = nil) then
  656. CreateWrapper(FItem.Count, Message.Control);
  657. end;
  658. procedure TTBCustomToolbar.CMControlListChange(var Message: TCMControlListChange);
  659. { Don't handle deletions inside CM_CONTROLCHANGE because CM_CONTROLCHANGE is
  660. sent *before* a control begins removing itself from its parent. (It used
  661. to handle both insertions and deletions inside CM_CONTROLCHANGE but this
  662. caused AV's.) }
  663. var
  664. Item: TTBControlItem;
  665. begin
  666. inherited;
  667. if not Message.Inserting and Assigned(FItem) then begin
  668. while True do begin
  669. Item := FindWrapper(Message.Control);
  670. if Item = nil then Break;
  671. { The control is being removed the control, not necessarily destroyed,
  672. so set DontFreeControl to True }
  673. Item.DontFreeControl := True;
  674. Item.Free;
  675. end;
  676. end;
  677. end;
  678. procedure TTBCustomToolbar.CMHintShow(var Message: TCMHintShow);
  679. { Since the items on a toolbar aren't "real" controls, it needs a CM_HINTSHOW
  680. handler for their hints to be displayed. }
  681. var
  682. V: TTBItemViewer;
  683. begin
  684. with Message.HintInfo^ do begin
  685. HintStr := '';
  686. V := FView.ViewerFromPoint(CursorPos);
  687. if Assigned(V) then begin
  688. if not IsRectEmpty(V.BoundsRect) then begin
  689. CursorRect := V.BoundsRect;
  690. HintStr := V.GetHintText;
  691. end;
  692. end;
  693. end;
  694. end;
  695. procedure TTBCustomToolbar.CMShowHintChanged(var Message: TMessage);
  696. begin
  697. inherited;
  698. if ShowHint then
  699. FView.Style := FView.Style + [vsAlwaysShowHints]
  700. else
  701. FView.Style := FView.Style - [vsAlwaysShowHints];
  702. end;
  703. procedure TTBCustomToolbar.WMGetObject(var Message: TMessage);
  704. begin
  705. if not FView.HandleWMGetObject(Message) then
  706. inherited;
  707. end;
  708. procedure TTBCustomToolbar.WMSetCursor(var Message: TWMSetCursor);
  709. var
  710. P: TPoint;
  711. Cursor: HCURSOR;
  712. R: TRect;
  713. begin
  714. if not(csDesigning in ComponentState) and
  715. (Message.CursorWnd = WindowHandle) and
  716. (Smallint(Message.HitTest) = HTCLIENT) then begin
  717. GetCursorPos(P);
  718. FView.UpdateSelection(@P, True);
  719. if Assigned(FView.Selected) then begin
  720. Cursor := 0;
  721. R := FView.Selected.BoundsRect;
  722. P := ScreenToClient(P);
  723. Dec(P.X, R.Left);
  724. Dec(P.Y, R.Top);
  725. TTBItemViewerAccess(FView.Selected).GetCursor(P, Cursor);
  726. if Cursor <> 0 then begin
  727. SetCursor(Cursor);
  728. Message.Result := 1;
  729. Exit;
  730. end;
  731. end;
  732. end;
  733. inherited;
  734. end;
  735. procedure TTBCustomToolbar.WMSysCommand(var Message: TWMSysCommand);
  736. begin
  737. if FMenuBar and Enabled and Showing then
  738. with Message do
  739. if (CmdType and $FFF0 = SC_KEYMENU) and (Key <> VK_SPACE) and
  740. (GetCapture = 0) then begin
  741. if not KeyboardOpen(Char(Key), False) then begin
  742. if Key = Ord('-') then Exit;
  743. MessageBeep(0);
  744. end;
  745. Result := 1;
  746. end;
  747. end;
  748. procedure TTBCustomToolbar.Paint;
  749. var
  750. R: TRect;
  751. begin
  752. { Draw dotted border in design mode on undocked toolbars }
  753. if not Docked and (csDesigning in ComponentState) then
  754. with Canvas do begin
  755. R := ClientRect;
  756. Pen.Style := psDot;
  757. Pen.Color := clBtnShadow;
  758. Brush.Style := bsClear;
  759. Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  760. Pen.Style := psSolid;
  761. end;
  762. FView.DrawSubitems(Canvas);
  763. end;
  764. procedure TTBCustomToolbar.CMDialogKey(var Message: TCMDialogKey);
  765. begin
  766. if (Message.CharCode = VK_MENU) and FMenuBar then
  767. FView.SetAccelsVisibility(True);
  768. inherited;
  769. end;
  770. procedure TTBCustomToolbar.CMDialogChar(var Message: TCMDialogChar);
  771. begin
  772. { On toolbars that aren't menu bars, handle CM_DIALOGCHAR instead of
  773. WM_SYSCOMMAND }
  774. if not FMenuBar and Enabled and Showing and (Message.CharCode <> 0) then
  775. if KeyboardOpen(Chr(Message.CharCode), True) then begin
  776. Message.Result := 1;
  777. Exit;
  778. end;
  779. inherited;
  780. end;
  781. procedure TTBCustomToolbar.CancelHover;
  782. begin
  783. if not MouseCapture then
  784. FView.UpdateSelection(nil, True);
  785. end;
  786. procedure TTBCustomToolbar.CMMouseLeave(var Message: TMessage);
  787. begin
  788. CancelHover;
  789. inherited;
  790. end;
  791. procedure TTBCustomToolbar.DoContextPopup(MousePos: TPoint;
  792. var Handled: Boolean);
  793. begin
  794. CancelHover;
  795. inherited;
  796. end;
  797. procedure TTBCustomToolbar.MouseMove(Shift: TShiftState; X, Y: Integer);
  798. var
  799. P: TPoint;
  800. Item: TTBCustomItem;
  801. begin
  802. if not(csDesigning in ComponentState) then begin
  803. P := ClientToScreen(Point(X, Y));
  804. FView.UpdateSelection(@P, True);
  805. if Assigned(FView.Selected) then begin
  806. Item := FView.Selected.Item;
  807. if not(tboLongHintInMenuOnly in Item.EffectiveOptions) then
  808. Hint := Item.Hint
  809. else
  810. Hint := '';
  811. with TTBItemViewerAccess(FView.Find(Item)) do
  812. begin
  813. MouseMove(X - BoundsRect.Left, Y - BoundsRect.Top);
  814. end;
  815. end
  816. else
  817. Hint := '';
  818. end;
  819. { Call TrackMouseEvent to be sure that we are notified when the mouse leaves
  820. the window. We won't get a CM_MOUSELEAVE message if the mouse moves
  821. directly from the toolbar to another application's window }
  822. CallTrackMouseEvent(Handle, TME_LEAVE);
  823. inherited;
  824. end;
  825. procedure TTBCustomToolbar.WMCancelMode(var Message: TWMCancelMode);
  826. begin
  827. inherited;
  828. { We can receive a WM_CANCELMODE message during a modal loop if a dialog
  829. pops up. Respond by hiding menus to make it look like the modal loop
  830. has returned, even though it really hasn't yet.
  831. Note: Similar code in TTBModalHandler.WndProc. }
  832. if vsModal in FView.State then
  833. FView.CancelMode;
  834. end;
  835. procedure TTBCustomToolbar.WMMouseLeave(var Message: TMessage);
  836. begin
  837. { A WM_MOUSELEAVE handler is necessary because the control won't get a
  838. CM_MOUSELEAVE message if the user presses Alt+Space. Also, CM_MOUSELEAVE
  839. messages are also not sent if the application is in a
  840. Application.ProcessMessages loop. }
  841. if not FIgnoreMouseLeave then
  842. CancelHover;
  843. inherited;
  844. end;
  845. procedure TTBCustomToolbar.WMNCMouseMove(var Message: TWMNCMouseMove);
  846. begin
  847. Hint := '';
  848. CancelHover;
  849. inherited;
  850. end;
  851. function TTBCustomToolbar.KeyboardOpen(Key: Char;
  852. RequirePrimaryAccel: Boolean): Boolean;
  853. var
  854. I: TTBItemViewer;
  855. IsOnlyItemWithAccel: Boolean;
  856. begin
  857. I := nil;
  858. FView.SetAccelsVisibility(True);
  859. try
  860. Result := False;
  861. if Key = #0 then begin
  862. I := FView.FirstSelectable;
  863. if I = nil then Exit;
  864. FView.Selected := I;
  865. FView.EnterToolbarLoop([]);
  866. end
  867. else begin
  868. I := FView.NextSelectableWithAccel(nil, Key, RequirePrimaryAccel,
  869. IsOnlyItemWithAccel);
  870. if (I = nil) or not I.Item.Enabled then
  871. Exit;
  872. if IsOnlyItemWithAccel then begin
  873. FView.Selected := I;
  874. FView.EnterToolbarLoop([tbetExecuteSelected]);
  875. end
  876. else if FMenuBar then begin
  877. FView.Selected := I;
  878. FView.EnterToolbarLoop([]);
  879. end
  880. else
  881. Exit;
  882. end;
  883. Result := True;
  884. finally
  885. if Assigned(I) then
  886. FView.SetAccelsVisibility(False);
  887. end;
  888. end;
  889. procedure TTBCustomToolbar.MouseDown(Button: TMouseButton; Shift: TShiftState;
  890. X, Y: Integer);
  891. var
  892. OldParent: TWinControl;
  893. P: TPoint;
  894. Item: TTBCustomItem;
  895. begin
  896. OldParent := Parent;
  897. inherited;
  898. if Parent <> OldParent then
  899. { if the inherited handler (TTBDockableWindow.MouseDown) changed the Parent
  900. (due to the toolbar moving between docks), nothing else should be done }
  901. Exit;
  902. if not(csDesigning in ComponentState) and (Button = mbLeft) then begin
  903. P := ClientToScreen(Point(X, Y));
  904. FView.UpdateSelection(@P, True);
  905. if Assigned(FView.Selected) then begin
  906. Item := FView.Selected.Item;
  907. if not(tbisClicksTransparent in TTBCustomItemAccess(Item).ItemStyle) then begin
  908. FIgnoreMouseLeave := True;
  909. try
  910. FView.EnterToolbarLoop([tbetMouseDown]);
  911. finally
  912. FIgnoreMouseLeave := False;
  913. end;
  914. end;
  915. end;
  916. end;
  917. end;
  918. procedure TTBCustomToolbar.CMFontChanged(var Message: TMessage);
  919. begin
  920. inherited;
  921. if not FSystemFont then
  922. Arrange;
  923. end;
  924. function TTBCustomToolbar.GetChevronHint: String;
  925. begin
  926. Result := FChevronItem.Hint;
  927. end;
  928. procedure TTBCustomToolbar.SetChevronHint(const Value: String);
  929. begin
  930. FChevronItem.Hint := Value;
  931. FChevronItem.Caption := EscapeAmpersands(GetShortHint(Value));
  932. end;
  933. procedure TTBCustomToolbar.SetChevronMoveItems(Value: Boolean);
  934. begin
  935. if FChevronMoveItems <> Value then begin
  936. FChevronMoveItems := Value;
  937. FView.UsePriorityList := Value and not(csDesigning in ComponentState);
  938. end;
  939. end;
  940. procedure TTBCustomToolbar.SetChevronPriorityForNewItems(Value: TTBChevronPriorityForNewItems);
  941. begin
  942. FChevronPriorityForNewItems := Value;
  943. FView.NewViewersGetHighestPriority := (Value = tbcpHighest);
  944. end;
  945. function TTBCustomToolbar.IsChevronHintStored: Boolean;
  946. begin
  947. Result := (FChevronItem.Hint <> FChevronItem.GetDefaultHint);
  948. end;
  949. function TTBCustomToolbar.GetImages: TCustomImageList;
  950. begin
  951. Result := FItem.SubMenuImages;
  952. end;
  953. procedure TTBCustomToolbar.SetImages(Value: TCustomImageList);
  954. begin
  955. FItem.SubMenuImages := Value;
  956. end;
  957. function TTBCustomToolbar.GetLinkSubitems: TTBCustomItem;
  958. begin
  959. Result := FItem.LinkSubitems;
  960. end;
  961. procedure TTBCustomToolbar.SetLinkSubitems(Value: TTBCustomItem);
  962. begin
  963. FItem.LinkSubitems := Value;
  964. end;
  965. procedure TTBCustomToolbar.SetMenuBar(Value: Boolean);
  966. begin
  967. if FMenuBar <> Value then begin
  968. FMenuBar := Value;
  969. if Value then begin
  970. ControlStyle := ControlStyle + [csMenuEvents];
  971. FView.Style := FView.Style + [vsMenuBar];
  972. end
  973. else begin
  974. ControlStyle := ControlStyle - [csMenuEvents];
  975. FView.Style := FView.Style - [vsMenuBar];
  976. end;
  977. if not(csLoading in ComponentState) then begin
  978. FullSize := Value;
  979. if Value then
  980. ShrinkMode := tbsmWrap
  981. else
  982. ShrinkMode := tbsmChevron;
  983. CloseButton := not Value;
  984. ProcessShortCuts := Value;
  985. end;
  986. if Value and not(csDesigning in ComponentState) then
  987. InstallHookProc(Self, HookProc, [hpGetMessage])
  988. else
  989. UninstallHookProc(Self, HookProc);
  990. SetMainWindowHook;
  991. end;
  992. end;
  993. function TTBCustomToolbar.GetOptions: TTBItemOptions;
  994. begin
  995. Result := FItem.Options;
  996. end;
  997. procedure TTBCustomToolbar.SetOptions(Value: TTBItemOptions);
  998. begin
  999. FItem.Options := Value;
  1000. end;
  1001. procedure TTBCustomToolbar.SetProcessShortCuts(Value: Boolean);
  1002. begin
  1003. if FProcessShortCuts <> Value then begin
  1004. FProcessShortCuts := Value;
  1005. SetMainWindowHook;
  1006. end;
  1007. end;
  1008. procedure TTBCustomToolbar.SetSystemFont(Value: Boolean);
  1009. begin
  1010. if FSystemFont <> Value then begin
  1011. FSystemFont := Value;
  1012. Arrange;
  1013. end;
  1014. end;
  1015. procedure TTBCustomToolbar.SetShrinkMode(Value: TTBShrinkMode);
  1016. begin
  1017. if FShrinkMode <> Value then begin
  1018. FShrinkMode := Value;
  1019. if Docked then
  1020. CurrentDock.ArrangeToolbars
  1021. else if not Floating then
  1022. Arrange;
  1023. end;
  1024. end;
  1025. procedure TTBCustomToolbar.SetFloatingWidth(Value: Integer);
  1026. begin
  1027. if FFloatingWidth <> Value then begin
  1028. FFloatingWidth := Value;
  1029. if Floating then begin
  1030. UpdateViewProperties;
  1031. Arrange;
  1032. end;
  1033. end;
  1034. end;
  1035. function TTBCustomToolbar.CalcWrapOffset(const ADock: TTBDock): Integer;
  1036. begin
  1037. if ADock = nil then
  1038. Result := FFloatingWidth
  1039. else begin
  1040. if FShrinkMode = tbsmWrap then begin
  1041. if not(ADock.Position in [dpLeft, dpRight]) then
  1042. Result := ADock.Width - ADock.NonClientWidth - NonClientWidth
  1043. else
  1044. Result := ADock.Height - ADock.NonClientHeight - NonClientHeight;
  1045. end
  1046. else
  1047. Result := 0;
  1048. end;
  1049. end;
  1050. function TTBCustomToolbar.CalcChevronOffset(const ADock: TTBDock;
  1051. const AOrientation: TTBViewOrientation): Integer;
  1052. begin
  1053. if (FShrinkMode = tbsmChevron) and Docked and (ADock = CurrentDock) then begin
  1054. Result := CurrentSize;
  1055. { Subtract non-client size }
  1056. if AOrientation <> tbvoVertical then
  1057. Dec(Result, NonClientWidth)
  1058. else
  1059. Dec(Result, NonClientHeight);
  1060. if Result < 0 then
  1061. Result := 0; { in case CurrentSize wasn't properly initialized yet }
  1062. end
  1063. else
  1064. Result := 0;
  1065. end;
  1066. procedure TTBCustomToolbar.UpdateViewProperties;
  1067. var
  1068. DT: TTBDockType;
  1069. begin
  1070. DT := TBGetDockTypeOf(CurrentDock, Floating);
  1071. FView.Orientation := DockTypeToOrientation[DT];
  1072. FView.ChevronSize := tbChevronSize;
  1073. if Assigned(CurrentDock) or Floating then begin
  1074. FView.ChevronOffset := CalcChevronOffset(CurrentDock, FView.Orientation);
  1075. FView.WrapOffset := CalcWrapOffset(CurrentDock);
  1076. end
  1077. else begin
  1078. FView.ChevronOffset := 0;
  1079. FView.WrapOffset := 0;
  1080. { Only enable chevron/wrapping when the width of the toolbar is fixed }
  1081. if not AutoResize or ((akLeft in Anchors) and (akRight in Anchors)) then begin
  1082. if FShrinkMode = tbsmChevron then
  1083. FView.ChevronOffset := Width - NonClientWidth
  1084. else if FShrinkMode = tbsmWrap then
  1085. FView.WrapOffset := Width - NonClientWidth;
  1086. end;
  1087. end;
  1088. end;
  1089. {}{DOCKING STUFF}
  1090. procedure TTBCustomToolbar.ReadPositionData(var S: string);
  1091. begin
  1092. inherited;
  1093. if Floating then
  1094. FloatingWidth := StrToIntDef(CutToChar(S, ':', true), 0);
  1095. end;
  1096. function TTBCustomToolbar.WritePositionData: string;
  1097. begin
  1098. Result := inherited;
  1099. if Floating then
  1100. Result := Result + ':' + IntToStr(FFloatingWidth);
  1101. end;
  1102. procedure TTBCustomToolbar.GetMinBarSize(var MinimumSize: TPoint);
  1103. var
  1104. WH: Integer;
  1105. begin
  1106. MinimumSize.X := 0;
  1107. MinimumSize.Y := 0;
  1108. if Docked then begin
  1109. WH := CurrentDock.GetMinRowSize(EffectiveDockRow, Self);
  1110. if not(CurrentDock.Position in [dpLeft, dpRight]) then
  1111. MinimumSize.Y := WH
  1112. else
  1113. MinimumSize.X := WH;
  1114. end;
  1115. end;
  1116. procedure TTBCustomToolbar.GetBaseSize(var ASize: TPoint);
  1117. begin
  1118. FView.ValidatePositions;
  1119. ASize := FBaseSize;
  1120. { MP }
  1121. if Assigned(FOnGetBaseSize) then FOnGetBaseSize(Self, ASize);
  1122. end;
  1123. function TTBCustomToolbar.DoArrange(CanMoveControls: Boolean;
  1124. PreviousDockType: TTBDockType; NewFloating: Boolean; NewDock: TTBDock): TPoint;
  1125. var
  1126. DT: TTBDockType;
  1127. O: TTBViewOrientation;
  1128. TempBaseSize: TPoint;
  1129. begin
  1130. //outputdebugstring (pchar(format('%s.DoArrange(%d)', [Name, Ord(CanMoveControls)])));
  1131. if CanMoveControls then begin
  1132. UpdateViewProperties;
  1133. Result := FView.UpdatePositions;
  1134. end
  1135. else begin
  1136. DT := TBGetDockTypeOf(NewDock, NewFloating);
  1137. O := DockTypeToOrientation[DT];
  1138. Result.X := 0;
  1139. Result.Y := 0;
  1140. FView.CalculatePositions(False, O, CalcWrapOffset(NewDock),
  1141. CalcChevronOffset(NewDock, O), tbChevronSize, TempBaseSize, Result,
  1142. FLastWrappedLines);
  1143. end;
  1144. end;
  1145. procedure TTBCustomToolbar.ControlExistsAtPos(const P: TPoint;
  1146. var ControlExists: Boolean);
  1147. var
  1148. P2: TPoint;
  1149. begin
  1150. inherited;
  1151. if not ControlExists and not(csDesigning in ComponentState) then begin
  1152. P2 := ClientToScreen(P);
  1153. FView.UpdateSelection(@P2, True);
  1154. if Assigned(FView.Selected) and
  1155. not(tbisClicksTransparent in TTBCustomItemAccess(FView.Selected.Item).ItemStyle) then
  1156. ControlExists := True;
  1157. end;
  1158. end;
  1159. procedure TTBCustomToolbar.BuildPotentialSizesList(SizesList: TList);
  1160. var
  1161. Margins: TRect;
  1162. MinX, SaveWrapX: Integer;
  1163. X, PrevWrappedLines: Integer;
  1164. S: TPoint;
  1165. S2: TSmallPoint;
  1166. begin
  1167. View.GetMargins(tbvoFloating, Margins);
  1168. MinX := Margins.Left + Margins.Right;
  1169. SaveWrapX := FFloatingWidth;
  1170. try
  1171. { Add the widest size to the list }
  1172. FFloatingWidth := 0;
  1173. S := DoArrange(False, dtNotDocked, True, nil);
  1174. SizesList.Add(Pointer(PointToSmallPoint(S)));
  1175. { Calculate and add rest of sizes to the list }
  1176. PrevWrappedLines := 1;
  1177. X := S.X-1;
  1178. while X >= MinX do begin
  1179. FFloatingWidth := X;
  1180. S := DoArrange(False, dtNotDocked, True, nil);
  1181. if S.X > X then { if it refuses to go any smaller }
  1182. Break
  1183. else
  1184. if X = S.X then begin
  1185. S2 := PointToSmallPoint(S);
  1186. if FLastWrappedLines <> PrevWrappedLines then
  1187. SizesList.Add(Pointer(S2))
  1188. else
  1189. SizesList[SizesList.Count-1] := Pointer(S2);
  1190. PrevWrappedLines := FLastWrappedLines;
  1191. Dec(X);
  1192. end
  1193. else
  1194. X := S.X;
  1195. end;
  1196. finally
  1197. FFloatingWidth := SaveWrapX;
  1198. end;
  1199. end;
  1200. function CompareNewSizes(const Item1, Item2, ExtraData: Pointer): Integer; far;
  1201. begin
  1202. { Sorts in descending order }
  1203. if ExtraData = nil then
  1204. Result := TSmallPoint(Item2).X - TSmallPoint(Item1).X
  1205. else
  1206. Result := TSmallPoint(Item2).Y - TSmallPoint(Item1).Y;
  1207. end;
  1208. procedure TTBCustomToolbar.ResizeBegin(ASizeHandle: TTBSizeHandle);
  1209. const
  1210. MaxSizeSens = 12;
  1211. var
  1212. I, NewSize: Integer;
  1213. S, N: TSmallPoint;
  1214. P: TPoint;
  1215. begin
  1216. inherited;
  1217. FSizeData := AllocMem(SizeOf(TToolbar97SizeData));
  1218. with PToolbar97SizeData(FSizeData)^ do begin
  1219. SizeHandle := ASizeHandle;
  1220. OrigLeft := Parent.Left;
  1221. OrigTop := Parent.Top;
  1222. OrigWidth := Parent.Width;
  1223. OrigHeight := Parent.Height;
  1224. NCXDiff := ClientToScreen(Point(0, 0)).X - OrigLeft;
  1225. CurRightX := FFloatingWidth;
  1226. DisableSensCheck := False;
  1227. OpSide := False;
  1228. NewSizes := TList.Create;
  1229. BuildPotentialSizesList(NewSizes);
  1230. for I := 0 to NewSizes.Count-1 do begin
  1231. P := SmallPointToPoint(TSmallPoint(NewSizes.List[I]));
  1232. AddFloatingNCAreaToSize(P);
  1233. NewSizes.List[I] := Pointer(PointToSmallPoint(P));
  1234. end;
  1235. ListSortEx(NewSizes, CompareNewSizes,
  1236. Pointer(Ord(ASizeHandle in [twshTop, twshBottom])));
  1237. SizeSens := MaxSizeSens;
  1238. { Adjust sensitivity if it's too high }
  1239. for I := 0 to NewSizes.Count-1 do begin
  1240. Pointer(S) := NewSizes[I];
  1241. if (S.X = Width) and (S.Y = Height) then begin
  1242. if I > 0 then begin
  1243. Pointer(N) := NewSizes[I-1];
  1244. if ASizeHandle in [twshLeft, twshRight] then
  1245. NewSize := N.X - S.X - 1
  1246. else
  1247. NewSize := N.Y - S.Y - 1;
  1248. if NewSize < SizeSens then SizeSens := NewSize;
  1249. end;
  1250. if I < NewSizes.Count-1 then begin
  1251. Pointer(N) := NewSizes[I+1];
  1252. if ASizeHandle in [twshLeft, twshRight] then
  1253. NewSize := S.X - N.X - 1
  1254. else
  1255. NewSize := S.Y - N.Y - 1;
  1256. if NewSize < SizeSens then SizeSens := NewSize;
  1257. end;
  1258. Break;
  1259. end;
  1260. end;
  1261. if SizeSens < 0 then SizeSens := 0;
  1262. end;
  1263. end;
  1264. procedure TTBCustomToolbar.ResizeTrack(var Rect: TRect; const OrigRect: TRect);
  1265. var
  1266. Pos: TPoint;
  1267. NewOpSide: Boolean;
  1268. Reverse: Boolean;
  1269. I: Integer;
  1270. P: TSmallPoint;
  1271. begin
  1272. inherited;
  1273. with PToolbar97SizeData(FSizeData)^ do begin
  1274. GetCursorPos(Pos);
  1275. Dec(Pos.X, OrigLeft); Dec(Pos.Y, OrigTop);
  1276. if SizeHandle = twshLeft then
  1277. Pos.X := OrigWidth-Pos.X
  1278. else
  1279. if SizeHandle = twshTop then
  1280. Pos.Y := OrigHeight-Pos.Y;
  1281. { Adjust Pos to make up for the "sizing sensitivity", as seen in Office 97 }
  1282. if SizeHandle in [twshLeft, twshRight] then
  1283. NewOpSide := Pos.X < OrigWidth
  1284. else
  1285. NewOpSide := Pos.Y < OrigHeight;
  1286. if (not DisableSensCheck) or (OpSide <> NewOpSide) then begin
  1287. DisableSensCheck := False;
  1288. OpSide := NewOpSide;
  1289. if SizeHandle in [twshLeft, twshRight] then begin
  1290. if (Pos.X >= OrigWidth-SizeSens) and (Pos.X < OrigWidth+SizeSens) then
  1291. Pos.X := OrigWidth;
  1292. end
  1293. else begin
  1294. if (Pos.Y >= OrigHeight-SizeSens) and (Pos.Y < OrigHeight+SizeSens) then
  1295. Pos.Y := OrigHeight;
  1296. end;
  1297. end;
  1298. Rect := OrigRect;
  1299. if SizeHandle in [twshLeft, twshRight] then
  1300. Reverse := Pos.X > OrigWidth
  1301. else
  1302. Reverse := Pos.Y > OrigHeight;
  1303. if not Reverse then
  1304. I := NewSizes.Count-1
  1305. else
  1306. I := 0;
  1307. while True do begin
  1308. if (not Reverse and (I < 0)) or
  1309. (Reverse and (I >= NewSizes.Count)) then
  1310. Break;
  1311. Pointer(P) := NewSizes[I];
  1312. if SizeHandle in [twshLeft, twshRight] then begin
  1313. if (not Reverse and ((I = NewSizes.Count-1) or (Pos.X >= P.X))) or
  1314. (Reverse and ((I = 0) or (Pos.X < P.X))) then begin
  1315. if I = 0 then
  1316. CurRightX := 0
  1317. else
  1318. CurRightX := P.X - NCXDiff*2;
  1319. if SizeHandle = twshRight then
  1320. Rect.Right := Rect.Left + P.X
  1321. else
  1322. Rect.Left := Rect.Right - P.X;
  1323. Rect.Bottom := Rect.Top + P.Y;
  1324. DisableSensCheck := not EqualRect(Rect, OrigRect);
  1325. end;
  1326. end
  1327. else begin
  1328. if (not Reverse and ((I = NewSizes.Count-1) or (Pos.Y >= P.Y))) or
  1329. (Reverse and ((I = 0) or (Pos.Y < P.Y))) then begin
  1330. if I = NewSizes.Count-1 then
  1331. CurRightX := 0
  1332. else
  1333. CurRightX := P.X - NCXDiff*2;
  1334. if SizeHandle = twshBottom then
  1335. Rect.Bottom := Rect.Top + P.Y
  1336. else
  1337. Rect.Top := Rect.Bottom - P.Y;
  1338. Rect.Right := Rect.Left + P.X;
  1339. DisableSensCheck := not EqualRect(Rect, OrigRect);
  1340. end;
  1341. end;
  1342. if not Reverse then
  1343. Dec(I)
  1344. else
  1345. Inc(I);
  1346. end;
  1347. end;
  1348. end;
  1349. procedure TTBCustomToolbar.ResizeTrackAccept;
  1350. begin
  1351. inherited;
  1352. FloatingWidth := PToolbar97SizeData(FSizeData)^.CurRightX;
  1353. end;
  1354. procedure TTBCustomToolbar.ResizeEnd;
  1355. begin
  1356. inherited;
  1357. if Assigned(FSizeData) then begin
  1358. PToolbar97SizeData(FSizeData)^.NewSizes.Free;
  1359. FreeMem(FSizeData);
  1360. FSizeData := nil;
  1361. end;
  1362. end;
  1363. function TTBCustomToolbar.GetShrinkMode: TTBShrinkMode;
  1364. begin
  1365. Result := FShrinkMode;
  1366. end;
  1367. procedure TTBCustomToolbar.GetMinShrinkSize(var AMinimumSize: Integer);
  1368. var
  1369. I: TTBItemViewer;
  1370. begin
  1371. I := FView.HighestPriorityViewer;
  1372. if Assigned(I) then begin
  1373. if not(CurrentDock.Position in [dpLeft, dpRight]) then
  1374. AMinimumSize := I.BoundsRect.Right - I.BoundsRect.Left
  1375. else
  1376. AMinimumSize := I.BoundsRect.Bottom - I.BoundsRect.Top;
  1377. end;
  1378. if not(CurrentDock.Position in [dpLeft, dpRight]) then
  1379. Inc(AMinimumSize, NonClientWidth)
  1380. else
  1381. Inc(AMinimumSize, NonClientHeight);
  1382. Inc(AMinimumSize, tbChevronSize);
  1383. end;
  1384. procedure TTBCustomToolbar.BeginUpdate;
  1385. begin
  1386. FView.BeginUpdate;
  1387. end;
  1388. procedure TTBCustomToolbar.EndUpdate;
  1389. begin
  1390. FView.EndUpdate;
  1391. end;
  1392. procedure TTBCustomToolbar.GetTabOrderList(List: TList);
  1393. var
  1394. CtlList: TList;
  1395. I, J: Integer;
  1396. CtlI, CtlJ: TWinControl;
  1397. begin
  1398. inherited;
  1399. { Remove off-edge items and their children from List }
  1400. CtlList := TList.Create;
  1401. try
  1402. FView.GetOffEdgeControlList(CtlList);
  1403. for I := 0 to CtlList.Count-1 do begin
  1404. CtlI := CtlList[I];
  1405. J := 0;
  1406. while J < List.Count do begin
  1407. CtlJ := List[J];
  1408. if (CtlJ = CtlI) or CtlI.ContainsControl(CtlJ) then
  1409. List.Delete(J)
  1410. else
  1411. Inc(J);
  1412. end;
  1413. end;
  1414. finally
  1415. CtlList.Free;
  1416. end;
  1417. end;
  1418. procedure TTBCustomToolbar.CMWinIniChange(var Message: TWMSettingChange);
  1419. begin
  1420. inherited;
  1421. if Message.Flag = SPI_SETNONCLIENTMETRICS then begin
  1422. TBInitToolbarSystemFont;
  1423. Arrange;
  1424. end;
  1425. end;
  1426. function TTBCustomToolbar.IsShortCut(var Message: TWMKey): Boolean;
  1427. begin
  1428. Result := False;
  1429. if Assigned(FOnShortCut) then
  1430. FOnShortCut(Message, Result);
  1431. Result := Result or FItem.IsShortCut(Message);
  1432. end;
  1433. var
  1434. HookCount: Integer;
  1435. HookList: TList;
  1436. class function TTBCustomToolbar.MainWindowHook(var Message: TMessage): Boolean;
  1437. function GetActiveForm: TCustomForm;
  1438. var
  1439. Wnd: HWND;
  1440. Ctl: TWinControl;
  1441. begin
  1442. { Note: We don't use Screen.ActiveCustomForm because when an EXE calls a
  1443. DLL that shows a modal form, Screen.ActiveCustomForm doesn't change in
  1444. the EXE; it remains set to the last form that was active in the EXE.
  1445. Use FindControl(GetActiveWindow) instead to avoid this problem; it will
  1446. return nil when a form in another module is active. }
  1447. Result := nil;
  1448. Wnd := GetActiveWindow;
  1449. if Wnd <> 0 then begin
  1450. Ctl := FindControl(Wnd);
  1451. if Assigned(Ctl) and (Ctl is TCustomForm) then
  1452. Result := TCustomForm(Ctl);
  1453. end;
  1454. end;
  1455. function HandleShortCutOnForm(const Form: TCustomForm): Boolean;
  1456. var
  1457. I: Integer;
  1458. Toolbar: TTBCustomToolbar;
  1459. begin
  1460. Result := False;
  1461. if Form = nil then
  1462. Exit;
  1463. for I := 0 to HookList.Count-1 do begin
  1464. Toolbar := HookList[I];
  1465. if Toolbar.ProcessShortCuts and
  1466. (TBGetToolWindowParentForm(Toolbar) = Form) and
  1467. IsWindowEnabled(Form.Handle) and
  1468. Toolbar.IsShortCut(TWMKey(Message)) then begin
  1469. Message.Result := 1;
  1470. Result := True;
  1471. Exit;
  1472. end;
  1473. end;
  1474. end;
  1475. function TraverseControls(Container: TWinControl): Boolean;
  1476. var
  1477. I: Integer;
  1478. Control: TControl;
  1479. begin
  1480. Result := False;
  1481. if Container.Showing then
  1482. for I := 0 to Container.ControlCount - 1 do begin
  1483. Control := Container.Controls[I];
  1484. if Control.Visible and Control.Enabled then begin
  1485. if (csMenuEvents in Control.ControlStyle) and
  1486. ((Control is TTBDock) or (Control is TTBCustomToolbar)) and
  1487. (Control.Perform(WM_SYSCOMMAND, TMessage(Message).WParam,
  1488. TMessage(Message).LParam) <> 0) or (Control is TWinControl) and
  1489. TraverseControls(TWinControl(Control)) then begin
  1490. Result := True;
  1491. Exit;
  1492. end;
  1493. end;
  1494. end;
  1495. end;
  1496. var
  1497. ActiveForm: TCustomForm;
  1498. ActiveMDIChild: TForm;
  1499. begin
  1500. Result := False;
  1501. if (Message.Msg = CM_APPKEYDOWN) and Assigned(HookList) then begin
  1502. { Process shortcuts on toolbars. Search forms in this order:
  1503. 1. If the active form is an MDI parent form, the active MDI child form
  1504. if it has the focus.
  1505. 2. The active form.
  1506. 3. The main form. }
  1507. ActiveForm := GetActiveForm;
  1508. if Assigned(ActiveForm) and (ActiveForm is TForm) and
  1509. (TForm(ActiveForm).FormStyle = fsMDIForm) then begin
  1510. ActiveMDIChild := TForm(ActiveForm).ActiveMDIChild;
  1511. { Don't search the child form if a control on the MDI parent form is
  1512. currently focused (i.e. Screen.ActiveCustomForm <> ActiveMDIChild) }
  1513. if Assigned(ActiveMDIChild) and
  1514. (Screen.ActiveCustomForm = ActiveMDIChild) and
  1515. HandleShortCutOnForm(ActiveMDIChild) then begin
  1516. Result := True;
  1517. Exit;
  1518. end;
  1519. end;
  1520. if HandleShortCutOnForm(ActiveForm) then
  1521. Result := True
  1522. else begin
  1523. if (Application.MainForm <> ActiveForm) and
  1524. HandleShortCutOnForm(Application.MainForm) then
  1525. Result := True;
  1526. end;
  1527. end
  1528. else if Message.Msg = CM_APPSYSCOMMAND then begin
  1529. { Handle "Alt or Alt+[key] pressed on secondary form" case. If there's a
  1530. menu bar on the active form we want the keypress to go to it instead of
  1531. to the main form (the VCL's default handling). }
  1532. ActiveForm := GetActiveForm;
  1533. if Assigned(ActiveForm) and IsWindowEnabled(ActiveForm.Handle) and
  1534. IsWindowVisible(ActiveForm.Handle) and TraverseControls(ActiveForm) then begin
  1535. Message.Result := 1;
  1536. Result := True;
  1537. end;
  1538. end;
  1539. end;
  1540. procedure TTBCustomToolbar.SetMainWindowHook;
  1541. begin
  1542. if (ProcessShortCuts or MenuBar) and not(csDesigning in ComponentState) then
  1543. InstallMainWindowHook
  1544. else
  1545. UninstallMainWindowHook;
  1546. end;
  1547. procedure TTBCustomToolbar.InstallMainWindowHook;
  1548. begin
  1549. if FMainWindowHookInstalled then
  1550. Exit;
  1551. if HookCount = 0 then
  1552. Application.HookMainWindow(MainWindowHook);
  1553. Inc(HookCount);
  1554. AddToList(HookList, Self);
  1555. FMainWindowHookInstalled := True;
  1556. end;
  1557. procedure TTBCustomToolbar.UninstallMainWindowHook;
  1558. begin
  1559. if not FMainWindowHookInstalled then
  1560. Exit;
  1561. FMainWindowHookInstalled := False;
  1562. RemoveFromList(HookList, Self);
  1563. Dec(HookCount);
  1564. if HookCount = 0 then
  1565. Application.UnhookMainWindow(MainWindowHook);
  1566. end;
  1567. procedure TTBCustomToolbar.ChangeScale(M, D: Integer);
  1568. begin
  1569. inherited;
  1570. Items.ChangeScale(M, D);
  1571. View.RecreateAllViewers;
  1572. end;
  1573. end.