Skip to content

Commit f6bdaa2

Browse files
Owen McGirrOwen McGirr
authored andcommitted
Add optional auto selection after point scanning
- Add a cancellable countdown with native scanner-colour feedback and release-to-menu interruption. - Persist desktop auto-select settings and preserve pause, safety controls, drag exclusion and click error recovery. - Cover timing, configuration compatibility, switch holds and countdown drawing with fake input tests. 🤖 Auto-generated
1 parent 1b7b167 commit f6bdaa2

11 files changed

Lines changed: 478 additions & 17 deletions

src-tauri/src/overlay.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,13 @@ pub(crate) fn render_marker(frame: &Frame, scale: f64) -> Pixmap {
474474
pixmap
475475
}
476476

477-
fn draw_dwell_progress(pixmap: &mut Pixmap, center: f32, unit: f32, color: [u8; 3], permille: u16) {
477+
pub(crate) fn draw_dwell_progress(
478+
pixmap: &mut Pixmap,
479+
center: f32,
480+
unit: f32,
481+
color: [u8; 3],
482+
permille: u16,
483+
) {
478484
let radius = unit * 0.29;
479485
let width = (unit * 0.045).max(3.0);
480486
let segments = 64usize;

src-tauri/src/overlay_windows.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ pub(crate) fn present_solid(
229229
present_rgba(window, x, y, width.max(1), height.max(1), &rgba)
230230
}
231231

232-
fn present_rgba(
232+
pub(crate) fn present_rgba(
233233
window: HWND,
234234
x: i32,
235235
y: i32,

src-tauri/src/point_scan.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub struct Config {
2121
pub speed: usize,
2222
pub grid_size: usize,
2323
pub block_interval_ms: u64,
24+
pub auto_select_enabled: bool,
25+
pub auto_select_delay_ms: u64,
2426
pub select_key: String,
2527
pub next_key: String,
2628
pub back_key: String,
@@ -35,6 +37,8 @@ impl Default for Config {
3537
speed: 2,
3638
grid_size: 4,
3739
block_interval_ms: 1000,
40+
auto_select_enabled: false,
41+
auto_select_delay_ms: 1000,
3842
select_key: "Space".into(),
3943
next_key: "Enter".into(),
4044
back_key: "Backspace".into(),
@@ -59,6 +63,8 @@ impl Config {
5963
speed: self.speed,
6064
grid_size: self.grid_size,
6165
block_interval_ms: self.block_interval_ms,
66+
auto_select_enabled: self.auto_select_enabled,
67+
auto_select_delay_ms: self.auto_select_delay_ms,
6268
}
6369
}
6470
pub fn validate(&self) -> Result<(), String> {
@@ -73,12 +79,16 @@ pub struct PointSettings {
7379
pub speed: usize,
7480
pub grid_size: usize,
7581
pub block_interval_ms: u64,
82+
pub auto_select_enabled: bool,
83+
pub auto_select_delay_ms: u64,
7684
}
7785
impl PointSettings {
7886
fn validate(&self) -> Result<(), String> {
7987
if self.speed > 4
8088
|| !(2..=10).contains(&self.grid_size)
8189
|| !(250..=5000).contains(&self.block_interval_ms)
90+
|| !(100..=100_000).contains(&self.auto_select_delay_ms)
91+
|| !self.auto_select_delay_ms.is_multiple_of(100)
8292
{
8393
return Err("Point scan speed, grid size, or interval is invalid.".into());
8494
}
@@ -412,6 +422,7 @@ impl Technique for Engine {
412422
grid,
413423
strips,
414424
tiles: vec![],
425+
countdown: None,
415426
label: (self.phase == Phase::RowEscape).then(|| {
416427
let scale = self.units_per_logical_pixel;
417428
let width = (360.0 * scale).min(self.screen.width);
@@ -471,6 +482,28 @@ mod tests {
471482
})
472483
}
473484
#[test]
485+
fn auto_select_delays_are_bounded_and_round_trip() {
486+
for delay in [100, 500, 1000, 100_000] {
487+
let config = Config {
488+
auto_select_enabled: true,
489+
auto_select_delay_ms: delay,
490+
..Config::default()
491+
};
492+
config.validate().unwrap();
493+
let restored: Config =
494+
serde_json::from_value(serde_json::to_value(&config).unwrap()).unwrap();
495+
assert_eq!(restored, config);
496+
}
497+
for delay in [0, 99, 101, 100_100, u64::MAX] {
498+
assert!(Config {
499+
auto_select_delay_ms: delay,
500+
..Config::default()
501+
}
502+
.validate()
503+
.is_err());
504+
}
505+
}
506+
#[test]
474507
fn grid_highlights_fill_only_the_current_target_then_clear_for_lines() {
475508
for scale in [1.0, 2.0] {
476509
let config = Config {
@@ -835,11 +868,15 @@ mod tests {
835868
assert!(e.technique.x > -1000.0);
836869
}
837870
#[test]
838-
fn existing_flat_settings_round_trip_without_schema_changes() {
871+
fn existing_flat_settings_gain_safe_auto_select_defaults() {
839872
let mut json = serde_json::json!({"mode":"grid","automatic":false,"speed":4,"gridSize":7,"blockIntervalMs":1500,"selectKey":"F1","nextKey":"F2","backKey":"F3","pauseKey":"F4"});
840873
let config: Config = serde_json::from_value(json.clone()).unwrap();
841874
config.validate().unwrap();
842875
assert_eq!(config.scanner_color, crate::scanning::ScannerColor::Blue);
876+
assert!(!config.auto_select_enabled);
877+
assert_eq!(config.auto_select_delay_ms, 1000);
878+
json["autoSelectEnabled"] = serde_json::json!(false);
879+
json["autoSelectDelayMs"] = serde_json::json!(1000);
843880
json["scannerColor"] = serde_json::json!("blue");
844881
assert_eq!(serde_json::to_value(&config).unwrap(), json);
845882
assert!(!config.switches().automatic);

0 commit comments

Comments
 (0)