Skip to main content

rustapi/actions/
edit_sector.rs

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        // let item = TheNodeUIItem::Markdown("desc".into(), fl!("action_edit_sector_desc"));
194        // nodeui.add_item(item);
195
196        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 the update sector is a screen widget, refresh the screen list to show potential new names
720        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}