|
@@ -39,11 +39,17 @@ type
|
|
|
protected
|
|
|
procedure MouseHandler(Event: TAbstractEvent); virtual;
|
|
|
public
|
|
|
- Border: TFresnelLength;
|
|
|
+ Padding: TFresnelLength;
|
|
|
+ ThumbArea: TFresnelRect;
|
|
|
+ TrackArea: TFresnelRect;
|
|
|
+ ButtonLT: TFresnelRect;
|
|
|
+ ButtonRB: TFresnelRect;
|
|
|
constructor Create(AOwner: TComponent); override; overload;
|
|
|
+ procedure Layout; virtual;
|
|
|
procedure Draw(Renderer: TFresnelRenderer); virtual;
|
|
|
+ procedure DrawButton(Renderer: TFresnelRenderer; LT: boolean); virtual;
|
|
|
procedure DrawCorner(Renderer: TFresnelRenderer; const r: TFresnelRect); virtual;
|
|
|
- function GetHit(const X, Y: TFresnelLength; out aPosition: TFresnelLength): THit; override;
|
|
|
+ function GetHit(const X, Y: TFresnelLength; out aPosition: TFresnelLength): TSBHit; override;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelRenderer }
|
|
@@ -135,6 +141,8 @@ type
|
|
|
procedure FillRect(const aColor: TFPColor; const aRect: TFresnelRect); virtual; abstract;
|
|
|
// Draw a line from point A (x1,y1) to B (x2,y2) using given color.
|
|
|
procedure Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength); virtual; abstract;
|
|
|
+ // Draw a filled polygon
|
|
|
+ procedure Polygon(const aColor: TFPColor; const p: PFresnelPoint; Count: integer); virtual; abstract;
|
|
|
// Restores a saved state of clipping and matrix.
|
|
|
procedure Restore; virtual; abstract;
|
|
|
// Draw (and optionally fill) a rounded rectangle with given boundaries and color.
|
|
@@ -408,7 +416,7 @@ procedure TRendererScrollBar.MouseHandler(Event: TAbstractEvent);
|
|
|
var
|
|
|
MouseEvt: TFresnelMouseEvent absolute Event;
|
|
|
X, Y, p, NewPos: TFresnelLength;
|
|
|
- Hit: THit;
|
|
|
+ Hit: TSBHit;
|
|
|
begin
|
|
|
// the mouse event has the coord of the Parent's clientbox
|
|
|
// -> translate to GrandParent's child box
|
|
@@ -429,17 +437,17 @@ begin
|
|
|
writeln('TRendererScrollBar.MouseHandler Mouse Down ',Parent.Name,' Horz=',Horizontal,' Hit=',MouseDownHit,' p=',FloatToCSSStr(MouseDownGrabPos));
|
|
|
{$ENDIF}
|
|
|
case MouseDownHit of
|
|
|
- THit.hButtonLT: ;
|
|
|
- THit.hButtonRB: ;
|
|
|
- THit.hThumb:
|
|
|
+ TSBHit.hButtonLT: ;
|
|
|
+ TSBHit.hButtonRB: ;
|
|
|
+ TSBHit.hThumb:
|
|
|
begin
|
|
|
SetPointerCapture((MouseEvt as TFresnelMouseDownEvent).PointerId);
|
|
|
exit;
|
|
|
end;
|
|
|
- THit.hTrackLT:
|
|
|
+ TSBHit.hTrackLT:
|
|
|
// scroll one page left/top
|
|
|
NewPos:=Position-Page;
|
|
|
- THit.hTrackRB:
|
|
|
+ TSBHit.hTrackRB:
|
|
|
// scroll one page right/bottom
|
|
|
NewPos:=Position+Page;
|
|
|
else exit;
|
|
@@ -451,11 +459,11 @@ begin
|
|
|
if (MouseEvt.Button=mbLeft) then
|
|
|
begin
|
|
|
Hit:=GetHit(X,Y,p);
|
|
|
- if Hit=THit.hNone then ;
|
|
|
+ if Hit=TSBHit.hNone then ;
|
|
|
{$IFDEF VerboseFresnelScrolling}
|
|
|
writeln('TRendererScrollBar.MouseHandler Mouse Move ',Parent.Name,' Horz=',Horizontal,' Hit=',Hit,' p=',FloatToCSSStr(p),' GrabPos=',FloatToCSSStr(MouseDownGrabPos));
|
|
|
{$ENDIF}
|
|
|
- if MouseDownHit=THit.hThumb then
|
|
|
+ if MouseDownHit=TSBHit.hThumb then
|
|
|
begin
|
|
|
// move thumb
|
|
|
NewPos:=MouseDownPosition+(p-MouseDownGrabPos);
|
|
@@ -471,7 +479,7 @@ begin
|
|
|
writeln('TRendererScrollBar.MouseHandler Mouse Up ',Parent.Name,' Horz=',Horizontal,' Hit=',Hit,' p=',FloatToCSSStr(p));
|
|
|
{$ENDIF}
|
|
|
MouseDownGrabPos:=0;
|
|
|
- MouseDownHit:=THit.hNone;
|
|
|
+ MouseDownHit:=TSBHit.hNone;
|
|
|
ReleasePointerCapture((MouseEvt as TFresnelMouseUpEvent).PointerId);
|
|
|
end;
|
|
|
end;
|
|
@@ -485,85 +493,237 @@ begin
|
|
|
AddEventListener(evtMouseUp,@MouseHandler);
|
|
|
end;
|
|
|
|
|
|
-procedure TRendererScrollBar.Draw(Renderer: TFresnelRenderer);
|
|
|
+procedure TRendererScrollBar.Layout;
|
|
|
var
|
|
|
- CurTrackColor, CurThumbColor: TFPColor;
|
|
|
- FromPos, ToPos, l, Radius: TFresnelLength;
|
|
|
r: TFresnelRect;
|
|
|
- ThumbR: TFresnelRoundRect;
|
|
|
- c: TFresnelCSSCorner;
|
|
|
+ aBarLength, aBarWidth, BtnSize, FromPos, ToPos, l: TFresnelLength;
|
|
|
begin
|
|
|
r:=Box;
|
|
|
+ ThumbArea:=Default(TFresnelRect);
|
|
|
+ TrackArea:=Default(TFresnelRect);
|
|
|
+ ButtonLT:=Default(TFresnelRect);
|
|
|
+ ButtonRB:=Default(TFresnelRect);
|
|
|
+ Padding:=0;
|
|
|
|
|
|
- GetColors(CurThumbColor,CurTrackColor);
|
|
|
- // draw track
|
|
|
- Renderer.FillRect(CurTrackColor,r);
|
|
|
- if Size<1 then
|
|
|
- exit;
|
|
|
+ if r.IsEmpty then exit;
|
|
|
+
|
|
|
+ if Horizontal then
|
|
|
+ begin
|
|
|
+ aBarLength:=r.Width;
|
|
|
+ aBarWidth:=r.Height;
|
|
|
+ end else begin
|
|
|
+ aBarLength:=r.Height;
|
|
|
+ aBarWidth:=r.Width;
|
|
|
+ end;
|
|
|
+ Padding:=round(Min(aBarLength,aBarWidth)/6);
|
|
|
+
|
|
|
+ if Viewport.ScrollbarsHaveButtons then
|
|
|
+ begin
|
|
|
+ BtnSize:=Min(aBarLength/2,aBarWidth)-2*Padding;
|
|
|
+ if BtnSize<1 then exit;
|
|
|
+ if Horizontal then
|
|
|
+ begin
|
|
|
+ ButtonLT.Left:=r.Left+Padding;
|
|
|
+ ButtonLT.Right:=ButtonLT.Left+BtnSize;
|
|
|
+ ButtonLT.Top:=r.Top+(aBarWidth-BtnSize)/2;
|
|
|
+ ButtonLT.Bottom:=ButtonLT.Top+BtnSize;
|
|
|
+
|
|
|
+ ButtonRB.Right:=r.Right-Padding;
|
|
|
+ ButtonRB.Left:=ButtonRB.Right-BtnSize;
|
|
|
+ ButtonRB.Top:=ButtonLT.Top;
|
|
|
+ ButtonRB.Bottom:=ButtonLT.Bottom;
|
|
|
+
|
|
|
+ TrackArea.Left:=ButtonLT.Right+Padding;
|
|
|
+ TrackArea.Right:=ButtonRB.Left-Padding;
|
|
|
+ TrackArea.Top:=r.Top+Padding;
|
|
|
+ TrackArea.Bottom:=r.Bottom-Padding;
|
|
|
+ end else begin
|
|
|
+ ButtonLT.Left:=r.Left+(aBarWidth-BtnSize)/2;
|
|
|
+ ButtonLT.Right:=ButtonLT.Left+BtnSize;
|
|
|
+ ButtonLT.Top:=r.Top+Padding;
|
|
|
+ ButtonLT.Bottom:=ButtonLT.Top+BtnSize;
|
|
|
+
|
|
|
+ ButtonRB.Left:=ButtonLT.Left;
|
|
|
+ ButtonRB.Right:=ButtonLT.Right;
|
|
|
+ ButtonRB.Bottom:=r.Bottom-Padding;
|
|
|
+ ButtonRB.Top:=ButtonRB.Bottom-BtnSize;
|
|
|
+
|
|
|
+ TrackArea.Left:=r.Left+Padding;
|
|
|
+ TrackArea.Right:=r.Right-Padding;
|
|
|
+ TrackArea.Top:=ButtonLT.Bottom+Padding;
|
|
|
+ TrackArea.Bottom:=ButtonRB.Top-Padding;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ TrackArea.Left:=r.Left+Padding;
|
|
|
+ TrackArea.Top:=r.Top+Padding;
|
|
|
+ TrackArea.Right:=r.Right-Padding;
|
|
|
+ TrackArea.Bottom:=r.Bottom-Padding;
|
|
|
+ end;
|
|
|
+ if TrackArea.IsEmpty then
|
|
|
+ TrackArea:=Default(TFresnelRect);
|
|
|
|
|
|
- // draw thumb
|
|
|
FromPos:=Position/Size;
|
|
|
if FromPos<0 then FromPos:=0;
|
|
|
if FromPos>1 then FromPos:=1;
|
|
|
ToPos:=(Position+Page)/Size;
|
|
|
if ToPos<0 then ToPos:=0;
|
|
|
if ToPos>1 then ToPos:=1;
|
|
|
+
|
|
|
+ ThumbArea:=TrackArea;
|
|
|
if Horizontal then
|
|
|
begin
|
|
|
- if r.Width<r.Height then exit;
|
|
|
- Border:=round(r.Height/6);
|
|
|
+ l:=ThumbArea.Width;
|
|
|
+ FromPos:=FromPos*l;
|
|
|
+ ToPos:=ToPos*l;
|
|
|
+ ThumbArea.Left:=ThumbArea.Left+FromPos;
|
|
|
+ ThumbArea.Right:=ThumbArea.Left+ToPos-FromPos;
|
|
|
end else begin
|
|
|
- if r.Height<r.Width then exit;
|
|
|
- Border:=round(r.Width/6);
|
|
|
+ l:=ThumbArea.Height;
|
|
|
+ FromPos:=FromPos*l;
|
|
|
+ ToPos:=ToPos*l;
|
|
|
+ ThumbArea.Top:=ThumbArea.Top+FromPos;
|
|
|
+ ThumbArea.Bottom:=ThumbArea.Top+ToPos-FromPos;
|
|
|
end;
|
|
|
- Radius:=Border*2;
|
|
|
- for c in TFresnelCSSCorner do begin
|
|
|
- ThumbR.Radii[c].X:=Radius;
|
|
|
- ThumbR.Radii[c].Y:=Radius;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TRendererScrollBar.Draw(Renderer: TFresnelRenderer);
|
|
|
+var
|
|
|
+ FromPos, ToPos, l, RadiusX, RadiusY: TFresnelLength;
|
|
|
+ r: TFresnelRect;
|
|
|
+ ThumbR: TFresnelRoundRect;
|
|
|
+ c: TFresnelCSSCorner;
|
|
|
+begin
|
|
|
+ Layout;
|
|
|
+ r:=Box;
|
|
|
+
|
|
|
+ // draw track
|
|
|
+ Renderer.FillRect(GetTrackColor,r);
|
|
|
+ if Size<1 then
|
|
|
+ exit;
|
|
|
+
|
|
|
+ //writeln('TRendererScrollBar.Draw Horz=',Horizontal,' Box=',Box.ToString,' ButtonLT=',ButtonLT.ToString,' Track=',TrackArea.ToString,' Thumb=',ThumbArea.ToString,' ButtonRB=',ButtonRB.ToString);
|
|
|
+
|
|
|
+ // draw thumb
|
|
|
+ if (ThumbArea.Width>=1) and (ThumbArea.Height>=1) then
|
|
|
+ begin
|
|
|
+ RadiusX:=Min(2*Padding,ThumbArea.Width/2);
|
|
|
+ RadiusY:=Min(2*Padding,ThumbArea.Height/2);
|
|
|
+ //writeln('TRendererScrollBar.Draw ',FloatToCSSStr(RadiusX),' Padding=',FloatToCSSStr(Padding));
|
|
|
+ if (RadiusX>1) and (RadiusY>1) then
|
|
|
+ begin
|
|
|
+ // round corners
|
|
|
+ ThumbR.Box:=ThumbArea;
|
|
|
+ for c in TFresnelCSSCorner do
|
|
|
+ begin
|
|
|
+ ThumbR.Radii[c].X:=RadiusX;
|
|
|
+ ThumbR.Radii[c].Y:=RadiusY;
|
|
|
+ end;
|
|
|
+ //writeln('TRendererScrollBar.Draw ROUND ',ThumbR.Box.ToString,' ',FloatToCSSStr(RadiusX));
|
|
|
+ Renderer.RoundRect(GetThumbColor,ThumbR,true);
|
|
|
+ end else begin
|
|
|
+ // rect
|
|
|
+ Renderer.FillRect(GetThumbColor,ThumbArea);
|
|
|
+ end;
|
|
|
end;
|
|
|
- ThumbR.Box.Left:=r.Left+Border;
|
|
|
- ThumbR.Box.Top:=r.Top+Border;
|
|
|
- ThumbR.Box.Right:=r.Right-Border;
|
|
|
- ThumbR.Box.Bottom:=r.Bottom-Border;
|
|
|
+
|
|
|
if Horizontal then
|
|
|
+ DrawButton(Renderer,true);
|
|
|
+ //DrawButton(Renderer,false);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TRendererScrollBar.DrawButton(Renderer: TFresnelRenderer; LT: boolean);
|
|
|
+var
|
|
|
+ r: TFresnelRect;
|
|
|
+ p: TFresnelPointArray;
|
|
|
+ w, h: TFresnelLength;
|
|
|
+begin
|
|
|
+ // draw a triangular arrow, starting with the tip
|
|
|
+ p:=[];
|
|
|
+ SetLength(p,3);
|
|
|
+ if LT then
|
|
|
begin
|
|
|
- l:=ThumbR.Box.Width;
|
|
|
- ThumbR.Box.Left:=ThumbR.Box.Left+FromPos*l;
|
|
|
- ThumbR.Box.Right:=ThumbR.Box.Left+Max((ToPos-FromPos)*l,2*Radius);
|
|
|
- end else begin
|
|
|
- l:=ThumbR.Box.Height;
|
|
|
- ThumbR.Box.Top:=ThumbR.Box.Top+FromPos*l;
|
|
|
- ThumbR.Box.Bottom:=ThumbR.Box.Top+Max((ToPos-FromPOs)*l,2*Radius);
|
|
|
+ r:=ButtonLT;
|
|
|
+ w:=r.Right-r.Left;
|
|
|
+ h:=r.Bottom-r.Top;
|
|
|
+ if Horizontal then
|
|
|
+ begin
|
|
|
+ // left arrow
|
|
|
+ p[0].X:=r.Left+w/4;
|
|
|
+ p[0].Y:=r.Top+h/2;
|
|
|
+ p[1].X:=r.Right-w/4;
|
|
|
+ p[1].Y:=r.Top;
|
|
|
+ p[2].X:=p[1].X;
|
|
|
+ p[2].Y:=r.Bottom;
|
|
|
+ end else begin
|
|
|
+ // right arrow
|
|
|
+ p[0].X:=r.Right-w/4;
|
|
|
+ p[0].Y:=r.Top+h/2;
|
|
|
+ p[1].X:=r.Right-w/2;
|
|
|
+ p[1].Y:=r.Bottom;
|
|
|
+ p[2].X:=p[1].X;
|
|
|
+ p[2].Y:=r.Top;
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else begin
|
|
|
+ r:=ButtonRB;
|
|
|
+ if Horizontal then
|
|
|
+ begin
|
|
|
+ // top arrow
|
|
|
+ p[0].X:=r.Left+w/2;
|
|
|
+ p[0].Y:=r.Top+h/4;
|
|
|
+ p[1].X:=r.Right;
|
|
|
+ p[1].Y:=r.Bottom-h/4;
|
|
|
+ p[2].X:=r.Left;
|
|
|
+ p[2].Y:=p[1].Y;
|
|
|
+ end else begin
|
|
|
+ // bottom arrow
|
|
|
+ p[0].X:=r.Left+w/2;
|
|
|
+ p[0].Y:=r.Bottom-h/4;
|
|
|
+ p[1].X:=r.Left;
|
|
|
+ p[1].Y:=r.Top+h/4;
|
|
|
+ p[2].X:=r.Right;
|
|
|
+ p[2].Y:=p[1].Y;
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
- Renderer.RoundRect(CurThumbColor,ThumbR,true);
|
|
|
+ //writeln('TRendererScrollBar.DrawButton Horz=',Horizontal,' LT=',LT,' r=',r.ToString,' p0=',p[0].ToString,' ',p[1].ToString,' ',p[2].ToString);
|
|
|
+ Renderer.Polygon(GetThumbColor,@p[0],3);
|
|
|
end;
|
|
|
|
|
|
procedure TRendererScrollBar.DrawCorner(Renderer: TFresnelRenderer; const r: TFresnelRect);
|
|
|
-var
|
|
|
- CurThumbColor, CurTrackColor: TFPColor;
|
|
|
begin
|
|
|
- GetColors(CurThumbColor,CurTrackColor);
|
|
|
- Renderer.FillRect(CurTrackColor,r);
|
|
|
+ Renderer.FillRect(GetTrackColor,r);
|
|
|
end;
|
|
|
|
|
|
-function TRendererScrollBar.GetHit(const X, Y: TFresnelLength; out aPosition: TFresnelLength): THit;
|
|
|
+function TRendererScrollBar.GetHit(const X, Y: TFresnelLength; out aPosition: TFresnelLength): TSBHit;
|
|
|
var
|
|
|
- LT, RB: TFresnelLength;
|
|
|
+ LT, RB, l: TFresnelLength;
|
|
|
begin
|
|
|
- Result:=THit.hNone;
|
|
|
+ Result:=TSBHit.hNone;
|
|
|
aPosition:=0;
|
|
|
if Horizontal then
|
|
|
begin
|
|
|
- LT:=Box.Left+Border;
|
|
|
- RB:=Box.Right-Border;
|
|
|
- if LT>RB-1 then exit;
|
|
|
- aPosition:=(X-LT) / (RB-LT);
|
|
|
+ if (ButtonLT.Width>0) and (X<=ButtonLT.Right+Padding/2) then
|
|
|
+ exit(TSBHit.hButtonLT);
|
|
|
+ if (ButtonRB.Width>0) and (X>=ButtonRB.Left-Padding/2) then
|
|
|
+ exit(TSBHit.hButtonRB);
|
|
|
+ l:=TrackArea.Width;
|
|
|
+ if l<=0 then exit;
|
|
|
+ if l>=1 then
|
|
|
+ aPosition:=(X-TrackArea.Left) / l
|
|
|
+ else if X>Box.Right then
|
|
|
+ aPosition:=1;
|
|
|
end else begin
|
|
|
- LT:=Box.Top+Border;
|
|
|
- RB:=Box.Bottom-Border;
|
|
|
- if LT>RB-1 then exit;
|
|
|
- aPosition:=(Y-LT) / (RB-LT);
|
|
|
+ if (ButtonLT.Height>0) and (Y<=ButtonLT.Bottom+Padding/2) then
|
|
|
+ exit(TSBHit.hButtonLT);
|
|
|
+ if (ButtonRB.Height>0) and (Y>=ButtonRB.Top-Padding/2) then
|
|
|
+ exit(TSBHit.hButtonRB);
|
|
|
+ l:=TrackArea.Height;
|
|
|
+ if l<=0 then exit;
|
|
|
+ if l>=1 then
|
|
|
+ aPosition:=(Y-TrackArea.Top) / l
|
|
|
+ else if Y>Box.Bottom then
|
|
|
+ aPosition:=1;
|
|
|
end;
|
|
|
if aPosition<0 then aPosition:=0;
|
|
|
if aPosition>1 then aPosition:=1;
|
|
@@ -572,11 +732,11 @@ begin
|
|
|
//writeln('TRendererScrollBar.GetHit Horz=',Horizontal,' aPosition=',FloatToCSSStr(aPosition),' Position=',FloatToCSSStr(Position),' Size=',FloatToCSSStr(Size),' LT=',FloatToCSSStr(LT),' RB=',FloatToCSSStr(RB),' Y=',FloatToCSSStr(Y));
|
|
|
|
|
|
if aPosition<Position then
|
|
|
- Result:=THit.hTrackLT
|
|
|
+ Result:=TSBHit.hTrackLT
|
|
|
else if aPosition>=Position+Page then
|
|
|
- Result:=THit.hTrackRB
|
|
|
+ Result:=TSBHit.hTrackRB
|
|
|
else
|
|
|
- Result:=THit.hThumb;
|
|
|
+ Result:=TSBHit.hThumb;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelRenderer }
|