Skip to content
Snippets Groups Projects
arrow.rs 2.46 KiB
Newer Older
Finn Bear's avatar
Finn Bear committed
use crate::egui::{Align2, Pos2, Stroke, Ui};
use eframe::egui::{Color32, FontFamily, FontId, Shape};
Finn Bear's avatar
Finn Bear committed
use eframe::emath::Rot2;
Finn Bear's avatar
Finn Bear committed
use std::cmp::Ordering;
Finn Bear's avatar
Finn Bear committed

/// Pointy line used to emphasize something.
Finn Bear's avatar
Finn Bear committed
#[must_use = "must call show"]
Finn Bear's avatar
Finn Bear committed
pub struct Arrow {
    pub origin: Pos2,
    pub tip: Pos2,
Finn Bear's avatar
Finn Bear committed
    pub stroke: Color32,
    pub stroke_width: f32,
    pub label: String,
    pub font_size: f32,
}

impl Default for Arrow {
    fn default() -> Self {
        Self {
            origin: Pos2::ZERO,
            tip: Pos2::new(1.0, 1.0),
            stroke: Color32::BLACK,
            stroke_width: 6.0,
            label: String::new(),
            font_size: 40.0,
        }
    }
Finn Bear's avatar
Finn Bear committed
}

impl Arrow {
    pub fn show(&self, ui: &mut Ui) {
        // Based on: https://docs.rs/egui/latest/src/egui/widgets/plot/items/mod.rs.html#977-985
        let vector = self.tip - self.origin;
        let rot = Rot2::from_angle(std::f32::consts::TAU / 10.0);
Finn Bear's avatar
Finn Bear committed
        let tip_length = self.stroke_width * 4.0;
Finn Bear's avatar
Finn Bear committed
        let tip = self.origin + vector;
        let dir = vector.normalized();
Finn Bear's avatar
Finn Bear committed
        let stroke = Stroke::new(self.stroke_width, self.stroke);
Finn Bear's avatar
Finn Bear committed
        ui.painter()
Finn Bear's avatar
Finn Bear committed
            .add(Shape::line_segment([self.origin, self.tip], stroke));
Finn Bear's avatar
Finn Bear committed
        ui.painter().add(Shape::line(
            vec![
                tip - tip_length * (rot.inverse() * dir),
                tip,
                tip - tip_length * (rot * dir),
            ],
Finn Bear's avatar
Finn Bear committed
            stroke,
Finn Bear's avatar
Finn Bear committed
        ));
Finn Bear's avatar
Finn Bear committed
        if !self.label.is_empty() {
            let align = match (vector.x.total_cmp(&0.0), vector.y.total_cmp(&0.0)) {
                (Ordering::Less, Ordering::Less) => Align2::LEFT_TOP,
                (Ordering::Less, Ordering::Equal) => Align2::LEFT_CENTER,
                (Ordering::Less, Ordering::Greater) => Align2::LEFT_BOTTOM,
                (Ordering::Equal, Ordering::Less) => Align2::CENTER_TOP,
                (Ordering::Equal, Ordering::Equal) => Align2::CENTER_CENTER,
                (Ordering::Equal, Ordering::Greater) => Align2::CENTER_BOTTOM,
                (Ordering::Greater, Ordering::Less) => Align2::RIGHT_TOP,
                (Ordering::Greater, Ordering::Equal) => Align2::RIGHT_CENTER,
                (Ordering::Greater, Ordering::Greater) => Align2::RIGHT_BOTTOM,
            };
            ui.painter().text(
                self.origin,
                align,
                self.label.as_str(),
                FontId::new(self.font_size, FontFamily::Proportional),
                self.stroke,
            );
        }
Finn Bear's avatar
Finn Bear committed
    }
}