generated from GarandPLG/rust-flake-template
Add marking mode; rename resize and zoom methods
Introduce a marking mode that lets users toggle cells with Space and clear them with Backspace. BoardState now stores `marking_cells` and a list of `marked_cells` and provides methods to start, clear, and update marks. CellWidget tracks a `marked` flag and renders marked cells in LightMagenta. Keybindings are updated: Space now reads “Marking cells”, Backspace reads “Cancel marking”, and the original Enter binding is commented out. The former `resize_change` and `zoom_change` functions are renamed to `change_resize` and `change_zoom`; all call sites are updated accordingly.
This commit is contained in:
+1
-1
@@ -60,7 +60,7 @@ impl App {
|
|||||||
let Some(state) = self.states_mut() else {
|
let Some(state) = self.states_mut() else {
|
||||||
panic!("State issue")
|
panic!("State issue")
|
||||||
};
|
};
|
||||||
state.skirmish.board.resize_change(&window_area);
|
state.skirmish.board.change_resize(&window_area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,17 +197,17 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
group: Group::Select,
|
group: Group::Select,
|
||||||
symbol: "Space",
|
symbol: "Space",
|
||||||
description: "Select",
|
description: "Marking cells",
|
||||||
},
|
|
||||||
KeyBinding {
|
|
||||||
action: Action::Enter,
|
|
||||||
code: KeyCode::Enter,
|
|
||||||
kind: KeyEventKind::Press,
|
|
||||||
modifiers: KeyModifiers::NONE,
|
|
||||||
group: Group::Select,
|
|
||||||
symbol: "Enter",
|
|
||||||
description: "Submit",
|
|
||||||
},
|
},
|
||||||
|
// KeyBinding {
|
||||||
|
// action: Action::Enter,
|
||||||
|
// code: KeyCode::Enter,
|
||||||
|
// kind: KeyEventKind::Press,
|
||||||
|
// modifiers: KeyModifiers::NONE,
|
||||||
|
// group: Group::Select,
|
||||||
|
// symbol: "Enter",
|
||||||
|
// description: "Submit",
|
||||||
|
// },
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
action: Action::Esc,
|
action: Action::Esc,
|
||||||
code: KeyCode::Esc,
|
code: KeyCode::Esc,
|
||||||
@@ -222,9 +222,9 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
code: KeyCode::Backspace,
|
code: KeyCode::Backspace,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
group: Group::Input,
|
group: Group::Select,
|
||||||
symbol: "Backspace",
|
symbol: "Backspace",
|
||||||
description: "Delete character",
|
description: "Cancel marking",
|
||||||
},
|
},
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
action: Action::ZoomIn,
|
action: Action::ZoomIn,
|
||||||
|
|||||||
@@ -62,27 +62,40 @@ pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
|
|||||||
Action::ZoomIn => match board.zoom_level {
|
Action::ZoomIn => match board.zoom_level {
|
||||||
ZoomLevel::ZoomedIn => {}
|
ZoomLevel::ZoomedIn => {}
|
||||||
ZoomLevel::Default => {
|
ZoomLevel::Default => {
|
||||||
board.zoom_change(ZoomLevel::ZoomedIn);
|
board.change_zoom(ZoomLevel::ZoomedIn);
|
||||||
board.vertical_offset.next();
|
board.vertical_offset.next();
|
||||||
}
|
}
|
||||||
ZoomLevel::ZoomedOut => {
|
ZoomLevel::ZoomedOut => {
|
||||||
board.zoom_change(ZoomLevel::Default);
|
board.change_zoom(ZoomLevel::Default);
|
||||||
board.vertical_offset.next();
|
board.vertical_offset.next();
|
||||||
board.vertical_offset.next();
|
board.vertical_offset.next();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Action::ZoomOut => match board.zoom_level {
|
Action::ZoomOut => match board.zoom_level {
|
||||||
ZoomLevel::ZoomedIn => {
|
ZoomLevel::ZoomedIn => {
|
||||||
board.zoom_change(ZoomLevel::Default);
|
board.change_zoom(ZoomLevel::Default);
|
||||||
board.vertical_offset.prev();
|
board.vertical_offset.prev();
|
||||||
}
|
}
|
||||||
ZoomLevel::Default => {
|
ZoomLevel::Default => {
|
||||||
board.zoom_change(ZoomLevel::ZoomedOut);
|
board.change_zoom(ZoomLevel::ZoomedOut);
|
||||||
board.vertical_offset.prev();
|
board.vertical_offset.prev();
|
||||||
board.vertical_offset.prev();
|
board.vertical_offset.prev();
|
||||||
}
|
}
|
||||||
ZoomLevel::ZoomedOut => {}
|
ZoomLevel::ZoomedOut => {}
|
||||||
},
|
},
|
||||||
|
Action::Space => {
|
||||||
|
if board.marking_cells {
|
||||||
|
board.marking_cells = false;
|
||||||
|
board.clear_marked_cells();
|
||||||
|
} else {
|
||||||
|
board.marking_cells = true;
|
||||||
|
board.start_marking_cells();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Action::Backspace => {
|
||||||
|
board.marking_cells = false;
|
||||||
|
board.clear_marked_cells()
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ pub struct BoardState {
|
|||||||
focused_cell: FocusedCell,
|
focused_cell: FocusedCell,
|
||||||
player_base_coords: (usize, usize),
|
player_base_coords: (usize, usize),
|
||||||
enemy_base_coords: (usize, usize),
|
enemy_base_coords: (usize, usize),
|
||||||
|
pub marking_cells: bool,
|
||||||
|
marked_cells: Vec<(usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoardState {
|
impl BoardState {
|
||||||
@@ -70,6 +72,9 @@ impl BoardState {
|
|||||||
cells.push(rows);
|
cells.push(rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let marking_cells: bool = false;
|
||||||
|
let marked_cells: Vec<(usize, usize)> = Vec::new();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
cells_area,
|
cells_area,
|
||||||
cell_width,
|
cell_width,
|
||||||
@@ -85,6 +90,8 @@ impl BoardState {
|
|||||||
focused_cell,
|
focused_cell,
|
||||||
player_base_coords,
|
player_base_coords,
|
||||||
enemy_base_coords,
|
enemy_base_coords,
|
||||||
|
marking_cells,
|
||||||
|
marked_cells,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,11 +99,76 @@ impl BoardState {
|
|||||||
&mut self.cells[row][col]
|
&mut self.cells[row][col]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_marked_cells(&self) -> Vec<&CellWidget> {
|
||||||
|
self.marked_cells
|
||||||
|
.iter()
|
||||||
|
.map(move |&(row, col)| &self.cells[row][col])
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_last_marked_cell(&self) -> Option<(usize, usize)> {
|
||||||
|
self.marked_cells.last().cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_marked_cell(&mut self, row: usize, col: usize, old_row: usize, old_col: usize) {
|
||||||
|
let last_cell: Option<(usize, usize)> = self.get_last_marked_cell();
|
||||||
|
let cell: &mut CellWidget = self.get_mut_cell(row, col);
|
||||||
|
|
||||||
|
if cell.get_marked() {
|
||||||
|
if last_cell == Some((old_row, old_col)) {
|
||||||
|
self.get_mut_cell(old_row, old_col).set_marked(false);
|
||||||
|
self.marked_cells.pop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cell.set_marked(true);
|
||||||
|
self.marked_cells.push((row, col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_marking_cells(&mut self) {
|
||||||
|
let row: usize = self.focused_cell.get_row();
|
||||||
|
let col: usize = self.focused_cell.get_col();
|
||||||
|
|
||||||
|
let cell: &mut CellWidget = self.get_mut_cell(row, col);
|
||||||
|
cell.set_marked(true);
|
||||||
|
|
||||||
|
self.marked_cells.push((row, col));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_marked_cells(&mut self) {
|
||||||
|
for (row, col) in self.marked_cells.clone() {
|
||||||
|
self.get_mut_cell(row, col).set_marked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.marked_cells.clear();
|
||||||
|
}
|
||||||
|
|
||||||
fn max_offset(map_size: usize, size: usize) -> usize {
|
fn max_offset(map_size: usize, size: usize) -> usize {
|
||||||
if map_size > size { map_size - size } else { 0 }
|
if map_size > size { map_size - size } else { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize_change(&mut self, area: &Rect) {
|
pub fn is_focused_cell_visible(&self) -> bool {
|
||||||
|
let vertical_offset: usize = self.vertical_offset.get_value();
|
||||||
|
let horizontal_offset: usize = self.horizontal_offset.get_value();
|
||||||
|
|
||||||
|
let row: usize = self.focused_cell.get_row();
|
||||||
|
let col: usize = self.focused_cell.get_col();
|
||||||
|
|
||||||
|
if 0usize.saturating_add(vertical_offset) > row
|
||||||
|
|| row >= self.rows.saturating_add(vertical_offset)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if 0usize.saturating_add(horizontal_offset) > col
|
||||||
|
|| col >= self.cols.saturating_add(horizontal_offset)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_resize(&mut self, area: &Rect) {
|
||||||
self.cells_area = cells_area_helper(area);
|
self.cells_area = cells_area_helper(area);
|
||||||
|
|
||||||
self.cols = (self.cells_area.width / self.cell_width as u16) as usize;
|
self.cols = (self.cells_area.width / self.cell_width as u16) as usize;
|
||||||
@@ -111,7 +183,7 @@ impl BoardState {
|
|||||||
Offset::new(Some(self.vertical_offset.get_value()), Some(v_max_offset));
|
Offset::new(Some(self.vertical_offset.get_value()), Some(v_max_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zoom_change(&mut self, new_zoom_level: ZoomLevel) {
|
pub fn change_zoom(&mut self, new_zoom_level: ZoomLevel) {
|
||||||
self.zoom_level = new_zoom_level;
|
self.zoom_level = new_zoom_level;
|
||||||
|
|
||||||
self.cell_width = cell_size_helper(CellSizes::Width, self.zoom_level);
|
self.cell_width = cell_size_helper(CellSizes::Width, self.zoom_level);
|
||||||
@@ -149,26 +221,9 @@ impl BoardState {
|
|||||||
|
|
||||||
self.get_mut_cell(old_row, old_col).set_selected(false);
|
self.get_mut_cell(old_row, old_col).set_selected(false);
|
||||||
self.get_mut_cell(new_row, new_col).set_selected(true);
|
self.get_mut_cell(new_row, new_col).set_selected(true);
|
||||||
|
|
||||||
|
if self.marking_cells {
|
||||||
|
self.set_marked_cell(new_row, new_col, old_row, old_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_focused_cell_visible(&self) -> bool {
|
|
||||||
let vertical_offset: usize = self.vertical_offset.get_value();
|
|
||||||
let horizontal_offset: usize = self.horizontal_offset.get_value();
|
|
||||||
|
|
||||||
let row: usize = self.focused_cell.get_row();
|
|
||||||
let col: usize = self.focused_cell.get_col();
|
|
||||||
|
|
||||||
if 0usize.saturating_add(vertical_offset) > row
|
|
||||||
|| row >= self.rows.saturating_add(vertical_offset)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if 0usize.saturating_add(horizontal_offset) > col
|
|
||||||
|| col >= self.cols.saturating_add(horizontal_offset)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-12
@@ -25,6 +25,8 @@ const ACTIONS: &[Action] = &[
|
|||||||
Action::ZoomOut,
|
Action::ZoomOut,
|
||||||
Action::VolumeUp,
|
Action::VolumeUp,
|
||||||
Action::VolumeDown,
|
Action::VolumeDown,
|
||||||
|
Action::Space,
|
||||||
|
Action::Backspace,
|
||||||
Action::Mute,
|
Action::Mute,
|
||||||
Action::Quit,
|
Action::Quit,
|
||||||
Action::Quit2,
|
Action::Quit2,
|
||||||
@@ -92,19 +94,16 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
|||||||
horizontal: 1,
|
horizontal: 1,
|
||||||
vertical: 1,
|
vertical: 1,
|
||||||
});
|
});
|
||||||
|
// .centered(
|
||||||
|
// Constraint::Length(
|
||||||
|
// (states.skirmish.board.cell_width * states.skirmish.board.cols) as u16,
|
||||||
|
// ),
|
||||||
|
// Constraint::Length(
|
||||||
|
// (states.skirmish.board.cell_height * states.skirmish.board.rows) as u16,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
|
||||||
// TODO: add actual (effective) board sizes as Constraints
|
BoardWidget::new(&states.skirmish.board).render(cells_area, buf);
|
||||||
BoardWidget::new(&states.skirmish.board).render(
|
|
||||||
cells_area.centered(
|
|
||||||
Constraint::Length(
|
|
||||||
(states.skirmish.board.cell_width * states.skirmish.board.cols) as u16,
|
|
||||||
),
|
|
||||||
Constraint::Length(
|
|
||||||
(states.skirmish.board.cell_height * states.skirmish.board.rows) as u16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ pub struct CellWidget {
|
|||||||
selected: bool,
|
selected: bool,
|
||||||
zoom_level: ZoomLevel,
|
zoom_level: ZoomLevel,
|
||||||
tag: CellTag,
|
tag: CellTag,
|
||||||
|
marked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellWidget {
|
impl CellWidget {
|
||||||
@@ -43,6 +44,7 @@ impl CellWidget {
|
|||||||
selected,
|
selected,
|
||||||
zoom_level,
|
zoom_level,
|
||||||
tag,
|
tag,
|
||||||
|
marked: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +60,14 @@ impl CellWidget {
|
|||||||
self.tag = tag;
|
self.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_marked(&self) -> bool {
|
||||||
|
self.marked
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_marked(&mut self, marked: bool) {
|
||||||
|
self.marked = marked
|
||||||
|
}
|
||||||
|
|
||||||
fn col_to_letters(&self) -> String {
|
fn col_to_letters(&self) -> String {
|
||||||
let mut col: usize = self.col + 1;
|
let mut col: usize = self.col + 1;
|
||||||
let mut letters: Vec<char> = Vec::new();
|
let mut letters: Vec<char> = Vec::new();
|
||||||
@@ -80,6 +90,7 @@ impl CellWidget {
|
|||||||
|
|
||||||
fn fg_color(&self) -> Color {
|
fn fg_color(&self) -> Color {
|
||||||
match self.tag {
|
match self.tag {
|
||||||
|
_ if self.marked => Color::LightMagenta,
|
||||||
_ if self.selected => Color::LightYellow,
|
_ if self.selected => Color::LightYellow,
|
||||||
CellTag::Base(Players::Player) if !self.selected => Color::LightBlue,
|
CellTag::Base(Players::Player) if !self.selected => Color::LightBlue,
|
||||||
CellTag::Base(Players::Enemy) if !self.selected => Color::LightRed,
|
CellTag::Base(Players::Enemy) if !self.selected => Color::LightRed,
|
||||||
|
|||||||
Reference in New Issue
Block a user