TB2Toolbar.pas 53 KB

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