use egui::{Context, Pos2, RawInput, Ui};
use egui_map::map::Map;
use egui_map::map::objects::{
MapPoint, MarkerContext, NodeAnimation, NodeTemplate, NotificationContext, SteadyAnimation,
};
use std::cell::RefCell;
use std::rc::Rc;
use std::time::Instant;
#[derive(Default)]
struct RecordingTemplate {
notifications: RefCell<Vec<(NodeAnimation, usize)>>,
markers: RefCell<Vec<(SteadyAnimation, usize)>>,
}
impl NodeTemplate for RecordingTemplate {
fn node_ui(&self, _ui: &mut Ui, _position: Pos2, _zoom: f32, _point: &MapPoint) {}
fn selection_ui(&self, _ui: &mut Ui, _position: Pos2, _zoom: f32) {}
fn notification_ui(&self, ui: &mut Ui, ctx: NotificationContext) -> bool {
self.notifications
.borrow_mut()
.push((ctx.kind, ctx.node_id));
ui.ctx().request_repaint();
true
}
fn marker_ui(&self, ui: &mut Ui, ctx: MarkerContext) {
self.markers.borrow_mut().push((ctx.kind, ctx.node_id));
ui.ctx().request_repaint();
}
}
fn map_with_two_nodes() -> Map {
let mut map = Map::new();
map.add_points(vec![
MapPoint::new(1, [0.0, 0.0]),
MapPoint::new(2, [50.0, 0.0]),
]);
map
}
fn render_once(map: &mut Map) {
let ctx = Context::default();
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(400.0, 300.0));
let mut out = ctx.run_ui(
RawInput {
screen_rect: Some(screen),
..RawInput::default()
},
|ui| {
ui.add(&mut *map);
},
);
out.textures_delta.clear();
}
#[test]
fn notification_ui_receives_the_requested_kind_and_node_id() {
let template = Rc::new(RecordingTemplate::default());
let mut map = map_with_two_nodes();
map.set_node_template(template.clone());
map.node(1).unwrap().ripple(Instant::now());
map.node(2).unwrap().crosshair(Instant::now());
render_once(&mut map);
let mut seen = template.notifications.borrow().clone();
seen.sort_by_key(|(_, id)| *id);
assert_eq!(
seen,
vec![(NodeAnimation::Ripple, 1), (NodeAnimation::Crosshair, 2)],
"the template must be told exactly which NodeAnimation each node requested"
);
}
#[test]
fn marker_ui_receives_the_requested_kind_for_persistent_state() {
let template = Rc::new(RecordingTemplate::default());
let mut map = map_with_two_nodes();
map.set_node_template(template.clone());
map.node(1).unwrap().halo();
map.node(2).unwrap().orbit();
render_once(&mut map);
let mut seen = template.markers.borrow().clone();
seen.sort_by_key(|(_, id)| *id);
assert_eq!(
seen,
vec![(SteadyAnimation::Halo, 1), (SteadyAnimation::Orbit, 2)],
"the template must be told exactly which SteadyAnimation each node's state requested"
);
}
#[test]
fn marker_ui_receives_the_shared_marker_animation_kind_for_update_marker() {
let template = Rc::new(RecordingTemplate::default());
let mut map = map_with_two_nodes();
map.set_node_template(template.clone());
map.settings.marker_animation = SteadyAnimation::Orbit;
map.update_marker(100, 2);
render_once(&mut map);
assert_eq!(
*template.markers.borrow(),
vec![(SteadyAnimation::Orbit, 2)],
"a Map::update_marker marker must report MapSettings::marker_animation as its kind, \
and the id of the node it points at"
);
}