Files
kiln/src/glyph_picker.rs
T
randrews 03d6337f04 Refactor main.rs into focused modules: render, editor, glyph_picker
Splits the flat 432-line main.rs into four modules so each file has one
clear job: render.rs owns layout constants and drawing primitives,
editor.rs owns EditorTab/EditorState and the side panel, glyph_picker.rs
owns the floating picker dialog with a decoupled (open, glyph) interface,
and main.rs is reduced to AppMode, App, and the frame loop (~150 lines).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 19:09:16 -05:00

112 lines
4.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<Glyph> = {
let mut seen: Vec<Glyph> = 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 0x200x7E.
ui.label("Character");
const CHAR_COLS: usize = 16;
let chars: Vec<char> =
(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;
}
}
});
}