BREP_app 0.2.0

The BREP CAD application: an eframe (egui + wgpu) host that draws the brep-render 3D engine into an egui frame — native + wasm from one codebase.
Documentation
//! The SINGLE source of truth for toolbar-button styling — shared by the main
//! toolbar (`toolbar.rs`), the context bar (`context_bar.rs`), and the 2D sketcher
//! toolbar (`sketch.rs`). Every toolbar button goes through here, so sizing/style
//! changes land in ONE place. Buttons show either one custom-font glyph or several
//! custom-font layers painted at the same origin, with the human label in the hover
//! TOOLTIP. They remain SQUARE (min-width == height).
use eframe::egui;

/// Square edge length of a single-glyph toolbar button (min-width == height).
pub const TOOLBAR_BTN: f32 = 28.0;

fn square() -> egui::Vec2 {
    egui::vec2(TOOLBAR_BTN, TOOLBAR_BTN)
}

// Flat color-layer artwork for icons that are otherwise a single glyph, so ANY
// plain `button`/`toggle` call site renders them in color with no change — the
// same stacked-layer trick the main toolbar's file icons use (see
// [`layered_button`]). Each treatment is `(fill glyph UNDER, ink glyph OVER)`;
// the fill glyph lives in a private-use slot and the ink glyph is the base
// codepoint, so a plain text use (e.g. a heading) still shows the ink outline.
const BUG_FILL: egui::Color32 = egui::Color32::from_rgb(0xE1, 0x54, 0x4A);
const BUG_INK: egui::Color32 = egui::Color32::from_rgb(0x5E, 0x1A, 0x14);
const BOOK_FILL: egui::Color32 = egui::Color32::from_rgb(0x2E, 0x9E, 0x8F);
const BOOK_INK: egui::Color32 = egui::Color32::from_rgb(0x12, 0x48, 0x40);
const DRAW_FILL: egui::Color32 = egui::Color32::from_rgb(0xF2, 0xB3, 0x3D);
const DRAW_INK: egui::Color32 = egui::Color32::from_rgb(0x6E, 0x4A, 0x12);

const BUG_LAYERS: &[(&str, egui::Color32)] = &[("\u{E05A}", BUG_FILL), ("\u{1F41E}", BUG_INK)];
const BOOK_LAYERS: &[(&str, egui::Color32)] = &[("\u{E05B}", BOOK_FILL), ("\u{1F4DA}", BOOK_INK)];
const DRAW_LAYERS: &[(&str, egui::Color32)] = &[("\u{E05C}", DRAW_FILL), ("\u{270D}", DRAW_INK)];

/// The layered color artwork for a base glyph, if it has one — keyed by the ink
/// (base) glyph. Lets a single-glyph `button`/`button_enabled`/`toggle` render
/// in color automatically, so the toolbar, the workbench registry, and the
/// sketch tool row all light up without any per-call-site plumbing.
fn color_layers(glyph: &str) -> Option<&'static [(&'static str, egui::Color32)]> {
    match glyph {
        "\u{1F41E}" => Some(BUG_LAYERS),  // Submit Bug — bug_report
        "\u{1F4DA}" => Some(BOOK_LAYERS), // step.parts library — menu_book
        "\u{270D}" => Some(DRAW_LAYERS),  // Freehand sketch — draw (pencil)
        _ => None,
    }
}

/// A plain action toolbar button: `glyph` shown, `tooltip` on hover. Square.
/// A glyph with a registered [`color_layers`] treatment renders in color.
pub fn button(ui: &mut egui::Ui, glyph: &str, tooltip: &str) -> egui::Response {
    if let Some(layers) = color_layers(glyph) {
        return layered_button(ui, layers, tooltip);
    }
    ui.add(egui::Button::new(glyph).min_size(square()))
        .on_hover_text(tooltip)
}

/// A toolbar button enabled only when `enabled` (undo/redo, selection actions).
pub fn button_enabled(
    ui: &mut egui::Ui,
    enabled: bool,
    glyph: &str,
    tooltip: &str,
) -> egui::Response {
    if let Some(layers) = color_layers(glyph) {
        return layered_button_enabled(ui, enabled, layers, tooltip);
    }
    ui.add_enabled(enabled, egui::Button::new(glyph).min_size(square()))
        .on_hover_text(tooltip)
}

/// Draw several custom-font glyphs at the exact same origin. Each layer gets
/// its own color, allowing a single traditional icon to have a filled body,
/// outline, shadow, and highlights while remaining entirely font/vector based.
pub fn layered_button(
    ui: &mut egui::Ui,
    layers: &[(&str, egui::Color32)],
    tooltip: &str,
) -> egui::Response {
    layered_button_enabled(ui, true, layers, tooltip)
}

/// Enabled/disabled variant of [`layered_button`].
pub fn layered_button_enabled(
    ui: &mut egui::Ui,
    enabled: bool,
    layers: &[(&str, egui::Color32)],
    tooltip: &str,
) -> egui::Response {
    let response = ui
        .add_enabled(enabled, egui::Button::new("").min_size(square()))
        .on_hover_text(tooltip);

    let opacity = if enabled {
        1.0
    } else {
        ui.visuals().disabled_alpha()
    };
    paint_layers(ui, response.rect, layers, opacity);
    response
}

/// Toggle variant for a layered custom-font icon. The normal egui selected
/// background remains intact; only the icon artwork is custom-painted.
pub fn layered_toggle(
    ui: &mut egui::Ui,
    selected: bool,
    layers: &[(&str, egui::Color32)],
    tooltip: &str,
) -> egui::Response {
    let response = ui
        .add(egui::Button::new("").min_size(square()).selected(selected))
        .on_hover_text(tooltip);
    paint_layers(ui, response.rect, layers, 1.0);
    response
}

fn paint_layers(
    ui: &egui::Ui,
    rect: egui::Rect,
    layers: &[(&str, egui::Color32)],
    opacity: f32,
) {
    let mut font = egui::TextStyle::Button.resolve(ui.style());
    font.size = 17.0;
    for (glyph, color) in layers {
        ui.painter().text(
            rect.center(),
            egui::Align2::CENTER_CENTER,
            *glyph,
            font.clone(),
            color.gamma_multiply(opacity),
        );
    }
}

/// A toolbar TOGGLE button (draw-tool selection, wireframe): pressed when `selected`.
/// A glyph with a registered [`color_layers`] treatment renders in color.
pub fn toggle(ui: &mut egui::Ui, selected: bool, glyph: &str, tooltip: &str) -> egui::Response {
    if let Some(layers) = color_layers(glyph) {
        return layered_toggle(ui, selected, layers, tooltip);
    }
    ui.add(egui::Button::new(glyph).min_size(square()).selected(selected))
        .on_hover_text(tooltip)
}

/// The outcome of a toolbar [`select`] combo for one frame.
pub struct SelectResult {
    /// The option `id` the user picked THIS frame — `Some` only on a real change
    /// (differs from `current`); `None` otherwise.
    pub changed: Option<String>,
    /// The combo HEADER's screen rect (the verifier clicks this to open the menu).
    pub header_rect: egui::Rect,
    /// `(id, rect)` per menu item while the menu is OPEN (empty when closed) — the
    /// verifier clicks an item rect to drive a SELECTION.
    pub item_rects: Vec<(String, egui::Rect)>,
}

/// A toolbar SELECT (combo box) matched to the toolbar-button height — the ONE
/// place a toolbar dropdown's style lives, so it reads as part of the button row.
/// `options` are `(label, id)` pairs; `current` is the selected id. Publishes the
/// header rect and (while open) per-item rects for the headed verifier.
pub fn select(
    ui: &mut egui::Ui,
    id_source: &str,
    current: &str,
    options: &[(&str, &str)],
) -> SelectResult {
    let current_label = options
        .iter()
        .find(|(_, id)| *id == current)
        .map(|(label, _)| *label)
        .unwrap_or(current);
    let mut changed = None;
    let mut item_rects = Vec::new();
    let inner = egui::ComboBox::from_id_salt(("toolbar-select", id_source))
        // Let the popup size to its content (all options visible) — a fixed
        // TOOLBAR_BTN height capped the menu to ~one row, hiding options past the
        // first when the list grew (e.g. the added placeholder workbenches).
        .selected_text(current_label)
        .show_ui(ui, |ui| {
            for (label, id) in options {
                let resp = ui.selectable_label(*id == current, *label);
                item_rects.push(((*id).to_string(), resp.rect));
                if resp.clicked() && *id != current {
                    changed = Some((*id).to_string());
                }
            }
        });
    SelectResult { changed, header_rect: inner.response.rect, item_rects }
}