mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-19 00:19:26 +02:00
LazReport, implements Justified Alignment, issue #23796
git-svn-id: trunk@40397 -
This commit is contained in:
parent
b0299832bb
commit
73faf28aaf
@ -373,6 +373,7 @@ type
|
|||||||
function GetHideDuplicates: Boolean;
|
function GetHideDuplicates: Boolean;
|
||||||
function GetHideZeroValues: Boolean;
|
function GetHideZeroValues: Boolean;
|
||||||
function GetIsLastValueSet: boolean;
|
function GetIsLastValueSet: boolean;
|
||||||
|
function GetJustify: boolean;
|
||||||
function GetLayout: TTextLayout;
|
function GetLayout: TTextLayout;
|
||||||
function GetWordBreak: Boolean;
|
function GetWordBreak: Boolean;
|
||||||
function GetWordWrap: Boolean;
|
function GetWordWrap: Boolean;
|
||||||
@ -389,6 +390,7 @@ type
|
|||||||
procedure SetHideDuplicates(const AValue: Boolean);
|
procedure SetHideDuplicates(const AValue: Boolean);
|
||||||
procedure SetHideZeroValues(AValue: Boolean);
|
procedure SetHideZeroValues(AValue: Boolean);
|
||||||
procedure SetIsLastValueSet(const AValue: boolean);
|
procedure SetIsLastValueSet(const AValue: boolean);
|
||||||
|
procedure SetJustify(AValue: boolean);
|
||||||
procedure SetLayout(const AValue: TTextLayout);
|
procedure SetLayout(const AValue: TTextLayout);
|
||||||
procedure SetWordBreak(AValue: Boolean);
|
procedure SetWordBreak(AValue: Boolean);
|
||||||
procedure SetWordWrap(const AValue: Boolean);
|
procedure SetWordWrap(const AValue: Boolean);
|
||||||
@ -431,6 +433,7 @@ type
|
|||||||
procedure DefinePopupMenu(Popup: TPopupMenu); override;
|
procedure DefinePopupMenu(Popup: TPopupMenu); override;
|
||||||
|
|
||||||
procedure MonitorFontChanges;
|
procedure MonitorFontChanges;
|
||||||
|
property Justify: boolean read GetJustify write SetJustify;
|
||||||
|
|
||||||
published
|
published
|
||||||
property Font : TFont read fFont write SetFont;
|
property Font : TFont read fFont write SetFont;
|
||||||
@ -1749,6 +1752,88 @@ begin
|
|||||||
result := copy(result, 3, Length(result));
|
result := copy(result, 3, Length(result));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure CanvasTextRectJustify(const Canvas:TCanvas;
|
||||||
|
const ARect: TRect; X1, X2, Y: integer; const Text: string;
|
||||||
|
Trimmed: boolean);
|
||||||
|
var
|
||||||
|
WordCount,SpcCount,SpcSize:Integer;
|
||||||
|
Arr: TArrUTF8Item;
|
||||||
|
PxSpc,RxSpc,Extra: Integer;
|
||||||
|
i: Integer;
|
||||||
|
Cini,Cend: Integer;
|
||||||
|
SpaceWidth, AvailWidth: Integer;
|
||||||
|
s:string;
|
||||||
|
begin
|
||||||
|
|
||||||
|
AvailWidth := (X2-X1);
|
||||||
|
// count words
|
||||||
|
Arr := UTF8CountWords(Text, WordCount, SpcCount, SpcSize);
|
||||||
|
|
||||||
|
// handle trimmed text
|
||||||
|
s := Text;
|
||||||
|
if (SpcCount>0) then
|
||||||
|
begin
|
||||||
|
Cini := 0;
|
||||||
|
CEnd := Length(Arr)-1;
|
||||||
|
if Trimmed then
|
||||||
|
begin
|
||||||
|
s := Trim(Text);
|
||||||
|
if Arr[Cini].Space then
|
||||||
|
begin
|
||||||
|
Inc(Cini);
|
||||||
|
Dec(SpcCount);
|
||||||
|
end;
|
||||||
|
if Arr[CEnd].Space then
|
||||||
|
begin
|
||||||
|
Dec(CEnd);
|
||||||
|
Dec(SpcCount);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
AvailWidth := AvailWidth - Canvas.TextWidth(s);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// check if long way is needed
|
||||||
|
if (SpcCount>0) and (AvailWidth>0) then
|
||||||
|
begin
|
||||||
|
|
||||||
|
SpaceWidth := Canvas.TextWidth(' ');
|
||||||
|
PxSpc := AvailWidth div SpcCount;
|
||||||
|
RxSpc := AvailWidth mod SpcCount;
|
||||||
|
if PxSPC=0 then
|
||||||
|
begin
|
||||||
|
PxSPC := 1;
|
||||||
|
RxSpc := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
for i:=CIni to CEnd do
|
||||||
|
if Arr[i].Space then
|
||||||
|
begin
|
||||||
|
X1 := X1 + Arr[i].Count * SpaceWidth;
|
||||||
|
if AvailWidth>0 then
|
||||||
|
begin
|
||||||
|
Extra := PxSpc;
|
||||||
|
if RxSpc>0 then
|
||||||
|
begin
|
||||||
|
Inc(Extra);
|
||||||
|
Dec(RxSpc);
|
||||||
|
end;
|
||||||
|
X1 := X1 + Extra;
|
||||||
|
Dec(AvailWidth, Extra);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
s := Copy(Text, Arr[i].Index, Arr[i].Count);
|
||||||
|
Canvas.TextRect(ARect, X1, Y, s);
|
||||||
|
X1 := X1 + Canvas.TextWidth(s);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end else
|
||||||
|
Canvas.TextRect(ARect, X1, Y, s);
|
||||||
|
|
||||||
|
SetLength(Arr, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TfrReportDesigner }
|
{ TfrReportDesigner }
|
||||||
|
|
||||||
procedure TfrReportDesigner.SetModified(AValue: Boolean);
|
procedure TfrReportDesigner.SetModified(AValue: Boolean);
|
||||||
@ -2697,6 +2782,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TfrMemoView.SetJustify(AValue: boolean);
|
||||||
|
begin
|
||||||
|
// only if AValue=true change Adjust to reflect justify
|
||||||
|
// otherwise let it alone, so previous value of alignment is respected
|
||||||
|
if Avalue then
|
||||||
|
Adjust := Adjust or %11;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TfrMemoView.SetLayout(const AValue: TTextLayout);
|
procedure TfrMemoView.SetLayout(const AValue: TTextLayout);
|
||||||
begin
|
begin
|
||||||
if Layout<>AValue then
|
if Layout<>AValue then
|
||||||
@ -3073,6 +3166,7 @@ var
|
|||||||
n, {nw, w, }curx, lasty: Integer;
|
n, {nw, w, }curx, lasty: Integer;
|
||||||
lastyf: Double;
|
lastyf: Double;
|
||||||
Ts: TTextStyle;
|
Ts: TTextStyle;
|
||||||
|
ParaEnd: boolean;
|
||||||
begin
|
begin
|
||||||
lastyf := curyf + thf - LineSpc - 1;
|
lastyf := curyf + thf - LineSpc - 1;
|
||||||
lastY := Round(lastyf);
|
lastY := Round(lastyf);
|
||||||
@ -3085,11 +3179,14 @@ var
|
|||||||
begin
|
begin
|
||||||
n := Length(St);
|
n := Length(St);
|
||||||
//w := Ord(St[n - 1]) * 256 + Ord(St[n]);
|
//w := Ord(St[n - 1]) * 256 + Ord(St[n]);
|
||||||
|
ParaEnd := true;
|
||||||
SetLength(St, n - 2);
|
SetLength(St, n - 2);
|
||||||
if Length(St) > 0 then
|
if Length(St) > 0 then
|
||||||
begin
|
begin
|
||||||
if St[Length(St)] = #1 then
|
if St[Length(St)] = #1 then
|
||||||
SetLength(St, Length(St) - 1);
|
SetLength(St, Length(St) - 1)
|
||||||
|
else
|
||||||
|
ParaEnd := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// handle any alignment with same code
|
// handle any alignment with same code
|
||||||
@ -3128,7 +3225,12 @@ var
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if not Exporting then
|
if not Exporting then
|
||||||
Canvas.TextRect(DR, CurX, round(curYf), St)
|
begin
|
||||||
|
if Justify and not ParaEnd then
|
||||||
|
CanvasTextRectJustify(Canvas, DR, x+gapx, x+dx-1-gapx, round(CurYf), St, true)
|
||||||
|
else
|
||||||
|
Canvas.TextRect(DR, CurX, round(curYf), St);
|
||||||
|
end
|
||||||
else
|
else
|
||||||
CurReport.InternalOnExportText(X, round(curYf), St, Self);
|
CurReport.InternalOnExportText(X, round(curYf), St, Self);
|
||||||
|
|
||||||
@ -3575,8 +3677,7 @@ procedure TfrMemoView.LoadFromStream(Stream: TStream);
|
|||||||
var
|
var
|
||||||
w: Word;
|
w: Word;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
TmpAlign: TAlignment;
|
tmpLayout: TTextLayout;
|
||||||
TmpLayout: TTextLayout;
|
|
||||||
tmpAngle: Byte;
|
tmpAngle: Byte;
|
||||||
begin
|
begin
|
||||||
{$IFDEF DebugLR}
|
{$IFDEF DebugLR}
|
||||||
@ -3606,13 +3707,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
if frVersion>23 then
|
if frVersion>23 then
|
||||||
begin
|
begin
|
||||||
Read(TmpAlign{%H-},SizeOf(TmpAlign));
|
Read(tmpAngle, SizeOf(tmpAngle));
|
||||||
|
Adjust := (Adjust and not 3) or (tmpAngle and %11);
|
||||||
Read(TmpLayout{%H-},SizeOf(TmpLayout));
|
Read(TmpLayout{%H-},SizeOf(TmpLayout));
|
||||||
tmpAngle := 0;
|
tmpAngle := 0;
|
||||||
Read(tmpAngle,SizeOf(tmpAngle));
|
Read(tmpAngle,SizeOf(tmpAngle));
|
||||||
|
|
||||||
BeginUpdate;
|
BeginUpdate;
|
||||||
Alignment := tmpAlign;
|
|
||||||
Layout := tmpLayout;
|
Layout := tmpLayout;
|
||||||
Angle := tmpAngle;
|
Angle := tmpAngle;
|
||||||
EndUpdate;
|
EndUpdate;
|
||||||
@ -3643,15 +3744,16 @@ begin
|
|||||||
RestoreProperty('Alignment',XML.GetValue(Path+'Alignment/Value',''));
|
RestoreProperty('Alignment',XML.GetValue(Path+'Alignment/Value',''));
|
||||||
RestoreProperty('Layout',XML.GetValue(Path+'Layout/Value',''));
|
RestoreProperty('Layout',XML.GetValue(Path+'Layout/Value',''));
|
||||||
Angle := XML.GetValue(Path+'Angle/Value'{%H-}, 0);
|
Angle := XML.GetValue(Path+'Angle/Value'{%H-}, 0);
|
||||||
|
Justify := XML.GetValue(Path+'Justify/Value', false);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TfrMemoView.SaveToStream(Stream: TStream);
|
procedure TfrMemoView.SaveToStream(Stream: TStream);
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
w: Word;
|
w: Word;
|
||||||
tmpAlign: TAlignment;
|
|
||||||
tmpLayout: TTextLayout;
|
tmpLayout: TTextLayout;
|
||||||
tmpAngle: Byte;
|
tmpAngle: Byte;
|
||||||
|
tmpByteAlign: Byte;
|
||||||
begin
|
begin
|
||||||
inherited SaveToStream(Stream);
|
inherited SaveToStream(Stream);
|
||||||
frWriteString(Stream, Font.Name);
|
frWriteString(Stream, Font.Name);
|
||||||
@ -3670,14 +3772,11 @@ begin
|
|||||||
Write(Highlight, 10);
|
Write(Highlight, 10);
|
||||||
frWriteString(Stream, HighlightStr);
|
frWriteString(Stream, HighlightStr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if (Adjust and %11 = %11) then
|
tmpByteAlign := Adjust and %11;
|
||||||
tmpAlign := taLeftJustify
|
|
||||||
else
|
|
||||||
tmpAlign := Alignment;
|
|
||||||
tmpLayout := Layout;
|
tmpLayout := Layout;
|
||||||
tmpAngle := Angle;
|
tmpAngle := Angle;
|
||||||
Write(tmpAlign,SizeOf(tmpAlign));
|
Write(tmpByteAlign, SizeOf(tmpByteAlign));
|
||||||
Write(tmpLayout,SizeOf(tmpLayout));
|
Write(tmpLayout,SizeOf(tmpLayout));
|
||||||
Write(tmpAngle,SizeOf(tmpAngle));
|
Write(tmpAngle,SizeOf(tmpAngle));
|
||||||
end;
|
end;
|
||||||
@ -3702,6 +3801,7 @@ begin
|
|||||||
XML.SetValue(Path+'Alignment/Value',GetSaveProperty('Alignment'));
|
XML.SetValue(Path+'Alignment/Value',GetSaveProperty('Alignment'));
|
||||||
XML.SetValue(Path+'Layout/Value', GetSaveProperty('Layout'));
|
XML.SetValue(Path+'Layout/Value', GetSaveProperty('Layout'));
|
||||||
XML.SetValue(Path+'Angle/Value'{%H-}, Angle);
|
XML.SetValue(Path+'Angle/Value'{%H-}, Angle);
|
||||||
|
XML.SetValue(Path+'Justify/Value', Justify);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TfrMemoView.GetBlob(b: TfrTField);
|
procedure TfrMemoView.GetBlob(b: TfrTField);
|
||||||
@ -3832,6 +3932,11 @@ begin
|
|||||||
result := FLastValue<>nil;
|
result := FLastValue<>nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TfrMemoView.GetJustify: boolean;
|
||||||
|
begin
|
||||||
|
result := (Adjust and %11) = %11;
|
||||||
|
end;
|
||||||
|
|
||||||
function TfrMemoView.GetLayout: TTextLayout;
|
function TfrMemoView.GetLayout: TTextLayout;
|
||||||
begin
|
begin
|
||||||
result := TTextLayout((adjust shr 3) and %11);
|
result := TTextLayout((adjust shr 3) and %11);
|
||||||
@ -3844,7 +3949,10 @@ end;
|
|||||||
|
|
||||||
function TfrMemoView.GetAlignment: TAlignment;
|
function TfrMemoView.GetAlignment: TAlignment;
|
||||||
begin
|
begin
|
||||||
Result:=Classes.TAlignment(Adjust and %11);
|
if (Adjust and %11) = %11 then
|
||||||
|
result := taLeftJustify
|
||||||
|
else
|
||||||
|
Result:=Classes.TAlignment(Adjust and %11);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TfrMemoView.GetAngle: Byte;
|
function TfrMemoView.GetAngle: Byte;
|
||||||
@ -3915,11 +4023,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TfrMemoView.SetAlignment(const AValue: TAlignment);
|
procedure TfrMemoView.SetAlignment(const AValue: TAlignment);
|
||||||
|
var
|
||||||
|
b: byte;
|
||||||
begin
|
begin
|
||||||
if Alignment<>AValue then
|
if Alignment<>AValue then
|
||||||
begin
|
begin
|
||||||
BeforeChange;
|
BeforeChange;
|
||||||
Adjust := (Adjust and not 3) or ord(AValue);
|
// just in case, check for crazy value stored by alignment=justify
|
||||||
|
// in previous versions.
|
||||||
|
b := byte(AValue) and %11;
|
||||||
|
Adjust := (Adjust and not 3) or b;
|
||||||
AfterChange;
|
AfterChange;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -22,6 +22,17 @@ uses
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
LCLType,LCLIntf,LCLProc,LConvEncoding;
|
LCLType,LCLIntf,LCLProc,LConvEncoding;
|
||||||
|
|
||||||
|
type
|
||||||
|
TUTF8Item=packed record
|
||||||
|
Index: Integer;
|
||||||
|
UTF8Index: Integer;
|
||||||
|
Count: byte;
|
||||||
|
UTF8Count: byte;
|
||||||
|
Space: boolean;
|
||||||
|
end;
|
||||||
|
TArrUTF8Item=array of TUTF8Item;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
procedure frReadMemo(Stream: TStream; l: TStrings);
|
procedure frReadMemo(Stream: TStream; l: TStrings);
|
||||||
procedure frReadMemo22(Stream: TStream; l: TStrings);
|
procedure frReadMemo22(Stream: TStream; l: TStrings);
|
||||||
@ -64,6 +75,7 @@ function UTF8Index(index:integer; desc:string): Integer;
|
|||||||
function UTF8CharIn(ch:TUTF8Char; const arrstr:array of string): boolean;
|
function UTF8CharIn(ch:TUTF8Char; const arrstr:array of string): boolean;
|
||||||
function UTF8QuotedStr(s:string; Quote: TUTF8Char; desc:string=''): string;
|
function UTF8QuotedStr(s:string; Quote: TUTF8Char; desc:string=''): string;
|
||||||
function PosLast(SubChr:char; const Source:string):integer;
|
function PosLast(SubChr:char; const Source:string):integer;
|
||||||
|
function UTF8CountWords(const str:string; out WordCount,SpcCount,SpcSize:Integer): TArrUTF8Item;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -814,4 +826,43 @@ begin
|
|||||||
Result:=-1;
|
Result:=-1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function UTF8CountWords(const str:string; out WordCount,SpcCount,SpcSize:Integer): TArrUTF8Item;
|
||||||
|
var
|
||||||
|
b,i,j,n,len: Integer;
|
||||||
|
spc: boolean;
|
||||||
|
begin
|
||||||
|
i := 1;
|
||||||
|
len := 0;
|
||||||
|
SetLength(result, 0);
|
||||||
|
WordCount := 0;
|
||||||
|
SpcCount := 0;
|
||||||
|
SpcSize := 0;
|
||||||
|
while i<=Length(str) do
|
||||||
|
begin
|
||||||
|
b := UTF8CharacterStrictLength(@Str[i]);
|
||||||
|
spc := (b=1) and (str[i]=' ');
|
||||||
|
inc(len);
|
||||||
|
j := Length(result)-1;
|
||||||
|
if (j<0) or (result[j].Space<>Spc) then
|
||||||
|
begin
|
||||||
|
inc(j);
|
||||||
|
SetLength(result, j+1);
|
||||||
|
result[j].Count:=0;
|
||||||
|
result[j].UTF8Count:=0;
|
||||||
|
result[j].Index:=i;
|
||||||
|
result[j].UTF8Index:=len;
|
||||||
|
if not spc then
|
||||||
|
Inc(WordCount)
|
||||||
|
else
|
||||||
|
Inc(SpcCount);
|
||||||
|
end;
|
||||||
|
result[j].Space := Spc;
|
||||||
|
result[j].UTF8Count := result[j].UTF8Count + 1;
|
||||||
|
result[j].Count := result[j].Count + b;
|
||||||
|
inc(i,b);
|
||||||
|
if Spc then
|
||||||
|
Inc(SpcSize);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
Loading…
Reference in New Issue
Block a user