blockworx/canvas/
egui_compat.rs1use blockworx_geom::{Align, Align2, Pos2, Rangef, Rect, Vec2};
11use blockworx_paint::{AnimKey, Base, Color, Cursor, EditId, Font, FontFamily, Palette, Waker};
12
13pub trait IntoEgui {
15 type Out;
16
17 fn egui(self) -> Self::Out;
18}
19
20pub trait IntoGeom {
22 type Out;
23
24 fn geom(self) -> Self::Out;
25}
26
27macro_rules! xy {
29 ($ours:ty, $theirs:ty) => {
30 impl IntoEgui for $ours {
31 type Out = $theirs;
32
33 #[inline]
34 fn egui(self) -> Self::Out {
35 <$theirs>::new(self.x, self.y)
36 }
37 }
38
39 impl IntoGeom for $theirs {
40 type Out = $ours;
41
42 #[inline]
43 fn geom(self) -> Self::Out {
44 <$ours>::new(self.x, self.y)
45 }
46 }
47 };
48}
49
50xy!(Pos2, egui::Pos2);
51xy!(Vec2, egui::Vec2);
52
53impl IntoEgui for Rect {
54 type Out = egui::Rect;
55
56 #[inline]
57 fn egui(self) -> Self::Out {
58 egui::Rect::from_min_max(self.min.egui(), self.max.egui())
59 }
60}
61
62impl IntoGeom for egui::Rect {
63 type Out = Rect;
64
65 #[inline]
66 fn geom(self) -> Self::Out {
67 Rect::from_min_max(self.min.geom(), self.max.geom())
68 }
69}
70
71impl IntoEgui for Rangef {
72 type Out = egui::Rangef;
73
74 #[inline]
75 fn egui(self) -> Self::Out {
76 egui::Rangef::new(self.min, self.max)
77 }
78}
79
80impl IntoGeom for egui::Rangef {
81 type Out = Rangef;
82
83 #[inline]
84 fn geom(self) -> Self::Out {
85 Rangef::new(self.min, self.max)
86 }
87}
88
89impl IntoEgui for Align {
90 type Out = egui::Align;
91
92 #[inline]
93 fn egui(self) -> Self::Out {
94 match self {
95 Align::Min => egui::Align::Min,
96 Align::Center => egui::Align::Center,
97 Align::Max => egui::Align::Max,
98 }
99 }
100}
101
102impl IntoGeom for egui::Align {
103 type Out = Align;
104
105 #[inline]
106 fn geom(self) -> Self::Out {
107 match self {
108 egui::Align::Min => Align::Min,
109 egui::Align::Center => Align::Center,
110 egui::Align::Max => Align::Max,
111 }
112 }
113}
114
115impl IntoEgui for Align2 {
116 type Out = egui::Align2;
117
118 #[inline]
119 fn egui(self) -> Self::Out {
120 egui::Align2([self.x().egui(), self.y().egui()])
121 }
122}
123
124impl IntoGeom for egui::Align2 {
125 type Out = Align2;
126
127 #[inline]
128 fn geom(self) -> Self::Out {
129 Align2([self.x().geom(), self.y().geom()])
130 }
131}
132
133impl IntoEgui for Color {
134 type Out = egui::Color32;
135
136 #[inline]
137 fn egui(self) -> Self::Out {
138 let [r, g, b, a] = self.to_array();
139 egui::Color32::from_rgba_premultiplied(r, g, b, a)
140 }
141}
142
143impl IntoGeom for egui::Color32 {
144 type Out = Color;
145
146 #[inline]
147 fn geom(self) -> Self::Out {
148 let [r, g, b, a] = self.to_array();
149 Color::from_rgba_premultiplied(r, g, b, a)
150 }
151}
152
153impl IntoEgui for FontFamily {
154 type Out = egui::FontFamily;
155
156 #[inline]
157 fn egui(self) -> Self::Out {
158 match self {
159 FontFamily::Proportional => egui::FontFamily::Proportional,
160 FontFamily::Monospace => egui::FontFamily::Monospace,
161 FontFamily::Named(name) => egui::FontFamily::Name(name),
162 }
163 }
164}
165
166impl IntoGeom for egui::FontFamily {
167 type Out = FontFamily;
168
169 #[inline]
170 fn geom(self) -> Self::Out {
171 match self {
172 egui::FontFamily::Proportional => FontFamily::Proportional,
173 egui::FontFamily::Monospace => FontFamily::Monospace,
174 egui::FontFamily::Name(name) => FontFamily::Named(name),
175 }
176 }
177}
178
179impl IntoEgui for Font {
180 type Out = egui::FontId;
181
182 #[inline]
183 fn egui(self) -> Self::Out {
184 egui::FontId::new(self.size, self.family.egui())
185 }
186}
187
188impl IntoEgui for &Font {
189 type Out = egui::FontId;
190
191 #[inline]
192 fn egui(self) -> Self::Out {
193 self.clone().egui()
194 }
195}
196
197impl IntoGeom for egui::FontId {
198 type Out = Font;
199
200 #[inline]
201 fn geom(self) -> Self::Out {
202 Font::new(self.size, self.family.geom())
203 }
204}
205
206impl IntoEgui for Cursor {
207 type Out = egui::CursorIcon;
208
209 #[inline]
210 fn egui(self) -> Self::Out {
211 match self {
212 Cursor::Default => egui::CursorIcon::Default,
213 Cursor::Crosshair => egui::CursorIcon::Crosshair,
214 Cursor::Text => egui::CursorIcon::Text,
215 Cursor::PointingHand => egui::CursorIcon::PointingHand,
216 Cursor::Move => egui::CursorIcon::Move,
217 Cursor::Grab => egui::CursorIcon::Grab,
218 Cursor::Grabbing => egui::CursorIcon::Grabbing,
219 }
220 }
221}
222
223impl IntoEgui for EditId {
224 type Out = egui::Id;
225
226 #[inline]
227 fn egui(self) -> Self::Out {
228 egui::Id::new(self.get())
229 }
230}
231
232impl IntoEgui for AnimKey {
233 type Out = egui::Id;
234
235 #[inline]
236 fn egui(self) -> Self::Out {
237 egui::Id::new(self.get())
238 }
239}
240
241pub fn waker(ctx: &egui::Context) -> Waker {
245 let ctx = ctx.clone();
246 Waker::new(move || ctx.request_repaint())
247}
248
249pub fn visuals(palette: &Palette) -> egui::Visuals {
255 use egui::Stroke;
256 let c = |b| palette.get(b).egui();
257 let mut v = if palette.is_dark() {
258 egui::Visuals::dark()
259 } else {
260 egui::Visuals::light()
261 };
262
263 v.override_text_color = Some(c(Base::B05));
264 v.panel_fill = c(Base::B00);
265 v.window_fill = c(Base::B01);
266 v.window_stroke = Stroke::new(1.0, c(Base::B02));
267 v.extreme_bg_color = c(Base::B00); v.faint_bg_color = c(Base::B01);
269 v.code_bg_color = c(Base::B01);
270 v.hyperlink_color = c(Base::B0D);
271 v.selection.bg_fill = c(Base::B0D).gamma_multiply(0.4);
272 v.selection.stroke = Stroke::new(1.0, c(Base::B05));
273
274 let w = &mut v.widgets;
275 w.noninteractive.bg_fill = c(Base::B01);
276 w.noninteractive.weak_bg_fill = c(Base::B01);
277 w.noninteractive.bg_stroke = Stroke::new(1.0, c(Base::B02));
278 w.noninteractive.fg_stroke = Stroke::new(1.0, c(Base::B05));
279
280 w.inactive.bg_fill = c(Base::B02);
281 w.inactive.weak_bg_fill = c(Base::B01);
282 w.inactive.bg_stroke = Stroke::new(1.0, c(Base::B02));
283 w.inactive.fg_stroke = Stroke::new(1.0, c(Base::B05));
284
285 w.hovered.bg_fill = c(Base::B03);
286 w.hovered.weak_bg_fill = c(Base::B02);
287 w.hovered.bg_stroke = Stroke::new(1.0, c(Base::B0D));
288 w.hovered.fg_stroke = Stroke::new(1.5, c(Base::B06));
289
290 w.active.bg_fill = c(Base::B0D);
291 w.active.weak_bg_fill = c(Base::B03);
292 w.active.bg_stroke = Stroke::new(1.0, c(Base::B0D));
293 w.active.fg_stroke = Stroke::new(2.0, c(Base::B00));
294
295 w.open.bg_fill = c(Base::B02);
296 w.open.weak_bg_fill = c(Base::B01);
297 w.open.bg_stroke = Stroke::new(1.0, c(Base::B02));
298 w.open.fg_stroke = Stroke::new(1.0, c(Base::B05));
299
300 v
301}
302
303#[cfg(test)]
304mod tests;