Skip to main content

NodeTemplate

Trait NodeTemplate 

Source
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§

Source

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.

Source

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.

Source

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.

Source

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".

Implementors§