Skip to main content

rvlib/tools/
mod.rs

1mod always_active_zoom;
2mod attributes;
3mod bbox;
4mod brush;
5mod core;
6mod instance_anno_shared;
7mod rot90;
8mod wand;
9mod zoom;
10use crate::{
11    history::{History, Record},
12    tools_data::{AttributesToolData, BboxToolData, BrushToolData, VisibleInactiveToolsState},
13    world::World,
14};
15
16pub use self::core::Manipulate;
17use crate::tools_data::Rot90ToolData;
18pub use always_active_zoom::AlwaysActiveZoom;
19pub use attributes::Attributes;
20pub use bbox::Bbox;
21pub use brush::Brush;
22pub use rot90::{Rot90, rotate90};
23use std::fmt::Debug;
24use tracing::info;
25pub use wand::{CmdServer, WandServer};
26pub use zoom::Zoom;
27pub const BBOX_NAME: &str = bbox::ACTOR_NAME;
28pub const BRUSH_NAME: &str = brush::ACTOR_NAME;
29pub const ZOOM_NAME: &str = "Zoom";
30pub const ROT90_NAME: &str = rot90::ACTOR_NAME;
31pub const ALWAYS_ACTIVE_ZOOM: &str = "AlwaysActiveZoom";
32pub const ATTRIBUTES_NAME: &str = "Attributes";
33
34macro_rules! make_tools {
35($(($tool:ident, $label:expr, $name:expr, $active:expr, $always_active:expr, $data_default:expr, $visible_inactive_names:expr)),+) => {
36        #[must_use] pub fn get_visible_inactive_names(name: &str) -> [&str; 1]{
37            $(if name == $name {
38                return $visible_inactive_names;
39            })+
40            else {
41                panic!("unknown tool {name}");
42            }
43
44        }
45        #[derive(Clone, Debug)]
46        pub enum ToolWrapper {
47            $($tool($tool)),+
48        }
49        #[must_use]
50        pub fn make_tool_vec() -> Vec<ToolState> {
51            vec![$(
52                ToolState {
53                    tool_wrapper: ToolWrapper::$tool($tool::new()),
54                    is_active: $active,
55                    is_always_active: $always_active,
56                    name: $name,
57                    button_label: $label
58                }),+]
59        }
60        #[must_use] pub fn add_tools_initial_data(mut tdm: $crate::ToolsDataMap) -> $crate::ToolsDataMap {
61
62            $(if tdm.get_mut($name).is_none() {
63                tdm.insert(
64                    $name.to_string(),
65                    $crate::tools_data::ToolsData::new(
66                        $crate::tools_data::ToolSpecifics::$tool($data_default), VisibleInactiveToolsState::default()
67                    ),
68                );
69            })+
70            tdm
71        }
72    };
73}
74make_tools!(
75    (
76        Rot90,
77        "🔄",
78        ROT90_NAME,
79        true,
80        true,
81        Rot90ToolData::default(),
82        [""]
83    ),
84    (
85        Brush,
86        "✏",
87        BRUSH_NAME,
88        false,
89        false,
90        BrushToolData::default(),
91        [BBOX_NAME]
92    ),
93    (
94        Bbox,
95        "⬜",
96        BBOX_NAME,
97        false,
98        false,
99        BboxToolData::default(),
100        [BRUSH_NAME]
101    ),
102    (
103        Attributes,
104        "A",
105        ATTRIBUTES_NAME,
106        false,
107        false,
108        AttributesToolData::default(),
109        [""]
110    ),
111    (Zoom, "🔍", ZOOM_NAME, false, false, (), [""]),
112    (
113        AlwaysActiveZoom,
114        "AA🔍",
115        ALWAYS_ACTIVE_ZOOM,
116        true,
117        true,
118        (),
119        [""]
120    )
121);
122
123#[macro_export]
124macro_rules! apply_tool_method_mut {
125    ($tool_state:expr, $f:ident, $($args:expr),*) => {
126        match &mut $tool_state.tool_wrapper {
127            ToolWrapper::Rot90(z) => z.$f($($args,)*),
128            ToolWrapper::Brush(z) => z.$f($($args,)*),
129            ToolWrapper::Bbox(z) => z.$f($($args,)*),
130            ToolWrapper::Zoom(z) => z.$f($($args,)*),
131            ToolWrapper::AlwaysActiveZoom(z) => z.$f($($args,)*),
132            ToolWrapper::Attributes(z) => z.$f($($args,)*),
133        }
134    };
135}
136
137pub struct ToolState {
138    pub tool_wrapper: ToolWrapper,
139    is_active: bool,
140    is_always_active: bool, // no entry in the menu
141    pub name: &'static str,
142    pub button_label: &'static str,
143}
144impl ToolState {
145    pub fn activate(&mut self, mut world: World, mut history: History) -> (World, History) {
146        info!("activate {}", self.name);
147        self.is_active = true;
148        world = apply_tool_method_mut!(self, on_activate, world);
149        if !self.is_always_active() {
150            history.push(Record::new(world.clone(), self.name));
151        }
152        (world, history)
153    }
154    pub fn file_changed(&mut self, mut world: World, mut history: History) -> (World, History) {
155        (world, history) = apply_tool_method_mut!(self, on_filechange, world, history);
156        (world, history)
157    }
158    pub fn deactivate(&mut self, mut world: World) -> World {
159        if self.is_active {
160            info!("deactivate {}", self.name);
161            world = apply_tool_method_mut!(self, on_deactivate, world);
162        }
163        if !self.is_always_active {
164            self.is_active = false;
165        }
166        world
167    }
168    #[must_use]
169    pub fn is_active(&self) -> bool {
170        self.is_active
171    }
172    #[must_use]
173    pub fn is_always_active(&self) -> bool {
174        self.is_always_active
175    }
176}