diff --git a/components/fpspreadsheet/examples/other/chart/read_chart_demo.lpr b/components/fpspreadsheet/examples/other/chart/read_chart_demo.lpr index f21493ad3..d3c449321 100644 --- a/components/fpspreadsheet/examples/other/chart/read_chart_demo.lpr +++ b/components/fpspreadsheet/examples/other/chart/read_chart_demo.lpr @@ -33,12 +33,25 @@ begin WriteLn (' Hatch styles: '); for j := 0 to chart.Hatches.Count-1 do - WriteLn(' "', chart.Hatches[j].Name, '" ', + WriteLn(' "', chart.Hatches[j].Name, '" ', GetEnumName(TypeInfo(TsChartHatchStyle), ord(chart.Hatches[j].Style)), ' ', - 'Line color: ', IntToHex(chart.Hatches[j].LineColor, 6), ' ', - 'Distance: ', chart.Hatches[j].LineDistance:0:0, 'mm ', - 'Angle: ', chart.Hatches[j].LineAngle:0:0, 'deg ', - 'Filled: ', chart.Hatches[j].Filled); + 'Line color:', IntToHex(chart.Hatches[j].LineColor, 6), ' ', + 'Distance:', chart.Hatches[j].LineDistance:0:0, 'mm ', + 'Angle:', chart.Hatches[j].LineAngle:0:0, 'deg ', + 'Filled:', chart.Hatches[j].Filled); + + WriteLn (' Gradient styles: '); + for j := 0 to chart.Gradients.Count-1 do + WriteLn(' "', chart.Gradients[j].Name, '" ', + GetEnumName(TypeInfo(TsChartGradientStyle), ord(chart.Gradients[j].Style)), ' ', + 'StartColor:', IntToHex(chart.Gradients[j].StartColor, 6), ' ', + 'EndColor:', IntToHex(chart.Gradients[j].EndColor, 6), ' ', +// 'StartIntensity:', chart.Gradients[j].StartIntensity*100:0:0, '% ', +// 'EndIntensity:', chart.Gradients[j].EndIntensity*100:0:0, '% ', + 'Border:', chart.Gradients[j].Border*100:0:0, '% ', + 'Angle:', chart.Gradients[j].Angle:0:0, 'deg ', + 'CenterX:', chart.Gradients[j].CenterX*100:0:0, '% ', + 'CenterY:', chart.Gradients[j].CenterY*100:0:0, '% '); end; finally diff --git a/components/fpspreadsheet/source/common/fpschart.pas b/components/fpspreadsheet/source/common/fpschart.pas index aa4ae0e8b..8d57d91e7 100644 --- a/components/fpspreadsheet/source/common/fpschart.pas +++ b/components/fpspreadsheet/source/common/fpschart.pas @@ -61,10 +61,11 @@ type private function GetItem(AIndex: Integer): TsChartGradient; procedure SetItem(AIndex: Integer; AValue: TsChartGradient); + public function AddGradient(AName: String; AStyle: TsChartGradientStyle; AStartColor, AEndColor: TsColor; AStartIntensity, AEndIntensity: Double; ABorder, ACenterX, ACenterY, AAngle: Double): Integer; - public + function AddAxialGradient(AName: String; AStartColor, AEndColor: TsColor; AStartIntensity, AEndIntensity, ABorder, AAngle: Double): Integer; function AddEllipticGradient(AName: String; AStartColor, AEndColor: TsColor; diff --git a/components/fpspreadsheet/source/common/fpsopendocumentchart.pas b/components/fpspreadsheet/source/common/fpsopendocumentchart.pas index 737027a2c..0f406b1dd 100644 --- a/components/fpspreadsheet/source/common/fpsopendocumentchart.pas +++ b/components/fpspreadsheet/source/common/fpsopendocumentchart.pas @@ -20,6 +20,7 @@ type FChartFiles: TStrings; FPointSeparatorSettings: TFormatSettings; procedure ReadChartFiles(AStream: TStream; AFileList: String); + procedure ReadObjectGradientStyles(ANode: TDOMNode; AChart: TsChart); procedure ReadObjectHatchStyles(ANode: TDOMNode; AChart: TsChart); procedure ReadObjectLineStyles(ANode: TDOMNode; AChart: TsChart); procedure ReadObjectStyles(ANode: TDOMNode; AChart: TsChart); @@ -355,12 +356,78 @@ begin 'draw:hatch': // read hatch pattern ReadObjectHatchStyles(ANode, AChart); 'draw:gradient': // gradient definition - ; + ReadObjectGradientStyles(ANode, AChart); end; ANode := ANode.NextSibling; end; end; +procedure TsSpreadOpenDocChartReader.ReadObjectGradientStyles(ANode: TDOMNode; + AChart: TsChart); +var + i: Integer; + s: String; + styleName: String; + gs: TsChartGradientStyle; + gradientStyle: TsChartGradientStyle = cgsLinear; + startColor: TsColor = scSilver; + endColor: TsColor = scWhite; + startIntensity, endIntensity: Double; + border, centerX, centerY: Double; + angle: Double = 0.0; +begin + styleName := GetAttrValue(ANode, 'draw:display-name'); + if styleName ='' then + styleName := GetAttrValue(ANode, 'draw:name'); + + s := GetAttrValue(ANode, 'draw:style'); + if s <> '' then + for gs in TsChartGradientStyle do + if GRADIENT_STYLES[gs] = s then + begin + gradientStyle := gs; + break; + end; + + s := GetAttrValue(ANode, 'draw:start-color'); + if s <> '' then + startColor := HTMLColorStrToColor(s); + + s := GetAttrValue(ANode, 'draw:end-color'); + if s <> '' then + endColor := HTMLColorStrToColor(s); + + s := GetAttrValue(ANode, 'draw:start-intensity'); + if not TryPercentStrToFloat(s, startIntensity) then + startIntensity := 1.0; + + s := GetAttrValue(ANode, 'draw:end-intensity'); + if not TryPercentStrToFloat(s, endIntensity) then + endIntensity := 1.0; + + s := GetAttrValue(ANode, 'draw:border'); + if not TryPercentStrToFloat(s, border) then + border := 0.0; + + s := GetAttrValue(ANode, 'draw:angle'); + if s <> '' then begin + for i := Length(s) downto 1 do + if not (s[i] in ['0'..'9', '.', '+', '-']) then Delete(s, i, 1); + angle := StrToFloatDef(s, 0.0, FPointSeparatorSettings); + end; + + s := GetAttrValue(ANode, 'draw:cx'); + if not TryPercentStrToFloat(s, centerX) then + centerX := 0.0; + + s := GetAttrValue(ANode, 'draw:cy'); + if not TryPercentStrToFloat(s, centerY) then + centerY := 0.0; + + AChart.Gradients.AddGradient(styleName, gradientStyle, startColor, endColor, + startIntensity, endIntensity, border, centerX, centerY, angle); +end; + { Read the hatch pattern stored in the "draw:hatch" nodes of the chart's Object styles.xml file. } procedure TsSpreadOpenDocChartReader.ReadObjectHatchStyles(ANode: TDOMNode; AChart: TsChart); diff --git a/components/fpspreadsheet/source/common/fpsutils.pas b/components/fpspreadsheet/source/common/fpsutils.pas index 078486fc5..77cdfca9b 100644 --- a/components/fpspreadsheet/source/common/fpsutils.pas +++ b/components/fpspreadsheet/source/common/fpsutils.pas @@ -165,6 +165,8 @@ function TryStrToFloatAuto(AText: String; out ANumber: Double; function TryFractionStrToFloat(AText: String; out ANumber: Double; out AIsMixed: Boolean; out AMaxDigits: Integer): Boolean; +function TryPercentStrToFloat(AText: String; out ANumber: Double): Boolean; + function Round(AValue: Double): Int64; function cmToPts(AValue: Double): Double; inline; @@ -1976,6 +1978,24 @@ begin Result := true; end; +{@@ ---------------------------------------------------------------------------- + Converts a percent-formatted string to a decimal number. + Example: '150%' --> 1.5 +-------------------------------------------------------------------------------} +function TryPercentStrToFloat(AText: String; out ANumber: Double): boolean; +var + res: Integer; +begin + Result := false; + if AText = '' then + exit; + if AText[Length(AText)] = '%' then Delete(AText, Length(AText), 1); + val(AText, ANumber, res); + Result := (res = 0); + if Result then + ANumber := ANumber * 0.01; +end; + {@@ ---------------------------------------------------------------------------- Special rounding function which avoids banker's rounding -------------------------------------------------------------------------------}