cosmic-text/src/cursor.rs
2025-01-22 17:00:01 -07:00

156 lines
4.2 KiB
Rust

/// Current cursor location
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct Cursor {
/// Index of [`BufferLine`] in [`Buffer::lines`]
pub line: usize,
/// First-byte-index of glyph at cursor (will insert behind this glyph)
pub index: usize,
/// Whether to associate the cursor with the run before it or the run after it if placed at the
/// boundary between two runs
pub affinity: Affinity,
}
impl Cursor {
/// Create a new cursor
pub const fn new(line: usize, index: usize) -> Self {
Self::new_with_affinity(line, index, Affinity::Before)
}
/// Create a new cursor, specifying the affinity
pub const fn new_with_affinity(line: usize, index: usize, affinity: Affinity) -> Self {
Self {
line,
index,
affinity,
}
}
}
/// Whether to associate cursors placed at a boundary between runs with the run before or after it.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
pub enum Affinity {
#[default]
Before,
After,
}
impl Affinity {
pub fn before(&self) -> bool {
*self == Self::Before
}
pub fn after(&self) -> bool {
*self == Self::After
}
pub fn from_before(before: bool) -> Self {
if before {
Self::Before
} else {
Self::After
}
}
pub fn from_after(after: bool) -> Self {
if after {
Self::After
} else {
Self::Before
}
}
}
/// The position of a cursor within a [`Buffer`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct LayoutCursor {
/// Index of [`BufferLine`] in [`Buffer::lines`]
pub line: usize,
/// Index of [`LayoutLine`] in [`BufferLine::layout`]
pub layout: usize,
/// Index of [`LayoutGlyph`] in [`LayoutLine::glyphs`]
pub glyph: usize,
}
impl LayoutCursor {
/// Create a new [`LayoutCursor`]
pub const fn new(line: usize, layout: usize, glyph: usize) -> Self {
Self {
line,
layout,
glyph,
}
}
}
/// A motion to perform on a [`Cursor`]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Motion {
/// Apply specific [`LayoutCursor`]
LayoutCursor(LayoutCursor),
/// Move cursor to previous character ([`Self::Left`] in LTR, [`Self::Right`] in RTL)
Previous,
/// Move cursor to next character ([`Self::Right`] in LTR, [`Self::Left`] in RTL)
Next,
/// Move cursor left
Left,
/// Move cursor right
Right,
/// Move cursor up
Up,
/// Move cursor down
Down,
/// Move cursor to start of line
Home,
/// Move cursor to start of line, skipping whitespace
SoftHome,
/// Move cursor to end of line
End,
/// Move cursor to start of paragraph
ParagraphStart,
/// Move cursor to end of paragraph
ParagraphEnd,
/// Move cursor up one page
PageUp,
/// Move cursor down one page
PageDown,
/// Move cursor up or down by a number of pixels
Vertical(i32),
/// Move cursor to previous word boundary
PreviousWord,
/// Move cursor to next word boundary
NextWord,
/// Move cursor to next word boundary to the left
LeftWord,
/// Move cursor to next word boundary to the right
RightWord,
/// Move cursor to the start of the document
BufferStart,
/// Move cursor to the end of the document
BufferEnd,
/// Move cursor to specific line
GotoLine(usize),
}
/// Scroll position in [`Buffer`]
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
pub struct Scroll {
/// Index of [`BufferLine`] in [`Buffer::lines`]. This will be adjusted as needed if layout is
/// out of bounds
pub line: usize,
/// Pixel offset from the start of the [`BufferLine`]. This will be adjusted as needed
/// if it is negative or exceeds the height of the [`BufferLine::layout`] lines.
pub vertical: f32,
/// The horizontal position of scroll in fractional pixels
pub horizontal: f32,
}
impl Scroll {
/// Create a new scroll
pub const fn new(line: usize, vertical: f32, horizontal: f32) -> Self {
Self {
line,
vertical,
horizontal,
}
}
}