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
142 changes: 131 additions & 11 deletions packages/flutter_box_transform/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ class MyApp extends StatelessWidget {
class PlaygroundModel with ChangeNotifier {
Rect rect = Rect.zero;
Flip flip = Flip.none;

bool showSecondImageBox = false;
Rect rect2 = Rect.zero;
Flip flip2 = Flip.none;

int lastRectAdjusted = 1; // 1 or 2

Rect clampingRect = Rect.largest;
Rect? playgroundArea;
late BoxConstraints constraints = const BoxConstraints(
Expand All @@ -73,6 +80,7 @@ class PlaygroundModel with ChangeNotifier {
bool constraintsEnabled = false;
bool resizable = true;
bool movable = true;
bool hideHandlesWhenNotResizable = true;

void reset(BuildContext context) {
final Size size = MediaQuery.of(context).size;
Expand All @@ -85,6 +93,17 @@ class PlaygroundModel with ChangeNotifier {
kInitialHeight,
);
flip = Flip.none;

rect2 = Rect.fromLTWH(
(width - kInitialWidth) / 3,
(height - kInitialHeight) / 3,
kInitialWidth,
kInitialHeight,
);
flip2 = Flip.none;

lastRectAdjusted = 1;

clampingRect = Rect.fromLTWH(
0,
0,
Expand All @@ -101,13 +120,22 @@ class PlaygroundModel with ChangeNotifier {
movable = true;
clampingEnabled = false;
constraintsEnabled = false;
hideHandlesWhenNotResizable = true;

notifyListeners();
}

void onRectChanged(UITransformResult result) {
rect = result.rect;
flip = result is UIResizeResult ? result.flip : flip;
lastRectAdjusted = 1;
notifyListeners();
}

void onRect2Changed(UITransformResult result) {
rect2 = result.rect;
flip2 = result is UIResizeResult ? result.flip : flip;
lastRectAdjusted = 2;
notifyListeners();
}

Expand Down Expand Up @@ -150,11 +178,13 @@ class PlaygroundModel with ChangeNotifier {

void flipHorizontally() {
flip = Flip.fromValue(flip.horizontalValue * -1, flip.verticalValue);
flip2 = Flip.fromValue(flip2.horizontalValue * -1, flip2.verticalValue);
notifyListeners();
}

void flipVertically() {
flip = Flip.fromValue(flip.horizontalValue, flip.verticalValue * -1);
flip2 = Flip.fromValue(flip2.horizontalValue, flip2.verticalValue * -1);
notifyListeners();
}

Expand All @@ -178,6 +208,16 @@ class PlaygroundModel with ChangeNotifier {
notifyListeners();
}

void toggleHideHandlesWhenNotResizable(bool enabled) {
hideHandlesWhenNotResizable = enabled;
notifyListeners();
}

void toggleShowSecondImageBox(bool enabled) {
showSecondImageBox = enabled;
notifyListeners();
}

void onClampingRectChanged({
double? left,
double? top,
Expand Down Expand Up @@ -230,7 +270,7 @@ const double kSidePanelWidth = 300;
const double kInitialWidth = 400;
const double kInitialHeight = 300;
const double kStrokeWidth = 1.5;
const Color kGridColor = Color(0x7FC3E8F3);
const Color kGridColor = Color.fromARGB(126, 27, 181, 228);

class _PlaygroundState extends State<Playground> with WidgetsBindingObserver {
@override
Expand Down Expand Up @@ -311,7 +351,17 @@ class _PlaygroundState extends State<Playground> with WidgetsBindingObserver {
),
if (model.clampingEnabled && model.playgroundArea != null)
const ClampingRect(),
const ImageBox(),
ImageBox(
rect: model.rect,
flip: model.flip,
imageAsset: 'assets/images/landscape2.jpg',
onChanged: model.onRectChanged),
if (model.showSecondImageBox)
ImageBox(
rect: model.rect2,
flip: model.flip2,
imageAsset: 'assets/images/landscape.jpg',
onChanged: model.onRect2Changed),
],
),
),
Expand All @@ -323,7 +373,17 @@ class _PlaygroundState extends State<Playground> with WidgetsBindingObserver {
}

class ImageBox extends StatefulWidget {
const ImageBox({super.key});
const ImageBox(
{super.key,
required this.rect,
required this.flip,
required this.imageAsset,
required this.onChanged});

final Rect rect;
final Flip flip;
final String imageAsset;
final Function(TransformResult<Rect, Offset, Size>)? onChanged;

@override
State<ImageBox> createState() => _ImageBoxState();
Expand All @@ -340,13 +400,14 @@ class _ImageBoxState extends State<ImageBox> {
final PlaygroundModel model = context.watch<PlaygroundModel>();
final Color handleColor = Theme.of(context).colorScheme.primary;
return TransformableBox(
key: const ValueKey('image-box'),
rect: model.rect,
flip: model.flip,
key: ValueKey('image-box-${widget.imageAsset}'),
rect: widget.rect,
flip: widget.flip,
clampingRect: model.clampingEnabled ? model.clampingRect : null,
constraints: model.constraintsEnabled ? model.constraints : null,
onChanged: model.onRectChanged,
onChanged: widget.onChanged,
resizable: model.resizable,
hideHandlesWhenNotResizable: model.hideHandlesWhenNotResizable,
movable: model.movable,
flipChild: model.flipChild,
flipWhileResizing: model.flipRectWhileResizing,
Expand All @@ -373,8 +434,8 @@ class _ImageBoxState extends State<ImageBox> {
height: rect.height,
decoration: BoxDecoration(
color: Colors.white,
image: const DecorationImage(
image: AssetImage('assets/images/landscape2.jpg'),
image: DecorationImage(
image: AssetImage(widget.imageAsset),
fit: BoxFit.fill,
),
border: Border.symmetric(
Expand Down Expand Up @@ -646,12 +707,70 @@ class ControlPanel extends StatelessWidget {
),
),
const Divider(height: 1),
Container(
height: 44,
padding: const EdgeInsets.fromLTRB(16, 0, 6, 0),
alignment: Alignment.centerLeft,
child: Row(
children: [
Expanded(
child: Text(
'Hide corner/side controls if not resizable',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
SizedBox(
height: 20,
child: Transform.scale(
scale: 0.7,
child: Switch(
value: model.hideHandlesWhenNotResizable,
onChanged: (value) =>
model.toggleHideHandlesWhenNotResizable(value),
),
),
),
],
),
),
const Divider(height: 1),
const FlipControls(),
const Divider(height: 1),
const ClampingControls(),
const Divider(height: 1),
const ConstraintsControls(),
const Divider(height: 1),
Container(
height: 44,
padding: const EdgeInsets.fromLTRB(16, 0, 6, 0),
alignment: Alignment.centerLeft,
child: Row(
children: [
Expanded(
child: Text(
'Add second image',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
SizedBox(
height: 20,
child: Transform.scale(
scale: 0.7,
child: Switch(
value: model.showSecondImageBox,
onChanged: (value) =>
model.toggleShowSecondImageBox(value),
),
),
),
],
),
),
const Divider(height: 1),
],
),
),
Expand All @@ -665,12 +784,13 @@ class PositionControls extends StatelessWidget {
@override
Widget build(BuildContext context) {
final PlaygroundModel model = context.watch<PlaygroundModel>();
final Rect rect = model.rect;
final Rect rect = model.lastRectAdjusted == 1 ? model.rect : model.rect2;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
const SectionHeader('POSITION'),
SectionHeader(
'POSITION${model.lastRectAdjusted == 2 ? " of SECOND IMAGE" : ""}'),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
Expand Down
54 changes: 34 additions & 20 deletions packages/flutter_box_transform/lib/src/transformable_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ class TransformableBox extends StatefulWidget {
/// all resizing operations.
final bool resizable;

/// Whether the box should hide the corner/side resize controls when [resizable] is
/// false.
final bool hideHandlesWhenNotResizable;

/// Whether the box is movable or not. Setting this to false will disable
/// all moving operations.
final bool movable;
Expand Down Expand Up @@ -263,6 +267,7 @@ class TransformableBox extends StatefulWidget {
this.onTerminalHeightReached,
this.onTerminalSizeReached,
this.resizable = true,
this.hideHandlesWhenNotResizable = true,
this.movable = true,
this.flipWhileResizing = true,
this.flipChild = true,
Expand Down Expand Up @@ -336,6 +341,7 @@ class _TransformableBoxState extends State<TransformableBox> {
..constraints = widget.constraints
..resolveResizeModeCallback = widget.resolveResizeModeCallback
..resizable = widget.resizable
..hideHandlesWhenNotResizable = widget.hideHandlesWhenNotResizable
..movable = widget.movable
..flipWhileResizing = widget.flipWhileResizing
..flipChild = widget.flipChild;
Expand Down Expand Up @@ -370,6 +376,12 @@ class _TransformableBoxState extends State<TransformableBox> {
controller.resizable = widget.resizable;
}

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

if (oldWidget.movable != widget.movable) {
controller.movable = widget.movable;
}
Expand Down Expand Up @@ -482,26 +494,28 @@ class _TransformableBoxState extends State<TransformableBox> {
),
),
),
for (final handle in HandlePosition.corners)
_CornerHandleWidget(
key: ValueKey(handle),
handlePosition: handle,
handleTapSize: widget.handleTapSize,
builder: widget.cornerHandleBuilder,
onPointerDown: onHandlePanStart,
onPointerUpdate: onHandlePanUpdate,
onPointerUp: onHandlePanEnd,
),
for (final handle in HandlePosition.sides)
_SideHandleWidget(
key: ValueKey(handle),
handlePosition: handle,
handleTapSize: widget.handleTapSize,
builder: widget.sideHandleBuilder,
onPointerDown: onHandlePanStart,
onPointerUpdate: onHandlePanUpdate,
onPointerUp: onHandlePanEnd,
),
if (controller.resizable || !controller.hideHandlesWhenNotResizable)
for (final handle in HandlePosition.corners)
_CornerHandleWidget(
key: ValueKey(handle),
handlePosition: handle,
handleTapSize: widget.handleTapSize,
builder: widget.cornerHandleBuilder,
onPointerDown: onHandlePanStart,
onPointerUpdate: onHandlePanUpdate,
onPointerUp: onHandlePanEnd,
),
if (controller.resizable || !controller.hideHandlesWhenNotResizable)
for (final handle in HandlePosition.sides)
_SideHandleWidget(
key: ValueKey(handle),
handlePosition: handle,
handleTapSize: widget.handleTapSize,
builder: widget.sideHandleBuilder,
onPointerDown: onHandlePanStart,
onPointerUpdate: onHandlePanUpdate,
onPointerUp: onHandlePanEnd,
),
],
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ class TransformableBoxController extends ChangeNotifier {
/// all resizing operations.
bool resizable = true;

/// Whether the box should hide the corner/side resize controls when [resizable] is
/// false.
bool hideHandlesWhenNotResizable = true;

/// Whether to allow flipping of the box while resizing. If this is set to
/// true, the box will flip when the user drags the handles to opposite
/// corners of the rect.
Expand Down Expand Up @@ -143,6 +147,13 @@ class TransformableBoxController extends ChangeNotifier {
notifyListeners();
}

/// Whether the box should hide the corner/side resize controls when [resizable] is
/// false.
void setHideHandlesWhenNotResizable(bool hideHandlesWhenNotResizable) {
this.hideHandlesWhenNotResizable = hideHandlesWhenNotResizable;
notifyListeners();
}

/// Whether to allow flipping of the box while resizing. If this is set to
/// true, the box will flip when the user drags the handles to opposite
/// corners of the rect.
Expand Down