Skip to content
Open
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
29 changes: 13 additions & 16 deletions .metadata
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
# This file should be version controlled and should not be manually edited.

version:
revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
channel: stable
revision: "603104015dd692ea3403755b55d07813d5cf8965"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- platform: android
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- platform: ios
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
create_revision: 603104015dd692ea3403755b55d07813d5cf8965
base_revision: 603104015dd692ea3403755b55d07813d5cf8965
- platform: linux
create_revision: 603104015dd692ea3403755b55d07813d5cf8965
base_revision: 603104015dd692ea3403755b55d07813d5cf8965
- platform: macos
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
- platform: web
create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
create_revision: 603104015dd692ea3403755b55d07813d5cf8965
base_revision: 603104015dd692ea3403755b55d07813d5cf8965
- platform: windows
create_revision: 603104015dd692ea3403755b55d07813d5cf8965
base_revision: 603104015dd692ea3403755b55d07813d5cf8965

# User provided section

Expand Down
2 changes: 2 additions & 0 deletions lib/src/domain/models/drawing_tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ enum DrawingTool {
eraser,
polygon,
square,
pan,
circle;

bool get isEraser => this == DrawingTool.eraser;
Expand All @@ -14,4 +15,5 @@ enum DrawingTool {
bool get isPolygon => this == DrawingTool.polygon;
bool get isSquare => this == DrawingTool.square;
bool get isCircle => this == DrawingTool.circle;
bool get isPan => this == DrawingTool.pan;
}
4 changes: 4 additions & 0 deletions lib/src/extensions/drawing_tool_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ extension DrawingToolExtensions on DrawingTool {
return StrokeType.square;
case DrawingTool.circle:
return StrokeType.circle;
default:
return StrokeType.normal;
}
}

Expand All @@ -32,6 +34,8 @@ extension DrawingToolExtensions on DrawingTool {
return SystemMouseCursors.precise;
case DrawingTool.fill:
return SystemMouseCursors.click;
case DrawingTool.pan:
return SystemMouseCursors.grab;
}
}
}
6 changes: 6 additions & 0 deletions lib/src/presentation/widgets/canvas_side_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ class _CanvasSideBarState extends State<CanvasSideBar> {
widget.drawingTool.value = DrawingTool.eraser,
tooltip: 'Eraser',
),
_IconBox(
iconData: Icons.pan_tool,
selected: widget.drawingTool.value == DrawingTool.pan,
onTap: () => widget.drawingTool.value = DrawingTool.pan,
tooltip: 'Pan',
),
_IconBox(
iconData: FontAwesomeIcons.square,
selected: widget.drawingTool.value == DrawingTool.square,
Expand Down
121 changes: 93 additions & 28 deletions lib/src/presentation/widgets/drawing_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ class _DrawingCanvasState extends State<DrawingCanvas> {

ValueNotifier<List<Stroke>> get _strokes => widget.strokesListenable;

final TransformationController _transformationController =
TransformationController();
double _minX = 0, _maxX = 0, _minY = 0, _maxY = 0;

CurrentStrokeValueNotifier get _currentStroke =>
widget.currentStrokeListenable;

void _onPointerDown(PointerDownEvent event) {
final box = context.findRenderObject() as RenderBox?;
if (box == null) return;
final offset = box.globalToLocal(event.position);
final localPosition =
_transformationController.toScene(event.localPosition);
// convert the offset to standard size so that it
// can be scaled back to the device size
final standardOffset = offset.scaleToStandard(box.size);
Expand All @@ -59,17 +65,66 @@ class _DrawingCanvasState extends State<DrawingCanvas> {
filled: widget.options.fillShape,
);
widget.onDrawingStrokeChanged?.call(_currentStroke.value);
_minX = _strokes.value.isEmpty
? localPosition.dx
: _minX < localPosition.dx
? _minX
: localPosition.dx;

_maxX = _strokes.value.isEmpty
? localPosition.dx
: _maxX > localPosition.dx
? _maxX
: localPosition.dx;

_minY = _strokes.value.isEmpty
? localPosition.dy
: _minY < localPosition.dy
? _minY
: localPosition.dy;

_maxY = _strokes.value.isEmpty
? localPosition.dy
: _minY > localPosition.dy
? _minY
: localPosition.dy;
}

void _onPointerMove(PointerMoveEvent event) {
final box = context.findRenderObject() as RenderBox?;
if (box == null) return;
final offset = box.globalToLocal(event.position);
final localPosition =
_transformationController.toScene(event.localPosition);
// convert the offset to standard size so that it
// can be scaled back to the device size
final standardOffset = offset.scaleToStandard(box.size);
_currentStroke.addPoint(standardOffset);
widget.onDrawingStrokeChanged?.call(_currentStroke.value);

_minX = _strokes.value.isEmpty
? localPosition.dx
: _minX < localPosition.dx
? _minX
: localPosition.dx;

_maxX = _strokes.value.isEmpty
? localPosition.dx
: _maxX > localPosition.dx
? _maxX
: localPosition.dx;

_minY = _strokes.value.isEmpty
? localPosition.dy
: _minY < localPosition.dy
? _minY
: localPosition.dy;

_maxY = _strokes.value.isEmpty
? localPosition.dy
: _minY > localPosition.dy
? _minY
: localPosition.dy;
}

void _onPointerUp(PointerUpEvent event) {
Expand All @@ -89,36 +144,46 @@ class _DrawingCanvasState extends State<DrawingCanvas> {
onPointerUp: _onPointerUp,
onPointerMove: _onPointerMove,
onPointerDown: _onPointerDown,
child: Stack(
children: [
Positioned.fill(
child: RepaintBoundary(
key: widget.canvasKey,
child: CustomPaint(
isComplex: true,
painter: _DrawingCanvasPainter(
strokesListenable: _strokes,
backgroundColor: widget.options.backgroundColor,
child: InteractiveViewer(
transformationController: _transformationController,
panEnabled: currentTool.isPan ? true : false,
minScale: 0.1,
maxScale: 5.0,
child: SizedBox(
width: (_maxX - _minX).abs() + 2000,
height: (_maxY - _minY).abs() + 2000,
child: Stack(
children: [
Positioned.fill(
child: RepaintBoundary(
key: widget.canvasKey,
child: CustomPaint(
isComplex: true,
painter: _DrawingCanvasPainter(
strokesListenable: _strokes,
backgroundColor: widget.options.backgroundColor,
),
),
),
),
),
),
),

// Draw the current stroke on top of the rest of the strokes.
Positioned.fill(
child: RepaintBoundary(
child: CustomPaint(
isComplex: true,
painter: _DrawingCanvasPainter(
strokeListenable: _currentStroke,
backgroundColor: widget.options.backgroundColor,
showGridListenable: _showGrid,
backgroundImageListenable: widget.backgroundImageListenable,

// Draw the current stroke on top of the rest of the strokes.
Positioned.fill(
child: RepaintBoundary(
child: CustomPaint(
isComplex: true,
painter: _DrawingCanvasPainter(
strokeListenable: _currentStroke,
backgroundColor: widget.options.backgroundColor,
showGridListenable: _showGrid,
backgroundImageListenable:
widget.backgroundImageListenable,
),
),
),
),
),
),
),
],
],
)),
),
),
);
Expand Down