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
21 changes: 21 additions & 0 deletions lib/core/commands/command_factory/command_factory.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/text_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clip_area_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clip_path_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/path_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/ellipse_shape_command.dart';
Expand All @@ -16,6 +18,19 @@ class CommandFactory {
) =>
PathCommand(path, paint);

ClipPathCommand createClipPathCommand(
PathWithActionHistory path,
Paint paint, {
Offset? startPoint,
Offset? endPoint,
}) =>
ClipPathCommand(
path,
paint,
startPoint: startPoint,
endPoint: endPoint,
);

LineCommand createLineCommand(
PathWithActionHistory path,
Paint paint,
Expand Down Expand Up @@ -72,4 +87,10 @@ class CommandFactory {
SprayCommand createSprayCommand(List<Offset> points, Paint paint) {
return SprayCommand(points, paint);
}

ClipAreaCommand createClipAreaCommand(
PathWithActionHistory path,
Paint paint,
) =>
ClipAreaCommand(path, paint);
}
6 changes: 6 additions & 0 deletions lib/core/commands/command_implementation/command.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clip_area_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clip_path_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/path_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/ellipse_shape_command.dart';
Expand All @@ -24,6 +26,10 @@ abstract class Command with EquatableMixin {
return EllipseShapeCommand.fromJson(json);
case SerializerType.TEXT_COMMAND:
return TextCommand.fromJson(json);
case SerializerType.CLIP_PATH_COMMAND:
return ClipPathCommand.fromJson(json);
case SerializerType.CLIP_AREA_COMMAND:
return ClipAreaCommand.fromJson(json);
default:
return PathCommand.fromJson(json);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'dart:ui';

import 'package:json_annotation/json_annotation.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
import 'package:paintroid/core/commands/path_with_action_history.dart';
import 'package:paintroid/core/json_serialization/converter/paint_converter.dart';
import 'package:paintroid/core/json_serialization/converter/path_with_action_history_converter.dart';
import 'package:paintroid/core/json_serialization/versioning/serializer_version.dart';
import 'package:paintroid/core/json_serialization/versioning/version_strategy.dart';

part 'clip_area_command.g.dart';

@JsonSerializable()
class ClipAreaCommand extends GraphicCommand {
@JsonKey(includeToJson: true, includeFromJson: true)
final String type;
@JsonKey(includeToJson: true, includeFromJson: true)
final int version;

@PathWithActionHistoryConverter()
final PathWithActionHistory clipPathData;

ClipAreaCommand(
this.clipPathData,
Paint paint, {
this.type = SerializerType.CLIP_AREA_COMMAND,
int? version,
}) : version = version ??
VersionStrategyManager.strategy.getClipAreaCommandVersion(),
super(paint);

@override
void call(Canvas canvas) {
final Rect canvasBounds = canvas.getLocalClipBounds();

Path areaToClear = Path.combine(
PathOperation.difference,
Path()..addRect(canvasBounds),
clipPathData.path,
);

canvas.drawPath(
areaToClear,
Paint()
..blendMode = BlendMode.clear
..style = PaintingStyle.fill);
}

@override
List<Object?> get props => [paint, clipPathData, type, version];

factory ClipAreaCommand.fromJson(Map<String, dynamic> json) {
int version = json['version'] as int;

switch (version) {
case Version.v1:
return _$ClipAreaCommandFromJson(json);
case Version.v2:
// For different versions of ClipAreaCommand the deserialization
// has to be implemented manually.
// Autogenerated code can only be used for one version
default:
return _$ClipAreaCommandFromJson(json);
}
}

@override
Map<String, dynamic> toJson() => _$ClipAreaCommandToJson(this);
}

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import 'dart:ui';

import 'package:flutter/widgets.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
import 'package:paintroid/core/commands/path_with_action_history.dart';
import 'package:paintroid/core/json_serialization/converter/offset_converter.dart';
import 'package:paintroid/core/json_serialization/converter/path_with_action_history_converter.dart';
import 'package:paintroid/core/json_serialization/converter/paint_converter.dart';
import 'package:paintroid/core/json_serialization/versioning/serializer_version.dart';
import 'package:paintroid/core/json_serialization/versioning/version_strategy.dart';
import 'package:path_drawing/path_drawing.dart';

part 'clip_path_command.g.dart';

@JsonSerializable()
class ClipPathCommand extends GraphicCommand {
@JsonKey(includeToJson: true, includeFromJson: true)
final String type;
@JsonKey(includeToJson: true, includeFromJson: true)
final int version;

@PathWithActionHistoryConverter()
final PathWithActionHistory path;

@OffsetConverter()
final Offset? startPoint;
@OffsetConverter()
final Offset? endPoint;

ClipPathCommand(
this.path,
super.paint, {
this.startPoint,
this.endPoint,
this.type = SerializerType.CLIP_PATH_COMMAND,
int? version,
}) : version = version ??
VersionStrategyManager.strategy.getClipPathCommandVersion();

@override
void call(Canvas canvas) {
final dashLength = paint.strokeWidth * 4;
final dashGap = paint.strokeWidth * 2;

final dashedPath = dashPath(
path.path,
dashArray: CircularIntervalList<double>([dashLength, dashGap]),
);
canvas.drawPath(dashedPath, paint);

if (startPoint != null &&
endPoint != null &&
(startPoint!.dx != endPoint!.dx || startPoint!.dy != endPoint!.dy)) {
final solidPaint = Paint()
..color = paint.color
..style = PaintingStyle.stroke
..strokeWidth = paint.strokeWidth
..isAntiAlias = true;

final solidPath = Path()
..moveTo(startPoint!.dx, startPoint!.dy)
..lineTo(endPoint!.dx, endPoint!.dy);

canvas.drawPath(solidPath, solidPaint);
}
}

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

factory ClipPathCommand.fromJson(Map<String, dynamic> json) {
int version = json['version'] as int;

switch (version) {
case Version.v1:
return _$ClipPathCommandFromJson(json);
case Version.v2:
// For different versions of ClipPathCommand the deserialization
// has to be implemented manually.
// Autogenerated code can only be used for one version
default:
return _$ClipPathCommandFromJson(json);
}
}

@override
Map<String, dynamic> toJson() => _$ClipPathCommandToJson(this);
}

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

17 changes: 15 additions & 2 deletions lib/core/commands/command_manager/command_manager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'dart:ui';

import 'package:paintroid/core/commands/command_implementation/command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clip_area_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clip_path_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/text_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
Expand All @@ -23,13 +25,19 @@ class CommandManager {
_undoStack.add(command);
}

void removeCommand(Command commandToRemove) {
_undoStack.remove(commandToRemove);
}

void setUndoStack(List<Command> commands) {
_undoStack.clear();
_undoStack.addAll(commands);
}

void executeLastCommand(Canvas canvas) {
if (_undoStack.isEmpty) return;
if (_undoStack.isEmpty) {
return;
}
final lastCommand = _undoStack.last;
if (lastCommand is GraphicCommand) {
lastCommand.call(canvas);
Expand All @@ -45,7 +53,9 @@ class CommandManager {
}

void discardLastCommand() {
if (_undoStack.isNotEmpty) _undoStack.removeLast();
if (_undoStack.isNotEmpty) {
_undoStack.removeLast();
}
}

void clearUndoStack({Iterable<Command>? newCommands}) {
Expand Down Expand Up @@ -115,6 +125,9 @@ class CommandManager {
return ToolData.TEXT;
} else if (command.runtimeType == SprayCommand) {
return ToolData.SPRAY;
} else if (command.runtimeType == ClipAreaCommand ||
command.runtimeType == ClipPathCommand) {
return ToolData.CLIPPING;
} else {
return ToolData.BRUSH;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class SerializerVersion {
static const int ELLIPSE_SHAPE_COMMAND_VERSION = Version.v1;
static const int TEXT_COMMAND_VERSION = Version.v1;
static const int SPRAY_COMMAND_VERSION = Version.v1;
static const int CLIP_PATH_COMMAND_VERSION = Version.v1;
static const int CLIP_AREA_COMMAND_VERSION = Version.v1;
}

class Version {
Expand All @@ -25,4 +27,6 @@ class SerializerType {
static const String ELLIPSE_SHAPE_COMMAND = 'EllipseShapeCommand';
static const String TEXT_COMMAND = 'TextCommand';
static const String SPRAY_COMMAND = 'SprayCommand';
static const String CLIP_PATH_COMMAND = 'ClipPathCommand';
static const String CLIP_AREA_COMMAND = 'ClipAreaCommand';
}
12 changes: 12 additions & 0 deletions lib/core/json_serialization/versioning/version_strategy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ abstract class IVersionStrategy {
int getTextCommandVersion();

int getSprayCommandVersion();

int getClipPathCommandVersion();

int getClipAreaCommandVersion();
}

class ProductionVersionStrategy implements IVersionStrategy {
Expand All @@ -39,6 +43,14 @@ class ProductionVersionStrategy implements IVersionStrategy {

@override
int getSprayCommandVersion() => SerializerVersion.SPRAY_COMMAND_VERSION;

@override
int getClipPathCommandVersion() =>
SerializerVersion.CLIP_PATH_COMMAND_VERSION;

@override
int getClipAreaCommandVersion() =>
SerializerVersion.CLIP_AREA_COMMAND_VERSION;
}

class VersionStrategyManager {
Expand Down
Loading