Skip to main content

rustapi/actions/
recess.rs

1use crate::prelude::*;
2use rusterix::{PixelSource, Value};
3
4pub struct Recess {
5    id: TheId,
6    nodeui: TheNodeUI,
7}
8
9impl Action for Recess {
10    fn new() -> Self
11    where
12        Self: Sized,
13    {
14        let mut nodeui: TheNodeUI = TheNodeUI::default();
15
16        let item = TheNodeUIItem::FloatEditSlider(
17            "actionRecessDepth".into(),
18            "".into(),
19            "".into(),
20            0.1,
21            0.0..=1.0,
22            false,
23        );
24        nodeui.add_item(item);
25
26        let item = TheNodeUIItem::Selector(
27            "actionRecessTarget".into(),
28            "".into(),
29            "".into(),
30            vec!["Front".to_string(), "Back".to_string()],
31            1,
32        );
33        nodeui.add_item(item);
34
35        let item = TheNodeUIItem::Icons(
36            "actionRecessTiles".into(),
37            "".into(),
38            "".into(),
39            vec![
40                (
41                    TheRGBABuffer::new(TheDim::sized(36, 36)),
42                    "CAP".to_string(),
43                    Uuid::nil(),
44                ),
45                (
46                    TheRGBABuffer::new(TheDim::sized(36, 36)),
47                    "SIDE".to_string(),
48                    Uuid::nil(),
49                ),
50            ],
51        );
52        nodeui.add_item(item);
53
54        let item = TheNodeUIItem::Markdown("desc".into(), "".into());
55        nodeui.add_item(item);
56
57        Self {
58            id: TheId::named(&fl!("action_recess")),
59            nodeui,
60        }
61    }
62
63    fn id(&self) -> TheId {
64        self.id.clone()
65    }
66
67    fn info(&self) -> String {
68        fl!("action_recess_desc")
69    }
70
71    fn role(&self) -> ActionRole {
72        ActionRole::Editor
73    }
74
75    fn accel(&self) -> Option<TheAccelerator> {
76        Some(TheAccelerator::new(TheAcceleratorKey::ALT, 'r'))
77    }
78
79    fn is_applicable(&self, map: &Map, _ctx: &mut TheContext, server_ctx: &ServerContext) -> bool {
80        // Only applicable if we have selected sectors and we are in 2D Profile Editing Mode
81        !map.selected_sectors.is_empty()
82            && server_ctx.editor_view_mode == EditorViewMode::D2
83            && server_ctx.editing_surface.is_some()
84    }
85
86    fn load_params(&mut self, map: &Map) {
87        if let Some(sector_id) = map.selected_sectors.first() {
88            if let Some(sector) = map.find_sector(*sector_id) {
89                self.nodeui.set_f32_value(
90                    "actionRecessDepth",
91                    sector.properties.get_float_default("profile_amount", 0.1),
92                );
93                self.nodeui.set_i32_value(
94                    "actionRecessTarget",
95                    sector.properties.get_int_default("profile_target", 1),
96                );
97            }
98        }
99    }
100
101    fn load_params_project(&mut self, project: &Project, server_ctx: &mut ServerContext) {
102        let mut cap_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
103        let mut jamb_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
104        let mut cap_id = Uuid::nil();
105        let mut jamb_id = Uuid::nil();
106
107        if let Some(map) = project.get_map(server_ctx) {
108            if let Some(sector_id) = map.selected_sectors.first() {
109                if let Some(sector) = map.find_sector(*sector_id) {
110                    if let Some(Value::Source(PixelSource::TileId(id))) =
111                        sector.properties.get("cap_source")
112                    {
113                        if let Some(tile) = project.tiles.get(id)
114                            && !tile.is_empty()
115                        {
116                            cap_icon = tile.textures[0].to_rgba();
117                            cap_id = *id;
118                        }
119                    }
120                    if let Some(Value::Source(PixelSource::TileId(id))) =
121                        sector.properties.get("jamb_source")
122                    {
123                        if let Some(tile) = project.tiles.get(id)
124                            && !tile.is_empty()
125                        {
126                            jamb_icon = tile.textures[0].to_rgba();
127                            jamb_id = *id;
128                        }
129                    }
130                }
131            }
132        }
133
134        if let Some(item) = self.nodeui.get_item_mut("actionRecessTiles") {
135            match item {
136                TheNodeUIItem::Icons(_, _, _, items) => {
137                    if items.len() == 2 {
138                        items[0].0 = cap_icon;
139                        items[0].2 = cap_id;
140                        items[1].0 = jamb_icon;
141                        items[1].2 = jamb_id;
142                    }
143                }
144                _ => {}
145            }
146        }
147    }
148
149    fn apply(
150        &self,
151        map: &mut Map,
152        _ui: &mut TheUI,
153        _ctx: &mut TheContext,
154        server_ctx: &mut ServerContext,
155    ) -> Option<ProjectUndoAtom> {
156        let mut changed = false;
157        let prev = map.clone();
158
159        let depth = self
160            .nodeui
161            .get_f32_value("actionRecessDepth")
162            .unwrap_or(0.0);
163
164        let target = self.nodeui.get_i32_value("actionRecessTarget").unwrap_or(1);
165
166        let cap = self.nodeui.get_tile_id("actionRecessTiles", 0);
167        let jamb = self.nodeui.get_tile_id("actionRecessTiles", 1);
168
169        for sector_id in &map.selected_sectors.clone() {
170            if let Some(sector) = map.find_sector_mut(*sector_id) {
171                sector.properties.set("profile_op", Value::Int(2));
172                sector.properties.set("profile_amount", Value::Float(depth));
173                sector.properties.set("profile_target", Value::Int(target));
174
175                if let Some(cap) = cap
176                    && cap != Uuid::nil()
177                {
178                    sector.properties.set(
179                        "cap_source",
180                        Value::Source(rusterix::PixelSource::TileId(cap)),
181                    );
182                }
183                if let Some(jamb) = jamb
184                    && jamb != Uuid::nil()
185                {
186                    sector.properties.set(
187                        "jamb_source",
188                        Value::Source(rusterix::PixelSource::TileId(jamb)),
189                    );
190                }
191                changed = true;
192            }
193        }
194
195        if changed {
196            Some(ProjectUndoAtom::MapEdit(
197                server_ctx.pc,
198                Box::new(prev),
199                Box::new(map.clone()),
200            ))
201        } else {
202            None
203        }
204    }
205
206    fn params(&self) -> TheNodeUI {
207        self.nodeui.clone()
208    }
209
210    fn handle_event(
211        &mut self,
212        event: &TheEvent,
213        project: &mut Project,
214        _ui: &mut TheUI,
215        ctx: &mut TheContext,
216        _server_ctx: &mut ServerContext,
217    ) -> bool {
218        if let TheEvent::TileDropped(id, tile_id, index) = event {
219            if let Some(item) = self.nodeui.get_item_mut(&id.name) {
220                match item {
221                    TheNodeUIItem::Icons(_, _, _, items) => {
222                        if *index < items.len() {
223                            if let Some(tile) = project.tiles.get(tile_id)
224                                && !tile.is_empty()
225                            {
226                                items[*index].0 = tile.textures[0].to_rgba();
227                                items[*index].2 = *tile_id;
228                                ctx.ui.send(TheEvent::Custom(
229                                    TheId::named("Update Action List"),
230                                    TheValue::Empty,
231                                ));
232                                return true;
233                            }
234                        }
235                    }
236                    _ => {}
237                }
238            }
239        }
240        self.nodeui.handle_event(event)
241    }
242}