1use crate::prelude::*;
2use rusterix::{PixelSource, Value};
3
4pub struct CreateProp {
5 id: TheId,
6 nodeui: TheNodeUI,
7}
8
9fn parse_source_from_text_or_tile(text: &str, fallback_tile_id: Uuid) -> Option<PixelSource> {
10 let trimmed = text.trim();
11 if !trimmed.is_empty() {
12 if let Ok(id) = Uuid::parse_str(trimmed) {
13 return Some(PixelSource::TileId(id));
14 }
15 if let Ok(index) = trimmed.parse::<u16>() {
16 return Some(PixelSource::PaletteIndex(index));
17 }
18 }
19 if fallback_tile_id != Uuid::nil() {
20 Some(PixelSource::TileId(fallback_tile_id))
21 } else {
22 None
23 }
24}
25
26fn source_to_text_and_uuid(source: Option<&Value>) -> (String, Uuid) {
27 if let Some(Value::Source(ps)) = source {
28 match ps {
29 PixelSource::TileId(id) => (id.to_string(), *id),
30 PixelSource::PaletteIndex(i) => (i.to_string(), Uuid::nil()),
31 _ => (String::new(), Uuid::nil()),
32 }
33 } else {
34 (String::new(), Uuid::nil())
35 }
36}
37
38impl Action for CreateProp {
39 fn new() -> Self
40 where
41 Self: Sized,
42 {
43 let mut nodeui: TheNodeUI = TheNodeUI::default();
44
45 nodeui.add_item(TheNodeUIItem::OpenTree("prop".into()));
46 nodeui.add_item(TheNodeUIItem::Selector(
47 "actionPropType".into(),
48 "".into(),
49 "".into(),
50 vec![
51 "table".into(),
52 "bookcase".into(),
53 "crate".into(),
54 "barrel".into(),
55 "bed".into(),
56 ],
57 0,
58 ));
59 nodeui.add_item(TheNodeUIItem::CloseTree);
60
61 nodeui.add_item(TheNodeUIItem::OpenTree("table".into()));
62 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
63 "actionTableHeight".into(),
64 "".into(),
65 "".into(),
66 0.75,
67 0.0..=10.0,
68 false,
69 ));
70 nodeui.add_item(TheNodeUIItem::Checkbox(
71 "actionTableChairs".into(),
72 "".into(),
73 "".into(),
74 false,
75 ));
76 nodeui.add_item(TheNodeUIItem::IntEditSlider(
77 "actionTableChairCount".into(),
78 "".into(),
79 "".into(),
80 4,
81 0..=8,
82 false,
83 ));
84 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
85 "actionTableChairOffset".into(),
86 "".into(),
87 "".into(),
88 0.45,
89 0.0..=3.0,
90 false,
91 ));
92 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
93 "actionTableChairWidth".into(),
94 "".into(),
95 "".into(),
96 0.85,
97 0.20..=3.0,
98 false,
99 ));
100 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
101 "actionTableChairBackHeight".into(),
102 "".into(),
103 "".into(),
104 1.0,
105 0.25..=3.0,
106 false,
107 ));
108 nodeui.add_item(TheNodeUIItem::Icons(
109 "actionTableChairTile".into(),
110 "".into(),
111 "".into(),
112 vec![(
113 TheRGBABuffer::new(TheDim::sized(36, 36)),
114 "".to_string(),
115 Uuid::nil(),
116 )],
117 ));
118 nodeui.add_item(TheNodeUIItem::Text(
119 "actionTableChairTileId".into(),
120 "".into(),
121 "".into(),
122 "".into(),
123 None,
124 false,
125 ));
126 nodeui.add_item(TheNodeUIItem::CloseTree);
127
128 nodeui.add_item(TheNodeUIItem::OpenTree("bookcase".into()));
129 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
130 "actionBookcaseHeight".into(),
131 "".into(),
132 "".into(),
133 2.0,
134 0.2..=8.0,
135 false,
136 ));
137 nodeui.add_item(TheNodeUIItem::IntEditSlider(
138 "actionBookcaseShelves".into(),
139 "".into(),
140 "".into(),
141 4,
142 1..=12,
143 false,
144 ));
145 nodeui.add_item(TheNodeUIItem::Checkbox(
146 "actionBookcaseBooks".into(),
147 "".into(),
148 "".into(),
149 true,
150 ));
151 nodeui.add_item(TheNodeUIItem::CloseTree);
152
153 nodeui.add_item(TheNodeUIItem::OpenTree("crate".into()));
154 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
155 "actionCrateHeight".into(),
156 "".into(),
157 "".into(),
158 1.0,
159 0.2..=8.0,
160 false,
161 ));
162 nodeui.add_item(TheNodeUIItem::CloseTree);
163
164 nodeui.add_item(TheNodeUIItem::OpenTree("barrel".into()));
165 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
166 "actionBarrelHeight".into(),
167 "".into(),
168 "".into(),
169 1.0,
170 0.2..=8.0,
171 false,
172 ));
173 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
174 "actionBarrelBulge".into(),
175 "".into(),
176 "".into(),
177 1.12,
178 1.0..=1.5,
179 false,
180 ));
181 nodeui.add_item(TheNodeUIItem::IntEditSlider(
182 "actionBarrelSegments".into(),
183 "".into(),
184 "".into(),
185 12,
186 6..=32,
187 false,
188 ));
189 nodeui.add_item(TheNodeUIItem::CloseTree);
190
191 nodeui.add_item(TheNodeUIItem::OpenTree("bed".into()));
192 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
193 "actionBedHeight".into(),
194 "".into(),
195 "".into(),
196 0.55,
197 0.2..=3.0,
198 false,
199 ));
200 nodeui.add_item(TheNodeUIItem::Checkbox(
201 "actionBedHeadboard".into(),
202 "".into(),
203 "".into(),
204 true,
205 ));
206 nodeui.add_item(TheNodeUIItem::Selector(
207 "actionBedHeadboardSide".into(),
208 "".into(),
209 "".into(),
210 vec!["start".into(), "end".into()],
211 0,
212 ));
213 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
214 "actionBedHeadboardHeight".into(),
215 "".into(),
216 "".into(),
217 0.7,
218 0.2..=2.5,
219 false,
220 ));
221 nodeui.add_item(TheNodeUIItem::Icons(
222 "actionBedMattressTile".into(),
223 "".into(),
224 "".into(),
225 vec![(
226 TheRGBABuffer::new(TheDim::sized(36, 36)),
227 "".to_string(),
228 Uuid::nil(),
229 )],
230 ));
231 nodeui.add_item(TheNodeUIItem::Text(
232 "actionBedMattressTileId".into(),
233 "".into(),
234 "".into(),
235 "".into(),
236 None,
237 false,
238 ));
239 nodeui.add_item(TheNodeUIItem::CloseTree);
240
241 nodeui.add_item(TheNodeUIItem::OpenTree("material".into()));
242 nodeui.add_item(TheNodeUIItem::Icons(
243 "actionMaterialTile".into(),
244 "".into(),
245 "".into(),
246 vec![(
247 TheRGBABuffer::new(TheDim::sized(36, 36)),
248 "".to_string(),
249 Uuid::nil(),
250 )],
251 ));
252 nodeui.add_item(TheNodeUIItem::Text(
253 "actionMaterialTileId".into(),
254 "".into(),
255 "".into(),
256 "".into(),
257 None,
258 false,
259 ));
260 nodeui.add_item(TheNodeUIItem::CloseTree);
261
262 Self {
263 id: TheId::named("Create Prop"),
264 nodeui,
265 }
266 }
267
268 fn id(&self) -> TheId {
269 self.id.clone()
270 }
271
272 fn info(&self) -> String {
273 "Create or edit parametric props on selected sectors.".to_string()
274 }
275
276 fn role(&self) -> ActionRole {
277 ActionRole::Editor
278 }
279
280 fn is_applicable(&self, map: &Map, _ctx: &mut TheContext, server_ctx: &ServerContext) -> bool {
281 !map.selected_sectors.is_empty()
282 && server_ctx.editor_view_mode == EditorViewMode::D2
283 && server_ctx.editing_surface.is_some()
284 }
285
286 fn load_params(&mut self, map: &Map) {
287 if let Some(sector_id) = map.selected_sectors.first()
288 && let Some(sector) = map.find_sector(*sector_id)
289 {
290 let prop_kind = sector.properties.get_int_default("profile_prop_kind", 0);
291 self.nodeui
292 .set_i32_value("actionPropType", prop_kind.clamp(0, 4));
293 self.nodeui.set_f32_value(
294 "actionTableHeight",
295 sector.properties.get_float_default("profile_amount", 0.75),
296 );
297 self.nodeui.set_bool_value(
298 "actionTableChairs",
299 sector.properties.get_bool_default("table_chairs", false),
300 );
301 self.nodeui.set_i32_value(
302 "actionTableChairCount",
303 sector.properties.get_int_default("table_chair_count", 4),
304 );
305 self.nodeui.set_f32_value(
306 "actionTableChairOffset",
307 sector
308 .properties
309 .get_float_default("table_chair_offset", 0.45),
310 );
311 self.nodeui.set_f32_value(
312 "actionTableChairWidth",
313 sector
314 .properties
315 .get_float_default("table_chair_width", 0.85),
316 );
317 self.nodeui.set_f32_value(
318 "actionTableChairBackHeight",
319 sector
320 .properties
321 .get_float_default("table_chair_back_height", 1.0),
322 );
323 self.nodeui.set_f32_value(
324 "actionBookcaseHeight",
325 sector.properties.get_float_default("profile_amount", 2.0),
326 );
327 self.nodeui.set_f32_value(
328 "actionCrateHeight",
329 sector.properties.get_float_default("profile_amount", 1.0),
330 );
331 self.nodeui.set_f32_value(
332 "actionBarrelHeight",
333 sector.properties.get_float_default("profile_amount", 1.0),
334 );
335 self.nodeui.set_f32_value(
336 "actionBarrelBulge",
337 sector.properties.get_float_default("barrel_bulge", 1.12),
338 );
339 self.nodeui.set_i32_value(
340 "actionBarrelSegments",
341 sector.properties.get_int_default("barrel_segments", 12),
342 );
343 self.nodeui.set_f32_value(
344 "actionBedHeight",
345 sector.properties.get_float_default("profile_amount", 0.55),
346 );
347 self.nodeui.set_bool_value(
348 "actionBedHeadboard",
349 sector.properties.get_bool_default("bed_headboard", true),
350 );
351 self.nodeui.set_i32_value(
352 "actionBedHeadboardSide",
353 sector
354 .properties
355 .get_int_default("bed_headboard_side", 0)
356 .clamp(0, 1),
357 );
358 self.nodeui.set_f32_value(
359 "actionBedHeadboardHeight",
360 sector
361 .properties
362 .get_float_default("bed_headboard_height", 0.7),
363 );
364 self.nodeui.set_i32_value(
365 "actionBookcaseShelves",
366 sector.properties.get_int_default("bookcase_shelves", 4),
367 );
368 self.nodeui.set_bool_value(
369 "actionBookcaseBooks",
370 sector.properties.get_bool_default("bookcase_books", true),
371 );
372
373 let (tile_text, tile_id) = source_to_text_and_uuid(sector.properties.get("cap_source"));
374 self.nodeui
375 .set_text_value("actionMaterialTileId", tile_text);
376 if let Some(item) = self.nodeui.get_item_mut("actionMaterialTile")
377 && let TheNodeUIItem::Icons(_, _, _, items) = item
378 && items.len() == 1
379 {
380 items[0].2 = tile_id;
381 }
382
383 let (chair_tile_text, chair_tile_id) =
384 source_to_text_and_uuid(sector.properties.get("chair_source"));
385 self.nodeui
386 .set_text_value("actionTableChairTileId", chair_tile_text);
387 if let Some(item) = self.nodeui.get_item_mut("actionTableChairTile")
388 && let TheNodeUIItem::Icons(_, _, _, items) = item
389 && items.len() == 1
390 {
391 items[0].2 = chair_tile_id;
392 }
393
394 let (bed_mattress_tile_text, bed_mattress_tile_id) =
395 source_to_text_and_uuid(sector.properties.get("bed_mattress_source"));
396 self.nodeui
397 .set_text_value("actionBedMattressTileId", bed_mattress_tile_text);
398 if let Some(item) = self.nodeui.get_item_mut("actionBedMattressTile")
399 && let TheNodeUIItem::Icons(_, _, _, items) = item
400 && items.len() == 1
401 {
402 items[0].2 = bed_mattress_tile_id;
403 }
404 }
405 }
406
407 fn load_params_project(&mut self, project: &Project, server_ctx: &mut ServerContext) {
408 let mut tile_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
409 let mut tile_id = Uuid::nil();
410 let mut chair_tile_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
411 let mut chair_tile_id = Uuid::nil();
412 let mut bed_mattress_tile_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
413 let mut bed_mattress_tile_id = Uuid::nil();
414
415 if let Some(map) = project.get_map(server_ctx)
416 && let Some(sector_id) = map.selected_sectors.first()
417 && let Some(sector) = map.find_sector(*sector_id)
418 && let Some(Value::Source(PixelSource::TileId(id))) =
419 sector.properties.get("cap_source")
420 && let Some(tile) = project.tiles.get(id)
421 && !tile.is_empty()
422 {
423 tile_icon = tile.textures[0].to_rgba();
424 tile_id = *id;
425 }
426 if let Some(map) = project.get_map(server_ctx)
427 && let Some(sector_id) = map.selected_sectors.first()
428 && let Some(sector) = map.find_sector(*sector_id)
429 && let Some(Value::Source(PixelSource::TileId(id))) =
430 sector.properties.get("chair_source")
431 && let Some(tile) = project.tiles.get(id)
432 && !tile.is_empty()
433 {
434 chair_tile_icon = tile.textures[0].to_rgba();
435 chair_tile_id = *id;
436 }
437 if let Some(map) = project.get_map(server_ctx)
438 && let Some(sector_id) = map.selected_sectors.first()
439 && let Some(sector) = map.find_sector(*sector_id)
440 && let Some(Value::Source(PixelSource::TileId(id))) =
441 sector.properties.get("bed_mattress_source")
442 && let Some(tile) = project.tiles.get(id)
443 && !tile.is_empty()
444 {
445 bed_mattress_tile_icon = tile.textures[0].to_rgba();
446 bed_mattress_tile_id = *id;
447 }
448
449 if let Some(item) = self.nodeui.get_item_mut("actionMaterialTile")
450 && let TheNodeUIItem::Icons(_, _, _, items) = item
451 && items.len() == 1
452 {
453 items[0].0 = tile_icon;
454 items[0].2 = tile_id;
455 }
456 if let Some(item) = self.nodeui.get_item_mut("actionTableChairTile")
457 && let TheNodeUIItem::Icons(_, _, _, items) = item
458 && items.len() == 1
459 {
460 items[0].0 = chair_tile_icon;
461 items[0].2 = chair_tile_id;
462 }
463 if let Some(item) = self.nodeui.get_item_mut("actionBedMattressTile")
464 && let TheNodeUIItem::Icons(_, _, _, items) = item
465 && items.len() == 1
466 {
467 items[0].0 = bed_mattress_tile_icon;
468 items[0].2 = bed_mattress_tile_id;
469 }
470 }
471
472 fn apply(
473 &self,
474 map: &mut Map,
475 _ui: &mut TheUI,
476 _ctx: &mut TheContext,
477 server_ctx: &mut ServerContext,
478 ) -> Option<ProjectUndoAtom> {
479 let prop_type = self.nodeui.get_i32_value("actionPropType").unwrap_or(0);
480
481 let prev = map.clone();
482
483 let height = self
484 .nodeui
485 .get_f32_value("actionTableHeight")
486 .unwrap_or(0.75)
487 .max(0.0);
488 let chairs_enabled = self
489 .nodeui
490 .get_bool_value("actionTableChairs")
491 .unwrap_or(false);
492 let chair_count = self
493 .nodeui
494 .get_i32_value("actionTableChairCount")
495 .unwrap_or(4)
496 .clamp(0, 8);
497 let chair_offset = self
498 .nodeui
499 .get_f32_value("actionTableChairOffset")
500 .unwrap_or(0.45)
501 .max(0.0);
502 let chair_width = self
503 .nodeui
504 .get_f32_value("actionTableChairWidth")
505 .unwrap_or(0.85)
506 .max(0.20);
507 let chair_back_height = self
508 .nodeui
509 .get_f32_value("actionTableChairBackHeight")
510 .unwrap_or(1.0)
511 .max(0.25);
512 let bookcase_height = self
513 .nodeui
514 .get_f32_value("actionBookcaseHeight")
515 .unwrap_or(2.0)
516 .max(0.2);
517 let crate_height = self
518 .nodeui
519 .get_f32_value("actionCrateHeight")
520 .unwrap_or(1.0)
521 .max(0.2);
522 let barrel_height = self
523 .nodeui
524 .get_f32_value("actionBarrelHeight")
525 .unwrap_or(1.0)
526 .max(0.2);
527 let barrel_bulge = self
528 .nodeui
529 .get_f32_value("actionBarrelBulge")
530 .unwrap_or(1.12)
531 .clamp(1.0, 1.5);
532 let barrel_segments = self
533 .nodeui
534 .get_i32_value("actionBarrelSegments")
535 .unwrap_or(12)
536 .clamp(6, 32);
537 let bed_height = self
538 .nodeui
539 .get_f32_value("actionBedHeight")
540 .unwrap_or(0.55)
541 .clamp(0.2, 3.0);
542 let bed_headboard = self
543 .nodeui
544 .get_bool_value("actionBedHeadboard")
545 .unwrap_or(true);
546 let bed_headboard_side = self
547 .nodeui
548 .get_i32_value("actionBedHeadboardSide")
549 .unwrap_or(0)
550 .clamp(0, 1);
551 let bed_headboard_height = self
552 .nodeui
553 .get_f32_value("actionBedHeadboardHeight")
554 .unwrap_or(0.7)
555 .clamp(0.2, 2.5);
556 let bookcase_shelves = self
557 .nodeui
558 .get_i32_value("actionBookcaseShelves")
559 .unwrap_or(4)
560 .clamp(1, 12);
561 let bookcase_books = self
562 .nodeui
563 .get_bool_value("actionBookcaseBooks")
564 .unwrap_or(true);
565
566 let tile_id = self
567 .nodeui
568 .get_tile_id("actionMaterialTile", 0)
569 .unwrap_or(Uuid::nil());
570 let tile_text = self
571 .nodeui
572 .get_text_value("actionMaterialTileId")
573 .unwrap_or_default();
574 let table_source = parse_source_from_text_or_tile(&tile_text, tile_id);
575 let chair_tile_id = self
576 .nodeui
577 .get_tile_id("actionTableChairTile", 0)
578 .unwrap_or(Uuid::nil());
579 let chair_tile_text = self
580 .nodeui
581 .get_text_value("actionTableChairTileId")
582 .unwrap_or_default();
583 let chair_source = parse_source_from_text_or_tile(&chair_tile_text, chair_tile_id);
584 let bed_mattress_tile_id = self
585 .nodeui
586 .get_tile_id("actionBedMattressTile", 0)
587 .unwrap_or(Uuid::nil());
588 let bed_mattress_tile_text = self
589 .nodeui
590 .get_text_value("actionBedMattressTileId")
591 .unwrap_or_default();
592 let bed_mattress_source =
593 parse_source_from_text_or_tile(&bed_mattress_tile_text, bed_mattress_tile_id);
594
595 let mut changed = false;
596 for sector_id in &map.selected_sectors.clone() {
597 if let Some(sector) = map.find_sector_mut(*sector_id) {
598 sector.properties.set("profile_op", Value::Int(1));
599 sector
600 .properties
601 .set("profile_prop_kind", Value::Int(prop_type));
602 sector.properties.set(
603 "profile_amount",
604 Value::Float(match prop_type {
605 1 => bookcase_height,
606 2 => crate_height,
607 3 => barrel_height,
608 4 => bed_height,
609 _ => height,
610 }),
611 );
612 sector.properties.set("profile_table", Value::Bool(true));
613 if prop_type == 0 {
614 sector
615 .properties
616 .set("table_chairs", Value::Bool(chairs_enabled));
617 sector
618 .properties
619 .set("table_chair_count", Value::Int(chair_count));
620 sector
621 .properties
622 .set("table_chair_offset", Value::Float(chair_offset));
623 sector
624 .properties
625 .set("table_chair_width", Value::Float(chair_width));
626 sector
627 .properties
628 .set("table_chair_back_height", Value::Float(chair_back_height));
629 sector.properties.remove("bookcase_shelves");
630 sector.properties.remove("bookcase_books");
631 sector.properties.remove("book_source");
632 sector.properties.remove("barrel_bulge");
633 sector.properties.remove("barrel_segments");
634 sector.properties.remove("bed_headboard");
635 sector.properties.remove("bed_headboard_side");
636 sector.properties.remove("bed_headboard_height");
637 sector.properties.remove("bed_mattress_source");
638 } else if prop_type == 1 {
639 sector
640 .properties
641 .set("bookcase_shelves", Value::Int(bookcase_shelves));
642 sector
643 .properties
644 .set("bookcase_books", Value::Bool(bookcase_books));
645 sector.properties.remove("table_chairs");
646 sector.properties.remove("table_chair_count");
647 sector.properties.remove("table_chair_offset");
648 sector.properties.remove("table_chair_width");
649 sector.properties.remove("table_chair_back_height");
650 sector.properties.remove("chair_source");
651 sector.properties.remove("barrel_bulge");
652 sector.properties.remove("barrel_segments");
653 sector.properties.remove("bed_headboard");
654 sector.properties.remove("bed_headboard_side");
655 sector.properties.remove("bed_headboard_height");
656 sector.properties.remove("bed_mattress_source");
657
658 if bookcase_books {
659 let palette_index = (8 + (sector.id % 24)) as u16;
660 sector.properties.set(
661 "book_source",
662 Value::Source(PixelSource::PaletteIndex(palette_index)),
663 );
664 } else {
665 sector.properties.remove("book_source");
666 }
667 } else if prop_type == 3 {
668 sector
669 .properties
670 .set("barrel_bulge", Value::Float(barrel_bulge));
671 sector
672 .properties
673 .set("barrel_segments", Value::Int(barrel_segments));
674 sector.properties.remove("table_chairs");
675 sector.properties.remove("table_chair_count");
676 sector.properties.remove("table_chair_offset");
677 sector.properties.remove("table_chair_width");
678 sector.properties.remove("table_chair_back_height");
679 sector.properties.remove("chair_source");
680 sector.properties.remove("bookcase_shelves");
681 sector.properties.remove("bookcase_books");
682 sector.properties.remove("book_source");
683 sector.properties.remove("bed_headboard");
684 sector.properties.remove("bed_headboard_side");
685 sector.properties.remove("bed_headboard_height");
686 sector.properties.remove("bed_mattress_source");
687 } else if prop_type == 4 {
688 sector
689 .properties
690 .set("bed_headboard", Value::Bool(bed_headboard));
691 sector
692 .properties
693 .set("bed_headboard_side", Value::Int(bed_headboard_side));
694 sector
695 .properties
696 .set("bed_headboard_height", Value::Float(bed_headboard_height));
697 sector.properties.remove("table_chairs");
698 sector.properties.remove("table_chair_count");
699 sector.properties.remove("table_chair_offset");
700 sector.properties.remove("table_chair_width");
701 sector.properties.remove("table_chair_back_height");
702 sector.properties.remove("chair_source");
703 sector.properties.remove("bookcase_shelves");
704 sector.properties.remove("bookcase_books");
705 sector.properties.remove("book_source");
706 sector.properties.remove("barrel_bulge");
707 sector.properties.remove("barrel_segments");
708 if let Some(source) = bed_mattress_source.clone().or(table_source.clone()) {
709 sector
710 .properties
711 .set("bed_mattress_source", Value::Source(source));
712 } else {
713 sector.properties.remove("bed_mattress_source");
714 }
715 } else {
716 sector.properties.remove("table_chairs");
718 sector.properties.remove("table_chair_count");
719 sector.properties.remove("table_chair_offset");
720 sector.properties.remove("table_chair_width");
721 sector.properties.remove("table_chair_back_height");
722 sector.properties.remove("chair_source");
723 sector.properties.remove("bookcase_shelves");
724 sector.properties.remove("bookcase_books");
725 sector.properties.remove("book_source");
726 sector.properties.remove("barrel_bulge");
727 sector.properties.remove("barrel_segments");
728 sector.properties.remove("bed_headboard");
729 sector.properties.remove("bed_headboard_side");
730 sector.properties.remove("bed_headboard_height");
731 sector.properties.remove("bed_mattress_source");
732 }
733
734 if let Some(source) = table_source.clone() {
735 let src = Value::Source(source);
736 sector.properties.set("cap_source", src.clone());
737 sector.properties.set("jamb_source", src);
738 } else {
739 sector.properties.remove("cap_source");
740 sector.properties.remove("jamb_source");
741 }
742 if let Some(source) = chair_source.clone() {
743 let src = Value::Source(source);
744 sector.properties.set("chair_source", src);
745 } else {
746 sector.properties.remove("chair_source");
747 }
748 changed = true;
749 }
750 }
751
752 if changed {
753 Some(ProjectUndoAtom::MapEdit(
754 server_ctx.pc,
755 Box::new(prev),
756 Box::new(map.clone()),
757 ))
758 } else {
759 None
760 }
761 }
762
763 fn params(&self) -> TheNodeUI {
764 self.nodeui.clone()
765 }
766
767 fn handle_event(
768 &mut self,
769 event: &TheEvent,
770 project: &mut Project,
771 _ui: &mut TheUI,
772 ctx: &mut TheContext,
773 _server_ctx: &mut ServerContext,
774 ) -> bool {
775 if let TheEvent::TileDropped(id, tile_id, index) = event
776 && let Some(item) = self.nodeui.get_item_mut(&id.name)
777 && let TheNodeUIItem::Icons(_, _, _, items) = item
778 && *index < items.len()
779 && let Some(tile) = project.tiles.get(tile_id)
780 && !tile.is_empty()
781 {
782 items[*index].0 = tile.textures[0].to_rgba();
783 items[*index].2 = *tile_id;
784 if id.name == "actionMaterialTile" {
785 self.nodeui
786 .set_text_value("actionMaterialTileId", tile_id.to_string());
787 } else if id.name == "actionTableChairTile" {
788 self.nodeui
789 .set_text_value("actionTableChairTileId", tile_id.to_string());
790 } else if id.name == "actionBedMattressTile" {
791 self.nodeui
792 .set_text_value("actionBedMattressTileId", tile_id.to_string());
793 }
794 ctx.ui.send(TheEvent::Custom(
795 TheId::named("Update Action List"),
796 TheValue::Empty,
797 ));
798 return true;
799 }
800 self.nodeui.handle_event(event)
801 }
802}