1use blockworx_geom::{Align, Align2, Pos2, Rangef, Rect, Vec2};
11use blockworx_paint::{
12 AnimKey, Base, Chord, Color, Cursor, EditId, Font, FontFamily, Key, Modifiers, Palette,
13};
14
15pub trait IntoEgui {
17 type Out;
18
19 fn egui(self) -> Self::Out;
20}
21
22pub trait IntoGeom {
24 type Out;
25
26 fn geom(self) -> Self::Out;
27}
28
29macro_rules! xy {
31 ($ours:ty, $theirs:ty) => {
32 impl IntoEgui for $ours {
33 type Out = $theirs;
34
35 #[inline]
36 fn egui(self) -> Self::Out {
37 <$theirs>::new(self.x, self.y)
38 }
39 }
40
41 impl IntoGeom for $theirs {
42 type Out = $ours;
43
44 #[inline]
45 fn geom(self) -> Self::Out {
46 <$ours>::new(self.x, self.y)
47 }
48 }
49 };
50}
51
52xy!(Pos2, egui::Pos2);
53xy!(Vec2, egui::Vec2);
54
55impl IntoEgui for Rect {
56 type Out = egui::Rect;
57
58 #[inline]
59 fn egui(self) -> Self::Out {
60 egui::Rect::from_min_max(self.min.egui(), self.max.egui())
61 }
62}
63
64impl IntoGeom for egui::Rect {
65 type Out = Rect;
66
67 #[inline]
68 fn geom(self) -> Self::Out {
69 Rect::from_min_max(self.min.geom(), self.max.geom())
70 }
71}
72
73impl IntoEgui for Rangef {
74 type Out = egui::Rangef;
75
76 #[inline]
77 fn egui(self) -> Self::Out {
78 egui::Rangef::new(self.min, self.max)
79 }
80}
81
82impl IntoGeom for egui::Rangef {
83 type Out = Rangef;
84
85 #[inline]
86 fn geom(self) -> Self::Out {
87 Rangef::new(self.min, self.max)
88 }
89}
90
91impl IntoEgui for Align {
92 type Out = egui::Align;
93
94 #[inline]
95 fn egui(self) -> Self::Out {
96 match self {
97 Align::Min => egui::Align::Min,
98 Align::Center => egui::Align::Center,
99 Align::Max => egui::Align::Max,
100 }
101 }
102}
103
104impl IntoGeom for egui::Align {
105 type Out = Align;
106
107 #[inline]
108 fn geom(self) -> Self::Out {
109 match self {
110 egui::Align::Min => Align::Min,
111 egui::Align::Center => Align::Center,
112 egui::Align::Max => Align::Max,
113 }
114 }
115}
116
117impl IntoEgui for Align2 {
118 type Out = egui::Align2;
119
120 #[inline]
121 fn egui(self) -> Self::Out {
122 egui::Align2([self.x().egui(), self.y().egui()])
123 }
124}
125
126impl IntoGeom for egui::Align2 {
127 type Out = Align2;
128
129 #[inline]
130 fn geom(self) -> Self::Out {
131 Align2([self.x().geom(), self.y().geom()])
132 }
133}
134
135impl IntoEgui for Color {
136 type Out = egui::Color32;
137
138 #[inline]
139 fn egui(self) -> Self::Out {
140 let [r, g, b, a] = self.to_array();
141 egui::Color32::from_rgba_premultiplied(r, g, b, a)
142 }
143}
144
145impl IntoGeom for egui::Color32 {
146 type Out = Color;
147
148 #[inline]
149 fn geom(self) -> Self::Out {
150 let [r, g, b, a] = self.to_array();
151 Color::from_rgba_premultiplied(r, g, b, a)
152 }
153}
154
155impl IntoEgui for FontFamily {
156 type Out = egui::FontFamily;
157
158 #[inline]
159 fn egui(self) -> Self::Out {
160 match self {
161 FontFamily::Proportional => egui::FontFamily::Proportional,
162 FontFamily::Monospace => egui::FontFamily::Monospace,
163 FontFamily::Named(name) => egui::FontFamily::Name(name),
164 }
165 }
166}
167
168impl IntoGeom for egui::FontFamily {
169 type Out = FontFamily;
170
171 #[inline]
172 fn geom(self) -> Self::Out {
173 match self {
174 egui::FontFamily::Proportional => FontFamily::Proportional,
175 egui::FontFamily::Monospace => FontFamily::Monospace,
176 egui::FontFamily::Name(name) => FontFamily::Named(name),
177 }
178 }
179}
180
181impl IntoEgui for Font {
182 type Out = egui::FontId;
183
184 #[inline]
185 fn egui(self) -> Self::Out {
186 egui::FontId::new(self.size, self.family.egui())
187 }
188}
189
190impl IntoEgui for &Font {
191 type Out = egui::FontId;
192
193 #[inline]
194 fn egui(self) -> Self::Out {
195 self.clone().egui()
196 }
197}
198
199impl IntoGeom for egui::FontId {
200 type Out = Font;
201
202 #[inline]
203 fn geom(self) -> Self::Out {
204 Font::new(self.size, self.family.geom())
205 }
206}
207
208impl IntoEgui for Cursor {
209 type Out = egui::CursorIcon;
210
211 #[inline]
212 fn egui(self) -> Self::Out {
213 match self {
214 Cursor::Default => egui::CursorIcon::Default,
215 Cursor::Crosshair => egui::CursorIcon::Crosshair,
216 Cursor::Text => egui::CursorIcon::Text,
217 Cursor::PointingHand => egui::CursorIcon::PointingHand,
218 Cursor::Move => egui::CursorIcon::Move,
219 Cursor::Grab => egui::CursorIcon::Grab,
220 Cursor::Grabbing => egui::CursorIcon::Grabbing,
221 }
222 }
223}
224
225impl IntoEgui for EditId {
226 type Out = egui::Id;
227
228 #[inline]
229 fn egui(self) -> Self::Out {
230 egui::Id::new(self.get())
231 }
232}
233
234impl IntoEgui for AnimKey {
235 type Out = egui::Id;
236
237 #[inline]
238 fn egui(self) -> Self::Out {
239 egui::Id::new(self.get())
240 }
241}
242
243impl IntoEgui for Key {
244 type Out = egui::Key;
245
246 #[inline]
247 fn egui(self) -> Self::Out {
248 match self {
249 Key::Num0 => egui::Key::Num0,
250 Key::Num1 => egui::Key::Num1,
251 Key::Num2 => egui::Key::Num2,
252 Key::Num3 => egui::Key::Num3,
253 Key::Num4 => egui::Key::Num4,
254 Key::Num5 => egui::Key::Num5,
255 Key::Num6 => egui::Key::Num6,
256 Key::Num7 => egui::Key::Num7,
257 Key::Num8 => egui::Key::Num8,
258 Key::B => egui::Key::B,
259 Key::E => egui::Key::E,
260 Key::I => egui::Key::I,
261 Key::K => egui::Key::K,
262 Key::M => egui::Key::M,
263 Key::N => egui::Key::N,
264 Key::P => egui::Key::P,
265 Key::R => egui::Key::R,
266 Key::T => egui::Key::T,
267 Key::Y => egui::Key::Y,
268 Key::Z => egui::Key::Z,
269 Key::Equals => egui::Key::Equals,
270 Key::Plus => egui::Key::Plus,
271 Key::Minus => egui::Key::Minus,
272 Key::ArrowLeft => egui::Key::ArrowLeft,
273 Key::ArrowRight => egui::Key::ArrowRight,
274 Key::ArrowUp => egui::Key::ArrowUp,
275 Key::ArrowDown => egui::Key::ArrowDown,
276 }
277 }
278}
279
280impl IntoEgui for Modifiers {
281 type Out = egui::Modifiers;
282
283 #[inline]
284 fn egui(self) -> Self::Out {
285 match self {
286 Modifiers::None => egui::Modifiers::NONE,
287 Modifiers::Command => egui::Modifiers::COMMAND,
288 Modifiers::CommandShift => egui::Modifiers::COMMAND | egui::Modifiers::SHIFT,
289 }
290 }
291}
292
293impl IntoEgui for Chord {
294 type Out = egui::KeyboardShortcut;
295
296 #[inline]
297 fn egui(self) -> Self::Out {
298 egui::KeyboardShortcut::new(self.modifiers.egui(), self.key.egui())
299 }
300}
301
302pub fn visuals(palette: &Palette) -> egui::Visuals {
308 use egui::Stroke;
309 let c = |b| palette.get(b).egui();
310 let mut v = if palette.is_dark() {
311 egui::Visuals::dark()
312 } else {
313 egui::Visuals::light()
314 };
315
316 v.override_text_color = Some(c(Base::B05));
317 v.panel_fill = c(Base::B00);
318 v.window_fill = c(Base::B01);
319 v.window_stroke = Stroke::new(1.0, c(Base::B02));
320 v.extreme_bg_color = c(Base::B00); v.faint_bg_color = c(Base::B01);
322 v.code_bg_color = c(Base::B01);
323 v.hyperlink_color = c(Base::B0D);
324 v.selection.bg_fill = c(Base::B0D).gamma_multiply(0.4);
325 v.selection.stroke = Stroke::new(1.0, c(Base::B05));
326
327 let w = &mut v.widgets;
328 w.noninteractive.bg_fill = c(Base::B01);
329 w.noninteractive.weak_bg_fill = c(Base::B01);
330 w.noninteractive.bg_stroke = Stroke::new(1.0, c(Base::B02));
331 w.noninteractive.fg_stroke = Stroke::new(1.0, c(Base::B05));
332
333 w.inactive.bg_fill = c(Base::B02);
334 w.inactive.weak_bg_fill = c(Base::B01);
335 w.inactive.bg_stroke = Stroke::new(1.0, c(Base::B02));
336 w.inactive.fg_stroke = Stroke::new(1.0, c(Base::B05));
337
338 w.hovered.bg_fill = c(Base::B03);
339 w.hovered.weak_bg_fill = c(Base::B02);
340 w.hovered.bg_stroke = Stroke::new(1.0, c(Base::B0D));
341 w.hovered.fg_stroke = Stroke::new(1.5, c(Base::B06));
342
343 w.active.bg_fill = c(Base::B0D);
344 w.active.weak_bg_fill = c(Base::B03);
345 w.active.bg_stroke = Stroke::new(1.0, c(Base::B0D));
346 w.active.fg_stroke = Stroke::new(2.0, c(Base::B00));
347
348 w.open.bg_fill = c(Base::B02);
349 w.open.weak_bg_fill = c(Base::B01);
350 w.open.bg_stroke = Stroke::new(1.0, c(Base::B02));
351 w.open.fg_stroke = Stroke::new(1.0, c(Base::B05));
352
353 v
354}
355
356#[cfg(test)]
357mod tests;