keys 2
This commit is contained in:
+10
-2
@@ -13,7 +13,7 @@ use crate::editor_menu::{MenuEntry, MenuLevel};
|
||||
use crate::log::{LogWidget, log_preview_line};
|
||||
use crate::render::{BoardWidget, board_to_screen, screen_to_board};
|
||||
use crate::ui::Ui;
|
||||
use crate::utils::rgba8_to_color;
|
||||
use crate::utils::{glyph_to_span, rgba8_to_color};
|
||||
use kiln_core::cp437::tile_to_char;
|
||||
use kiln_core::game::GameState;
|
||||
use kiln_core::glyph::Glyph;
|
||||
@@ -458,6 +458,14 @@ pub(crate) fn draw_editor(frame: &mut Frame, ed: &mut EditorState, ui: &mut Ui)
|
||||
Span::styled(label, label_style),
|
||||
]));
|
||||
}
|
||||
MenuEntry::Glyph { key, glyph, label, .. } => {
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(format!("[{}] ", key), key_style),
|
||||
glyph_to_span(glyph),
|
||||
Span::raw(" "),
|
||||
Span::styled(label, label_style),
|
||||
]));
|
||||
}
|
||||
MenuEntry::Blank => lines.push(Line::from("")),
|
||||
// A horizontal rule spanning the sidebar's inner width.
|
||||
MenuEntry::Separator => lines.push(Line::from(Span::styled(
|
||||
@@ -514,7 +522,7 @@ fn draw_footer_lines<'a>(
|
||||
// The archetype currently being drawn (no UI to change it yet).
|
||||
Line::from(Span::styled(ed.current_archetype.name(), label_style)),
|
||||
Line::from(vec![
|
||||
Span::styled("[g] ", key_style),
|
||||
Span::styled("[G] ", key_style),
|
||||
Span::styled("Glyph ", label_style),
|
||||
preview,
|
||||
]),
|
||||
|
||||
@@ -2,6 +2,8 @@ use crate::editor::EditorState;
|
||||
use crate::menu::{MenuItem, MenuKey};
|
||||
use crate::mode::PendingMode;
|
||||
use kiln_core::{Archetype, Builtin};
|
||||
use kiln_core::game::KeyType;
|
||||
use kiln_core::glyph::Glyph;
|
||||
|
||||
/// One level in the editor's sidebar menu tree.
|
||||
///
|
||||
@@ -100,10 +102,21 @@ impl MenuLevel {
|
||||
ed.set_current(Archetype::Builtin(Builtin::Pusher, "pusher_west"))
|
||||
}),
|
||||
],
|
||||
MenuLevel::Items => vec![MenuEntry::item('t', "♦ Gem", |ed| {
|
||||
// 't' for 'treasure' — 'g' conflicts with glyph picker
|
||||
ed.set_current(Archetype::Builtin(Builtin::Gem, "gem"))
|
||||
})],
|
||||
MenuLevel::Items => vec![
|
||||
MenuEntry::item('t', "♦ Gem", |ed| {
|
||||
// 't' for 'treasure' — 'g' conflicts with glyph picker
|
||||
ed.set_current(Archetype::Builtin(Builtin::Gem, "gem"))
|
||||
}),
|
||||
MenuEntry::Separator,
|
||||
MenuEntry::glyph('b', KeyType::Blue.glyph(), "Blue key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_blue"))),
|
||||
MenuEntry::glyph('g', KeyType::Green.glyph(),"Green key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_green"))),
|
||||
MenuEntry::glyph('c', KeyType::Cyan.glyph(),"Cyan key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_cyan"))),
|
||||
MenuEntry::glyph('r', KeyType::Red.glyph(),"Red key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_red"))),
|
||||
MenuEntry::glyph('p', KeyType::Purple.glyph(),"Purple key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_purple"))),
|
||||
MenuEntry::glyph('o', KeyType::Orange.glyph(), "Orange key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_orange"))),
|
||||
MenuEntry::glyph('y', KeyType::Yellow.glyph(), "Yellow key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_yellow"))),
|
||||
MenuEntry::glyph('w', KeyType::White.glyph(), "White key", |ed| ed.set_current(Archetype::Builtin(Builtin::Key, "key_white"))),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +126,7 @@ impl MenuLevel {
|
||||
pub(crate) fn perform_key(self, ch: char, editor: &mut EditorState) {
|
||||
let action = self.entries().into_iter().find_map(|entry| match entry {
|
||||
MenuEntry::Item { key, action, .. } if key == ch => Some(action),
|
||||
MenuEntry::Glyph { key, action, .. } if key == ch => Some(action),
|
||||
_ => None,
|
||||
});
|
||||
if let Some(action) = action {
|
||||
@@ -134,6 +148,17 @@ pub(crate) enum MenuEntry {
|
||||
/// Run when the user presses `key`; mutates the editor session.
|
||||
action: Box<dyn FnOnce(&mut EditorState)>,
|
||||
},
|
||||
/// An item labeled by a styled Glyph
|
||||
Glyph {
|
||||
/// The letter the user presses to activate this item.
|
||||
key: char,
|
||||
/// The glyph to show next to the label
|
||||
glyph: Glyph,
|
||||
/// Display label shown after the `[key]` in the sidebar.
|
||||
label: String,
|
||||
/// Run when the user presses `key`; mutates the editor session.
|
||||
action: Box<dyn FnOnce(&mut EditorState)>,
|
||||
},
|
||||
/// A blank spacer line. Part of the menu API; no current level uses one yet.
|
||||
#[allow(dead_code)]
|
||||
Blank,
|
||||
@@ -156,6 +181,20 @@ impl MenuEntry {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn glyph<F: FnOnce(&mut EditorState) + 'static>(
|
||||
key: char,
|
||||
glyph: Glyph,
|
||||
label: impl Into<String>,
|
||||
action: F,
|
||||
) -> Self {
|
||||
MenuEntry::Glyph {
|
||||
key,
|
||||
glyph,
|
||||
label: label.into(),
|
||||
action: Box::new(action),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn value<F: FnOnce(&EditorState) -> String + 'static>(action: F) -> Self {
|
||||
MenuEntry::CurrentValue(Box::new(action))
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ pub(crate) fn handle_editor_input(event: Event, term_w: u16, ed: &mut EditorStat
|
||||
KeyCode::Right => ed.move_cursor(1, 0),
|
||||
KeyCode::Char('l') => ui.log.toggle(),
|
||||
// `g` opens the glyph picker to edit the current drawing glyph.
|
||||
KeyCode::Char('g') => ed.open_glyph_picker(),
|
||||
KeyCode::Char('G') => ed.open_glyph_picker(),
|
||||
// Space stamps the current thing; Tab toggles draw mode.
|
||||
KeyCode::Char(' ') => ed.place_current(),
|
||||
KeyCode::Tab => ed.toggle_draw_mode(),
|
||||
@@ -143,7 +143,7 @@ pub(crate) fn handle_editor_input(event: Event, term_w: u16, ed: &mut EditorStat
|
||||
},
|
||||
Event::Mouse(m) => match m.kind {
|
||||
// Right-click moves the cursor to the clicked cell (if on the board).
|
||||
MouseEventKind::Down(MouseButton::Right) => ed.set_cursor_at_screen(m.column, m.row),
|
||||
MouseEventKind::Down(MouseButton::Left) => ed.set_cursor_at_screen(m.column, m.row),
|
||||
// Dragging the divider resizes the sidebar.
|
||||
MouseEventKind::Drag(_) => ed.resize_sidebar(term_w.saturating_sub(m.column), term_w),
|
||||
_ => {}
|
||||
|
||||
@@ -86,7 +86,7 @@ impl Widget for StatusSidebarWidget {
|
||||
Line::from(vec![
|
||||
Span::raw("Gems: "),
|
||||
Span::styled(gem_char, gem_style),
|
||||
Span::raw(format!("{}", self.gems)),
|
||||
Span::raw(format!("{} ", self.gems)),
|
||||
]),
|
||||
Line::from(""),
|
||||
Line::from_iter(key_spans.into_iter()),
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use color::Rgba8;
|
||||
use kiln_core::cp437::tile_to_char;
|
||||
use kiln_core::glyph::Glyph;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::prelude::Color;
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::Span;
|
||||
|
||||
/// Converts a core [`Rgba8`] color into a ratatui truecolor [`Color`].
|
||||
///
|
||||
@@ -10,6 +14,17 @@ pub fn rgba8_to_color(c: Rgba8) -> Color {
|
||||
Color::Rgb(c.r, c.g, c.b)
|
||||
}
|
||||
|
||||
/// Converts a [`Glyph`] to a single-character styled [`Span`].
|
||||
///
|
||||
/// The tile index is mapped to a CP437 character; fg and bg are both applied.
|
||||
pub fn glyph_to_span(glyph: Glyph) -> Span<'static> {
|
||||
let ch = tile_to_char(glyph.tile).to_string();
|
||||
let style = Style::default()
|
||||
.fg(rgba8_to_color(glyph.fg))
|
||||
.bg(rgba8_to_color(glyph.bg));
|
||||
Span::styled(ch, style)
|
||||
}
|
||||
|
||||
/// Returns true if two `Rect`s share at least one cell.
|
||||
pub fn rects_overlap(a: Rect, b: Rect) -> bool {
|
||||
a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height
|
||||
|
||||
Reference in New Issue
Block a user