diff --git a/src-tauri/src/point_workflow.rs b/src-tauri/src/point_workflow.rs index 4d7974d7..eeefd408 100644 --- a/src-tauri/src/point_workflow.rs +++ b/src-tauri/src/point_workflow.rs @@ -921,14 +921,19 @@ mod tests { session.technique.phase(), Phase::Workflow(WorkflowPhase::Mouse) ); - assert!(session + let selected: Vec<_> = session .technique .mouse .frame(screen, 1.0, Default::default(), false) .tiles - .iter() - .skip(1) - .any(|tile| tile.selected)); + .into_iter() + .filter(|tile| tile.selected) + .map(|tile| tile.text) + .collect(); + assert_eq!( + selected, + ["Left click", "Right click", "Double click", "Start drag"] + ); } #[test] diff --git a/src-tauri/src/scan_keyboard.rs b/src-tauri/src/scan_keyboard.rs index 5efbca00..dfdca2be 100644 --- a/src-tauri/src/scan_keyboard.rs +++ b/src-tauri/src/scan_keyboard.rs @@ -542,6 +542,7 @@ impl Keyboard { weight: Self::weight(key), role: style.role, active: style.active, + blank: false, } }) .collect() diff --git a/src-tauri/src/scan_mouse.rs b/src-tauri/src/scan_mouse.rs index a1eea663..d2a3cd5d 100644 --- a/src-tauri/src/scan_mouse.rs +++ b/src-tauri/src/scan_mouse.rs @@ -53,14 +53,14 @@ impl MousePanel { use Key::*; if !more { vec![ - vec![Move(-1, -1), Move(0, -1), Move(1, -1)], - vec![Move(-1, 0), Click, Move(1, 0)], - vec![Move(-1, 1), Move(0, 1), Move(1, 1)], - vec![RightClick, DoubleClick, Drag], + vec![Click, RightClick, DoubleClick, Drag], + vec![Move(-1, -1), Move(0, -1), Move(1, -1), Scroll(1)], + vec![Move(-1, 0), Move(1, 0)], + vec![Move(-1, 1), Move(0, 1), Move(1, 1), Scroll(-1)], vec![More, Keyboard, Dock, Close], ] } else { - let mut rows = vec![vec![Scroll(1), Scroll(-1)], vec![Speed(-1), Speed(1)]]; + let mut rows = vec![vec![Speed(-1), Speed(1)]]; if displays > 1 { rows.push(vec![ Monitor(-1, 0), @@ -194,11 +194,17 @@ impl MousePanel { .iter() .map(|row| { row.iter() - .map(|&key| PanelKey { - text: self.label(key), - weight: 1.0, - role: Self::role(key), - active: key == Key::Drag && self.dragging, + .flat_map(|&key| { + let tile = PanelKey { + text: self.label(key), + weight: 1.0, + role: Self::role(key), + active: key == Key::Drag && self.dragging, + blank: false, + }; + // Keep ← and → under the diagonal arrows. + let blank = matches!(key, Key::Move(_, 0)).then(PanelKey::blank); + std::iter::once(tile).chain(blank) }) .collect() }) @@ -221,18 +227,27 @@ mod tests { #[test] fn pages_and_monitor_controls_follow_available_displays() { let mut panel = MousePanel::new(Resolved::default(), 1, 100); - assert_eq!(panel.rows[1][1], Key::Click); - assert_eq!(panel.rows[0].len(), 3); + use Key::*; + assert_eq!( + panel.rows, + [ + vec![Click, RightClick, DoubleClick, Drag], + vec![Move(-1, -1), Move(0, -1), Move(1, -1), Scroll(1)], + vec![Move(-1, 0), Move(1, 0)], + vec![Move(-1, 1), Move(0, 1), Move(1, 1), Scroll(-1)], + vec![More, Keyboard, Dock, Close], + ] + ); panel.choose(Key::More); assert!(!panel .rows .iter() .flatten() - .any(|key| matches!(key, Key::Monitor(..)))); + .any(|key| matches!(key, Key::Monitor(..) | Key::Scroll(..)))); panel.set_displays(2); - assert_eq!(panel.rows[2].len(), 4); + assert_eq!(panel.rows[1].len(), 4); panel.choose(Key::Movement); - assert_eq!(panel.rows[1][1], Key::Click); + assert_eq!(panel.rows[0][0], Key::Click); } #[test] @@ -252,6 +267,41 @@ mod tests { .all(|tile| tile.rect.x >= screen.x && tile.rect.y >= screen.y)); } + #[test] + fn horizontal_arrows_align_with_the_diagonals_and_stay_selectable() { + let screen = Rect { + x: 0.0, + y: 0.0, + width: 1920.0, + height: 1080.0, + }; + let mut panel = MousePanel::new(Resolved::default(), 1, 100); + let tile = |frame: &Frame, text: &str| { + frame + .tiles + .iter() + .find(|tile| tile.text == text) + .unwrap() + .rect + }; + let frame = panel.frame(screen, 1.0, ScannerColor::default(), false); + assert_eq!(tile(&frame, "←").x, tile(&frame, "↖").x); + assert_eq!(tile(&frame, "←").width, tile(&frame, "↖").width); + assert_eq!(tile(&frame, "→").x, tile(&frame, "↗").x); + assert_eq!(tile(&frame, "→").width, tile(&frame, "↗").width); + assert_eq!(frame.tiles.len(), 1 + 18 + 1, "spacers draw no tiles"); + + panel.handle(Action::Next); + panel.handle(Action::Next); + panel.handle(Action::Select); + panel.handle(Action::Next); + let frame = panel.frame(screen, 1.0, ScannerColor::default(), false); + let selected: Vec<_> = frame.tiles.iter().filter(|tile| tile.selected).collect(); + assert_eq!(selected.len(), 1); + assert_eq!(selected[0].text, "→"); + assert_eq!(panel.handle(Action::Select), Some(Key::Move(1, 0))); + } + #[test] fn panel_matches_keyboard_geometry_and_reports_its_state() { let screen = Rect { @@ -276,10 +326,9 @@ mod tests { panel.handle(Action::Select); let status = panel.frame(screen, 1.0, color, false).tiles.pop().unwrap(); - assert_eq!(status.text, "Movement · Select ↖"); + assert_eq!(status.text, "Movement · Select Left click"); panel.choose(Key::More); - panel.handle(Action::Next); panel.handle(Action::Select); let status = panel.frame(screen, 1.0, color, false).tiles.pop().unwrap(); assert_eq!(status.text, "More controls · Select Slower 100%"); diff --git a/src-tauri/src/scan_panel.rs b/src-tauri/src/scan_panel.rs index cb30dd8e..46d52e86 100644 --- a/src-tauri/src/scan_panel.rs +++ b/src-tauri/src/scan_panel.rs @@ -11,6 +11,20 @@ pub struct PanelKey { pub weight: f64, pub role: TileRole, pub active: bool, + /// Reserves a cell without drawing it or counting it as a scanner column. + pub blank: bool, +} + +impl PanelKey { + pub fn blank() -> Self { + Self { + text: String::new(), + weight: 1.0, + role: TileRole::Utility, + active: false, + blank: true, + } + } } pub struct Panel { @@ -61,8 +75,13 @@ impl Panel { let total_weight: f64 = row.iter().map(|key| key.weight).sum(); let cell_unit = (width - gap * (row.len() - 1) as f64).max(1.0) / total_weight; let mut left = x; - for (c, key) in row.iter().enumerate() { + let mut c = 0; + for key in row { let key_width = cell_unit * key.weight; + if key.blank { + left += key_width + gap; + continue; + } frame.tiles.push(FrameTile { thickness: self.thickness, color, @@ -85,6 +104,7 @@ impl Panel { }), }); left += key_width + gap; + c += 1; } } frame.tiles.push(FrameTile { @@ -130,6 +150,7 @@ mod tests { weight, role: TileRole::Utility, active: false, + blank: false, } }