Skip to content

Commit 6bf321f

Browse files
committed
PAINTROID-796 add clip area command
1 parent b99d04c commit 6bf321f

File tree

15 files changed

+291
-25
lines changed

15 files changed

+291
-25
lines changed

lib/core/commands/command_factory/command_factory.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:ui';
22

3+
import 'package:paintroid/core/commands/command_implementation/graphic/clip_area_command.dart';
34
import 'package:paintroid/core/commands/command_implementation/graphic/clip_path_command.dart';
45
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
56
import 'package:paintroid/core/commands/command_implementation/graphic/path_command.dart';
@@ -57,4 +58,10 @@ class CommandFactory {
5758
SprayCommand createSprayCommand(List<Offset> points, Paint paint) {
5859
return SprayCommand(points, paint);
5960
}
61+
62+
ClipAreaCommand createClipAreaCommand(
63+
PathWithActionHistory path,
64+
Paint paint,
65+
) =>
66+
ClipAreaCommand(path, paint);
6067
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import 'dart:ui';
2+
3+
import 'package:json_annotation/json_annotation.dart';
4+
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
5+
import 'package:paintroid/core/commands/path_with_action_history.dart';
6+
import 'package:paintroid/core/json_serialization/converter/paint_converter.dart';
7+
import 'package:paintroid/core/json_serialization/converter/path_with_action_history_converter.dart';
8+
import 'package:paintroid/core/json_serialization/versioning/serializer_version.dart';
9+
import 'package:paintroid/core/json_serialization/versioning/version_strategy.dart';
10+
11+
part 'clip_area_command.g.dart';
12+
13+
@JsonSerializable()
14+
class ClipAreaCommand extends GraphicCommand {
15+
@JsonKey(includeToJson: true, includeFromJson: true)
16+
final String type;
17+
@JsonKey(includeToJson: true, includeFromJson: true)
18+
final int version;
19+
20+
@PathWithActionHistoryConverter()
21+
final PathWithActionHistory clipPathData;
22+
23+
ClipAreaCommand(
24+
this.clipPathData,
25+
Paint paint, {
26+
this.type = SerializerType.CLIP_AREA_COMMAND,
27+
int? version,
28+
}) : version = version ??
29+
VersionStrategyManager.strategy.getClipAreaCommandVersion(),
30+
super(paint);
31+
32+
@override
33+
void call(Canvas canvas) {
34+
final Rect canvasBounds = canvas.getLocalClipBounds();
35+
36+
Path areaToClear = Path.combine(
37+
PathOperation.difference,
38+
Path()..addRect(canvasBounds),
39+
clipPathData.path,
40+
);
41+
42+
canvas.drawPath(
43+
areaToClear,
44+
Paint()
45+
..blendMode = BlendMode.clear
46+
..style = PaintingStyle.fill);
47+
}
48+
49+
@override
50+
List<Object?> get props => [paint, clipPathData, type, version];
51+
52+
factory ClipAreaCommand.fromJson(Map<String, dynamic> json) {
53+
int version = json['version'] as int;
54+
55+
switch (version) {
56+
case Version.v1:
57+
return _$ClipAreaCommandFromJson(json);
58+
case Version.v2:
59+
// For different versions of ClipAreaCommand the deserialization
60+
// has to be implemented manually.
61+
// Autogenerated code can only be used for one version
62+
default:
63+
return _$ClipAreaCommandFromJson(json);
64+
}
65+
}
66+
67+
@override
68+
Map<String, dynamic> toJson() => _$ClipAreaCommandToJson(this);
69+
}

lib/core/commands/command_implementation/graphic/clip_area_command.g.dart

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/core/commands/command_manager/command_manager.dart

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@ class CommandManager {
2222
_undoStack.add(command);
2323
}
2424

25+
void removeCommand(Command commandToRemove) {
26+
_undoStack.remove(commandToRemove);
27+
}
28+
2529
void setUndoStack(List<Command> commands) {
2630
_undoStack.clear();
2731
_undoStack.addAll(commands);
2832
}
2933

3034
void executeLastCommand(Canvas canvas) {
31-
if (_undoStack.isEmpty) return;
35+
if (_undoStack.isEmpty) {
36+
return;
37+
}
3238
final lastCommand = _undoStack.last;
3339
if (lastCommand is GraphicCommand) {
3440
lastCommand.call(canvas);
@@ -44,7 +50,9 @@ class CommandManager {
4450
}
4551

4652
void discardLastCommand() {
47-
if (_undoStack.isNotEmpty) _undoStack.removeLast();
53+
if (_undoStack.isNotEmpty) {
54+
_undoStack.removeLast();
55+
}
4856
}
4957

5058
void clearUndoStack({Iterable<Command>? newCommands}) {
@@ -110,8 +118,7 @@ class CommandManager {
110118
return ToolData.SHAPES;
111119
} else if (command.runtimeType == CircleShapeCommand) {
112120
return ToolData.SHAPES;
113-
}
114-
else if (command.runtimeType == SprayCommand) {
121+
} else if (command.runtimeType == SprayCommand) {
115122
return ToolData.SPRAY;
116123
} else {
117124
return ToolData.BRUSH;

lib/core/json_serialization/versioning/serializer_version.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class SerializerVersion {
77
static const int CIRCLE_SHAPE_COMMAND_VERSION = Version.v1;
88
static const int SPRAY_COMMAND_VERSION = Version.v1;
99
static const int CLIP_PATH_COMMAND_VERSION = Version.v1;
10+
static const int CLIP_AREA_COMMAND_VERSION = Version.v1;
1011
}
1112

1213
class Version {
@@ -25,4 +26,5 @@ class SerializerType {
2526
static const String CIRCLE_SHAPE_COMMAND = 'CircleShapeCommand';
2627
static const String SPRAY_COMMAND = 'SprayCommand';
2728
static const String CLIP_PATH_COMMAND = 'DashedPathCommand';
29+
static const String CLIP_AREA_COMMAND = 'ClipAreaCommand';
2830
}

lib/core/json_serialization/versioning/version_strategy.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ abstract class IVersionStrategy {
1414
int getSprayCommandVersion();
1515

1616
int getClipPathCommandVersion();
17+
18+
int getClipAreaCommandVersion();
1719
}
1820

1921
class ProductionVersionStrategy implements IVersionStrategy {
@@ -40,6 +42,10 @@ class ProductionVersionStrategy implements IVersionStrategy {
4042
@override
4143
int getClipPathCommandVersion() =>
4244
SerializerVersion.CLIP_PATH_COMMAND_VERSION;
45+
46+
@override
47+
int getClipAreaCommandVersion() =>
48+
SerializerVersion.CLIP_AREA_COMMAND_VERSION;
4349
}
4450

4551
class VersionStrategyManager {

lib/core/providers/object/tools/clipping_tool_provider.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:paintroid/core/commands/command_manager/command_manager_provider
55
import 'package:paintroid/core/commands/graphic_factory/graphic_factory_provider.dart';
66
import 'package:paintroid/core/enums/tool_types.dart';
77
import 'package:paintroid/core/tools/implementation/clipping_tool.dart';
8+
import 'package:paintroid/core/providers/object/tools/clipping_tool_state_provider.dart';
89

910
part 'clipping_tool_provider.g.dart';
1011

@@ -16,7 +17,8 @@ class ClippingToolProvider extends _$ClippingToolProvider {
1617
commandManager: ref.watch(commandManagerProvider),
1718
commandFactory: ref.watch(commandFactoryProvider),
1819
graphicFactory: ref.watch(graphicFactoryProvider),
19-
type: ToolType.CLIPPING, // Ensure ToolType.CLIPPING is defined
20+
clippingToolState: ref.watch(clippingToolState.notifier),
21+
type: ToolType.CLIPPING,
2022
);
2123
}
2224
}

lib/core/providers/object/tools/clipping_tool_provider.g.dart

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:riverpod_annotation/riverpod_annotation.dart';
2+
3+
part 'clipping_tool_state_provider.g.dart';
4+
5+
@riverpod
6+
class ClippingToolState extends _$ClippingToolState {
7+
@override
8+
bool build() {
9+
return false;
10+
}
11+
12+
void setHasActiveClipPath(bool hasActive) {
13+
state = hasActive;
14+
}
15+
16+
void clearClipPath() {
17+
state = false;
18+
}
19+
20+
bool get hasActiveClipPath => state;
21+
}

lib/core/providers/object/tools/clipping_tool_state_provider.g.dart

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)