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, 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}