use crate::annotation_system::annotation_support::AnnotationKey;
use crate::gui_system::latitude_longitude::LatitudeLongitude;
use crate::gui_system::map_widget::map_widget_components::{
MapInteractionCommand, SpecificInteractionCommand,
};
use iced::advanced::graphics::geometry::Frame;
use iced::widget::Action;
use iced::widget::canvas::Text;
use iced::{Color, Renderer, Vector};
use std::time::{Duration, Instant};
pub(crate) const HALO_COLOR: Color = Color::from_rgba(1.0, 1.0, 1.0, 0.8);
const HALO_WIDTH: f32 = 1.0;
const HOVER_DELAY: Duration = Duration::from_secs(1);
pub(crate) fn fill_text_with_halo(frame: &mut Frame<Renderer>, text: Text) {
for (dx, dy) in [
(-1.0, -1.0),
(0.0, -1.0),
(1.0, -1.0),
(-1.0, 0.0),
(1.0, 0.0),
(-1.0, 1.0),
(0.0, 1.0),
(1.0, 1.0),
] {
frame.fill_text(Text {
position: text.position + Vector::new(dx, dy) * HALO_WIDTH,
color: HALO_COLOR,
..text.clone()
});
}
frame.fill_text(text);
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct HoverTarget {
pub(crate) key: AnnotationKey,
pub(crate) anchor: LatitudeLongitude,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct HoverHit {
pub(crate) target: HoverTarget,
pub(crate) cursor: LatitudeLongitude,
}
#[derive(Debug, Clone, Copy)]
struct Hover {
target: HoverTarget,
visible_at: Instant,
}
#[derive(Debug, Default)]
pub(crate) struct AnnotationInteractionState {
hovered: Option<Hover>,
}
impl AnnotationInteractionState {
pub(crate) fn aim(
&mut self,
hit: Option<HoverHit>,
client_id: u32,
) -> Option<Action<MapInteractionCommand>> {
let target = hit.map(|hit| hit.target);
if self.hovered.map(|hover| hover.target) == target {
return None;
}
let was_visible = self.description_target().is_some();
self.hovered = target.map(|target| Hover {
target,
visible_at: Instant::now() + HOVER_DELAY,
});
match hit {
Some(hit) => Some(Action::publish(MapInteractionCommand {
client_id,
command: SpecificInteractionCommand::AnnotationHovered(hit.target.key, hit.cursor),
})),
None => was_visible.then(Action::request_redraw),
}
}
pub(crate) fn settle(&self, now: Instant) -> Option<Action<MapInteractionCommand>> {
let hover = self.hovered?;
(now < hover.visible_at).then(|| Action::request_redraw_at(hover.visible_at))
}
pub(crate) fn description_target(&self) -> Option<HoverTarget> {
self.hovered
.filter(|hover| Instant::now() >= hover.visible_at)
.map(|hover| hover.target)
}
}