use crate::crosswords::pos::Column;
use crate::crosswords::pos::Line;
use crate::crosswords::pos::Side;
use crate::event::ClickState;
use rio_backend::crosswords::pos::Pos;
use rio_window::event::ElementState;
use rio_window::event::MouseButton;
use std::time::Instant;
#[derive(Default, Debug)]
pub struct AccumulatedScroll {
pub x: f64,
pub y: f64,
}
#[derive(Debug)]
pub struct Mouse {
pub multiplier: f64,
pub divider: f64,
pub left_button_state: ElementState,
pub middle_button_state: ElementState,
pub right_button_state: ElementState,
pub last_click_timestamp: Instant,
pub last_click_button: MouseButton,
pub click_state: ClickState,
pub accumulated_scroll: AccumulatedScroll,
pub square_side: Side,
pub inside_text_area: bool,
pub x: usize,
pub y: usize,
pub on_border: bool,
pub raw_y: f64,
}
impl Default for Mouse {
fn default() -> Mouse {
Mouse {
multiplier: 3.0,
divider: 1.0,
last_click_timestamp: Instant::now(),
last_click_button: MouseButton::Left,
left_button_state: ElementState::Released,
middle_button_state: ElementState::Released,
right_button_state: ElementState::Released,
click_state: ClickState::None,
square_side: Side::Left,
inside_text_area: Default::default(),
on_border: false,
accumulated_scroll: AccumulatedScroll::default(),
x: Default::default(),
y: Default::default(),
raw_y: 0.0,
}
}
}
impl Mouse {
pub fn new(multiplier: f64, divider: f64) -> Self {
Self {
multiplier,
divider,
..Default::default()
}
}
#[inline]
pub fn set_multiplier_and_divider(&mut self, multiplier: f64, divider: f64) {
self.multiplier = multiplier;
self.divider = divider;
}
}
#[inline]
pub fn calculate_mouse_position(
mouse: &Mouse,
display_offset: usize,
columns_rows: (usize, usize),
margin_x_left: f32,
margin_y_top: f32,
cell_dimension: (f32, f32),
) -> Pos {
if cell_dimension.0 == 0.0 || cell_dimension.1 == 0.0 {
return Pos::default();
}
let cell_width = cell_dimension.0;
let cell_height = cell_dimension.1;
let margin_x = margin_x_left as usize;
let margin_y = margin_y_top as usize;
let col = if (margin_x + cell_width as usize) > mouse.x {
Column(0)
} else {
let col = ((mouse.x - margin_x) as f32 / cell_width) as usize;
std::cmp::min(Column(col), Column(columns_rows.0 - 1))
};
let row = mouse.y.saturating_sub(margin_y) as f32 / cell_height;
let calc_row = std::cmp::min(row as usize, columns_rows.1 - 1);
let row = Line(calc_row as i32) - (display_offset);
Pos::new(row, col)
}
#[inline]
pub fn calculate_side_by_pos(
x: usize,
margin_x: f32,
cell_width: f32,
grid_width: f32,
) -> Side {
let x_in_grid = (x as f32 - margin_x).max(0.0);
let cell_x = x_in_grid % cell_width;
let threshold = cell_width * 0.6;
let additional_padding = (grid_width - margin_x) % cell_width;
let end_of_grid = grid_width - margin_x - additional_padding;
if cell_x >= threshold || x as f32 >= end_of_grid {
Side::Right
} else {
Side::Left
}
}
#[cfg(test)]
pub mod test {
use super::*;
#[test]
fn test_pos_calc_moving_mouse_x_with_scale_1() {
let display_offset = 0;
let columns = 10;
let lines = 5;
let margin_x_left = 0.0;
let margin_y_top = 0.0;
let cell_dimension_width = 9.4;
let cell_dimension_height = 18.0;
let mouse = Mouse {
x: 8,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 9,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 10,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 17,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 19,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(2)));
}
#[test]
fn test_pos_calc_moving_mouse_x_with_scale_2() {
let display_offset = 0;
let columns = 10;
let lines = 5;
let margin_x_left = 0.0; let margin_y_top = 0.0;
let cell_dimension_width = 9.4;
let cell_dimension_height = 18.0;
let mouse = Mouse {
x: 8,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 9,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 10,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 17,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 19,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(2)));
}
#[test]
fn test_pos_calc_moving_mouse_x_with_scale_1_with_margin_10() {
let display_offset = 0;
let columns = 10;
let lines = 5;
let margin_x_left = 10.0; let margin_y_top = 0.0;
let cell_dimension_width = 9.4;
let cell_dimension_height = 18.0;
let mouse = Mouse {
x: 8,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 9,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 18,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 20,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 28,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 29,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(2)));
let mouse = Mouse {
x: 38,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(2)));
let mouse = Mouse {
x: 39,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(3)));
}
#[test]
fn test_pos_calc_moving_mouse_x_with_scale_2_with_margin_10() {
let display_offset = 0;
let columns = 10;
let lines = 5;
let margin_x_left = 20.0; let margin_y_top = 0.0;
let cell_dimension_width = 9.4;
let cell_dimension_height = 18.0;
let mouse = Mouse {
x: 9,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 28,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 30,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
}
#[test]
fn test_row_not_double_scaled() {
let display_offset = 0;
let columns = 96;
let lines = 27;
let margin_x_left = 4.0; let margin_y_top = 72.0; let cell_w = 16.41;
let cell_h = 33.0;
let mouse = Mouse {
x: 100,
y: 280,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_w, cell_h),
);
assert_eq!(pos.row, Line(6));
let mouse = Mouse {
x: 100,
y: 820,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_w, cell_h),
);
assert_eq!(pos.row, Line(22));
}
#[test]
fn test_col_not_double_scaled() {
let display_offset = 0;
let columns = 96;
let lines = 27;
let margin_x_left = 20.0; let margin_y_top = 72.0;
let cell_w = 16.41;
let cell_h = 33.0;
let mouse = Mouse {
x: 70,
y: 200,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_w, cell_h),
);
assert_eq!(pos.col, Column(3));
}
#[test]
fn test_pos_calc_font_size_12_6_moving_mouse_x_with_scale_1_with_margin_10() {
let display_offset = 0;
let columns = 10;
let lines = 5;
let margin_x_left = 10.0;
let margin_y_top = 0.0;
let cell_dimension_width = 12.6;
let cell_dimension_height = 18.0;
let mouse = Mouse {
x: 10,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 22,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(0)));
let mouse = Mouse {
x: 23,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 35,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(1)));
let mouse = Mouse {
x: 36,
..Default::default()
};
let pos = calculate_mouse_position(
&mouse,
display_offset,
(columns, lines),
margin_x_left,
margin_y_top,
(cell_dimension_width, cell_dimension_height),
);
assert_eq!(pos, Pos::new(Line(0), Column(2)));
}
#[test]
fn test_side_by_pos_float_precision() {
let cell_width = 16.41_f32;
let margin_x = 8.0; let grid_width = 8.0 + 96.0 * cell_width;
assert_eq!(
calculate_side_by_pos(16, margin_x, cell_width, grid_width),
Side::Left,
);
assert_eq!(
calculate_side_by_pos(17, margin_x, cell_width, grid_width),
Side::Left,
);
assert_eq!(
calculate_side_by_pos(18, margin_x, cell_width, grid_width),
Side::Right,
);
}
#[test]
fn test_side_by_pos_no_drift_at_high_columns() {
let cell_width = 16.41_f32;
let margin_x = 8.0;
let grid_width = 8.0 + 96.0 * cell_width;
assert_eq!(
calculate_side_by_pos(1256, margin_x, cell_width, grid_width),
Side::Left,
);
assert_eq!(
calculate_side_by_pos(1266, margin_x, cell_width, grid_width),
Side::Right,
);
}
#[test]
fn test_side_by_pos_prescaled_margin() {
let cell_width = 16.0;
let margin_x = 40.0; let grid_width = 40.0 + 80.0 * 16.0;
assert_eq!(
calculate_side_by_pos(41, margin_x, cell_width, grid_width),
Side::Left,
);
assert_eq!(
calculate_side_by_pos(50, margin_x, cell_width, grid_width),
Side::Right,
);
assert_eq!(
calculate_side_by_pos(49, margin_x, cell_width, grid_width),
Side::Left,
);
assert_eq!(
calculate_side_by_pos(30, margin_x, cell_width, grid_width),
Side::Left,
);
}
}