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