Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PAINTROID-764 Add more shapes to Shapes Tool #103

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
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
26 changes: 26 additions & 0 deletions lib/core/commands/command_factory/command_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import 'dart:ui';
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/circle_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/heart_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/square_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/star_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/spray_command.dart';
import 'package:paintroid/core/commands/path_with_action_history.dart';

Expand Down Expand Up @@ -40,6 +42,30 @@ class CommandFactory {
) =>
CircleShapeCommand(paint, radius, center);

StarShapeCommand createStarShapeCommand(
Paint paint,
int numPoints,
double radius,
double angle,
Offset center,
) =>
StarShapeCommand(
paint,
numPoints,
radius,
angle,
center,
);

HeartShapeCommand createHeartShapeCommand(
Paint paint,
double width,
double height,
double angle,
Offset center,
) =>
HeartShapeCommand(paint, width, height, angle, center);

SprayCommand createSprayCommand(List<Offset> points, Paint paint) {
return SprayCommand(points, paint);
}
Expand Down
3 changes: 3 additions & 0 deletions lib/core/commands/command_implementation/command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:paintroid/core/commands/command_implementation/graphic/line_comm
import 'package:paintroid/core/commands/command_implementation/graphic/path_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/circle_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/square_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/star_shape_command.dart';
import 'package:paintroid/core/json_serialization/versioning/serializer_version.dart';

abstract class Command with EquatableMixin {
Expand All @@ -21,6 +22,8 @@ abstract class Command with EquatableMixin {
return SquareShapeCommand.fromJson(json);
case SerializerType.CIRCLE_SHAPE_COMMAND:
return CircleShapeCommand.fromJson(json);
case SerializerType.STAR_SHAPE_COMMAND:
return StarShapeCommand.fromJson(json);
default:
return PathCommand.fromJson(json);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'dart:math';

import 'package:flutter/widgets.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/shape_command.dart';
import 'package:paintroid/core/json_serialization/converter/offset_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';

part 'heart_shape_command.g.dart';

@JsonSerializable()
class HeartShapeCommand extends ShapeCommand {
final double width;
final double height;
final double angle;
@OffsetConverter()
final Offset center;

final int version;
final String type;

HeartShapeCommand(
super.paint,
this.width,
this.height,
this.angle,
this.center, {
int? version,
this.type = SerializerType.HEART_SHAPE_COMMAND,
}) : version = version ??
VersionStrategyManager.strategy.getHeartShapeCommandVersion();

Path get path => _getHeartPath(angle);

@override
void call(Canvas canvas) => canvas.drawPath(path, paint);

@override
List<Object?> get props => [paint, width, height, center];

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

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

switch (version) {
case Version.v1:
return _$HeartShapeCommandFromJson(json);
default:
return _$HeartShapeCommandFromJson(json);
}
}

Path _getHeartPath(double angle) {
Path path = Path();
final double w = width / 2;
final double h = height / 2;
const double rotationOffset = 3 * pi / 4;

path.moveTo(0, -h * 0.25);

path.cubicTo(
-w,
-h * 1.25,
-w * 1.25,
h * 0.25,
0,
h * 0.75,
);

path.cubicTo(
w * 1.25,
h * 0.25,
w,
-h * 1.25,
0,
-h * 0.25,
);

path.close();

final Matrix4 rotationMatrix = Matrix4.identity()
..rotateZ(angle + rotationOffset);

path = path.transform(rotationMatrix.storage);

path = path.shift(center);

return path;
}
}

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,78 @@
import 'dart:math';
import 'dart:ui';

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/shape_command.dart';
import 'package:paintroid/core/extensions/path_extension.dart';
import 'package:paintroid/core/json_serialization/converter/offset_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';

part 'star_shape_command.g.dart';

@JsonSerializable()
class StarShapeCommand extends ShapeCommand {
final int numberOfPoints;
final double radius;
final double angle;
@OffsetConverter()
final Offset center;

final int version;
final String type;

StarShapeCommand(
super.paint,
this.numberOfPoints,
this.radius,
this.angle,
this.center, {
int? version,
this.type = SerializerType.STAR_SHAPE_COMMAND,
}) : version = version ??
VersionStrategyManager.strategy.getStarShapeCommandVersion();

Path get path => _getStarPath();

@override
void call(Canvas canvas) => canvas.drawPath(path, paint);

@override
List<Object?> get props => [paint, numberOfPoints, radius, center];

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

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

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

Path _getStarPath() {
final path = Path();
final innerRadius = radius / 2;
final angleStep = pi / numberOfPoints;
for (int i = 0; i < numberOfPoints * 2; i++) {
final currentRadius = (i % 2 == 0) ? radius : innerRadius;
final currentAngle = i * angleStep + angle;
final point = Offset(
center.dx + currentRadius * cos(currentAngle),
center.dy + currentRadius * sin(currentAngle),
);
i == 0 ? path.moveToOffset(point) : path.lineToOffset(point);
}
path.close();
return path;
}
}

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

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

import 'package:flutter/material.dart';
import 'package:paintroid/core/commands/command_implementation/command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/circle_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/heart_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/square_shape_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/shape/star_shape_command.dart';
import 'package:paintroid/core/tools/line_tool/vertex.dart';
import 'package:paintroid/core/tools/line_tool/vertex_stack.dart';
import 'package:paintroid/core/tools/tool_data.dart';
Expand Down Expand Up @@ -110,8 +113,11 @@ class CommandManager {
return ToolData.SHAPES;
} else if (command.runtimeType == CircleShapeCommand) {
return ToolData.SHAPES;
}
else if (command.runtimeType == SprayCommand) {
} else if (command.runtimeType == StarShapeCommand) {
return ToolData.SHAPES;
} else if (command.runtimeType == HeartShapeCommand) {
return ToolData.SHAPES;
} else if (command.runtimeType == SprayCommand) {
return ToolData.SPRAY;
} else {
return ToolData.BRUSH;
Expand Down
27 changes: 8 additions & 19 deletions lib/core/database/project_database.g.dart

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

5 changes: 1 addition & 4 deletions lib/core/enums/shape_type.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
enum ShapeType {
circle,
square,
}
enum ShapeType { circle, square, star, heart }
5 changes: 1 addition & 4 deletions lib/core/json_serialization/converter/offset_converter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ class OffsetConverter implements JsonConverter<Offset, Map<String, dynamic>> {

@override
Map<String, dynamic> toJson(Offset offset) {
return <String, dynamic>{
'dx': offset.dx,
'dy': offset.dy,
};
return <String, dynamic>{'dx': offset.dx, 'dy': offset.dy};
}
}
Loading
Loading