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