Skip to main content

rvlib/tools/
rot90.rs

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    #[allow(clippy::indexing_slicing)]
56    let data = world.data.tools_data_map[ACTOR_NAME].specifics.rot90()?;
57    let data_of_file = data.annotations_map().get(file);
58    Ok(if let Some((nrot, _)) = &data_of_file {
59        match nrot {
60            NRotations::Zero => im,
61            NRotations::One => im.rotate270(),
62            NRotations::Two => im.rotate180(),
63            NRotations::Three => im.rotate90(),
64        }
65    } else {
66        im
67    })
68}
69
70/// rotate 90 degrees counter clockwise
71fn rot90(mut world: World, n_rotations: NRotations, skip_annos: bool) -> World {
72    let shape = world.data.shape();
73    match n_rotations {
74        NRotations::Zero => (),
75        NRotations::One => {
76            if !skip_annos {
77                trace_ok_err(rot90_instannos_once(&mut world, shape));
78            }
79            world.data.apply(|im| im.rotate270());
80        }
81        NRotations::Two => {
82            world.data.apply(|im| im.rotate180());
83        }
84        NRotations::Three => {
85            world.data.apply(|im| im.rotate90());
86        }
87    }
88    if !matches!(n_rotations, NRotations::Zero) {
89        world.set_zoom_box(None);
90        world.request_redraw_image();
91    }
92    world
93}
94#[derive(Clone, Copy, Debug)]
95pub struct Rot90;
96
97impl Rot90 {
98    fn key_pressed(
99        &mut self,
100        _events: &Events,
101        mut world: World,
102        mut history: History,
103    ) -> (World, History) {
104        let skip_annos = false;
105        world = rot90(world, NRotations::One, skip_annos);
106        if let Some(anno) = get_annos_mut(&mut world) {
107            *anno = anno.increase();
108            tracing::info!(
109                "Image rotated by 90°. Image has been rotated {} {}.",
110                anno.to_num(),
111                if anno.to_num() == 1 { "time" } else { "times" }
112            );
113        }
114        history.push(Record::new(world.clone(), ACTOR_NAME));
115        (world, history)
116    }
117}
118
119impl Manipulate for Rot90 {
120    fn new() -> Self {
121        Self {}
122    }
123
124    fn on_filechange(&mut self, mut world: World, history: History) -> (World, History) {
125        use_currentimageshape_for_annos(&mut world);
126        if let Some(nrot) = get_annos_if_some(&world).copied() {
127            let skip_annos = true;
128            world = rot90(world, nrot, skip_annos);
129        }
130        (world, history)
131    }
132
133    fn events_tf(&mut self, world: World, history: History, event: &Events) -> (World, History) {
134        let (world, history) = make_tool_transform!(
135            self,
136            world,
137            history,
138            event,
139            [(pressed, KeyCode::R, key_pressed)]
140        );
141        (world, history)
142    }
143}