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