pub trait NodeTemplate {
// Required methods
fn node_ui(
&self,
ui: &mut Ui,
_viewport_position: Pos2,
_zoom: f32,
_point: &MapPoint,
);
fn selection_ui(&self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32);
fn notification_ui(&self, ui: &mut Ui, ctx: NotificationContext) -> bool;
fn marker_ui(&self, ui: &mut Ui, ctx: MarkerContext);
}Expand description
Customizes how nodes and their visual effects are rendered.
When a template is installed with
Map::set_node_template, the widget
delegates all node painting to it instead of using the built-in shapes and
animations — including the node name labels, so draw the name yourself in
NodeTemplate::node_ui if you need it.
The positions passed to these methods are in screen coordinates: already
scaled by zoom and translated to the viewport origin. Multiply every size
by zoom so your shapes scale together with the map.
§Animation idioms
egui only repaints on demand, so any method that animates (a blinking
marker, a fading notification, …) must call
ui.ctx().request_repaint() to keep the
frames coming. Time-driven effects are usually computed from
Instant::now() (see initial_time in
NodeTemplate::notification_ui) or from the system clock.
§Examples
A node drawn as a rounded box with its name inside, plus a notification animation that expands and fades out over two seconds:
use egui_map::map::objects::{MapPoint, NodeTemplate, NotificationContext, MarkerContext};
use egui::{Align2, Color32, CornerRadius, FontId, Pos2, Rect, Stroke, Ui, Vec2};
use std::time::Instant;
struct BoxedNodes;
impl NodeTemplate for BoxedNodes {
fn node_ui(&self, ui: &mut Ui, position: Pos2, zoom: f32, point: &MapPoint) {
// Multiply every size by `zoom` so the node scales with the map.
let rect = Rect::from_center_size(position, Vec2::new(90.0 * zoom, 35.0 * zoom));
let rounding = CornerRadius::same((10.0 * zoom) as u8);
let painter = ui.painter();
painter.rect_filled(rect, rounding, ui.visuals().extreme_bg_color);
painter.rect_stroke(
rect,
rounding,
Stroke::new(4.0 * zoom, Color32::WHITE),
egui::StrokeKind::Middle,
);
painter.text(
position,
Align2::CENTER_CENTER,
point.get_name(),
FontId::proportional(12.0 * zoom),
Color32::WHITE,
);
}
fn notification_ui(&self, ui: &mut Ui, ctx: NotificationContext) -> bool {
let secs = Instant::now().duration_since(ctx.initial_time).as_secs_f32();
// Expand the stroke and fade the color out over 2 seconds.
let alpha = (1.0 - secs / 2.0).clamp(0.0, 1.0);
let fading = Color32::from_rgba_unmultiplied(
ctx.color.r(),
ctx.color.g(),
ctx.color.b(),
(255.0 * alpha) as u8,
);
let rect = Rect::from_center_size(ctx.position, Vec2::new(90.0 * ctx.zoom, 35.0 * ctx.zoom));
ui.painter().rect_stroke(
rect,
CornerRadius::same((10.0 * ctx.zoom) as u8),
Stroke::new((4.0 + 25.0 * secs) * ctx.zoom, fading),
egui::StrokeKind::Middle,
);
// Keep the animation frames coming.
ui.ctx().request_repaint();
// Returning `false` removes the notification.
secs < 2.0
}
}§Note on NodeAnimation/SteadyAnimation in the examples above
The hidden (#-prefixed) stub methods above still take Pos2/f32
directly rather than a context struct – only NotificationContext and
MarkerContext exist; node_ui/selection_ui were not wide enough to
need one.
Required Methods§
Sourcefn node_ui(
&self,
ui: &mut Ui,
_viewport_position: Pos2,
_zoom: f32,
_point: &MapPoint,
)
fn node_ui( &self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32, _point: &MapPoint, )
Draws a node, replacing the default filled circle.
Called every frame for each visible node. The widget no longer draws
the node name once a template is installed, so render it here (e.g.
with Painter::text) if you need it.
Sourcefn selection_ui(&self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32)
fn selection_ui(&self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32)
Draws the highlight over the node closest to the mouse pointer.
The nearest node is only computed while the pointer is over the map and
MapSettings::node_text_visibility is VisibilitySetting::Hover.
Sourcefn notification_ui(&self, ui: &mut Ui, ctx: NotificationContext) -> bool
fn notification_ui(&self, ui: &mut Ui, ctx: NotificationContext) -> bool
Draws the notification effect of a node notified at
ctx.initial_time.
Called every frame for each node passed to
Map::notify or animated through
Map::node’s event methods (pulse, ripple,
…). ctx.kind is which of those was requested and ctx.node_id is
the id of the node it belongs to – use them to dispatch to the
matching built-in Animation
function (or your own effect) instead of reimplementing every
animation by hand. See NotificationContext for the rest of the
fields. Should return true while the animation is still playing —
remember to call
ui.ctx().request_repaint() —;
once it returns false the notification is discarded.
Sourcefn marker_ui(&self, ui: &mut Ui, ctx: MarkerContext)
fn marker_ui(&self, ui: &mut Ui, ctx: MarkerContext)
Draws a marker over the given node.
Called every frame for two different things – see MarkerContext
for what ctx.kind/ctx.node_id mean in each case. For animated
markers (e.g. a blinking light), drive the effect from the system
clock and call
ui.ctx().request_repaint().
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".