Skip to main content

egui_map_view/layers/area/
layer.rs

1use crate::layers::{default_opacity, Layer};
2use crate::projection::MapProjection;
3use egui::{Color32, Painter, Response};
4use serde::{Deserialize, Serialize};
5use std::any::Any;
6
7use super::types::{Area, AreaMode, DraggedObject};
8
9/// Layer implementation that allows the user to draw polygons on the map.
10#[derive(Clone, Serialize, Deserialize)]
11#[serde(default)]
12pub struct AreaLayer {
13    pub(crate) areas: Vec<Area>,
14
15    #[serde(skip)]
16    /// The radius of the nodes.
17    pub node_radius: f32,
18
19    #[serde(skip)]
20    /// The fill color of the nodes.
21    pub node_fill: Color32,
22
23    #[serde(skip)]
24    /// The current drawing mode.
25    pub mode: AreaMode,
26
27    #[serde(skip)]
28    pub(crate) dragged_object: Option<DraggedObject>,
29
30    #[serde(skip)]
31    pub(crate) hovered_object: Option<DraggedObject>,
32
33    /// The opacity of the layer.
34    #[serde(default = "default_opacity")]
35    pub opacity: f32,
36
37    #[serde(skip)]
38    /// The index of the currently selected area. Only used when in `AreaMode::Selected`.
39    pub selected_area: Option<usize>,
40}
41
42impl Default for AreaLayer {
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48impl AreaLayer {
49    /// Creates a new `AreaLayer`.
50    #[must_use]
51    pub fn new() -> Self {
52        Self {
53            areas: Vec::new(),
54            node_radius: 5.0,
55            node_fill: Color32::from_rgb(0, 128, 0),
56            mode: AreaMode::default(),
57            dragged_object: None,
58            hovered_object: None,
59            opacity: 1.0,
60            selected_area: None,
61        }
62    }
63
64    /// Adds a new area to the layer.
65    pub fn add_area(&mut self, area: Area) {
66        self.areas.push(area);
67    }
68
69    /// Returns a reference to the areas in the layer.
70    #[must_use]
71    pub fn areas(&self) -> &Vec<Area> {
72        &self.areas
73    }
74
75    /// Returns a mutable reference to the areas in the layer.
76    pub fn areas_mut(&mut self) -> &mut Vec<Area> {
77        &mut self.areas
78    }
79}
80
81impl Layer for AreaLayer {
82    fn as_any(&self) -> &dyn Any {
83        self
84    }
85
86    fn as_any_mut(&mut self) -> &mut dyn Any {
87        self
88    }
89
90    fn opacity(&self) -> f32 {
91        self.opacity
92    }
93
94    fn set_opacity(&mut self, opacity: f32) {
95        self.opacity = opacity;
96    }
97
98    fn handle_input(&mut self, response: &Response, projection: &MapProjection) -> bool {
99        match self.mode {
100            AreaMode::Disabled => {
101                self.hovered_object = None;
102                false
103            }
104            AreaMode::Modify => self.handle_modify_input(response, projection, None),
105            AreaMode::ModifySelected => {
106                if response.clicked()
107                    && let Some(pointer_pos) = response.interact_pointer_pos()
108                {
109                    // Find if any area was clicked to select it.
110                    let clicked_area_idx =
111                        self.areas.iter().enumerate().rev().find_map(|(idx, area)| {
112                            let contains_fill = area.contains(pointer_pos, projection);
113                            let over_handle = self.find_object_at(pointer_pos, projection, Some(idx)).is_some();
114                            let over_segment = self.find_line_segment_at(pointer_pos, projection, Some(idx)).is_some();
115
116                            if contains_fill || over_handle || over_segment {
117                                Some(idx)
118                            } else {
119                                None
120                            }
121                        });
122
123                    if clicked_area_idx != self.selected_area {
124                        self.selected_area = clicked_area_idx;
125                        return true;
126                    }
127                }
128
129                if let Some(selected_idx) = self.selected_area {
130                    self.handle_modify_input(response, projection, Some(selected_idx))
131                } else {
132                    false
133                }
134            }
135        }
136    }
137
138    fn draw(&self, painter: &Painter, projection: &MapProjection) {
139        self.draw_layer(painter, projection);
140    }
141}