Skip to content

Commit

Permalink
ref: Divider config (#26)
Browse files Browse the repository at this point in the history
* Add ResizableDivider config class

* Move divider config into new model

* Fix alignment of line within space

* Add indent and endIndent back to DividerPainter

* Clean up helper methods

* Rename height to size

* Add ResizableDivider tests
  • Loading branch information
andyhorn authored May 8, 2024
1 parent e182ca7 commit fafb38f
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 71 deletions.
15 changes: 10 additions & 5 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,13 @@ class _ExampleAppState extends State<ExampleApp> {
child: ResizableContainer(
controller: controller1,
direction: direction,
dividerWidth: 3.0,
dividerColor: Colors.blue,
dividerIndent: 12,
dividerEndIndent: 12,
divider: const ResizableDivider(
thickness: 3.0,
size: 5.0,
color: Colors.blue,
indent: 12,
endIndent: 12,
),
children: [
LayoutBuilder(
builder: (context, constraints) => Center(
Expand All @@ -121,7 +124,9 @@ class _ExampleAppState extends State<ExampleApp> {
),
ResizableContainer(
controller: controller2,
dividerColor: Colors.green,
divider: const ResizableDivider(
color: Colors.green,
),
direction: direction == Axis.horizontal
? Axis.vertical
: Axis.horizontal,
Expand Down
1 change: 1 addition & 0 deletions lib/flutter_resizable_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ library flutter_resizable_container;
export 'src/resizable_container.dart';
export 'src/resizable_controller.dart';
export 'src/resizable_child_data.dart';
export 'src/resizable_divider.dart';
14 changes: 7 additions & 7 deletions lib/src/divider_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ class DividerPainter extends CustomPainter {
const DividerPainter({
required this.color,
required this.direction,
required this.width,
required this.thickness,
this.indent,
this.endIndent,
});

final Axis direction;
final double width;
final double thickness;
final Color color;
final double? indent;
final double? endIndent;
Expand All @@ -34,7 +34,7 @@ class DividerPainter extends CustomPainter {
return Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = width;
..strokeWidth = thickness;
}

Path _getPath(Size size) {
Expand All @@ -55,7 +55,7 @@ class DividerPainter extends CustomPainter {
// The indent should be the lesser of the available height, the specified
// indent, or 0.
final indentAmount = min(size.height, indent ?? 0.0);
return Point(width / 2, indentAmount);
return Point(size.width / 2, indentAmount);
}

// If the direction is vertical, the divider is a horizontal line and the
Expand All @@ -64,7 +64,7 @@ class DividerPainter extends CustomPainter {
// The indent should be the lesser of the available width, the specified
// indent, or 0.
final indentAmount = min(size.width, indent ?? 0.0);
return Point(indentAmount, width / 2);
return Point(indentAmount, size.height / 2);
}

Point<double> _getEndingPoint(Size size) {
Expand All @@ -75,7 +75,7 @@ class DividerPainter extends CustomPainter {
// The indent should be the available height minus the indent amount,
// capped at a minimum of 0.
final indentAmount = max(0.0, size.height - (endIndent ?? 0));
return Point(width / 2, indentAmount);
return Point(size.width / 2, indentAmount);
}

// If the direction is vertical, the divider is a horizontal line and the
Expand All @@ -84,6 +84,6 @@ class DividerPainter extends CustomPainter {
// The indent should be the available width minus the indent amount, capped
// at a minimum of 0.
final indentAmount = max(0.0, size.width - (endIndent ?? 0));
return Point(indentAmount, width / 2);
return Point(indentAmount, size.height / 2);
}
}
39 changes: 8 additions & 31 deletions lib/src/resizable_container.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_resizable_container/flutter_resizable_container.dart';
import 'package:flutter_resizable_container/src/extensions/box_constraints_ext.dart';
import 'package:flutter_resizable_container/src/resizable_container_divider.dart';
import 'package:flutter_resizable_container/src/resizable_controller.dart';

/// A container that holds multiple child [Widget]s that can be resized.
///
Expand All @@ -17,11 +17,9 @@ class ResizableContainer extends StatelessWidget {
required this.children,
required this.controller,
required this.direction,
this.dividerColor,
this.dividerWidth = 2.0,
this.dividerIndent,
this.dividerEndIndent,
}) : assert(
ResizableDivider? divider,
}) : divider = divider ?? const ResizableDivider(),
assert(
children.length == controller.data.length,
'Controller must have as many data items as there are children.',
);
Expand All @@ -35,25 +33,8 @@ class ResizableContainer extends StatelessWidget {
/// The direction along which the child widgets will be laid and resized.
final Axis direction;

/// The width of the dividers between the children.
final double dividerWidth;

/// The color of the dividers between the children.
///
/// If not provided, Theme.of(context).dividerColor will be used.
final Color? dividerColor;

/// The indent of the divider at its start.
///
/// For dividers running from top-to-bottom, this indents the top.
/// For dividers running from left-to-right, this indents the left.
final double? dividerIndent;

/// The indent of the divider at its end.
///
/// For dividers running from top-to-bottom, this indents the bottom.
/// For dividers running from left-to-right, this indents the right.
final double? dividerEndIndent;
/// Configuration values for the dividing space/line between this container's [children].
final ResizableDivider divider;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -93,11 +74,7 @@ class ResizableContainer extends StatelessWidget {
),
if (i < children.length - 1) ...[
ResizableContainerDivider(
dividerColor:
dividerColor ?? Theme.of(context).dividerColor,
dividerWidth: dividerWidth,
indent: dividerIndent,
endIndent: dividerEndIndent,
config: divider,
direction: direction,
onResizeUpdate: (delta) => controller.adjustChildSize(
index: i,
Expand All @@ -116,7 +93,7 @@ class ResizableContainer extends StatelessWidget {

double _getAvailableSpace(BoxConstraints constraints) {
final totalSpace = constraints.maxForDirection(direction);
final dividerSpace = (children.length - 1) * dividerWidth;
final dividerSpace = (children.length - 1) * divider.size;
return totalSpace - dividerSpace;
}

Expand Down
59 changes: 36 additions & 23 deletions lib/src/resizable_container_divider.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import 'package:flutter/material.dart';
import 'package:flutter_resizable_container/src/divider_painter.dart';
import 'package:flutter_resizable_container/src/resizable_divider.dart';

class ResizableContainerDivider extends StatelessWidget {
const ResizableContainerDivider({
super.key,
required this.direction,
required this.onResizeUpdate,
required this.dividerWidth,
required this.dividerColor,
this.indent,
this.endIndent,
required this.config,
});

final Axis direction;
final void Function(double) onResizeUpdate;
final double dividerWidth;
final Color dividerColor;
final double? indent;
final double? endIndent;
final ResizableDivider config;

@override
Widget build(BuildContext context) {
final width = _getWidth();
final height = _getHeight();

return MouseRegion(
cursor: _getCursor(),
child: GestureDetector(
Expand All @@ -31,15 +29,18 @@ class ResizableContainerDivider extends StatelessWidget {
? (details) => onResizeUpdate(details.delta.dx)
: null,
child: SizedBox(
height: direction == Axis.horizontal ? double.infinity : dividerWidth,
width: direction == Axis.horizontal ? dividerWidth : double.infinity,
child: CustomPaint(
painter: DividerPainter(
direction: direction,
width: dividerWidth,
color: dividerColor,
indent: indent,
endIndent: endIndent,
height: height,
width: width,
child: Center(
child: CustomPaint(
size: Size(width, height),
painter: DividerPainter(
direction: direction,
color: config.color ?? Theme.of(context).dividerColor,
thickness: config.thickness,
indent: config.indent,
endIndent: config.endIndent,
),
),
),
),
Expand All @@ -48,11 +49,23 @@ class ResizableContainerDivider extends StatelessWidget {
}

MouseCursor _getCursor() {
switch (direction) {
case Axis.horizontal:
return SystemMouseCursors.resizeLeftRight;
case Axis.vertical:
return SystemMouseCursors.resizeUpDown;
}
return switch (direction) {
Axis.horizontal => SystemMouseCursors.resizeLeftRight,
Axis.vertical => SystemMouseCursors.resizeUpDown,
};
}

double _getHeight() {
return switch (direction) {
Axis.horizontal => double.infinity,
Axis.vertical => config.size,
};
}

double _getWidth() {
return switch (direction) {
Axis.horizontal => config.size,
Axis.vertical => double.infinity,
};
}
}
40 changes: 40 additions & 0 deletions lib/src/resizable_divider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';

class ResizableDivider {
const ResizableDivider({
this.thickness = 1.0,
this.size = 2.0,
this.color,
this.indent,
this.endIndent,
}) : assert(size >= thickness, '[size] must be >= [thickness].'),
assert(thickness > 0, '[thickness] must be > 0.');

/// The thickness of the line drawn within the divider.
///
/// Defaults to 1.0.
final double thickness;

/// The divider's size (height/width) extent.
/// The divider line will be drawn in the center of this space.
///
/// Defaults to 2.0.
final double size;

/// The color of the dividers between children.
///
/// Defaults to [ThemeData.dividerColor].
final Color? color;

/// The amount of empty space to the leading edge of the divider.
///
/// For dividers running from top-to-bottom, this adds empty space at the top.
/// For dividers running from left-to-right, this adds empty space to the left.
final double? indent;

/// The amount of empty space to the trailing edge of the divider.
///
/// For dividers running from top-to-bottom, this adds empty space at the bottom.
/// For dividers running from left-to-right, this adds empty space to the right.
final double? endIndent;
}
20 changes: 15 additions & 5 deletions test/resizable_container_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ void main() {
body: ResizableContainer(
controller: controller,
direction: Axis.horizontal,
dividerWidth: dividerWidth,
divider: const ResizableDivider(
size: dividerWidth,
),
children: const [
SizedBox.expand(
key: Key('BoxA'),
Expand Down Expand Up @@ -143,7 +145,9 @@ void main() {
body: ResizableContainer(
controller: controller,
direction: Axis.horizontal,
dividerWidth: dividerWidth,
divider: const ResizableDivider(
size: dividerWidth,
),
children: const [
SizedBox.expand(
key: Key('BoxA'),
Expand Down Expand Up @@ -231,7 +235,9 @@ void main() {
),
],
),
dividerWidth: dividerWidth,
divider: const ResizableDivider(
size: dividerWidth,
),
direction: Axis.horizontal,
children: const [
SizedBox.expand(
Expand Down Expand Up @@ -277,7 +283,9 @@ void main() {
),
],
),
dividerWidth: dividerWidth,
divider: const ResizableDivider(
size: dividerWidth,
),
direction: Axis.horizontal,
children: const [
SizedBox.expand(
Expand Down Expand Up @@ -325,7 +333,9 @@ void main() {
final container = ResizableContainer(
controller: controller,
direction: Axis.horizontal,
dividerWidth: 2.0,
divider: const ResizableDivider(
size: 2.0,
),
children: const [
SizedBox.expand(
key: Key('Box A'),
Expand Down
42 changes: 42 additions & 0 deletions test/resizable_divider_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'package:flutter_resizable_container/flutter_resizable_container.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
group(ResizableDivider, () {
group('thickness', () {
test('must be greater than 0', () {
expect(() => ResizableDivider(thickness: 0), throwsAssertionError);
});

test('accepts greater than 0', () {
expect(
() => const ResizableDivider(thickness: 1),
isNot(throwsAssertionError),
);
});
});

group('size', () {
test('throws if less than thickness', () {
expect(
() => ResizableDivider(thickness: 1, size: 0.5),
throwsAssertionError,
);
});

test('does not throw if the same as thickness', () {
expect(
() => const ResizableDivider(thickness: 1, size: 1),
isNot(throwsAssertionError),
);
});

test('does not throw if greater than thickness', () {
expect(
() => const ResizableDivider(thickness: 1, size: 2),
isNot(throwsAssertionError),
);
});
});
});
}

0 comments on commit fafb38f

Please sign in to comment.