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));
inc(CurSize,NewSize-OldSize);
Child.PreferredSize[Orientation]:=NewSize;
end;
crsHomogenousChildResize: if EnlargeStyle = crsSameSize then begin
begin (* First check for any cells forced bigger by there MinSize
// add to PreferredSize This only happens for crsSameSize (because even if the total
DiffSize:=TargetSize-CurSize; area grows, individual cells may shrink, if there
OldSize:=Child.PreferredSize[Orientation]; PreferredSize is above the average)
NewSize:=Min(OldSize+Factor.Offset,OldSize+DiffSize); If they take extra space, then other cells that would have hit
inc(CurSize,NewSize-OldSize); there MaxSize, may stay below it.
Child.PreferredSize[Orientation]:=NewSize; 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;
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;