TBXLists.pas 40 KB

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