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
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ analyzer:
exclude:
- lib/src/**.pb*.dart
- lib/**.g.dart
- test/**.mocks.dart
- test/**.mocks.dart
93 changes: 47 additions & 46 deletions lib/core/commands/command_factory/command_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clipboard_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/delete_region_command.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 @@ -23,16 +25,22 @@ class CommandFactory {
PathWithActionHistory path,
Paint paint, {
bool isCursor = false,
}) => PathCommand(path, paint, isCursorPath: isCursor);

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

LineCommand createLineCommand(
PathWithActionHistory path,
Paint paint,
Offset startPoint,
Offset endPoint,
) =>
LineCommand(path, paint, startPoint, endPoint);
) => LineCommand(path, paint, startPoint, endPoint);

SquareShapeCommand createSquareShapeCommand(
Paint paint,
Expand All @@ -41,9 +49,14 @@ class CommandFactory {
Offset bottomLeft,
Offset bottomRight,
ShapeStyle style,
) =>
SquareShapeCommand(
paint, topLeft, topRight, bottomLeft, bottomRight, style);
) => SquareShapeCommand(
paint,
topLeft,
topRight,
bottomLeft,
bottomRight,
style,
);

EllipseShapeCommand createEllipseShapeCommand(
Paint paint,
Expand All @@ -52,30 +65,15 @@ class CommandFactory {
Offset center,
ShapeStyle style,
double angle,
) =>
EllipseShapeCommand(
paint,
radiusX,
radiusY,
center,
style,
angle,
);
) => EllipseShapeCommand(paint, radiusX, radiusY, center, style, angle);

ClipboardCommand createClipboardCommand(
Paint paint,
Uint8List imageData,
ui.Offset offset,
double scale,
double rotation,
) =>
ClipboardCommand(
paint,
imageData,
offset,
scale,
rotation,
);
) => ClipboardCommand(paint, imageData, offset, scale, rotation);

TextCommand createTextCommand(
Offset point,
Expand All @@ -86,17 +84,16 @@ class CommandFactory {
double rotationAngle, {
double scaleX = 1.0,
double scaleY = 1.0,
}) =>
TextCommand(
point,
text,
style,
fontSize,
paint,
rotationAngle: rotationAngle,
scaleX: scaleX,
scaleY: scaleY,
);
}) => TextCommand(
point,
text,
style,
fontSize,
paint,
rotationAngle: rotationAngle,
scaleX: scaleX,
scaleY: scaleY,
);

StarShapeCommand createStarShapeCommand(
Paint paint,
Expand All @@ -106,16 +103,15 @@ class CommandFactory {
ShapeStyle style,
double radiusX,
double radiusY,
) =>
StarShapeCommand(
paint,
numPoints,
angle,
center,
style,
radiusX,
radiusY,
);
) => StarShapeCommand(
paint,
numPoints,
angle,
center,
style,
radiusX,
radiusY,
);

HeartShapeCommand createHeartShapeCommand(
Paint paint,
Expand All @@ -124,8 +120,7 @@ class CommandFactory {
double angle,
Offset center,
ShapeStyle style,
) =>
HeartShapeCommand(paint, width, height, angle, center, style);
) => HeartShapeCommand(paint, width, height, angle, center, style);

SprayCommand createSprayCommand(List<Offset> points, Paint paint) {
return SprayCommand(points, paint);
Expand All @@ -139,6 +134,12 @@ class CommandFactory {
region,
);

ClipAreaCommand createClipAreaCommand(
PathWithActionHistory path,
Paint paint,
) =>
ClipAreaCommand(path, paint);

ColorChangedCommand createColorChangedCommand(
Color oldColor,
Color newColor,
Expand Down
6 changes: 6 additions & 0 deletions lib/core/commands/command_implementation/command.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:equatable/equatable.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clipboard_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/delete_region_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 Down Expand Up @@ -39,6 +41,10 @@ abstract class Command with EquatableMixin {
return HeartShapeCommand.fromJson(json);
case SerializerType.STAR_SHAPE_COMMAND:
return StarShapeCommand.fromJson(json);
case SerializerType.CLIP_PATH_COMMAND:
return ClipPathCommand.fromJson(json);
case SerializerType.CLIP_AREA_COMMAND:
return ClipAreaCommand.fromJson(json);
case SerializerType.COLOR_CHANGED_COMMAND:
return ColorChangedCommand.fromJson(json);
default:
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,91 @@
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 * 2.5;
final dashGap = paint.strokeWidth * 1.5;
final dashArray = CircularIntervalList<double>([dashLength, dashGap]);

final borderPaint = Paint()
..color = const Color(0xFF000000)
..style = PaintingStyle.stroke
..strokeWidth = paint.strokeWidth * 1.2
..strokeCap = paint.strokeCap
..strokeJoin = paint.strokeJoin;

final combinedPath = Path()..addPath(path.path, Offset.zero);

if (startPoint != null &&
endPoint != null &&
(startPoint!.dx != endPoint!.dx || startPoint!.dy != endPoint!.dy)) {
combinedPath.lineTo(endPoint!.dx, endPoint!.dy);
}

final dashedPath = dashPath(
combinedPath,
dashArray: dashArray,
);

canvas.drawPath(dashedPath, borderPaint);
canvas.drawPath(dashedPath, paint);
}

@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);
}
Loading
Loading