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);
// returns the number of children/gaps, that can grow (ResizeableCount)
// and the maximum factor, by which the children/gaps can grow (TResizeFactor)
var var
i: Integer; i: Integer;
CurScale: Double;
CurOffset: LongInt;
Child: TAutoSizeBox;
begin begin
Factor.Scale:=0; for i:=0 to ChildCount[Orientation]-2 do begin
Factor.Offset:=0; Children[Orientation][i].BorderRightBottom[Orientation]:=Max(
ResizeableCount:=0; Children[Orientation][i].BorderRightBottom[Orientation],
ResizableSize:=TargetSize; Children[Orientation][i+1].BorderLeftTop[Orientation]
);
Children[Orientation][i+1].BorderLeftTop[Orientation]:=0;
end;
end;
procedure EnlargeChilds;
var
i: Integer;
Child: TAutoSizeBox;
RemainingTargetSize, RemainingCurSize, NonResizeableCount: Integer;
ScaleChanged: Boolean;
CurScale, CurOffset: Double;
NewSizeEx, NewSizeCarry: Double;
NewSize, OldSize, DiffSize: Integer;
begin
case EnlargeStyle of case EnlargeStyle of
crsScaleChilds, crsHomogenousChildResize, crsSameSize:
crsAnchorAligning:
exit; // no resizing
crsScaleChilds,crsHomogenousChildResize:
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if (Child.MaximumSize[Orientation]>0)
and (Child.PreferredSize[Orientation]>=Child.MaximumSize[Orientation])
then begin
// this child can not be further enlarged
continue;
end;
inc(ResizeableCount);
case EnlargeStyle of
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
// this childs size will be set to its MinimumSize
ResizableSize:=ResizableSize - Child.MinimumSize[Orientation];
continue;
end;
inc(ResizeableCount);
end;
end;
crsHomogenousSpaceResize:
if ChildCount[Orientation]>0 then begin
Factor.Scale:=double(TargetSize);
Factor.Offset:=TargetSize;
ResizeableCount:=ChildCount[Orientation]+1;
end;
else
raise Exception.Create('TAutoSizeBox.ResizeChilds');
end;
end;
procedure EnlargeChilds(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
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;
case EnlargeStyle of
crsScaleChilds:
begin begin
// scale PreferredSize RemainingTargetSize := Max(0, TargetSize-CurSpacing);
DiffSize:=TargetSize-CurSize; RemainingCurSize := Max(0, CurSize-CurSpacing);
OldSize:=Child.PreferredSize[Orientation]; NonResizeableCount := 0;
NewSize:=round(double(OldSize)*Factor.Scale);
NewSize:=Min(OldSize+DiffSize,Max(OldSize+1,NewSize)); if EnlargeStyle = crsSameSize then begin
inc(CurSize,NewSize-OldSize); (* First check for any cells forced bigger by there MinSize
Child.PreferredSize[Orientation]:=NewSize; This only happens for crsSameSize (because even if the total
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
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
continue;
if (NewSize<=Child.MinimumSize[Orientation])
then begin
// this childs size will be set to its MinimumSize
RemainingTargetSize:=RemainingTargetSize - Child.MinimumSize[Orientation];
RemainingCurSize:=RemainingCurSize - Child.PreferredSize[Orientation];
Child.PreferredSize[Orientation]:=Child.MinimumSize[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;
until (not ScaleChanged) or (RemainingCurSize<=0);
if RemainingCurSize<=0 then
exit;
end;
repeat
ScaleChanged:=False;
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;
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
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;
end;
assert(DiffSize = 0, 'EnlargeChilds: DiffSize = 0');
end; end;
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;
crsHomogenousSpaceResize: crsHomogenousSpaceResize:
begin begin
if i=0 then begin SimplifySpacing;
// add to left/top border 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
// add to left/top border
OldSize:=Child.BorderLeftTop[Orientation];
NewSizeEx:=double(OldSize)+CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
NewSizeCarry:=NewSizeEx - NewSize;
DiffSize:=TargetSize-CurSize;
NewSize:=Min(NewSize,OldSize+DiffSize);
inc(CurSize,NewSize-OldSize);
Child.BorderLeftTop[Orientation]:=NewSize;
end;
// add to right/bottom border
OldSize:=Child.BorderRightBottom[Orientation];
NewSizeEx:=double(OldSize)+CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
NewSizeCarry:=NewSizeEx - NewSize;
DiffSize:=TargetSize-CurSize; DiffSize:=TargetSize-CurSize;
OldSize:=Child.BorderLeftTop[Orientation]; NewSize:=Min(NewSize,OldSize+DiffSize);
NewSize:=Min(OldSize+Factor.Offset,OldSize+DiffSize);
inc(CurSize,NewSize-OldSize); inc(CurSize,NewSize-OldSize);
Child.BorderLeftTop[Orientation]:=NewSize; Child.BorderRightBottom[Orientation]:=NewSize;
end; end;
// add to right/bottom border
DiffSize:=TargetSize-CurSize;
OldSize:=Child.BorderRightBottom[Orientation];
NewSize:=Min(OldSize+Factor.Offset,OldSize+DiffSize);
inc(CurSize,NewSize-OldSize);
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;
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:
crsAnchorAligning:
exit; // no resizing
crsScaleChilds,crsHomogenousChildResize:
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if (Child.PreferredSize[Orientation]<=Child.MinimumSize[Orientation])
or (Child.PreferredSize[Orientation]<=1)
then begin
// this child can not be further shrinked
continue;
end;
inc(ResizeableCount);
case ShrinkStyle of
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
// this childs size will be set to its MaximumSize
ResizableSize:=ResizableSize - Child.MaximumSize[Orientation];
continue;
end;
if (CurOffset<=Child.MinimumSize[Orientation])
then begin
// this childs size will be set to its MinimumSize
ResizableSize:=ResizableSize - Child.MinimumSize[Orientation];
continue;
end;
inc(ResizeableCount);
end;
end;
crsHomogenousSpaceResize:
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if i=0 then begin
CurScale:=double(TargetSize);
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;
else
raise Exception.Create('TAutoSizeBox.ResizeChilds');
end;
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 begin
// scale PreferredSize RemainingTargetSize := Max(0, TargetSize-CurSpacing);
DiffSize:=CurSize-TargetSize; RemainingCurSize := Max(0, CurSize-CurSpacing);
OldSize:=Child.PreferredSize[Orientation]; NonResizeableCount := 0;
NewSize:=Min(round(OldSize*Factor.Scale),OldSize-1);
NewSize:=Max(Max(1,NewSize),OldSize-DiffSize);
dec(CurSize,OldSize-NewSize);
Child.PreferredSize[Orientation]:=NewSize;
end;
crsHomogenousChildResize: if ShrinkStyle = crsSameSize then begin
begin (* First check for any cells forced smaller by there MaxSize
// add to PreferredSize This only happens for crsSameSize (because even if the total
DiffSize:=CurSize-TargetSize; area shrinks, individual cells may grow, if there
OldSize:=Child.PreferredSize[Orientation]; PreferredSize is below the average)
NewSize:=OldSize-Factor.Offset; If they take less space, then other cells that would have hit
NewSize:=Max(Max(NewSize,1),OldSize-DiffSize); there MinSize, may stay above it.
dec(CurSize,OldSize-NewSize); In the "MinSize Loop" the scale will only shrink, so no further
Child.PreferredSize[Orientation]:=NewSize; 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
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
continue;
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];
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;
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
// this childs size will be set to its MinimumSize
NewSize := Max(Min(1, Max(0, RemainingTargetSize-CurrentMinimumSizeSum)),Child.MinimumSize[Orientation]);
RemainingTargetSize:=RemainingTargetSize - NewSize;
RemainingCurSize:=RemainingCurSize - Child.PreferredSize[Orientation];
CurrentMinimumSizeSum := CurrentMinimumSizeSum - Child.MinimumSize[Orientation];
Child.PreferredSize[Orientation]:=NewSize;
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 := RemainingCurSize - RemainingTargetSize;
NewSizeCarry := 0;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
continue;
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
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])');
dec(DiffSize,OldSize-NewSize);
Child.PreferredSize[Orientation]:=NewSize;
end;
assert(DiffSize=0, 'ShrinkChilds: DiffSize=0');
end; end;
crsHomogenousSpaceResize: crsHomogenousSpaceResize:
begin begin
if i=0 then begin SimplifySpacing;
// add to left/top border RemainingTargetSize := TargetSize;
DiffSize:=CurSize-TargetSize; RemainingCurSize := CurSize;
OldSize:=Child.BorderLeftTop[Orientation]; NonResizeableCount := 0;
NewSize:=Max(Max(0,OldSize-Factor.Offset),OldSize-DiffSize); LeftMostSpaceLimited := False;
dec(CurSize,OldSize-NewSize);
Child.BorderLeftTop[Orientation]:=NewSize; repeat
end; ScaleChanged:=False;
// add to right/bottom border CurOffset := (RemainingCurSize-RemainingTargetSize) / (ChildCount[Orientation]-NonResizeableCount+1);
DiffSize := Round(CurOffset);
if (ChildCount[Orientation] > 0) and not LeftMostSpaceLimited then begin
// add to left/top border
Child:=Children[Orientation][0];
OldSize:=Child.BorderLeftTop[Orientation];
NewSize:=OldSize-DiffSize;
if NewSize < 1 then begin
RemainingCurSize:=RemainingCurSize - Child.BorderLeftTop[Orientation];
Child.BorderLeftTop[Orientation]:=0;
LeftMostSpaceLimited := True;
inc(NonResizeableCount);
ScaleChanged := True;
continue;
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
OldSize:=Child.BorderRightBottom[Orientation];
NewSize:=OldSize-DiffSize;
if NewSize < 1 then begin
RemainingCurSize:=RemainingCurSize - Child.BorderRightBottom[Orientation];
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; DiffSize:=CurSize-TargetSize;
OldSize:=Child.BorderRightBottom[Orientation]; NewSizeCarry := 0;
NewSize:=Max(Max(0,OldSize-Factor.Offset),OldSize-DiffSize); if (ChildCount[Orientation] > 0) and not LeftMostSpaceLimited then begin
dec(CurSize,OldSize-NewSize); // add to left/top border
Child.BorderRightBottom[Orientation]:=NewSize; Child:=Children[Orientation][0];
if i<ChildCount[Orientation]-1 then 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;
for i:=0 to ChildCount[Orientation]-1 do begin
Child:=Children[Orientation][i];
if Child.LimitedSize[Orientation] then
Continue;
// add to right/bottom border
OldSize:=Child.BorderRightBottom[Orientation];
NewSizeEx:=double(OldSize)-CurOffset+NewSizeCarry;
NewSize:=Round(NewSizeEx);
NewSizeCarry:=NewSizeEx - NewSize;
NewSize:=Max(NewSize,OldSize-DiffSize);
dec(DiffSize,OldSize-NewSize);
Child.BorderRightBottom[Orientation]:=NewSize;
end;
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;
dec(CurSize,OldSize-NewSize);
Child.PreferredSize[Orientation]:=NewSize;
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;