use eframe::egui; use egui::{Align2, Color32, FontId, Rect, Sense, Stroke, vec2}; use crate::game::{Archetype, Glyph}; use crate::render::{CELL_H, CELL_W, pos_to_cell}; /// Renders the floating glyph-picker dialog and updates `glyph` in place. /// /// Shows three sections: board palette (unique glyphs on the current board), /// FG/BG color pickers, and a 16×6 printable-ASCII character grid. /// Closes when the window's X button is clicked, writing `false` to `open`. pub(crate) fn show( ctx: &egui::Context, open: &mut bool, glyph: &mut Glyph, board_cells: &[(Glyph, Archetype)], ) { // Collect unique glyphs from the board before the window closure borrows // `glyph` mutably, to avoid a borrow conflict with `board_cells`. let board_glyphs: Vec = { let mut seen: Vec = Vec::new(); for (g, _) in board_cells { if !seen.contains(g) { seen.push(*g); } } seen }; egui::Window::new("Glyph") .collapsible(false) .resizable(false) .open(open) .show(ctx, |ui| { // ----- Board palette ----- ui.label("Board palette"); ui.horizontal_wrapped(|ui| { for &g in &board_glyphs { let (r, resp) = ui.allocate_exact_size(vec2(CELL_W, CELL_H), Sense::click()); { let p = ui.painter(); p.rect_filled(r, 0.0, g.bg); p.text(r.center(), Align2::CENTER_CENTER, g.ch, FontId::monospace(CELL_H), g.fg); if g == *glyph { p.rect_stroke(r, 0.0, Stroke::new(1.0, Color32::WHITE), egui::epaint::StrokeKind::Middle); } } if resp.clicked() { *glyph = g; } } }); ui.separator(); // ----- Colors ----- ui.label("Colors"); ui.horizontal(|ui| { ui.label("FG"); egui::color_picker::color_edit_button_srgba( ui, &mut glyph.fg, egui::color_picker::Alpha::Opaque); ui.label("BG"); egui::color_picker::color_edit_button_srgba( ui, &mut glyph.bg, egui::color_picker::Alpha::Opaque); }); ui.separator(); // ----- Character grid ----- // 16 columns × 6 rows covering printable ASCII 0x20–0x7E. ui.label("Character"); const CHAR_COLS: usize = 16; let chars: Vec = (0x20u32..=0x7eu32).filter_map(char::from_u32).collect(); let rows = chars.len().div_ceil(CHAR_COLS); let grid_size = vec2(CHAR_COLS as f32 * CELL_W, rows as f32 * CELL_H); let (grid_rect, grid_resp) = ui.allocate_exact_size(grid_size, Sense::click()); let fg = glyph.fg; let bg = glyph.bg; let cur_ch = glyph.ch; { let p = ui.painter(); for (i, &ch) in chars.iter().enumerate() { let col = i % CHAR_COLS; let row = i / CHAR_COLS; let tl = grid_rect.min + vec2(col as f32 * CELL_W, row as f32 * CELL_H); let cell = Rect::from_min_size(tl, vec2(CELL_W, CELL_H)); p.rect_filled(cell, 0.0, bg); p.text(cell.center(), Align2::CENTER_CENTER, ch, FontId::monospace(CELL_H), fg); if ch == cur_ch { p.rect_stroke(cell, 0.0, Stroke::new(1.0, Color32::WHITE), egui::epaint::StrokeKind::Middle); } } } if grid_resp.clicked() && let Some(pos) = grid_resp.interact_pointer_pos() { let (col, row) = pos_to_cell(grid_rect.min, pos); let idx = row as usize * CHAR_COLS + col as usize; if let Some(&ch) = chars.get(idx) { glyph.ch = ch; } } }); }