Skip to main content

iced_core/widget/operation/
text.rs

1//! Operate on widgets that have text.
2use crate::Point;
3use crate::Vector;
4use crate::text::{Fragment, Target};
5use crate::widget::operation::{Operation, Outcome};
6
7/// The internal state of a widget that has text.
8pub trait Text {
9    /// Returns the text of the widget.
10    fn text(&self) -> Fragment<'_>;
11
12    /// Selects text between the given positions in layout coordinates.
13    ///
14    /// `start` is the position where the user started selecting from,
15    /// while `end` is the final position of the selection.
16    fn select(&mut self, start: Point, end: Point, target: Target);
17
18    /// Selects all the text of the widget.
19    fn select_all(&mut self);
20
21    /// Deselects any selected text;
22    fn deselect(&mut self);
23
24    /// Returns the selected text, if any.
25    ///
26    // TODO: Make immutable
27    fn copy(&mut self) -> Option<String>;
28}
29
30impl Text for String {
31    fn text(&self) -> Fragment<'_> {
32        self.as_str().into()
33    }
34
35    fn select(&mut self, _start: Point, _end: Point, _target: Target) {}
36    fn select_all(&mut self) {}
37    fn deselect(&mut self) {}
38
39    fn copy(&mut self) -> Option<String> {
40        None
41    }
42}
43
44/// Selects text between the given positions in layout coordinates.
45///
46/// `start` is the position where the user started selecting from,
47/// while `end` is the final position of the selection.
48pub fn select(start: Point, end: Point, target: Target) -> impl Operation {
49    struct Select {
50        start: Point,
51        end: Point,
52        target: Target,
53        translation: Vector,
54    }
55
56    impl Operation for Select {
57        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation)) {
58            let translation = self.translation;
59            operate(self);
60            self.translation = translation;
61        }
62
63        fn scrollable(
64            &mut self,
65            _id: Option<&crate::widget::Id>,
66            _bounds: crate::Rectangle,
67            _content: crate::Size,
68            translation: crate::Vector,
69            _state: &mut dyn super::Scrollable,
70        ) {
71            self.translation += translation;
72        }
73
74        fn text(
75            &mut self,
76            _id: Option<&crate::widget::Id>,
77            _bounds: crate::Rectangle,
78            state: &mut dyn Text,
79        ) {
80            state.select(
81                self.start + self.translation,
82                self.end + self.translation,
83                self.target,
84            );
85        }
86    }
87
88    Select {
89        start,
90        end,
91        target,
92        translation: Vector::ZERO,
93    }
94}
95
96/// Selects all selectable text.
97pub fn select_all() -> impl Operation {
98    struct SelectAll;
99
100    impl Operation for SelectAll {
101        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation)) {
102            operate(self);
103        }
104
105        fn text(
106            &mut self,
107            _id: Option<&crate::widget::Id>,
108            _bounds: crate::Rectangle,
109            state: &mut dyn Text,
110        ) {
111            state.select_all();
112        }
113    }
114
115    SelectAll
116}
117
118/// Deselects any selected text.
119pub fn deselect() -> impl Operation {
120    struct Deselect;
121
122    impl Operation for Deselect {
123        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation)) {
124            operate(self);
125        }
126
127        fn text(
128            &mut self,
129            _id: Option<&crate::widget::Id>,
130            _bounds: crate::Rectangle,
131            state: &mut dyn Text,
132        ) {
133            state.deselect();
134        }
135    }
136
137    Deselect
138}
139
140/// Collects all the selected text.
141pub fn copy() -> impl Operation<String> {
142    struct Copy {
143        text: String,
144    }
145
146    impl Operation<String> for Copy {
147        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<String>)) {
148            operate(self);
149        }
150
151        fn text(
152            &mut self,
153            _id: Option<&crate::widget::Id>,
154            _bounds: crate::Rectangle,
155            state: &mut dyn Text,
156        ) {
157            let Some(text) = state.copy() else {
158                return;
159            };
160
161            if text.is_empty() {
162                return;
163            }
164
165            if !self.text.is_empty() {
166                self.text.push('\n');
167            }
168
169            self.text.push_str(&text);
170        }
171
172        fn finish(&self) -> Outcome<String> {
173            Outcome::Some(self.text.clone())
174        }
175    }
176
177    Copy {
178        text: String::new(),
179    }
180}