use crate::annotation_system::annotation_support::{
Annotation, ClosestPoint, DirectionFlag, LabelPosition, MercatorRectangle, RenderingInformation,
};
use crate::gui_system::internal_math::MercatorPoint;
use crate::gui_system::latitude_longitude::LatitudeLongitude;
use crate::gui_system::map_widget::map_widget_components::FocusTarget;
pub use bytes::Bytes;
use iced::Color;
use iced::advanced::image::Handle;
use slotmap::{SlotMap, new_key_type};
const WAYPOINT_HALF_SIZE: f64 = 12.0;
new_key_type! {
pub struct WaypointKey;
}
#[derive(Debug, Clone)]
pub struct WaypointSymbol(InternalWaypointImage);
impl WaypointSymbol {
pub fn image(data: impl Into<Bytes>) -> Self {
WaypointSymbol(InternalWaypointImage::Image(Handle::from_bytes(
data.into(),
)))
}
pub fn cross(color: Color) -> Self {
WaypointSymbol(InternalWaypointImage::Cross(color))
}
}
#[derive(Debug, Clone, Default)]
pub struct WaypointSystem {
pub(crate) waypoint_collection: SlotMap<WaypointKey, WaypointInfo>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WaypointError {
KeyNotContained,
}
impl WaypointSystem {
pub fn add_way_point(
&mut self,
symbol: WaypointSymbol,
position: LatitudeLongitude,
description: Option<String>,
) -> WaypointKey {
self.waypoint_collection.insert(WaypointInfo {
image: symbol.0,
mercator_rectangle: MercatorRectangle::create_from_position(
position,
WAYPOINT_HALF_SIZE,
),
description,
flag: None,
})
}
pub fn update_waypoint_position(
&mut self,
key: WaypointKey,
position: LatitudeLongitude,
) -> Result<(), WaypointError> {
self.waypoint_collection
.get_mut(key)
.ok_or(WaypointError::KeyNotContained)?
.mercator_rectangle =
MercatorRectangle::create_from_position(position, WAYPOINT_HALF_SIZE);
Ok(())
}
pub fn update_waypoint_symbol(
&mut self,
key: WaypointKey,
symbol: WaypointSymbol,
) -> Result<(), WaypointError> {
self.waypoint_collection
.get_mut(key)
.ok_or(WaypointError::KeyNotContained)?
.image = symbol.0;
Ok(())
}
pub fn update_waypoint_description(
&mut self,
key: WaypointKey,
description: Option<String>,
) -> Result<(), WaypointError> {
self.waypoint_collection
.get_mut(key)
.ok_or(WaypointError::KeyNotContained)?
.description = description;
Ok(())
}
pub fn set_flag(
&mut self,
key: WaypointKey,
flag: Option<DirectionFlag>,
) -> Result<(), WaypointError> {
self.waypoint_collection
.get_mut(key)
.ok_or(WaypointError::KeyNotContained)?
.flag = flag;
Ok(())
}
pub fn delete_waypoint(&mut self, key: WaypointKey) -> Result<(), WaypointError> {
let deletion = self.waypoint_collection.remove(key);
if deletion.is_some() {
Ok(())
} else {
Err(WaypointError::KeyNotContained)
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum InternalWaypointImage {
Image(Handle),
Cross(Color),
}
#[derive(Debug, Clone)]
pub(crate) struct WaypointInfo {
pub(crate) image: InternalWaypointImage,
pub(crate) description: Option<String>,
pub(crate) flag: Option<DirectionFlag>,
pub(crate) mercator_rectangle: MercatorRectangle,
}
impl Annotation for WaypointInfo {
fn description(&self, _cursor: LatitudeLongitude) -> Option<String> {
self.description.clone()
}
fn cull_bounds(&self) -> &MercatorRectangle {
&self.mercator_rectangle
}
fn closest_point(&self, _position: MercatorPoint) -> ClosestPoint {
ClosestPoint::Inside
}
fn focus_target(&self, _fill: f32) -> FocusTarget {
FocusTarget::Position(self.get_center())
}
fn label_anchor(&self, _cursor: LatitudeLongitude) -> LabelPosition {
LabelPosition::FixGeoLocation(self.mercator_rectangle.get_center())
}
fn get_flag(&self) -> Option<DirectionFlag> {
self.flag
}
fn get_render_information(&self) -> RenderingInformation<'_> {
match self.image.clone() {
InternalWaypointImage::Image(image) => RenderingInformation::Image(image),
InternalWaypointImage::Cross(color) => RenderingInformation::Cross(color),
}
}
fn clone_box(&self) -> Box<dyn Annotation> {
Box::new(self.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creation_deletion() {
let mut system = WaypointSystem::default();
let key = system.add_way_point(
WaypointSymbol::cross(Color::WHITE),
LatitudeLongitude::new(50.0, 7.0),
None,
);
assert_ne!(key, WaypointKey::default());
let first = system.delete_waypoint(key);
assert!(first.is_ok(), "We should have some data here.");
let second = system.delete_waypoint(key);
assert!(second.is_err(), "That should be empty.");
}
}