Skip to content

Commit

Permalink
PAINTROID-660 Add LineTool
Browse files Browse the repository at this point in the history
rebase on restructured project
  • Loading branch information
Lenkomotive committed Feb 5, 2024
1 parent 13cde45 commit 670f12b
Show file tree
Hide file tree
Showing 26 changed files with 895 additions and 49 deletions.
1 change: 1 addition & 0 deletions packages/command/lib/command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export 'src/command_factory/command_factory.dart';
export 'src/command_implementation/command.dart';
export 'src/command_implementation/graphic/draw_path_command.dart';
export 'src/command_implementation/graphic/graphic_command.dart';
export 'src/command_implementation/graphic/line_path_command.dart';
export 'src/command_manager/command_manager.dart';
export 'src/command_manager/sync_command_manager.dart';
export 'utils/path_with_action_history.dart';
4 changes: 4 additions & 0 deletions packages/command/lib/src/command_factory/command_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ class CommandFactory {
DrawPathCommand createDrawPathCommand(
PathWithActionHistory path, Paint paint) =>
DrawPathCommand(path, paint);

LinePathCommand createLinePathCommand(PathWithActionHistory path, Paint paint,
Offset startPoint, Offset endPoint) =>
LinePathCommand(path, paint, startPoint, endPoint);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'dart:ui';

import 'package:command/command.dart';
import 'package:flutter/widgets.dart';
import 'package:tools/tools.dart';

class LinePathCommand extends GraphicCommand {
LinePathCommand(this.path, super.paint, this.startPoint, this.endPoint);

PathWithActionHistory path;
Offset startPoint;
Offset endPoint;
bool isSourcePath = false;

@override
void call(Canvas canvas) {
canvas.drawPath(path, paint);
}

@override
List<Object?> get props => [paint, path];

void drawVertices(Canvas canvas, VertexStack vertexStack) {
for (var vertex in vertexStack) {
canvas.drawCircle(
vertex.vertexCenter, Vertex.VERTEX_RADIUS, Vertex.getVertexPaint());
}
}

void setAsSourcePath() {
isSourcePath = true;
}

void updatePath(PathWithActionHistory newPath) {
path = newPath;
}

@override
Map<String, dynamic> toJson() {
// TODO: implement toJson
throw UnimplementedError();
}
}
9 changes: 9 additions & 0 deletions packages/command/lib/src/command_manager/command_manager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:ui';

import 'package:command/command.dart';
import 'package:tools/tools.dart';

abstract class CommandManager {
Iterable<Command> get history;
Expand All @@ -16,4 +17,12 @@ abstract class CommandManager {
void discardLastCommand();

void clearHistory({Iterable<Command>? newCommands});

void drawLineToolGhostPaths(
Canvas canvas,
LinePathCommand? ingoingGhostPathCommand,
LinePathCommand? outgoingGhostPathCommand,
);

void drawLineToolVertices(Canvas canvas, VertexStack vertexStack);
}
22 changes: 22 additions & 0 deletions packages/command/lib/src/command_manager/sync_command_manager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:ui';

import 'package:command/command.dart';
import 'package:tools/tools.dart';

class SyncCommandManager implements CommandManager {
SyncCommandManager({required List<Command> commands}) : _history = commands;
Expand Down Expand Up @@ -48,4 +49,25 @@ class SyncCommandManager implements CommandManager {
_history.addAll(newCommands);
}
}

@override
void drawLineToolGhostPaths(
Canvas canvas,
LinePathCommand? ingoingGhostPathCommand,
LinePathCommand? outgoingGhostPathCommand,
) {
ingoingGhostPathCommand?.call(canvas);
outgoingGhostPathCommand?.call(canvas);
}

@override
void drawLineToolVertices(Canvas canvas, VertexStack vertexStack) {
for (var vertex in vertexStack) {
canvas.drawCircle(
vertex.vertexCenter,
Vertex.VERTEX_RADIUS,
Vertex.getVertexPaint(),
);
}
}
}
2 changes: 2 additions & 0 deletions packages/command/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ dependencies:
path: ../component_library
io_library:
path: ../io_library
tools:
path: ../tools

dev_dependencies:
flutter_test:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:command/command_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:tools/tools.dart';
import 'package:workspace_screen/workspace_screen.dart';

class CanvasPainter extends ConsumerWidget {
Expand Down Expand Up @@ -51,15 +52,17 @@ class PaintingLayer extends ConsumerWidget {
final cachedImage = ref.watch(
canvasStateProvider.select((state) => state.cachedImage),
);
final commands = ref.watch(commandManagerProvider);
final commandManager = ref.watch(commandManagerProvider);

ref.watch(CanvasDirtyState.provider);

final currentTool = ref.read(toolBoxStateProvider).currentTool;

return RepaintBoundary(
child: Opacity(
opacity: 0.99,
child: CustomPaint(
foregroundPainter: CommandPainter(commands),
foregroundPainter: CommandPainter(commandManager, currentTool),
child: cachedImage != null
? RawImage(
image: cachedImage,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
import 'package:command/command.dart';
import 'package:flutter/material.dart';
import 'package:tools/tools.dart';

class CommandPainter extends CustomPainter {
CommandPainter(this.commandManager);
CommandPainter(this.commandManager, this.tool);

final CommandManager commandManager;
final Tool tool;

@override
void paint(Canvas canvas, Size size) {
canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
commandManager.executeLastCommand(canvas);
switch (tool.type) {
case ToolType.LINE:
_drawGhostPathsAndVertices(canvas);
break;
default:
commandManager.executeLastCommand(canvas);
break;
}
}

void _drawGhostPathsAndVertices(Canvas canvas) {
commandManager.drawLineToolGhostPaths(
canvas,
(tool as LineTool).ingoingGhostPathCommand,
(tool as LineTool).outgoingGhostPathCommand,
);
commandManager.drawLineToolVertices(
canvas,
(tool as LineTool).vertexStack,
);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class _DrawingCanvasState extends ConsumerState<DrawingCanvas> {
final _transformationController = TransformationController();
var _pointersOnScreen = 0;
var _isZooming = false;
Offset _lastPointerUpPosition = Offset.zero;

void _resetCanvasScale({bool fitToScreen = false}) =>
WidgetsBinding.instance.addPostFrameCallback((_) {
Expand Down Expand Up @@ -49,6 +50,7 @@ class _DrawingCanvasState extends ConsumerState<DrawingCanvas> {

void _onPointerUp(PointerUpEvent _) {
_pointersOnScreen--;
_lastPointerUpPosition = _.position;
if (_isZooming && _pointersOnScreen == 0) _isZooming = false;
}

Expand Down Expand Up @@ -81,9 +83,20 @@ class _DrawingCanvasState extends ConsumerState<DrawingCanvas> {

void _onInteractionEnd(ScaleEndDetails details) {
if (!_isZooming) {
// wird net gecalled irgendwie mit pointer up kombiniera

if (!multiScaleInProgress) {
_toolBoxStateNotifier.didTapUp();
_canvasStateNotifier.updateCachedImage();
_toolBoxStateNotifier.didTapUp(_globalToCanvas(_lastPointerUpPosition));
_canvasDirtyNotifier.repaint();
final currentTool = ref.read(toolBoxStateProvider).currentTool;
switch (currentTool.type) {
case ToolType.LINE:
_canvasStateNotifier.resetCanvasWithExistingCommands();
break;
default:
_canvasStateNotifier.updateCachedImage();
break;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,84 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:tools/tools.dart';
import 'package:workspace_screen/workspace_screen.dart';

class TopAppBar extends AppBar {
TopAppBar({Key? key, required String title})
: super(
key: key,
title: Text(title),
centerTitle: false,
actions: [const OverflowMenu()],
);
class TopAppBar extends ConsumerWidget implements PreferredSizeWidget {
final String title;

const TopAppBar({Key? key, required this.title}) : super(key: key);

@override
Widget build(BuildContext context, WidgetRef ref) {
final currentTool = ref.watch(toolBoxStateProvider).currentTool;

List<Widget> actions = [
if (currentTool.type == ToolType.LINE) ...[
PlusButton(onPressed: () {
_onPlusPressed(currentTool);
}),
CheckMarkButton(onPressed: () {
onCheckmarkPressed(currentTool);
}),
],
const OverflowMenu(),
];

return AppBar(
title: Text(title),
centerTitle: false,
actions: actions,
);
}

@override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);

void _onPlusPressed(Tool currentTool) {
switch (currentTool.type) {
case ToolType.LINE:
(currentTool as LineTool).onPlus();
break;
default:
break;
}
}

void onCheckmarkPressed(Tool currentTool) {
switch (currentTool.type) {
case ToolType.LINE:
(currentTool as LineTool).onCheckMark();
break;
default:
break;
}
}
}

class PlusButton extends StatelessWidget {
final VoidCallback onPressed;

const PlusButton({Key? key, required this.onPressed}) : super(key: key);

@override
Widget build(BuildContext context) {
return IconButton(
icon: const Icon(Icons.add),
onPressed: onPressed,
);
}
}

class CheckMarkButton extends StatelessWidget {
final VoidCallback onPressed;

const CheckMarkButton({Key? key, required this.onPressed}) : super(key: key);

@override
Widget build(BuildContext context) {
return IconButton(
icon: const Icon(Icons.check),
onPressed: onPressed,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,22 @@ class CanvasState extends _$CanvasState {
if (commands.isEmpty) {
state = state.copyWith(cachedImage: null);
} else {
final recorder = state.graphicFactory.createPictureRecorder();
final canvas = state.graphicFactory.createCanvasWithRecorder(recorder);
final size = state.size;
canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
state.commandManager.executeAllCommands(canvas);
final picture = recorder.endRecording();
final img =
await picture.toImage(size.width.toInt(), size.height.toInt());
state = state.copyWith(cachedImage: img);
await _executeAllCommandsOnCanvas();
}
}

Future<void> resetCanvasWithExistingCommands() async {
await _executeAllCommandsOnCanvas();
}

Future<void> _executeAllCommandsOnCanvas() async {
final recorder = state.graphicFactory.createPictureRecorder();
final canvas = state.graphicFactory.createCanvasWithRecorder(recorder);
final size = state.size;
canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
state.commandManager.executeAllCommands(canvas);
final picture = recorder.endRecording();
final img = await picture.toImage(size.width.toInt(), size.height.toInt());
state = state.copyWith(cachedImage: img);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 670f12b

Please sign in to comment.