1use egui::{Color32, Painter, Rect, Shape, Stroke, Style, Vec2, epaint::PathShape, pos2, vec2};
2
3use crate::{InPinId, OutPinId};
4
5use super::{SnarlStyle, WireStyle};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8pub enum AnyPin {
9 Out(OutPinId),
10 In(InPinId),
11}
12
13#[derive(Debug)]
16pub enum AnyPins<'a> {
17 Out(&'a [OutPinId]),
19 In(&'a [InPinId]),
21}
22
23pub struct PinWireInfo {
28 pub color: Color32,
30
31 pub style: WireStyle,
34}
35
36pub trait SnarlPin {
38 fn pin_rect(&self, x: f32, y0: f32, y1: f32, size: f32) -> Rect {
40 let y = (y0 + y1) * 0.5;
42 let pin_pos = pos2(x, y);
43 Rect::from_center_size(pin_pos, vec2(size, size))
44 }
45
46 #[must_use]
54 fn draw(
55 self,
56 snarl_style: &SnarlStyle,
57 style: &Style,
58 rect: Rect,
59 painter: &Painter,
60 ) -> PinWireInfo;
61}
62
63#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66#[cfg_attr(feature = "egui-probe", derive(egui_probe::EguiProbe))]
67pub enum PinShape {
68 #[default]
70 Circle,
71
72 Triangle,
74
75 Square,
77
78 Star,
80}
81
82#[derive(Default)]
87pub struct PinInfo {
88 pub shape: Option<PinShape>,
90
91 pub fill: Option<Color32>,
93
94 pub stroke: Option<Stroke>,
96
97 pub wire_color: Option<Color32>,
100
101 pub wire_style: Option<WireStyle>,
103
104 pub position: Option<f32>,
106}
107
108impl PinInfo {
109 #[must_use]
111 pub const fn with_shape(mut self, shape: PinShape) -> Self {
112 self.shape = Some(shape);
113 self
114 }
115
116 #[must_use]
118 pub const fn with_fill(mut self, fill: Color32) -> Self {
119 self.fill = Some(fill);
120 self
121 }
122
123 #[must_use]
125 pub const fn with_stroke(mut self, stroke: Stroke) -> Self {
126 self.stroke = Some(stroke);
127 self
128 }
129
130 #[must_use]
132 pub const fn with_wire_style(mut self, wire_style: WireStyle) -> Self {
133 self.wire_style = Some(wire_style);
134 self
135 }
136
137 #[must_use]
139 pub const fn with_wire_color(mut self, wire_color: Color32) -> Self {
140 self.wire_color = Some(wire_color);
141 self
142 }
143
144 #[must_use]
146 pub fn circle() -> Self {
147 PinInfo {
148 shape: Some(PinShape::Circle),
149 ..Default::default()
150 }
151 }
152
153 #[must_use]
155 pub fn triangle() -> Self {
156 PinInfo {
157 shape: Some(PinShape::Triangle),
158 ..Default::default()
159 }
160 }
161
162 #[must_use]
164 pub fn square() -> Self {
165 PinInfo {
166 shape: Some(PinShape::Square),
167 ..Default::default()
168 }
169 }
170
171 #[must_use]
173 pub fn star() -> Self {
174 PinInfo {
175 shape: Some(PinShape::Star),
176 ..Default::default()
177 }
178 }
179
180 #[must_use]
182 pub fn get_shape(&self, snarl_style: &SnarlStyle) -> PinShape {
183 self.shape.unwrap_or_else(|| snarl_style.get_pin_shape())
184 }
185
186 #[must_use]
188 pub fn get_fill(&self, snarl_style: &SnarlStyle, style: &Style) -> Color32 {
189 self.fill.unwrap_or_else(|| snarl_style.get_pin_fill(style))
190 }
191
192 #[must_use]
194 pub fn get_stroke(&self, snarl_style: &SnarlStyle, style: &Style) -> Stroke {
195 self.stroke
196 .unwrap_or_else(|| snarl_style.get_pin_stroke(style))
197 }
198
199 #[must_use]
203 pub fn draw(
204 &self,
205 snarl_style: &SnarlStyle,
206 style: &Style,
207 rect: Rect,
208 painter: &Painter,
209 ) -> PinWireInfo {
210 let shape = self.get_shape(snarl_style);
211 let fill = self.get_fill(snarl_style, style);
212 let stroke = self.get_stroke(snarl_style, style);
213 draw_pin(painter, shape, fill, stroke, rect);
214
215 PinWireInfo {
216 color: self.wire_color.unwrap_or(fill),
217 style: self
218 .wire_style
219 .unwrap_or_else(|| snarl_style.get_wire_style()),
220 }
221 }
222}
223
224impl SnarlPin for PinInfo {
225 fn draw(
226 self,
227 snarl_style: &SnarlStyle,
228 style: &Style,
229 rect: Rect,
230 painter: &Painter,
231 ) -> PinWireInfo {
232 Self::draw(&self, snarl_style, style, rect, painter)
233 }
234}
235
236pub fn draw_pin(painter: &Painter, shape: PinShape, fill: Color32, stroke: Stroke, rect: Rect) {
237 let center = rect.center();
238 let size = f32::min(rect.width(), rect.height());
239
240 match shape {
241 PinShape::Circle => {
242 painter.circle(center, size / 2.0, fill, stroke);
243 }
244 PinShape::Triangle => {
245 const A: Vec2 = vec2(-0.649_519, 0.4875);
246 const B: Vec2 = vec2(0.649_519, 0.4875);
247 const C: Vec2 = vec2(0.0, -0.6375);
248
249 let points = vec![center + A * size, center + B * size, center + C * size];
250
251 painter.add(Shape::Path(PathShape {
252 points,
253 closed: true,
254 fill,
255 stroke: stroke.into(),
256 }));
257 }
258 PinShape::Square => {
259 let points = vec![
260 center + vec2(-0.5, -0.5) * size,
261 center + vec2(0.5, -0.5) * size,
262 center + vec2(0.5, 0.5) * size,
263 center + vec2(-0.5, 0.5) * size,
264 ];
265
266 painter.add(Shape::Path(PathShape {
267 points,
268 closed: true,
269 fill,
270 stroke: stroke.into(),
271 }));
272 }
273
274 PinShape::Star => {
275 let points = vec![
276 center + size * 0.700_000 * vec2(0.0, -1.0),
277 center + size * 0.267_376 * vec2(-0.587_785, -0.809_017),
278 center + size * 0.700_000 * vec2(-0.951_057, -0.309_017),
279 center + size * 0.267_376 * vec2(-0.951_057, 0.309_017),
280 center + size * 0.700_000 * vec2(-0.587_785, 0.809_017),
281 center + size * 0.267_376 * vec2(0.0, 1.0),
282 center + size * 0.700_000 * vec2(0.587_785, 0.809_017),
283 center + size * 0.267_376 * vec2(0.951_057, 0.309_017),
284 center + size * 0.700_000 * vec2(0.951_057, -0.309_017),
285 center + size * 0.267_376 * vec2(0.587_785, -0.809_017),
286 ];
287
288 painter.add(Shape::Path(PathShape {
289 points,
290 closed: true,
291 fill,
292 stroke: stroke.into(),
293 }));
294 }
295 }
296}