1use iced_core::Color;
2use iced_widget::{
3 button, checkbox, combo_box, container, markdown, overlay::menu, pick_list,
4 progress_bar, qr_code, radio, rule, scrollable, slider, svg, table, text_editor,
5 text_input, toggler,
6};
7use triomphe::Arc;
8
9#[derive(Clone, Debug)]
16pub struct GraphixTheme {
17 pub inner: iced_core::Theme,
18 pub overrides: Option<Arc<StyleOverrides>>,
19}
20
21impl GraphixTheme {
22 pub fn palette(&self) -> iced_core::theme::palette::Palette {
23 self.inner.palette()
24 }
25}
26
27#[derive(Clone, Debug)]
28pub struct StyleOverrides {
29 pub button: Option<ButtonSpec>,
30 pub checkbox: Option<CheckboxSpec>,
31 pub container: Option<ContainerSpec>,
32 pub menu: Option<MenuSpec>,
33 pub pick_list: Option<PickListSpec>,
34 pub progress_bar: Option<ProgressBarSpec>,
35 pub radio: Option<RadioSpec>,
36 pub rule: Option<RuleSpec>,
37 pub scrollable: Option<ScrollableSpec>,
38 pub slider: Option<SliderSpec>,
39 pub text_editor: Option<TextEditorSpec>,
40 pub text_input: Option<TextInputSpec>,
41 pub toggler: Option<TogglerSpec>,
42}
43
44#[derive(Clone, Copy, Debug)]
47pub struct ButtonSpec {
48 pub background: Option<Color>,
49 pub border_color: Option<Color>,
50 pub border_radius: Option<f32>,
51 pub border_width: Option<f32>,
52 pub text_color: Option<Color>,
53}
54
55#[derive(Clone, Copy, Debug)]
56pub struct CheckboxSpec {
57 pub accent: Option<Color>,
58 pub background: Option<Color>,
59 pub border_color: Option<Color>,
60 pub border_radius: Option<f32>,
61 pub border_width: Option<f32>,
62 pub icon_color: Option<Color>,
63 pub text_color: Option<Color>,
64}
65
66#[derive(Clone, Copy, Debug)]
67pub struct TextInputSpec {
68 pub background: Option<Color>,
69 pub border_color: Option<Color>,
70 pub border_radius: Option<f32>,
71 pub border_width: Option<f32>,
72 pub icon_color: Option<Color>,
73 pub placeholder_color: Option<Color>,
74 pub selection_color: Option<Color>,
75 pub value_color: Option<Color>,
76}
77
78#[derive(Clone, Copy, Debug)]
79pub struct TogglerSpec {
80 pub background: Option<Color>,
81 pub background_border_color: Option<Color>,
82 pub border_radius: Option<f32>,
83 pub foreground: Option<Color>,
84 pub foreground_border_color: Option<Color>,
85 pub text_color: Option<Color>,
86}
87
88#[derive(Clone, Copy, Debug)]
89pub struct SliderSpec {
90 pub handle_border_color: Option<Color>,
91 pub handle_border_width: Option<f32>,
92 pub handle_color: Option<Color>,
93 pub handle_radius: Option<f32>,
94 pub rail_color: Option<Color>,
95 pub rail_fill_color: Option<Color>,
96 pub rail_width: Option<f32>,
97}
98
99#[derive(Clone, Copy, Debug)]
100pub struct RadioSpec {
101 pub background: Option<Color>,
102 pub border_color: Option<Color>,
103 pub border_width: Option<f32>,
104 pub dot_color: Option<Color>,
105 pub text_color: Option<Color>,
106}
107
108#[derive(Clone, Copy, Debug)]
109pub struct PickListSpec {
110 pub background: Option<Color>,
111 pub border_color: Option<Color>,
112 pub border_radius: Option<f32>,
113 pub border_width: Option<f32>,
114 pub handle_color: Option<Color>,
115 pub placeholder_color: Option<Color>,
116 pub text_color: Option<Color>,
117}
118
119#[derive(Clone, Copy, Debug)]
120pub struct TextEditorSpec {
121 pub background: Option<Color>,
122 pub border_color: Option<Color>,
123 pub border_radius: Option<f32>,
124 pub border_width: Option<f32>,
125 pub placeholder_color: Option<Color>,
126 pub selection_color: Option<Color>,
127 pub value_color: Option<Color>,
128}
129
130#[derive(Clone, Copy, Debug)]
131pub struct ContainerSpec {
132 pub background: Option<Color>,
133 pub border_color: Option<Color>,
134 pub border_radius: Option<f32>,
135 pub border_width: Option<f32>,
136 pub text_color: Option<Color>,
137}
138
139#[derive(Clone, Copy, Debug)]
140pub struct ScrollableSpec {
141 pub background: Option<Color>,
142 pub border_color: Option<Color>,
143 pub border_radius: Option<f32>,
144 pub border_width: Option<f32>,
145 pub scroller_color: Option<Color>,
146}
147
148#[derive(Clone, Copy, Debug)]
149pub struct ProgressBarSpec {
150 pub background: Option<Color>,
151 pub bar_color: Option<Color>,
152 pub border_radius: Option<f32>,
153}
154
155#[derive(Clone, Copy, Debug)]
156pub struct RuleSpec {
157 pub color: Option<Color>,
158 pub radius: Option<f32>,
159 pub width: Option<f32>,
160}
161
162#[derive(Clone, Copy, Debug)]
163pub struct MenuSpec {
164 pub background: Option<Color>,
165 pub border_color: Option<Color>,
166 pub border_radius: Option<f32>,
167 pub border_width: Option<f32>,
168 pub selected_background: Option<Color>,
169 pub selected_text_color: Option<Color>,
170 pub text_color: Option<Color>,
171}
172
173fn hover_adjust(color: Color, is_dark: bool) -> Color {
176 if is_dark {
177 Color::from_rgba(
178 (color.r + 0.15).min(1.0),
179 (color.g + 0.15).min(1.0),
180 (color.b + 0.15).min(1.0),
181 color.a,
182 )
183 } else {
184 Color::from_rgba(
185 (color.r - 0.10).max(0.0),
186 (color.g - 0.10).max(0.0),
187 (color.b - 0.10).max(0.0),
188 color.a,
189 )
190 }
191}
192
193fn dim(color: Color) -> Color {
194 Color::from_rgba(color.r, color.g, color.b, color.a * 0.5)
195}
196
197impl ButtonSpec {
203 fn resolve(&self, theme: &iced_core::Theme, status: button::Status) -> button::Style {
204 let is_dark = theme.extended_palette().is_dark;
205 let mut s = button::primary(theme, status);
206 if let Some(bg) = self.background {
207 let bg = match status {
208 button::Status::Hovered => hover_adjust(bg, is_dark),
209 button::Status::Disabled => dim(bg),
210 _ => bg,
211 };
212 s.background = Some(bg.into());
213 }
214 if let Some(tc) = self.text_color {
215 s.text_color =
216 if matches!(status, button::Status::Disabled) { dim(tc) } else { tc };
217 }
218 if let Some(bc) = self.border_color {
219 s.border.color = bc;
220 }
221 if let Some(bw) = self.border_width {
222 s.border.width = bw;
223 }
224 if let Some(br) = self.border_radius {
225 s.border.radius = br.into();
226 }
227 s
228 }
229}
230
231impl CheckboxSpec {
232 fn resolve(
233 &self,
234 theme: &iced_core::Theme,
235 status: checkbox::Status,
236 ) -> checkbox::Style {
237 let is_dark = theme.extended_palette().is_dark;
238 let mut s = checkbox::primary(theme, status);
239 let is_disabled = matches!(status, checkbox::Status::Disabled { .. });
240 let is_hovered = matches!(status, checkbox::Status::Hovered { .. });
241 let is_checked = match status {
242 checkbox::Status::Active { is_checked }
243 | checkbox::Status::Hovered { is_checked }
244 | checkbox::Status::Disabled { is_checked } => is_checked,
245 };
246 if let Some(accent) = self.accent {
247 if let Some(bg) = self.background {
248 let c = if is_checked { accent } else { bg };
249 let c = if is_disabled {
250 dim(c)
251 } else if is_hovered {
252 hover_adjust(c, is_dark)
253 } else {
254 c
255 };
256 s.background = c.into();
257 } else {
258 if is_checked {
260 let c = if is_disabled {
261 dim(accent)
262 } else if is_hovered {
263 hover_adjust(accent, is_dark)
264 } else {
265 accent
266 };
267 s.background = c.into();
268 }
269 }
270 } else if let Some(bg) = self.background {
271 if !is_checked {
272 let c = if is_disabled {
273 dim(bg)
274 } else if is_hovered {
275 hover_adjust(bg, is_dark)
276 } else {
277 bg
278 };
279 s.background = c.into();
280 }
281 }
282 if let Some(ic) = self.icon_color {
283 s.icon_color = if is_disabled { dim(ic) } else { ic };
284 }
285 if let Some(tc) = self.text_color {
286 s.text_color = Some(if is_disabled { dim(tc) } else { tc });
287 }
288 if let Some(bc) = self.border_color {
289 s.border.color = if is_disabled { dim(bc) } else { bc };
290 }
291 if let Some(bw) = self.border_width {
292 s.border.width = bw;
293 }
294 if let Some(br) = self.border_radius {
295 s.border.radius = br.into();
296 }
297 s
298 }
299}
300
301impl TextInputSpec {
302 fn resolve(
303 &self,
304 theme: &iced_core::Theme,
305 status: text_input::Status,
306 ) -> text_input::Style {
307 let is_dark = theme.extended_palette().is_dark;
308 let mut s = text_input::default(theme, status);
309 if let Some(bg) = self.background {
310 s.background = match status {
311 text_input::Status::Active => bg,
312 text_input::Status::Hovered | text_input::Status::Focused { .. } => {
313 hover_adjust(bg, is_dark)
314 }
315 text_input::Status::Disabled => dim(bg),
316 }
317 .into();
318 }
319 if let Some(bc) = self.border_color {
320 s.border.color = bc;
321 }
322 if let Some(bw) = self.border_width {
323 s.border.width = bw;
324 }
325 if let Some(br) = self.border_radius {
326 s.border.radius = br.into();
327 }
328 if let Some(ic) = self.icon_color {
329 s.icon = ic;
330 }
331 if let Some(pc) = self.placeholder_color {
332 s.placeholder = pc;
333 }
334 if let Some(vc) = self.value_color {
335 s.value = vc;
336 }
337 if let Some(sc) = self.selection_color {
338 s.selection = sc;
339 }
340 s
341 }
342}
343
344impl TogglerSpec {
345 fn resolve(
346 &self,
347 theme: &iced_core::Theme,
348 status: toggler::Status,
349 ) -> toggler::Style {
350 let is_dark = theme.extended_palette().is_dark;
351 let mut s = toggler::default(theme, status);
352 let is_hovered = matches!(status, toggler::Status::Hovered { .. });
353 let is_disabled = matches!(status, toggler::Status::Disabled { .. });
354 if let Some(bg) = self.background {
355 s.background = if is_disabled {
356 dim(bg)
357 } else if is_hovered {
358 hover_adjust(bg, is_dark)
359 } else {
360 bg
361 }
362 .into();
363 }
364 if let Some(bbc) = self.background_border_color {
365 s.background_border_color = if is_disabled { dim(bbc) } else { bbc };
366 }
367 if let Some(fg) = self.foreground {
368 s.foreground = if is_disabled { dim(fg) } else { fg }.into();
369 }
370 if let Some(fbc) = self.foreground_border_color {
371 s.foreground_border_color = if is_disabled { dim(fbc) } else { fbc };
372 }
373 if let Some(tc) = self.text_color {
374 s.text_color = Some(if is_disabled { dim(tc) } else { tc });
375 }
376 if let Some(br) = self.border_radius {
377 s.border_radius = Some(br.into());
378 }
379 s
380 }
381}
382
383impl SliderSpec {
384 fn resolve(&self, theme: &iced_core::Theme, status: slider::Status) -> slider::Style {
385 let is_dark = theme.extended_palette().is_dark;
386 let mut s = slider::default(theme, status);
387 let is_hovered = matches!(status, slider::Status::Hovered);
388 if let Some(rfc) = self.rail_fill_color {
389 s.rail.backgrounds.0 = rfc.into();
390 }
391 if let Some(rc) = self.rail_color {
392 s.rail.backgrounds.1 = rc.into();
393 }
394 if let Some(rw) = self.rail_width {
395 s.rail.width = rw;
396 }
397 if let Some(hc) = self.handle_color {
398 let hc = if is_hovered { hover_adjust(hc, is_dark) } else { hc };
399 s.handle.background = hc.into();
400 }
401 if let Some(hr) = self.handle_radius {
402 s.handle.shape = slider::HandleShape::Circle { radius: hr };
403 }
404 if let Some(hbw) = self.handle_border_width {
405 s.handle.border_width = hbw;
406 }
407 if let Some(hbc) = self.handle_border_color {
408 s.handle.border_color = hbc;
409 }
410 s
411 }
412}
413
414impl RadioSpec {
415 fn resolve(&self, theme: &iced_core::Theme, status: radio::Status) -> radio::Style {
416 let is_dark = theme.extended_palette().is_dark;
417 let mut s = radio::default(theme, status);
418 let is_hovered = matches!(status, radio::Status::Hovered { .. });
419 if let Some(bg) = self.background {
420 s.background = if is_hovered { hover_adjust(bg, is_dark) } else { bg }.into();
421 }
422 if let Some(dc) = self.dot_color {
423 s.dot_color = dc;
424 }
425 if let Some(bw) = self.border_width {
426 s.border_width = bw;
427 }
428 if let Some(bc) = self.border_color {
429 s.border_color = bc;
430 }
431 if let Some(tc) = self.text_color {
432 s.text_color = Some(tc);
433 }
434 s
435 }
436}
437
438impl PickListSpec {
439 fn resolve(
440 &self,
441 theme: &iced_core::Theme,
442 status: pick_list::Status,
443 ) -> pick_list::Style {
444 let is_dark = theme.extended_palette().is_dark;
445 let mut s = pick_list::default(theme, status);
446 let is_hovered = matches!(
447 status,
448 pick_list::Status::Hovered | pick_list::Status::Opened { .. }
449 );
450 if let Some(bg) = self.background {
451 s.background = if is_hovered { hover_adjust(bg, is_dark) } else { bg }.into();
452 }
453 if let Some(tc) = self.text_color {
454 s.text_color = tc;
455 }
456 if let Some(pc) = self.placeholder_color {
457 s.placeholder_color = pc;
458 }
459 if let Some(hc) = self.handle_color {
460 s.handle_color = hc;
461 }
462 if let Some(bc) = self.border_color {
463 s.border.color = bc;
464 }
465 if let Some(bw) = self.border_width {
466 s.border.width = bw;
467 }
468 if let Some(br) = self.border_radius {
469 s.border.radius = br.into();
470 }
471 s
472 }
473}
474
475impl TextEditorSpec {
476 fn resolve(
477 &self,
478 theme: &iced_core::Theme,
479 status: text_editor::Status,
480 ) -> text_editor::Style {
481 let is_dark = theme.extended_palette().is_dark;
482 let mut s = text_editor::default(theme, status);
483 if let Some(bg) = self.background {
484 s.background = match status {
485 text_editor::Status::Active => bg,
486 text_editor::Status::Hovered | text_editor::Status::Focused { .. } => {
487 hover_adjust(bg, is_dark)
488 }
489 text_editor::Status::Disabled => dim(bg),
490 }
491 .into();
492 }
493 if let Some(bc) = self.border_color {
494 s.border.color = bc;
495 }
496 if let Some(bw) = self.border_width {
497 s.border.width = bw;
498 }
499 if let Some(br) = self.border_radius {
500 s.border.radius = br.into();
501 }
502 if let Some(pc) = self.placeholder_color {
503 s.placeholder = pc;
504 }
505 if let Some(vc) = self.value_color {
506 s.value = vc;
507 }
508 if let Some(sc) = self.selection_color {
509 s.selection = sc;
510 }
511 s
512 }
513}
514
515impl ContainerSpec {
516 fn resolve(&self, theme: &iced_core::Theme) -> container::Style {
517 let mut s = container::transparent(theme);
518 if let Some(bg) = self.background {
519 s.background = Some(bg.into());
520 }
521 if let Some(tc) = self.text_color {
522 s.text_color = Some(tc);
523 }
524 if let Some(bc) = self.border_color {
525 s.border.color = bc;
526 }
527 if let Some(bw) = self.border_width {
528 s.border.width = bw;
529 }
530 if let Some(br) = self.border_radius {
531 s.border.radius = br.into();
532 }
533 s
534 }
535}
536
537impl ScrollableSpec {
538 fn resolve(
539 &self,
540 theme: &iced_core::Theme,
541 status: scrollable::Status,
542 ) -> scrollable::Style {
543 let is_dark = theme.extended_palette().is_dark;
544 let mut s = scrollable::default(theme, status);
545 for rail in [&mut s.vertical_rail, &mut s.horizontal_rail] {
547 if let Some(bg) = self.background {
548 rail.background = Some(bg.into());
549 }
550 if let Some(bc) = self.border_color {
551 rail.border.color = bc;
552 }
553 if let Some(bw) = self.border_width {
554 rail.border.width = bw;
555 }
556 if let Some(br) = self.border_radius {
557 rail.border.radius = br.into();
558 }
559 if let Some(sc) = self.scroller_color {
560 let is_hovered = matches!(status, scrollable::Status::Hovered { .. });
561 let sc = if is_hovered { hover_adjust(sc, is_dark) } else { sc };
562 rail.scroller.background = sc.into();
563 }
564 }
565 s
566 }
567}
568
569impl ProgressBarSpec {
570 fn resolve(&self, theme: &iced_core::Theme) -> progress_bar::Style {
571 let mut s = progress_bar::primary(theme);
572 if let Some(bg) = self.background {
573 s.background = bg.into();
574 }
575 if let Some(bar) = self.bar_color {
576 s.bar = bar.into();
577 }
578 if let Some(br) = self.border_radius {
579 s.border.radius = br.into();
580 }
581 s
582 }
583}
584
585impl RuleSpec {
586 fn resolve(&self, theme: &iced_core::Theme) -> rule::Style {
587 let mut s = rule::default(theme);
588 if let Some(c) = self.color {
589 s.color = c;
590 }
591 if let Some(r) = self.radius {
592 s.radius = r.into();
593 }
594 if let Some(w) = self.width {
595 s.fill_mode = rule::FillMode::Percent(w);
596 }
597 s
598 }
599}
600
601impl MenuSpec {
602 fn resolve(&self, theme: &iced_core::Theme) -> menu::Style {
603 let mut s = menu::default(theme);
604 if let Some(bg) = self.background {
605 s.background = bg.into();
606 }
607 if let Some(bc) = self.border_color {
608 s.border.color = bc;
609 }
610 if let Some(bw) = self.border_width {
611 s.border.width = bw;
612 }
613 if let Some(br) = self.border_radius {
614 s.border.radius = br.into();
615 }
616 if let Some(tc) = self.text_color {
617 s.text_color = tc;
618 }
619 if let Some(stc) = self.selected_text_color {
620 s.selected_text_color = stc;
621 }
622 if let Some(sb) = self.selected_background {
623 s.selected_background = sb.into();
624 }
625 s
626 }
627}
628
629macro_rules! impl_catalog_with_status {
634 ($module:ident, $field:ident, $fallback:expr) => {
635 impl $module::Catalog for GraphixTheme {
636 type Class<'a> = $module::StyleFn<'a, Self>;
637
638 fn default<'a>() -> Self::Class<'a> {
639 Box::new(|theme, status| {
640 if let Some(spec) =
641 theme.overrides.as_ref().and_then(|o| o.$field.as_ref())
642 {
643 spec.resolve(&theme.inner, status)
644 } else {
645 #[allow(clippy::redundant_closure_call)]
646 ($fallback)(&theme.inner, status)
647 }
648 })
649 }
650
651 fn style(
652 &self,
653 class: &Self::Class<'_>,
654 status: $module::Status,
655 ) -> $module::Style {
656 class(self, status)
657 }
658 }
659 };
660}
661
662macro_rules! impl_catalog_no_status {
663 ($module:ident, $field:ident, $fallback:expr) => {
664 impl $module::Catalog for GraphixTheme {
665 type Class<'a> = $module::StyleFn<'a, Self>;
666
667 fn default<'a>() -> Self::Class<'a> {
668 Box::new(|theme| {
669 if let Some(spec) =
670 theme.overrides.as_ref().and_then(|o| o.$field.as_ref())
671 {
672 spec.resolve(&theme.inner)
673 } else {
674 #[allow(clippy::redundant_closure_call)]
675 ($fallback)(&theme.inner)
676 }
677 })
678 }
679
680 fn style(&self, class: &Self::Class<'_>) -> $module::Style {
681 class(self)
682 }
683 }
684 };
685}
686
687impl_catalog_with_status!(button, button, button::primary);
688impl_catalog_with_status!(checkbox, checkbox, checkbox::primary);
689impl_catalog_with_status!(text_input, text_input, text_input::default);
690impl_catalog_with_status!(toggler, toggler, toggler::default);
691impl_catalog_with_status!(slider, slider, slider::default);
692impl_catalog_with_status!(radio, radio, radio::default);
693impl pick_list::Catalog for GraphixTheme {
695 type Class<'a> = pick_list::StyleFn<'a, Self>;
696
697 fn default<'a>() -> <Self as pick_list::Catalog>::Class<'a> {
698 Box::new(|theme, status| {
699 if let Some(spec) =
700 theme.overrides.as_ref().and_then(|o| o.pick_list.as_ref())
701 {
702 spec.resolve(&theme.inner, status)
703 } else {
704 pick_list::default(&theme.inner, status)
705 }
706 })
707 }
708
709 fn style(
710 &self,
711 class: &<Self as pick_list::Catalog>::Class<'_>,
712 status: pick_list::Status,
713 ) -> pick_list::Style {
714 class(self, status)
715 }
716}
717impl_catalog_with_status!(text_editor, text_editor, text_editor::default);
718
719impl scrollable::Catalog for GraphixTheme {
720 type Class<'a> = scrollable::StyleFn<'a, Self>;
721
722 fn default<'a>() -> Self::Class<'a> {
723 Box::new(|theme, status| {
724 if let Some(spec) =
725 theme.overrides.as_ref().and_then(|o| o.scrollable.as_ref())
726 {
727 spec.resolve(&theme.inner, status)
728 } else {
729 scrollable::default(&theme.inner, status)
730 }
731 })
732 }
733
734 fn style(
735 &self,
736 class: &Self::Class<'_>,
737 status: scrollable::Status,
738 ) -> scrollable::Style {
739 class(self, status)
740 }
741}
742
743impl_catalog_no_status!(container, container, container::transparent);
744impl_catalog_no_status!(progress_bar, progress_bar, progress_bar::primary);
745impl_catalog_no_status!(rule, rule, rule::default);
746
747impl menu::Catalog for GraphixTheme {
749 type Class<'a> = menu::StyleFn<'a, Self>;
750
751 fn default<'a>() -> <Self as menu::Catalog>::Class<'a> {
752 Box::new(|theme| {
753 if let Some(spec) = theme.overrides.as_ref().and_then(|o| o.menu.as_ref()) {
754 spec.resolve(&theme.inner)
755 } else {
756 menu::default(&theme.inner)
757 }
758 })
759 }
760
761 fn style(&self, class: &<Self as menu::Catalog>::Class<'_>) -> menu::Style {
762 class(self)
763 }
764}
765
766impl combo_box::Catalog for GraphixTheme {}
768
769impl iced_core::widget::text::Catalog for GraphixTheme {
771 type Class<'a> = iced_core::widget::text::StyleFn<'a, Self>;
772
773 fn default<'a>() -> Self::Class<'a> {
774 Box::new(|_theme| iced_core::widget::text::Style::default())
775 }
776
777 fn style(&self, class: &Self::Class<'_>) -> iced_core::widget::text::Style {
778 class(self)
779 }
780}
781
782impl svg::Catalog for GraphixTheme {
784 type Class<'a> = svg::StyleFn<'a, Self>;
785
786 fn default<'a>() -> Self::Class<'a> {
787 Box::new(|_theme, _status| svg::Style::default())
788 }
789
790 fn style(&self, class: &Self::Class<'_>, status: svg::Status) -> svg::Style {
791 class(self, status)
792 }
793}
794
795impl table::Catalog for GraphixTheme {
797 type Class<'a> = table::StyleFn<'a, Self>;
798
799 fn default<'a>() -> Self::Class<'a> {
800 Box::new(|theme| table::default(&theme.inner))
801 }
802
803 fn style(&self, class: &Self::Class<'_>) -> table::Style {
804 class(self)
805 }
806}
807
808impl qr_code::Catalog for GraphixTheme {
810 type Class<'a> = qr_code::StyleFn<'a, Self>;
811
812 fn default<'a>() -> Self::Class<'a> {
813 Box::new(|theme| qr_code::default(&theme.inner))
814 }
815
816 fn style(&self, class: &Self::Class<'_>) -> qr_code::Style {
817 class(self)
818 }
819}
820
821impl markdown::Catalog for GraphixTheme {
823 fn code_block<'a>() -> <Self as container::Catalog>::Class<'a> {
824 Box::new(|theme| container::dark(&theme.inner))
825 }
826}
827
828impl iced_core::theme::Base for GraphixTheme {
830 fn default(preference: iced_core::theme::Mode) -> Self {
831 GraphixTheme {
832 inner: iced_core::theme::Base::default(preference),
833 overrides: None,
834 }
835 }
836
837 fn mode(&self) -> iced_core::theme::Mode {
838 self.inner.mode()
839 }
840
841 fn base(&self) -> iced_core::theme::Style {
842 self.inner.base()
843 }
844
845 fn palette(&self) -> Option<iced_core::theme::palette::Palette> {
846 iced_core::theme::Base::palette(&self.inner)
847 }
848
849 fn name(&self) -> &str {
850 self.inner.name()
851 }
852}