rustapi/actions/
relief.rs1use crate::prelude::*;
2use rusterix::{PixelSource, Value};
3
4pub struct Relief {
5 id: TheId,
6 nodeui: TheNodeUI,
7}
8
9impl Action for Relief {
10 fn new() -> Self
11 where
12 Self: Sized,
13 {
14 let mut nodeui: TheNodeUI = TheNodeUI::default();
15
16 let item = TheNodeUIItem::FloatEditSlider(
17 "actionReliefHeight".into(),
18 "".into(),
19 "".into(),
20 0.2, 0.0..=1.0, false,
23 );
24 nodeui.add_item(item);
25
26 let item = TheNodeUIItem::Selector(
27 "actionReliefTarget".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 "actionReliefTiles".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_relief")),
59 nodeui,
60 }
61 }
62
63 fn id(&self) -> TheId {
64 self.id.clone()
65 }
66
67 fn info(&self) -> String {
68 fl!("action_relief_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, 'e'))
78 }
79
80 fn is_applicable(&self, map: &Map, _ctx: &mut TheContext, server_ctx: &ServerContext) -> bool {
81 !map.selected_sectors.is_empty()
83 && server_ctx.editor_view_mode == EditorViewMode::D2
84 && server_ctx.editing_surface.is_some()
85 }
86
87 fn load_params(&mut self, map: &Map) {
88 if let Some(sector_id) = map.selected_sectors.first() {
89 if let Some(sector) = map.find_sector(*sector_id) {
90 self.nodeui.set_f32_value(
91 "actionReliefHeight",
92 sector.properties.get_float_default("profile_amount", 0.1),
93 );
94 self.nodeui.set_i32_value(
95 "actionReliefTarget",
96 sector.properties.get_int_default("profile_target", 1),
97 );
98 }
99 }
100 }
101
102 fn load_params_project(&mut self, project: &Project, server_ctx: &mut ServerContext) {
103 let mut cap_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
104 let mut jamb_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
105 let mut cap_id = Uuid::nil();
106 let mut jamb_id = Uuid::nil();
107
108 if let Some(map) = project.get_map(server_ctx) {
109 if let Some(sector_id) = map.selected_sectors.first() {
110 if let Some(sector) = map.find_sector(*sector_id) {
111 if let Some(Value::Source(PixelSource::TileId(id))) =
112 sector.properties.get("cap_source")
113 {
114 if let Some(tile) = project.tiles.get(id)
115 && !tile.is_empty()
116 {
117 cap_icon = tile.textures[0].to_rgba();
118 cap_id = *id;
119 }
120 }
121 if let Some(Value::Source(PixelSource::TileId(id))) =
122 sector.properties.get("jamb_source")
123 {
124 if let Some(tile) = project.tiles.get(id)
125 && !tile.is_empty()
126 {
127 jamb_icon = tile.textures[0].to_rgba();
128 jamb_id = *id;
129 }
130 }
131 }
132 }
133 }
134
135 if let Some(item) = self.nodeui.get_item_mut("actionReliefTiles") {
136 match item {
137 TheNodeUIItem::Icons(_, _, _, items) => {
138 if items.len() == 2 {
139 items[0].0 = cap_icon;
140 items[0].2 = cap_id;
141 items[1].0 = jamb_icon;
142 items[1].2 = jamb_id;
143 }
144 }
145 _ => {}
146 }
147 }
148 }
149
150 fn apply(
151 &self,
152 map: &mut Map,
153 _ui: &mut TheUI,
154 _ctx: &mut TheContext,
155 server_ctx: &mut ServerContext,
156 ) -> Option<ProjectUndoAtom> {
157 let mut changed = false;
158 let prev = map.clone();
159
160 let mut height = self
161 .nodeui
162 .get_f32_value("actionReliefHeight")
163 .unwrap_or(0.0);
164 if height < 0.0 {
165 height = 0.0;
166 }
167
168 let target = self.nodeui.get_i32_value("actionReliefTarget").unwrap_or(1);
169 let cap = self.nodeui.get_tile_id("actionReliefTiles", 0);
170 let jamb = self.nodeui.get_tile_id("actionReliefTiles", 1);
171
172 for sector_id in &map.selected_sectors.clone() {
173 if let Some(sector) = map.find_sector_mut(*sector_id) {
174 sector.properties.set("profile_op", Value::Int(1)); sector
176 .properties
177 .set("profile_amount", Value::Float(height));
178
179 sector.properties.set("profile_target", Value::Int(target));
180
181 if let Some(cap) = cap
182 && cap != Uuid::nil()
183 {
184 sector.properties.set(
185 "cap_source",
186 Value::Source(rusterix::PixelSource::TileId(cap)),
187 );
188 }
189 if let Some(jamb) = jamb
190 && jamb != Uuid::nil()
191 {
192 sector.properties.set(
193 "jamb_source",
194 Value::Source(rusterix::PixelSource::TileId(jamb)),
195 );
196 }
197 changed = true;
198 }
199 }
200
201 if changed {
202 Some(ProjectUndoAtom::MapEdit(
203 server_ctx.pc,
204 Box::new(prev),
205 Box::new(map.clone()),
206 ))
207 } else {
208 None
209 }
210 }
211
212 fn params(&self) -> TheNodeUI {
213 self.nodeui.clone()
214 }
215
216 fn handle_event(
217 &mut self,
218 event: &TheEvent,
219 project: &mut Project,
220 _ui: &mut TheUI,
221 ctx: &mut TheContext,
222 _server_ctx: &mut ServerContext,
223 ) -> bool {
224 if let TheEvent::TileDropped(id, tile_id, index) = event {
225 if let Some(item) = self.nodeui.get_item_mut(&id.name) {
226 match item {
227 TheNodeUIItem::Icons(_, _, _, items) => {
228 if *index < items.len() {
229 if let Some(tile) = project.tiles.get(tile_id)
230 && !tile.is_empty()
231 {
232 items[*index].0 = tile.textures[0].to_rgba();
233 items[*index].2 = *tile_id;
234 ctx.ui.send(TheEvent::Custom(
235 TheId::named("Update Action List"),
236 TheValue::Empty,
237 ));
238 return true;
239 }
240 }
241 }
242 _ => {}
243 }
244 }
245 }
246 self.nodeui.handle_event(event)
247 }
248}