use crate::layers::{default_opacity, Layer};
use crate::projection::MapProjection;
use egui::{Color32, Painter, Response};
use serde::{Deserialize, Serialize};
use std::any::Any;
use super::types::{Area, AreaMode, DraggedObject};
#[derive(Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct AreaLayer {
pub(crate) areas: Vec<Area>,
#[serde(skip)]
pub node_radius: f32,
#[serde(skip)]
pub node_fill: Color32,
#[serde(skip)]
pub mode: AreaMode,
#[serde(skip)]
pub(crate) dragged_object: Option<DraggedObject>,
#[serde(skip)]
pub(crate) hovered_object: Option<DraggedObject>,
#[serde(default = "default_opacity")]
pub opacity: f32,
#[serde(skip)]
pub selected_area: Option<usize>,
}
impl Default for AreaLayer {
fn default() -> Self {
Self::new()
}
}
impl AreaLayer {
#[must_use]
pub fn new() -> Self {
Self {
areas: Vec::new(),
node_radius: 5.0,
node_fill: Color32::from_rgb(0, 128, 0),
mode: AreaMode::default(),
dragged_object: None,
hovered_object: None,
opacity: 1.0,
selected_area: None,
}
}
pub fn add_area(&mut self, area: Area) {
self.areas.push(area);
}
#[must_use]
pub fn areas(&self) -> &Vec<Area> {
&self.areas
}
pub fn areas_mut(&mut self) -> &mut Vec<Area> {
&mut self.areas
}
}
impl Layer for AreaLayer {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn opacity(&self) -> f32 {
self.opacity
}
fn set_opacity(&mut self, opacity: f32) {
self.opacity = opacity;
}
fn handle_input(&mut self, response: &Response, projection: &MapProjection) -> bool {
match self.mode {
AreaMode::Disabled => {
self.hovered_object = None;
false
}
AreaMode::Modify => self.handle_modify_input(response, projection, None),
AreaMode::ModifySelected => {
if response.clicked()
&& let Some(pointer_pos) = response.interact_pointer_pos()
{
let clicked_area_idx =
self.areas.iter().enumerate().rev().find_map(|(idx, area)| {
let contains_fill = area.contains(pointer_pos, projection);
let over_handle = self.find_object_at(pointer_pos, projection, Some(idx)).is_some();
let over_segment = self.find_line_segment_at(pointer_pos, projection, Some(idx)).is_some();
if contains_fill || over_handle || over_segment {
Some(idx)
} else {
None
}
});
if clicked_area_idx != self.selected_area {
self.selected_area = clicked_area_idx;
return true;
}
}
if let Some(selected_idx) = self.selected_area {
self.handle_modify_input(response, projection, Some(selected_idx))
} else {
false
}
}
}
}
fn draw(&self, painter: &Painter, projection: &MapProjection) {
self.draw_layer(painter, projection);
}
}