Skip to content

Commit 297c1ae

Browse files
authored
Merge pull request #49 from bluefireteam/feat/rotate-controls
feat: adding rotate features
2 parents 9b427e3 + 81a830d commit 297c1ae

File tree

5 files changed

+138
-1
lines changed

5 files changed

+138
-1
lines changed

packages/mini_sprite_editor/lib/l10n/arb/app_en.arb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@
215215
"flipHorizontally": "Flip horizontally",
216216
"@flipHorizontally": {
217217
"description": "Label for flipping the sprite horizontally"
218+
},
219+
"rotateClockwise": "Rotate clockwise",
220+
"@rotateClockwise": {
221+
"description": "Label for rotating the sprite clockwise"
222+
},
223+
"rotateCounterClockwise": "Rotate counter clockwise",
224+
"@rotateCounterClockwise": {
225+
"description": "Label for rotating the sprite counter clockwise"
218226
}
219-
220227
}

packages/mini_sprite_editor/lib/sprite/cubit/sprite_cubit.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ class SpriteCubit extends ReplayCubit<SpriteState> {
9393
emit(state.copyWith(pixels: newPixels));
9494
}
9595

96+
void rotateSpriteClockwise() {
97+
final newPixels = List.generate(
98+
state.pixels[0].length,
99+
(i) => List.generate(state.pixels.length, (j) => -1),
100+
);
101+
102+
for (var y = 0; y < state.pixels.length; y++) {
103+
for (var x = 0; x < state.pixels[y].length; x++) {
104+
newPixels[x][state.pixels.length - y - 1] = state.pixels[y][x];
105+
}
106+
}
107+
108+
emit(state.copyWith(pixels: newPixels));
109+
}
110+
111+
void rotateSpriteCounterClockwise() {
112+
final newPixels = List.generate(
113+
state.pixels[0].length,
114+
(i) => List.generate(state.pixels.length, (j) => -1),
115+
);
116+
117+
for (var y = 0; y < state.pixels.length; y++) {
118+
for (var x = 0; x < state.pixels[y].length; x++) {
119+
newPixels[state.pixels[0].length - x - 1][y] = state.pixels[y][x];
120+
}
121+
}
122+
123+
emit(state.copyWith(pixels: newPixels));
124+
}
125+
96126
Offset _projectOffset(Offset position, double pixelSize) {
97127
final projected = position / pixelSize;
98128
final x = projected.dx.floorToDouble();

packages/mini_sprite_editor/lib/sprite/view/sprite_page.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,24 @@ class SpriteView extends StatelessWidget {
191191
child: const Icon(Icons.transform),
192192
),
193193
),
194+
IconButton(
195+
key: const Key('rotate_clockwise_key'),
196+
onPressed: () async {
197+
context.read<SpriteCubit>().rotateSpriteClockwise();
198+
},
199+
tooltip: l10n.rotateClockwise,
200+
icon: const Icon(Icons.rotate_right),
201+
),
202+
IconButton(
203+
key: const Key('rotate_counter_clockwise_key'),
204+
onPressed: () async {
205+
context
206+
.read<SpriteCubit>()
207+
.rotateSpriteCounterClockwise();
208+
},
209+
tooltip: l10n.rotateCounterClockwise,
210+
icon: const Icon(Icons.rotate_left),
211+
),
194212
IconButton(
195213
key: const Key('copy_to_clipboard_key'),
196214
onPressed: () {

packages/mini_sprite_editor/test/sprite/cubit/sprite_cubit_test.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,46 @@ void main() {
9797
expect(cubit.state, equals(expected));
9898
});
9999

100+
test('rotate clockwise', () {
101+
final cubit = SpriteCubit();
102+
final state = SpriteState.initial().copyWith(
103+
pixels: [
104+
[1, 1],
105+
[0, 0],
106+
],
107+
);
108+
final expected = SpriteState.initial().copyWith(
109+
pixels: [
110+
[0, 1],
111+
[0, 1],
112+
],
113+
);
114+
cubit
115+
..setSprite(state.pixels)
116+
..rotateSpriteClockwise();
117+
expect(cubit.state, equals(expected));
118+
});
119+
120+
test('rotate counter clockwise', () {
121+
final cubit = SpriteCubit();
122+
final state = SpriteState.initial().copyWith(
123+
pixels: [
124+
[1, 1],
125+
[0, 0],
126+
],
127+
);
128+
final expected = SpriteState.initial().copyWith(
129+
pixels: [
130+
[1, 0],
131+
[1, 0],
132+
],
133+
);
134+
cubit
135+
..setSprite(state.pixels)
136+
..rotateSpriteCounterClockwise();
137+
expect(cubit.state, equals(expected));
138+
});
139+
100140
group('importFromClipboard', () {
101141
late GetClipboardStub stub;
102142
final sprite = MiniSprite(const [

packages/mini_sprite_editor/test/sprite/view/sprite_view_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,48 @@ void main() async {
255255
});
256256
});
257257

258+
group('rotate', () {
259+
testWidgets('rotates clockwise', (tester) async {
260+
_mockState(
261+
spriteState: SpriteState.initial(),
262+
toolsState: ToolsState.initial(),
263+
configState: ConfigState.initial(),
264+
libraryState: LibraryState.initial(),
265+
);
266+
await tester.pumpTest(
267+
spriteCubit: spriteCubit,
268+
toolsCubit: toolsCubit,
269+
configCubit: configCubit,
270+
libraryCubit: libraryCubit,
271+
);
272+
273+
await tester.tap(find.byKey(const Key('rotate_clockwise_key')));
274+
await tester.pump();
275+
276+
verify(() => spriteCubit.rotateSpriteClockwise()).called(1);
277+
});
278+
279+
testWidgets('rotates counter clockwise', (tester) async {
280+
_mockState(
281+
spriteState: SpriteState.initial(),
282+
toolsState: ToolsState.initial(),
283+
configState: ConfigState.initial(),
284+
libraryState: LibraryState.initial(),
285+
);
286+
await tester.pumpTest(
287+
spriteCubit: spriteCubit,
288+
toolsCubit: toolsCubit,
289+
configCubit: configCubit,
290+
libraryCubit: libraryCubit,
291+
);
292+
293+
await tester.tap(find.byKey(const Key('rotate_counter_clockwise_key')));
294+
await tester.pump();
295+
296+
verify(() => spriteCubit.rotateSpriteCounterClockwise()).called(1);
297+
});
298+
});
299+
258300
group('tools', () {
259301
group('brush', () {
260302
testWidgets(

0 commit comments

Comments
 (0)