Simplify: extract paint_glyph, drop unused param and redundant comments
- Add paint_glyph(painter, rect, glyph) to render.rs; draw_glyph now delegates to it, eliminating the duplicated rect_filled+text pattern that appeared in four places across editor.rs and glyph_picker.rs - Remove unused _board param from show_editor_panel and its call site - Drop redundant section-header comments in glyph_picker.rs (the ui.label() calls immediately below already name each section) - Remove extracted fg/bg/cur_ch locals in the char grid loop now that paint_glyph accepts a Glyph directly - Fix CLAUDE.md update phase description (stale from pre-refactor) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -38,8 +38,9 @@ The game is a single Rust binary using **eframe 0.33 / egui 0.33** for the GUI.
|
|||||||
`update` is structured in phases:
|
`update` is structured in phases:
|
||||||
- Input handling — arrow keys move the player (Play mode only)
|
- Input handling — arrow keys move the player (Play mode only)
|
||||||
- `egui::TopBottomPanel::top` — menu bar (File → Exit, Play/Edit mode toggle)
|
- `egui::TopBottomPanel::top` — menu bar (File → Exit, Play/Edit mode toggle)
|
||||||
- `egui::SidePanel::right` — archetype palette panel (Edit mode only; declared before CentralPanel)
|
- `editor::show_editor_panel` — archetype palette panel (Edit mode only; declared before CentralPanel)
|
||||||
- `egui::CentralPanel::default` — game viewport; rendered with `ui.painter()`; click-to-paint in Edit mode
|
- `egui::CentralPanel::default` — game viewport; rendered with `render::draw_board`; click-to-paint in Edit mode
|
||||||
|
- `glyph_picker::show` — floating picker dialog (Edit mode only, when open)
|
||||||
|
|
||||||
### Modules
|
### Modules
|
||||||
|
|
||||||
|
|||||||
+6
-22
@@ -1,8 +1,8 @@
|
|||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::{Align2, FontId, Sense, vec2};
|
use egui::{Sense, vec2};
|
||||||
|
|
||||||
use crate::game::{Archetype, Board, Glyph, ALL_ARCHETYPES};
|
use crate::game::{Archetype, Glyph, ALL_ARCHETYPES};
|
||||||
use crate::render::{CELL_H, CELL_W, PALETTE_PANEL_W};
|
use crate::render::{CELL_H, CELL_W, PALETTE_PANEL_W, paint_glyph};
|
||||||
|
|
||||||
/// Which tab is active in the editor side panel.
|
/// Which tab is active in the editor side panel.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
@@ -43,12 +43,11 @@ impl EditorState {
|
|||||||
///
|
///
|
||||||
/// Shows tab bar (Palette / Board / World) and, on the Palette tab, the
|
/// Shows tab bar (Palette / Board / World) and, on the Palette tab, the
|
||||||
/// scrollable archetype list and current-glyph preview button.
|
/// scrollable archetype list and current-glyph preview button.
|
||||||
pub(crate) fn show_editor_panel(ctx: &egui::Context, editor: &mut EditorState, _board: &Board) {
|
pub(crate) fn show_editor_panel(ctx: &egui::Context, editor: &mut EditorState) {
|
||||||
egui::SidePanel::right("palette_panel")
|
egui::SidePanel::right("palette_panel")
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_width(PALETTE_PANEL_W)
|
.default_width(PALETTE_PANEL_W)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
// Tab bar
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.selectable_value(&mut editor.tab, EditorTab::Palette, "Palette");
|
ui.selectable_value(&mut editor.tab, EditorTab::Palette, "Palette");
|
||||||
ui.selectable_value(&mut editor.tab, EditorTab::Board, "Board");
|
ui.selectable_value(&mut editor.tab, EditorTab::Board, "Board");
|
||||||
@@ -72,12 +71,7 @@ pub(crate) fn show_editor_panel(ctx: &egui::Context, editor: &mut EditorState, _
|
|||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let (r, cell_resp) = ui.allocate_exact_size(
|
let (r, cell_resp) = ui.allocate_exact_size(
|
||||||
vec2(CELL_W, CELL_H), Sense::click());
|
vec2(CELL_W, CELL_H), Sense::click());
|
||||||
{
|
paint_glyph(ui.painter(), r, &glyph);
|
||||||
let p = ui.painter();
|
|
||||||
p.rect_filled(r, 0.0, glyph.bg);
|
|
||||||
p.text(r.center(), Align2::CENTER_CENTER,
|
|
||||||
glyph.ch, FontId::monospace(CELL_H), glyph.fg);
|
|
||||||
}
|
|
||||||
let label_resp =
|
let label_resp =
|
||||||
ui.selectable_label(is_selected, archetype.name());
|
ui.selectable_label(is_selected, archetype.name());
|
||||||
if cell_resp.clicked() || label_resp.clicked() {
|
if cell_resp.clicked() || label_resp.clicked() {
|
||||||
@@ -94,17 +88,7 @@ pub(crate) fn show_editor_panel(ctx: &egui::Context, editor: &mut EditorState, _
|
|||||||
// Paint a preview cell showing the current glyph, sized like a board cell.
|
// Paint a preview cell showing the current glyph, sized like a board cell.
|
||||||
let (cell_rect, glyph_btn) =
|
let (cell_rect, glyph_btn) =
|
||||||
ui.allocate_exact_size(vec2(CELL_W, CELL_H), Sense::click());
|
ui.allocate_exact_size(vec2(CELL_W, CELL_H), Sense::click());
|
||||||
{
|
paint_glyph(ui.painter(), cell_rect, &editor.glyph);
|
||||||
let p = ui.painter();
|
|
||||||
p.rect_filled(cell_rect, 0.0, editor.glyph.bg);
|
|
||||||
p.text(
|
|
||||||
cell_rect.center(),
|
|
||||||
Align2::CENTER_CENTER,
|
|
||||||
editor.glyph.ch,
|
|
||||||
FontId::monospace(CELL_H),
|
|
||||||
editor.glyph.fg,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if glyph_btn.clicked() {
|
if glyph_btn.clicked() {
|
||||||
editor.glyph_picker_open = true;
|
editor.glyph_picker_open = true;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-17
@@ -1,8 +1,8 @@
|
|||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::{Align2, Color32, FontId, Rect, Sense, Stroke, vec2};
|
use egui::{Color32, Rect, Sense, Stroke, vec2};
|
||||||
|
|
||||||
use crate::game::{Archetype, Glyph};
|
use crate::game::{Archetype, Glyph};
|
||||||
use crate::render::{CELL_H, CELL_W, pos_to_cell};
|
use crate::render::{CELL_H, CELL_W, paint_glyph, pos_to_cell};
|
||||||
|
|
||||||
/// Renders the floating glyph-picker dialog and updates `glyph` in place.
|
/// Renders the floating glyph-picker dialog and updates `glyph` in place.
|
||||||
///
|
///
|
||||||
@@ -32,22 +32,17 @@ pub(crate) fn show(
|
|||||||
.resizable(false)
|
.resizable(false)
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
// ----- Board palette -----
|
|
||||||
ui.label("Board palette");
|
ui.label("Board palette");
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
for &g in &board_glyphs {
|
for &g in &board_glyphs {
|
||||||
let (r, resp) =
|
let (r, resp) =
|
||||||
ui.allocate_exact_size(vec2(CELL_W, CELL_H), Sense::click());
|
ui.allocate_exact_size(vec2(CELL_W, CELL_H), Sense::click());
|
||||||
{
|
|
||||||
let p = ui.painter();
|
let p = ui.painter();
|
||||||
p.rect_filled(r, 0.0, g.bg);
|
paint_glyph(p, r, &g);
|
||||||
p.text(r.center(), Align2::CENTER_CENTER, g.ch,
|
|
||||||
FontId::monospace(CELL_H), g.fg);
|
|
||||||
if g == *glyph {
|
if g == *glyph {
|
||||||
p.rect_stroke(r, 0.0, Stroke::new(1.0, Color32::WHITE),
|
p.rect_stroke(r, 0.0, Stroke::new(1.0, Color32::WHITE),
|
||||||
egui::epaint::StrokeKind::Middle);
|
egui::epaint::StrokeKind::Middle);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if resp.clicked() {
|
if resp.clicked() {
|
||||||
*glyph = g;
|
*glyph = g;
|
||||||
}
|
}
|
||||||
@@ -56,7 +51,6 @@ pub(crate) fn show(
|
|||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
// ----- Colors -----
|
|
||||||
ui.label("Colors");
|
ui.label("Colors");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("FG");
|
ui.label("FG");
|
||||||
@@ -69,7 +63,6 @@ pub(crate) fn show(
|
|||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
// ----- Character grid -----
|
|
||||||
// 16 columns × 6 rows covering printable ASCII 0x20–0x7E.
|
// 16 columns × 6 rows covering printable ASCII 0x20–0x7E.
|
||||||
ui.label("Character");
|
ui.label("Character");
|
||||||
const CHAR_COLS: usize = 16;
|
const CHAR_COLS: usize = 16;
|
||||||
@@ -79,9 +72,6 @@ pub(crate) fn show(
|
|||||||
let grid_size = vec2(CHAR_COLS as f32 * CELL_W, rows as f32 * CELL_H);
|
let grid_size = vec2(CHAR_COLS as f32 * CELL_W, rows as f32 * CELL_H);
|
||||||
let (grid_rect, grid_resp) =
|
let (grid_rect, grid_resp) =
|
||||||
ui.allocate_exact_size(grid_size, Sense::click());
|
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();
|
let p = ui.painter();
|
||||||
for (i, &ch) in chars.iter().enumerate() {
|
for (i, &ch) in chars.iter().enumerate() {
|
||||||
@@ -90,10 +80,8 @@ pub(crate) fn show(
|
|||||||
let tl = grid_rect.min
|
let tl = grid_rect.min
|
||||||
+ vec2(col as f32 * CELL_W, row as f32 * CELL_H);
|
+ vec2(col as f32 * CELL_W, row as f32 * CELL_H);
|
||||||
let cell = Rect::from_min_size(tl, vec2(CELL_W, CELL_H));
|
let cell = Rect::from_min_size(tl, vec2(CELL_W, CELL_H));
|
||||||
p.rect_filled(cell, 0.0, bg);
|
paint_glyph(p, cell, &Glyph { ch, fg: glyph.fg, bg: glyph.bg });
|
||||||
p.text(cell.center(), Align2::CENTER_CENTER, ch,
|
if ch == glyph.ch {
|
||||||
FontId::monospace(CELL_H), fg);
|
|
||||||
if ch == cur_ch {
|
|
||||||
p.rect_stroke(cell, 0.0, Stroke::new(1.0, Color32::WHITE),
|
p.rect_stroke(cell, 0.0, Stroke::new(1.0, Color32::WHITE),
|
||||||
egui::epaint::StrokeKind::Middle);
|
egui::epaint::StrokeKind::Middle);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@ impl eframe::App for App {
|
|||||||
// --- Editor side panel ---
|
// --- Editor side panel ---
|
||||||
// Must be declared before CentralPanel so egui allocates its space first.
|
// Must be declared before CentralPanel so egui allocates its space first.
|
||||||
if self.mode == AppMode::Edit {
|
if self.mode == AppMode::Edit {
|
||||||
show_editor_panel(ctx, &mut self.editor, &self.state.board);
|
show_editor_panel(ctx, &mut self.editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Board rendering ---
|
// --- Board rendering ---
|
||||||
|
|||||||
+11
-7
@@ -49,11 +49,17 @@ pub(crate) const MIN_WINDOW_W: f32 = CELL_W * 10.0 + 2.0 * PANEL_MARGIN;
|
|||||||
/// Minimum window height: enough room for 5 cells plus menu and margins.
|
/// Minimum window height: enough room for 5 cells plus menu and margins.
|
||||||
pub(crate) const MIN_WINDOW_H: f32 = CELL_H * 5.0 + MENU_H + 2.0 * PANEL_MARGIN;
|
pub(crate) const MIN_WINDOW_H: f32 = CELL_H * 5.0 + MENU_H + 2.0 * PANEL_MARGIN;
|
||||||
|
|
||||||
/// Draws a single cell at grid position `(x, y)` using the given glyph.
|
/// Paints a glyph into an already-allocated `rect`.
|
||||||
///
|
///
|
||||||
/// Each cell is rendered as two layers:
|
/// Unlike [`draw_glyph`], this does not compute the rect from grid coordinates —
|
||||||
/// 1. A filled rectangle in `glyph.bg` covering the full cell area.
|
/// the caller owns the rect (typically from [`egui::Ui::allocate_exact_size`])
|
||||||
/// 2. A monospace character (`glyph.ch`) in `glyph.fg`, centered in the cell.
|
/// and handles interaction. Use this when you need the click [`egui::Response`].
|
||||||
|
pub(crate) fn paint_glyph(painter: &egui::Painter, rect: Rect, glyph: &Glyph) {
|
||||||
|
painter.rect_filled(rect, 0.0, glyph.bg);
|
||||||
|
painter.text(rect.center(), Align2::CENTER_CENTER, glyph.ch, FontId::monospace(CELL_H), glyph.fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws a single cell at grid position `(x, y)` using the given glyph.
|
||||||
///
|
///
|
||||||
/// `origin` is the pixel position of cell `(0, 0)` — the top-left corner of
|
/// `origin` is the pixel position of cell `(0, 0)` — the top-left corner of
|
||||||
/// the board within the panel. Cell positions are computed from `origin` using
|
/// the board within the panel. Cell positions are computed from `origin` using
|
||||||
@@ -61,9 +67,7 @@ pub(crate) const MIN_WINDOW_H: f32 = CELL_H * 5.0 + MENU_H + 2.0 * PANEL_MARGIN;
|
|||||||
pub(crate) fn draw_glyph(painter: &egui::Painter, origin: Pos2, x: usize, y: usize, glyph: &Glyph) {
|
pub(crate) fn draw_glyph(painter: &egui::Painter, origin: Pos2, x: usize, y: usize, glyph: &Glyph) {
|
||||||
let tl = origin + vec2(x as f32 * CELL_W, y as f32 * CELL_H);
|
let tl = origin + vec2(x as f32 * CELL_W, y as f32 * CELL_H);
|
||||||
let rect = Rect::from_min_size(tl, vec2(CELL_W, CELL_H));
|
let rect = Rect::from_min_size(tl, vec2(CELL_W, CELL_H));
|
||||||
let center = rect.center();
|
paint_glyph(painter, rect, glyph);
|
||||||
painter.rect_filled(rect, 0.0, glyph.bg);
|
|
||||||
painter.text(center, Align2::CENTER_CENTER, glyph.ch, FontId::monospace(CELL_H), glyph.fg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws all board cells then the player overlay at `origin`.
|
/// Draws all board cells then the player overlay at `origin`.
|
||||||
|
|||||||
Reference in New Issue
Block a user