1use crate::prelude::*;
2use rusterix::PixelSource;
3use std::str::FromStr;
4
5pub const EDIT_SECTOR_ACTION_ID: &str = "1a1dea50-0181-46d9-acd6-913755c915e0";
6
7pub struct EditSector {
8 id: TheId,
9 nodeui: TheNodeUI,
10 show_terrain: bool,
11}
12
13fn parse_hide_patterns(value: &str) -> Vec<String> {
14 value
15 .split(',')
16 .map(|s| s.trim())
17 .filter(|s| !s.is_empty())
18 .map(|s| s.trim_matches('"').to_string())
19 .collect()
20}
21
22impl EditSector {
23 fn build_nodeui(show_terrain: bool) -> TheNodeUI {
24 let mut nodeui: TheNodeUI = TheNodeUI::default();
25
26 let item = TheNodeUIItem::Text(
27 "actionSectorName".into(),
28 "".into(),
29 "".into(),
30 "".into(),
31 None,
32 false,
33 );
34 nodeui.add_item(item);
35
36 let item = TheNodeUIItem::Text(
37 "actionSectorItem".into(),
38 "".into(),
39 "".into(),
40 "".into(),
41 None,
42 false,
43 );
44 nodeui.add_item(item);
45
46 nodeui.add_item(TheNodeUIItem::Checkbox(
47 "actionSectorVisible".into(),
48 "".into(),
49 "".into(),
50 true,
51 ));
52
53 if show_terrain {
54 nodeui.add_item(TheNodeUIItem::OpenTree("terrain".into()));
55
56 let item = TheNodeUIItem::Selector(
57 "actionSectorTerrain".into(),
58 "".into(),
59 "".into(),
60 vec!["None".into(), "Exclude".into(), "Ridge".into()],
61 0,
62 );
63 nodeui.add_item(item);
64
65 let item = TheNodeUIItem::FloatEditSlider(
66 "actionSectorTerrainRidgeHeight".into(),
67 "".into(),
68 "".into(),
69 1.0,
70 0.0..=0.0,
71 false,
72 );
73 nodeui.add_item(item);
74
75 let item = TheNodeUIItem::FloatEditSlider(
76 "actionSectorTerrainRidgePlateau".into(),
77 "".into(),
78 "".into(),
79 0.0,
80 0.0..=0.0,
81 false,
82 );
83 nodeui.add_item(item);
84
85 let item = TheNodeUIItem::FloatEditSlider(
86 "actionSectorTerrainRidgeFalloff".into(),
87 "".into(),
88 "".into(),
89 5.0,
90 0.0..=0.0,
91 false,
92 );
93 nodeui.add_item(item);
94
95 let item = TheNodeUIItem::IntEditSlider(
96 "actionSectorTerrainRidgeSubdiv".into(),
97 "".into(),
98 "".into(),
99 1,
100 1..=8,
101 false,
102 );
103 nodeui.add_item(item);
104
105 nodeui.add_item(TheNodeUIItem::Icons(
106 "actionSectorTerrainTile".into(),
107 "".into(),
108 "".into(),
109 vec![(
110 TheRGBABuffer::new(TheDim::sized(36, 36)),
111 "".to_string(),
112 Uuid::nil(),
113 )],
114 ));
115
116 nodeui.add_item(TheNodeUIItem::Text(
117 "actionSectorTileId".into(),
118 "".into(),
119 "".into(),
120 "".into(),
121 None,
122 false,
123 ));
124
125 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
126 "actionSectorTerrainTileFalloff".into(),
127 "".into(),
128 "".into(),
129 1.0,
130 0.0..=16.0,
131 false,
132 ));
133
134 nodeui.add_item(TheNodeUIItem::Checkbox(
135 "actionSectorTerrainRidgeWaterEnabled".into(),
136 "".into(),
137 "".into(),
138 false,
139 ));
140
141 nodeui.add_item(TheNodeUIItem::FloatEditSlider(
142 "actionSectorTerrainRidgeWaterLevel".into(),
143 "".into(),
144 "".into(),
145 0.0,
146 -16.0..=16.0,
147 false,
148 ));
149
150 nodeui.add_item(TheNodeUIItem::Icons(
151 "actionSectorTerrainRidgeWaterTile".into(),
152 "".into(),
153 "".into(),
154 vec![(
155 TheRGBABuffer::new(TheDim::sized(36, 36)),
156 "".to_string(),
157 Uuid::nil(),
158 )],
159 ));
160
161 nodeui.add_item(TheNodeUIItem::Text(
162 "actionSectorTerrainRidgeWaterTileId".into(),
163 "".into(),
164 "".into(),
165 "".into(),
166 None,
167 false,
168 ));
169
170 nodeui.add_item(TheNodeUIItem::CloseTree);
171
172 nodeui.add_item(TheNodeUIItem::Text(
173 "actionIsoHideOnEnter".into(),
174 "".into(),
175 "".into(),
176 "".into(),
177 None,
178 false,
179 ));
180 }
181
182 nodeui
183 }
184}
185
186impl Action for EditSector {
187 fn new() -> Self
188 where
189 Self: Sized,
190 {
191 let nodeui = Self::build_nodeui(true);
192
193 Self {
197 id: TheId::named_with_id(
198 &fl!("action_edit_sector"),
199 Uuid::from_str(EDIT_SECTOR_ACTION_ID).unwrap(),
200 ),
201 nodeui,
202 show_terrain: true,
203 }
204 }
205
206 fn id(&self) -> TheId {
207 self.id.clone()
208 }
209
210 fn info(&self) -> String {
211 fl!("action_edit_sector_desc")
212 }
213
214 fn role(&self) -> ActionRole {
215 ActionRole::Editor
216 }
217
218 fn accel(&self) -> Option<TheAccelerator> {
219 None
220 }
221
222 fn is_applicable(&self, map: &Map, _ctx: &mut TheContext, _server_ctx: &ServerContext) -> bool {
223 map.selected_sectors.len() == 1
224 }
225
226 fn load_params(&mut self, map: &Map) {
227 if let Some(sector_id) = map.selected_sectors.first() {
228 if let Some(sector) = map.find_sector(*sector_id) {
229 self.nodeui
230 .set_text_value("actionSectorName", sector.name.clone());
231
232 let item_name = sector.properties.get_str_default("item", "".into());
233 self.nodeui.set_text_value("actionSectorItem", item_name);
234
235 let visible = sector.properties.get_bool_default("visible", true);
236 self.nodeui.set_bool_value("actionSectorVisible", visible);
237
238 let terrain_mode = sector.properties.get_int_default("terrain_mode", 0);
239 self.nodeui
240 .set_i32_value("actionSectorTerrain", terrain_mode);
241
242 let ridge_height = sector.properties.get_float_default("ridge_height", 1.0);
243 self.nodeui
244 .set_f32_value("actionSectorTerrainRidgeHeight", ridge_height);
245
246 let ridge_plateau = sector
247 .properties
248 .get_float_default("ridge_plateau_width", 0.0);
249 self.nodeui
250 .set_f32_value("actionSectorTerrainRidgePlateau", ridge_plateau);
251
252 let ridge_falloff = sector
253 .properties
254 .get_float_default("ridge_falloff_distance", 5.0);
255 self.nodeui
256 .set_f32_value("actionSectorTerrainRidgeFalloff", ridge_falloff);
257 self.nodeui.set_i32_value(
258 "actionSectorTerrainRidgeSubdiv",
259 sector.properties.get_int_default("ridge_subdiv", 1).max(1),
260 );
261 self.nodeui.set_f32_value(
262 "actionSectorTerrainTileFalloff",
263 sector
264 .properties
265 .get_float_default("terrain_tile_falloff", 1.0),
266 );
267
268 self.nodeui.set_bool_value(
269 "actionSectorTerrainRidgeWaterEnabled",
270 sector
271 .properties
272 .get_bool_default("ridge_water_enabled", false),
273 );
274 self.nodeui.set_f32_value(
275 "actionSectorTerrainRidgeWaterLevel",
276 sector
277 .properties
278 .get_float_default("ridge_water_level", 0.0),
279 );
280
281 let terrain_tile_id = if let Some(Value::Source(PixelSource::TileId(id))) =
282 sector.properties.get("terrain_source")
283 {
284 *id
285 } else {
286 Uuid::nil()
287 };
288 self.nodeui.set_text_value(
289 "actionSectorTileId",
290 if terrain_tile_id == Uuid::nil() {
291 String::new()
292 } else {
293 terrain_tile_id.to_string()
294 },
295 );
296 if let Some(item) = self.nodeui.get_item_mut("actionSectorTerrainTile")
297 && let TheNodeUIItem::Icons(_, _, _, items) = item
298 && items.len() == 1
299 {
300 items[0].2 = terrain_tile_id;
301 }
302
303 let ridge_water_tile_id = if let Some(Value::Source(PixelSource::TileId(id))) =
304 sector.properties.get("ridge_water_source")
305 {
306 *id
307 } else {
308 Uuid::nil()
309 };
310 self.nodeui.set_text_value(
311 "actionSectorTerrainRidgeWaterTileId",
312 if ridge_water_tile_id == Uuid::nil() {
313 String::new()
314 } else {
315 ridge_water_tile_id.to_string()
316 },
317 );
318 if let Some(item) = self
319 .nodeui
320 .get_item_mut("actionSectorTerrainRidgeWaterTile")
321 && let TheNodeUIItem::Icons(_, _, _, items) = item
322 && items.len() == 1
323 {
324 items[0].2 = ridge_water_tile_id;
325 }
326
327 let iso_hide_on_enter = match sector.properties.get("iso_hide_on_enter") {
328 Some(Value::StrArray(values)) => values.join(", "),
329 _ => String::new(),
330 };
331 self.nodeui
332 .set_text_value("actionIsoHideOnEnter", iso_hide_on_enter);
333 }
334 }
335 }
336
337 fn load_params_project(&mut self, _project: &Project, server_ctx: &mut ServerContext) {
338 let show_terrain = server_ctx.get_map_context() == MapContext::Region;
339 if show_terrain != self.show_terrain {
340 let name = self
341 .nodeui
342 .get_text_value("actionSectorName")
343 .unwrap_or_default();
344 let item = self
345 .nodeui
346 .get_text_value("actionSectorItem")
347 .unwrap_or_default();
348 let visible = self
349 .nodeui
350 .get_bool_value("actionSectorVisible")
351 .unwrap_or(true);
352 let terrain_mode = self
353 .nodeui
354 .get_i32_value("actionSectorTerrain")
355 .unwrap_or(0);
356 let ridge_height = self
357 .nodeui
358 .get_f32_value("actionSectorTerrainRidgeHeight")
359 .unwrap_or(1.0);
360 let ridge_plateau = self
361 .nodeui
362 .get_f32_value("actionSectorTerrainRidgePlateau")
363 .unwrap_or(0.0);
364 let ridge_falloff = self
365 .nodeui
366 .get_f32_value("actionSectorTerrainRidgeFalloff")
367 .unwrap_or(5.0);
368 let ridge_subdiv = self
369 .nodeui
370 .get_i32_value("actionSectorTerrainRidgeSubdiv")
371 .unwrap_or(1);
372 let terrain_tile_falloff = self
373 .nodeui
374 .get_f32_value("actionSectorTerrainTileFalloff")
375 .unwrap_or(1.0);
376 let ridge_water_enabled = self
377 .nodeui
378 .get_bool_value("actionSectorTerrainRidgeWaterEnabled")
379 .unwrap_or(false);
380 let ridge_water_level = self
381 .nodeui
382 .get_f32_value("actionSectorTerrainRidgeWaterLevel")
383 .unwrap_or(0.0);
384 let tile_id_text = self
385 .nodeui
386 .get_text_value("actionSectorTileId")
387 .unwrap_or_default();
388 let terrain_tile_id = self
389 .nodeui
390 .get_tile_id("actionSectorTerrainTile", 0)
391 .unwrap_or(Uuid::nil());
392 let water_tile_id_text = self
393 .nodeui
394 .get_text_value("actionSectorTerrainRidgeWaterTileId")
395 .unwrap_or_default();
396 let ridge_water_tile_id = self
397 .nodeui
398 .get_tile_id("actionSectorTerrainRidgeWaterTile", 0)
399 .unwrap_or(Uuid::nil());
400 let iso_hide_on_enter = self
401 .nodeui
402 .get_text_value("actionIsoHideOnEnter")
403 .unwrap_or_default();
404
405 self.nodeui = Self::build_nodeui(show_terrain);
406 self.show_terrain = show_terrain;
407
408 self.nodeui.set_text_value("actionSectorName", name);
409 self.nodeui.set_text_value("actionSectorItem", item);
410 self.nodeui.set_bool_value("actionSectorVisible", visible);
411 self.nodeui
412 .set_i32_value("actionSectorTerrain", terrain_mode);
413 self.nodeui
414 .set_f32_value("actionSectorTerrainRidgeHeight", ridge_height);
415 self.nodeui
416 .set_f32_value("actionSectorTerrainRidgePlateau", ridge_plateau);
417 self.nodeui
418 .set_f32_value("actionSectorTerrainRidgeFalloff", ridge_falloff);
419 self.nodeui
420 .set_i32_value("actionSectorTerrainRidgeSubdiv", ridge_subdiv.max(1));
421 self.nodeui
422 .set_f32_value("actionSectorTerrainTileFalloff", terrain_tile_falloff);
423 self.nodeui
424 .set_bool_value("actionSectorTerrainRidgeWaterEnabled", ridge_water_enabled);
425 self.nodeui
426 .set_f32_value("actionSectorTerrainRidgeWaterLevel", ridge_water_level);
427 self.nodeui
428 .set_text_value("actionSectorTileId", tile_id_text);
429 if let Some(item) = self.nodeui.get_item_mut("actionSectorTerrainTile")
430 && let TheNodeUIItem::Icons(_, _, _, items) = item
431 && items.len() == 1
432 {
433 items[0].2 = terrain_tile_id;
434 }
435 self.nodeui
436 .set_text_value("actionSectorTerrainRidgeWaterTileId", water_tile_id_text);
437 if let Some(item) = self
438 .nodeui
439 .get_item_mut("actionSectorTerrainRidgeWaterTile")
440 && let TheNodeUIItem::Icons(_, _, _, items) = item
441 && items.len() == 1
442 {
443 items[0].2 = ridge_water_tile_id;
444 }
445 self.nodeui
446 .set_text_value("actionIsoHideOnEnter", iso_hide_on_enter);
447 }
448 }
449
450 fn apply(
451 &self,
452 map: &mut Map,
453 _ui: &mut TheUI,
454 _ctx: &mut TheContext,
455 server_ctx: &mut ServerContext,
456 ) -> Option<ProjectUndoAtom> {
457 let mut changed = false;
458 let prev = map.clone();
459
460 let name = self
461 .nodeui
462 .get_text_value("actionSectorName")
463 .unwrap_or(String::new());
464
465 let item = self
466 .nodeui
467 .get_text_value("actionSectorItem")
468 .unwrap_or(String::new());
469
470 let visible = self
471 .nodeui
472 .get_bool_value("actionSectorVisible")
473 .unwrap_or(true);
474 let is_region_mode = server_ctx.get_map_context() == MapContext::Region;
475 let terrain_role = self
476 .nodeui
477 .get_i32_value("actionSectorTerrain")
478 .unwrap_or(0);
479 let ridge_height = self
480 .nodeui
481 .get_f32_value("actionSectorTerrainRidgeHeight")
482 .unwrap_or(1.0);
483 let ridge_plateau = self
484 .nodeui
485 .get_f32_value("actionSectorTerrainRidgePlateau")
486 .unwrap_or(0.0);
487 let ridge_falloff = self
488 .nodeui
489 .get_f32_value("actionSectorTerrainRidgeFalloff")
490 .unwrap_or(5.0);
491 let ridge_subdiv = self
492 .nodeui
493 .get_i32_value("actionSectorTerrainRidgeSubdiv")
494 .unwrap_or(1)
495 .clamp(1, 8);
496 let terrain_tile_falloff = self
497 .nodeui
498 .get_f32_value("actionSectorTerrainTileFalloff")
499 .unwrap_or(1.0);
500 let terrain_tile_id = self
501 .nodeui
502 .get_tile_id("actionSectorTerrainTile", 0)
503 .unwrap_or(Uuid::nil());
504 let ridge_water_enabled = self
505 .nodeui
506 .get_bool_value("actionSectorTerrainRidgeWaterEnabled")
507 .unwrap_or(false);
508 let ridge_water_level = self
509 .nodeui
510 .get_f32_value("actionSectorTerrainRidgeWaterLevel")
511 .unwrap_or(0.0);
512 let ridge_water_tile_id = self
513 .nodeui
514 .get_tile_id("actionSectorTerrainRidgeWaterTile", 0)
515 .unwrap_or(Uuid::nil());
516 let tile_id_text = self
517 .nodeui
518 .get_text_value("actionSectorTileId")
519 .unwrap_or_default();
520 let terrain_tile_id = if let Ok(id) = Uuid::parse_str(tile_id_text.trim()) {
521 id
522 } else {
523 terrain_tile_id
524 };
525 let ridge_water_tile_text = self
526 .nodeui
527 .get_text_value("actionSectorTerrainRidgeWaterTileId")
528 .unwrap_or_default();
529 let ridge_water_tile_id = if let Ok(id) = Uuid::parse_str(ridge_water_tile_text.trim()) {
530 id
531 } else {
532 ridge_water_tile_id
533 };
534 let iso_hide_on_enter = self
535 .nodeui
536 .get_text_value("actionIsoHideOnEnter")
537 .unwrap_or_default();
538 let iso_hide_patterns = parse_hide_patterns(&iso_hide_on_enter);
539
540 if let Some(sector_id) = map.selected_sectors.first() {
541 if let Some(sector) = map.find_sector_mut(*sector_id) {
542 if name != sector.name {
543 sector.name = name;
544 changed = true;
545 }
546
547 let it = sector.properties.get_str_default("item", "".into());
548 if item != it {
549 sector.properties.set("item", Value::Str(item));
550 changed = true;
551 }
552
553 let vis = sector.properties.get_bool_default("visible", true);
554 if vis != visible {
555 sector.properties.set("visible", Value::Bool(visible));
556 changed = true;
557 }
558
559 if is_region_mode {
560 let terr = sector.properties.get_int_default("terrain_mode", 0);
561 if terrain_role != terr {
562 sector
563 .properties
564 .set("terrain_mode", Value::Int(terrain_role));
565 changed = true;
566 }
567
568 let r_height = sector.properties.get_float_default("ridge_height", 1.0);
569 if ridge_height != r_height {
570 sector
571 .properties
572 .set("ridge_height", Value::Float(ridge_height));
573 changed = true;
574 }
575
576 let r_plateau = sector
577 .properties
578 .get_float_default("ridge_plateau_width", 0.0);
579 if ridge_plateau != r_plateau {
580 sector
581 .properties
582 .set("ridge_plateau_width", Value::Float(ridge_plateau));
583 changed = true;
584 }
585
586 let r_falloff = sector
587 .properties
588 .get_float_default("ridge_falloff_distance", 5.0);
589 if ridge_falloff != r_falloff {
590 sector
591 .properties
592 .set("ridge_falloff_distance", Value::Float(ridge_falloff));
593 changed = true;
594 }
595
596 let r_subdiv = sector.properties.get_int_default("ridge_subdiv", 1).max(1);
597 if ridge_subdiv != r_subdiv {
598 sector
599 .properties
600 .set("ridge_subdiv", Value::Int(ridge_subdiv));
601 changed = true;
602 }
603
604 let r_tile_falloff = sector
605 .properties
606 .get_float_default("terrain_tile_falloff", 1.0);
607 if (r_tile_falloff - terrain_tile_falloff).abs() > f32::EPSILON {
608 sector.properties.set(
609 "terrain_tile_falloff",
610 Value::Float(terrain_tile_falloff.max(0.0)),
611 );
612 changed = true;
613 }
614
615 let curr_ridge_water_enabled = sector
616 .properties
617 .get_bool_default("ridge_water_enabled", false);
618 if curr_ridge_water_enabled != ridge_water_enabled {
619 sector
620 .properties
621 .set("ridge_water_enabled", Value::Bool(ridge_water_enabled));
622 changed = true;
623 }
624
625 let curr_ridge_water_level = sector
626 .properties
627 .get_float_default("ridge_water_level", 0.0);
628 if (curr_ridge_water_level - ridge_water_level).abs() > f32::EPSILON {
629 sector
630 .properties
631 .set("ridge_water_level", Value::Float(ridge_water_level));
632 changed = true;
633 }
634
635 match terrain_tile_id {
636 id if id != Uuid::nil() => {
637 let has_changed = match sector.properties.get("terrain_source") {
638 Some(Value::Source(PixelSource::TileId(existing))) => {
639 *existing != id
640 }
641 _ => true,
642 };
643 if has_changed {
644 sector
645 .properties
646 .set("terrain_source", Value::Source(PixelSource::TileId(id)));
647 changed = true;
648 }
649 }
650 _ => {
651 if sector.properties.contains("terrain_source") {
652 sector.properties.remove("terrain_source");
653 changed = true;
654 }
655 }
656 }
657
658 match ridge_water_tile_id {
659 id if id != Uuid::nil() => {
660 let has_changed = match sector.properties.get("ridge_water_source") {
661 Some(Value::Source(PixelSource::TileId(existing))) => {
662 *existing != id
663 }
664 _ => true,
665 };
666 if has_changed {
667 sector.properties.set(
668 "ridge_water_source",
669 Value::Source(PixelSource::TileId(id)),
670 );
671 changed = true;
672 }
673 }
674 _ => {
675 if sector.properties.contains("ridge_water_source") {
676 sector.properties.remove("ridge_water_source");
677 changed = true;
678 }
679 }
680 }
681
682 let curr_iso_hide = match sector.properties.get("iso_hide_on_enter") {
683 Some(Value::StrArray(values)) => values.clone(),
684 _ => Vec::new(),
685 };
686 if curr_iso_hide != iso_hide_patterns {
687 if iso_hide_patterns.is_empty() {
688 sector.properties.remove("iso_hide_on_enter");
689 } else {
690 sector.properties.set(
691 "iso_hide_on_enter",
692 Value::StrArray(iso_hide_patterns.clone()),
693 );
694 }
695 changed = true;
696 }
697 }
698 }
699 }
700
701 if changed {
702 Some(ProjectUndoAtom::MapEdit(
703 server_ctx.pc,
704 Box::new(prev),
705 Box::new(map.clone()),
706 ))
707 } else {
708 None
709 }
710 }
711
712 fn apply_project(
713 &self,
714 project: &mut Project,
715 ui: &mut TheUI,
716 _ctx: &mut TheContext,
717 server_ctx: &mut ServerContext,
718 ) {
719 if let ProjectContext::ScreenWidget(id, widget_id) = server_ctx.pc {
721 if let Some(tree_layout) = ui.get_tree_layout("Project Tree") {
722 if let Some(node) = tree_layout.get_node_by_id_mut(&id) {
723 if let Some(screen) = project.screens.get(&id) {
724 gen_screen_tree_items(node, screen);
725 }
726 node.new_item_selected(&TheId::named_with_id_and_reference(
727 "Screen Content List Item",
728 widget_id,
729 id,
730 ));
731 }
732 }
733 }
734 }
735
736 fn params(&self) -> TheNodeUI {
737 self.nodeui.clone()
738 }
739
740 fn handle_event(
741 &mut self,
742 event: &TheEvent,
743 project: &mut Project,
744 _ui: &mut TheUI,
745 ctx: &mut TheContext,
746 _server_ctx: &mut ServerContext,
747 ) -> bool {
748 if let TheEvent::TileDropped(id, tile_id, index) = event
749 && id.name == "actionSectorTerrainTile"
750 && let Some(tile) = project.tiles.get(tile_id)
751 && !tile.is_empty()
752 && let Some(TheNodeUIItem::Icons(_, _, _, items)) =
753 self.nodeui.get_item_mut("actionSectorTerrainTile")
754 {
755 items[*index].0 = tile.textures[0].to_rgba();
756 items[*index].2 = *tile_id;
757 self.nodeui
758 .set_text_value("actionSectorTileId", tile_id.to_string());
759 ctx.ui.send(TheEvent::Custom(
760 TheId::named("Update Action List"),
761 TheValue::Empty,
762 ));
763 return true;
764 }
765 if let TheEvent::TileDropped(id, tile_id, index) = event
766 && id.name == "actionSectorTerrainRidgeWaterTile"
767 && let Some(tile) = project.tiles.get(tile_id)
768 && !tile.is_empty()
769 && let Some(TheNodeUIItem::Icons(_, _, _, items)) = self
770 .nodeui
771 .get_item_mut("actionSectorTerrainRidgeWaterTile")
772 {
773 items[*index].0 = tile.textures[0].to_rgba();
774 items[*index].2 = *tile_id;
775 self.nodeui
776 .set_text_value("actionSectorTerrainRidgeWaterTileId", tile_id.to_string());
777 ctx.ui.send(TheEvent::Custom(
778 TheId::named("Update Action List"),
779 TheValue::Empty,
780 ));
781 return true;
782 }
783 self.nodeui.handle_event(event)
784 }
785}