Skip to main content

blockworx/
preferences_menu.rs

1//! The preferences menu: cascading Mode / Theme / Font submenus that edit
2//! [`Preferences`] in place. The app reads the mutated preferences and applies
3//! them (palette, fonts) on the next frame.
4
5use egui::{FontFamily, RichText, TextWrapMode, Ui};
6
7use blockworx_paint::{FontChoice, Mode, Scheme};
8
9use crate::preferences::Preferences;
10
11/// egui menu popups shrink-to-fit their content, and with proportional fonts the
12/// sub-pixel width of a label can round just past the popup width, wrapping the
13/// last glyph onto its own line (e.g. "Them\ne"). Extend mode makes each label
14/// size the popup to fit rather than wrap. Must be set on every submenu's `Ui`,
15/// since each popup gets a fresh style.
16fn no_wrap(ui: &mut Ui) {
17    ui.style_mut().wrap_mode = Some(TextWrapMode::Extend);
18}
19
20/// Populate the document menu's Preferences submenu: Mode, Theme, Font.
21pub fn menu(ui: &mut Ui, prefs: &mut Preferences) {
22    no_wrap(ui);
23    ui.menu_button("Mode", |ui| mode_menu(ui, prefs));
24    ui.menu_button("Theme", |ui| theme_menu(ui, prefs));
25    ui.menu_button("Font", |ui| font_menu(ui, prefs));
26}
27
28fn mode_menu(ui: &mut Ui, prefs: &mut Preferences) {
29    no_wrap(ui);
30    for mode in Mode::ALL {
31        // The egui theme-switcher glyph (☀ / 🌙 / 💻) precedes the label.
32        let label = format!("{}  {}", mode.glyph(), mode.display_name());
33        if ui.selectable_label(mode == prefs.mode, label).clicked() {
34            prefs.mode = mode;
35        }
36    }
37}
38
39fn theme_menu(ui: &mut Ui, prefs: &mut Preferences) {
40    no_wrap(ui);
41    for theme in Scheme::ALL {
42        if ui
43            .selectable_label(theme == prefs.theme, theme.display_name())
44            .clicked()
45        {
46            prefs.theme = theme;
47        }
48    }
49}
50
51fn font_menu(ui: &mut Ui, prefs: &mut Preferences) {
52    no_wrap(ui);
53    for choice in FontChoice::ALL {
54        // Preview each entry in its own typeface via its registered font family.
55        let label = RichText::new(choice.display_name())
56            .family(FontFamily::Name(choice.family_name().into()));
57        if ui.selectable_label(choice == prefs.font, label).clicked() {
58            prefs.font = choice;
59        }
60    }
61}