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}