TB2Toolbar.pas 52 KB

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