mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-13 10:09:14 +02:00
TAChart: Add wordwrapping feature to axis title.
git-svn-id: trunk@64799 -
This commit is contained in:
parent
970b6b43d6
commit
2d5c00038e
@ -116,11 +116,14 @@ type
|
|||||||
FRange: TChartRange;
|
FRange: TChartRange;
|
||||||
FTitle: TChartAxisTitle;
|
FTitle: TChartAxisTitle;
|
||||||
FTransformations: TChartAxisTransformations;
|
FTransformations: TChartAxisTransformations;
|
||||||
|
FWrappedTitle: String;
|
||||||
FZPosition: TChartDistance;
|
FZPosition: TChartDistance;
|
||||||
|
|
||||||
function GetMarks: TChartAxisMarks; inline;
|
function GetMarks: TChartAxisMarks; inline;
|
||||||
|
function GetRealTitle: String;
|
||||||
function GetValue(AIndex: Integer): TChartValueText; inline;
|
function GetValue(AIndex: Integer): TChartValueText; inline;
|
||||||
function GetValueCount: Integer; inline;
|
function GetValueCount: Integer; inline;
|
||||||
|
function IsWordwrappedTitle: Boolean;
|
||||||
function PositionIsStored: Boolean;
|
function PositionIsStored: Boolean;
|
||||||
procedure SetAtDataOnly(AValue: Boolean);
|
procedure SetAtDataOnly(AValue: Boolean);
|
||||||
procedure SetAxisPen(AValue: TChartAxisPen);
|
procedure SetAxisPen(AValue: TChartAxisPen);
|
||||||
@ -139,6 +142,7 @@ type
|
|||||||
procedure SetTitle(AValue: TChartAxisTitle);
|
procedure SetTitle(AValue: TChartAxisTitle);
|
||||||
procedure SetTransformations(AValue: TChartAxisTransformations);
|
procedure SetTransformations(AValue: TChartAxisTransformations);
|
||||||
procedure SetZPosition(AValue: TChartDistance);
|
procedure SetZPosition(AValue: TChartDistance);
|
||||||
|
procedure WordwrapTitle(ADrawer: IChartDrawer; AClipRect: TRect);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
function GetDisplayName: String; override;
|
function GetDisplayName: String; override;
|
||||||
@ -160,8 +164,8 @@ type
|
|||||||
function IsFlipped: Boolean; override;
|
function IsFlipped: Boolean; override;
|
||||||
function IsPointInside(const APoint: TPoint): Boolean;
|
function IsPointInside(const APoint: TPoint): Boolean;
|
||||||
function IsVertical: Boolean; inline;
|
function IsVertical: Boolean; inline;
|
||||||
procedure Measure(
|
procedure Measure(const AExtent: TDoubleRect; const AClipRect: TRect;
|
||||||
const AExtent: TDoubleRect; var AMeasureData: TChartAxisGroup);
|
var AMeasureData: TChartAxisGroup);
|
||||||
function MeasureLabelSize(ADrawer: IChartDrawer): Integer;
|
function MeasureLabelSize(ADrawer: IChartDrawer): Integer;
|
||||||
function PositionToCoord(const ARect: TRect): Integer;
|
function PositionToCoord(const ARect: TRect): Integer;
|
||||||
procedure PrepareHelper(
|
procedure PrepareHelper(
|
||||||
@ -235,8 +239,8 @@ type
|
|||||||
procedure Draw(ACurrentZ: Integer; var AIndex: Integer);
|
procedure Draw(ACurrentZ: Integer; var AIndex: Integer);
|
||||||
function GetAxisByAlign(AAlign: TChartAxisAlignment): TChartAxis;
|
function GetAxisByAlign(AAlign: TChartAxisAlignment): TChartAxis;
|
||||||
function GetEnumerator: TChartAxisEnumerator;
|
function GetEnumerator: TChartAxisEnumerator;
|
||||||
function Measure(
|
function Measure(const AExtent: TDoubleRect; const AClipRect: TRect;
|
||||||
const AExtent: TDoubleRect; ADepth: Integer): TChartAxisMargins;
|
ADepth: Integer): TChartAxisMargins;
|
||||||
procedure Prepare(ARect: TRect);
|
procedure Prepare(ARect: TRect);
|
||||||
procedure PrepareGroups;
|
procedure PrepareGroups;
|
||||||
procedure SetAxisByAlign(AAlign: TChartAxisAlignment; AValue: TChartAxis);
|
procedure SetAxisByAlign(AAlign: TChartAxisAlignment; AValue: TChartAxis);
|
||||||
@ -276,7 +280,8 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
LResources, Math, PropEdits, TAChartStrConsts, TAGeometry, TAMath;
|
LResources, Math, PropEdits,
|
||||||
|
TAChartStrConsts, TAGeometry, TAMath;
|
||||||
|
|
||||||
var
|
var
|
||||||
VIdentityTransform: TChartAxisTransformations;
|
VIdentityTransform: TChartAxisTransformations;
|
||||||
@ -636,7 +641,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
TPointBoolArr(p)[IsVertical] := FTitlePos;
|
TPointBoolArr(p)[IsVertical] := FTitlePos;
|
||||||
p += FHelper.FZOffset;
|
p += FHelper.FZOffset;
|
||||||
Title.DrawLabel(FHelper.FDrawer, p, p, Title.Caption, FTitlePolygon);
|
Title.DrawLabel(FHelper.FDrawer, p, p, GetRealTitle, FTitlePolygon);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TChartAxis.GetAlignment: TChartAxisAlignment;
|
function TChartAxis.GetAlignment: TChartAxisAlignment;
|
||||||
@ -665,6 +670,14 @@ begin
|
|||||||
Result := TChartAxisMarks(inherited Marks);
|
Result := TChartAxisMarks(inherited Marks);
|
||||||
end{%H-}; // to silence the compiler warning of impossible inherited inside inline proc
|
end{%H-}; // to silence the compiler warning of impossible inherited inside inline proc
|
||||||
|
|
||||||
|
function TChartAxis.GetRealTitle: String;
|
||||||
|
begin
|
||||||
|
if Title.Visible and IsWordwrappedTitle then
|
||||||
|
Result := FWrappedTitle
|
||||||
|
else
|
||||||
|
Result := Title.Caption;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChartAxis.GetMarkValues;
|
procedure TChartAxis.GetMarkValues;
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
@ -763,6 +776,13 @@ begin
|
|||||||
Result := Alignment in [calLeft, calRight];
|
Result := Alignment in [calLeft, calRight];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TChartAxis.IsWordwrappedTitle: Boolean;
|
||||||
|
begin
|
||||||
|
Result := Title.Wordwrap and (
|
||||||
|
((FAlignment in [calLeft, calRight]) and (abs(Title.LabelFont.Orientation) = 900)) or
|
||||||
|
((FAlignment in [calTop, calBottom]) and (Title.LabelFont.Orientation = 0)) );
|
||||||
|
end;
|
||||||
|
|
||||||
function TChartAxis.MakeValuesInRangeParams(
|
function TChartAxis.MakeValuesInRangeParams(
|
||||||
AMin, AMax: Double): TValuesInRangeParams;
|
AMin, AMax: Double): TValuesInRangeParams;
|
||||||
begin
|
begin
|
||||||
@ -779,7 +799,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TChartAxis.Measure(
|
procedure TChartAxis.Measure(
|
||||||
const AExtent: TDoubleRect; var AMeasureData: TChartAxisGroup);
|
const AExtent: TDoubleRect; const AClipRect: TRect; var AMeasureData: TChartAxisGroup);
|
||||||
var
|
var
|
||||||
v: Boolean;
|
v: Boolean;
|
||||||
d: IChartDrawer;
|
d: IChartDrawer;
|
||||||
@ -788,7 +808,7 @@ var
|
|||||||
begin
|
begin
|
||||||
if not Title.Visible or (Title.Caption = '') then exit(0);
|
if not Title.Visible or (Title.Caption = '') then exit(0);
|
||||||
// Workaround for issue #19780, fix after upgrade to FPC 2.6.
|
// Workaround for issue #19780, fix after upgrade to FPC 2.6.
|
||||||
with Title.MeasureLabel(d, Title.Caption) do
|
with Title.MeasureLabel(d, GetRealTitle) do
|
||||||
Result := IfThen(v, cx, cy);
|
Result := IfThen(v, cx, cy);
|
||||||
if Title.DistanceToCenter then
|
if Title.DistanceToCenter then
|
||||||
Result := Result div 2;
|
Result := Result div 2;
|
||||||
@ -856,11 +876,16 @@ begin
|
|||||||
maxi := i;
|
maxi := i;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if Title.Visible and IsWordwrappedTitle then
|
||||||
|
WordwrapTitle(d, AClipRect);
|
||||||
|
|
||||||
with AMeasureData do begin
|
with AMeasureData do begin
|
||||||
FSize := Max(sz, FSize);
|
FSize := Max(sz, FSize);
|
||||||
FTitleSize := Max(TitleSize, FTitleSize);
|
FTitleSize := Max(TitleSize, FTitleSize);
|
||||||
FMargin := Max(Margin, FMargin);
|
FMargin := Max(Margin, FMargin);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if minc < MaxInt then begin
|
if minc < MaxInt then begin
|
||||||
UpdateFirstLast(minc, mini, rmin, rmax);
|
UpdateFirstLast(minc, mini, rmin, rmax);
|
||||||
UpdateFirstLast(maxc, maxi, rmin, rmax);
|
UpdateFirstLast(maxc, maxi, rmin, rmax);
|
||||||
@ -1139,6 +1164,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
procedure TChartAxis.WordwrapTitle(ADrawer: IChartDrawer; AClipRect: TRect);
|
||||||
|
var
|
||||||
|
w: Integer;
|
||||||
|
begin
|
||||||
|
if Alignment in [calLeft, calRight] then
|
||||||
|
w := AClipRect.Height
|
||||||
|
else if Alignment in [calBottom, calTop] then
|
||||||
|
w := AClipRect.Width
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
FWrappedTitle := Title.Caption;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
ADrawer.Font := Title.LabelFont;
|
||||||
|
FWrappedTitle := TADrawUtils.WordWrap(Title.Caption, ADrawer, w, Title.TextFormat);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TChartAxisList }
|
{ TChartAxisList }
|
||||||
|
|
||||||
function TChartAxisList.Add: TChartAxis; inline;
|
function TChartAxisList.Add: TChartAxis; inline;
|
||||||
@ -1210,8 +1253,8 @@ begin
|
|||||||
AList.Sort(ACompare);
|
AList.Sort(ACompare);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TChartAxisList.Measure(
|
function TChartAxisList.Measure(const AExtent: TDoubleRect;
|
||||||
const AExtent: TDoubleRect; ADepth: Integer): TChartAxisMargins;
|
const AClipRect: TRect; ADepth: Integer): TChartAxisMargins;
|
||||||
var
|
var
|
||||||
g: ^TChartAxisGroup;
|
g: ^TChartAxisGroup;
|
||||||
|
|
||||||
@ -1239,14 +1282,14 @@ begin
|
|||||||
for j := 0 to g^.FCount - 1 do begin
|
for j := 0 to g^.FCount - 1 do begin
|
||||||
axis := TChartAxis(FGroupOrder[ai]);
|
axis := TChartAxis(FGroupOrder[ai]);
|
||||||
try
|
try
|
||||||
axis.Measure(AExtent, g^);
|
axis.Measure(AExtent, AClipRect, g^);
|
||||||
except
|
except
|
||||||
axis.Visible := false;
|
axis.Visible := false;
|
||||||
raise;
|
raise;
|
||||||
end;
|
end;
|
||||||
ai += 1;
|
ai += 1;
|
||||||
end;
|
end;
|
||||||
// Axises of the same group should have the same Alignment, Position and ZPosition.
|
// Axes of the same group should have the same Alignment, Position and ZPosition.
|
||||||
if axis.IsDefaultPosition then
|
if axis.IsDefaultPosition then
|
||||||
Result[axis.Alignment] += Max(0,
|
Result[axis.Alignment] += Max(0,
|
||||||
g^.FSize + g^.FTitleSize + g^.FMargin +
|
g^.FSize + g^.FTitleSize + g^.FMargin +
|
||||||
|
@ -41,11 +41,13 @@ type
|
|||||||
strict private
|
strict private
|
||||||
FCaption: String;
|
FCaption: String;
|
||||||
FPositionOnMarks: Boolean;
|
FPositionOnMarks: Boolean;
|
||||||
|
FWordwrap: Boolean;
|
||||||
|
|
||||||
function GetFont: TFont;
|
function GetFont: TFont;
|
||||||
procedure SetCaption(AValue: String);
|
procedure SetCaption(AValue: String);
|
||||||
procedure SetFont(AValue: TFont);
|
procedure SetFont(AValue: TFont);
|
||||||
procedure SetPositionOnMarks(AValue: Boolean);
|
procedure SetPositionOnMarks(AValue: Boolean);
|
||||||
|
procedure SetWordwrap(AValue: Boolean);
|
||||||
public
|
public
|
||||||
constructor Create(AOwner: TCustomChart);
|
constructor Create(AOwner: TCustomChart);
|
||||||
|
|
||||||
@ -60,6 +62,7 @@ type
|
|||||||
read FPositionOnMarks write SetPositionOnMarks default false;
|
read FPositionOnMarks write SetPositionOnMarks default false;
|
||||||
property TextFormat;
|
property TextFormat;
|
||||||
property Visible default false;
|
property Visible default false;
|
||||||
|
property Wordwrap: Boolean read FWordwrap write SetWordwrap default false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ICoordTransformer = interface
|
ICoordTransformer = interface
|
||||||
@ -603,6 +606,14 @@ begin
|
|||||||
StyleChanged(Self);
|
StyleChanged(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxisTitle.SetWordwrap(AValue: Boolean);
|
||||||
|
begin
|
||||||
|
if FWordwrap = AValue then exit;
|
||||||
|
FWordwrap := AValue;
|
||||||
|
StyleChanged(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TCustomChartAxisMarks }
|
{ TCustomChartAxisMarks }
|
||||||
|
|
||||||
constructor TCustomChartAxisMarks.Create(AOwner: TCustomChart);
|
constructor TCustomChartAxisMarks.Create(AOwner: TCustomChart);
|
||||||
|
@ -15,7 +15,7 @@ unit TADrawUtils;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, FPCanvas, FPImage, Types, TAChartUtils;
|
SysUtils, Classes, FPCanvas, FPImage, Types, TAChartUtils;
|
||||||
|
|
||||||
type
|
type
|
||||||
// Same types as in Graphics unit, but without dependency.
|
// Same types as in Graphics unit, but without dependency.
|
||||||
@ -191,10 +191,14 @@ type
|
|||||||
function FPColorToChartColor(AFPColor: TFPColor): TChartColor;
|
function FPColorToChartColor(AFPColor: TFPColor): TChartColor;
|
||||||
function ColorDef(AColor, ADefaultColor: TChartColor): TChartColor; inline;
|
function ColorDef(AColor, ADefaultColor: TChartColor): TChartColor; inline;
|
||||||
|
|
||||||
|
function Wordwrap(const AText: String; ADrawer: IChartDrawer;
|
||||||
|
AMaxWidth: Integer; ATextFormat: TChartTextFormat): String;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Math, fasthtmlparser, htmlutil, TAGeometry, TAHtml;
|
StrUtils, Math, fasthtmlparser, htmlutil, TAGeometry, TAHtml;
|
||||||
|
|
||||||
const
|
const
|
||||||
LINE_INTERVAL = 2;
|
LINE_INTERVAL = 2;
|
||||||
@ -798,5 +802,65 @@ begin
|
|||||||
Result := TChartTextOut.Create(Self);
|
Result := TChartTextOut.Create(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Inserts LineEndings into the provided string AText such that its width
|
||||||
|
// does not exceed the given width.
|
||||||
|
function WordWrap(const AText: String; ADrawer: IChartDrawer;
|
||||||
|
AMaxWidth: Integer; ATextFormat: TChartTextFormat): string;
|
||||||
|
var
|
||||||
|
L: TStrings;
|
||||||
|
sa: TStringArray;
|
||||||
|
line, testline: String;
|
||||||
|
s: String;
|
||||||
|
w, ws, wspace: Integer;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
|
||||||
|
if ATextFormat = tfNormal then
|
||||||
|
begin
|
||||||
|
wspace := ADrawer.TextExtent(' ').X;
|
||||||
|
L := TStringList.Create;
|
||||||
|
try
|
||||||
|
L.Text := AText;
|
||||||
|
for i := 0 to L.Count-1 do
|
||||||
|
begin
|
||||||
|
sa := SplitString(L[i], ' ');
|
||||||
|
line := '';
|
||||||
|
w := 0;
|
||||||
|
for s in sa do
|
||||||
|
begin
|
||||||
|
ws := ADrawer.TextExtent(s).X;
|
||||||
|
if w + wspace + ws <= AMaxWidth then
|
||||||
|
begin
|
||||||
|
line := IfThen(line='', s, line + ' ' + s);
|
||||||
|
w := w + wspace + ws;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if line = '' then
|
||||||
|
begin
|
||||||
|
Result := IfThen(Result='', s, Result + LineEnding + s);
|
||||||
|
line := '';
|
||||||
|
w := 0;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Result := IfThen(Result='', line, Result + LineEnding + line);
|
||||||
|
line := s;
|
||||||
|
w := ws;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if line <> '' then
|
||||||
|
Result := IfThen(Result='', line, Result + LineEnding + line);
|
||||||
|
if i <> L.Count-1 then
|
||||||
|
Result := Result + LineEnding;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
L.Free;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
// ToDo: Implement wordwrap for html format
|
||||||
|
Result := AText;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -1521,7 +1521,7 @@ begin
|
|||||||
CalculateTransformationCoeffs(scSeriesMargins, scChartMargins, scMinDataSpace);
|
CalculateTransformationCoeffs(scSeriesMargins, scChartMargins, scMinDataSpace);
|
||||||
cr := FClipRect;
|
cr := FClipRect;
|
||||||
for tries := 1 to 10 do begin
|
for tries := 1 to 10 do begin
|
||||||
axisMargin := AxisList.Measure(CurrentExtent, scDepth);
|
axisMargin := AxisList.Measure(CurrentExtent, FClipRect, scDepth);
|
||||||
axisMargin[calLeft] := Max(axisMargin[calLeft], scDepth);
|
axisMargin[calLeft] := Max(axisMargin[calLeft], scDepth);
|
||||||
axisMargin[calBottom] := Max(axisMargin[calBottom], scDepth);
|
axisMargin[calBottom] := Max(axisMargin[calBottom], scDepth);
|
||||||
FClipRect := cr;
|
FClipRect := cr;
|
||||||
|
Loading…
Reference in New Issue
Block a user