LazReport, implements Justified Alignment, issue #23796

git-svn-id: trunk@40397 -
This commit is contained in:
jesus 2013-02-24 19:44:59 +00:00
parent b0299832bb
commit 73faf28aaf
2 changed files with 179 additions and 15 deletions

View File

@ -373,6 +373,7 @@ type
function GetHideDuplicates: Boolean;
function GetHideZeroValues: Boolean;
function GetIsLastValueSet: boolean;
function GetJustify: boolean;
function GetLayout: TTextLayout;
function GetWordBreak: Boolean;
function GetWordWrap: Boolean;
@ -389,6 +390,7 @@ type
procedure SetHideDuplicates(const AValue: Boolean);
procedure SetHideZeroValues(AValue: Boolean);
procedure SetIsLastValueSet(const AValue: boolean);
procedure SetJustify(AValue: boolean);
procedure SetLayout(const AValue: TTextLayout);
procedure SetWordBreak(AValue: Boolean);
procedure SetWordWrap(const AValue: Boolean);
@ -431,6 +433,7 @@ type
procedure DefinePopupMenu(Popup: TPopupMenu); override;
procedure MonitorFontChanges;
property Justify: boolean read GetJustify write SetJustify;
published
property Font : TFont read fFont write SetFont;
@ -1749,6 +1752,88 @@ begin
result := copy(result, 3, Length(result));
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 }
procedure TfrReportDesigner.SetModified(AValue: Boolean);
@ -2697,6 +2782,14 @@ begin
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);
begin
if Layout<>AValue then
@ -3073,6 +3166,7 @@ var
n, {nw, w, }curx, lasty: Integer;
lastyf: Double;
Ts: TTextStyle;
ParaEnd: boolean;
begin
lastyf := curyf + thf - LineSpc - 1;
lastY := Round(lastyf);
@ -3085,11 +3179,14 @@ var
begin
n := Length(St);
//w := Ord(St[n - 1]) * 256 + Ord(St[n]);
ParaEnd := true;
SetLength(St, n - 2);
if Length(St) > 0 then
begin
if St[Length(St)] = #1 then
SetLength(St, Length(St) - 1);
SetLength(St, Length(St) - 1)
else
ParaEnd := false;
end;
// handle any alignment with same code
@ -3128,7 +3225,12 @@ var
end;
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
CurReport.InternalOnExportText(X, round(curYf), St, Self);
@ -3575,8 +3677,7 @@ procedure TfrMemoView.LoadFromStream(Stream: TStream);
var
w: Word;
i: Integer;
TmpAlign: TAlignment;
TmpLayout: TTextLayout;
tmpLayout: TTextLayout;
tmpAngle: Byte;
begin
{$IFDEF DebugLR}
@ -3606,13 +3707,13 @@ begin
end;
if frVersion>23 then
begin
Read(TmpAlign{%H-},SizeOf(TmpAlign));
Read(tmpAngle, SizeOf(tmpAngle));
Adjust := (Adjust and not 3) or (tmpAngle and %11);
Read(TmpLayout{%H-},SizeOf(TmpLayout));
tmpAngle := 0;
Read(tmpAngle,SizeOf(tmpAngle));
BeginUpdate;
Alignment := tmpAlign;
Layout := tmpLayout;
Angle := tmpAngle;
EndUpdate;
@ -3643,15 +3744,16 @@ begin
RestoreProperty('Alignment',XML.GetValue(Path+'Alignment/Value',''));
RestoreProperty('Layout',XML.GetValue(Path+'Layout/Value',''));
Angle := XML.GetValue(Path+'Angle/Value'{%H-}, 0);
Justify := XML.GetValue(Path+'Justify/Value', false);
end;
procedure TfrMemoView.SaveToStream(Stream: TStream);
var
i: Integer;
w: Word;
tmpAlign: TAlignment;
tmpLayout: TTextLayout;
tmpAngle: Byte;
tmpByteAlign: Byte;
begin
inherited SaveToStream(Stream);
frWriteString(Stream, Font.Name);
@ -3670,14 +3772,11 @@ begin
Write(Highlight, 10);
frWriteString(Stream, HighlightStr);
end;
if (Adjust and %11 = %11) then
tmpAlign := taLeftJustify
else
tmpAlign := Alignment;
tmpByteAlign := Adjust and %11;
tmpLayout := Layout;
tmpAngle := Angle;
Write(tmpAlign,SizeOf(tmpAlign));
Write(tmpByteAlign, SizeOf(tmpByteAlign));
Write(tmpLayout,SizeOf(tmpLayout));
Write(tmpAngle,SizeOf(tmpAngle));
end;
@ -3702,6 +3801,7 @@ begin
XML.SetValue(Path+'Alignment/Value',GetSaveProperty('Alignment'));
XML.SetValue(Path+'Layout/Value', GetSaveProperty('Layout'));
XML.SetValue(Path+'Angle/Value'{%H-}, Angle);
XML.SetValue(Path+'Justify/Value', Justify);
end;
procedure TfrMemoView.GetBlob(b: TfrTField);
@ -3832,6 +3932,11 @@ begin
result := FLastValue<>nil;
end;
function TfrMemoView.GetJustify: boolean;
begin
result := (Adjust and %11) = %11;
end;
function TfrMemoView.GetLayout: TTextLayout;
begin
result := TTextLayout((adjust shr 3) and %11);
@ -3844,7 +3949,10 @@ end;
function TfrMemoView.GetAlignment: TAlignment;
begin
Result:=Classes.TAlignment(Adjust and %11);
if (Adjust and %11) = %11 then
result := taLeftJustify
else
Result:=Classes.TAlignment(Adjust and %11);
end;
function TfrMemoView.GetAngle: Byte;
@ -3915,11 +4023,16 @@ begin
end;
procedure TfrMemoView.SetAlignment(const AValue: TAlignment);
var
b: byte;
begin
if Alignment<>AValue then
begin
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;
end;
end;

View File

@ -22,6 +22,17 @@ uses
{$ENDIF}
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 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 UTF8QuotedStr(s:string; Quote: TUTF8Char; desc:string=''): string;
function PosLast(SubChr:char; const Source:string):integer;
function UTF8CountWords(const str:string; out WordCount,SpcCount,SpcSize:Integer): TArrUTF8Item;
implementation
@ -814,4 +826,43 @@ begin
Result:=-1;
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.