|
@@ -33,6 +33,7 @@ uses
|
|
contnrs,
|
|
contnrs,
|
|
fpCanvas,
|
|
fpCanvas,
|
|
fpImage,
|
|
fpImage,
|
|
|
|
+ fpTTF,
|
|
fpreportstreamer,
|
|
fpreportstreamer,
|
|
{$IF FPC_FULLVERSION>=30101}
|
|
{$IF FPC_FULLVERSION>=30101}
|
|
fpexprpars,
|
|
fpexprpars,
|
|
@@ -142,7 +143,7 @@ type
|
|
moResetAggregateOnColumn
|
|
moResetAggregateOnColumn
|
|
);
|
|
);
|
|
TFPReportMemoOptions = set of TFPReportMemoOption;
|
|
TFPReportMemoOptions = set of TFPReportMemoOption;
|
|
- TFPReportWordWrapOverflow = (wwoTruncate,wwoOverflow,wwoSplit);
|
|
|
|
|
|
+ TFPReportWordOverflow = (woTruncate,woOverflow,woSplit);
|
|
|
|
|
|
TFPReportSections = set of rsPage..rsColumn;
|
|
TFPReportSections = set of rsPage..rsColumn;
|
|
|
|
|
|
@@ -1930,13 +1931,13 @@ type
|
|
ExpressionNodes: array of TExprNodeInfoRec;
|
|
ExpressionNodes: array of TExprNodeInfoRec;
|
|
FFont: TFPReportFont;
|
|
FFont: TFPReportFont;
|
|
FUseParentFont: Boolean;
|
|
FUseParentFont: Boolean;
|
|
- FWordWrapOverflow: TFPReportWordWrapOverflow;
|
|
|
|
|
|
+ FWordOverflow: TFPReportWordOverflow;
|
|
function GetParentFont: TFPReportFont;
|
|
function GetParentFont: TFPReportFont;
|
|
procedure HandleFontChange(Sender: TObject);
|
|
procedure HandleFontChange(Sender: TObject);
|
|
procedure SetCullThreshold(AValue: TFPReportCullThreshold);
|
|
procedure SetCullThreshold(AValue: TFPReportCullThreshold);
|
|
procedure SetText(AValue: TFPReportString);
|
|
procedure SetText(AValue: TFPReportString);
|
|
procedure SetUseParentFont(AValue: Boolean);
|
|
procedure SetUseParentFont(AValue: Boolean);
|
|
- procedure SetWordWrapOverflow(AValue: TFPReportWordWrapOverflow);
|
|
|
|
|
|
+ procedure SetWordOverflow(AValue: TFPReportWordOverflow);
|
|
procedure ApplyHorzTextAlignment;
|
|
procedure ApplyHorzTextAlignment;
|
|
procedure ApplyVertTextAlignment;
|
|
procedure ApplyVertTextAlignment;
|
|
function GetTextLines: TStrings;
|
|
function GetTextLines: TStrings;
|
|
@@ -1960,7 +1961,8 @@ type
|
|
procedure SetFont(const AValue: TFPReportFont);
|
|
procedure SetFont(const AValue: TFPReportFont);
|
|
procedure CullTextOutOfBounds;
|
|
procedure CullTextOutOfBounds;
|
|
protected
|
|
protected
|
|
- procedure WrapText(const AText: String; var ALines: TStrings; const ALineWidth: TFPReportUnits; out AHeight: TFPReportUnits); virtual;
|
|
|
|
|
|
+ procedure AddTextLine(lFC: TFPFontCacheItem; var S: String; MaxW: TFPReportUnits);
|
|
|
|
+ procedure WrapText(const AText: String; lFC: TFPFontCacheItem; const ALineWidth: TFPReportUnits; out AHeight: TFPReportUnits); virtual;
|
|
procedure ReassignParentFont;
|
|
procedure ReassignParentFont;
|
|
procedure ParentFontChanged; override;
|
|
procedure ParentFontChanged; override;
|
|
function CreateTextAlignment: TFPReportTextAlignment; virtual;
|
|
function CreateTextAlignment: TFPReportTextAlignment; virtual;
|
|
@@ -1984,7 +1986,7 @@ type
|
|
property UseParentFont: Boolean read FUseParentFont write SetUseParentFont default True;
|
|
property UseParentFont: Boolean read FUseParentFont write SetUseParentFont default True;
|
|
{ % of line height that should be visible, otherwise it's culled if StretchMode = smDontStretch. Valid range is 1-100% and default is 75%}
|
|
{ % of line height that should be visible, otherwise it's culled if StretchMode = smDontStretch. Valid range is 1-100% and default is 75%}
|
|
property CullThreshold: TFPReportCullThreshold read FCullThreshold write SetCullThreshold default 75;
|
|
property CullThreshold: TFPReportCullThreshold read FCullThreshold write SetCullThreshold default 75;
|
|
- Property WordWrapOverflow : TFPReportWordWrapOverflow read FWordWrapOverflow write SetWordWrapOverflow;
|
|
|
|
|
|
+ Property WordOverflow : TFPReportWordOverflow read FWordOverflow write SetWordOverflow;
|
|
protected
|
|
protected
|
|
// *****************************
|
|
// *****************************
|
|
// This block is made Protected simply for Unit Testing purposes.
|
|
// This block is made Protected simply for Unit Testing purposes.
|
|
@@ -2026,7 +2028,7 @@ type
|
|
property LineSpacing;
|
|
property LineSpacing;
|
|
property LinkColor;
|
|
property LinkColor;
|
|
property Options;
|
|
property Options;
|
|
- Property WordWrapOverflow;
|
|
|
|
|
|
+ Property WordOverflow;
|
|
property StretchMode;
|
|
property StretchMode;
|
|
property Text;
|
|
property Text;
|
|
property TextAlignment;
|
|
property TextAlignment;
|
|
@@ -2353,8 +2355,7 @@ uses
|
|
typinfo,
|
|
typinfo,
|
|
FPReadPNG,
|
|
FPReadPNG,
|
|
FPWritePNG,
|
|
FPWritePNG,
|
|
- base64,
|
|
|
|
- fpTTF;
|
|
|
|
|
|
+ base64;
|
|
|
|
|
|
resourcestring
|
|
resourcestring
|
|
cPageCountMarker = '~PC~';
|
|
cPageCountMarker = '~PC~';
|
|
@@ -3916,95 +3917,94 @@ begin
|
|
Changed;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomMemo.SetWordWrapOverflow(AValue: TFPReportWordWrapOverflow);
|
|
|
|
|
|
+procedure TFPReportCustomMemo.SetWordOverflow(AValue: TFPReportWordOverflow);
|
|
begin
|
|
begin
|
|
- if FWordWrapOverflow=AValue then Exit;
|
|
|
|
- FWordWrapOverflow:=AValue;
|
|
|
|
|
|
+ if FWordOverflow=AValue then Exit;
|
|
|
|
+ FWordOverflow:=AValue;
|
|
Changed;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomMemo.WrapText(const AText: String; var ALines: TStrings; const ALineWidth: TFPReportUnits; out
|
|
|
|
- AHeight: TFPReportUnits);
|
|
|
|
|
|
+{ All = True) indicates that if the text is split over multiple lines the last
|
|
|
|
+ line must also be processed before continuing. If All = False, then double
|
|
|
|
+ CR can be ignored. }
|
|
|
|
+
|
|
|
|
+procedure TFPReportCustomMemo.AddTextLine(lFC: TFPFontCacheItem; Var S : String; MaxW : TFPReportUnits);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ w: single;
|
|
|
|
+ m: integer;
|
|
|
|
+ s2, s3: string;
|
|
|
|
+begin
|
|
|
|
+ s2 := s;
|
|
|
|
+ w := lFC.TextWidth(s2, Font.Size);
|
|
|
|
+ if (Length(s2) > 1) and (w > maxw) then
|
|
|
|
+ begin
|
|
|
|
+ while w > maxw do
|
|
|
|
+ begin
|
|
|
|
+ m := Length(s);
|
|
|
|
+ repeat
|
|
|
|
+ Dec(m);
|
|
|
|
+ s2 := Copy(s,1,m);
|
|
|
|
+ w := lFC.TextWidth(s2, Font.Size);
|
|
|
|
+ until w <= maxw;
|
|
|
|
+
|
|
|
|
+ s3 := s2; // we might need the value of s2 later again
|
|
|
|
+
|
|
|
|
+ // are we in the middle of a word. If so find the beginning of word.
|
|
|
|
+ while (m > 0) and (s2[m] <> ' ') do
|
|
|
|
+ Dec(m);
|
|
|
|
+ s2 := Copy(s,1,m);
|
|
|
|
+
|
|
|
|
+ if s2 = '' then
|
|
|
|
+ begin
|
|
|
|
+ // Single word does not fit. S3 is max word that fits.
|
|
|
|
+ s2 := s3;
|
|
|
|
+ Case WordOverflow of
|
|
|
|
+ woOverflow:
|
|
|
|
+ begin
|
|
|
|
+ { We reached the beginning of the line without finding a word that fits the maxw.
|
|
|
|
+ So we are forced to use a longer than maxw word. We were in the middle of
|
|
|
|
+ a word, so now find the end of the current word. }
|
|
|
|
+ m := Length(s2);
|
|
|
|
+ while (m < Length(s)) and (s[m]<> ' ') do
|
|
|
|
+ Inc(m);
|
|
|
|
+ s2:=Copy(s,1,m);
|
|
|
|
+ end;
|
|
|
|
+ woTruncate:
|
|
|
|
+ m:=Length(S); // Discard the remainder of the word.
|
|
|
|
+ woSplit:
|
|
|
|
+ m:=Length(S3); // S3 was the longest possible part of the word. Split after
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ FTextLines.Add(s2);
|
|
|
|
+ s := Copy(s, m+1, Length(s));
|
|
|
|
+ s2 := s;
|
|
|
|
+ w := lFC.TextWidth(s2, Font.Size);
|
|
|
|
+ end; { while }
|
|
|
|
+ if s2 <> '' then
|
|
|
|
+ FTextLines.Add(s2);
|
|
|
|
+ s := '';
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ if s2 <> '' then
|
|
|
|
+ FTextLines.Add(s2);
|
|
|
|
+ s := '';
|
|
|
|
+ end; { if/else }
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportCustomMemo.WrapText(const AText: String; lFC: TFPFontCacheItem; const ALineWidth: TFPReportUnits; out AHeight: TFPReportUnits);
|
|
|
|
+
|
|
var
|
|
var
|
|
maxw: single; // value in pixels
|
|
maxw: single; // value in pixels
|
|
n: integer;
|
|
n: integer;
|
|
s: string;
|
|
s: string;
|
|
c: char;
|
|
c: char;
|
|
lWidth: single;
|
|
lWidth: single;
|
|
- lFC: TFPFontCacheItem;
|
|
|
|
|
|
+
|
|
lDescenderHeight: single;
|
|
lDescenderHeight: single;
|
|
lHeight: single;
|
|
lHeight: single;
|
|
|
|
|
|
- // -----------------
|
|
|
|
- { All = True) indicates that if the text is split over multiple lines the last
|
|
|
|
- line must also be processed before continuing. If All = False, then double
|
|
|
|
- CR can be ignored. }
|
|
|
|
- procedure AddLine(all: boolean);
|
|
|
|
- var
|
|
|
|
- w: single;
|
|
|
|
- m: integer;
|
|
|
|
- s2, s3: string;
|
|
|
|
- begin
|
|
|
|
- s2 := s;
|
|
|
|
- w := lFC.TextWidth(s2, Font.Size);
|
|
|
|
- if (Length(s2) > 1) and (w > maxw) then
|
|
|
|
- begin
|
|
|
|
- while w > maxw do
|
|
|
|
- begin
|
|
|
|
- m := Length(s);
|
|
|
|
- repeat
|
|
|
|
- Dec(m);
|
|
|
|
- s2 := Copy(s,1,m);
|
|
|
|
- w := lFC.TextWidth(s2, Font.Size);
|
|
|
|
- until w <= maxw;
|
|
|
|
-
|
|
|
|
- s3 := s2; // we might need the value of s2 later again
|
|
|
|
-
|
|
|
|
- // are we in the middle of a word. If so find the beginning of word.
|
|
|
|
- while (m > 0) and (s2[m] <> ' ') do
|
|
|
|
- Dec(m);
|
|
|
|
- s2 := Copy(s,1,m);
|
|
|
|
-
|
|
|
|
- if s2 = '' then
|
|
|
|
- begin
|
|
|
|
- // Single word does not fit. S3 is max word that fits.
|
|
|
|
- s2 := s3;
|
|
|
|
- Case WordWrapOverflow of
|
|
|
|
- wwoOverflow:
|
|
|
|
- begin
|
|
|
|
- { We reached the beginning of the line without finding a word that fits the maxw.
|
|
|
|
- So we are forced to use a longer than maxw word. We were in the middle of
|
|
|
|
- a word, so now find the end of the current word. }
|
|
|
|
- m := Length(s2);
|
|
|
|
- while (m < Length(s)) and (s[m]<> ' ') do
|
|
|
|
- Inc(m);
|
|
|
|
- s2:=Copy(s,1,m);
|
|
|
|
- end;
|
|
|
|
- wwoTruncate:
|
|
|
|
- m:=Length(S); // Discard the remainder of the word.
|
|
|
|
- wwoSplit:
|
|
|
|
- m:=Length(S3); // S3 was the longest possible part of the word. Split after
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- ALines.Add(s2);
|
|
|
|
- s := Copy(s, m+1, Length(s));
|
|
|
|
- s2 := s;
|
|
|
|
- w := lFC.TextWidth(s2, Font.Size);
|
|
|
|
- end; { while }
|
|
|
|
- if all then
|
|
|
|
- begin
|
|
|
|
- if s2 <> '' then
|
|
|
|
- ALines.Add(s2);
|
|
|
|
- s := '';
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- if s2 <> '' then
|
|
|
|
- ALines.Add(s2);
|
|
|
|
- s := '';
|
|
|
|
- end; { if/else }
|
|
|
|
- end;
|
|
|
|
|
|
|
|
begin
|
|
begin
|
|
if AText = '' then
|
|
if AText = '' then
|
|
@@ -4012,10 +4012,6 @@ begin
|
|
|
|
|
|
if ALineWidth = 0 then
|
|
if ALineWidth = 0 then
|
|
Exit;
|
|
Exit;
|
|
- { We are doing a PostScript Name lookup (it contains Bold, Italic info) }
|
|
|
|
- lFC := gTTFontCache.FindFont(Font.Name);
|
|
|
|
- if not Assigned(lFC) then
|
|
|
|
- raise EReportFontNotFound.CreateFmt(SErrFontNotFound, [Font.Name]);
|
|
|
|
{ result is in pixels }
|
|
{ result is in pixels }
|
|
lWidth := lFC.TextWidth(Text, Font.Size);
|
|
lWidth := lFC.TextWidth(Text, Font.Size);
|
|
lHeight := lFC.TextHeight(Text, Font.Size, lDescenderHeight);
|
|
lHeight := lFC.TextHeight(Text, Font.Size, lDescenderHeight);
|
|
@@ -4023,35 +4019,34 @@ begin
|
|
AHeight := PixelsToMM(lHeight+lDescenderHeight);
|
|
AHeight := PixelsToMM(lHeight+lDescenderHeight);
|
|
|
|
|
|
s := '';
|
|
s := '';
|
|
- ALines.Clear;
|
|
|
|
n := 1;
|
|
n := 1;
|
|
maxw := mmToPixels(ALineWidth - TextAlignment.LeftMargin - TextAlignment.RightMargin);
|
|
maxw := mmToPixels(ALineWidth - TextAlignment.LeftMargin - TextAlignment.RightMargin);
|
|
{ Do we really need to do text wrapping? There must be no linefeed characters and lWidth must be less than maxw. }
|
|
{ Do we really need to do text wrapping? There must be no linefeed characters and lWidth must be less than maxw. }
|
|
if ((Pos(#13, AText) = 0) and (Pos(#10, AText) = 0)) and (lWidth <= maxw) then
|
|
if ((Pos(#13, AText) = 0) and (Pos(#10, AText) = 0)) and (lWidth <= maxw) then
|
|
begin
|
|
begin
|
|
- ALines.Add(AText);
|
|
|
|
|
|
+ FTextLines.Add(AText);
|
|
Exit;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ We got here, so wrapping is needed. First process line wrapping as indicated
|
|
{ We got here, so wrapping is needed. First process line wrapping as indicated
|
|
by LineEnding characters in the text. }
|
|
by LineEnding characters in the text. }
|
|
while n <= Length(AText) do
|
|
while n <= Length(AText) do
|
|
- begin
|
|
|
|
|
|
+ begin
|
|
c := AText[n];
|
|
c := AText[n];
|
|
if (c = #13) or (c = #10) then
|
|
if (c = #13) or (c = #10) then
|
|
begin
|
|
begin
|
|
{ See code comment of AddLine() for the meaning of the True argument. }
|
|
{ See code comment of AddLine() for the meaning of the True argument. }
|
|
- AddLine(true);
|
|
|
|
|
|
+ AddTextLine(lfc,S,maxw);
|
|
if (c = #13) and (n < Length(AText)) and (AText[n+1] = #10) then
|
|
if (c = #13) and (n < Length(AText)) and (AText[n+1] = #10) then
|
|
Inc(n);
|
|
Inc(n);
|
|
end
|
|
end
|
|
else
|
|
else
|
|
s := s + c;
|
|
s := s + c;
|
|
Inc(n);
|
|
Inc(n);
|
|
- end; { while }
|
|
|
|
|
|
+ end; { while }
|
|
|
|
|
|
{ Now wrap lines that are longer than ALineWidth }
|
|
{ Now wrap lines that are longer than ALineWidth }
|
|
- AddLine(true);
|
|
|
|
|
|
+ AddTextLine(lfc,S,maxW);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFPReportElement.ApplyStretchMode(const ADesiredHeight: TFPReportUnits);
|
|
procedure TFPReportElement.ApplyStretchMode(const ADesiredHeight: TFPReportUnits);
|
|
@@ -4896,7 +4891,10 @@ procedure TFPReportCustomMemo.RecalcLayout;
|
|
end;
|
|
end;
|
|
|
|
|
|
var
|
|
var
|
|
- h: TFPReportUnits;
|
|
|
|
|
|
+ h, maxW: TFPReportUnits;
|
|
|
|
+ lFC : TFPFontCacheItem;
|
|
|
|
+ S : String;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
FTextBlockList.Clear;
|
|
FTextBlockList.Clear;
|
|
FCurTextBlock := nil;
|
|
FCurTextBlock := nil;
|
|
@@ -4904,11 +4902,18 @@ begin
|
|
FTextLines := TStringList.Create
|
|
FTextLines := TStringList.Create
|
|
else
|
|
else
|
|
FTextLines.Clear;
|
|
FTextLines.Clear;
|
|
-
|
|
|
|
|
|
+ { We are doing a PostScript Name lookup (it contains Bold, Italic info) }
|
|
|
|
+ lFC := gTTFontCache.FindFont(Font.Name);
|
|
|
|
+ if not Assigned(lFC) then
|
|
|
|
+ raise EReportFontNotFound.CreateFmt(SErrFontNotFound, [Font.Name]);
|
|
if not (moDisableWordWrap in Options) then
|
|
if not (moDisableWordWrap in Options) then
|
|
- WrapText(Text, FTextLines, Layout.Width, h)
|
|
|
|
|
|
+ WrapText(Text, lfc, Layout.Width, h)
|
|
else
|
|
else
|
|
- FTextLines.Add(Text);
|
|
|
|
|
|
+ begin
|
|
|
|
+ maxw := mmToPixels(Layout.Width - TextAlignment.LeftMargin - TextAlignment.RightMargin);
|
|
|
|
+ S:=Text;
|
|
|
|
+ AddTextLine(lfc,S,maxw);
|
|
|
|
+ end;
|
|
|
|
|
|
if StretchMode <> smDontStretch then
|
|
if StretchMode <> smDontStretch then
|
|
ApplyStretchMode(CalcNeededHeight(h));
|
|
ApplyStretchMode(CalcNeededHeight(h));
|
|
@@ -5132,7 +5137,7 @@ begin
|
|
TextAlignment.Assign(E.TextAlignment);
|
|
TextAlignment.Assign(E.TextAlignment);
|
|
Options := E.Options;
|
|
Options := E.Options;
|
|
Original := E;
|
|
Original := E;
|
|
- WordWrapOverflow:= E.WordWrapOverflow;
|
|
|
|
|
|
+ WordOverflow:= E.WordOverflow;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|