Skip to content

Commit

Permalink
Add suppressed auto size.
Browse files Browse the repository at this point in the history
  • Loading branch information
bosskmk committed Dec 8, 2022
1 parent c7df807 commit 93a0628
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 343 deletions.
218 changes: 103 additions & 115 deletions lib/src/helper/pluto_size_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,177 +41,165 @@ enum PlutoAutoSizeMode {

/// Returns the auto-sizing class according to
/// [PlutoAutoSizeMode.equal] or [PlutoAutoSizeMode.scale].
///
/// {@template exceeds_max_size}
/// If [itemMinSize] * [length] is greater than [maxSize],
/// all items are changed to [itemMinSize]
/// The total size of items exceeds [maxSize].
/// {@endtemplate}
///
/// {@template auto_size_scale_mode}
/// If [mode] is [PlutoAutoSizeMode.scale], you must pass the value of [scale].
/// If the screen size is 1,000 and the total width of the items is 500
/// scale is 1,000 / 500 = 2
/// In this case, the size of the items is doubled.
/// {@endtemplate}
class PlutoAutoSizeHelper {
static PlutoAutoSize items({
static PlutoAutoSize items<T>({
required double maxSize,
required int length,
required double itemMinSize,
required Iterable<T> items,
required bool Function(T) isSuppressed,
required double Function(T) getItemSize,
required double Function(T) getItemMinSize,
required void Function(T, double) setItemSize,
required PlutoAutoSizeMode mode,
double? scale,
}) {
if (mode.isScale) assert(scale != null);

switch (mode) {
case PlutoAutoSizeMode.equal:
return PlutoAutoSizeEqual(
return PlutoAutoSizeEqual<T>(
maxSize: maxSize,
length: length,
itemMinSize: itemMinSize,
items: items,
isSuppressedItem: isSuppressed,
getItemSize: getItemSize,
getItemMinSize: getItemMinSize,
setItemSize: setItemSize,
);
case PlutoAutoSizeMode.scale:
return PlutoAutoSizeScale(
return PlutoAutoSizeScale<T>(
maxSize: maxSize,
length: length,
scale: scale!,
itemMinSize: itemMinSize,
items: items,
isSuppressedItem: isSuppressed,
getItemSize: getItemSize,
getItemMinSize: getItemMinSize,
setItemSize: setItemSize,
);
case PlutoAutoSizeMode.none:
throw Exception('Mode cannot be called with PlutoAutoSizeMode.none.');
}
}
}

abstract class PlutoAutoSize {
double getItemSize(double originalSize);
}

/// Change the width of the items equally within the [maxSize] range.
///
/// [getItemSize] must be called for the length of the items.
///
/// {@macro exceeds_max_size}
class PlutoAutoSizeEqual implements PlutoAutoSize {
PlutoAutoSizeEqual({
abstract class PlutoAutoSize<T> {
const PlutoAutoSize({
required this.maxSize,
required this.length,
required this.itemMinSize,
}) : _eachSize = maxSize / length,
_overSize = length * itemMinSize > maxSize;
required this.items,
required this.isSuppressedItem,
required this.getItemSize,
required this.getItemMinSize,
required this.setItemSize,
});

/// Total size the item will occupy.
final double maxSize;

final int length;
/// List of items to set size for.
final Iterable<T> items;

final double itemMinSize;
/// A callback to override the auto size setting.
final bool Function(T) isSuppressedItem;

final double _eachSize;
/// A callback that returns the original size of the item.
final double Function(T) getItemSize;

final bool _overSize;
/// A callback that returns the minimum size of an item.
final double Function(T) getItemMinSize;

int _count = 1;
/// Callback for setting the size of the item.
final void Function(T, double) setItemSize;

double _accumulateSize = 0;
/// Call the [setItemSize] callback while traversing the [items] list.
void update();
}

/// Change the width of the items equally within the [maxSize] range.
class PlutoAutoSizeEqual<T> extends PlutoAutoSize<T> {
const PlutoAutoSizeEqual({
required super.maxSize,
required super.items,
required super.isSuppressedItem,
required super.getItemSize,
required super.getItemMinSize,
required super.setItemSize,
});

@override
double getItemSize(double originalSize) {
assert(_count <= length);
void update() {
final length = items.length;

double size = _overSize ? itemMinSize : _eachSize;
double eachSize = maxSize / length;

if (_overSize) {
size = itemMinSize;
} else {
size = _eachSize;
bool isSuppressed(T e) {
return isSuppressedItem(e) || eachSize < getItemMinSize(e);
}

// Last item
if (_count == length) {
size = maxSize - _accumulateSize;
final suppressedItems = items.where(isSuppressed);

++_count;
if (suppressedItems.isNotEmpty) {
final totalSuppressedSize = suppressedItems.fold<double>(0, (p, e) {
return p + (isSuppressedItem(e) ? getItemSize(e) : getItemMinSize(e));
});

return size;
}
eachSize =
(maxSize - totalSuppressedSize) / (length - suppressedItems.length);
}

_accumulateSize += size;
for (final item in items) {
if (isSuppressedItem(item)) continue;

++_count;

return size;
setItemSize(item, max(eachSize, getItemMinSize(item)));
}
}
}

/// Change the size of items according to the ratio.
///
/// [getItemSize] must be called for the length of the items.
///
/// {@macro exceeds_max_size}
///
/// {@macro auto_size_scale_mode}
class PlutoAutoSizeScale implements PlutoAutoSize {
PlutoAutoSizeScale({
required this.maxSize,
required this.length,
required this.scale,
required this.itemMinSize,
}) : _overSize = length * itemMinSize > maxSize;

final double maxSize;

final int length;
class PlutoAutoSizeScale<T> extends PlutoAutoSize<T> {
const PlutoAutoSizeScale({
required super.maxSize,
required super.items,
required super.isSuppressedItem,
required super.getItemSize,
required super.getItemMinSize,
required super.setItemSize,
});

final double scale;
@override
void update() {
final length = items.length;

final double itemMinSize;
double effectiveMaxSize = maxSize;

final bool _overSize;
double totalWidth = items.fold<double>(0, (p, e) => p += getItemSize(e));

int _count = 1;
double scale = maxSize / totalWidth;

double _accumulateSize = 0;
bool isSuppressed(T e) {
return isSuppressedItem(e) || getItemSize(e) * scale < getItemMinSize(e);
}

@override
double getItemSize(double originalSize) {
assert(_count <= length);
final suppressedItems = items.where(isSuppressed);

double size;
if (suppressedItems.isNotEmpty) {
final totalSuppressedSize = suppressedItems.fold<double>(0, (p, e) {
return p + (isSuppressedItem(e) ? getItemSize(e) : getItemMinSize(e));
});

if (_overSize) {
size = itemMinSize;
} else {
size = max(originalSize * scale, itemMinSize).roundToDouble();
effectiveMaxSize = maxSize - totalSuppressedSize;

final remaining = maxSize - _accumulateSize - size;
totalWidth = items.whereNot(isSuppressed).fold(0, (p, e) {
return p + getItemSize(e);
});

final remainingCount = length - _count;
scale = effectiveMaxSize / totalWidth;
}

if (remainingCount > 0) {
final remainingMinSize = remaining / remainingCount;
for (int i = 0; i < length; i += 1) {
final item = items.elementAt(i);

if (remainingMinSize < itemMinSize) {
double needingSize =
remainingCount * (itemMinSize - remainingMinSize);
if (isSuppressedItem(item)) continue;

size -= needingSize;
}
}
final minSize = getItemMinSize(item);

// Last item
if (_count == length) {
++_count;
final size = max(minSize, getItemSize(item) * scale);

return maxSize - _accumulateSize;
}
setItemSize(item, size);
}

_accumulateSize += size;

++_count;

return size;
}
}

Expand Down
18 changes: 6 additions & 12 deletions lib/src/manager/state/column_sizing_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,14 @@ mixin ColumnSizingState implements IPlutoGridState {
assert(columnsAutoSizeMode.isNone == false);
assert(columns.isNotEmpty);

double? scale;

if (columnsAutoSizeMode.isScale) {
final totalWidth = columns.fold<double>(0, (pre, e) => pre += e.width);

scale = maxWidth / totalWidth;
}

return PlutoAutoSizeHelper.items(
return PlutoAutoSizeHelper.items<PlutoColumn>(
maxSize: maxWidth,
length: columns.length,
itemMinSize: PlutoGridSettings.minColumnWidth,
items: columns,
isSuppressed: (e) => e.suppressedAutoSize,
getItemSize: (e) => e.width,
getItemMinSize: (e) => e.minWidth,
setItemSize: (e, size) => e.width = size,
mode: columnsAutoSizeMode,
scale: scale,
);
}

Expand Down
4 changes: 4 additions & 0 deletions lib/src/manager/state/column_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,10 @@ mixin ColumnState implements IPlutoGridState {
PlutoMoveDirection.right,
correctHorizontalOffset,
);

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
activateColumnsAutoSize();
});
}

@override
Expand Down
58 changes: 28 additions & 30 deletions lib/src/manager/state/visibility_layout_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,44 @@ abstract class IVisibilityLayoutState {
mixin VisibilityLayoutState implements IPlutoGridState {
@override
void updateVisibilityLayout({bool notify = false}) {
if (refColumns.isEmpty) {
return;
}
if (refColumns.isEmpty) return;

double leftX = 0;
double bodyX = 0;
double rightX = 0;
_updateColumnSize();

PlutoAutoSize? autoSizeHelper;
_updateColumnPosition();

if (activatedColumnsAutoSize) {
double offsetMaxWidth = maxWidth!;
updateScrollViewport();

if (showFrozenColumn) {
if (hasLeftFrozenColumns) {
offsetMaxWidth -= PlutoGridSettings.gridBorderWidth;
}
if (notify) scroll.horizontal?.notifyListeners();
}

if (hasRightFrozenColumns) {
offsetMaxWidth -= PlutoGridSettings.gridBorderWidth;
}
void _updateColumnSize() {
if (!activatedColumnsAutoSize) return;

double offset = 0;

if (showFrozenColumn) {
if (hasLeftFrozenColumns) {
offset += PlutoGridSettings.gridBorderWidth;
}

autoSizeHelper = getColumnsAutoSizeHelper(
columns: refColumns,
maxWidth: offsetMaxWidth,
);
if (hasRightFrozenColumns) {
offset += PlutoGridSettings.gridBorderWidth;
}
}

for (final column in refColumns) {
if (autoSizeHelper != null) {
column.width = autoSizeHelper.getItemSize(column.width);
}
getColumnsAutoSizeHelper(
columns: refColumns,
maxWidth: maxWidth! - offset,
).update();
}

void _updateColumnPosition() {
double leftX = 0;
double bodyX = 0;
double rightX = 0;

for (final column in refColumns) {
if (showFrozenColumn) {
switch (column.frozen) {
case PlutoColumnFrozen.none:
Expand All @@ -73,11 +77,5 @@ mixin VisibilityLayoutState implements IPlutoGridState {
bodyX += column.width;
}
}

updateScrollViewport();

if (notify) {
scroll.horizontal?.notifyListeners();
}
}
}
Loading

0 comments on commit 93a0628

Please sign in to comment.