use std::{cmp::{self},
fmt::{Debug, Display}};
use serde::{Deserialize, Serialize};
use crate::{ChUnit, Position};
#[derive(Default, Clone, PartialEq, Serialize, Deserialize, Copy, size_of::SizeOf)]
pub struct SelectionRange {
pub start_display_col_index: ChUnit,
pub end_display_col_index: ChUnit,
}
#[derive(Clone, PartialEq, Serialize, Deserialize, Copy, Debug)]
pub enum ScrollOffsetColLocationInRange {
Overflow,
Underflow,
}
impl SelectionRange {
pub fn locate_scroll_offset_col(
&self,
scroll_offset: Position,
) -> ScrollOffsetColLocationInRange {
if self.start_display_col_index >= scroll_offset.col_index {
ScrollOffsetColLocationInRange::Underflow
} else {
ScrollOffsetColLocationInRange::Overflow
}
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize, Copy, Debug)]
pub enum CaretLocationInRange {
Overflow,
Underflow,
Contained,
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Debug, size_of::SizeOf)]
pub enum CaretMovementDirection {
Up,
Down,
Left,
Right,
Overlap,
}
#[cfg(test)]
mod tests_range {
use super::*;
use crate::{assert_eq2, ch};
#[test]
fn test_locate() {
let range = {
let start = ch!(1);
let end = ch!(4);
SelectionRange::new(start, end)
};
assert_eq2!(range.locate_column(ch!(0)), CaretLocationInRange::Underflow);
assert_eq2!(range.locate_column(ch!(1)), CaretLocationInRange::Contained);
assert_eq2!(range.locate_column(ch!(2)), CaretLocationInRange::Contained);
assert_eq2!(range.locate_column(ch!(3)), CaretLocationInRange::Contained);
assert_eq2!(range.locate_column(ch!(4)), CaretLocationInRange::Overflow);
assert_eq2!(range.locate_column(ch!(5)), CaretLocationInRange::Overflow);
}
}
impl SelectionRange {
pub fn caret_movement_direction(
previous_caret_display_position: Position,
current_caret_display_position: Position,
) -> CaretMovementDirection {
let previous_caret_display_row_index = previous_caret_display_position.row_index;
let current_caret_display_row_index = current_caret_display_position.row_index;
let previous_caret_display_col_index = previous_caret_display_position.col_index;
let current_caret_display_col_index = current_caret_display_position.col_index;
if previous_caret_display_row_index == current_caret_display_row_index {
Self::caret_movement_direction_left_right(
previous_caret_display_col_index,
current_caret_display_col_index,
)
} else {
Self::caret_movement_direction_up_down(
previous_caret_display_row_index,
current_caret_display_row_index,
)
}
}
pub fn caret_movement_direction_up_down(
previous_caret_display_row_index: ChUnit,
current_caret_display_row_index: ChUnit,
) -> CaretMovementDirection {
match current_caret_display_row_index.cmp(&previous_caret_display_row_index) {
cmp::Ordering::Greater => CaretMovementDirection::Down,
cmp::Ordering::Less => CaretMovementDirection::Up,
cmp::Ordering::Equal => CaretMovementDirection::Overlap,
}
}
pub fn caret_movement_direction_left_right(
previous_caret_display_col_index: ChUnit,
current_caret_display_col_index: ChUnit,
) -> CaretMovementDirection {
match current_caret_display_col_index.cmp(&previous_caret_display_col_index) {
cmp::Ordering::Greater => CaretMovementDirection::Right,
cmp::Ordering::Less => CaretMovementDirection::Left,
cmp::Ordering::Equal => CaretMovementDirection::Overlap,
}
}
pub fn locate_column(&self, caret_display_col_index: ChUnit) -> CaretLocationInRange {
if caret_display_col_index < self.start_display_col_index {
CaretLocationInRange::Underflow
} else if caret_display_col_index >= self.end_display_col_index {
CaretLocationInRange::Overflow
} else {
CaretLocationInRange::Contained
}
}
pub fn new(start_display_col_index: ChUnit, end_display_col_index: ChUnit) -> Self {
Self {
start_display_col_index,
end_display_col_index,
}
}
pub fn grow_end_by(&self, amount: ChUnit) -> Self {
let mut copy = *self;
copy.end_display_col_index += amount;
copy
}
pub fn shrink_end_by(&self, amount: ChUnit) -> Self {
let mut copy = *self;
copy.end_display_col_index -= amount;
copy
}
pub fn grow_start_by(&self, amount: ChUnit) -> Self {
let mut copy = *self;
copy.start_display_col_index -= amount;
copy
}
pub fn shrink_start_by(&self, amount: ChUnit) -> Self {
let mut copy = *self;
copy.start_display_col_index += amount;
copy
}
}
mod range_impl_debug_format {
use super::*;
pub fn debug_format(
range: &SelectionRange,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(
f,
"[start_display_col_index: {0}, end_display_col_index: {1}]",
range.start_display_col_index,
range.end_display_col_index
)
}
impl Display for SelectionRange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
debug_format(self, f)
}
}
impl Debug for SelectionRange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
debug_format(self, f)
}
}
}