use egui::{Color32, Painter, Rect, Shape, Stroke, Style, Vec2, epaint::PathShape, pos2, vec2};
use crate::{InPinId, OutPinId};
use super::{TreeizeStyle, WireStyle};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum AnyPin {
Out(OutPinId),
In(InPinId),
}
#[derive(Debug)]
pub enum AnyPins<'a> {
Out(&'a [OutPinId]),
In(&'a [InPinId]),
}
pub struct PinWireInfo {
pub color: Color32,
pub style: WireStyle,
}
pub trait TreeizePin {
fn pin_rect(&self, x0: f32, x1: f32, y: f32, size: f32) -> Rect {
let x = (x0 + x1) * 0.5;
let pin_pos = pos2(x, y);
Rect::from_center_size(pin_pos, vec2(size, size))
}
#[must_use]
fn draw(
self,
treeize_style: &TreeizeStyle,
style: &Style,
rect: Rect,
painter: &Painter,
) -> PinWireInfo;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "egui-probe", derive(egui_probe::EguiProbe))]
pub enum PinShape {
#[default]
Circle,
Triangle,
Square,
Star,
}
#[derive(Default)]
pub struct PinInfo {
pub shape: Option<PinShape>,
pub fill: Option<Color32>,
pub stroke: Option<Stroke>,
pub wire_color: Option<Color32>,
pub wire_style: Option<WireStyle>,
pub position: Option<f32>,
}
impl PinInfo {
#[must_use]
pub const fn with_shape(mut self, shape: PinShape) -> Self {
self.shape = Some(shape);
self
}
#[must_use]
pub const fn with_fill(mut self, fill: Color32) -> Self {
self.fill = Some(fill);
self
}
#[must_use]
pub const fn with_stroke(mut self, stroke: Stroke) -> Self {
self.stroke = Some(stroke);
self
}
#[must_use]
pub const fn with_wire_style(mut self, wire_style: WireStyle) -> Self {
self.wire_style = Some(wire_style);
self
}
#[must_use]
pub const fn with_wire_color(mut self, wire_color: Color32) -> Self {
self.wire_color = Some(wire_color);
self
}
#[must_use]
pub fn circle() -> Self {
PinInfo { shape: Some(PinShape::Circle), ..Default::default() }
}
#[must_use]
pub fn triangle() -> Self {
PinInfo { shape: Some(PinShape::Triangle), ..Default::default() }
}
#[must_use]
pub fn square() -> Self {
PinInfo { shape: Some(PinShape::Square), ..Default::default() }
}
#[must_use]
pub fn star() -> Self {
PinInfo { shape: Some(PinShape::Star), ..Default::default() }
}
#[must_use]
pub fn get_shape(&self, treeize_style: &TreeizeStyle) -> PinShape {
self.shape.unwrap_or_else(|| treeize_style.get_pin_shape())
}
#[must_use]
pub fn get_fill(&self, treeize_style: &TreeizeStyle, style: &Style) -> Color32 {
self.fill.unwrap_or_else(|| treeize_style.get_pin_fill(style))
}
#[must_use]
pub fn get_stroke(&self, treeize_style: &TreeizeStyle, style: &Style) -> Stroke {
self.stroke.unwrap_or_else(|| treeize_style.get_pin_stroke(style))
}
#[must_use]
pub fn draw(
&self,
treeize_style: &TreeizeStyle,
style: &Style,
rect: Rect,
painter: &Painter,
) -> PinWireInfo {
let shape = self.get_shape(treeize_style);
let fill = self.get_fill(treeize_style, style);
let stroke = self.get_stroke(treeize_style, style);
draw_pin(painter, shape, fill, stroke, rect);
PinWireInfo {
color: self.wire_color.unwrap_or(fill),
style: self.wire_style.unwrap_or_else(|| treeize_style.get_wire_style()),
}
}
}
impl TreeizePin for PinInfo {
fn draw(
self,
treeize_style: &TreeizeStyle,
style: &Style,
rect: Rect,
painter: &Painter,
) -> PinWireInfo {
Self::draw(&self, treeize_style, style, rect, painter)
}
}
pub fn draw_pin(painter: &Painter, shape: PinShape, fill: Color32, stroke: Stroke, rect: Rect) {
let center = rect.center();
let size = f32::min(rect.width(), rect.height());
match shape {
PinShape::Circle => {
painter.circle(center, size / 2.0, fill, stroke);
}
PinShape::Triangle => {
const A: Vec2 = vec2(-0.649_519, 0.4875);
const B: Vec2 = vec2(0.649_519, 0.4875);
const C: Vec2 = vec2(0.0, -0.6375);
let points = vec![center + A * size, center + B * size, center + C * size];
painter.add(Shape::Path(PathShape { points, closed: true, fill, stroke: stroke.into() }));
}
PinShape::Square => {
let points = vec![
center + vec2(-0.5, -0.5) * size,
center + vec2(0.5, -0.5) * size,
center + vec2(0.5, 0.5) * size,
center + vec2(-0.5, 0.5) * size,
];
painter.add(Shape::Path(PathShape { points, closed: true, fill, stroke: stroke.into() }));
}
PinShape::Star => {
let points = vec![
center + size * 0.700_000 * vec2(0.0, -1.0),
center + size * 0.267_376 * vec2(-0.587_785, -0.809_017),
center + size * 0.700_000 * vec2(-0.951_057, -0.309_017),
center + size * 0.267_376 * vec2(-0.951_057, 0.309_017),
center + size * 0.700_000 * vec2(-0.587_785, 0.809_017),
center + size * 0.267_376 * vec2(0.0, 1.0),
center + size * 0.700_000 * vec2(0.587_785, 0.809_017),
center + size * 0.267_376 * vec2(0.951_057, 0.309_017),
center + size * 0.700_000 * vec2(0.951_057, -0.309_017),
center + size * 0.267_376 * vec2(0.587_785, -0.809_017),
];
painter.add(Shape::Path(PathShape { points, closed: true, fill, stroke: stroke.into() }));
}
}
}