LCL: Refactor ChildSizing. Fix constraint handling.

This commit is contained in:
Martin 2024-03-23 22:40:45 +01:00
parent db6ed214b9
commit 22881f66db

View File

@ -84,6 +84,7 @@ type
Control: TControl; // the Control of a leaf node Control: TControl; // the Control of a leaf node
MinimumSize: array[TAutoSizeBoxOrientation] of integer; MinimumSize: array[TAutoSizeBoxOrientation] of integer;
MaximumSize: array[TAutoSizeBoxOrientation] of integer; // 0 means inifinte MaximumSize: array[TAutoSizeBoxOrientation] of integer; // 0 means inifinte
LimitedSize: array[TAutoSizeBoxOrientation] of boolean; // Was force set by Max or Min
PreferredSize: array[TAutoSizeBoxOrientation] of integer;// without theme space PreferredSize: array[TAutoSizeBoxOrientation] of integer;// without theme space
LeftTop: array[TAutoSizeBoxOrientation] of integer; LeftTop: array[TAutoSizeBoxOrientation] of integer;
BorderLeftTop: array[TAutoSizeBoxOrientation] of integer; BorderLeftTop: array[TAutoSizeBoxOrientation] of integer;
@ -1767,7 +1768,7 @@ type
var var
EnlargeStyle: TChildControlResizeStyle; EnlargeStyle: TChildControlResizeStyle;
ShrinkStyle: TChildControlResizeStyle; ShrinkStyle: TChildControlResizeStyle;
CurSize: LongInt; CurSize, CurSpacing, CurrentMinimumSizeSum: LongInt;
function GetChildTotalSize: integer; function GetChildTotalSize: integer;
// computes the total preferred size of all children of this Orientation // computes the total preferred size of all children of this Orientation
@ -1777,10 +1778,14 @@ var
s: LongInt; s: LongInt;
begin begin
Result:=0; Result:=0;
CurSpacing := 0;
CurrentMinimumSizeSum := 0;
for i:=0 to ChildCount[Orientation]-1 do begin for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i]; Child:=Children[Orientation][i];
if i=0 then if i=0 then begin
inc(Result,Child.BorderLeftTop[Orientation]); inc(Result,Child.BorderLeftTop[Orientation]);
inc(CurSpacing,Child.BorderLeftTop[Orientation]);
end;
if Child.PreferredSize[Orientation]<1 then if Child.PreferredSize[Orientation]<1 then
Child.PreferredSize[Orientation]:=1; Child.PreferredSize[Orientation]:=1;
inc(Result,Child.PreferredSize[Orientation]); inc(Result,Child.PreferredSize[Orientation]);
@ -1788,451 +1793,414 @@ var
if i<ChildCount[Orientation]-1 then if i<ChildCount[Orientation]-1 then
s:=Max(s,Children[Orientation][i+1].BorderLeftTop[Orientation]); s:=Max(s,Children[Orientation][i+1].BorderLeftTop[Orientation]);
inc(Result,s); inc(Result,s);
inc(CurSpacing,s);
inc(CurrentMinimumSizeSum,Child.MinimumSize[Orientation]);
end; end;
end; end;
procedure GetChildMaxResize(out Factor: TResizeFactor; procedure SimplifySpacing;
out ResizeableCount, ResizableSize: integer); var
// returns the number of children/gaps, that can grow (ResizeableCount) i: Integer;
// and the maximum factor, by which the children/gaps can grow (TResizeFactor) begin
for i:=0 to ChildCount[Orientation]-2 do begin
Children[Orientation][i].BorderRightBottom[Orientation]:=Max(
Children[Orientation][i].BorderRightBottom[Orientation],
Children[Orientation][i+1].BorderLeftTop[Orientation]
);
Children[Orientation][i+1].BorderLeftTop[Orientation]:=0;
end;
end;
procedure EnlargeChilds;
var var
i: Integer; i: Integer;
CurScale: Double;
CurOffset: LongInt;
Child: TAutoSizeBox; Child: TAutoSizeBox;
RemainingTargetSize, RemainingCurSize, NonResizeableCount: Integer;
ScaleChanged: Boolean;
CurScale, CurOffset: Double;
NewSizeEx, NewSizeCarry: Double;
NewSize, OldSize, DiffSize: Integer;
begin begin
Factor.Scale:=0;
Factor.Offset:=0;
ResizeableCount:=0;
ResizableSize:=TargetSize;
case EnlargeStyle of case EnlargeStyle of
crsScaleChilds, crsHomogenousChildResize, crsSameSize:
begin
RemainingTargetSize := Max(0, TargetSize-CurSpacing);
RemainingCurSize := Max(0, CurSize-CurSpacing);
NonResizeableCount := 0;
crsAnchorAligning: if EnlargeStyle = crsSameSize then begin
exit; // no resizing (* First check for any cells forced bigger by there MinSize
This only happens for crsSameSize (because even if the total
crsScaleChilds,crsHomogenousChildResize: area grows, individual cells may shrink, if there
PreferredSize is above the average)
If they take extra space, then other cells that would have hit
there MaxSize, may stay below it.
In the "MaxSize Loop" the scale will only grow, so no further
MinSize hits can happen there.
*)
if ChildCount[Orientation] > NonResizeableCount then
NewSize := RemainingTargetSize div (ChildCount[Orientation] - NonResizeableCount);
repeat
ScaleChanged:=False;
for i:=0 to ChildCount[Orientation]-1 do begin for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i]; Child:=Children[Orientation][i];
if (Child.MaximumSize[Orientation]>0) if Child.LimitedSize[Orientation] then
and (Child.PreferredSize[Orientation]>=Child.MaximumSize[Orientation])
then begin
// this child can not be further enlarged
continue; continue;
end;
inc(ResizeableCount);
case EnlargeStyle of if (NewSize<=Child.MinimumSize[Orientation])
crsScaleChilds, crsHomogenousChildResize:
begin
if Child.MaximumSize[Orientation]=0 then begin
CurScale:=double(TargetSize);
CurOffset:=TargetSize;
end else begin
CurScale:=double(Child.MaximumSize[Orientation])
/Child.PreferredSize[Orientation];
CurOffset:=Child.MaximumSize[Orientation]
-Child.PreferredSize[Orientation];
end;
if (Factor.Offset=0) or (Factor.Offset>CurOffset) then begin
Factor.Scale:=CurScale;
Factor.Offset:=CurOffset;
end;
end;
end;
end;
crsSameSize:
begin
Factor.Offset:=1; // prevent abort
if ChildCount[Orientation] > 0 then
CurOffset := TargetSize div ChildCount[Orientation];
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if (Child.MaximumSize[Orientation]>0)
and (CurOffset>=Child.MaximumSize[Orientation])
then begin
// this childs size will be set to its MaximumSize
ResizableSize:=ResizableSize - Child.MaximumSize[Orientation];
continue;
end;
if (CurOffset<=Child.MinimumSize[Orientation])
then begin then begin
// this childs size will be set to its MinimumSize // this childs size will be set to its MinimumSize
ResizableSize:=ResizableSize - Child.MinimumSize[Orientation]; RemainingTargetSize:=RemainingTargetSize - Child.MinimumSize[Orientation];
continue; RemainingCurSize:=RemainingCurSize - Child.PreferredSize[Orientation];
end; Child.PreferredSize[Orientation]:=Child.MinimumSize[Orientation];
inc(ResizeableCount); Child.LimitedSize[Orientation] := True;
end; inc(NonResizeableCount);
end; OldSize := NewSize;
if ChildCount[Orientation] > NonResizeableCount then
crsHomogenousSpaceResize: NewSize := RemainingTargetSize div (ChildCount[Orientation] - NonResizeableCount)
if ChildCount[Orientation]>0 then begin
Factor.Scale:=double(TargetSize);
Factor.Offset:=TargetSize;
ResizeableCount:=ChildCount[Orientation]+1;
end;
else else
raise Exception.Create('TAutoSizeBox.ResizeChilds'); break;
ScaleChanged := OldSize <> NewSize;
if ScaleChanged then
break; // for i :=
end; end;
end; end;
until (not ScaleChanged) or (RemainingCurSize<=0);
procedure EnlargeChilds(const Factor: TResizeFactor; ResizeableCount, ResizableSize: integer); if RemainingCurSize<=0 then
var exit;
i: Integer;
Child: TAutoSizeBox;
DiffSize: Integer;
NewSize: LongInt;
OldSize: LongInt;
begin
for i:=0 to ChildCount[Orientation]-1 do begin
if (TargetSize=CurSize) and (EnlargeStyle<>crsSameSize) then break;
Child:=Children[Orientation][i];
if (EnlargeStyle<>crsSameSize)
and (Child.MaximumSize[Orientation]<0)
and (Child.PreferredSize[Orientation]>=Child.MaximumSize[Orientation])
then begin
// this child can not be further enlarged
continue;
end; end;
repeat
ScaleChanged:=False;
case EnlargeStyle of case EnlargeStyle of
crsScaleChilds: begin
CurScale := double(RemainingTargetSize)/double(RemainingCurSize);
CurOffset := 0;
end;
crsHomogenousChildResize: begin
if ChildCount[Orientation] > NonResizeableCount then
CurOffset := double(RemainingTargetSize - RemainingCurSize) / (ChildCount[Orientation] - NonResizeableCount);
CurScale := 1;
end;
crsSameSize: begin
if ChildCount[Orientation] > NonResizeableCount then
CurOffset := double(RemainingTargetSize) / (ChildCount[Orientation] - NonResizeableCount);
CurScale := 0;
end;
end;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] or (Child.MaximumSize[Orientation]=0) then
continue;
NewSize:=Round(double(Child.PreferredSize[Orientation])*CurScale+CurOffset);
if (Child.MaximumSize[Orientation]>0)
and (NewSize>=Child.MaximumSize[Orientation])
then begin
// this childs size will be set to its MaximumSize
RemainingTargetSize:=RemainingTargetSize - Child.MaximumSize[Orientation];
RemainingCurSize:=RemainingCurSize - Child.PreferredSize[Orientation];
Child.PreferredSize[Orientation]:=Child.MaximumSize[Orientation];
Child.LimitedSize[Orientation] := True;
inc(NonResizeableCount);
ScaleChanged := True;
break; // for i :=
end;
end;
until (not ScaleChanged) or (RemainingCurSize<=0);
if RemainingCurSize<=0 then
exit;
DiffSize := RemainingTargetSize - RemainingCurSize;
NewSizeCarry := 0;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
continue;
crsScaleChilds:
begin
// scale PreferredSize
DiffSize:=TargetSize-CurSize;
OldSize:=Child.PreferredSize[Orientation]; OldSize:=Child.PreferredSize[Orientation];
NewSize:=round(double(OldSize)*Factor.Scale); NewSizeEx:=double(OldSize)*CurScale+CurOffset+NewSizeCarry;
NewSize:=Min(OldSize+DiffSize,Max(OldSize+1,NewSize)); NewSize:=Round(NewSizeEx);
inc(CurSize,NewSize-OldSize); if NewSize >= 1 then NewSizeCarry:=NewSizeEx - NewSize
else NewSizeCarry:=0;
if i = ChildCount[Orientation] - 1 then
NewSize:=OldSize+DiffSize
else
if (EnlargeStyle = crsSameSize) then
NewSize:=Max(1,NewSize)
else
NewSize:=Min(OldSize+DiffSize, Max(1,NewSize));
assert((Child.MaximumSize[Orientation]=0) or (NewSize<=Child.MaximumSize[Orientation]), 'EnlargeChilds: (Child.MaximumSize[Orientation]=0) or (NewSize<=Child.MaximumSize[Orientation])');
assert((NewSize>=Child.MinimumSize[Orientation]), 'EnlargeChilds: (NewSize>=Child.MinimumSize[Orientation])');
dec(DiffSize,NewSize-OldSize);
Child.PreferredSize[Orientation]:=NewSize; Child.PreferredSize[Orientation]:=NewSize;
end; end;
assert(DiffSize = 0, 'EnlargeChilds: DiffSize = 0');
crsHomogenousChildResize:
begin
// add to PreferredSize
DiffSize:=TargetSize-CurSize;
OldSize:=Child.PreferredSize[Orientation];
NewSize:=Min(OldSize+Factor.Offset,OldSize+DiffSize);
inc(CurSize,NewSize-OldSize);
Child.PreferredSize[Orientation]:=NewSize;
end; end;
crsHomogenousSpaceResize: crsHomogenousSpaceResize:
begin begin
SimplifySpacing;
CurOffset := (TargetSize-CurSize) / (ChildCount[Orientation]+1);
if CurOffset < 1 then
CurOffset := 1;
NewSizeCarry := 0;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if i=0 then begin if i=0 then begin
// add to left/top border // add to left/top border
DiffSize:=TargetSize-CurSize;
OldSize:=Child.BorderLeftTop[Orientation]; OldSize:=Child.BorderLeftTop[Orientation];
NewSize:=Min(OldSize+Factor.Offset,OldSize+DiffSize); NewSizeEx:=double(OldSize)+CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
NewSizeCarry:=NewSizeEx - NewSize;
DiffSize:=TargetSize-CurSize;
NewSize:=Min(NewSize,OldSize+DiffSize);
inc(CurSize,NewSize-OldSize); inc(CurSize,NewSize-OldSize);
Child.BorderLeftTop[Orientation]:=NewSize; Child.BorderLeftTop[Orientation]:=NewSize;
end; end;
// add to right/bottom border // add to right/bottom border
DiffSize:=TargetSize-CurSize;
OldSize:=Child.BorderRightBottom[Orientation]; OldSize:=Child.BorderRightBottom[Orientation];
NewSize:=Min(OldSize+Factor.Offset,OldSize+DiffSize); NewSizeEx:=double(OldSize)+CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
NewSizeCarry:=NewSizeEx - NewSize;
DiffSize:=TargetSize-CurSize;
NewSize:=Min(NewSize,OldSize+DiffSize);
inc(CurSize,NewSize-OldSize); inc(CurSize,NewSize-OldSize);
Child.BorderRightBottom[Orientation]:=NewSize; Child.BorderRightBottom[Orientation]:=NewSize;
if i<ChildCount[Orientation]-1 then
Child.BorderLeftTop[Orientation]:=NewSize;
end; end;
crsSameSize:
begin
OldSize:=Child.PreferredSize[Orientation];
if ResizeableCount <= 1 then
NewSize:=Max(1,OldSize+TargetSize-CurSize)
else
NewSize:=Max(1,round(double(ResizableSize)/ResizeableCount));
if (Child.MaximumSize[Orientation] > 0) and (NewSize >= Child.MaximumSize[Orientation]) then begin
NewSize := Child.MaximumSize[Orientation];
end
else
if (NewSize <= Child.MinimumSize[Orientation]) then begin
NewSize := Child.MinimumSize[Orientation];
end
else begin
dec(ResizableSize,NewSize);
dec(ResizeableCount);
end;
inc(CurSize,NewSize-OldSize);
Child.PreferredSize[Orientation]:=NewSize;
end;
end; end;
end; end;
end; end;
procedure GetChildMinResize(out Factor: TResizeFactor; procedure ShrinkChilds;
out ResizeableCount, ResizableSize: integer);
// returns the number of children/gaps, that can shrink (ResizeableCount)
// and the maximum factor, by which the children/gaps can shrink (TResizeFactor)
var var
i: Integer; i: Integer;
CurScale: Double;
CurOffset: LongInt;
Child: TAutoSizeBox; Child: TAutoSizeBox;
RemainingTargetSize, RemainingCurSize, NonResizeableCount: Integer;
ScaleChanged, LeftMostSpaceLimited: Boolean;
CurScale, CurOffset: Double;
NewSizeEx, NewSizeCarry: Double;
NewSize, OldSize, DiffSize: Integer;
begin begin
Factor.Scale:=0;
Factor.Offset:=0;
ResizeableCount:=0;
ResizableSize:=TargetSize;
case ShrinkStyle of case ShrinkStyle of
crsScaleChilds, crsHomogenousChildResize, crsSameSize:
begin
RemainingTargetSize := Max(0, TargetSize-CurSpacing);
RemainingCurSize := Max(0, CurSize-CurSpacing);
NonResizeableCount := 0;
crsAnchorAligning: if ShrinkStyle = crsSameSize then begin
exit; // no resizing (* First check for any cells forced smaller by there MaxSize
This only happens for crsSameSize (because even if the total
crsScaleChilds,crsHomogenousChildResize: area shrinks, individual cells may grow, if there
PreferredSize is below the average)
If they take less space, then other cells that would have hit
there MinSize, may stay above it.
In the "MinSize Loop" the scale will only shrink, so no further
MaxSize hits can happen there.
*)
if ChildCount[Orientation] > NonResizeableCount then
NewSize := RemainingTargetSize div (ChildCount[Orientation] - NonResizeableCount);
repeat
ScaleChanged:=False;
for i:=0 to ChildCount[Orientation]-1 do begin for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i]; Child:=Children[Orientation][i];
if (Child.PreferredSize[Orientation]<=Child.MinimumSize[Orientation]) if Child.LimitedSize[Orientation] then
or (Child.PreferredSize[Orientation]<=1)
then begin
// this child can not be further shrinked
continue; continue;
end;
inc(ResizeableCount);
case ShrinkStyle of if (Child.MaximumSize[Orientation] > 0) and (NewSize>=Child.MaximumSize[Orientation])
crsScaleChilds:
begin
CurScale:=double(Child.MinimumSize[Orientation])
/Child.PreferredSize[Orientation];
CurOffset:=Child.PreferredSize[Orientation]
-Child.MinimumSize[Orientation];
if (Factor.Offset=0) or (Factor.Scale<CurScale) then begin
Factor.Scale:=CurScale;
Factor.Offset:=CurOffset;
end;
end;
crsHomogenousChildResize:
begin
CurScale:=double(Child.MinimumSize[Orientation])
/Child.PreferredSize[Orientation];
CurOffset:=Child.PreferredSize[Orientation]
-Child.MinimumSize[Orientation];
if (Factor.Offset=0) or (Factor.Offset>CurOffset) then begin
Factor.Scale:=CurScale;
Factor.Offset:=CurOffset;
end;
end;
end;
end;
crsSameSize:
begin
Factor.Offset:=1; // prevent abort
if ChildCount[Orientation] > 0 then
CurOffset := TargetSize div ChildCount[Orientation];
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if (Child.MaximumSize[Orientation]>0)
and (CurOffset>=Child.MaximumSize[Orientation])
then begin then begin
// this childs size will be set to its MaximumSize // this childs size will be set to its MaximumSize
ResizableSize:=ResizableSize - Child.MaximumSize[Orientation]; RemainingTargetSize:=RemainingTargetSize - Child.MaximumSize[Orientation];
continue; RemainingCurSize:=RemainingCurSize - Child.PreferredSize[Orientation];
CurrentMinimumSizeSum := CurrentMinimumSizeSum - Child.MinimumSize[Orientation];
Child.PreferredSize[Orientation]:=Child.MaximumSize[Orientation];
Child.LimitedSize[Orientation] := True;
inc(NonResizeableCount);
OldSize := NewSize;
if ChildCount[Orientation] > NonResizeableCount then
NewSize := RemainingTargetSize div (ChildCount[Orientation] - NonResizeableCount)
else
break;
ScaleChanged := OldSize <> NewSize;
if ScaleChanged then
break; // for i :=
end; end;
if (CurOffset<=Child.MinimumSize[Orientation]) end;
until (not ScaleChanged) or (RemainingCurSize<=0);
if RemainingCurSize<=0 then
exit;
end;
repeat
ScaleChanged:=False;
case ShrinkStyle of
crsScaleChilds: begin
CurScale := double(RemainingTargetSize)/double(RemainingCurSize);
CurOffset := 0;
end;
crsHomogenousChildResize: begin
// negative CurOffset
if ChildCount[Orientation] > NonResizeableCount then
CurOffset := double(RemainingTargetSize - RemainingCurSize) / (ChildCount[Orientation] - NonResizeableCount);
CurScale := 1;
end;
crsSameSize: begin
if ChildCount[Orientation] > NonResizeableCount then
CurOffset := double(RemainingTargetSize) / (ChildCount[Orientation] - NonResizeableCount);
CurScale := 0;
end;
end;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
continue;
NewSize:=Round(double(Child.PreferredSize[Orientation])*CurScale+CurOffset);
if (NewSize<=Child.MinimumSize[Orientation])
then begin then begin
// this childs size will be set to its MinimumSize // this childs size will be set to its MinimumSize
ResizableSize:=ResizableSize - Child.MinimumSize[Orientation]; NewSize := Max(Min(1, Max(0, RemainingTargetSize-CurrentMinimumSizeSum)),Child.MinimumSize[Orientation]);
continue; RemainingTargetSize:=RemainingTargetSize - NewSize;
end; RemainingCurSize:=RemainingCurSize - Child.PreferredSize[Orientation];
inc(ResizeableCount); CurrentMinimumSizeSum := CurrentMinimumSizeSum - Child.MinimumSize[Orientation];
Child.PreferredSize[Orientation]:=NewSize;
Child.LimitedSize[Orientation] := True;
inc(NonResizeableCount);
ScaleChanged := True;
break; // for i :=
end; end;
end; end;
until (not ScaleChanged) or (RemainingCurSize<=0);
if RemainingCurSize<=0 then
exit;
crsHomogenousSpaceResize: DiffSize := RemainingCurSize - RemainingTargetSize;
NewSizeCarry := 0;
for i:=0 to ChildCount[Orientation]-1 do begin for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i]; Child:=Children[Orientation][i];
if i=0 then begin if Child.LimitedSize[Orientation] then
CurScale:=double(TargetSize); continue;
CurOffset:=Child.BorderLeftTop[Orientation];
if CurOffset>0 then begin
inc(ResizeableCount);
if (Factor.Offset=0) or (Factor.Offset>CurOffset) then begin
Factor.Scale:=CurScale;
Factor.Offset:=CurOffset;
end;
end;
end;
CurScale:=double(TargetSize);
CurOffset:=Child.BorderRightBottom[Orientation];
if CurOffset>0 then begin
inc(ResizeableCount);
if (Factor.Offset=0) or (Factor.Offset>CurOffset) then begin
Factor.Scale:=CurScale;
Factor.Offset:=CurOffset;
end;
end;
end;
OldSize:=Child.PreferredSize[Orientation];
NewSizeEx:=double(OldSize)*CurScale+CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
if NewSize >= 1 then NewSizeCarry:=NewSizeEx - NewSize
else NewSizeCarry:=0;
if i = ChildCount[Orientation] - 1 then
NewSize:=OldSize-DiffSize
else else
raise Exception.Create('TAutoSizeBox.ResizeChilds'); if (ShrinkStyle = crsSameSize) then
NewSize:=Max(1,NewSize)
else
NewSize:=Min(OldSize+DiffSize, Max(1,NewSize));
assert((Child.MaximumSize[Orientation]=0) or (NewSize<=Child.MaximumSize[Orientation]), 'EnlargeChilds: (Child.MaximumSize[Orientation]=0) or (NewSize<=Child.MaximumSize[Orientation])');
assert((NewSize>=Child.MinimumSize[Orientation]), 'EnlargeChilds: (NewSize>=Child.MinimumSize[Orientation])');
end; dec(DiffSize,OldSize-NewSize);
end;
procedure ShrinkChilds(const Factor: TResizeFactor; ResizeableCount, ResizableSize: integer);
var
i: Integer;
Child: TAutoSizeBox;
DiffSize: Integer;
NewSize: LongInt;
OldSize: LongInt;
begin
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if (ShrinkStyle<>crsSameSize)
and ( (Child.PreferredSize[Orientation]<=1)
or (Child.PreferredSize[Orientation]<=Child.MinimumSize[Orientation]) )
then begin
// this child can not be further shrinked
continue;
end;
case ShrinkStyle of
crsScaleChilds:
begin
// scale PreferredSize
DiffSize:=CurSize-TargetSize;
OldSize:=Child.PreferredSize[Orientation];
NewSize:=Min(round(OldSize*Factor.Scale),OldSize-1);
NewSize:=Max(Max(1,NewSize),OldSize-DiffSize);
dec(CurSize,OldSize-NewSize);
Child.PreferredSize[Orientation]:=NewSize; Child.PreferredSize[Orientation]:=NewSize;
end; end;
assert(DiffSize=0, 'ShrinkChilds: DiffSize=0');
crsHomogenousChildResize:
begin
// add to PreferredSize
DiffSize:=CurSize-TargetSize;
OldSize:=Child.PreferredSize[Orientation];
NewSize:=OldSize-Factor.Offset;
NewSize:=Max(Max(NewSize,1),OldSize-DiffSize);
dec(CurSize,OldSize-NewSize);
Child.PreferredSize[Orientation]:=NewSize;
end; end;
crsHomogenousSpaceResize: crsHomogenousSpaceResize:
begin begin
if i=0 then begin SimplifySpacing;
RemainingTargetSize := TargetSize;
RemainingCurSize := CurSize;
NonResizeableCount := 0;
LeftMostSpaceLimited := False;
repeat
ScaleChanged:=False;
CurOffset := (RemainingCurSize-RemainingTargetSize) / (ChildCount[Orientation]-NonResizeableCount+1);
DiffSize := Round(CurOffset);
if (ChildCount[Orientation] > 0) and not LeftMostSpaceLimited then begin
// add to left/top border // add to left/top border
DiffSize:=CurSize-TargetSize; Child:=Children[Orientation][0];
OldSize:=Child.BorderLeftTop[Orientation]; OldSize:=Child.BorderLeftTop[Orientation];
NewSize:=Max(Max(0,OldSize-Factor.Offset),OldSize-DiffSize); NewSize:=OldSize-DiffSize;
dec(CurSize,OldSize-NewSize); if NewSize < 1 then begin
Child.BorderLeftTop[Orientation]:=NewSize; RemainingCurSize:=RemainingCurSize - Child.BorderLeftTop[Orientation];
Child.BorderLeftTop[Orientation]:=0;
LeftMostSpaceLimited := True;
inc(NonResizeableCount);
ScaleChanged := True;
continue;
end; end;
end;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
Continue;
// add to right/bottom border // add to right/bottom border
DiffSize:=CurSize-TargetSize;
OldSize:=Child.BorderRightBottom[Orientation]; OldSize:=Child.BorderRightBottom[Orientation];
NewSize:=Max(Max(0,OldSize-Factor.Offset),OldSize-DiffSize); NewSize:=OldSize-DiffSize;
dec(CurSize,OldSize-NewSize); if NewSize < 1 then begin
Child.BorderRightBottom[Orientation]:=NewSize; RemainingCurSize:=RemainingCurSize - Child.BorderRightBottom[Orientation];
if i<ChildCount[Orientation]-1 then Child.BorderRightBottom[Orientation]:=0;
Child.LimitedSize[Orientation] := True;
inc(NonResizeableCount);
ScaleChanged := True;
break; // for i :=
end;
end;
until (not ScaleChanged) or (RemainingCurSize<=0) or (ChildCount[Orientation]<=NonResizeableCount-1);
if (RemainingCurSize<=0) or (ChildCount[Orientation]<=NonResizeableCount-1) then
exit;
DiffSize:=CurSize-TargetSize;
NewSizeCarry := 0;
if (ChildCount[Orientation] > 0) and not LeftMostSpaceLimited then begin
// add to left/top border
Child:=Children[Orientation][0];
OldSize:=Child.BorderLeftTop[Orientation];
NewSizeEx:=double(OldSize)-CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
NewSizeCarry:=NewSizeEx - NewSize;
NewSize:=Max(NewSize,OldSize-DiffSize);
dec(DiffSize,OldSize-NewSize);
Child.BorderLeftTop[Orientation]:=NewSize; Child.BorderLeftTop[Orientation]:=NewSize;
end; end;
for i:=0 to ChildCount[Orientation]-1 do begin
crsSameSize: Child:=Children[Orientation][i];
begin if Child.LimitedSize[Orientation] then
OldSize:=Child.PreferredSize[Orientation]; Continue;
if ResizeableCount <= 1 then // add to right/bottom border
NewSize:=Max(1,OldSize+TargetSize-CurSize) OldSize:=Child.BorderRightBottom[Orientation];
else NewSizeEx:=double(OldSize)-CurOffset+NewSizeCarry;
NewSize:=Max(1,round(double(ResizableSize)/ResizeableCount)); NewSize:=Round(NewSizeEx);
if (Child.MaximumSize[Orientation] > 0) and (NewSize >= Child.MaximumSize[Orientation]) then begin NewSizeCarry:=NewSizeEx - NewSize;
NewSize := Child.MaximumSize[Orientation]; NewSize:=Max(NewSize,OldSize-DiffSize);
end dec(DiffSize,OldSize-NewSize);
else Child.BorderRightBottom[Orientation]:=NewSize;
if (NewSize <= Child.MinimumSize[Orientation]) then begin
NewSize := Child.MinimumSize[Orientation];
end
else begin
dec(ResizableSize,NewSize);
dec(ResizeableCount);
end; end;
dec(CurSize,OldSize-NewSize);
Child.PreferredSize[Orientation]:=NewSize;
end;
end; end;
end; end;
end; end;
var
MaxResizeFactorPerItem, MinResizeFactorPerItem, CurScale: TResizeFactor;
ResizeableCount, ResizableSize: integer;
i: Integer;
begin begin
CurSize:=GetChildTotalSize; CurSize:=GetChildTotalSize;
//DebugLn('TAutoSizeBox.ResizeChilds CurSize=',dbgs(CurSize),' TargetSize=',dbgs(TargetSize)); //DebugLn('TAutoSizeBox.ResizeChilds CurSize=',dbgs(CurSize),' TargetSize=',dbgs(TargetSize));
EnlargeStyle:=crsAnchorAligning; EnlargeStyle:=crsAnchorAligning;
ShrinkStyle:=crsAnchorAligning; ShrinkStyle:=crsAnchorAligning;
i:=0; if TargetSize>=CurSize then begin
if TargetSize>CurSize then begin
// enlarge // enlarge
if Orientation=asboHorizontal then if Orientation=asboHorizontal then
EnlargeStyle:=ChildSizing.EnlargeHorizontal EnlargeStyle:=ChildSizing.EnlargeHorizontal
else else
EnlargeStyle:=ChildSizing.EnlargeVertical; EnlargeStyle:=ChildSizing.EnlargeVertical;
while TargetSize>CurSize do begin // grow children
// shrink children if (TargetSize>CurSize) or (EnlargeStyle=crsSameSize) then
GetChildMaxResize(MaxResizeFactorPerItem,ResizeableCount, ResizableSize); EnlargeChilds;
if (ResizeableCount=0) or (MaxResizeFactorPerItem.Offset=0) then break;
CurScale.Scale:=(double(TargetSize)/CurSize);
if (MaxResizeFactorPerItem.Scale>0)
and (MaxResizeFactorPerItem.Scale<CurScale.Scale) then
CurScale.Scale:=MaxResizeFactorPerItem.Scale;
CurScale.Offset:=((TargetSize-CurSize-1) div ResizeableCount)+1;
// note: the above formula makes sure, that Offset>0
if (MaxResizeFactorPerItem.Offset>0)
and (MaxResizeFactorPerItem.Offset<CurScale.Offset) then
CurScale.Offset:=MaxResizeFactorPerItem.Offset;
EnlargeChilds(CurScale, ResizeableCount, ResizableSize);
inc(i);
if i>1000 then RaiseGDBException('TAutoSizeBox.ResizeChilds consistency error');
end;
end else if TargetSize<CurSize then begin end else if TargetSize<CurSize then begin
// shrink // shrink
if Orientation=asboHorizontal then if Orientation=asboHorizontal then
ShrinkStyle:=ChildSizing.ShrinkHorizontal ShrinkStyle:=ChildSizing.ShrinkHorizontal
else else
ShrinkStyle:=ChildSizing.ShrinkVertical; ShrinkStyle:=ChildSizing.ShrinkVertical;
while TargetSize<CurSize do begin ShrinkChilds;
GetChildMinResize(MinResizeFactorPerItem,ResizeableCount, ResizableSize);
if (ResizeableCount=0) or (MinResizeFactorPerItem.Offset=0) then break;
CurScale.Scale:=(double(TargetSize)/CurSize);
if (MinResizeFactorPerItem.Scale>0)
and (MinResizeFactorPerItem.Scale>CurScale.Scale) then
CurScale.Scale:=MinResizeFactorPerItem.Scale;
CurScale.Offset:=((CurSize-TargetSize-1) div ResizeableCount)+1;
// note: the above formula makes sure, that Offset>0
if (MinResizeFactorPerItem.Offset>0)
and (MinResizeFactorPerItem.Offset>CurScale.Offset) then
CurScale.Offset:=MinResizeFactorPerItem.Offset;
ShrinkChilds(CurScale, ResizeableCount, ResizableSize);
inc(i);
if i>1000 then RaiseGDBException('TAutoSizeBox.ResizeChilds consistency error');
end;
end; end;
end; end;