From e029129edd0463e770137602e0dc5c0108b114ea Mon Sep 17 00:00:00 2001 From: devFKS <97810571+devFKS@users.noreply.github.com> Date: Thu, 7 Jul 2022 20:46:39 -0500 Subject: [PATCH 1/3] Apply Min/Max Constraints --- lib/src/resizable_widget.dart | 11 +++ lib/src/resizable_widget_args_info.dart | 4 + lib/src/resizable_widget_child_data.dart | 4 +- lib/src/resizable_widget_model.dart | 117 ++++++++++++++++++----- 4 files changed, 113 insertions(+), 23 deletions(-) diff --git a/lib/src/resizable_widget.dart b/lib/src/resizable_widget.dart index c1ecc43..e947708 100644 --- a/lib/src/resizable_widget.dart +++ b/lib/src/resizable_widget.dart @@ -23,6 +23,13 @@ class ResizableWidget extends StatefulWidget { /// If this value is [null], [children] will be split into the same size. final List? percentages; + /// Applies a Maximum Percent of the screen each widget can occupy + /// One element must be set to null + final List? maxPercentages; + /// Applies a Minimum Percent of the screen each widget can occupy + /// One element must be set to null + final List? minPercentages; + /// When set to true, creates horizontal separators. @Deprecated('Use [isHorizontalSeparator] instead') final bool isColumnChildren; @@ -53,6 +60,8 @@ class ResizableWidget extends StatefulWidget { Key? key, required this.children, this.percentages, + this.maxPercentages, + this.minPercentages, @Deprecated('Use [isHorizontalSeparator] instead') this.isColumnChildren = false, this.isHorizontalSeparator = false, @@ -65,6 +74,8 @@ class ResizableWidget extends StatefulWidget { assert(percentages == null || percentages!.length == children.length); assert(percentages == null || percentages!.reduce((value, element) => value + element) == 1); + assert(maxPercentages == null || maxPercentages!.contains(null)); + assert(minPercentages == null || minPercentages!.contains(null)); } @override diff --git a/lib/src/resizable_widget_args_info.dart b/lib/src/resizable_widget_args_info.dart index 2e43b6b..9fc89d2 100644 --- a/lib/src/resizable_widget_args_info.dart +++ b/lib/src/resizable_widget_args_info.dart @@ -4,6 +4,8 @@ import 'resizable_widget.dart'; class ResizableWidgetArgsInfo { final List children; final List? percentages; + final List? maxPercentages; + final List? minPercentages; final bool isHorizontalSeparator; final bool isDisabledSmartHide; final double separatorSize; @@ -13,6 +15,8 @@ class ResizableWidgetArgsInfo { ResizableWidgetArgsInfo(ResizableWidget widget) : children = widget.children, percentages = widget.percentages, + maxPercentages = widget.maxPercentages, + minPercentages = widget.minPercentages, isHorizontalSeparator = // TODO: delete the deprecated member on the next minor update. // ignore: deprecated_member_use_from_same_package diff --git a/lib/src/resizable_widget_child_data.dart b/lib/src/resizable_widget_child_data.dart index f504b87..fdaadf0 100644 --- a/lib/src/resizable_widget_child_data.dart +++ b/lib/src/resizable_widget_child_data.dart @@ -6,5 +6,7 @@ class ResizableWidgetChildData { double? percentage; double? defaultPercentage; double? hidingPercentage; - ResizableWidgetChildData(this.widget, this.percentage); + double? maxPercentage; + double? minPercentage; + ResizableWidgetChildData(this.widget, this.percentage, this.maxPercentage, this.minPercentage); } diff --git a/lib/src/resizable_widget_model.dart b/lib/src/resizable_widget_model.dart index 3971178..2a4c1aa 100644 --- a/lib/src/resizable_widget_model.dart +++ b/lib/src/resizable_widget_model.dart @@ -7,6 +7,18 @@ import 'widget_size_info.dart'; typedef SeparatorFactory = Widget Function(SeparatorArgsBasicInfo basicInfo); +enum ResizableWidgetResizeImplReturnState { + VALID, + INVALID +} + +class ResizableWidgetResizeImplReturn { + ResizableWidgetResizeImplReturnState state; + double size; + double percent; + ResizableWidgetResizeImplReturn({required this.size, required this.percent, required this.state}); +} + class ResizableWidgetModel { final ResizableWidgetArgsInfo _info; final children = []; @@ -22,9 +34,14 @@ class ResizableWidgetModel { final size = originalChildren.length; final originalPercentages = _info.percentages ?? List.filled(size, 1 / size); + final maxPercentages = _info.maxPercentages; + final minPercentages = _info.minPercentages; for (var i = 0; i < size - 1; i++) { children.add(ResizableWidgetChildData( - originalChildren[i], originalPercentages[i])); + originalChildren[i], originalPercentages[i], + (maxPercentages != null ? maxPercentages[i] : null), + (minPercentages != null ? minPercentages[i] : null) + )); children.add(ResizableWidgetChildData( separatorFactory.call(SeparatorArgsBasicInfo( 2 * i + 1, @@ -33,10 +50,16 @@ class ResizableWidgetModel { _info.separatorSize, _info.separatorColor, )), - null)); + null, + null, + null, + )); } children.add(ResizableWidgetChildData( - originalChildren[size - 1], originalPercentages[size - 1])); + originalChildren[size - 1], originalPercentages[size - 1], + (maxPercentages != null ? maxPercentages[size - 1] : null), + (minPercentages != null ? minPercentages[size - 1] : null) + )); } void setSizeIfNeeded(BoxConstraints constraints) { @@ -63,35 +86,46 @@ class ResizableWidgetModel { } void resize(int separatorIndex, Offset offset) { - final leftSize = _resizeImpl(separatorIndex - 1, offset); - final rightSize = _resizeImpl(separatorIndex + 1, offset * (-1)); + ResizableWidgetResizeImplReturn leftReturn = _resizeImpl(separatorIndex - 1, offset, apply: false); + if(leftReturn.state != ResizableWidgetResizeImplReturnState.VALID) { + return; + } + + ResizableWidgetResizeImplReturn rightReturn = _resizeImpl(separatorIndex + 1, offset * (-1), apply: false); + if(rightReturn.state != ResizableWidgetResizeImplReturnState.VALID) { + return; + } + __applyResizeImpl(separatorIndex - 1, leftReturn); + __applyResizeImpl(separatorIndex + 1, rightReturn); - if (leftSize < 0) { + + if (leftReturn.size < 0) { _resizeImpl( separatorIndex - 1, _info.isHorizontalSeparator - ? Offset(0, -leftSize) - : Offset(-leftSize, 0)); + ? Offset(0, -leftReturn.size) + : Offset(-leftReturn.size, 0)); _resizeImpl( separatorIndex + 1, _info.isHorizontalSeparator - ? Offset(0, leftSize) - : Offset(leftSize, 0)); + ? Offset(0, leftReturn.size) + : Offset(leftReturn.size, 0)); } - if (rightSize < 0) { + if (rightReturn.size < 0) { _resizeImpl( separatorIndex - 1, _info.isHorizontalSeparator - ? Offset(0, rightSize) - : Offset(rightSize, 0)); + ? Offset(0, rightReturn.size) + : Offset(rightReturn.size, 0)); _resizeImpl( separatorIndex + 1, _info.isHorizontalSeparator - ? Offset(0, -rightSize) - : Offset(-rightSize, 0)); + ? Offset(0, -rightReturn.size) + : Offset(-rightReturn.size, 0)); } } + void callOnResized() { _info.onResized?.call(children .where((x) => x.widget is! Separator) @@ -136,13 +170,52 @@ class ResizableWidgetModel { return true; } - double _resizeImpl(int widgetIndex, Offset offset) { - final size = children[widgetIndex].size ?? 0; - children[widgetIndex].size = - size + (_info.isHorizontalSeparator ? offset.dy : offset.dx); - children[widgetIndex].percentage = - children[widgetIndex].size! / maxSizeWithoutSeparators!; - return children[widgetIndex].size!; + + ResizableWidgetResizeImplReturn _resizeImpl(int widgetIndex, Offset offset, {bool apply = true}) { + final size = children[widgetIndex].size ?? 0; + final appliedSize = size + (_info.isHorizontalSeparator ? offset.dy : offset.dx); + final appliedPercentage = size / maxSizeWithoutSeparators!; + + + /// Check if transformation will exceed the requested Min / Max value for the specific row / column + if( + ( + (children[widgetIndex].minPercentage != null) && + (children[widgetIndex].minPercentage! > appliedPercentage) && + ( + ((_info.isHorizontalSeparator == false) && (offset.dx < 0)) || + ((_info.isHorizontalSeparator == true) && (offset.dy < 0)) + ) + ) || + ( + (children[widgetIndex].maxPercentage != null) && + (children[widgetIndex].maxPercentage! < appliedPercentage) && + ( + ((_info.isHorizontalSeparator == false) && (offset.dx > 0)) || + ((_info.isHorizontalSeparator == true) && (offset.dy > 0)) + ) + ) + ) { + return ResizableWidgetResizeImplReturn( + size: children[widgetIndex].size!, + percent: children[widgetIndex].percentage!, + state: ResizableWidgetResizeImplReturnState.INVALID + ); + } + + ResizableWidgetResizeImplReturn _data = ResizableWidgetResizeImplReturn( + size: appliedSize, + percent: appliedPercentage, + state: ResizableWidgetResizeImplReturnState.VALID + ); + if(apply) { __applyResizeImpl(widgetIndex, _data); } + return _data; + } + + + void __applyResizeImpl(int widgetIndex, ResizableWidgetResizeImplReturn data){ + children[widgetIndex].size = data.size; + children[widgetIndex].percentage = data.percent; } bool _isNearlyZero(double size) { From bb42db9c22e4b2188224bdf64c220a64fbe6b723 Mon Sep 17 00:00:00 2001 From: devFKS <97810571+devFKS@users.noreply.github.com> Date: Fri, 8 Jul 2022 07:34:16 -0500 Subject: [PATCH 2/3] Use real numbers instead of nulls --- lib/src/resizable_widget.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/resizable_widget.dart b/lib/src/resizable_widget.dart index e947708..47a451c 100644 --- a/lib/src/resizable_widget.dart +++ b/lib/src/resizable_widget.dart @@ -24,10 +24,10 @@ class ResizableWidget extends StatefulWidget { final List? percentages; /// Applies a Maximum Percent of the screen each widget can occupy - /// One element must be set to null + /// At least one element must be set to double.infinity final List? maxPercentages; /// Applies a Minimum Percent of the screen each widget can occupy - /// One element must be set to null + /// At least one element must be set to 0.0 final List? minPercentages; /// When set to true, creates horizontal separators. @@ -74,8 +74,8 @@ class ResizableWidget extends StatefulWidget { assert(percentages == null || percentages!.length == children.length); assert(percentages == null || percentages!.reduce((value, element) => value + element) == 1); - assert(maxPercentages == null || maxPercentages!.contains(null)); - assert(minPercentages == null || minPercentages!.contains(null)); + assert(maxPercentages == null || maxPercentages!.contains(double.infinity)); + assert(minPercentages == null || minPercentages!.contains(0)); } @override From 2b0ab16b21570d99ebc0d82660ee0383ef826a4e Mon Sep 17 00:00:00 2001 From: devFKS <97810571+devFKS@users.noreply.github.com> Date: Fri, 8 Jul 2022 14:01:48 -0500 Subject: [PATCH 3/3] Fix too restrictive assertion --- lib/src/resizable_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/resizable_widget.dart b/lib/src/resizable_widget.dart index 47a451c..5b90a97 100644 --- a/lib/src/resizable_widget.dart +++ b/lib/src/resizable_widget.dart @@ -75,7 +75,7 @@ class ResizableWidget extends StatefulWidget { assert(percentages == null || percentages!.reduce((value, element) => value + element) == 1); assert(maxPercentages == null || maxPercentages!.contains(double.infinity)); - assert(minPercentages == null || minPercentages!.contains(0)); + assert(minPercentages == null || minPercentages!.reduce((value, element) => value! + element!)! < 1); } @override