TBXStatusBars.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. unit TBXStatusBars;
  2. // TBX Package
  3. // Copyright 2001-2004 Alex A. Denisov. All Rights Reserved
  4. // See TBX.chm for license and installation instructions
  5. //
  6. // Id: TBXStatusBars.pas 15 2004-05-15 04:45:26Z Alex@ZEISS
  7. interface
  8. {$I TB2Ver.inc}
  9. uses
  10. Windows, Messages, Classes, SysUtils, Controls, Forms, Graphics, TBX,
  11. TBXThemes, TB2ITem, ImgList, UITypes;
  12. type
  13. TTBXCustomStatusBar = class;
  14. TPercent = 0..100;
  15. TTBXStatusPanel = class(TCollectionItem)
  16. private
  17. FAlignment: TAlignment;
  18. FCaption: TCaption;
  19. FControl: TControl;
  20. FEnabled: Boolean;
  21. FFramed: Boolean;
  22. FFontSettings: TFontSettings;
  23. FHint: string;
  24. FImageIndex: TImageIndex;
  25. FMaxSize: Integer;
  26. FSize: Integer;
  27. FStretchPriority: TPercent;
  28. FTag: Integer;
  29. FTextTruncation: TTextTruncation;
  30. FViewPriority: TPercent;
  31. procedure FontSettingsChanged(Sender: TObject);
  32. procedure SetAlignment(Value: TAlignment);
  33. procedure SetCaption(const Value: TCaption);
  34. procedure SetControl(Value: TControl);
  35. procedure SetEnabled(Value: Boolean);
  36. procedure SetFramed(Value: Boolean);
  37. procedure SetImageIndex(Value: TImageIndex);
  38. procedure SetMaxSize(Value: Integer);
  39. procedure SetSize(Value: Integer);
  40. procedure SetStretchPriority(Value: TPercent);
  41. procedure SetTextTruncation(Value: TTextTruncation);
  42. procedure SetViewPriority(Value: TPercent);
  43. procedure SetFontSettings(const Value: TFontSettings);
  44. protected
  45. CachedBounds: TRect;
  46. CachedSize: Integer;
  47. CachedVisible: Boolean;
  48. CachedGripper: Boolean;
  49. function StatusBar: TTBXCustomStatusBar;
  50. function GetDisplayName: string; override;
  51. public
  52. constructor Create(Collection: TCollection); override;
  53. destructor Destroy; override;
  54. procedure Assign(Source: TPersistent); override;
  55. property BoundsRect: TRect read CachedBounds;
  56. property Visible: Boolean read CachedVisible;
  57. published
  58. property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
  59. property Caption: TCaption read FCaption write SetCaption;
  60. property Control: TControl read FControl write SetControl;
  61. property Enabled: Boolean read FEnabled write SetEnabled default True;
  62. property Framed: Boolean read FFramed write SetFramed default True;
  63. property FontSettings: TFontSettings read FFontSettings write SetFontSettings;
  64. property Hint: string read FHint write FHint;
  65. property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
  66. property MaxSize: Integer read FMaxSize write SetMaxSize default 0;
  67. property ViewPriority: TPercent read FViewPriority write SetViewPriority default 100;
  68. property Size: Integer read FSize write SetSize default 50;
  69. property StretchPriority: TPercent read FStretchPriority write SetStretchPriority default 0;
  70. property Tag: Integer read FTag write FTag;
  71. property TextTruncation: TTextTruncation read FTextTruncation write SetTextTruncation default twNone;
  72. end;
  73. TTBXStatusPanels = class(TCollection)
  74. private
  75. FStatusBar: TTBXCustomStatusBar;
  76. function GetItem(Index: Integer): TTBXStatusPanel;
  77. procedure SetItem(Index: Integer; Value: TTBXStatusPanel);
  78. protected
  79. function GetOwner: TPersistent; override;
  80. procedure Update(Item: TCollectionItem); override;
  81. public
  82. constructor Create(AStatusBar: TTBXCustomStatusBar);
  83. function Add: TTBXStatusPanel;
  84. function FindPanel(AControl: TControl): TTBXStatusPanel;
  85. property StatusBar: TTBXCustomStatusBar read FStatusBar;
  86. property Items[Index: Integer]: TTBXStatusPanel read GetItem write SetItem; default;
  87. end;
  88. TSBAdjustContentRect = procedure(Sender: TTBXCustomStatusBar; Panel: TTBXStatusPanel; var ARect: TRect) of object;
  89. TSBAdjustFont = procedure(Sender: TTBXCustomStatusBar; Panel: TTBXStatusPanel; AFont: TFont) of object;
  90. TSBPanelEvent = procedure(Sender: TTBXCustomStatusBar; Panel: TTBXStatusPanel) of object;
  91. TTBXCustomStatusBar = class(TCustomControl)
  92. private
  93. FPanels: TTBXStatusPanels;
  94. FImageChangeLink: TChangeLink;
  95. FImages: TCustomImageList;
  96. FSimplePanel: Boolean;
  97. FSimpleText: TCaption;
  98. FSizeGrip: Boolean;
  99. FUpdateCount: Integer;
  100. FUseSystemFont: Boolean;
  101. FOnAdjustContentRect: TSBAdjustContentRect;
  102. FOnAdjustFont: TSBAdjustFont;
  103. FOnPanelClick: TSBPanelEvent;
  104. FOnPanelDblClick: TSBPanelEvent;
  105. FFixAlign: Boolean;
  106. procedure CMControlChange(var Message: TCMControlChange); message CM_CONTROLCHANGE;
  107. procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  108. procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
  109. procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED;
  110. procedure ImageListChange(Sender: TObject);
  111. procedure SetImages(Value: TCustomImageList);
  112. procedure SetPanels(Value: TTBXStatusPanels);
  113. procedure SetSimplePanel(Value: Boolean);
  114. procedure SetSimpleText(const Value: TCaption);
  115. procedure SetSizeGrip(Value: Boolean);
  116. procedure SetUseSystemFont(Value: Boolean);
  117. procedure TBMThemeChange(var Message); message TBM_THEMECHANGE;
  118. procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  119. procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  120. protected
  121. CachedPanelMargins: TTBXMargins;
  122. procedure AdjustPanelContentRect(APanel: TTBXStatusPanel; var ARect: TRect); virtual;
  123. procedure AlignControls(AControl: TControl; var Rect: TRect); override;
  124. procedure BeginUpdate;
  125. procedure Change; dynamic;
  126. procedure ChangeScale(M, D: Integer; isDpiChange: Boolean); override;
  127. procedure Click; override;
  128. procedure CreateParams(var Params: TCreateParams); override;
  129. procedure CreateWnd; override;
  130. procedure DblClick; override;
  131. procedure DoAdjustFont(APanel: TTBXStatusPanel; AFont: TFont); virtual;
  132. procedure DoPanelClick(APanel: TTBXStatusPanel); virtual;
  133. procedure DoPanelDblClick(APanel: TTBXStatusPanel); virtual;
  134. procedure EndUpdate;
  135. function GetGripperRect: TRect;
  136. procedure Loaded; override;
  137. function IsSizeGripVisible: Boolean;
  138. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  139. procedure Paint; override;
  140. procedure PaintPanel(ARect: TRect; APanel: TTBXStatusPanel; IsLast: Boolean); virtual;
  141. procedure Resize; override;
  142. procedure UpdateCache; virtual;
  143. procedure UpdatePanels; virtual;
  144. public
  145. constructor Create(AOwner: TComponent); override;
  146. destructor Destroy; override;
  147. function GetPanelAt(const Pt: TPoint): TTBXStatusPanel; overload;
  148. function GetPanelAt(X, Y: Integer): TTBXStatusPanel; overload;
  149. function GetPanelRect(APanel: TTBXStatusPanel): TRect;
  150. procedure FlipChildren(AllLevels: Boolean); override;
  151. property Align default alBottom;
  152. property FixAlign: Boolean read FFixAlign write FFixAlign default False;
  153. property DoubleBuffered default True;
  154. property Images: TCustomImageList read FImages write SetImages;
  155. property Panels: TTBXStatusPanels read FPanels write SetPanels;
  156. property SimplePanel: Boolean read FSimplePanel write SetSimplePanel default False;
  157. property SimpleText: TCaption read FSimpleText write SetSimpleText;
  158. property SizeGrip: Boolean read FSizeGrip write SetSizeGrip default True;
  159. property UseSystemFont: Boolean read FUseSystemFont write SetUseSystemFont;
  160. property OnAdjustContentRect: TSBAdjustContentRect read FOnAdjustContentRect write FOnAdjustContentRect;
  161. property OnAdjustFont: TSBAdjustFont read FOnAdjustFont write FOnAdjustFont;
  162. property OnPanelClick: TSBPanelEvent read FOnPanelClick write FOnPanelClick;
  163. property OnPanelDblClick: TSBPanelEvent read FOnPanelDblClick write FOnPanelDblClick;
  164. published
  165. property Height default 22;
  166. end;
  167. TTBXStatusBar = class(TTBXCustomStatusBar)
  168. published
  169. property Action;
  170. property Align;
  171. property Anchors;
  172. property Constraints;
  173. property Ctl3D;
  174. property DoubleBuffered;
  175. property DragCursor;
  176. property DragKind;
  177. property DragMode;
  178. property Enabled;
  179. property FixAlign;
  180. property Font;
  181. property Images;
  182. property Panels;
  183. property ParentFont;
  184. property ParentShowHint;
  185. property PopupMenu;
  186. property SimplePanel;
  187. property SimpleText;
  188. property SizeGrip;
  189. property ShowHint;
  190. property UseSystemFont;
  191. property Visible;
  192. property OnAdjustContentRect;
  193. property OnClick;
  194. property OnContextPopup;
  195. property OnDblClick;
  196. property OnDragDrop;
  197. property OnDragOver;
  198. property OnEndDock;
  199. property OnEndDrag;
  200. property OnMouseDown;
  201. property OnMouseMove;
  202. property OnMouseUp;
  203. property OnPanelClick;
  204. property OnPanelDblClick;
  205. property OnResize;
  206. property OnStartDock;
  207. property OnStartDrag;
  208. end;
  209. implementation
  210. uses TBXUtils, Types, PasTools;
  211. type TFontSettingsAccess = class(TFontSettings);
  212. function CompareViewPriorities(Item1, Item2: Pointer): Integer;
  213. var
  214. P1, P2: TTBXStatusPanel;
  215. begin
  216. P1 := TTBXStatusPanel(Item1);
  217. P2 := TTBXStatusPanel(Item2);
  218. Result := P2.ViewPriority - P1.ViewPriority;
  219. end;
  220. function CompareStretchPriorities(Item1, Item2: Pointer): Integer;
  221. var
  222. P1, P2: TTBXStatusPanel;
  223. begin
  224. P1 := TTBXStatusPanel(Item1);
  225. P2 := TTBXStatusPanel(Item2);
  226. Result := P1.StretchPriority - P2.StretchPriority;
  227. end;
  228. { TTBXStatusPanel }
  229. procedure TTBXStatusPanel.Assign(Source: TPersistent);
  230. function FindControl(AControl: TControl): TControl;
  231. begin
  232. if AControl <> nil then
  233. Result := StatusBar.Owner.FindComponent(AControl.Name) as TControl
  234. else
  235. Result := nil;
  236. end;
  237. begin
  238. if Source is TTBXStatusPanel then
  239. begin
  240. ViewPriority := TTBXStatusPanel(Source).ViewPriority;
  241. Control := FindControl(TTBXStatusPanel(Source).Control);
  242. end
  243. else inherited Assign(Source);
  244. end;
  245. constructor TTBXStatusPanel.Create(Collection: TCollection);
  246. begin
  247. inherited Create(Collection);
  248. FSize := 50;
  249. FEnabled := True;
  250. FFramed := True;
  251. FImageIndex := -1;
  252. FViewPriority := 100;
  253. FFontSettings := TFontSettings.Create;
  254. TFontSettingsAccess(FFontSettings).OnChange := FontSettingsChanged;
  255. end;
  256. destructor TTBXStatusPanel.Destroy;
  257. var
  258. AControl: TControl;
  259. begin
  260. AControl := Control;
  261. FControl := nil;
  262. FFontSettings.Free;
  263. inherited Destroy;
  264. if (AControl <> nil) and not (csDestroying in AControl.ComponentState) and
  265. ((AControl is TWinControl) and TWinControl(AControl).HandleAllocated) then
  266. begin
  267. AControl.BringToFront;
  268. AControl.Perform(CM_SHOWINGCHANGED, 0, 0);
  269. end;
  270. end;
  271. function TTBXStatusPanel.GetDisplayName: string;
  272. begin
  273. Result := Caption;
  274. if (Result = '') and (Control <> nil) then Result := '[ ' + Control.Name + ' ]';
  275. if Result = '' then Result := inherited GetDisplayName;
  276. end;
  277. procedure TTBXStatusPanel.SetAlignment(Value: TAlignment);
  278. begin
  279. FAlignment := Value;
  280. Changed(False);
  281. end;
  282. procedure TTBXStatusPanel.SetCaption(const Value: TCaption);
  283. begin
  284. if Value <> FCaption then
  285. begin
  286. FCaption := Value;
  287. Changed(False);
  288. end;
  289. end;
  290. procedure TTBXStatusPanel.SetControl(Value: TControl);
  291. var
  292. Panel: TTBXStatusPanel;
  293. PrevControl: TControl;
  294. P: TControl;
  295. begin
  296. if FControl <> Value then
  297. begin
  298. if Value <> nil then
  299. begin
  300. P := StatusBar;
  301. while P <> nil do
  302. if P = Value then raise EInvalidOperation.Create('Can''t insert own parent')
  303. else P := P.Parent;
  304. Panel := TTBXStatusPanels(Collection).FindPanel(Value);
  305. if (Panel <> nil) and (Panel <> Self) then Panel.SetControl(nil);
  306. end;
  307. PrevControl := FControl;
  308. FControl := Value;
  309. FControl.Parent := StatusBar;
  310. if Value <> nil then Value.FreeNotification(StatusBar);
  311. Changed(True);
  312. if PrevControl <> nil then PrevControl.Perform(CM_SHOWINGCHANGED, 0, 0);
  313. end;
  314. end;
  315. procedure TTBXStatusPanel.SetEnabled(Value: Boolean);
  316. begin
  317. if Value <> FEnabled then
  318. begin
  319. FEnabled := Value;
  320. Changed(False);
  321. end;
  322. end;
  323. procedure TTBXStatusPanel.SetFramed(Value: Boolean);
  324. begin
  325. if Value <> FFramed then
  326. begin
  327. FFramed := Value;
  328. Changed(False);
  329. end;
  330. end;
  331. procedure TTBXStatusPanel.SetMaxSize(Value: Integer);
  332. begin
  333. if Value <> FMaxSize then
  334. begin
  335. FMaxSize := Value;
  336. Changed(True);
  337. end;
  338. end;
  339. procedure TTBXStatusPanel.SetViewPriority(Value: TPercent);
  340. begin
  341. if Value <> FViewPriority then
  342. begin
  343. FViewPriority := Value;
  344. Changed(True);
  345. end;
  346. end;
  347. procedure TTBXStatusPanel.SetSize(Value: Integer);
  348. begin
  349. if Value <> FSize then
  350. begin
  351. FSize := Value;
  352. Changed(True);
  353. end;
  354. end;
  355. procedure TTBXStatusPanel.SetStretchPriority(Value: TPercent);
  356. begin
  357. if Value <> FStretchPriority then
  358. begin
  359. FStretchPriority := Value;
  360. Changed(True);
  361. end;
  362. end;
  363. procedure TTBXStatusPanel.SetTextTruncation(Value: TTextTruncation);
  364. begin
  365. FTextTruncation := Value;
  366. Changed(False);
  367. end;
  368. function TTBXStatusPanel.StatusBar: TTBXCustomStatusBar;
  369. begin
  370. Result := TTBXStatusPanels(Collection).StatusBar;
  371. end;
  372. procedure TTBXStatusPanel.SetImageIndex(Value: TImageIndex);
  373. begin
  374. if Value <> FImageIndex then
  375. begin
  376. FImageIndex := Value;
  377. if StatusBar.Images <> nil then Changed(False);
  378. end;
  379. end;
  380. procedure TTBXStatusPanel.FontSettingsChanged(Sender: TObject);
  381. begin
  382. Changed(False);
  383. end;
  384. procedure TTBXStatusPanel.SetFontSettings(const Value: TFontSettings);
  385. begin
  386. FFontSettings := Value;
  387. end;
  388. { TTBXStatusPanels }
  389. function TTBXStatusPanels.Add: TTBXStatusPanel;
  390. begin
  391. Result := TTBXStatusPanel(inherited Add);
  392. end;
  393. constructor TTBXStatusPanels.Create(AStatusBar: TTBXCustomStatusBar);
  394. begin
  395. inherited Create(TTBXStatusPanel);
  396. FStatusBar := AStatusBar;
  397. end;
  398. function TTBXStatusPanels.FindPanel(AControl: TControl): TTBXStatusPanel;
  399. var
  400. I: Integer;
  401. begin
  402. for I := 0 to Count - 1 do
  403. begin
  404. Result := TTBXStatusPanel(inherited GetItem(I));
  405. if Result.FControl = AControl then Exit;
  406. end;
  407. Result := nil;
  408. end;
  409. function TTBXStatusPanels.GetItem(Index: Integer): TTBXStatusPanel;
  410. begin
  411. Result := TTBXStatusPanel(inherited GetItem(Index));
  412. end;
  413. function TTBXStatusPanels.GetOwner: TPersistent;
  414. begin
  415. Result := FStatusBar;
  416. end;
  417. procedure TTBXStatusPanels.SetItem(Index: Integer; Value: TTBXStatusPanel);
  418. begin
  419. inherited SetItem(Index, Value);
  420. end;
  421. procedure TTBXStatusPanels.Update(Item: TCollectionItem);
  422. begin
  423. FStatusBar.UpdatePanels;
  424. end;
  425. { TTBXCustomStatusBar }
  426. procedure TTBXCustomStatusBar.AdjustPanelContentRect(APanel: TTBXStatusPanel; var ARect: TRect);
  427. begin
  428. if APanel.Framed then
  429. with CachedPanelMargins do
  430. begin
  431. Inc(ARect.Left, LeftWidth);
  432. Inc(ARect.Top, TopHeight);
  433. Dec(ARect.Right, RightWidth);
  434. Dec(ARect.Bottom, BottomHeight);
  435. end;
  436. if Assigned(FOnAdjustContentRect) then FOnAdjustContentRect(Self, APanel, ARect);
  437. end;
  438. procedure TTBXCustomStatusBar.AlignControls(AControl: TControl; var Rect: TRect);
  439. begin
  440. if not (csDestroying in ComponentState) and (FUpdateCount = 0) and
  441. ((AControl = nil) and (Panels.Count > 0) or (AControl is TWinControl)) then
  442. begin
  443. Invalidate;
  444. UpdatePanels;
  445. end;
  446. end;
  447. procedure TTBXCustomStatusBar.BeginUpdate;
  448. begin
  449. Inc(FUpdateCount);
  450. end;
  451. procedure TTBXCustomStatusBar.Change;
  452. var
  453. Form: TCustomForm;
  454. begin
  455. if csDesigning in ComponentState then
  456. begin
  457. Form := GetParentForm(Self);
  458. if (Form <> nil) and (Form.Designer <> nil) then Form.Designer.Modified;
  459. end;
  460. end;
  461. procedure TTBXCustomStatusBar.ChangeScale(M, D: Integer; isDpiChange: Boolean);
  462. var
  463. I: Integer;
  464. Panel: TTBXStatusPanel;
  465. begin
  466. if UseSystemFont then ScalingFlags := [sfTop];
  467. { MP }
  468. // For VCL status bars, this is implemented in ApplySystemSettingsOnControl
  469. for I := 0 to Panels.Count - 1 do
  470. begin
  471. Panel := Panels[I];
  472. if Panel.StretchPriority = 0 then
  473. begin
  474. Panel.Size := MulDiv(Panel.Size, M, D);
  475. end;
  476. Panel.MaxSize := MulDiv(Panel.MaxSize, M, D);
  477. end;
  478. inherited;
  479. end;
  480. procedure TTBXCustomStatusBar.Click;
  481. var
  482. Pt: TPoint;
  483. Panel: TTBXStatusPanel;
  484. begin
  485. inherited;
  486. GetCursorPos(Pt);
  487. Panel := GetPanelAt(ScreenToClient(Pt));
  488. if Panel <> nil then DoPanelClick(Panel);
  489. end;
  490. procedure TTBXCustomStatusBar.CMControlChange(var Message: TCMControlChange);
  491. var
  492. Panel: TTBXStatusPanel;
  493. begin
  494. if FUpdateCount = 0 then
  495. begin
  496. { Can only accept TWinControl descendants }
  497. if not (csLoading in ComponentState) then
  498. if Message.Inserting and (Message.Control is TWinControl) then
  499. begin
  500. with Panels.Add do SetControl(Message.Control);
  501. end
  502. else
  503. begin
  504. Panel := Panels.FindPanel(Message.Control);
  505. if Panel <> nil then Panel.Free;
  506. end;
  507. end;
  508. end;
  509. procedure TTBXCustomStatusBar.CMFontChanged(var Message: TMessage);
  510. begin
  511. inherited;
  512. UpdatePanels;
  513. Invalidate;
  514. end;
  515. procedure TTBXCustomStatusBar.CMHintShow(var Message: TCMHintShow);
  516. var
  517. Panel: TTBXStatusPanel;
  518. begin
  519. Panel := GetPanelAt(Message.HintInfo.CursorPos);
  520. if Panel <> nil then
  521. begin
  522. Message.HintInfo.HintStr := Panel.Hint;
  523. Message.HintInfo.CursorRect := Panel.BoundsRect;
  524. end;
  525. end;
  526. procedure TTBXCustomStatusBar.CMVisibleChanged(var Message: TMessage);
  527. begin
  528. if FixAlign and (Parent <> nil) then Top := Parent.ClientHeight;
  529. inherited;
  530. end;
  531. constructor TTBXCustomStatusBar.Create(AOwner: TComponent);
  532. begin
  533. inherited Create(AOwner);
  534. ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents, csDoubleClicks];
  535. if not (csDesigning in ComponentState) then ControlStyle := ControlStyle - [csOpaque];
  536. Height := 22;
  537. Align := alBottom;
  538. Width := 150;
  539. FImageChangeLink := TChangeLink.Create;
  540. FImageChangeLink.OnChange := ImageListChange;
  541. FPanels := TTBXStatusPanels.Create(Self);
  542. FSizeGrip := True;
  543. DoubleBuffered := True;
  544. AddThemeNotification(Self);
  545. end;
  546. procedure TTBXCustomStatusBar.CreateParams(var Params: TCreateParams);
  547. begin
  548. inherited CreateParams(Params);
  549. with Params do
  550. WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
  551. end;
  552. procedure TTBXCustomStatusBar.CreateWnd;
  553. begin
  554. inherited CreateWnd;
  555. if not (csLoading in ComponentState) then UpdatePanels;
  556. end;
  557. procedure TTBXCustomStatusBar.DblClick;
  558. var
  559. Pt: TPoint;
  560. Panel: TTBXStatusPanel;
  561. begin
  562. inherited;
  563. GetCursorPos(Pt);
  564. Panel := GetPanelAt(ScreenToClient(Pt));
  565. if Panel <> nil then DoPanelDblClick(Panel);
  566. end;
  567. destructor TTBXCustomStatusBar.Destroy;
  568. begin
  569. RemoveThemeNotification(Self);
  570. FImageChangeLink.Free;
  571. FPanels.Free;
  572. inherited Destroy;
  573. end;
  574. procedure TTBXCustomStatusBar.DoAdjustFont(APanel: TTBXStatusPanel; AFont: TFont);
  575. begin
  576. { Changing AFont.Color will do nothing since it is replaced by the theme }
  577. if Assigned(FOnAdjustFont) then FOnAdjustFont(Self, APanel, AFont);
  578. end;
  579. procedure TTBXCustomStatusBar.DoPanelClick(APanel: TTBXStatusPanel);
  580. begin
  581. if Assigned(FOnPanelClick) then FOnPanelClick(Self, APanel);
  582. end;
  583. procedure TTBXCustomStatusBar.DoPanelDblClick(APanel: TTBXStatusPanel);
  584. begin
  585. if Assigned(FOnPanelDblClick) then FOnPanelDblClick(Self, APanel);
  586. end;
  587. procedure TTBXCustomStatusBar.EndUpdate;
  588. begin
  589. Dec(FUpdateCount);
  590. end;
  591. procedure TTBXCustomStatusBar.FlipChildren(AllLevels: Boolean);
  592. begin
  593. { do not flip controls }
  594. end;
  595. function TTBXCustomStatusBar.GetGripperRect: TRect;
  596. begin
  597. Result := ClientRect;
  598. with Result do
  599. begin
  600. Inc(Top, 3);
  601. // WORKAROUND: Should use GetSystemMetricsForControl, but as of now,
  602. // the grip bitmap drawn by DrawThemeBackground(..., SP_GRIPPER, ...) is not scaled
  603. Left := Right - GetSystemMetrics(SM_CXVSCROLL);
  604. end;
  605. end;
  606. function TTBXCustomStatusBar.GetPanelAt(const Pt: TPoint): TTBXStatusPanel;
  607. var
  608. I: Integer;
  609. begin
  610. for I := 0 to Panels.Count - 1 do
  611. begin
  612. Result := Panels[I];
  613. if Result.CachedVisible and PtInRect(Panels[I].BoundsRect, Pt) then Exit;
  614. end;
  615. Result := nil;
  616. end;
  617. function TTBXCustomStatusBar.GetPanelAt(X, Y: Integer): TTBXStatusPanel;
  618. begin
  619. Result := GetPanelAt(Point(X, Y));
  620. end;
  621. function TTBXCustomStatusBar.GetPanelRect(APanel: TTBXStatusPanel): TRect;
  622. begin
  623. if (APanel <> nil) and APanel.CachedVisible then Result := APanel.CachedBounds
  624. else Result := Rect(0, 0, 0, 0);
  625. end;
  626. procedure TTBXCustomStatusBar.ImageListChange(Sender: TObject);
  627. begin
  628. if Sender = Images then Invalidate;
  629. end;
  630. function TTBXCustomStatusBar.IsSizeGripVisible: Boolean;
  631. var
  632. ParentForm: TCustomForm;
  633. PBR, BR: TPoint;
  634. begin
  635. Result := False;
  636. if SizeGrip then
  637. begin
  638. ParentForm := GetParentForm(Self);
  639. if (ParentForm <> nil) and (ParentForm.WindowState = wsNormal) then
  640. begin
  641. PBR := ParentForm.ClientToScreen(ParentForm.ClientRect.BottomRight);
  642. BR := ClientToScreen(ClientRect.BottomRight);
  643. Result := (PBR.X = BR.X) and (PBR.Y = BR.Y);
  644. end;
  645. end;
  646. end;
  647. procedure TTBXCustomStatusBar.Loaded;
  648. begin
  649. inherited Loaded;
  650. UpdatePanels;
  651. end;
  652. procedure TTBXCustomStatusBar.Notification(AComponent: TComponent; Operation: TOperation);
  653. var
  654. Panel: TTBXStatusPanel;
  655. begin
  656. inherited Notification(AComponent, Operation);
  657. if Operation = opRemove then
  658. begin
  659. if not (csDestroying in ComponentState) then
  660. begin
  661. Panel := Panels.FindPanel(TControl(AComponent));
  662. if Panel <> nil then Panel.FControl := nil;
  663. end
  664. else if AComponent = Images then Images := nil;
  665. end;
  666. end;
  667. procedure TTBXCustomStatusBar.Paint;
  668. const
  669. CEnabledState: array [Boolean] of Integer = (ISF_DISABLED, 0);
  670. var
  671. CR, R: TRect;
  672. I: Integer;
  673. Panel: TTBXStatusPanel;
  674. PartID: Integer;
  675. Flags: Cardinal;
  676. begin
  677. inherited;
  678. CR := ClientRect;
  679. CurrentTheme.PaintStatusBar(Self, Canvas, CR, SBP_BODY);
  680. Inc(CR.Top, 2);
  681. if SimplePanel then
  682. begin
  683. if Length(SimpleText) > 0 then
  684. begin
  685. if UseSystemFont then Canvas.Font := GetToolbarFont(Self)
  686. else Canvas.Font := Self.Font;
  687. Canvas.Font.Color := GetTBXTextColor(CEnabledState[Enabled]);
  688. Canvas.Brush.Style := bsClear;
  689. Flags := DT_SINGLELINE or DT_VCENTER;
  690. InflateRect(CR, -4, 0);
  691. DrawTBXCaption(Canvas, CR, SimpleText, Flags, ISF_STATUSCOLOR or CEnabledState[Enabled]);
  692. Canvas.Brush.Style := bsSolid;
  693. end;
  694. end
  695. else
  696. for I := 0 to Panels.Count - 1 do
  697. begin
  698. Panel := Panels[I];
  699. if Panel.CachedVisible and RectVisible(Canvas.Handle, Panel.CachedBounds) then
  700. begin
  701. R := Panel.CachedBounds;
  702. if Panel.Framed then
  703. begin
  704. if Panel.CachedGripper then PartID := SBP_LASTPANE
  705. else PartID := SBP_PANE;
  706. CurrentTheme.PaintStatusBar(Self, Canvas, R, PartID);
  707. end;
  708. if UseSystemFont then Canvas.Font := GetToolbarFont(Self)
  709. else Canvas.Font := Self.Font;
  710. Canvas.Font.Color := GetTBXTextColor(CEnabledState[Panel.Enabled]);
  711. Panel.FontSettings.Apply(Canvas.Font);
  712. DoAdjustFont(Panel, Canvas.Font);
  713. AdjustPanelContentRect(Panel, R);
  714. PaintPanel(R, Panel, I = Panels.Count - 1);
  715. end;
  716. end;
  717. if IsSizeGripVisible then
  718. CurrentTheme.PaintStatusBar(Self, Canvas, GetGripperRect, SBP_GRIPPER);
  719. end;
  720. procedure TTBXCustomStatusBar.PaintPanel(ARect: TRect; APanel: TTBXStatusPanel; IsLast: Boolean);
  721. const
  722. EnabledState: array [Boolean] of Integer = (ISF_DISABLED, 0);
  723. Alignments: array [TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
  724. Truncations: array [TTextTruncation] of Integer = (0, DT_END_ELLIPSIS, DT_PATH_ELLIPSIS);
  725. var
  726. Flags: Integer;
  727. R: TRect;
  728. begin
  729. InflateRect(ARect, TBXScaleByTextHeightRunTime(Canvas, -3), 0);
  730. if (APanel.ImageIndex >= 0) and (Images <> nil) then
  731. begin
  732. R := ARect;
  733. R.Top := (R.Top + R.Bottom - Images.Height) div 2;
  734. R.Bottom := R.Top + Images.Height;
  735. case APanel.Alignment of
  736. taLeftJustify:
  737. begin
  738. R.Right := R.Left + Images.Width;
  739. ARect.Left := R.Right + TBXScaleByTextHeightRunTime(Canvas, 4);
  740. end;
  741. taRightJustify:
  742. begin
  743. R.Left := R.Right - Images.Width;
  744. ARect.Right := R.Left - TBXScaleByTextHeightRunTime(Canvas, 4);
  745. end;
  746. taCenter:
  747. begin
  748. R.Left := (R.Left + R.Right - Images.Width) div 2;
  749. R.Right := R.Left + Images.Width;
  750. end;
  751. end;
  752. if APanel.Enabled then Images.Draw(Canvas, R.Left, R.Top, APanel.ImageIndex)
  753. else DrawTBXImage(Canvas, R, Images, APanel.ImageIndex, ISF_DISABLED);
  754. end;
  755. Canvas.Brush.Style := bsClear;
  756. Flags := DT_SINGLELINE or DT_VCENTER or Alignments[APanel.Alignment] or Truncations[APanel.TextTruncation];
  757. DrawTBXCaption(Canvas, ARect, APanel.Caption, Flags, ISF_STATUSCOLOR or EnabledState[APanel.Enabled]);
  758. Canvas.Brush.Style := bsSolid;
  759. end;
  760. procedure TTBXCustomStatusBar.Resize;
  761. begin
  762. UpdatePanels;
  763. Invalidate;
  764. inherited;
  765. end;
  766. procedure TTBXCustomStatusBar.SetImages(Value: TCustomImageList);
  767. begin
  768. if FImages <> nil then FImages.UnRegisterChanges(FImageChangeLink);
  769. FImages := Value;
  770. if FImages <> nil then
  771. begin
  772. FImages.RegisterChanges(FImageChangeLink);
  773. FImages.FreeNotification(Self);
  774. end;
  775. Invalidate;
  776. end;
  777. procedure TTBXCustomStatusBar.SetPanels(Value: TTBXStatusPanels);
  778. begin
  779. FPanels.Assign(Value);
  780. end;
  781. procedure TTBXCustomStatusBar.SetSimplePanel(Value: Boolean);
  782. begin
  783. if FSimplePanel <> Value then
  784. begin
  785. FSimplePanel := Value;
  786. Invalidate;
  787. end;
  788. end;
  789. procedure TTBXCustomStatusBar.SetSimpleText(const Value: TCaption);
  790. begin
  791. if FSimpleText <> Value then
  792. begin
  793. FSimpleText := Value;
  794. Invalidate;
  795. end;
  796. end;
  797. procedure TTBXCustomStatusBar.SetSizeGrip(Value: Boolean);
  798. begin
  799. FSizeGrip := Value;
  800. Invalidate;
  801. end;
  802. procedure TTBXCustomStatusBar.SetUseSystemFont(Value: Boolean);
  803. begin
  804. if Value <> FUseSystemFont then
  805. begin
  806. FUseSystemFont := Value;
  807. UpdatePanels;
  808. Invalidate;
  809. end;
  810. end;
  811. procedure TTBXCustomStatusBar.TBMThemeChange(var Message);
  812. begin
  813. UpdatePanels;
  814. Invalidate;
  815. end;
  816. procedure TTBXCustomStatusBar.UpdateCache;
  817. var
  818. CR: TRect;
  819. Position, I: Integer;
  820. MaxWidth, WorkWidth: Integer;
  821. TotalSize, Delta, NewSize: Integer;
  822. SortList: TList;
  823. Panel: TTBXStatusPanel;
  824. begin
  825. if Panels.Count = 0 then Exit;
  826. CurrentTheme.GetMargins(MID_STATUSPANE, CachedPanelMargins);
  827. CR := ClientRect;
  828. Inc(CR.Top, 2);
  829. Position := 0;
  830. MaxWidth := CR.Right - CR.Left;
  831. WorkWidth := MaxWidth;
  832. TotalSize := 0;
  833. SortList := TList.Create;
  834. try
  835. { First Pass: Gather the panels with non-zero ViewPriority }
  836. for I := 0 to Panels.Count - 1 do
  837. with Panels[I] do
  838. begin
  839. CachedGripper := False;
  840. if ViewPriority > 0 then
  841. begin
  842. CachedSize := Size;
  843. CachedVisible := True;
  844. Inc(TotalSize, Size);
  845. SortList.Add(Panels[I])
  846. end
  847. else
  848. CachedVisible := False;
  849. end;
  850. SortList.Sort(CompareViewPriorities);
  851. { If necessary, hide the panels with low ViewPriority }
  852. if TotalSize > WorkWidth then
  853. begin
  854. while (TotalSize > WorkWidth) and (SortList.Count > 1) and
  855. (TTBXStatusPanel(SortList.Last).ViewPriority < 100) do
  856. begin
  857. TTBXStatusPanel(SortList.Last).CachedVisible := False;
  858. Dec(TotalSize, TTBXStatusPanel(SortList.Last).Size);
  859. SortList.Count := SortList.Count - 1;
  860. end;
  861. end;
  862. { Stretch to fill the empty space }
  863. Delta := WorkWidth - TotalSize;
  864. if Delta > 0 then
  865. begin
  866. for I := SortList.Count - 1 downto 0 do
  867. if TTBXStatusPanel(SortList[I]).StretchPriority = 0 then SortList.Delete(I);
  868. while (SortList.Count > 0) and (Delta > 0) do
  869. begin
  870. SortList.Sort(CompareStretchPriorities);
  871. { Start stretching with higher ViewPriority panels}
  872. Panel := TTBXStatusPanel(SortList.Last);
  873. NewSize := Panel.CachedSize + Delta;
  874. if (Panel.MaxSize > Panel.CachedSize) and (NewSize > Panel.MaxSize) then
  875. begin
  876. NewSize := Panel.MaxSize;
  877. end;
  878. // MP fix (this was inside branch above, but it has to be done always)
  879. Dec(Delta, NewSize - Panel.CachedSize);
  880. Panel.CachedSize := NewSize;
  881. SortList.Count := SortList.Count - 1;
  882. end;
  883. end;
  884. for I := 0 to Panels.Count - 1 do
  885. with Panels[I] do
  886. begin
  887. if Position >= WorkWidth then CachedVisible := False;
  888. if CachedVisible then
  889. begin
  890. CachedBounds := CR;
  891. CachedBounds.Left := Position;
  892. Inc(Position, CachedSize);
  893. if Position = WorkWidth then CachedGripper := True;
  894. CachedBounds.Right := Position;
  895. end
  896. else CachedBounds := Rect(0, 0, 0, 0);
  897. end;
  898. finally
  899. SortList.Free;
  900. end;
  901. end;
  902. procedure TTBXCustomStatusBar.UpdatePanels;
  903. var
  904. I: Integer;
  905. R: TRect;
  906. begin
  907. Invalidate;
  908. UpdateCache;
  909. for I := 0 to Panels.Count - 1 do
  910. begin
  911. with Panels[I] do
  912. if Visible then
  913. begin
  914. if Control <> nil then
  915. begin
  916. R := CachedBounds;
  917. if Framed then
  918. with CachedPanelMargins do
  919. begin
  920. Inc(R.Left, LeftWidth);
  921. Inc(R.Top, TopHeight);
  922. Dec(R.Right, RightWidth);
  923. Dec(R.Bottom, BottomHeight);
  924. end;
  925. Control.BoundsRect := R;
  926. end;
  927. end
  928. else if Control <> nil then Control.BoundsRect := Rect(0, 0, 0, 0);
  929. end;
  930. end;
  931. procedure TTBXCustomStatusBar.WMEraseBkgnd(var Message: TWMEraseBkgnd);
  932. begin
  933. Message.Result := 1;
  934. end;
  935. procedure TTBXCustomStatusBar.WMNCHitTest(var Message: TWMNCHitTest);
  936. var
  937. Pt: TPoint;
  938. begin
  939. inherited;
  940. if (Message.Result = HTCLIENT) and IsSizeGripVisible then
  941. begin
  942. Pt := ScreenToClient(SmallPointToPoint(Message.Pos));
  943. if PtInRect(GetGripperRect, Pt) then Message.Result := HTBOTTOMRIGHT;
  944. end;
  945. end;
  946. initialization
  947. end.