epaint/text/
cursor.rs

1//! Different types of text cursors, i.e. ways to point into a [`super::Galley`].
2
3/// Character cursor.
4///
5/// The default cursor is zero.
6#[derive(Clone, Copy, Debug, Default)]
7#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
8pub struct CCursor {
9    /// Character offset (NOT byte offset!).
10    pub index: usize,
11
12    /// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
13    /// do we prefer the next row?
14    /// This is *almost* always what you want, *except* for when
15    /// explicitly clicking the end of a row or pressing the end key.
16    pub prefer_next_row: bool,
17}
18
19impl CCursor {
20    #[inline]
21    pub fn new(index: usize) -> Self {
22        Self {
23            index,
24            prefer_next_row: false,
25        }
26    }
27}
28
29/// Two `CCursor`s are considered equal if they refer to the same character boundary,
30/// even if one prefers the start of the next row.
31impl PartialEq for CCursor {
32    #[inline]
33    fn eq(&self, other: &Self) -> bool {
34        self.index == other.index
35    }
36}
37
38impl std::ops::Add<usize> for CCursor {
39    type Output = Self;
40
41    fn add(self, rhs: usize) -> Self::Output {
42        Self {
43            index: self.index.saturating_add(rhs),
44            prefer_next_row: self.prefer_next_row,
45        }
46    }
47}
48
49impl std::ops::Sub<usize> for CCursor {
50    type Output = Self;
51
52    fn sub(self, rhs: usize) -> Self::Output {
53        Self {
54            index: self.index.saturating_sub(rhs),
55            prefer_next_row: self.prefer_next_row,
56        }
57    }
58}
59
60impl std::ops::AddAssign<usize> for CCursor {
61    fn add_assign(&mut self, rhs: usize) {
62        self.index = self.index.saturating_add(rhs);
63    }
64}
65
66impl std::ops::SubAssign<usize> for CCursor {
67    fn sub_assign(&mut self, rhs: usize) {
68        self.index = self.index.saturating_sub(rhs);
69    }
70}
71
72/// Row/column cursor.
73///
74/// This refers to rows and columns in layout terms--text wrapping creates multiple rows.
75#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
76#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
77pub struct LayoutCursor {
78    /// 0 is first row, and so on.
79    /// Note that a single paragraph can span multiple rows.
80    /// (a paragraph is text separated by `\n`).
81    pub row: usize,
82
83    /// Character based (NOT bytes).
84    /// It is fine if this points to something beyond the end of the current row.
85    /// When moving up/down it may again be within the next row.
86    pub column: usize,
87}