LCL: grids: Implements MinSize/MaxSize column properties for grids with AutofillColumns=true, issue #34548

This commit is contained in:
Jesus Reyes A 2021-08-23 12:21:06 -05:00
parent 06a60b60b6
commit 7b9589dc61

View File

@ -75,6 +75,9 @@ const
DEFCOLWIDTH = 64; DEFCOLWIDTH = 64;
DEFBUTTONWIDTH = 25; DEFBUTTONWIDTH = 25;
DEFIMAGEPADDING = 2; DEFIMAGEPADDING = 2;
DEFMINSIZE = 0;
DEFMAXSIZE = 0;
DEFSIZEPRIORITY = 1;
type type
EGridException = class(Exception); EGridException = class(Exception);
@ -2271,12 +2274,11 @@ procedure TCustomGrid.InternalAutoFillColumns;
end; end;
var var
I, ForcedIndex: Integer; i, availableSize, avgSize, rest: Integer;
Count: Integer; widths: array of record
aPriority, aMin, aMax: Integer; aIndex, aMin, aMax, aPriority, aWidth: Integer;
AvailableSize: Integer; end;
TotalWidth: Integer; // total grid's width done, isMax, isMin: boolean;
FixedSizeWidth: Integer; // total width of Fixed Sized Columns
begin begin
if not AutoFillColumns then if not AutoFillColumns then
exit; exit;
@ -2290,66 +2292,73 @@ begin
// when InternalAutoFillColumns is called from DoChangeBounds // when InternalAutoFillColumns is called from DoChangeBounds
// for example. // for example.
// Insert the algorithm that modify ColWidths accordingly // A simple algorithm is implemented:
//
// For testing purposes, a simple algortihm is implemented:
// if SizePriority=0, column size should be unmodified // if SizePriority=0, column size should be unmodified
// if SizePriority<>0 means variable size column, its size // if SizePriority<>0 means variable size column whose width
// is the average avalilable size. // is the average available size respecting each column
// MinSize and MaxSize constraints, such constraints
// are valid only if they are bigger than 0.
Count := 0; widths := nil;
FixedSizeWidth := 0; SetLength(widths, ColCount);
TotalWidth := 0;
for i:=0 to ColCount-1 do begin availableSize := ClientWidth - GetBorderWidth;
for i:=0 to ColCount-1 do
with widths[i] do begin
aIndex := i;
GetAutoFillColumnInfo(i, aMin, aMax, aPriority); GetAutoFillColumnInfo(i, aMin, aMax, aPriority);
AvailableSize := GetColWidths(i); aWidth := GetColWidths(i);
if aPriority>0 then if aPriority=0 then begin
Inc(Count) Dec(availableSize, aWidth);
else delete(widths, i, 1);
Inc(FixedSizeWidth, AvailableSize); end
Inc(TotalWidth, AvailableSize);
end; end;
if Count=0 then begin if Length(widths)=0 then begin
//it's an autofillcolumns grid, so at least one // it's an autofillcolumns grid either WITHOUT custom colums and
// of the columns must fill completely the grid's // fixedCols=ColCount or WITH custom columns where all columns
// available width, let it be that column the last // have PrioritySize=0, resize the last column (inherited behavior)
ForcedIndex := ColCount-1; i := ColCount-1;
if ForcedIndex>=FixedCols then if (i>=FixedCols) then // aMax of last column ...
Dec(FixedSizeWidth, GetColWidths(ForcedIndex)); SetColumnWidth(i, AvailableSize + GetColWidths(i));
Count := 1; exit;
end else end;
ForcedIndex := -1;
AvailableSize := ClientWidth - FixedSizeWidth - GetBorderWidth; avgSize := availableSize div Length(widths);
if AvailableSize<0 then begin
// There is no space available to fill with
// Variable Size Columns, what to do?
// Simply set all Variable Size Columns repeat
// to 0, decreasing the size beyond this done := true;
// shouldn't be allowed. for i:=Length(widths)-1 downto 0 do
for i:=0 to ColCount-1 do begin with widths[i] do begin
GetAutoFillColumnInfo(i, aMin, aMax, aPriority); isMax := ((aMax>0) and (avgSize>aMax));
if aPriority>0 then isMin := ((aMin>0) and (avgSize<aMin));
SetColumnWidth(i, 0); if isMax or isMin then begin
end; if isMax then aWidth := aMax;
end else begin if isMin then aWidth := aMin;
// Simpler case: There is actually available space to SetColumnWidth(aIndex, aWidth);
// to be shared for variable size columns. availableSize := Max(availableSize-aWidth, 0);
FixedSizeWidth := AvailableSize mod Count; // space left after filling columns Delete(widths, i, 1);
AvailableSize := AvailableSize div Count; if length(widths)>0 then
for i:=0 to ColCount-1 do begin avgSize := availableSize div length(widths);
GetAutoFillColumnInfo(i, aMin, aMax, aPriority); done := false;
if (APriority>0) or (i=ForcedIndex) then begin break:
if i=ColCount-1 then
// the last column gets all space left
SetColumnWidth(i, AvailableSize + FixedSizeWidth)
else
SetColumnWidth(i, AvailableSize);
end; end;
end; end;
until done;
if length(widths)>0 then begin
rest := availableSize mod length(widths);
for i:=0 to length(widths)-1 do
with widths[i] do begin
aWidth := Max(avgSize, 0);
if rest>0 then begin
inc(aWidth);
dec(rest);
end; end;
SetColumnWidth(aIndex, aWidth);
end;
end;
finally finally
FUpdatingAutoFillCols:=False; FUpdatingAutoFillCols:=False;
end; end;
@ -8686,6 +8695,8 @@ procedure TCustomGrid.GetAutoFillColumnInfo(const Index: Integer; var aMin,aMax,
var var
C: TGridColumn; C: TGridColumn;
begin begin
aMin := DEFMINSIZE;
aMax := DEFMAXSIZE;
if Index<FixedCols then if Index<FixedCols then
APriority := 0 APriority := 0
else if Columns.Enabled then begin else if Columns.Enabled then begin
@ -9406,6 +9417,8 @@ begin
cfg.setValue(cPath + '/index/value', c.Index); cfg.setValue(cPath + '/index/value', c.Index);
if c.IsWidthStored then if c.IsWidthStored then
cfg.setValue(cPath + '/width/value', c.Width); cfg.setValue(cPath + '/width/value', c.Width);
if c.IsMinSizeStored then cfg.SetValue(cPath + '/minsize/value', c.MinSize);
if c.IsMaxSizeStored then cfg.SetValue(cPath + '/maxsize/value', c.MaxSize);
if c.IsAlignmentStored then if c.IsAlignmentStored then
cfg.setValue(cPath + '/alignment/value', ord(c.Alignment)); cfg.setValue(cPath + '/alignment/value', ord(c.Alignment));
if c.IsLayoutStored then if c.IsLayoutStored then
@ -9548,8 +9561,9 @@ begin
cPath := Path + 'column' + IntToStr(i); cPath := Path + 'column' + IntToStr(i);
c.index := cfg.getValue(cPath + '/index/value', i); c.index := cfg.getValue(cPath + '/index/value', i);
s := cfg.GetValue(cPath + '/width/value', ''); s := cfg.GetValue(cPath + '/width/value', '');
if s<>'' then if s<>'' then c.Width := StrToIntDef(s, DEFCOLWIDTH);
c.Width := StrToIntDef(s, 64); c.MinSize := cfg.GetValue(cPath + '/minsize/value', DEFMINSIZE);
c.MaxSize := cfg.GetValue(cPath + '/maxsize/value', DEFMAXSIZE);
s := cfg.getValue(cPath + '/alignment/value', ''); s := cfg.getValue(cPath + '/alignment/value', '');
if s<>'' then if s<>'' then
c.Alignment := TAlignment(StrToIntDef(s, 0)); c.Alignment := TAlignment(StrToIntDef(s, 0));
@ -12845,14 +12859,12 @@ end;
function TGridColumn.GetDefaultMaxSize: Integer; function TGridColumn.GetDefaultMaxSize: Integer;
begin begin
// get a better default Result := DEFMAXSIZE;
Result := 200;
end; end;
function TGridColumn.GetDefaultMinSize: Integer; function TGridColumn.GetDefaultMinSize: Integer;
begin begin
// get a better default result := DEFMINSIZE;
result := 10;
end; end;
function TGridColumn.GetDefaultColor: TColor; function TGridColumn.GetDefaultColor: TColor;
@ -12868,7 +12880,7 @@ end;
function TGridColumn.GetDefaultSizePriority: Integer; function TGridColumn.GetDefaultSizePriority: Integer;
begin begin
Result := 1; Result := DEFSIZEPRIORITY;
end; end;
procedure TGridColumn.Assign(Source: TPersistent); procedure TGridColumn.Assign(Source: TPersistent);