TB2Toolbar.pas 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716
  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. http://www.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. http://www.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. FView.BackgroundColor := clBtnFace;
  504. FUpdateActions := True;
  505. FShrinkMode := tbsmChevron;
  506. FSystemFont := True;
  507. Color := clBtnFace;
  508. SetBounds(Left, Top, 23, 22);{}
  509. { MP }
  510. FOnGetBaseSize := nil;
  511. FOnEndModal := nil;
  512. end;
  513. destructor TTBCustomToolbar.Destroy;
  514. begin
  515. { Call Destroying to ensure csDestroying is in ComponentState now. Only
  516. needed for Delphi 4 and earlier since Delphi 5 calls Destroying in
  517. TComponent.BeforeDestruction }
  518. Destroying;
  519. UninstallHookProc(Self, HookProc);
  520. UninstallMainWindowHook;
  521. FreeAndNil(FView);
  522. FreeAndNil(FChevronItem);
  523. FreeAndNil(FItem);
  524. inherited;
  525. end;
  526. function TTBCustomToolbar.GetItems: TTBCustomItem;
  527. begin
  528. Result := FItem;
  529. end;
  530. function TTBCustomToolbar.GetItemClass: TTBRootItemClass;
  531. begin
  532. Result := TTBRootItem;
  533. end;
  534. function TTBCustomToolbar.GetViewClass: TTBToolbarViewClass;
  535. begin
  536. Result := TTBToolbarView;
  537. end;
  538. function TTBCustomToolbar.GetChevronItemClass: TTBChevronItemClass;
  539. begin
  540. Result := TTBChevronItem;
  541. end;
  542. procedure TTBCustomToolbar.CreateWrappersForAllControls;
  543. { Create wrappers for any controls that don't already have them }
  544. var
  545. L: TList;
  546. I, J, C: Integer;
  547. begin
  548. if ControlCount = 0 then
  549. Exit;
  550. L := TList.Create;
  551. try
  552. L.Capacity := ControlCount;
  553. for I := 0 to ControlCount-1 do
  554. L.Add(Controls[I]);
  555. C := FItem.Count-1;
  556. for I := 0 to C do
  557. if FItem[I] is TTBControlItem then begin
  558. J := L.IndexOf(TTBControlItem(FItem[I]).Control);
  559. if J <> -1 then
  560. L[J] := nil;
  561. end;
  562. for I := 0 to L.Count-1 do
  563. if Assigned(L[I]) then
  564. CreateWrapper(FItem.Count, L[I]);
  565. finally
  566. L.Free;
  567. end;
  568. end;
  569. procedure TTBCustomToolbar.Loaded;
  570. begin
  571. CreateWrappersForAllControls;
  572. inherited;
  573. end;
  574. procedure TTBCustomToolbar.GetChildren(Proc: TGetChildProc; Root: TComponent);
  575. begin
  576. TTBCustomItemAccess(FItem).GetChildren(Proc, Root);
  577. inherited;
  578. end;
  579. procedure TTBCustomToolbar.SetChildOrder(Child: TComponent; Order: Integer);
  580. begin
  581. if Child is TTBCustomItem then
  582. TTBCustomItemAccess(FItem).SetChildOrder(Child, Order);
  583. end;
  584. procedure TTBCustomToolbar.AlignControls(AControl: TControl; var Rect: TRect);
  585. { VCL calls this whenever any child controls in the toolbar are moved, sized,
  586. inserted, etc., and also when the toolbar is resized. }
  587. begin
  588. if FDisableAlignArrange = 0 then
  589. Arrange;
  590. end;
  591. procedure TTBCustomToolbar.InitiateAction;
  592. begin
  593. inherited;
  594. {}{ also add this to popupmenu(?) }
  595. { Update visible top-level items }
  596. if FUpdateActions then
  597. FView.InitiateActions;
  598. end;
  599. procedure TTBCustomToolbar.CMColorChanged(var Message: TMessage);
  600. begin
  601. { Synchronize FView.BackgroundColor with the new color }
  602. if Assigned(FView) then
  603. FView.BackgroundColor := Color;
  604. inherited;
  605. end;
  606. function TTBCustomToolbar.CreateWrapper(Index: Integer;
  607. Ctl: TControl): TTBControlItem;
  608. var
  609. I: Integer;
  610. S: String;
  611. begin
  612. Result := TTBControlItem.CreateControlItem(Owner, Ctl);
  613. if (csDesigning in ComponentState) and Assigned(Owner) then begin
  614. { Needs a name for compatibility with form inheritance }
  615. I := 1;
  616. while True do begin
  617. S := Format('TBControlItem%d', [I]);
  618. if Owner.FindComponent(S) = nil then
  619. Break;
  620. Inc(I);
  621. end;
  622. Result.Name := S;
  623. end;
  624. FItem.Insert(Index, Result);
  625. end;
  626. function TTBCustomToolbar.FindWrapper(Ctl: TControl): TTBControlItem;
  627. var
  628. I: Integer;
  629. Item: TTBCustomItem;
  630. begin
  631. Result := nil;
  632. for I := 0 to FItem.Count-1 do begin
  633. Item := FItem[I];
  634. if (Item is TTBControlItem) and
  635. (TTBControlItem(Item).Control = Ctl) then begin
  636. Result := TTBControlItem(Item);
  637. Break;
  638. end;
  639. end;
  640. end;
  641. procedure TTBCustomToolbar.CMControlChange(var Message: TCMControlChange);
  642. { A CM_CONTROLCHANGE handler must be used instead of a CM_CONTROLLISTCHANGE
  643. handler because when a CM_CONTROLLISTCHANGE message is sent it is relayed to
  644. *all* parents. CM_CONTROLCHANGE messages are only sent to the immediate
  645. parent. }
  646. begin
  647. inherited;
  648. { Don't automatically create TTBControlItem wrappers if the component
  649. is loading or being updated to reflect changes in an ancestor form,
  650. because wrappers will be streamed in }
  651. if Message.Inserting and not(csLoading in ComponentState) and
  652. not(csUpdating in ComponentState) and
  653. (FindWrapper(Message.Control) = nil) then
  654. CreateWrapper(FItem.Count, Message.Control);
  655. end;
  656. procedure TTBCustomToolbar.CMControlListChange(var Message: TCMControlListChange);
  657. { Don't handle deletions inside CM_CONTROLCHANGE because CM_CONTROLCHANGE is
  658. sent *before* a control begins removing itself from its parent. (It used
  659. to handle both insertions and deletions inside CM_CONTROLCHANGE but this
  660. caused AV's.) }
  661. var
  662. Item: TTBControlItem;
  663. begin
  664. inherited;
  665. if not Message.Inserting and Assigned(FItem) then begin
  666. while True do begin
  667. Item := FindWrapper(Message.Control);
  668. if Item = nil then Break;
  669. { The control is being removed the control, not necessarily destroyed,
  670. so set DontFreeControl to True }
  671. Item.DontFreeControl := True;
  672. Item.Free;
  673. end;
  674. end;
  675. end;
  676. procedure TTBCustomToolbar.CMHintShow(var Message: TCMHintShow);
  677. { Since the items on a toolbar aren't "real" controls, it needs a CM_HINTSHOW
  678. handler for their hints to be displayed. }
  679. var
  680. V: TTBItemViewer;
  681. begin
  682. with Message.HintInfo^ do begin
  683. HintStr := '';
  684. V := FView.ViewerFromPoint(CursorPos);
  685. if Assigned(V) then begin
  686. if not IsRectEmpty(V.BoundsRect) then begin
  687. CursorRect := V.BoundsRect;
  688. HintStr := V.GetHintText;
  689. end;
  690. end;
  691. end;
  692. end;
  693. procedure TTBCustomToolbar.CMShowHintChanged(var Message: TMessage);
  694. begin
  695. inherited;
  696. if ShowHint then
  697. FView.Style := FView.Style + [vsAlwaysShowHints]
  698. else
  699. FView.Style := FView.Style - [vsAlwaysShowHints];
  700. end;
  701. procedure TTBCustomToolbar.WMGetObject(var Message: TMessage);
  702. begin
  703. if not FView.HandleWMGetObject(Message) then
  704. inherited;
  705. end;
  706. procedure TTBCustomToolbar.WMSetCursor(var Message: TWMSetCursor);
  707. var
  708. P: TPoint;
  709. Cursor: HCURSOR;
  710. R: TRect;
  711. begin
  712. if not(csDesigning in ComponentState) and
  713. (Message.CursorWnd = WindowHandle) and
  714. (Smallint(Message.HitTest) = HTCLIENT) then begin
  715. GetCursorPos(P);
  716. FView.UpdateSelection(@P, True);
  717. if Assigned(FView.Selected) then begin
  718. Cursor := 0;
  719. R := FView.Selected.BoundsRect;
  720. P := ScreenToClient(P);
  721. Dec(P.X, R.Left);
  722. Dec(P.Y, R.Top);
  723. TTBItemViewerAccess(FView.Selected).GetCursor(P, Cursor);
  724. if Cursor <> 0 then begin
  725. SetCursor(Cursor);
  726. Message.Result := 1;
  727. Exit;
  728. end;
  729. end;
  730. end;
  731. inherited;
  732. end;
  733. procedure TTBCustomToolbar.WMSysCommand(var Message: TWMSysCommand);
  734. begin
  735. if FMenuBar and Enabled and Showing then
  736. with Message do
  737. if (CmdType and $FFF0 = SC_KEYMENU) and (Key <> VK_SPACE) and
  738. (GetCapture = 0) then begin
  739. if not KeyboardOpen(Char(Key), False) then begin
  740. if Key = Ord('-') then Exit;
  741. MessageBeep(0);
  742. end;
  743. Result := 1;
  744. end;
  745. end;
  746. procedure TTBCustomToolbar.Paint;
  747. var
  748. R: TRect;
  749. begin
  750. { Draw dotted border in design mode on undocked toolbars }
  751. if not Docked and (csDesigning in ComponentState) then
  752. with Canvas do begin
  753. R := ClientRect;
  754. Pen.Style := psDot;
  755. Pen.Color := clBtnShadow;
  756. Brush.Style := bsClear;
  757. Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  758. Pen.Style := psSolid;
  759. end;
  760. FView.DrawSubitems(Canvas);
  761. end;
  762. procedure TTBCustomToolbar.CMDialogKey(var Message: TCMDialogKey);
  763. begin
  764. if (Message.CharCode = VK_MENU) and FMenuBar then
  765. FView.SetAccelsVisibility(True);
  766. inherited;
  767. end;
  768. procedure TTBCustomToolbar.CMDialogChar(var Message: TCMDialogChar);
  769. begin
  770. { On toolbars that aren't menu bars, handle CM_DIALOGCHAR instead of
  771. WM_SYSCOMMAND }
  772. if not FMenuBar and Enabled and Showing and (Message.CharCode <> 0) then
  773. if KeyboardOpen(Chr(Message.CharCode), True) then begin
  774. Message.Result := 1;
  775. Exit;
  776. end;
  777. inherited;
  778. end;
  779. procedure TTBCustomToolbar.CancelHover;
  780. begin
  781. if not MouseCapture then
  782. FView.UpdateSelection(nil, True);
  783. end;
  784. procedure TTBCustomToolbar.CMMouseLeave(var Message: TMessage);
  785. begin
  786. CancelHover;
  787. inherited;
  788. end;
  789. procedure TTBCustomToolbar.DoContextPopup(MousePos: TPoint;
  790. var Handled: Boolean);
  791. begin
  792. CancelHover;
  793. inherited;
  794. end;
  795. procedure TTBCustomToolbar.MouseMove(Shift: TShiftState; X, Y: Integer);
  796. var
  797. P: TPoint;
  798. Item: TTBCustomItem;
  799. begin
  800. if not(csDesigning in ComponentState) then begin
  801. P := ClientToScreen(Point(X, Y));
  802. FView.UpdateSelection(@P, True);
  803. if Assigned(FView.Selected) then begin
  804. Item := FView.Selected.Item;
  805. if not(tboLongHintInMenuOnly in Item.EffectiveOptions) then
  806. Hint := Item.Hint
  807. else
  808. Hint := '';
  809. with TTBItemViewerAccess(FView.Find(Item)) do
  810. begin
  811. MouseMove(X - BoundsRect.Left, Y - BoundsRect.Top);
  812. end;
  813. end
  814. else
  815. Hint := '';
  816. end;
  817. { Call TrackMouseEvent to be sure that we are notified when the mouse leaves
  818. the window. We won't get a CM_MOUSELEAVE message if the mouse moves
  819. directly from the toolbar to another application's window }
  820. CallTrackMouseEvent(Handle, TME_LEAVE);
  821. inherited;
  822. end;
  823. procedure TTBCustomToolbar.WMCancelMode(var Message: TWMCancelMode);
  824. begin
  825. inherited;
  826. { We can receive a WM_CANCELMODE message during a modal loop if a dialog
  827. pops up. Respond by hiding menus to make it look like the modal loop
  828. has returned, even though it really hasn't yet.
  829. Note: Similar code in TTBModalHandler.WndProc. }
  830. if vsModal in FView.State then
  831. FView.CancelMode;
  832. end;
  833. procedure TTBCustomToolbar.WMMouseLeave(var Message: TMessage);
  834. begin
  835. { A WM_MOUSELEAVE handler is necessary because the control won't get a
  836. CM_MOUSELEAVE message if the user presses Alt+Space. Also, CM_MOUSELEAVE
  837. messages are also not sent if the application is in a
  838. Application.ProcessMessages loop. }
  839. if not FIgnoreMouseLeave then
  840. CancelHover;
  841. inherited;
  842. end;
  843. procedure TTBCustomToolbar.WMNCMouseMove(var Message: TWMNCMouseMove);
  844. begin
  845. Hint := '';
  846. CancelHover;
  847. inherited;
  848. end;
  849. function TTBCustomToolbar.KeyboardOpen(Key: Char;
  850. RequirePrimaryAccel: Boolean): Boolean;
  851. var
  852. I: TTBItemViewer;
  853. IsOnlyItemWithAccel: Boolean;
  854. begin
  855. I := nil;
  856. FView.SetAccelsVisibility(True);
  857. try
  858. Result := False;
  859. if Key = #0 then begin
  860. I := FView.FirstSelectable;
  861. if I = nil then Exit;
  862. FView.Selected := I;
  863. FView.EnterToolbarLoop([]);
  864. end
  865. else begin
  866. I := FView.NextSelectableWithAccel(nil, Key, RequirePrimaryAccel,
  867. IsOnlyItemWithAccel);
  868. if (I = nil) or not I.Item.Enabled then
  869. Exit;
  870. if IsOnlyItemWithAccel then begin
  871. FView.Selected := I;
  872. FView.EnterToolbarLoop([tbetExecuteSelected]);
  873. end
  874. else if FMenuBar then begin
  875. FView.Selected := I;
  876. FView.EnterToolbarLoop([]);
  877. end
  878. else
  879. Exit;
  880. end;
  881. Result := True;
  882. finally
  883. if Assigned(I) then
  884. FView.SetAccelsVisibility(False);
  885. end;
  886. end;
  887. procedure TTBCustomToolbar.MouseDown(Button: TMouseButton; Shift: TShiftState;
  888. X, Y: Integer);
  889. var
  890. OldParent: TWinControl;
  891. P: TPoint;
  892. Item: TTBCustomItem;
  893. begin
  894. OldParent := Parent;
  895. inherited;
  896. if Parent <> OldParent then
  897. { if the inherited handler (TTBDockableWindow.MouseDown) changed the Parent
  898. (due to the toolbar moving between docks), nothing else should be done }
  899. Exit;
  900. if not(csDesigning in ComponentState) and (Button = mbLeft) then begin
  901. P := ClientToScreen(Point(X, Y));
  902. FView.UpdateSelection(@P, True);
  903. if Assigned(FView.Selected) then begin
  904. Item := FView.Selected.Item;
  905. if not(tbisClicksTransparent in TTBCustomItemAccess(Item).ItemStyle) then begin
  906. FIgnoreMouseLeave := True;
  907. try
  908. FView.EnterToolbarLoop([tbetMouseDown]);
  909. finally
  910. FIgnoreMouseLeave := False;
  911. end;
  912. end;
  913. end;
  914. end;
  915. end;
  916. procedure TTBCustomToolbar.CMFontChanged(var Message: TMessage);
  917. begin
  918. inherited;
  919. if not FSystemFont then
  920. Arrange;
  921. end;
  922. function TTBCustomToolbar.GetChevronHint: String;
  923. begin
  924. Result := FChevronItem.Hint;
  925. end;
  926. procedure TTBCustomToolbar.SetChevronHint(const Value: String);
  927. begin
  928. FChevronItem.Hint := Value;
  929. FChevronItem.Caption := EscapeAmpersands(GetShortHint(Value));
  930. end;
  931. procedure TTBCustomToolbar.SetChevronMoveItems(Value: Boolean);
  932. begin
  933. if FChevronMoveItems <> Value then begin
  934. FChevronMoveItems := Value;
  935. FView.UsePriorityList := Value and not(csDesigning in ComponentState);
  936. end;
  937. end;
  938. procedure TTBCustomToolbar.SetChevronPriorityForNewItems(Value: TTBChevronPriorityForNewItems);
  939. begin
  940. FChevronPriorityForNewItems := Value;
  941. FView.NewViewersGetHighestPriority := (Value = tbcpHighest);
  942. end;
  943. function TTBCustomToolbar.IsChevronHintStored: Boolean;
  944. begin
  945. Result := (FChevronItem.Hint <> FChevronItem.GetDefaultHint);
  946. end;
  947. function TTBCustomToolbar.GetImages: TCustomImageList;
  948. begin
  949. Result := FItem.SubMenuImages;
  950. end;
  951. procedure TTBCustomToolbar.SetImages(Value: TCustomImageList);
  952. begin
  953. FItem.SubMenuImages := Value;
  954. end;
  955. function TTBCustomToolbar.GetLinkSubitems: TTBCustomItem;
  956. begin
  957. Result := FItem.LinkSubitems;
  958. end;
  959. procedure TTBCustomToolbar.SetLinkSubitems(Value: TTBCustomItem);
  960. begin
  961. FItem.LinkSubitems := Value;
  962. end;
  963. procedure TTBCustomToolbar.SetMenuBar(Value: Boolean);
  964. begin
  965. if FMenuBar <> Value then begin
  966. FMenuBar := Value;
  967. if Value then begin
  968. ControlStyle := ControlStyle + [csMenuEvents];
  969. FView.Style := FView.Style + [vsMenuBar, vsUseHiddenAccels];
  970. end
  971. else begin
  972. ControlStyle := ControlStyle - [csMenuEvents];
  973. FView.Style := FView.Style - [vsMenuBar, vsUseHiddenAccels];
  974. end;
  975. if not(csLoading in ComponentState) then begin
  976. FullSize := Value;
  977. if Value then
  978. ShrinkMode := tbsmWrap
  979. else
  980. ShrinkMode := tbsmChevron;
  981. CloseButton := not Value;
  982. ProcessShortCuts := Value;
  983. end;
  984. if Value and not(csDesigning in ComponentState) then
  985. InstallHookProc(Self, HookProc, [hpGetMessage])
  986. else
  987. UninstallHookProc(Self, HookProc);
  988. SetMainWindowHook;
  989. end;
  990. end;
  991. function TTBCustomToolbar.GetOptions: TTBItemOptions;
  992. begin
  993. Result := FItem.Options;
  994. end;
  995. procedure TTBCustomToolbar.SetOptions(Value: TTBItemOptions);
  996. begin
  997. FItem.Options := Value;
  998. end;
  999. procedure TTBCustomToolbar.SetProcessShortCuts(Value: Boolean);
  1000. begin
  1001. if FProcessShortCuts <> Value then begin
  1002. FProcessShortCuts := Value;
  1003. SetMainWindowHook;
  1004. end;
  1005. end;
  1006. procedure TTBCustomToolbar.SetSystemFont(Value: Boolean);
  1007. begin
  1008. if FSystemFont <> Value then begin
  1009. FSystemFont := Value;
  1010. Arrange;
  1011. end;
  1012. end;
  1013. procedure TTBCustomToolbar.SetShrinkMode(Value: TTBShrinkMode);
  1014. begin
  1015. if FShrinkMode <> Value then begin
  1016. FShrinkMode := Value;
  1017. if Docked then
  1018. CurrentDock.ArrangeToolbars
  1019. else if not Floating then
  1020. Arrange;
  1021. end;
  1022. end;
  1023. procedure TTBCustomToolbar.SetFloatingWidth(Value: Integer);
  1024. begin
  1025. if FFloatingWidth <> Value then begin
  1026. FFloatingWidth := Value;
  1027. if Floating then begin
  1028. UpdateViewProperties;
  1029. Arrange;
  1030. end;
  1031. end;
  1032. end;
  1033. function TTBCustomToolbar.CalcWrapOffset(const ADock: TTBDock): Integer;
  1034. begin
  1035. if ADock = nil then
  1036. Result := FFloatingWidth
  1037. else begin
  1038. if FShrinkMode = tbsmWrap then begin
  1039. if not(ADock.Position in [dpLeft, dpRight]) then
  1040. Result := ADock.Width - ADock.NonClientWidth - NonClientWidth
  1041. else
  1042. Result := ADock.Height - ADock.NonClientHeight - NonClientHeight;
  1043. end
  1044. else
  1045. Result := 0;
  1046. end;
  1047. end;
  1048. function TTBCustomToolbar.CalcChevronOffset(const ADock: TTBDock;
  1049. const AOrientation: TTBViewOrientation): Integer;
  1050. begin
  1051. if (FShrinkMode = tbsmChevron) and Docked and (ADock = CurrentDock) then begin
  1052. Result := CurrentSize;
  1053. { Subtract non-client size }
  1054. if AOrientation <> tbvoVertical then
  1055. Dec(Result, NonClientWidth)
  1056. else
  1057. Dec(Result, NonClientHeight);
  1058. if Result < 0 then
  1059. Result := 0; { in case CurrentSize wasn't properly initialized yet }
  1060. end
  1061. else
  1062. Result := 0;
  1063. end;
  1064. procedure TTBCustomToolbar.UpdateViewProperties;
  1065. var
  1066. DT: TTBDockType;
  1067. begin
  1068. DT := TBGetDockTypeOf(CurrentDock, Floating);
  1069. FView.Orientation := DockTypeToOrientation[DT];
  1070. FView.ChevronSize := tbChevronSize;
  1071. if Assigned(CurrentDock) or Floating then begin
  1072. FView.ChevronOffset := CalcChevronOffset(CurrentDock, FView.Orientation);
  1073. FView.WrapOffset := CalcWrapOffset(CurrentDock);
  1074. end
  1075. else begin
  1076. FView.ChevronOffset := 0;
  1077. FView.WrapOffset := 0;
  1078. { Only enable chevron/wrapping when the width of the toolbar is fixed }
  1079. if not AutoResize or ((akLeft in Anchors) and (akRight in Anchors)) then begin
  1080. if FShrinkMode = tbsmChevron then
  1081. FView.ChevronOffset := Width - NonClientWidth
  1082. else if FShrinkMode = tbsmWrap then
  1083. FView.WrapOffset := Width - NonClientWidth;
  1084. end;
  1085. end;
  1086. end;
  1087. {}{DOCKING STUFF}
  1088. procedure TTBCustomToolbar.ReadPositionData(var S: string);
  1089. begin
  1090. inherited;
  1091. if Floating then
  1092. FloatingWidth := StrToIntDef(CutToChar(S, ':', true), 0);
  1093. end;
  1094. function TTBCustomToolbar.WritePositionData: string;
  1095. begin
  1096. Result := inherited;
  1097. if Floating then
  1098. Result := Result + ':' + IntToStr(FFloatingWidth);
  1099. end;
  1100. procedure TTBCustomToolbar.GetMinBarSize(var MinimumSize: TPoint);
  1101. var
  1102. WH: Integer;
  1103. begin
  1104. MinimumSize.X := 0;
  1105. MinimumSize.Y := 0;
  1106. if Docked then begin
  1107. WH := CurrentDock.GetMinRowSize(EffectiveDockRow, Self);
  1108. if not(CurrentDock.Position in [dpLeft, dpRight]) then
  1109. MinimumSize.Y := WH
  1110. else
  1111. MinimumSize.X := WH;
  1112. end;
  1113. end;
  1114. procedure TTBCustomToolbar.GetBaseSize(var ASize: TPoint);
  1115. begin
  1116. FView.ValidatePositions;
  1117. ASize := FBaseSize;
  1118. { MP }
  1119. if Assigned(FOnGetBaseSize) then FOnGetBaseSize(Self, ASize);
  1120. end;
  1121. function TTBCustomToolbar.DoArrange(CanMoveControls: Boolean;
  1122. PreviousDockType: TTBDockType; NewFloating: Boolean; NewDock: TTBDock): TPoint;
  1123. var
  1124. DT: TTBDockType;
  1125. O: TTBViewOrientation;
  1126. TempBaseSize: TPoint;
  1127. begin
  1128. //outputdebugstring (pchar(format('%s.DoArrange(%d)', [Name, Ord(CanMoveControls)])));
  1129. if CanMoveControls then begin
  1130. UpdateViewProperties;
  1131. Result := FView.UpdatePositions;
  1132. end
  1133. else begin
  1134. DT := TBGetDockTypeOf(NewDock, NewFloating);
  1135. O := DockTypeToOrientation[DT];
  1136. Result.X := 0;
  1137. Result.Y := 0;
  1138. FView.CalculatePositions(False, O, CalcWrapOffset(NewDock),
  1139. CalcChevronOffset(NewDock, O), tbChevronSize, TempBaseSize, Result,
  1140. FLastWrappedLines);
  1141. end;
  1142. end;
  1143. procedure TTBCustomToolbar.ControlExistsAtPos(const P: TPoint;
  1144. var ControlExists: Boolean);
  1145. var
  1146. P2: TPoint;
  1147. begin
  1148. inherited;
  1149. if not ControlExists and not(csDesigning in ComponentState) then begin
  1150. P2 := ClientToScreen(P);
  1151. FView.UpdateSelection(@P2, True);
  1152. if Assigned(FView.Selected) and
  1153. not(tbisClicksTransparent in TTBCustomItemAccess(FView.Selected.Item).ItemStyle) then
  1154. ControlExists := True;
  1155. end;
  1156. end;
  1157. procedure TTBCustomToolbar.BuildPotentialSizesList(SizesList: TList);
  1158. var
  1159. Margins: TRect;
  1160. MinX, SaveWrapX: Integer;
  1161. X, PrevWrappedLines: Integer;
  1162. S: TPoint;
  1163. S2: TSmallPoint;
  1164. begin
  1165. View.GetMargins(tbvoFloating, Margins);
  1166. MinX := Margins.Left + Margins.Right;
  1167. SaveWrapX := FFloatingWidth;
  1168. try
  1169. { Add the widest size to the list }
  1170. FFloatingWidth := 0;
  1171. S := DoArrange(False, dtNotDocked, True, nil);
  1172. SizesList.Add(Pointer(PointToSmallPoint(S)));
  1173. { Calculate and add rest of sizes to the list }
  1174. PrevWrappedLines := 1;
  1175. X := S.X-1;
  1176. while X >= MinX do begin
  1177. FFloatingWidth := X;
  1178. S := DoArrange(False, dtNotDocked, True, nil);
  1179. if S.X > X then { if it refuses to go any smaller }
  1180. Break
  1181. else
  1182. if X = S.X then begin
  1183. S2 := PointToSmallPoint(S);
  1184. if FLastWrappedLines <> PrevWrappedLines then
  1185. SizesList.Add(Pointer(S2))
  1186. else
  1187. SizesList[SizesList.Count-1] := Pointer(S2);
  1188. PrevWrappedLines := FLastWrappedLines;
  1189. Dec(X);
  1190. end
  1191. else
  1192. X := S.X;
  1193. end;
  1194. finally
  1195. FFloatingWidth := SaveWrapX;
  1196. end;
  1197. end;
  1198. function CompareNewSizes(const Item1, Item2, ExtraData: Pointer): Integer; far;
  1199. begin
  1200. { Sorts in descending order }
  1201. if ExtraData = nil then
  1202. Result := TSmallPoint(Item2).X - TSmallPoint(Item1).X
  1203. else
  1204. Result := TSmallPoint(Item2).Y - TSmallPoint(Item1).Y;
  1205. end;
  1206. procedure TTBCustomToolbar.ResizeBegin(ASizeHandle: TTBSizeHandle);
  1207. const
  1208. MaxSizeSens = 12;
  1209. var
  1210. I, NewSize: Integer;
  1211. S, N: TSmallPoint;
  1212. P: TPoint;
  1213. begin
  1214. inherited;
  1215. FSizeData := AllocMem(SizeOf(TToolbar97SizeData));
  1216. with PToolbar97SizeData(FSizeData)^ do begin
  1217. SizeHandle := ASizeHandle;
  1218. OrigLeft := Parent.Left;
  1219. OrigTop := Parent.Top;
  1220. OrigWidth := Parent.Width;
  1221. OrigHeight := Parent.Height;
  1222. NCXDiff := ClientToScreen(Point(0, 0)).X - OrigLeft;
  1223. CurRightX := FFloatingWidth;
  1224. DisableSensCheck := False;
  1225. OpSide := False;
  1226. NewSizes := TList.Create;
  1227. BuildPotentialSizesList(NewSizes);
  1228. for I := 0 to NewSizes.Count-1 do begin
  1229. P := SmallPointToPoint(TSmallPoint(NewSizes.List[I]));
  1230. AddFloatingNCAreaToSize(P);
  1231. NewSizes.List[I] := Pointer(PointToSmallPoint(P));
  1232. end;
  1233. ListSortEx(NewSizes, CompareNewSizes,
  1234. Pointer(Ord(ASizeHandle in [twshTop, twshBottom])));
  1235. SizeSens := MaxSizeSens;
  1236. { Adjust sensitivity if it's too high }
  1237. for I := 0 to NewSizes.Count-1 do begin
  1238. Pointer(S) := NewSizes[I];
  1239. if (S.X = Width) and (S.Y = Height) then begin
  1240. if I > 0 then begin
  1241. Pointer(N) := NewSizes[I-1];
  1242. if ASizeHandle in [twshLeft, twshRight] then
  1243. NewSize := N.X - S.X - 1
  1244. else
  1245. NewSize := N.Y - S.Y - 1;
  1246. if NewSize < SizeSens then SizeSens := NewSize;
  1247. end;
  1248. if I < NewSizes.Count-1 then begin
  1249. Pointer(N) := NewSizes[I+1];
  1250. if ASizeHandle in [twshLeft, twshRight] then
  1251. NewSize := S.X - N.X - 1
  1252. else
  1253. NewSize := S.Y - N.Y - 1;
  1254. if NewSize < SizeSens then SizeSens := NewSize;
  1255. end;
  1256. Break;
  1257. end;
  1258. end;
  1259. if SizeSens < 0 then SizeSens := 0;
  1260. end;
  1261. end;
  1262. procedure TTBCustomToolbar.ResizeTrack(var Rect: TRect; const OrigRect: TRect);
  1263. var
  1264. Pos: TPoint;
  1265. NewOpSide: Boolean;
  1266. Reverse: Boolean;
  1267. I: Integer;
  1268. P: TSmallPoint;
  1269. begin
  1270. inherited;
  1271. with PToolbar97SizeData(FSizeData)^ do begin
  1272. GetCursorPos(Pos);
  1273. Dec(Pos.X, OrigLeft); Dec(Pos.Y, OrigTop);
  1274. if SizeHandle = twshLeft then
  1275. Pos.X := OrigWidth-Pos.X
  1276. else
  1277. if SizeHandle = twshTop then
  1278. Pos.Y := OrigHeight-Pos.Y;
  1279. { Adjust Pos to make up for the "sizing sensitivity", as seen in Office 97 }
  1280. if SizeHandle in [twshLeft, twshRight] then
  1281. NewOpSide := Pos.X < OrigWidth
  1282. else
  1283. NewOpSide := Pos.Y < OrigHeight;
  1284. if (not DisableSensCheck) or (OpSide <> NewOpSide) then begin
  1285. DisableSensCheck := False;
  1286. OpSide := NewOpSide;
  1287. if SizeHandle in [twshLeft, twshRight] then begin
  1288. if (Pos.X >= OrigWidth-SizeSens) and (Pos.X < OrigWidth+SizeSens) then
  1289. Pos.X := OrigWidth;
  1290. end
  1291. else begin
  1292. if (Pos.Y >= OrigHeight-SizeSens) and (Pos.Y < OrigHeight+SizeSens) then
  1293. Pos.Y := OrigHeight;
  1294. end;
  1295. end;
  1296. Rect := OrigRect;
  1297. if SizeHandle in [twshLeft, twshRight] then
  1298. Reverse := Pos.X > OrigWidth
  1299. else
  1300. Reverse := Pos.Y > OrigHeight;
  1301. if not Reverse then
  1302. I := NewSizes.Count-1
  1303. else
  1304. I := 0;
  1305. while True do begin
  1306. if (not Reverse and (I < 0)) or
  1307. (Reverse and (I >= NewSizes.Count)) then
  1308. Break;
  1309. Pointer(P) := NewSizes[I];
  1310. if SizeHandle in [twshLeft, twshRight] then begin
  1311. if (not Reverse and ((I = NewSizes.Count-1) or (Pos.X >= P.X))) or
  1312. (Reverse and ((I = 0) or (Pos.X < P.X))) then begin
  1313. if I = 0 then
  1314. CurRightX := 0
  1315. else
  1316. CurRightX := P.X - NCXDiff*2;
  1317. if SizeHandle = twshRight then
  1318. Rect.Right := Rect.Left + P.X
  1319. else
  1320. Rect.Left := Rect.Right - P.X;
  1321. Rect.Bottom := Rect.Top + P.Y;
  1322. DisableSensCheck := not EqualRect(Rect, OrigRect);
  1323. end;
  1324. end
  1325. else begin
  1326. if (not Reverse and ((I = NewSizes.Count-1) or (Pos.Y >= P.Y))) or
  1327. (Reverse and ((I = 0) or (Pos.Y < P.Y))) then begin
  1328. if I = NewSizes.Count-1 then
  1329. CurRightX := 0
  1330. else
  1331. CurRightX := P.X - NCXDiff*2;
  1332. if SizeHandle = twshBottom then
  1333. Rect.Bottom := Rect.Top + P.Y
  1334. else
  1335. Rect.Top := Rect.Bottom - P.Y;
  1336. Rect.Right := Rect.Left + P.X;
  1337. DisableSensCheck := not EqualRect(Rect, OrigRect);
  1338. end;
  1339. end;
  1340. if not Reverse then
  1341. Dec(I)
  1342. else
  1343. Inc(I);
  1344. end;
  1345. end;
  1346. end;
  1347. procedure TTBCustomToolbar.ResizeTrackAccept;
  1348. begin
  1349. inherited;
  1350. FloatingWidth := PToolbar97SizeData(FSizeData)^.CurRightX;
  1351. end;
  1352. procedure TTBCustomToolbar.ResizeEnd;
  1353. begin
  1354. inherited;
  1355. if Assigned(FSizeData) then begin
  1356. PToolbar97SizeData(FSizeData)^.NewSizes.Free;
  1357. FreeMem(FSizeData);
  1358. FSizeData := nil;
  1359. end;
  1360. end;
  1361. function TTBCustomToolbar.GetShrinkMode: TTBShrinkMode;
  1362. begin
  1363. Result := FShrinkMode;
  1364. end;
  1365. procedure TTBCustomToolbar.GetMinShrinkSize(var AMinimumSize: Integer);
  1366. var
  1367. I: TTBItemViewer;
  1368. begin
  1369. I := FView.HighestPriorityViewer;
  1370. if Assigned(I) then begin
  1371. if not(CurrentDock.Position in [dpLeft, dpRight]) then
  1372. AMinimumSize := I.BoundsRect.Right - I.BoundsRect.Left
  1373. else
  1374. AMinimumSize := I.BoundsRect.Bottom - I.BoundsRect.Top;
  1375. end;
  1376. if not(CurrentDock.Position in [dpLeft, dpRight]) then
  1377. Inc(AMinimumSize, NonClientWidth)
  1378. else
  1379. Inc(AMinimumSize, NonClientHeight);
  1380. Inc(AMinimumSize, tbChevronSize);
  1381. end;
  1382. procedure TTBCustomToolbar.BeginUpdate;
  1383. begin
  1384. FView.BeginUpdate;
  1385. end;
  1386. procedure TTBCustomToolbar.EndUpdate;
  1387. begin
  1388. FView.EndUpdate;
  1389. end;
  1390. procedure TTBCustomToolbar.GetTabOrderList(List: TList);
  1391. var
  1392. CtlList: TList;
  1393. I, J: Integer;
  1394. CtlI, CtlJ: TWinControl;
  1395. begin
  1396. inherited;
  1397. { Remove off-edge items and their children from List }
  1398. CtlList := TList.Create;
  1399. try
  1400. FView.GetOffEdgeControlList(CtlList);
  1401. for I := 0 to CtlList.Count-1 do begin
  1402. CtlI := CtlList[I];
  1403. J := 0;
  1404. while J < List.Count do begin
  1405. CtlJ := List[J];
  1406. if (CtlJ = CtlI) or CtlI.ContainsControl(CtlJ) then
  1407. List.Delete(J)
  1408. else
  1409. Inc(J);
  1410. end;
  1411. end;
  1412. finally
  1413. CtlList.Free;
  1414. end;
  1415. end;
  1416. procedure TTBCustomToolbar.CMWinIniChange(var Message: TWMSettingChange);
  1417. begin
  1418. inherited;
  1419. if Message.Flag = SPI_SETNONCLIENTMETRICS then begin
  1420. TBInitToolbarSystemFont;
  1421. Arrange;
  1422. end;
  1423. end;
  1424. function TTBCustomToolbar.IsShortCut(var Message: TWMKey): Boolean;
  1425. begin
  1426. Result := False;
  1427. if Assigned(FOnShortCut) then
  1428. FOnShortCut(Message, Result);
  1429. Result := Result or FItem.IsShortCut(Message);
  1430. end;
  1431. var
  1432. HookCount: Integer;
  1433. HookList: TList;
  1434. class function TTBCustomToolbar.MainWindowHook(var Message: TMessage): Boolean;
  1435. function GetActiveForm: TCustomForm;
  1436. var
  1437. Wnd: HWND;
  1438. Ctl: TWinControl;
  1439. begin
  1440. { Note: We don't use Screen.ActiveCustomForm because when an EXE calls a
  1441. DLL that shows a modal form, Screen.ActiveCustomForm doesn't change in
  1442. the EXE; it remains set to the last form that was active in the EXE.
  1443. Use FindControl(GetActiveWindow) instead to avoid this problem; it will
  1444. return nil when a form in another module is active. }
  1445. Result := nil;
  1446. Wnd := GetActiveWindow;
  1447. if Wnd <> 0 then begin
  1448. Ctl := FindControl(Wnd);
  1449. if Assigned(Ctl) and (Ctl is TCustomForm) then
  1450. Result := TCustomForm(Ctl);
  1451. end;
  1452. end;
  1453. function HandleShortCutOnForm(const Form: TCustomForm): Boolean;
  1454. var
  1455. I: Integer;
  1456. Toolbar: TTBCustomToolbar;
  1457. begin
  1458. Result := False;
  1459. if Form = nil then
  1460. Exit;
  1461. for I := 0 to HookList.Count-1 do begin
  1462. Toolbar := HookList[I];
  1463. if Toolbar.ProcessShortCuts and
  1464. (TBGetToolWindowParentForm(Toolbar) = Form) and
  1465. IsWindowEnabled(Form.Handle) and
  1466. Toolbar.IsShortCut(TWMKey(Message)) then begin
  1467. Message.Result := 1;
  1468. Result := True;
  1469. Exit;
  1470. end;
  1471. end;
  1472. end;
  1473. function TraverseControls(Container: TWinControl): Boolean;
  1474. var
  1475. I: Integer;
  1476. Control: TControl;
  1477. begin
  1478. Result := False;
  1479. if Container.Showing then
  1480. for I := 0 to Container.ControlCount - 1 do begin
  1481. Control := Container.Controls[I];
  1482. if Control.Visible and Control.Enabled then begin
  1483. if (csMenuEvents in Control.ControlStyle) and
  1484. ((Control is TTBDock) or (Control is TTBCustomToolbar)) and
  1485. (Control.Perform(WM_SYSCOMMAND, TMessage(Message).WParam,
  1486. TMessage(Message).LParam) <> 0) or (Control is TWinControl) and
  1487. TraverseControls(TWinControl(Control)) then begin
  1488. Result := True;
  1489. Exit;
  1490. end;
  1491. end;
  1492. end;
  1493. end;
  1494. var
  1495. ActiveForm: TCustomForm;
  1496. ActiveMDIChild: TForm;
  1497. begin
  1498. Result := False;
  1499. if (Message.Msg = CM_APPKEYDOWN) and Assigned(HookList) then begin
  1500. { Process shortcuts on toolbars. Search forms in this order:
  1501. 1. If the active form is an MDI parent form, the active MDI child form
  1502. if it has the focus.
  1503. 2. The active form.
  1504. 3. The main form. }
  1505. ActiveForm := GetActiveForm;
  1506. if Assigned(ActiveForm) and (ActiveForm is TForm) and
  1507. (TForm(ActiveForm).FormStyle = fsMDIForm) then begin
  1508. ActiveMDIChild := TForm(ActiveForm).ActiveMDIChild;
  1509. { Don't search the child form if a control on the MDI parent form is
  1510. currently focused (i.e. Screen.ActiveCustomForm <> ActiveMDIChild) }
  1511. if Assigned(ActiveMDIChild) and
  1512. (Screen.ActiveCustomForm = ActiveMDIChild) and
  1513. HandleShortCutOnForm(ActiveMDIChild) then begin
  1514. Result := True;
  1515. Exit;
  1516. end;
  1517. end;
  1518. if HandleShortCutOnForm(ActiveForm) then
  1519. Result := True
  1520. else begin
  1521. if (Application.MainForm <> ActiveForm) and
  1522. HandleShortCutOnForm(Application.MainForm) then
  1523. Result := True;
  1524. end;
  1525. end
  1526. else if Message.Msg = CM_APPSYSCOMMAND then begin
  1527. { Handle "Alt or Alt+[key] pressed on secondary form" case. If there's a
  1528. menu bar on the active form we want the keypress to go to it instead of
  1529. to the main form (the VCL's default handling). }
  1530. ActiveForm := GetActiveForm;
  1531. if Assigned(ActiveForm) and IsWindowEnabled(ActiveForm.Handle) and
  1532. IsWindowVisible(ActiveForm.Handle) and TraverseControls(ActiveForm) then begin
  1533. Message.Result := 1;
  1534. Result := True;
  1535. end;
  1536. end;
  1537. end;
  1538. procedure TTBCustomToolbar.SetMainWindowHook;
  1539. begin
  1540. if (ProcessShortCuts or MenuBar) and not(csDesigning in ComponentState) then
  1541. InstallMainWindowHook
  1542. else
  1543. UninstallMainWindowHook;
  1544. end;
  1545. procedure TTBCustomToolbar.InstallMainWindowHook;
  1546. begin
  1547. if FMainWindowHookInstalled then
  1548. Exit;
  1549. if HookCount = 0 then
  1550. Application.HookMainWindow(MainWindowHook);
  1551. Inc(HookCount);
  1552. AddToList(HookList, Self);
  1553. FMainWindowHookInstalled := True;
  1554. end;
  1555. procedure TTBCustomToolbar.UninstallMainWindowHook;
  1556. begin
  1557. if not FMainWindowHookInstalled then
  1558. Exit;
  1559. FMainWindowHookInstalled := False;
  1560. RemoveFromList(HookList, Self);
  1561. Dec(HookCount);
  1562. if HookCount = 0 then
  1563. Application.UnhookMainWindow(MainWindowHook);
  1564. end;
  1565. procedure TTBCustomToolbar.ChangeScale(M, D: Integer);
  1566. begin
  1567. inherited;
  1568. Items.ChangeScale(M, D);
  1569. View.RecreateAllViewers;
  1570. end;
  1571. end.