TB2Toolbar.pas 53 KB

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