1use image::DynamicImage;
2use rvimage_domain::{RvResult, ShapeI};
3
4use crate::{
5 InstanceAnnotate, annotations_accessor_mut,
6 events::{Events, KeyCode},
7 history::{History, Record},
8 make_tool_transform,
9 result::trace_ok_err,
10 tools_data::{annotations::InstanceAnnotations, rot90_data::NRotations},
11 util::Visibility,
12 world::World,
13 world_annotations_accessor,
14};
15use std::mem;
16
17use super::{BBOX_NAME, BRUSH_NAME, Manipulate, bbox, brush};
18
19pub const ACTOR_NAME: &str = "Rot90";
20annotations_accessor_mut!(ACTOR_NAME, rot90_mut, "Rotation 90 didn't work", NRotations);
21world_annotations_accessor!(ACTOR_NAME, rot90, "Rotation 90 didn't work", NRotations);
22
23fn rot90_instannos_of_file<T>(
24 annos: Option<&mut InstanceAnnotations<T>>,
25 shape: ShapeI,
26) -> RvResult<()>
27where
28 T: InstanceAnnotate,
29{
30 if let Some(annos) = annos {
31 for elt in annos.elts_iter_mut() {
32 *elt = mem::take(elt).rot90_with_image_ntimes(shape, 1)?;
33 }
34 }
35 Ok(())
36}
37
38fn rot90_instannos_once(world: &mut World, shape: ShapeI) -> RvResult<()> {
39 macro_rules! rot {
40 ($name:expr, $module:ident) => {
41 let annos = $module::get_annos_mut(world);
42 rot90_instannos_of_file(annos, shape)?;
43 if let Some(d) = $module::get_options_mut(world) {
44 d.core.is_redraw_annos_triggered = true;
45 }
46 world.request_redraw_annotations($name, Visibility::None);
47 };
48 }
49 rot!(BRUSH_NAME, brush);
50 rot!(BBOX_NAME, bbox);
51 Ok(())
52}
53
54pub fn rotate90(world: &World, im: DynamicImage, file: &str) -> RvResult<DynamicImage> {
55 let data = world.data.tools_data_map[ACTOR_NAME].specifics.rot90()?;
56 let data_of_file = data.annotations_map().get(file);
57 Ok(if let Some((nrot, _)) = &data_of_file {
58 match nrot {
59 NRotations::Zero => im,
60 NRotations::One => im.rotate270(),
61 NRotations::Two => im.rotate180(),
62 NRotations::Three => im.rotate90(),
63 }
64 } else {
65 im
66 })
67}
68
69fn rot90(mut world: World, n_rotations: NRotations, skip_annos: bool) -> World {
71 let shape = world.data.shape();
72 match n_rotations {
73 NRotations::Zero => (),
74 NRotations::One => {
75 if !skip_annos {
76 trace_ok_err(rot90_instannos_once(&mut world, shape));
77 }
78 world.data.apply(|im| im.rotate270());
79 }
80 NRotations::Two => {
81 world.data.apply(|im| im.rotate180());
82 }
83 NRotations::Three => {
84 world.data.apply(|im| im.rotate90());
85 }
86 }
87 if !matches!(n_rotations, NRotations::Zero) {
88 world.set_zoom_box(None);
89 world.request_redraw_image();
90 }
91 world
92}
93#[derive(Clone, Copy, Debug)]
94pub struct Rot90;
95
96impl Rot90 {
97 fn key_pressed(
98 &mut self,
99 _events: &Events,
100 mut world: World,
101 mut history: History,
102 ) -> (World, History) {
103 let skip_annos = false;
104 world = rot90(world, NRotations::One, skip_annos);
105 if let Some(anno) = get_annos_mut(&mut world) {
106 *anno = anno.increase();
107 }
108 history.push(Record::new(world.clone(), ACTOR_NAME));
109 (world, history)
110 }
111}
112
113impl Manipulate for Rot90 {
114 fn new() -> Self {
115 Self {}
116 }
117
118 fn on_filechange(&mut self, mut world: World, history: History) -> (World, History) {
119 use_currentimageshape_for_annos(&mut world);
120 if let Some(nrot) = get_annos_if_some(&world).copied() {
121 let skip_annos = true;
122 world = rot90(world, nrot, skip_annos);
123 }
124 (world, history)
125 }
126
127 fn events_tf(&mut self, world: World, history: History, event: &Events) -> (World, History) {
128 let (world, history) = make_tool_transform!(
129 self,
130 world,
131 history,
132 event,
133 [(pressed, KeyCode::R, key_pressed)]
134 );
135 (world, history)
136 }
137}