TBXStatusBars.pas 30 KB

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