1
0

TBXLists.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. unit TBXLists;
  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: TBXLists.pas 7 2004-02-21 06:07:53Z
  7. interface
  8. {$I TB2Ver.inc}
  9. {$I TBX.inc}
  10. uses
  11. Windows, Messages, Classes, SysUtils, Controls, Forms, Graphics, TB2Item, TBX,
  12. TBXThemes, UxTheme, ImgList;
  13. type
  14. { TTBXScrollBar }
  15. TSBIncrement = 1..1000;
  16. TSBZone = (sbzEmpty, sbzPrev, sbzPagePrev, sbzHandle, sbzPageNext, sbzNext);
  17. TSBAutoScrollEvent = procedure(Sender: TObject; var Direction, Interval: Integer) of object;
  18. TTBXScrollBar = class
  19. private
  20. FBounds: TRect;
  21. FLeft: Integer;
  22. FHandle: HWND;
  23. FHeight: Integer;
  24. FIncrement: TSBIncrement;
  25. FKind: TScrollBarKind;
  26. FPosition: Integer;
  27. FRange: Integer;
  28. FRight: Integer;
  29. FTop: Integer;
  30. FWidth: Integer;
  31. FWindow: Integer;
  32. FOnChange: TNotifyEvent;
  33. FOnAutoScroll: TSBAutoScrollEvent;
  34. FOnRedrawRequest: TNotifyEvent;
  35. procedure SetBounds(const Value: TRect);
  36. procedure SetKind(Value: TScrollBarKind);
  37. procedure SetPosition(Value: Integer);
  38. procedure SetRange(Value: Integer);
  39. function GetHandle: HWND;
  40. protected
  41. AutoScrollDirection: Integer;
  42. AutoScrolling: Boolean;
  43. AutoScrollInterval: Integer;
  44. Zones: array [TSBZone] of TRect;
  45. MouseDownZone: TSBZone;
  46. MouseDownPoint: TPoint;
  47. MouseDownPosition: Integer;
  48. LastMousePoint: TPoint;
  49. PrevCapture: HWND;
  50. UserChange: Boolean;
  51. procedure AdjustPosition(var NewPosition: Integer);
  52. procedure CreateWnd;
  53. procedure DestroyWnd;
  54. function GetZone(X, Y: Integer): TSBZone;
  55. function GetEffectiveWindow: Integer;
  56. function GetEnabled: Boolean; virtual;
  57. procedure HandleZoneClick(AZone: TSBZone);
  58. procedure MouseDown(Button: TMouseButton; X, Y: Integer); virtual;
  59. procedure MouseMove(X, Y: Integer); virtual;
  60. procedure MouseUp(Button: TMouseButton; X, Y: Integer); virtual;
  61. procedure PaintButton(Canvas: TCanvas; Rect: TRect; Direction: Integer; Pushed, Enabled: Boolean);
  62. procedure PaintHandle(Canvas: TCanvas; Rect: TRect; Pushed, Enabled: Boolean);
  63. procedure PaintTrack(Canvas: TCanvas; Rect: TRect; IsNextZone, Pushed, Enabled: Boolean);
  64. procedure PaintTo(Canvas: TCanvas);
  65. procedure SBWndProc(var Message: TMessage);
  66. procedure StartAutoScroll(Direction, Interval: Integer);
  67. procedure StopAutoScroll;
  68. procedure StartTimer(ID: Integer; Elapse: Integer);
  69. procedure StopTimer(ID: Integer);
  70. procedure TimerElapsed(ID: Integer; var NewElapse: Integer); virtual;
  71. procedure UpdateZones;
  72. property Handle: HWND read GetHandle;
  73. public
  74. constructor Create;
  75. destructor Destroy; override;
  76. procedure Redraw; virtual;
  77. procedure UpdatePosition(NewPosition: Integer);
  78. property Kind: TScrollBarKind read FKind write SetKind;
  79. property Bounds: TRect read FBounds write SetBounds;
  80. property Left: Integer read FLeft;
  81. property Height: Integer read FHeight;
  82. property Increment: TSBIncrement read FIncrement write FIncrement;
  83. property Position: Integer read FPosition write SetPosition;
  84. property Range: Integer read FRange write SetRange;
  85. property Right: Integer read FRight;
  86. property Top: Integer read FTop;
  87. property Width: Integer read FWidth;
  88. property Window: Integer read FWindow write FWindow;
  89. property OnAutoScroll: TSBAutoScrollEvent read FOnAutoScroll write FOnAutoScroll;
  90. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  91. property OnRedrawRequest: TNotifyEvent read FOnRedrawRequest write FOnRedrawRequest;
  92. end;
  93. { TTBXCustomList }
  94. TTBXCustomList = class;
  95. TTBXLMeasureHeight = procedure(Sender: TTBXCustomList; ACanvas: TCanvas; var AHeight: Integer) of object;
  96. TTBXLMeasureWidth = procedure(Sender: TTBXCustomList; ACanvas: TCanvas; AIndex: Integer; var AWidth: Integer) of object;
  97. TTBXLPaintEvent = procedure(Sender: TTBXCustomList; ACanvas: TCanvas; ARect: TRect; AIndex, AHoverIndex: Integer; var DrawDefault: Boolean) of object;
  98. TTBXLAdjustImageIndex = procedure(Sender: TTBXCustomList; AItemIndex: Integer; var ImageIndex: Integer) of object;
  99. TTBXCustomListViewer = class;
  100. TTBXCustomList = class(TTBXCustomItem)
  101. private
  102. FViewers: TList;
  103. FItemIndex: Integer;
  104. FMinWidth: Integer;
  105. FMaxWidth: Integer;
  106. FMaxVisibleItems: Integer;
  107. FShowImages: Boolean;
  108. FOnChange: TNotifyEvent;
  109. FOnClearItem: TTBXLPaintEvent;
  110. FOnDrawItem: TTBXLPaintEvent;
  111. FOnAdjustImageIndex: TTBXLAdjustImageIndex;
  112. FOnMeasureHeight: TTBXLMeasureHeight;
  113. FOnMeasureWidth: TTBXLMeasureWidth;
  114. procedure SetItemIndex(Value: Integer);
  115. protected
  116. function DoClearItem(ACanvas: TCanvas; ARect: TRect; AIndex, AHoverIndex: Integer): Boolean; virtual;
  117. function DoDrawItem(ACanvas: TCanvas; {MP} var ARect: TRect; AIndex, AHoverIndex: Integer): Boolean; virtual;
  118. procedure DoMeasureHeight(ACanvas: TCanvas; var AHeight: Integer); virtual;
  119. procedure DoMeasureWidth(ACanvas: TCanvas; AIndex: Integer; var AWidth: Integer); virtual;
  120. procedure DrawItem(ACanvas: TCanvas; AViewer: TTBXCustomListViewer; const ARect: TRect; AIndex, AHoverIndex: Integer); virtual;
  121. function GetImageIndex(ItemIndex: Integer): Integer; virtual;
  122. function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; override;
  123. function GetItemText(Index: Integer): string; virtual; abstract;
  124. function GetCount: Integer; virtual; abstract;
  125. procedure HandleChange; virtual;
  126. procedure HandleHover(AIndex: Integer); virtual;
  127. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  128. public
  129. constructor Create(AOwner: TComponent); override;
  130. procedure MakeVisible(AIndex: Integer);
  131. property ItemIndex: Integer read FItemIndex write SetItemIndex default -1;
  132. property MaxVisibleItems: Integer read FMaxVisibleItems write FMaxVisibleItems default 8;
  133. property MaxWidth: Integer read FMaxWidth write FMaxWidth default 0;
  134. property MinWidth: Integer read FMinWidth write FMinWidth default 32;
  135. property ShowImages: Boolean read FShowImages write FShowImages default False;
  136. property OnAdjustImageIndex: TTBXLAdjustImageIndex read FOnAdjustImageIndex write FOnAdjustImageIndex;
  137. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  138. property OnClearItem: TTBXLPaintEvent read FOnClearItem write FOnClearItem;
  139. property OnDrawItem: TTBXLPaintEvent read FOnDrawItem write FOnDrawItem;
  140. property OnMeasureHeight: TTBXLMeasureHeight read FOnMeasureHeight write FOnMeasureHeight;
  141. property OnMeasureWidth: TTBXLMeasureWidth read FOnMeasureWidth write FOnMeasureWidth;
  142. end;
  143. TTBXCustomListViewer = class(TTBXItemViewer)
  144. private
  145. FItemCount: Integer;
  146. FItemHeight: Integer;
  147. FHoverIndex: Integer;
  148. FHeight: Integer;
  149. FLastClientRect: TRect;
  150. FWheelAccumulator: Integer;
  151. FWidth: Integer;
  152. FOffset: Integer;
  153. FScrollBarWidth: Integer;
  154. FScrollBar: TTBXScrollBar;
  155. FVisibleItems: Integer;
  156. procedure ListChangeHandler(NewIndex: Integer);
  157. procedure SBAutoScrollHandler(Sender: TObject; var Direction, Interval: Integer);
  158. procedure SBChangeHandler(Sender: TObject);
  159. procedure SBRedrawHandler(Sender: TObject);
  160. protected
  161. MouseIsDown: Boolean;
  162. MouseInScrollBar: Boolean;
  163. IgnoreMouseUp: Boolean;
  164. IsChanging: Boolean;
  165. procedure AdjustAutoScrollHover(var AIndex: Integer; Direction: Integer); virtual;
  166. procedure CalcSize(const Canvas: TCanvas; var AWidth, AHeight: Integer); override;
  167. procedure DrawItems(const Canvas: TCanvas; const ClientAreaRect: TRect);
  168. function GetItemIndexAt(X, Y: Integer): Integer;
  169. function GetItemRect(Index: Integer): TRect;
  170. function GetItemHeight(ACanvas: TCanvas): Integer; virtual;
  171. function GetItemWidth(ACanvas: TCanvas; Index: Integer): Integer; virtual;
  172. procedure HandleAutoScroll(var Direction, Interval: Integer); virtual;
  173. procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  174. procedure MakeVisible(Index: Integer);
  175. procedure MouseDown(Shift: TShiftState; X, Y: Integer; var MouseDownOnMenu: Boolean); override;
  176. procedure MouseMove(X, Y: Integer); override;
  177. procedure MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean); override;
  178. procedure MouseWheel(WheelDelta: Integer; X, Y: Integer); override;
  179. procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect; IsHoverItem, IsPushed, UseDisabledShadow: Boolean); override;
  180. procedure UpdateItems;
  181. property HoverIndex: Integer read FHoverIndex write FHoverIndex;
  182. property Offset: Integer read FOffset; {vb+}
  183. property VisibleItems: Integer read FVisibleItems; {vb+}
  184. public
  185. constructor Create(AView: TTBView; AItem: TTBCustomItem; AGroupLevel: Integer); override;
  186. destructor Destroy; override;
  187. end;
  188. { TTBXStringList }
  189. TTBXStringList = class(TTBXCustomList)
  190. private
  191. FStrings: TStrings;
  192. procedure SetStrings(Value: TStrings);
  193. protected
  194. function GetItemText(Index: Integer): string; override;
  195. function GetCount: Integer; override;
  196. public
  197. constructor Create(AOwner: TComponent); override;
  198. destructor Destroy; override;
  199. published
  200. property ItemIndex;
  201. property MaxVisibleItems;
  202. property MaxWidth;
  203. property MinWidth;
  204. property Strings: TStrings read FStrings write SetStrings;
  205. property OnAdjustImageIndex;
  206. property OnChange;
  207. property OnClearItem;
  208. property OnClick;
  209. property OnDrawItem;
  210. property OnMeasureHeight;
  211. property OnMeasureWidth;
  212. end;
  213. TTBXStringListClass = class of TTBXStringList;
  214. {$IFNDEF MPEXCLUDE}
  215. { TTBXUndoList }
  216. TTBXUndoList = class(TTBXStringList)
  217. protected
  218. procedure DrawItem(ACanvas: TCanvas; AViewer: TTBXCustomListViewer; const ARect: TRect; AIndex, AHoverIndex: Integer); override;
  219. function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; override;
  220. procedure HandleHover(AIndex: Integer); override;
  221. end;
  222. TTBXUndoListViewer = class(TTBXCustomListViewer)
  223. protected
  224. procedure AdjustAutoScrollHover(var AIndex: Integer; Direction: Integer); override;
  225. procedure HandleAutoScroll(var Direction, Interval: Integer); override;
  226. end;
  227. {$ENDIF}
  228. implementation
  229. uses Types;
  230. type TTBViewAccess = class(TTBView);
  231. const
  232. SCROLL_TIMER = 1;
  233. AUTO_SCROLL_TIMER = 2;
  234. MIN_SB_HANDLE_SIZE = 8;
  235. CImageSpacing = 4;
  236. //----------------------------------------------------------------------------//
  237. { TTBXScrollBar }
  238. procedure TTBXScrollBar.AdjustPosition(var NewPosition: Integer);
  239. var
  240. W: Integer;
  241. begin
  242. W := GetEffectiveWindow;
  243. if NewPosition + W > Range then NewPosition := Range - W;
  244. if NewPosition < 0 then NewPosition := 0;
  245. end;
  246. constructor TTBXScrollBar.Create;
  247. begin
  248. FIncrement := 1;
  249. end;
  250. procedure TTBXScrollBar.CreateWnd;
  251. begin
  252. if FHandle = 0 then FHandle := {$IFDEF JR_D6}Classes.{$ENDIF}AllocateHWnd(SBWndProc);
  253. end;
  254. destructor TTBXScrollBar.Destroy;
  255. begin
  256. DestroyWnd;
  257. inherited;
  258. end;
  259. procedure TTBXScrollBar.DestroyWnd;
  260. begin
  261. if FHandle <> 0 then
  262. begin
  263. {$IFDEF JR_D6}Classes.{$ENDIF}DeallocateHWnd(FHandle);
  264. FHandle := 0;
  265. end;
  266. end;
  267. function TTBXScrollBar.GetEffectiveWindow: Integer;
  268. begin
  269. if Window <= 0 then
  270. begin
  271. if Kind = sbVertical then Result := Height
  272. else Result := Width;
  273. end
  274. else Result := Window;
  275. end;
  276. function TTBXScrollBar.GetEnabled: Boolean;
  277. begin
  278. Result := Range > GetEffectiveWindow;
  279. end;
  280. function TTBXScrollBar.GetHandle: HWND;
  281. begin
  282. if FHandle = 0 then CreateWnd;
  283. Result := FHandle;
  284. end;
  285. function TTBXScrollBar.GetZone(X, Y: Integer): TSBZone;
  286. var
  287. I: Integer;
  288. Pt: TPoint;
  289. begin
  290. Pt.X := X;
  291. Pt.Y := Y;
  292. for I := Ord(sbzPrev) to Ord(sbzNext) do
  293. begin
  294. Result := TSBZone(I);
  295. if PtInRect(Zones[Result], Pt) then Exit;
  296. end;
  297. Result := sbzEmpty;
  298. end;
  299. procedure TTBXScrollBar.HandleZoneClick(AZone: TSBZone);
  300. begin
  301. UserChange := True;
  302. case AZone of
  303. sbzPrev: Position := Position - Increment;
  304. sbzPagePrev: Position := Position - GetEffectiveWindow;
  305. sbzPageNext: Position := Position + GetEffectiveWindow;
  306. sbzNext: Position := Position + Increment;
  307. end;
  308. UserChange := False;
  309. end;
  310. procedure TTBXScrollBar.MouseDown(Button: TMouseButton; X, Y: Integer);
  311. begin
  312. if Button = mbLeft then
  313. begin
  314. MouseDownZone := GetZone(X, Y);
  315. MouseDownPoint := Point(X, Y);
  316. MouseDownPosition := Position;
  317. LastMousePoint := MouseDownPoint;
  318. if MouseDownZone in [sbzPrev, sbzPagePrev, sbzPageNext, sbzNext] then
  319. begin
  320. HandleZoneClick(MouseDownZone);
  321. StartTimer(SCROLL_TIMER, 500);
  322. end;
  323. Redraw;
  324. end;
  325. end;
  326. procedure TTBXScrollBar.MouseMove(X, Y: Integer);
  327. var
  328. Delta: Integer;
  329. ClientSize, HandleSize: Integer;
  330. begin
  331. LastMousePoint := Point(X, Y);
  332. if MouseDownZone = sbzHandle then
  333. begin
  334. if Kind = sbVertical then
  335. begin
  336. Delta := Y - MouseDownPoint.Y;
  337. ClientSize := Zones[sbzPageNext].Bottom - Zones[sbzPagePrev].Top;
  338. end
  339. else
  340. begin
  341. Delta := X - MouseDownPoint.X;
  342. ClientSize := Zones[sbzPageNext].Right - Zones[sbzPagePrev].Left;
  343. end;
  344. HandleSize := Round(ClientSize * Window / Range);
  345. if HandleSize < MIN_SB_HANDLE_SIZE then
  346. Delta := Round(Delta * (Range - Window) / (ClientSize - MIN_SB_HANDLE_SIZE))
  347. else
  348. Delta := Round(Delta * Range / ClientSize);
  349. if MouseDownPosition + Delta <> Position then
  350. begin
  351. UserChange := True;
  352. Position := MouseDownPosition + Delta;
  353. UserChange := False;
  354. end;
  355. end;
  356. end;
  357. procedure TTBXScrollBar.MouseUp(Button: TMouseButton; X, Y: Integer);
  358. begin
  359. StopTimer(SCROLL_TIMER);
  360. if Button = mbLeft then
  361. begin
  362. MouseDownZone := sbzEmpty;
  363. Redraw;
  364. end;
  365. end;
  366. procedure TTBXScrollBar.PaintButton(Canvas: TCanvas; Rect: TRect;
  367. Direction: Integer; Pushed, Enabled: Boolean);
  368. const
  369. DirectionFlags: array [0..3] of Cardinal = (DFCS_SCROLLLEFT, DFCS_SCROLLUP,
  370. DFCS_SCROLLRIGHT, DFCS_SCROLLDOWN);
  371. EnabledFlags: array [Boolean] of Cardinal = (DFCS_INACTIVE, 0);
  372. PushedFlags: array [Boolean] of Cardinal = (0, DFCS_PUSHED or DFCS_FLAT);
  373. DirectionXPFlags: array [0..3] of Cardinal = (ABS_LEFTNORMAL, ABS_UPNORMAL,
  374. ABS_RIGHTNORMAL, ABS_DOWNNORMAL);
  375. var
  376. StateFlags: Cardinal;
  377. begin
  378. if USE_THEMES then
  379. begin
  380. StateFlags := DirectionXPFlags[Direction];
  381. if not Enabled then Inc(StateFlags, 3)
  382. else if Pushed then Inc(StateFlags, 2);
  383. DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, SBP_ARROWBTN, StateFlags, Rect, nil);
  384. end
  385. else
  386. begin
  387. DrawFrameControl(Canvas.Handle, Rect, DFC_SCROLL,
  388. DirectionFlags[Direction] or EnabledFlags[Enabled] or PushedFlags[Pushed]);
  389. end;
  390. end;
  391. procedure TTBXScrollBar.PaintHandle(Canvas: TCanvas; Rect: TRect; Pushed, Enabled: Boolean);
  392. const
  393. PartXPFlags: array [TScrollBarKind] of Cardinal = (SBP_THUMBBTNHORZ, SBP_THUMBBTNVERT);
  394. var
  395. StateFlags: Cardinal;
  396. begin
  397. if USE_THEMES then
  398. begin
  399. StateFlags := SCRBS_NORMAL;
  400. if not Enabled then Inc(StateFlags, 3)
  401. else if Pushed then Inc(StateFlags, 2);
  402. DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, PartXPFlags[Kind], StateFlags, Rect, nil);
  403. end
  404. else
  405. begin
  406. DrawEdge(Canvas.Handle, Rect, EDGE_RAISED, BF_RECT or BF_ADJUST);
  407. Canvas.Brush.Color := clBtnFace;
  408. Canvas.FillRect(Rect);
  409. end;
  410. end;
  411. procedure TTBXScrollBar.PaintTo(Canvas: TCanvas);
  412. var
  413. R: TRect;
  414. E, IsVert: Boolean;
  415. I: Integer;
  416. Dummy: TPoint;
  417. begin
  418. UpdateZones;
  419. IsVert := Kind = sbVertical;
  420. E := GetEnabled;
  421. OffsetWindowOrgEx(Canvas.Handle, -Bounds.Left, -Bounds.Top, Dummy);
  422. try
  423. if IsVert then I := 1 else I := 0;
  424. PaintButton(Canvas, Zones[sbzPrev], I, MouseDownZone = sbzPrev, E);
  425. PaintButton(Canvas, Zones[sbzNext], I + 2, MouseDownZone = sbzNext, E);
  426. if not IsRectEmpty(Zones[sbzEmpty]) then
  427. begin
  428. Canvas.Brush.Color := clScrollBar;
  429. Canvas.Brush.Style := bsSolid;
  430. Canvas.FillRect(Zones[sbzEmpty]);
  431. end;
  432. if not IsRectEmpty(Zones[sbzPagePrev]) or not IsRectEmpty(Zones[sbzPageNext]) then
  433. begin
  434. R := Zones[sbzPagePrev];
  435. PaintTrack(Canvas, R, False, MouseDownZone = sbzPagePrev, E);
  436. R := Zones[sbzPageNext];
  437. PaintTrack(Canvas, R, True, MouseDownZone = sbzPageNext, E);
  438. end;
  439. if not IsRectEmpty(Zones[sbzHandle]) then
  440. PaintHandle(Canvas, Zones[sbzHandle], MouseDownZone = sbzHandle, E);
  441. finally
  442. OffsetWindowOrgEx(Canvas.Handle, Bounds.Left, Bounds.Top, Dummy);
  443. end;
  444. end;
  445. procedure TTBXScrollBar.PaintTrack(Canvas: TCanvas; Rect: TRect;
  446. IsNextZone, Pushed, Enabled: Boolean);
  447. const
  448. PartXPFlags: array [Boolean, TScrollBarKind] of Cardinal =
  449. ((SBP_LOWERTRACKHORZ, SBP_LOWERTRACKVERT), (SBP_UPPERTRACKHORZ, SBP_UPPERTRACKVERT));
  450. var
  451. StateFlags: Cardinal;
  452. begin
  453. if USE_THEMES then
  454. begin
  455. StateFlags := SCRBS_NORMAL;
  456. if not Enabled then Inc(StateFlags, 3)
  457. else if Pushed then Inc(StateFlags, 2);
  458. DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, PartXPFlags[IsNextZone, Kind],
  459. StateFlags, Rect, nil);
  460. end
  461. else
  462. begin
  463. if Pushed then Canvas.Brush.Color := cl3DDkShadow
  464. else Canvas.Brush.Bitmap := AllocPatternBitmap(clBtnHighlight, clScrollBar);
  465. Canvas.FillRect(Rect);
  466. end;
  467. end;
  468. procedure TTBXScrollBar.Redraw;
  469. begin
  470. if Assigned(FOnRedrawRequest) then FOnRedrawRequest(Self);
  471. end;
  472. procedure TTBXScrollBar.SBWndProc(var Message: TMessage);
  473. var
  474. I: Integer;
  475. procedure DefaultHandler;
  476. begin
  477. with Message do
  478. Result := DefWindowProc(FHandle, Msg, wParam, lParam);
  479. end;
  480. begin
  481. case Message.Msg of
  482. WM_TIMER: with TWMTimer(Message) do
  483. begin
  484. I := 0;
  485. TimerElapsed(TimerID, I);
  486. if I > 0 then StartTimer(TimerID, I)
  487. else StopTimer(TimerID);
  488. Result := 0;
  489. end;
  490. else
  491. DefaultHandler;
  492. end;
  493. end;
  494. procedure TTBXScrollBar.SetBounds(const Value: TRect);
  495. begin
  496. FBounds := Value;
  497. with Value do
  498. begin
  499. FLeft := Left;
  500. FTop := Top;
  501. FWidth := Right - Left;
  502. FHeight := Bottom - Top;
  503. end;
  504. UpdateZones;
  505. end;
  506. procedure TTBXScrollBar.SetKind(Value: TScrollBarKind);
  507. begin
  508. FKind := Value;
  509. UpdateZones;
  510. end;
  511. procedure TTBXScrollBar.SetPosition(Value: Integer);
  512. begin
  513. AdjustPosition(Value);
  514. if Value <> FPosition then
  515. begin
  516. FPosition := Value;
  517. if UserChange then
  518. begin
  519. Redraw;
  520. if Assigned(FOnChange) then FOnChange(Self);
  521. end;
  522. end;
  523. end;
  524. procedure TTBXScrollBar.SetRange(Value: Integer);
  525. begin
  526. if Value < 0 then Value := 0;
  527. if Value <> FRange then
  528. begin
  529. FRange := Value;
  530. Redraw;
  531. SetPosition(Position);
  532. end;
  533. end;
  534. procedure TTBXScrollBar.StartAutoScroll(Direction, Interval: Integer);
  535. begin
  536. if Direction <> 0 then
  537. begin
  538. AutoScrollDirection := Direction;
  539. AutoScrollInterval := Interval;
  540. if not AutoScrolling then
  541. begin
  542. StartTimer(AUTO_SCROLL_TIMER, Interval);
  543. AutoScrolling := True;
  544. end;
  545. end;
  546. end;
  547. procedure TTBXScrollBar.StartTimer(ID, Elapse: Integer);
  548. begin
  549. SetTimer(Handle, ID, Elapse, nil);
  550. end;
  551. procedure TTBXScrollBar.StopAutoScroll;
  552. begin
  553. if AutoScrolling then
  554. begin
  555. AutoScrolling := False;
  556. StopTimer(AUTO_SCROLL_TIMER);
  557. end;
  558. end;
  559. procedure TTBXScrollBar.StopTimer(ID: Integer);
  560. begin
  561. KillTimer(Handle, ID);
  562. end;
  563. procedure TTBXScrollBar.TimerElapsed(ID: Integer; var NewElapse: Integer);
  564. begin
  565. case ID of
  566. SCROLL_TIMER:
  567. if MouseDownZone <> sbzEmpty then
  568. if not (MouseDownZone in [sbzPagePrev, sbzPageNext]) or
  569. (GetZone(LastMousePoint.X, LastMousePoint.Y) = MouseDownZone) then
  570. begin
  571. HandleZoneClick(MouseDownZone);
  572. NewElapse := 100;
  573. end;
  574. AUTO_SCROLL_TIMER: if AutoScrolling then
  575. begin
  576. NewElapse := AutoScrollInterval;
  577. UpdatePosition(Position + AutoScrollDirection);
  578. if (Position = 0) or (Position + Window = Range) then NewElapse := 0;
  579. if Assigned(FOnAutoScroll) then
  580. FOnAutoScroll(Self, AutoScrollDirection, AutoScrollInterval);
  581. AutoScrolling := NewElapse > 0;
  582. end;
  583. end;
  584. end;
  585. procedure TTBXScrollBar.UpdatePosition(NewPosition: Integer);
  586. begin
  587. UserChange := True;
  588. if NewPosition < 0 then NewPosition := 0;
  589. if NewPosition > Range - Window then NewPosition := Range - Window;
  590. Position := NewPosition;
  591. UserChange := False;
  592. end;
  593. procedure TTBXScrollBar.UpdateZones;
  594. var
  595. SzL, SzT: Integer;
  596. ButtonSize: Integer;
  597. Lo, Hi: Integer;
  598. HandleSize, HandlePos: Integer;
  599. Window: Integer;
  600. IsVert: Boolean;
  601. procedure SetZone(var R: TRect; Lo, Hi: Integer);
  602. begin
  603. if IsVert then
  604. begin
  605. R.Left := 0;
  606. R.Right := Width;
  607. R.Top := Lo;
  608. R.Bottom := Hi;
  609. end
  610. else
  611. begin
  612. R.Left := Lo;
  613. R.Right := Hi;
  614. R.Top := 0;
  615. R.Bottom := Height;
  616. end;
  617. end;
  618. begin
  619. IsVert := Kind = sbVertical;
  620. Window := GetEffectiveWindow;
  621. if IsVert then
  622. begin
  623. SzL := Height;
  624. SzT := Width;
  625. end
  626. else
  627. begin
  628. SzL := Width;
  629. SzT := Height;
  630. end;
  631. { Buttons }
  632. ButtonSize := SzT;
  633. if ButtonSize * 2 >= SzL - 2 then ButtonSize := (SzL - 2) div 2;
  634. SetZone(Zones[sbzPrev], 0, ButtonSize);
  635. SetZone(Zones[sbzNext], SzL - ButtonSize, SzL);
  636. { Handle }
  637. Lo := ButtonSize;
  638. Hi := SzL - ButtonSize;
  639. if GetEnabled and (Hi - Lo > MIN_SB_HANDLE_SIZE + 4) then
  640. begin
  641. HandleSize := Round((Hi - Lo) * Window / Range);
  642. if HandleSize >= MIN_SB_HANDLE_SIZE then
  643. HandlePos := Round((Hi - Lo) * Position / Range)
  644. else
  645. begin
  646. HandleSize := MIN_SB_HANDLE_SIZE;
  647. HandlePos := Round((Hi - Lo - MIN_SB_HANDLE_SIZE) * Position / (Range - Window));
  648. end;
  649. Inc(HandlePos, Lo);
  650. SetZone(Zones[sbzHandle], HandlePos, HandlePos + HandleSize);
  651. SetZone(Zones[sbzPagePrev], Lo, HandlePos);
  652. SetZone(Zones[sbzPageNext], HandlePos + HandleSize, Hi);
  653. Zones[sbzEmpty].Right := -1;
  654. end
  655. else
  656. begin
  657. { Invalidate invisible zones }
  658. Zones[sbzPagePrev].Right := -1;
  659. Zones[sbzHandle].Right := -1;
  660. Zones[sbzPageNext].Right := -1;
  661. SetZone(Zones[sbzEmpty], Lo, Hi);
  662. end;
  663. end;
  664. //----------------------------------------------------------------------------//
  665. { TTBXCustomList }
  666. constructor TTBXCustomList.Create(AOwner: TComponent);
  667. begin
  668. inherited;
  669. FMinWidth := 32;
  670. FMaxWidth := 0;
  671. FMaxVisibleItems := 8;
  672. FItemIndex := -1;
  673. end;
  674. function TTBXCustomList.DoClearItem(ACanvas: TCanvas; ARect: TRect; AIndex, AHoverIndex: Integer): Boolean;
  675. begin
  676. Result := True;
  677. if Assigned(FOnClearItem) then FOnClearItem(Self, ACanvas, ARect, AIndex, AHoverIndex, Result);
  678. end;
  679. function TTBXCustomList.DoDrawItem(ACanvas: TCanvas; {MP} var ARect: TRect; AIndex, AHoverIndex: Integer): Boolean;
  680. begin
  681. Result := True;
  682. if Assigned(FOnDrawItem) then FOnDrawItem(Self, ACanvas, ARect, AIndex, AHoverIndex, Result);
  683. end;
  684. procedure TTBXCustomList.DoMeasureHeight(ACanvas: TCanvas; var AHeight: Integer);
  685. begin
  686. if Assigned(FOnMeasureHeight) then FOnMeasureHeight(Self, ACanvas, AHeight);
  687. end;
  688. procedure TTBXCustomList.DoMeasureWidth(ACanvas: TCanvas; AIndex: Integer; var AWidth: Integer);
  689. begin
  690. if Assigned(FOnMeasureWidth) then FOnMeasureWidth(Self, ACanvas, AIndex, AWidth);
  691. end;
  692. procedure TTBXCustomList.DrawItem(ACanvas: TCanvas; AViewer: TTBXCustomListViewer;
  693. const ARect: TRect; AIndex, AHoverIndex: Integer);
  694. const
  695. FillColors: array [Boolean] of TColor = (clWindow, clHighlight);
  696. TextColors: array [Boolean] of TColor = (clWindowText, clHighlightText);
  697. var
  698. S: string;
  699. R, R2: TRect;
  700. ImgList: TCustomImageList;
  701. begin
  702. ACanvas.Brush.Color := FillColors[AIndex = AHoverIndex];
  703. if DoClearItem(ACanvas, ARect, AIndex, AHoverIndex) then ACanvas.FillRect(ARect);
  704. ACanvas.Font.Color := TextColors[AIndex = AHoverIndex];
  705. R := ARect; {MP}
  706. if DoDrawItem(ACanvas, {MP} R, AIndex, AHoverIndex) then
  707. begin
  708. InflateRect(R, -4, 1);
  709. ImgList := AViewer.GetImageList;
  710. if ShowImages and (ImgList <> nil) then
  711. begin
  712. R2.Left := R.Left;
  713. R2.Top := (R.Top + R.Bottom - ImgList.Height) div 2;
  714. R2.Right := R2.Left + ImgList.Width;
  715. R2.Bottom := R2.Top + ImgList.Height;
  716. if Enabled then ImgList.Draw(ACanvas, R2.Left, R2.Top, GetImageIndex(AIndex))
  717. else DrawTBXImage(ACanvas, R2, ImgList, GetImageIndex(AIndex), ISF_DISABLED);
  718. Inc(R.Left, ImgList.Width + CImageSpacing);
  719. end;
  720. S := GetItemText(AIndex);
  721. if Length(S) > 0 then
  722. begin
  723. ACanvas.Brush.Style := bsClear;
  724. DrawText(ACanvas.Handle, PChar(S), Length(S), R, DT_SINGLELINE or DT_VCENTER {MP DEL});
  725. ACanvas.Brush.Style := bsSolid;
  726. end;
  727. end;
  728. end;
  729. function TTBXCustomList.GetImageIndex(ItemIndex: Integer): Integer;
  730. begin
  731. Result := ItemIndex;
  732. if Assigned(FOnAdjustImageIndex) then FOnAdjustImageIndex(Self, ItemIndex, Result);
  733. end;
  734. function TTBXCustomList.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
  735. begin
  736. Result := TTBXCustomListViewer;
  737. end;
  738. procedure TTBXCustomList.HandleChange;
  739. begin
  740. if Assigned(FOnChange) then FOnChange(Self);
  741. end;
  742. procedure TTBXCustomList.HandleHover(AIndex: Integer);
  743. begin
  744. end;
  745. procedure TTBXCustomList.MakeVisible(AIndex: Integer);
  746. var
  747. I: Integer;
  748. begin
  749. if FViewers <> nil then
  750. for I := 0 to FViewers.Count - 1 do
  751. TTBXCustomListViewer(FViewers[I]).MakeVisible(AIndex);
  752. end;
  753. procedure TTBXCustomList.Notification(AComponent: TComponent; Operation: TOperation);
  754. begin
  755. inherited Notification(AComponent, Operation);
  756. if (Operation = opRemove) and (AComponent = Images) then Images := nil;
  757. end;
  758. procedure TTBXCustomList.SetItemIndex(Value: Integer);
  759. var
  760. I: Integer;
  761. begin
  762. if Value < 0 then Value := -1;
  763. FItemIndex := Value;
  764. { Update viewers }
  765. if FViewers <> nil then
  766. for I := 0 to FViewers.Count - 1 do
  767. TTBXCustomListViewer(FViewers[I]).ListChangeHandler(Value);
  768. if Assigned(FOnChange) then FOnChange(Self);
  769. end;
  770. //----------------------------------------------------------------------------//
  771. { TTBXCustomListViewer }
  772. procedure TTBXCustomListViewer.AdjustAutoScrollHover(var AIndex: Integer; Direction: Integer);
  773. begin
  774. AIndex := -1; // turn off hover when autoscrolling
  775. end;
  776. procedure TTBXCustomListViewer.CalcSize(const Canvas: TCanvas; var AWidth, AHeight: Integer);
  777. var
  778. Item: TTBXCustomList;
  779. I, W: Integer;
  780. begin
  781. Item := TTBXCustomList(Self.Item);
  782. Canvas.Font := TTBViewAccess(View).GetFont;
  783. FItemCount := Item.GetCount;
  784. FItemHeight := GetItemHeight(Canvas);
  785. FVisibleItems := FItemCount;
  786. if FVisibleItems > Item.MaxVisibleItems then FVisibleItems := Item.MaxVisibleItems
  787. else if FVisibleItems <= 0 then FVisibleItems := 1;
  788. AHeight := FVisibleItems * FItemHeight;
  789. AWidth := 0;
  790. for I := 0 to FItemCount - 1 do
  791. begin
  792. W := GetItemWidth(Canvas, I);
  793. if W > AWidth then AWidth := W;
  794. end;
  795. if FItemCount > FVisibleItems then FScrollBarWidth := GetSystemMetrics(SM_CXVSCROLL)
  796. else FScrollBarWidth := 0;
  797. Inc(AWidth, FScrollBarWidth);
  798. if AWidth < Item.MinWidth then AWidth := Item.MinWidth;
  799. if (Item.MaxWidth > Item.MinWidth) and (AWidth > Item.MaxWidth) then AWidth := Item.MaxWidth;
  800. end;
  801. constructor TTBXCustomListViewer.Create(AView: TTBView; AItem: TTBCustomItem; AGroupLevel: Integer);
  802. var
  803. Index: Integer;
  804. begin
  805. inherited;
  806. Index := TTBXCustomList(AItem).ItemIndex;
  807. FItemCount := TTBXCustomList(AItem).GetCount;
  808. if (Index >= 0) and (Index < FItemCount) then
  809. with TTBXCustomList(AItem) do
  810. begin
  811. FVisibleItems := GetCount;
  812. if FVisibleItems > MaxVisibleItems then FVisibleItems := MaxVisibleItems;
  813. if Index < FOffset then FOffset := Index
  814. else if Index >= FOffset + FVisibleItems then FOffset := Index - FVisibleItems + 1
  815. end;
  816. FHoverIndex := Index;
  817. if FHoverIndex > FItemCount then FHoverIndex := -1;
  818. AddToList(TTBXCustomList(AItem).FViewers, Self);
  819. end;
  820. destructor TTBXCustomListViewer.Destroy;
  821. begin
  822. RemoveFromList(TTBXCustomList(Item).FViewers, Self);
  823. if FScrollBar <> nil then FScrollBar.Free;
  824. inherited;
  825. end;
  826. procedure TTBXCustomListViewer.DrawItems(const Canvas: TCanvas; const ClientAreaRect: TRect);
  827. var
  828. I: Integer;
  829. R: TRect;
  830. begin
  831. R := ClientAreaRect;
  832. R.Bottom := FItemHeight;
  833. Dec(R.Right, FScrollBarWidth);
  834. Canvas.Font := TTBViewAccess(View).GetFont;
  835. for I := FOffset to FItemCount - 1 do
  836. begin
  837. if RectVisible(Canvas.Handle, R) then
  838. TTBXCustomList(Item).DrawItem(Canvas, Self, R, I, HoverIndex);
  839. R.Top := R.Bottom;
  840. Inc(R.Bottom, FItemHeight);
  841. if R.Bottom > FHeight then Break;
  842. end;
  843. if R.Top < ClientAreaRect.Bottom then
  844. begin
  845. R.Bottom := ClientAreaRect.Bottom;
  846. Canvas.Brush.Color := clWindow;
  847. Canvas.FillRect(R);
  848. end;
  849. end;
  850. function TTBXCustomListViewer.GetItemHeight(ACanvas: TCanvas): Integer;
  851. var
  852. ImgList: TCustomImageList;
  853. begin
  854. Result := ACanvas.TextHeight('Q') + 2;
  855. with TTBXStringList(Item) do
  856. begin
  857. ImgList := GetImageList;
  858. if ShowImages and (ImgList <> nil) and (Result < ImgList.Height + 2) then
  859. Result := ImgList.Height + 2;
  860. DoMeasureHeight(ACanvas, Result);
  861. end;
  862. end;
  863. function TTBXCustomListViewer.GetItemIndexAt(X, Y: Integer): Integer;
  864. begin
  865. if (X < 0) or (X > FWidth - FScrollBarWidth) then Result := -1
  866. else
  867. begin
  868. Result := (Y div FItemHeight) + FOffset;
  869. if (Result < FOffset) or (Result >= FOffset + FVisibleItems) or (Result >= FItemCount) then
  870. Result := - 1;
  871. end;
  872. end;
  873. function TTBXCustomListViewer.GetItemRect(Index: Integer): TRect;
  874. begin
  875. { Note this method works properly only after Draw is called }
  876. Result := FLastClientRect;
  877. Inc(Result.Top, (Index - FOffset) * FItemHeight);
  878. Result.Bottom := Result.Top + FItemHeight;
  879. Dec(Result.Right, FScrollBarWidth);
  880. end;
  881. function TTBXCustomListViewer.GetItemWidth(ACanvas: TCanvas; Index: Integer): Integer;
  882. var
  883. S: string;
  884. ImgList: TCustomImageList;
  885. begin
  886. with TTBXStringList(Item) do
  887. begin
  888. S := GetItemText(Index);
  889. Result := ACanvas.TextWidth(S);
  890. if ShowImages then
  891. begin
  892. ImgList := GetImageList;
  893. if ImgList <> nil then
  894. begin
  895. Inc(Result, ImgList.Width);
  896. if Length(S) > 0 then Inc(Result, CImageSpacing);
  897. end;
  898. end;
  899. Inc(Result, 8);
  900. DoMeasureWidth(ACanvas, Index, Result)
  901. end;
  902. end;
  903. procedure TTBXCustomListViewer.HandleAutoScroll(var Direction, Interval: Integer);
  904. begin
  905. // do nothing by default
  906. end;
  907. procedure TTBXCustomListViewer.KeyDown(var Key: Word; Shift: TShiftState);
  908. var
  909. OldIndex, NewIndex, Index: Integer;
  910. DAD: TTBDoneActionData;
  911. begin
  912. OldIndex := FHoverIndex;
  913. case Key of
  914. VK_UP: NewIndex := OldIndex - 1;
  915. VK_DOWN: NewIndex := OldIndex + 1;
  916. VK_PRIOR: NewIndex := OldIndex - FVisibleItems;
  917. VK_NEXT: NewIndex := OldIndex + FVisibleItems;
  918. VK_HOME: NewIndex := 0;
  919. VK_END: NewIndex := FItemCount - 1;
  920. VK_RETURN:
  921. begin
  922. TTBXCustomList(Item).ItemIndex := FHoverIndex;
  923. Exit;
  924. end;
  925. {MP}
  926. Word('A')..Word('Z'), Word('a')..Word('z'):
  927. begin
  928. NewIndex := OldIndex;
  929. for Index := FHoverIndex + 1 to FHoverIndex + FItemCount do
  930. begin
  931. if IsAccel(Key, TTBXStringList(Item).GetItemText(Index mod FItemCount)) then
  932. begin
  933. NewIndex := Index mod FItemCount;
  934. // exit modal loop
  935. DAD := TTBViewAccess(TTBViewAccess(View).GetRootView).DoneActionData;
  936. DAD.ClickItem := Item;
  937. DAD.DoneAction := tbdaClickItem;
  938. DAD.Sound := True;
  939. TTBViewAccess(TTBViewAccess(View).GetRootView).DoneActionData := DAD;
  940. Break;
  941. end;
  942. end;
  943. Key := 0;
  944. end;
  945. else
  946. Exit;
  947. end;
  948. Key := 0;
  949. if NewIndex < 0 then NewIndex := 0;
  950. if NewIndex >= FItemCount then NewIndex := FItemCount - 1;
  951. TTBXCustomList(Item).ItemIndex := NewIndex;
  952. end;
  953. procedure TTBXCustomListViewer.ListChangeHandler(NewIndex: Integer);
  954. begin
  955. if not IsChanging and (NewIndex <> HoverIndex) then
  956. begin
  957. IsChanging := True;
  958. HoverIndex := NewIndex;
  959. TTBXCustomList(Item).HandleHover(NewIndex);
  960. MakeVisible(HoverIndex);
  961. UpdateItems;
  962. IsChanging := False;
  963. end;
  964. end;
  965. procedure TTBXCustomListViewer.MakeVisible(Index: Integer);
  966. begin
  967. if (Index >= 0) and (Index < FItemCount) then
  968. begin
  969. if Index < FOffset then FScrollBar.UpdatePosition(Index)
  970. else if Index >= FOffset + FVisibleItems then FScrollBar.UpdatePosition(Index - FVisibleItems + 1);
  971. end;
  972. end;
  973. procedure TTBXCustomListViewer.MouseDown(Shift: TShiftState; X, Y: Integer; var MouseDownOnMenu: Boolean);
  974. begin
  975. if X > FWidth - FScrollBarWidth then
  976. begin
  977. Dec(X, FWidth - FScrollBarWidth);
  978. MouseInScrollBar := True;
  979. FScrollBar.MouseDown(mbLeft, X, Y);
  980. MouseDownOnMenu := False;
  981. end
  982. else
  983. begin
  984. MouseIsDown := True;
  985. MouseMove(X, Y);
  986. end;
  987. inherited;
  988. View.SetCapture;
  989. end;
  990. procedure TTBXCustomListViewer.MouseMove(X, Y: Integer);
  991. var
  992. NewHoverIndex, OldHoverIndex, IndexLo, IndexHi, I: Integer;
  993. R: TRect;
  994. Canvas: TCanvas;
  995. DC: HDC;
  996. V, Dir: Integer;
  997. begin
  998. if MouseInScrollBar then
  999. begin
  1000. Dec(X, FWidth - FScrollBarWidth);
  1001. FScrollBar.MouseMove(X, Y);
  1002. Exit;
  1003. end;
  1004. if not View.Capture and (GetKeyState(VK_LBUTTON) < 0) then
  1005. begin
  1006. View.SetCapture;
  1007. MouseIsDown := True;
  1008. end;
  1009. NewHoverIndex := GetItemIndexAt(X, Y);
  1010. if FScrollBar <> nil then
  1011. begin
  1012. if MouseIsDown and ((Y < 0) or (Y >= FHeight)) then
  1013. begin
  1014. { Get AutoScroll Intervals }
  1015. V := Y;
  1016. if V >= FHeight then Dec(V, FHeight - 1);
  1017. V := Abs(V);
  1018. if Y < 0 then Dir := -1 else Dir := 1;
  1019. case V of
  1020. 0..9: V := 150;
  1021. 10..29: V := 100;
  1022. 30..50: begin V := 100; Dir := Dir * 2; end;
  1023. else
  1024. V := 100;
  1025. Dir := Dir * 4;
  1026. end;
  1027. if ((Dir < 0) and (FOffset > 0)) or
  1028. ((Dir > 0) and (FOffset + FVisibleItems < FItemCount)) then
  1029. FScrollBar.StartAutoScroll(Dir, V)
  1030. else
  1031. FScrollBar.StopAutoScroll;
  1032. AdjustAutoScrollHover(NewHoverIndex, Dir);
  1033. end
  1034. else FScrollBar.StopAutoScroll;
  1035. end;
  1036. if not MouseIsDown and (NewHoverIndex = -1) then Exit;
  1037. if NewHoverIndex <> FHoverIndex then
  1038. begin
  1039. Canvas := TCanvas.Create;
  1040. DC := GetDC(View.Window.Handle);
  1041. OldHoverIndex := FHoverIndex;
  1042. FHoverIndex := NewHoverIndex;
  1043. try
  1044. SetWindowOrgEx(DC, -BoundsRect.Left, -BoundsRect.Top, nil);
  1045. Canvas.Handle := DC;
  1046. Canvas.Font := TTBViewAccess(View).GetFont;
  1047. IndexLo := OldHoverIndex;
  1048. IndexHi := FHoverIndex;
  1049. if FHoverIndex < OldHoverIndex then
  1050. begin
  1051. IndexLo := FHoverIndex;
  1052. IndexHi := OldHoverIndex;
  1053. end;
  1054. for I := IndexLo to IndexHi do
  1055. begin
  1056. R := GetItemRect(I);
  1057. if (R.Top >= 0) and (R.Bottom <= FHeight) and RectVisible(DC, R) then
  1058. TTBXCustomList(Item).DrawItem(Canvas, Self, R, I, HoverIndex);
  1059. end;
  1060. finally
  1061. Canvas.Handle := 0;
  1062. Canvas.Free;
  1063. ReleaseDC(View.Window.Handle, DC);
  1064. end;
  1065. TTBXCustomList(Item).HandleHover(FHoverIndex);
  1066. end;
  1067. end;
  1068. procedure TTBXCustomListViewer.MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean);
  1069. var
  1070. DAD: TTBDoneActionData;
  1071. begin
  1072. if FScrollBar <> nil then FScrollBar.StopAutoScroll;
  1073. if MouseInScrollBar then
  1074. begin
  1075. inherited;
  1076. Dec(X, FWidth - FScrollBarWidth);
  1077. FScrollBar.MouseUp(mbLeft, X, Y);
  1078. DAD := TTBViewAccess(TTBViewAccess(View).GetRootView).DoneActionData;
  1079. DAD.DoneAction := tbdaNone;
  1080. TTBViewAccess(TTBViewAccess(View).GetRootView).DoneActionData := DAD;
  1081. MouseInScrollBar := False;
  1082. end
  1083. else if MouseIsDown then
  1084. begin
  1085. MouseIsDown := False;
  1086. TTBXCustomList(Item).ItemIndex := FHoverIndex;
  1087. inherited;
  1088. DAD := TTBViewAccess(TTBViewAccess(View).GetRootView).DoneActionData;
  1089. DAD.Sound := False;
  1090. TTBViewAccess(TTBViewAccess(View).GetRootView).DoneActionData := DAD;
  1091. end;
  1092. end;
  1093. procedure TTBXCustomListViewer.MouseWheel(WheelDelta, X, Y: Integer);
  1094. var
  1095. IsNegative: Boolean;
  1096. begin
  1097. if FScrollBar <> nil then
  1098. begin
  1099. Inc(FWheelAccumulator, WheelDelta);
  1100. while Abs(FWheelAccumulator) >= WHEEL_DELTA do
  1101. begin
  1102. IsNegative := FWheelAccumulator < 0;
  1103. FWheelAccumulator := Abs(FWheelAccumulator) - WHEEL_DELTA;
  1104. if IsNegative then
  1105. begin
  1106. if FWheelAccumulator <> 0 then FWheelAccumulator := -FWheelAccumulator;
  1107. FScrollBar.UpdatePosition(FScrollBar.Position + 1)
  1108. end
  1109. else
  1110. FScrollBar.UpdatePosition(FScrollBar.Position - 1)
  1111. end;
  1112. end;
  1113. end;
  1114. procedure TTBXCustomListViewer.Paint(const Canvas: TCanvas;
  1115. const ClientAreaRect: TRect; IsHoverItem, IsPushed, UseDisabledShadow: Boolean);
  1116. begin
  1117. { Cache some important info for later usage }
  1118. FLastClientRect := ClientAreaRect;
  1119. with ClientAreaRect do
  1120. begin
  1121. FWidth := Right - Left;
  1122. FHeight := Bottom - Top;
  1123. end;
  1124. DrawItems(Canvas, ClientAreaRect);
  1125. if FScrollBarWidth > 0 then
  1126. begin
  1127. if FScrollBar = nil then
  1128. begin
  1129. FScrollBar := TTBXScrollBar.Create;
  1130. FScrollBar.Kind := sbVertical;
  1131. FScrollBar.OnRedrawRequest := SBRedrawHandler;
  1132. FScrollBar.OnChange := SBChangeHandler;
  1133. FScrollBar.OnAutoScroll := SBAutoScrollHandler;
  1134. end;
  1135. FScrollBar.Bounds := Rect(ClientAreaRect.Right - FScrollBarWidth,
  1136. ClientAreaRect.Top, ClientAreaRect.Right, ClientAreaRect.Bottom);
  1137. FScrollBar.Range := FItemCount;
  1138. FScrollBar.Window := FVisibleItems;
  1139. FScrollBar.Position := FOffset;
  1140. FScrollBar.PaintTo(Canvas);
  1141. end;
  1142. end;
  1143. procedure TTBXCustomListViewer.SBAutoScrollHandler(Sender: TObject;
  1144. var Direction, Interval: Integer);
  1145. begin
  1146. HandleAutoScroll(Direction, Interval);
  1147. end;
  1148. procedure TTBXCustomListViewer.SBChangeHandler(Sender: TObject);
  1149. begin
  1150. FOffset := FScrollBar.Position;
  1151. UpdateItems;
  1152. end;
  1153. procedure TTBXCustomListViewer.SBRedrawHandler(Sender: TObject);
  1154. var
  1155. DC: HDC;
  1156. Canvas: TCanvas;
  1157. begin
  1158. Canvas := TCanvas.Create;
  1159. DC := GetDC(View.Window.Handle);
  1160. try
  1161. SetWindowOrgEx(DC, -BoundsRect.Left, -BoundsRect.Top, nil);
  1162. Canvas.Handle := DC;
  1163. FScrollBar.PaintTo(Canvas);
  1164. finally
  1165. Canvas.Handle := 0;
  1166. Canvas.Free;
  1167. ReleaseDC(View.Window.Handle, DC);
  1168. end;
  1169. end;
  1170. procedure TTBXCustomListViewer.UpdateItems;
  1171. var
  1172. DC: HDC;
  1173. Canvas: TCanvas;
  1174. begin
  1175. if Assigned(FScrollBar) then FOffset := FScrollBar.Position
  1176. else FOffset := 0;
  1177. Canvas := TCanvas.Create;
  1178. DC := GetDC(View.Window.Handle);
  1179. try
  1180. SetWindowOrgEx(DC, -BoundsRect.Left, -BoundsRect.Top, nil);
  1181. Canvas.Handle := DC;
  1182. DrawItems(Canvas, FLastClientRect);
  1183. finally
  1184. Canvas.Handle := 0;
  1185. Canvas.Free;
  1186. ReleaseDC(View.Window.Handle, DC);
  1187. end;
  1188. end;
  1189. //----------------------------------------------------------------------------//
  1190. { TTBXStringList }
  1191. constructor TTBXStringList.Create(AOwner: TComponent);
  1192. begin
  1193. inherited;
  1194. FStrings := TStringList.Create;
  1195. end;
  1196. destructor TTBXStringList.Destroy;
  1197. begin
  1198. FStrings.Free;
  1199. inherited;
  1200. end;
  1201. function TTBXStringList.GetCount: Integer;
  1202. begin
  1203. Result := FStrings.Count;
  1204. end;
  1205. function TTBXStringList.GetItemText(Index: Integer): string;
  1206. begin
  1207. Result := FStrings[Index];
  1208. end;
  1209. procedure TTBXStringList.SetStrings(Value: TStrings);
  1210. begin
  1211. FStrings.Assign(Value);
  1212. end;
  1213. //----------------------------------------------------------------------------//
  1214. {$IFNDEF MPEXCLUDE}
  1215. { TTBXUndoList }
  1216. procedure TTBXUndoList.DrawItem(ACanvas: TCanvas; AViewer: TTBXCustomListViewer;
  1217. const ARect: TRect; AIndex, AHoverIndex: Integer);
  1218. const
  1219. FillColors: array [Boolean] of TColor = (clWindow, clHighlight);
  1220. TextColors: array [Boolean] of TColor = (clWindowText, clHighlightText);
  1221. var
  1222. S: string;
  1223. R: TRect;
  1224. begin
  1225. ACanvas.Brush.Color := FillColors[AIndex <= AHoverIndex];
  1226. ACanvas.FillRect(ARect);
  1227. S := Strings[AIndex];
  1228. if Length(S) > 0 then
  1229. begin
  1230. R := ARect;
  1231. InflateRect(R, -4, 1);
  1232. ACanvas.Font.Color := TextColors[AIndex <= AHoverIndex];
  1233. ACanvas.Brush.Style := bsClear;
  1234. DrawText(ACanvas.Handle, PChar(S), Length(S), R, DT_SINGLELINE or DT_VCENTER);
  1235. ACanvas.Brush.Style := bsSolid;
  1236. end;
  1237. end;
  1238. function TTBXUndoList.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
  1239. begin
  1240. Result := TTBXUndoListViewer;
  1241. end;
  1242. procedure TTBXUndoList.HandleHover(AIndex: Integer);
  1243. begin
  1244. ItemIndex := AIndex;
  1245. end;
  1246. //----------------------------------------------------------------------------//
  1247. { TTBXUndoListViewer }
  1248. procedure TTBXUndoListViewer.AdjustAutoScrollHover(var AIndex: Integer; Direction: Integer);
  1249. begin
  1250. if Direction < 0 then AIndex := FOffset
  1251. else if Direction > 0 then AIndex := FOffset + FVisibleItems - 1;
  1252. end;
  1253. procedure TTBXUndoListViewer.HandleAutoScroll(var Direction, Interval: Integer);
  1254. begin
  1255. inherited;
  1256. if Direction < 0 then HoverIndex := FOffset
  1257. else if Direction > 0 then HoverIndex := FOffset + FVisibleItems - 1
  1258. else Exit;
  1259. TTBXCustomList(Item).HandleHover(HoverIndex);
  1260. UpdateItems;
  1261. end;
  1262. {$ENDIF}
  1263. end.