-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
state.rs
85 lines (70 loc) · 3.11 KB
/
state.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
use std::sync::Arc;
use crate::mutex::Mutex;
use crate::*;
use super::{CCursorRange, CursorRange};
type Undoer = crate::util::undoer::Undoer<(CCursorRange, String)>;
/// The text edit state stored between frames.
#[derive(Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct TextEditState {
cursor_range: Option<CursorRange>,
/// This is what is easiest to work with when editing text,
/// so users are more likely to read/write this.
ccursor_range: Option<CCursorRange>,
/// Wrapped in Arc for cheaper clones.
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) undoer: Arc<Mutex<Undoer>>,
// If IME candidate window is shown on this text edit.
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) has_ime: bool,
// Visual offset when editing singleline text bigger than the width.
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) singleline_offset: f32,
}
impl TextEditState {
pub fn load(ctx: &Context, id: Id) -> Option<Self> {
ctx.data().get_persisted(id)
}
pub fn store(self, ctx: &Context, id: Id) {
ctx.data().insert_persisted(id, self);
}
/// The the currently selected range of characters.
pub fn ccursor_range(&self) -> Option<CCursorRange> {
self.ccursor_range.or_else(|| {
self.cursor_range
.map(|cursor_range| cursor_range.as_ccursor_range())
})
}
/// Sets the currently selected range of characters.
pub fn set_ccursor_range(&mut self, ccursor_range: Option<CCursorRange>) {
self.cursor_range = None;
self.ccursor_range = ccursor_range;
}
pub fn set_cursor_range(&mut self, cursor_range: Option<CursorRange>) {
self.cursor_range = cursor_range;
self.ccursor_range = None;
}
pub fn cursor_range(&mut self, galley: &Galley) -> Option<CursorRange> {
self.cursor_range
.map(|cursor_range| {
// We only use the PCursor (paragraph number, and character offset within that paragraph).
// This is so that if we resize the [`TextEdit`] region, and text wrapping changes,
// we keep the same byte character offset from the beginning of the text,
// even though the number of rows changes
// (each paragraph can be several rows, due to word wrapping).
// The column (character offset) should be able to extend beyond the last word so that we can
// go down and still end up on the same column when we return.
CursorRange {
primary: galley.from_pcursor(cursor_range.primary.pcursor),
secondary: galley.from_pcursor(cursor_range.secondary.pcursor),
}
})
.or_else(|| {
self.ccursor_range.map(|ccursor_range| CursorRange {
primary: galley.from_ccursor(ccursor_range.primary),
secondary: galley.from_ccursor(ccursor_range.secondary),
})
})
}
}