mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-24 07:19:34 +01:00
fpvectorial: Now rendering ellipses with gradient filling works
git-svn-id: trunk@49471 -
This commit is contained in:
parent
7150522a7b
commit
94a1fa8b33
@ -438,7 +438,8 @@ type
|
|||||||
function GetHeight(ADest: TFPCustomCanvas): Double;
|
function GetHeight(ADest: TFPCustomCanvas): Double;
|
||||||
function GetWidth(ADest: TFPCustomCanvas): Double;
|
function GetWidth(ADest: TFPCustomCanvas): Double;
|
||||||
{@@ ASubpart is only valid if this routine returns vfrSubpartFound }
|
{@@ ASubpart is only valid if this routine returns vfrSubpartFound }
|
||||||
function TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult; virtual;
|
function GetLineIntersectionPoints(ACoord: Double; ACoordIsX: Boolean): TDoubleDynArray; virtual; // get all points where the entity inner area crosses a line
|
||||||
|
function TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult; virtual;
|
||||||
procedure Move(ADeltaX, ADeltaY: Double); virtual;
|
procedure Move(ADeltaX, ADeltaY: Double); virtual;
|
||||||
procedure MoveSubpart(ADeltaX, ADeltaY: Double; ASubpart: Cardinal); virtual;
|
procedure MoveSubpart(ADeltaX, ADeltaY: Double; ASubpart: Cardinal); virtual;
|
||||||
function GetSubpartCount: Integer; virtual;
|
function GetSubpartCount: Integer; virtual;
|
||||||
@ -496,6 +497,9 @@ type
|
|||||||
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas); overload;
|
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas); overload;
|
||||||
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas; ABrush: TvBrush); overload;
|
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas; ABrush: TvBrush); overload;
|
||||||
procedure AssignBrush(ABrush: TvBrush);
|
procedure AssignBrush(ABrush: TvBrush);
|
||||||
|
procedure DrawBrushGradient(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
|
x1, y1, x2, y2: Integer;
|
||||||
|
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||||
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
||||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||||
@ -589,7 +593,7 @@ type
|
|||||||
Render_Use_NextText_X: Boolean;
|
Render_Use_NextText_X: Boolean;
|
||||||
constructor Create(APage: TvPage); override;
|
constructor Create(APage: TvPage); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult; override;
|
function TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult; override;
|
||||||
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
||||||
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
||||||
@ -666,6 +670,8 @@ type
|
|||||||
VertHalfAxis: Double; // This half-axis is the vertical one when Angle=0
|
VertHalfAxis: Double; // This half-axis is the vertical one when Angle=0
|
||||||
{@@ The Angle is measured in degrees in relation to the positive X axis }
|
{@@ The Angle is measured in degrees in relation to the positive X axis }
|
||||||
Angle: Double;
|
Angle: Double;
|
||||||
|
function GetLineIntersectionPoints(ACoord: Double; ACoordIsX: Boolean): TDoubleDynArray; override;
|
||||||
|
function TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult; override;
|
||||||
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
||||||
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
||||||
@ -1031,7 +1037,7 @@ type
|
|||||||
function AddRasterImage: TvRasterImage;
|
function AddRasterImage: TvRasterImage;
|
||||||
function AddEmbeddedVectorialDoc: TvEmbeddedVectorialDoc;
|
function AddEmbeddedVectorialDoc: TvEmbeddedVectorialDoc;
|
||||||
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
||||||
function TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult; override;
|
function TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult; override;
|
||||||
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
||||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||||
@ -1104,7 +1110,7 @@ type
|
|||||||
procedure GetEffectiveCellSpacing(out ATopSpacing, ALeftSpacing, ARightSpacing, ABottomSpacing: Double); virtual;
|
procedure GetEffectiveCellSpacing(out ATopSpacing, ALeftSpacing, ARightSpacing, ABottomSpacing: Double); virtual;
|
||||||
function CalculateCellHeight_ForWidth(ADest: TFPCustomCanvas; AWidth: Double): Double; virtual;
|
function CalculateCellHeight_ForWidth(ADest: TFPCustomCanvas; AWidth: Double): Double; virtual;
|
||||||
function CalculateMaxNeededWidth(ADest: TFPCustomCanvas): Double; virtual;
|
function CalculateMaxNeededWidth(ADest: TFPCustomCanvas): Double; virtual;
|
||||||
function TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult; override;
|
function TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult; override;
|
||||||
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
||||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||||
@ -3167,7 +3173,12 @@ begin
|
|||||||
Result := Abs(ALeft - ARight);
|
Result := Abs(ALeft - ARight);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TvEntity.TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult;
|
function TvEntity.GetLineIntersectionPoints(ACoord: Double; ACoordIsX: Boolean): TDoubleDynArray;
|
||||||
|
begin
|
||||||
|
SetLength(Result, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvEntity.TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult;
|
||||||
begin
|
begin
|
||||||
Result := vfrNotFound;
|
Result := vfrNotFound;
|
||||||
end;
|
end;
|
||||||
@ -3350,6 +3361,71 @@ begin
|
|||||||
Brush.Color := ABrush.Color;
|
Brush.Color := ABrush.Color;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TvEntityWithPenAndBrush.DrawBrushGradient(ADest: TFPCustomCanvas;
|
||||||
|
var ARenderInfo: TvRenderInfo; x1, y1, x2, y2: Integer;
|
||||||
|
ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double);
|
||||||
|
|
||||||
|
function CoordToCanvasX(ACoord: Double): Integer;
|
||||||
|
begin
|
||||||
|
Result := Round(ADestX + AmulX * ACoord);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CoordToCanvasY(ACoord: Double): Integer;
|
||||||
|
begin
|
||||||
|
Result := Round(ADestY + AmulY * ACoord);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CanvasToCoordY(ACanvas: Integer): Double;
|
||||||
|
begin
|
||||||
|
Result := (ACanvas - ADestY) / AmulY;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CanvasToCoordX(ACanvas: Integer): Double;
|
||||||
|
begin
|
||||||
|
Result := (ACanvas - ADestX) / AmulX;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MixColors(AColor1, AColor2: TFPColor; APos, AMax: Double): TFPColor;
|
||||||
|
begin
|
||||||
|
Result.Alpha := Round(AColor1.Alpha * APos / AMax + AColor2.Alpha * (AMax - APos) / AMax);
|
||||||
|
Result.Red := Round(AColor1.Red * APos / AMax + AColor2.Red * (AMax - APos) / AMax);
|
||||||
|
Result.Green := Round(AColor1.Green * APos / AMax + AColor2.Green * (AMax - APos) / AMax);
|
||||||
|
Result.Blue := Round(AColor1.Blue * APos / AMax + AColor2.Blue * (AMax - APos) / AMax);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
lPoints: TDoubleDynArray;
|
||||||
|
lColor, lColor1, lColor2: TFPColor;
|
||||||
|
begin
|
||||||
|
if not (Brush.Kind in [bkVerticalGradient, bkHorizontalGradient]) then
|
||||||
|
Exit;
|
||||||
|
lColor1 := Brush.Gradient_colors[0];
|
||||||
|
lColor2 := Brush.Gradient_colors[1];
|
||||||
|
if Brush.Kind = bkVerticalGradient then
|
||||||
|
begin
|
||||||
|
for i := y1 to y2 do
|
||||||
|
begin
|
||||||
|
lPoints := GetLineIntersectionPoints(CanvasToCoordY(i), False);
|
||||||
|
lColor := MixColors(lColor1, lColor2, i-y1, y2-y1);
|
||||||
|
ADest.Pen.FPColor := lColor;
|
||||||
|
ADest.Pen.Style := psSolid;
|
||||||
|
ADest.Line(CoordToCanvasX(lPoints[0]), i, CoordToCanvasX(lPoints[1]), i);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else if Brush.Kind = bkHorizontalGradient then
|
||||||
|
begin
|
||||||
|
for i := x1 to x2 do
|
||||||
|
begin
|
||||||
|
lPoints := GetLineIntersectionPoints(CanvasToCoordX(i), True);
|
||||||
|
lColor := MixColors(lColor1, lColor2, i-x1, x2-x1);
|
||||||
|
ADest.Pen.FPColor := lColor;
|
||||||
|
ADest.Pen.Style := psSolid;
|
||||||
|
ADest.Line(i, CoordToCanvasY(lPoints[0]), i, CoordToCanvasY(lPoints[1]));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TvEntityWithPenAndBrush.Render(ADest: TFPCustomCanvas;
|
procedure TvEntityWithPenAndBrush.Render(ADest: TFPCustomCanvas;
|
||||||
var ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double; ADoDraw: Boolean);
|
var ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double; ADoDraw: Boolean);
|
||||||
begin
|
begin
|
||||||
@ -4170,11 +4246,11 @@ begin
|
|||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TvText.TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult;
|
function TvText.TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult;
|
||||||
var
|
var
|
||||||
lProximityFactor: Integer;
|
lProximityFactor: Integer;
|
||||||
begin
|
begin
|
||||||
lProximityFactor := 5;
|
lProximityFactor := ASnapFlexibility;
|
||||||
if (APos.X > X - lProximityFactor) and (APos.X < X + lProximityFactor)
|
if (APos.X > X - lProximityFactor) and (APos.X < X + lProximityFactor)
|
||||||
and (APos.Y > Y - lProximityFactor) and (APos.Y < Y + lProximityFactor) then
|
and (APos.Y > Y - lProximityFactor) and (APos.Y < Y + lProximityFactor) then
|
||||||
Result := vfrFound
|
Result := vfrFound
|
||||||
@ -4537,6 +4613,37 @@ end;
|
|||||||
|
|
||||||
{ TvEllipse }
|
{ TvEllipse }
|
||||||
|
|
||||||
|
function TvEllipse.GetLineIntersectionPoints(ACoord: Double; ACoordIsX: Boolean): TDoubleDynArray;
|
||||||
|
begin
|
||||||
|
SetLength(Result, 2);
|
||||||
|
// this is for axis-aligned ellipses
|
||||||
|
// (X-Xcenter)^2 / Rx^2 + (Y-Ycenter)^2 / Ry^2 <= 1
|
||||||
|
if ACoordIsX then
|
||||||
|
begin
|
||||||
|
// Y = sqrt( 1 - (X-Xcenter)^2 / Rx^2 ) * Ry + Xcenter
|
||||||
|
Result[0] := Max(0, 1-sqr(ACoord-X) / sqr(HorzHalfAxis));
|
||||||
|
Result[0] := sqrt(Result[0]) * VertHalfAxis + X;
|
||||||
|
Result[1] := Max(0, 1-sqr(ACoord-X) / sqr(HorzHalfAxis));
|
||||||
|
Result[1] := -1 * sqrt(Result[1]) * VertHalfAxis + X;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result[0] := Max(0, 1-sqr(ACoord-Y) / sqr(VertHalfAxis));
|
||||||
|
Result[0] := sqrt(Result[0]) * HorzHalfAxis + Y;
|
||||||
|
Result[1] := Max(0, 1-sqr(ACoord-Y) / sqr(VertHalfAxis));
|
||||||
|
Result[1] := -1 * sqrt(Result[1]) * HorzHalfAxis + Y;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvEllipse.TryToSelect(APos: TPoint; var ASubpart: Cardinal;
|
||||||
|
ASnapFlexibility: Integer): TvFindEntityResult;
|
||||||
|
begin
|
||||||
|
// this is for axis-aligned ellipses
|
||||||
|
// (X-Xcenter)^2 / Rx^2 + (Y-Ycenter)^2 / Ry^2 <= 1
|
||||||
|
Result := vfrNotFound;
|
||||||
|
//Result := vfrFound;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TvEllipse.CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double);
|
procedure TvEllipse.CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double);
|
||||||
var
|
var
|
||||||
t, tmp: Double;
|
t, tmp: Double;
|
||||||
@ -4632,13 +4739,19 @@ begin
|
|||||||
ADest.Ellipse(x1, y1, x2, y2);
|
ADest.Ellipse(x1, y1, x2, y2);
|
||||||
end;
|
end;
|
||||||
// Apply brush gradient
|
// Apply brush gradient
|
||||||
if Brush.Kind in [bkHorizontalGradient, bkVerticalGradient] then
|
if x1 > x2 then
|
||||||
begin
|
begin
|
||||||
{PrepareBrushBitmap(x2, y2);
|
dk := x1;
|
||||||
BrushBitmap.Canvas.Ellipse(0, 0, x2-x1, y2-y1);
|
x1 := x2;
|
||||||
AlphaBlendBrushBitmap(ADest, x1, y1);
|
x2 := dk;
|
||||||
FreeAndNil(BrushBitmap);}
|
|
||||||
end;
|
end;
|
||||||
|
if y1 > y2 then
|
||||||
|
begin
|
||||||
|
dk := y1;
|
||||||
|
y1 := y2;
|
||||||
|
y2 := dk;
|
||||||
|
end;
|
||||||
|
DrawBrushGradient(ADest, ARenderInfo, x1, y1, x2, y2, ADestX, ADestY, AMulX, AMulY);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TvRectangle }
|
{ TvRectangle }
|
||||||
@ -6472,9 +6585,9 @@ begin
|
|||||||
ABottom := Y;
|
ABottom := Y;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TvParagraph.TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult;
|
function TvParagraph.TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult;
|
||||||
begin
|
begin
|
||||||
Result:=inherited TryToSelect(APos, ASubpart);
|
Result:=inherited TryToSelect(APos, ASubpart, ASnapFlexibility);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvParagraph.Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
procedure TvParagraph.Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
@ -6845,9 +6958,9 @@ begin
|
|||||||
Result := Result + SpacingLeft + SpacingRight;
|
Result := Result + SpacingLeft + SpacingRight;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TvRichText.TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult;
|
function TvRichText.TryToSelect(APos: TPoint; var ASubpart: Cardinal; ASnapFlexibility: Integer = 5): TvFindEntityResult;
|
||||||
begin
|
begin
|
||||||
Result:=inherited TryToSelect(APos, ASubpart);
|
Result:=inherited TryToSelect(APos, ASubpart, ASnapFlexibility);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvRichText.Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
procedure TvRichText.Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
|
|||||||
@ -944,7 +944,7 @@ begin
|
|||||||
Result := [];
|
Result := [];
|
||||||
if AKey = 'fill' then
|
if AKey = 'fill' then
|
||||||
begin
|
begin
|
||||||
// Suppose for fill="url(#grad2)"
|
// Support for fill="url(#grad2)"
|
||||||
lDefName := Trim(AValue);
|
lDefName := Trim(AValue);
|
||||||
if Copy(lDefName, 0, 3) = 'url' then
|
if Copy(lDefName, 0, 3) = 'url' then
|
||||||
begin
|
begin
|
||||||
@ -1364,7 +1364,7 @@ begin
|
|||||||
else if lAttrName = 'y2' then
|
else if lAttrName = 'y2' then
|
||||||
y2 := lAttrValue;
|
y2 := lAttrValue;
|
||||||
end;
|
end;
|
||||||
if x2 = '0%' then lBrushEntity.Brush.Kind := bkVerticalGradient
|
if x2 = x1 then lBrushEntity.Brush.Kind := bkVerticalGradient
|
||||||
else lBrushEntity.Brush.Kind := bkHorizontalGradient;
|
else lBrushEntity.Brush.Kind := bkHorizontalGradient;
|
||||||
|
|
||||||
// <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
|
// <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user