epaint/text/
cursor.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Different types of text cursors, i.e. ways to point into a [`super::Galley`].

/// Character cursor.
///
/// The default cursor is zero.
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct CCursor {
    /// Character offset (NOT byte offset!).
    pub index: usize,

    /// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
    /// do we prefer the next row?
    /// This is *almost* always what you want, *except* for when
    /// explicitly clicking the end of a row or pressing the end key.
    pub prefer_next_row: bool,
}

impl CCursor {
    #[inline]
    pub fn new(index: usize) -> Self {
        Self {
            index,
            prefer_next_row: false,
        }
    }
}

impl From<Cursor> for CCursor {
    #[inline]
    fn from(c: Cursor) -> Self {
        c.ccursor
    }
}

/// Two `CCursor`s are considered equal if they refer to the same character boundary,
/// even if one prefers the start of the next row.
impl PartialEq for CCursor {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.index == other.index
    }
}

impl std::ops::Add<usize> for CCursor {
    type Output = Self;

    fn add(self, rhs: usize) -> Self::Output {
        Self {
            index: self.index.saturating_add(rhs),
            prefer_next_row: self.prefer_next_row,
        }
    }
}

impl std::ops::Sub<usize> for CCursor {
    type Output = Self;

    fn sub(self, rhs: usize) -> Self::Output {
        Self {
            index: self.index.saturating_sub(rhs),
            prefer_next_row: self.prefer_next_row,
        }
    }
}

impl std::ops::AddAssign<usize> for CCursor {
    fn add_assign(&mut self, rhs: usize) {
        self.index = self.index.saturating_add(rhs);
    }
}

impl std::ops::SubAssign<usize> for CCursor {
    fn sub_assign(&mut self, rhs: usize) {
        self.index = self.index.saturating_sub(rhs);
    }
}

/// Row Cursor
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct RCursor {
    /// 0 is first row, and so on.
    /// Note that a single paragraph can span multiple rows.
    /// (a paragraph is text separated by `\n`).
    pub row: usize,

    /// Character based (NOT bytes).
    /// It is fine if this points to something beyond the end of the current row.
    /// When moving up/down it may again be within the next row.
    pub column: usize,
}

/// Paragraph Cursor
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct PCursor {
    /// 0 is first paragraph, and so on.
    /// Note that a single paragraph can span multiple rows.
    /// (a paragraph is text separated by `\n`).
    pub paragraph: usize,

    /// Character based (NOT bytes).
    /// It is fine if this points to something beyond the end of the current paragraph.
    /// When moving up/down it may again be within the next paragraph.
    pub offset: usize,

    /// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
    /// do we prefer the next row?
    /// This is *almost* always what you want, *except* for when
    /// explicitly clicking the end of a row or pressing the end key.
    pub prefer_next_row: bool,
}

/// Two `PCursor`s are considered equal if they refer to the same character boundary,
/// even if one prefers the start of the next row.
impl PartialEq for PCursor {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.paragraph == other.paragraph && self.offset == other.offset
    }
}

/// All different types of cursors together.
///
/// They all point to the same place, but in their own different ways.
/// pcursor/rcursor can also point to after the end of the paragraph/row.
/// Does not implement `PartialEq` because you must think which cursor should be equivalent.
///
/// The default cursor is the zero-cursor, to the first character.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Cursor {
    pub ccursor: CCursor,
    pub rcursor: RCursor,
    pub pcursor: PCursor,
}