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
29impl From<Cursor> for CCursor {
30    #[inline]
31    fn from(c: Cursor) -> Self {
32        c.ccursor
33    }
34}
35
36/// Two `CCursor`s are considered equal if they refer to the same character boundary,
37/// even if one prefers the start of the next row.
38impl PartialEq for CCursor {
39    #[inline]
40    fn eq(&self, other: &Self) -> bool {
41        self.index == other.index
42    }
43}
44
45impl std::ops::Add<usize> for CCursor {
46    type Output = Self;
47
48    fn add(self, rhs: usize) -> Self::Output {
49        Self {
50            index: self.index.saturating_add(rhs),
51            prefer_next_row: self.prefer_next_row,
52        }
53    }
54}
55
56impl std::ops::Sub<usize> for CCursor {
57    type Output = Self;
58
59    fn sub(self, rhs: usize) -> Self::Output {
60        Self {
61            index: self.index.saturating_sub(rhs),
62            prefer_next_row: self.prefer_next_row,
63        }
64    }
65}
66
67impl std::ops::AddAssign<usize> for CCursor {
68    fn add_assign(&mut self, rhs: usize) {
69        self.index = self.index.saturating_add(rhs);
70    }
71}
72
73impl std::ops::SubAssign<usize> for CCursor {
74    fn sub_assign(&mut self, rhs: usize) {
75        self.index = self.index.saturating_sub(rhs);
76    }
77}
78
79/// Row Cursor
80#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
81#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
82pub struct RCursor {
83    /// 0 is first row, and so on.
84    /// Note that a single paragraph can span multiple rows.
85    /// (a paragraph is text separated by `\n`).
86    pub row: usize,
87
88    /// Character based (NOT bytes).
89    /// It is fine if this points to something beyond the end of the current row.
90    /// When moving up/down it may again be within the next row.
91    pub column: usize,
92}
93
94/// Paragraph Cursor
95#[derive(Clone, Copy, Debug, Default)]
96#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
97pub struct PCursor {
98    /// 0 is first paragraph, and so on.
99    /// Note that a single paragraph can span multiple rows.
100    /// (a paragraph is text separated by `\n`).
101    pub paragraph: usize,
102
103    /// Character based (NOT bytes).
104    /// It is fine if this points to something beyond the end of the current paragraph.
105    /// When moving up/down it may again be within the next paragraph.
106    pub offset: usize,
107
108    /// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
109    /// do we prefer the next row?
110    /// This is *almost* always what you want, *except* for when
111    /// explicitly clicking the end of a row or pressing the end key.
112    pub prefer_next_row: bool,
113}
114
115/// Two `PCursor`s are considered equal if they refer to the same character boundary,
116/// even if one prefers the start of the next row.
117impl PartialEq for PCursor {
118    #[inline]
119    fn eq(&self, other: &Self) -> bool {
120        self.paragraph == other.paragraph && self.offset == other.offset
121    }
122}
123
124/// All different types of cursors together.
125///
126/// They all point to the same place, but in their own different ways.
127/// pcursor/rcursor can also point to after the end of the paragraph/row.
128/// Does not implement `PartialEq` because you must think which cursor should be equivalent.
129///
130/// The default cursor is the zero-cursor, to the first character.
131#[derive(Clone, Copy, Debug, Default, PartialEq)]
132#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
133pub struct Cursor {
134    pub ccursor: CCursor,
135    pub rcursor: RCursor,
136    pub pcursor: PCursor,
137}