239 lines
5.3 KiB
ObjectPascal
239 lines
5.3 KiB
ObjectPascal
unit BCListBoxEx;
|
|
|
|
{$mode delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
|
|
LCLType;
|
|
|
|
type
|
|
TBCListBoxEx = class(TCustomControl)
|
|
private
|
|
mousepos: TPoint;
|
|
scrolly: integer;
|
|
fitems: TStringList;
|
|
itemselected: integer;
|
|
itemheight: integer;
|
|
lastitem: integer;
|
|
invalidatecount: integer;
|
|
scrollwidth: integer;
|
|
function GetItemRect(index: integer): TRect;
|
|
function GetItemVertically(y: integer): integer;
|
|
procedure ScrollToItemTop();
|
|
procedure ScrollToItemBottom();
|
|
procedure ScrollToItem(index: integer);
|
|
function ItemIsVisible(index: integer): boolean;
|
|
protected
|
|
procedure Click; override;
|
|
procedure KeyDown(var Key: word; Shift: TShiftState); override;
|
|
procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
|
|
function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): boolean; override;
|
|
function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): boolean; override;
|
|
procedure Paint; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
published
|
|
property Align;
|
|
property Items: TStringList read Fitems;
|
|
end;
|
|
|
|
procedure Register;
|
|
|
|
implementation
|
|
|
|
procedure Register;
|
|
begin
|
|
RegisterComponents('BGRA Controls', [TBCListBoxEx]);
|
|
end;
|
|
|
|
procedure TBCListBoxEx.Click;
|
|
var
|
|
tempitem: integer;
|
|
begin
|
|
tempitem := GetItemVertically(mousepos.Y);
|
|
if tempitem <> itemselected then
|
|
begin
|
|
itemselected := tempitem;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
constructor TBCListBoxEx.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
scrolly := 0;
|
|
itemheight := 150;
|
|
scrollwidth := 20;
|
|
lastitem := -1;
|
|
invalidatecount := 0;
|
|
itemselected := -1;
|
|
fitems := TStringList.Create;
|
|
end;
|
|
|
|
destructor TBCListBoxEx.Destroy;
|
|
begin
|
|
items.Free;
|
|
end;
|
|
|
|
procedure TBCListBoxEx.KeyDown(var Key: word; Shift: TShiftState);
|
|
var
|
|
tempitem: integer;
|
|
begin
|
|
case key of
|
|
vk_down:
|
|
begin
|
|
tempitem := itemselected + 1;
|
|
if (tempitem < items.Count) then
|
|
begin
|
|
itemselected := tempitem;
|
|
if not ItemIsVisible(itemselected) then
|
|
ScrollToItemBottom();
|
|
if not ItemIsVisible(itemselected) then
|
|
ScrollToItem(itemselected);
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
vk_up:
|
|
begin
|
|
tempitem := itemselected - 1;
|
|
if (tempitem >= 0) then
|
|
begin
|
|
itemselected := tempitem;
|
|
if not ItemIsVisible(itemselected) then
|
|
ScrollToItemTop();
|
|
if not ItemIsVisible(itemselected) then
|
|
ScrollToItem(itemselected);
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TBCListBoxEx.MouseMove(Shift: TShiftState; X, Y: integer);
|
|
var
|
|
tempitem: integer;
|
|
begin
|
|
mousepos := Point(x, y);
|
|
tempitem := GetItemVertically(mousepos.Y);
|
|
if tempitem <> lastitem then
|
|
begin
|
|
lastitem := tempitem;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
function TBCListBoxEx.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): boolean;
|
|
var
|
|
r: TRect;
|
|
begin
|
|
result := False;
|
|
r := GetItemRect(items.Count - 1);
|
|
if (r.Bottom >= Height) then
|
|
begin
|
|
result := True;
|
|
scrolly := scrolly - itemheight;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
function TBCListBoxEx.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): boolean;
|
|
var
|
|
lastscroll: integer;
|
|
begin
|
|
result := False;
|
|
lastscroll := scrolly;
|
|
scrolly := scrolly + itemheight;
|
|
if (scrolly > 0) then
|
|
scrolly := 0;
|
|
if scrolly <> lastscroll then
|
|
begin
|
|
result := True;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TBCListBoxEx.Paint;
|
|
var
|
|
i: integer;
|
|
r: TRect;
|
|
style: TTextStyle;
|
|
start: integer;
|
|
begin
|
|
style.Alignment := taCenter;
|
|
style.Layout := tlCenter;
|
|
start := -1;
|
|
|
|
for i := trunc(abs(scrolly) / itemheight) to items.Count - 1 do
|
|
begin
|
|
r := GetItemRect(i);
|
|
|
|
if (r.Top < Height) then
|
|
begin
|
|
if start = -1 then
|
|
start := i;
|
|
Canvas.Brush.Color := clGreen;
|
|
if (GetItemVertically(mousepos.Y) = i) then
|
|
canvas.Brush.Color := clMoneyGreen;
|
|
if (itemselected = i) then
|
|
canvas.Brush.Color := clBlue;
|
|
Canvas.Rectangle(r);
|
|
Canvas.Font.Color := clWhite;
|
|
Canvas.TextRect(r, 0, 0, items[i], style);
|
|
Caption := IntToStr(start) + '..' + IntToStr(i);
|
|
end
|
|
else
|
|
break;
|
|
end;
|
|
|
|
Canvas.Brush.Color := clGray;
|
|
Canvas.Rectangle(Width - scrollwidth, 0, Width, Height);
|
|
|
|
Canvas.Font.Color := clRed;
|
|
Canvas.TextOut(10, 10, IntToStr(invalidatecount));
|
|
Inc(invalidatecount);
|
|
end;
|
|
|
|
function TBCListBoxEx.GetItemRect(index: integer): TRect;
|
|
begin
|
|
Result := Rect(0, (index * itemheight) + scrolly, Width - scrollwidth,
|
|
(index * itemheight) + scrolly + itemheight);
|
|
end;
|
|
|
|
function TBCListBoxEx.GetItemVertically(y: integer): integer;
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := trunc(abs(scrolly) / itemheight);
|
|
Result := i + trunc(y / itemheight);
|
|
if (Result > items.Count) or (Result < 0) then
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TBCListBoxEx.ScrollToItemTop();
|
|
begin
|
|
scrolly := scrolly + itemheight;
|
|
end;
|
|
|
|
procedure TBCListBoxEx.ScrollToItemBottom();
|
|
begin
|
|
scrolly := scrolly - itemheight;
|
|
end;
|
|
|
|
procedure TBCListBoxEx.ScrollToItem(index: integer);
|
|
begin
|
|
scrolly := -itemheight * index;
|
|
end;
|
|
|
|
function TBCListBoxEx.ItemIsVisible(index: integer): boolean;
|
|
var
|
|
r: TRect;
|
|
begin
|
|
r := GetItemRect(index);
|
|
Result := Rect(0, 0, Width, Height).Contains(r);
|
|
end;
|
|
|
|
end.
|