TB2Toolbar.pas 53 KB

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