egui/widgets/text_edit/
state.rs1use std::sync::Arc;
2
3use epaint::text::cursor::CCursor;
4
5use crate::mutex::Mutex;
6
7use crate::{
8 Context, Id, Vec2,
9 text_selection::{CCursorRange, TextCursorState},
10};
11
12pub type TextEditUndoer = crate::util::undoer::Undoer<(CCursorRange, String)>;
13
14#[derive(Clone, Default)]
36#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
37#[cfg_attr(feature = "serde", serde(default))]
38pub struct TextEditState {
39 pub cursor: TextCursorState,
41
42 #[cfg_attr(feature = "serde", serde(skip))]
44 pub(crate) cursor_purpose: TextEditCursorPurpose,
45
46 #[cfg_attr(feature = "serde", serde(skip))]
48 pub(crate) undoer: Arc<Mutex<TextEditUndoer>>,
49
50 #[cfg_attr(feature = "serde", serde(skip))]
53 pub(crate) text_offset: Vec2,
54
55 #[cfg_attr(feature = "serde", serde(skip))]
58 pub(crate) last_interaction_time: f64,
59}
60
61impl TextEditState {
62 pub fn load(ctx: &Context, id: Id) -> Option<Self> {
63 ctx.data_mut(|d| d.get_persisted(id))
64 }
65
66 pub fn store(self, ctx: &Context, id: Id) {
67 ctx.data_mut(|d| d.insert_persisted(id, self));
68 }
69
70 pub fn undoer(&self) -> TextEditUndoer {
71 self.undoer.lock().clone()
72 }
73
74 #[expect(clippy::needless_pass_by_ref_mut)] pub fn set_undoer(&mut self, undoer: TextEditUndoer) {
76 *self.undoer.lock() = undoer;
77 }
78
79 pub fn clear_undoer(&mut self) {
80 self.set_undoer(TextEditUndoer::default());
81 }
82}
83
84#[derive(Clone, Default)]
85pub(crate) enum TextEditCursorPurpose {
86 #[default]
88 Selection,
89
90 ImeComposition {
93 active_range: Option<core::ops::Range<CCursor>>,
99 },
100}
101
102impl TextEditCursorPurpose {
103 pub(crate) fn is_selection(&self) -> bool {
104 matches!(self, Self::Selection)
105 }
106
107 pub(crate) fn is_ime_composition(&self) -> bool {
108 matches!(self, Self::ImeComposition { .. })
109 }
110}