initial editor mode
This commit is contained in:
@@ -50,6 +50,68 @@ impl<'a> BoardWidget<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps a board cell `(bx, by)` to its screen position within `area`, using the
|
||||
/// same centering/scrolling layout as [`BoardWidget`]. Returns `None` when the
|
||||
/// cell is scrolled out of view.
|
||||
///
|
||||
/// The inverse of [`screen_to_board`]; both reuse [`BoardWidget::axis`] so they
|
||||
/// stay consistent with how the board is actually drawn. (Unlike
|
||||
/// `speech::board_screen_pos`, which clamps off-screen cells to the edge, this
|
||||
/// reports off-screen cells as `None` — needed for exact cursor placement.)
|
||||
pub fn board_to_screen(area: Rect, board: &Board, bx: usize, by: usize) -> Option<(u16, u16)> {
|
||||
let (off_x, pad_x, cols) = BoardWidget::axis(board.width, area.width as usize, board.player.x);
|
||||
let (off_y, pad_y, rows) = BoardWidget::axis(board.height, area.height as usize, board.player.y);
|
||||
// Cell must fall within the visible window on both axes.
|
||||
if bx < off_x || bx >= off_x + cols || by < off_y || by >= off_y + rows {
|
||||
return None;
|
||||
}
|
||||
let sx = area.x + pad_x + (bx - off_x) as u16;
|
||||
let sy = area.y + pad_y + (by - off_y) as u16;
|
||||
Some((sx, sy))
|
||||
}
|
||||
|
||||
/// Maps a screen position `(sx, sy)` to the board cell drawn there within `area`,
|
||||
/// the inverse of [`board_to_screen`]. Returns `None` when the point lies outside
|
||||
/// the drawn board (in the centering pad or past the visible cells).
|
||||
pub fn screen_to_board(area: Rect, board: &Board, sx: u16, sy: u16) -> Option<(usize, usize)> {
|
||||
let (off_x, pad_x, cols) = BoardWidget::axis(board.width, area.width as usize, board.player.x);
|
||||
let (off_y, pad_y, rows) = BoardWidget::axis(board.height, area.height as usize, board.player.y);
|
||||
// Screen-space offset from the first drawn cell; reject anything before it.
|
||||
let col = (sx as i32) - (area.x as i32 + pad_x as i32);
|
||||
let row = (sy as i32) - (area.y as i32 + pad_y as i32);
|
||||
if col < 0 || row < 0 || col as usize >= cols || row as usize >= rows {
|
||||
return None;
|
||||
}
|
||||
Some((off_x + col as usize, off_y + row as usize))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::BoardWidget;
|
||||
|
||||
#[test]
|
||||
fn axis_centers_a_small_board() {
|
||||
// 10-cell board in a 20-cell view: no scroll, 5 cells of pad each side.
|
||||
let (off, pad, count) = BoardWidget::axis(10, 20, 3);
|
||||
assert_eq!((off, pad, count), (0, 5, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn axis_scrolls_a_large_board_to_follow_the_player() {
|
||||
// 100-cell board in a 20-cell view, player at 50: centered, no pad.
|
||||
let (off, pad, count) = BoardWidget::axis(100, 20, 50);
|
||||
assert_eq!((off, pad, count), (40, 0, 20));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn axis_clamps_scroll_at_the_edges() {
|
||||
// Player near the left edge can't scroll past 0.
|
||||
assert_eq!(BoardWidget::axis(100, 20, 2), (0, 0, 20));
|
||||
// Player near the right edge clamps to board_len - view.
|
||||
assert_eq!(BoardWidget::axis(100, 20, 99), (80, 0, 20));
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for BoardWidget<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let board = self.board;
|
||||
|
||||
Reference in New Issue
Block a user