use std::ops::RangeInclusive; use crate::model::{MAX_BANKS, MAX_PATTERNS}; #[derive(Clone, Copy, PartialEq, Eq, Default)] pub enum PatternsColumn { #[default] Banks, Patterns, } #[derive(Clone, Copy, Default)] pub struct PatternsNav { pub column: PatternsColumn, pub bank_cursor: usize, pub pattern_cursor: usize, pub bank_anchor: Option, pub pattern_anchor: Option, } impl PatternsNav { pub fn move_left(&mut self) { self.clear_selection(); self.column = PatternsColumn::Banks; } pub fn move_right(&mut self) { self.clear_selection(); self.column = PatternsColumn::Patterns; } pub fn move_up(&mut self) { match self.column { PatternsColumn::Banks => { self.bank_cursor = (self.bank_cursor + MAX_BANKS - 1) % MAX_BANKS; } PatternsColumn::Patterns => { self.pattern_cursor = (self.pattern_cursor + MAX_PATTERNS - 1) % MAX_PATTERNS; } } } pub fn move_down(&mut self) { match self.column { PatternsColumn::Banks => { self.bank_cursor = (self.bank_cursor + 1) % MAX_BANKS; } PatternsColumn::Patterns => { self.pattern_cursor = (self.pattern_cursor + 1) % MAX_PATTERNS; } } } pub fn move_up_clamped(&mut self) { match self.column { PatternsColumn::Banks => { self.bank_cursor = self.bank_cursor.saturating_sub(1); } PatternsColumn::Patterns => { self.pattern_cursor = self.pattern_cursor.saturating_sub(1); } } } pub fn move_down_clamped(&mut self) { match self.column { PatternsColumn::Banks => { self.bank_cursor = (self.bank_cursor + 1).min(MAX_BANKS - 1); } PatternsColumn::Patterns => { self.pattern_cursor = (self.pattern_cursor + 1).min(MAX_PATTERNS - 1); } } } pub fn selected_bank(&self) -> usize { self.bank_cursor } pub fn selected_pattern(&self) -> usize { self.pattern_cursor } pub fn bank_selection_range(&self) -> Option> { let anchor = self.bank_anchor?; let a = anchor.min(self.bank_cursor); let b = anchor.max(self.bank_cursor); Some(a..=b) } pub fn pattern_selection_range(&self) -> Option> { let anchor = self.pattern_anchor?; let a = anchor.min(self.pattern_cursor); let b = anchor.max(self.pattern_cursor); Some(a..=b) } pub fn selected_banks(&self) -> Vec { match self.bank_selection_range() { Some(range) => range.collect(), None => vec![self.bank_cursor], } } pub fn selected_patterns(&self) -> Vec { match self.pattern_selection_range() { Some(range) => range.collect(), None => vec![self.pattern_cursor], } } pub fn clear_selection(&mut self) { self.bank_anchor = None; self.pattern_anchor = None; } pub fn has_selection(&self) -> bool { match self.column { PatternsColumn::Banks => self.bank_anchor.is_some(), PatternsColumn::Patterns => self.pattern_anchor.is_some(), } } }