Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/assets/resize_scale.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 11 additions & 3 deletions packages/box_transform/lib/src/geometry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,9 @@ class Box {
}

/// Constrains the given [child] box instance within the bounds of this box.
/// This function will preserve the sign of the child's width and height.
/// It will also maintain the aspect ratio of the child if the [aspectRatio]
/// is specified.
///
/// [child] the child box to clamp inside this box.
/// [resizeMode] defines how to contain the child, whether it should keep its
Expand All @@ -646,16 +649,21 @@ class Box {
final double clampedLeft = math.min(x, right - childWidth);
final double clampedTop = math.min(y, bottom - childHeight);

double newLeft = math.max(left, clampedLeft);
double newTop = math.max(top, clampedTop);
final double newLeft = math.max(left, clampedLeft);
final double newTop = math.max(top, clampedTop);
double newWidth = math.min(width, childWidth);
double newHeight = math.min(height, childHeight);

if (resizeMode.isScalable && aspectRatio != null) {
final double newAspectRatio = newWidth / newHeight;
final double widthAdjustment = newHeight * aspectRatio;
final double heightAdjustment = newWidth / aspectRatio;

if (aspectRatio < newAspectRatio) {
newHeight = math.min(height, heightAdjustment);
newWidth = newHeight * aspectRatio;
} else {
} else if (aspectRatio > newAspectRatio) {
newWidth = math.min(width, widthAdjustment);
newHeight = newWidth / aspectRatio;
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter_box_transform/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ class _ImageBoxState extends State<ImageBox> {
resizable: model.resizable,
hideHandlesWhenNotResizable: model.hideHandlesWhenNotResizable,
movable: model.movable,
flipChild: model.flipChild,
allowContentFlipping: model.flipChild,
flipWhileResizing: model.flipRectWhileResizing,
onTerminalSizeReached: (
bool reachedMinWidth,
Expand All @@ -429,7 +429,7 @@ class _ImageBoxState extends State<ImageBox> {
maxHeightReached = reachedMaxHeight;
});
},
childBuilder: (context, rect, flip) => Container(
contentBuilder: (context, rect, flip) => Container(
width: rect.width,
height: rect.height,
decoration: BoxDecoration(
Expand Down Expand Up @@ -557,7 +557,7 @@ class _ClampingRectState extends State<ClampingRect> {
hasShadow: false,
handleAlign: HandleAlign.inside,
),
childBuilder: (context, _, flip) => Container(
contentBuilder: (context, _, flip) => Container(
width: model.clampingRect.width,
height: model.clampingRect.height,
alignment: Alignment.bottomRight,
Expand Down
48 changes: 28 additions & 20 deletions packages/flutter_box_transform/lib/src/transformable_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class TransformableBox extends StatefulWidget {
/// [TransformableBox]. This is the physical widget you wish to show resizable
/// handles on. It's most commonly something like an image widget, but it
/// could be anything you want to have resizable & draggable box handles on.
final TransformableChildBuilder childBuilder;
final TransformableChildBuilder contentBuilder;

/// A builder function that is used to build the corners handles of the
/// [TransformableBox]. If you don't specify it, the default handles will be
Expand Down Expand Up @@ -234,44 +234,49 @@ class TransformableBox extends StatefulWidget {
/// corners of the rect.
final bool flipWhileResizing;

/// Whether to flip the child of the box when the box is flipped. If this is
/// set to true, the child will be flipped when the box is flipped.
final bool flipChild;
/// Decides whether to flip the contents of the box when the box is flipped.
/// If this is set to true, the contents will be flipped when the box is
/// flipped.
final bool allowContentFlipping;

/// How to align the handles.
final HandleAlign handleAlign;

/// Creates a [TransformableBox] widget.
const TransformableBox({
super.key,
required this.childBuilder,
required this.contentBuilder,
this.onChanged,
this.onMoved,
this.onResized,
this.controller,
this.cornerHandleBuilder = _defaultCornerHandleBuilder,
this.sideHandleBuilder = _defaultSideHandleBuilder,
this.handleTapSize = 24,
// raw

// Additional controls.
this.resizable = true,
this.movable = true,
this.flipWhileResizing = true,
this.allowContentFlipping = true,
this.handleAlign = HandleAlign.center,
this.hideHandlesWhenNotResizable = true,

// Raw values.
Rect? rect,
Flip? flip,
Rect? clampingRect,
BoxConstraints? constraints,
ResolveResizeModeCallback? resolveResizeModeCallback,
// terminal update events

// Terminal update events.
this.onMinWidthReached,
this.onMaxWidthReached,
this.onMinHeightReached,
this.onMaxHeightReached,
this.onTerminalWidthReached,
this.onTerminalHeightReached,
this.onTerminalSizeReached,
this.resizable = true,
this.hideHandlesWhenNotResizable = true,
this.movable = true,
this.flipWhileResizing = true,
this.flipChild = true,
this.handleAlign = HandleAlign.center,
}) : assert(
controller == null ||
(rect == null &&
Expand All @@ -281,8 +286,8 @@ class TransformableBox extends StatefulWidget {
resolveResizeModeCallback == null),
'You can either provide a [controller] OR a [box], [flip], '
'[clampingRect], [constraints], and [resolveResizeModeCallback]. '
'You cannot use any of those properties when providing a controller and'
'vice versa.',
'You cannot use any of those properties when providing a controller '
'and vice versa.',
),
rect = rect ?? Rect.zero,
flip = flip ?? Flip.none,
Expand Down Expand Up @@ -317,7 +322,7 @@ class _TransformableBoxState extends State<TransformableBox> {
..movable = widget.movable
..resizable = widget.resizable
..flipWhileResizing = widget.flipWhileResizing
..flipChild = widget.flipChild;
..flipChild = widget.allowContentFlipping;
}
}

Expand All @@ -344,7 +349,7 @@ class _TransformableBoxState extends State<TransformableBox> {
..hideHandlesWhenNotResizable = widget.hideHandlesWhenNotResizable
..movable = widget.movable
..flipWhileResizing = widget.flipWhileResizing
..flipChild = widget.flipChild;
..flipChild = widget.allowContentFlipping;
}

// Return if the controller is external.
Expand All @@ -355,13 +360,16 @@ class _TransformableBoxState extends State<TransformableBox> {
if (oldWidget.rect != widget.rect) {
controller.rect = widget.rect;
}

if (oldWidget.flip != widget.flip) {
controller.flip = widget.flip;
}

if (oldWidget.resolveResizeModeCallback !=
widget.resolveResizeModeCallback) {
controller.resolveResizeModeCallback = widget.resolveResizeModeCallback;
}

if (oldWidget.clampingRect != widget.clampingRect) {
controller.clampingRect = widget.clampingRect;
controller.recalculatePosition(notify: false);
Expand All @@ -386,8 +394,8 @@ class _TransformableBoxState extends State<TransformableBox> {
controller.movable = widget.movable;
}

if (oldWidget.flipChild != widget.flipChild) {
controller.flipChild = widget.flipChild;
if (oldWidget.allowContentFlipping != widget.allowContentFlipping) {
controller.flipChild = widget.allowContentFlipping;
}

if (oldWidget.flipWhileResizing != widget.flipWhileResizing) {
Expand Down Expand Up @@ -490,7 +498,7 @@ class _TransformableBoxState extends State<TransformableBox> {
child: Transform.scale(
scaleX: controller.flipChild && flip.isHorizontal ? -1 : 1,
scaleY: controller.flipChild && flip.isVertical ? -1 : 1,
child: widget.childBuilder(context, box, flip),
child: widget.contentBuilder(context, box, flip),
),
),
),
Expand Down