mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-10 03:16:10 +02:00
fpvectorial: Add gradients with more than two colors
git-svn-id: trunk@51194 -
This commit is contained in:
parent
8ff7b2a5c9
commit
288db7b666
@ -123,9 +123,16 @@ type
|
||||
end;
|
||||
PvPen = ^TvPen;
|
||||
|
||||
TvBrushKind = (bkSimpleBrush, bkHorizontalGradient, bkVerticalGradient, vkOtherLinearGradient, bkRadialGradient);
|
||||
TvBrushKind = (bkSimpleBrush, bkHorizontalGradient, bkVerticalGradient, bkOtherLinearGradient, bkRadialGradient);
|
||||
TvCoordinateUnit = (vcuDocumentUnit, vcuPercentage);
|
||||
|
||||
TvGradientColor = record
|
||||
Color: TFPColor;
|
||||
Position: Double;
|
||||
end;
|
||||
|
||||
TvGradientColors = array of TvGradientColor;
|
||||
|
||||
TvBrush = record
|
||||
Color: TFPColor;
|
||||
Style: TFPBrushStyle;
|
||||
@ -133,7 +140,7 @@ type
|
||||
// Gradient filling support
|
||||
Gradient_cx, Gradient_cy, Gradient_r, Gradient_fx, Gradient_fy: Double;
|
||||
Gradient_cx_Unit, Gradient_cy_Unit, Gradient_r_Unit, Gradient_fx_Unit, Gradient_fy_Unit: TvCoordinateUnit;
|
||||
Gradient_colors: array of TFPColor;
|
||||
Gradient_colors: TvGradientColors;
|
||||
end;
|
||||
PvBrush = ^TvBrush;
|
||||
|
||||
@ -3633,29 +3640,83 @@ procedure TvEntityWithPenAndBrush.DrawPolygonBrushGradient(ADest: TFPCustomCanva
|
||||
var
|
||||
lPoints: TPointsArray;
|
||||
lColor, lColor1, lColor2: TFPColor;
|
||||
i, j: Integer;
|
||||
i, j, c: Integer;
|
||||
i1, i2: Integer;
|
||||
p, p1, p2: Double;
|
||||
begin
|
||||
if not (Brush.Kind in [bkVerticalGradient, bkHorizontalGradient]) then
|
||||
Exit;
|
||||
|
||||
lColor1 := Brush.Gradient_colors[1];
|
||||
lColor2 := Brush.Gradient_colors[0];
|
||||
ADest.Pen.Style := psSolid;
|
||||
if Brush.Kind = bkVerticalGradient then // horizontal (!) lines have same color
|
||||
if Length(Brush.Gradient_colors) = 1 then
|
||||
begin
|
||||
for i := y1 to y2 do
|
||||
lColor1 := Brush.Gradient_colors[0].Color;
|
||||
lColor2 := Brush.Gradient_colors[0].Color;
|
||||
c := 0;
|
||||
end else
|
||||
begin
|
||||
c := 0;
|
||||
lColor1 := Brush.Gradient_colors[0].Color;
|
||||
lColor2 := Brush.Gradient_colors[1].Color;
|
||||
p1 := Brush.Gradient_colors[0].Position;
|
||||
p2 := Brush.Gradient_colors[1].Position;
|
||||
end;
|
||||
|
||||
case Brush.Kind of
|
||||
bkVerticalGradient:
|
||||
begin // horizontal (!) lines have same color
|
||||
i1 := y1;
|
||||
i2 := y2;
|
||||
end;
|
||||
bkHorizontalGradient:
|
||||
begin // vertical lines have same color
|
||||
i1 := x1;
|
||||
i2 := x2;
|
||||
end;
|
||||
end;
|
||||
|
||||
ADest.Pen.Style := psSolid;
|
||||
for i := i1 to i2 do
|
||||
begin
|
||||
lPoints := GetLinePolygonIntersectionPoints(i, APolyPoints,
|
||||
Brush.Kind = bkHorizontalGradient);
|
||||
if Length(lPoints) < 2 then Continue;
|
||||
p := (i-i1) / (i2-i1) * 100.0; // p = "percent"
|
||||
// Use first color below first position
|
||||
if p < Brush.Gradient_colors[0].Position then
|
||||
lColor := Brush.Gradient_colors[0].Color
|
||||
else
|
||||
// Use last color above last position
|
||||
if p > Brush.Gradient_colors[High(Brush.Gradient_colors)].Position then
|
||||
lColor := Brush.Gradient_colors[High(Brush.Gradient_colors)].Color
|
||||
else
|
||||
if (c < High(Brush.Gradient_colors)) then
|
||||
begin
|
||||
lPoints := GetLinePolygonIntersectionPoints(i, APolyPoints, False);
|
||||
if Length(lPoints) < 2 then Continue;
|
||||
lColor := MixColors(lColor1, lColor2, i-y1, y2-y1);
|
||||
ADest.Pen.FPColor := lColor;
|
||||
j := 0;
|
||||
while j < High(lPoints) do
|
||||
// Use current color pair if percentage is below next position
|
||||
if (p < Brush.Gradient_colors[c+1].Position) then
|
||||
lColor := MixColors(lColor2, lColor1, p-p1, p2-p1)
|
||||
else
|
||||
// Next next color pair if percentage is above next position
|
||||
begin
|
||||
ADest.Line(lPoints[j].X, i, lPoints[j+1].X, i);
|
||||
inc(j, 2);
|
||||
inc(c);
|
||||
p1 := p2;
|
||||
p2 := Brush.Gradient_colors[c+1].Position;
|
||||
lColor1 := lColor2;
|
||||
lColor2 := Brush.Gradient_colors[c+1].Color;
|
||||
lColor := MixColors(lColor2, lColor1, p-p1, p2-p1);
|
||||
end;
|
||||
end;
|
||||
ADest.Pen.FPColor := lColor;
|
||||
j := 0;
|
||||
while j < High(lPoints) do
|
||||
begin
|
||||
case Brush.Kind of
|
||||
bkVerticalGradient : ADest.Line(lPoints[j].X, i, lPoints[j+1].X, i);
|
||||
bkHorizontalGradient: ADest.Line(i, lPoints[j].Y, i, lPoints[j+1].Y);
|
||||
end;
|
||||
inc(j, 2);
|
||||
end;
|
||||
end;
|
||||
{
|
||||
end
|
||||
else if Brush.Kind = bkHorizontalGradient then // vertical (!) lines have same color
|
||||
begin
|
||||
@ -3663,7 +3724,7 @@ begin
|
||||
begin
|
||||
lPoints := GetLinePolygonIntersectionPoints(i, APolyPoints, True);
|
||||
if Length(lPoints) < 2 then Continue;
|
||||
lColor := MixColors(lColor1, lColor2, i-x1, x2-x1);
|
||||
lColor := MixColors(lColor2, lColor1, i-x1, x2-x1);
|
||||
ADest.Pen.FPColor := lColor;
|
||||
j := 0;
|
||||
while (j < High(lPoints)) do
|
||||
@ -3673,6 +3734,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
}
|
||||
end;
|
||||
|
||||
{ Fills the entity's shape with a gradient.
|
||||
@ -3711,8 +3773,8 @@ begin
|
||||
if not (Brush.Kind in [bkVerticalGradient, bkHorizontalGradient]) then
|
||||
Exit;
|
||||
|
||||
lColor1 := Brush.Gradient_colors[1];
|
||||
lColor2 := Brush.Gradient_colors[0];
|
||||
lColor1 := Brush.Gradient_colors[1].Color;
|
||||
lColor2 := Brush.Gradient_colors[0].Color;
|
||||
if Brush.Kind = bkVerticalGradient then
|
||||
begin
|
||||
for i := y1 to y2 do
|
||||
@ -4239,7 +4301,7 @@ begin
|
||||
if ((APoints[j].Y <= ACoord) and (ACoord < APoints[j+1].Y)) or
|
||||
((APoints[j+1].Y <= ACoord) and (ACoord < APoints[j].Y)) then
|
||||
begin
|
||||
dy := APoints[j].Y - APoints[j].Y; // can't be zero here
|
||||
dy := APoints[j+1].Y - APoints[j].Y; // can't be zero here
|
||||
dx := APoints[j+1].X - APoints[j].X;
|
||||
xval := APoints[j].X + (ACoord - APoints[j].Y) * dx / dy;
|
||||
list.Add(pointer(PtrInt(round(xval))));
|
||||
|
@ -100,6 +100,7 @@ type
|
||||
// debug symbols
|
||||
FPathNumber: Integer;
|
||||
function ReadSVGColor(AValue: string): TFPColor;
|
||||
function ReadSVGGradientColorStyle(AValue: STring): TFPColor;
|
||||
function ReadSVGStyle(AValue: string; ADestEntity: TvEntityWithPen; ADestStyle: TvStyle = nil; AUseFillAsPen: Boolean = False): TvSetPenBrushAndFontElements;
|
||||
function ReadSVGStyleToStyleLists(AValue: string; AStyleKeys, AStyleValues: TStringList): TvSetPenBrushAndFontElements;
|
||||
function ReadSVGPenStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPen): TvSetPenBrushAndFontElements;
|
||||
@ -720,6 +721,37 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// style="stop-color:rgb(255,255,10);stop-opacity:1.0"
|
||||
function TvSVGVectorialReader.ReadSVGGradientColorStyle(AValue: String): TFPColor;
|
||||
var
|
||||
lStr, lStyleKeyStr, lStyleValueStr: String;
|
||||
lStrings: TStringList;
|
||||
i: Integer;
|
||||
p: Integer;
|
||||
begin
|
||||
Result := colBlack;
|
||||
if AValue = '' then Exit;
|
||||
lStrings := TStringList.Create;
|
||||
try
|
||||
lStrings.Delimiter := ';';
|
||||
lStrings.StrictDelimiter := True;
|
||||
lStrings.DelimitedText := LowerCase(AValue);
|
||||
for i := 0 to lStrings.Count-1 do
|
||||
begin
|
||||
lStr := lStrings.Strings[i];
|
||||
p := Pos(':', lStr);
|
||||
lStyleKeyStr := Trim(Copy(lStr, 1, p-1));
|
||||
lStyleValueStr := Trim(Copy(lStr, p+1, MaxInt));
|
||||
if lStyleKeyStr = 'stop-color' then
|
||||
Result := ReadSVGColor(lStyleValueStr)
|
||||
else if lStyleKeyStr = 'stop-opacity' then
|
||||
Result.Alpha := Round(StrToFloat(lStyleValueStr, FPointSeparator)*$FFFF);
|
||||
end;
|
||||
finally
|
||||
lStrings.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
// style="fill:none;stroke:black;stroke-width:3"
|
||||
function TvSVGVectorialReader.ReadSVGStyle(AValue: string;
|
||||
ADestEntity: TvEntityWithPen; ADestStyle: TvStyle = nil;
|
||||
@ -901,7 +933,7 @@ begin
|
||||
begin
|
||||
Len := Length(ADestEntity.Brush.Gradient_colors);
|
||||
SetLength(ADestEntity.Brush.Gradient_colors, Len+1);
|
||||
ADestEntity.Brush.Gradient_colors[Len] := ReadSVGColor(AValue);
|
||||
ADestEntity.Brush.Gradient_colors[Len].Color := ReadSVGColor(AValue);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1198,11 +1230,11 @@ var
|
||||
lPreviousLayer: TvEntityWithSubEntities;
|
||||
lAttrName, lAttrValue, lNodeName: DOMString;
|
||||
lLayerName: String;
|
||||
i: Integer;
|
||||
i, len: Integer;
|
||||
lCurNode, lCurSubNode: TDOMNode;
|
||||
lBrushEntity: TvEntityWithPenAndBrush;
|
||||
lCurEntity: TvEntity;
|
||||
lOffset: Double;
|
||||
lGradientColor: TvGradientColor;
|
||||
x1, x2, y1, y2: string;
|
||||
begin
|
||||
lCurNode := ANode.FirstChild;
|
||||
@ -1290,8 +1322,12 @@ begin
|
||||
else if lAttrName = 'y2' then
|
||||
y2 := lAttrValue;
|
||||
end;
|
||||
if x2 = x1 then lBrushEntity.Brush.Kind := bkVerticalGradient
|
||||
else lBrushEntity.Brush.Kind := bkHorizontalGradient;
|
||||
if x2 = x1 then
|
||||
lBrushEntity.Brush.Kind := bkVerticalGradient
|
||||
else if y2=y1 then
|
||||
lBrushEntity.Brush.Kind := bkHorizontalGradient
|
||||
else
|
||||
lBrushEntity.Brush.Kind := bkOtherLinearGradient;
|
||||
|
||||
// <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
|
||||
// <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
|
||||
@ -1299,19 +1335,22 @@ begin
|
||||
while Assigned(lCurSubNode) do
|
||||
begin
|
||||
lNodeName := LowerCase(lCurSubNode.NodeName);
|
||||
|
||||
for i := 0 to lCurSubNode.Attributes.Length - 1 do
|
||||
begin
|
||||
lAttrName := lCurSubNode.Attributes.Item[i].NodeName;
|
||||
lAttrValue := lCurSubNode.Attributes.Item[i].NodeValue;
|
||||
if lAttrName = 'offset' then
|
||||
if lNodeName = 'stop' then begin
|
||||
for i := 0 to lCurSubNode.Attributes.Length - 1 do
|
||||
begin
|
||||
lOffset := StringWithUnitToFloat(lAttrValue);
|
||||
end
|
||||
else if lAttrName = 'style' then
|
||||
ReadSVGStyle(lAttrValue, lBrushEntity);
|
||||
lAttrName := lCurSubNode.Attributes.Item[i].NodeName;
|
||||
lAttrValue := lCurSubNode.Attributes.Item[i].NodeValue;
|
||||
if lAttrName = 'offset' then
|
||||
lGradientColor.Position := StringWithUnitToFloat(lAttrValue)
|
||||
else if lAttrName = 'style' then
|
||||
lGradientColor.Color := ReadSVGGradientColorStyle(lAttrValue)
|
||||
else if lAttrName = 'stop-color' then
|
||||
lGradientColor.Color := ReadSVGColor(lAttrValue);
|
||||
end;
|
||||
len := Length(lBrushEntity.Brush.Gradient_colors);
|
||||
SetLength(lBrushEntity.Brush.Gradient_colors, Len+1);
|
||||
lBrushEntity.Brush.Gradient_colors[len] := lGradientColor;
|
||||
end;
|
||||
|
||||
lCurSubNode := lCurSubNode.NextSibling;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user