TB2Toolbar.pas 53 KB

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