Skip to main content

gpui/
input.rs

1use crate::{
2    App, Bounds, ClipboardItem, Context, Entity, InputHandler, Pixels, UTF16Selection, Window,
3};
4use std::ops::Range;
5
6/// Implement this trait to allow views to handle textual input when implementing an editor, field, etc.
7///
8/// Once your view implements this trait, you can use it to construct an [`ElementInputHandler<V>`].
9/// This input handler can then be assigned during paint by calling [`Window::handle_input`].
10///
11/// See [`InputHandler`] for details on how to implement each method.
12pub trait EntityInputHandler: 'static + Sized {
13    /// See [`InputHandler::text_for_range`] for details
14    fn text_for_range(
15        &mut self,
16        range: Range<usize>,
17        adjusted_range: &mut Option<Range<usize>>,
18        window: &mut Window,
19        cx: &mut Context<Self>,
20    ) -> Option<String>;
21
22    /// See [`InputHandler::selected_text_range`] for details
23    fn selected_text_range(
24        &mut self,
25        ignore_disabled_input: bool,
26        window: &mut Window,
27        cx: &mut Context<Self>,
28    ) -> Option<UTF16Selection>;
29
30    /// See [`InputHandler::marked_text_range`] for details
31    fn marked_text_range(
32        &self,
33        window: &mut Window,
34        cx: &mut Context<Self>,
35    ) -> Option<Range<usize>>;
36
37    /// See [`InputHandler::unmark_text`] for details
38    fn unmark_text(&mut self, window: &mut Window, cx: &mut Context<Self>);
39
40    /// See [`InputHandler::paste`] for details
41    fn paste(&mut self, item: ClipboardItem, window: &mut Window, cx: &mut Context<Self>) {
42        if let Some(text) = item.text() {
43            self.replace_text_in_range(None, &text, window, cx);
44        }
45    }
46
47    /// See [`InputHandler::replace_text_in_range`] for details
48    fn replace_text_in_range(
49        &mut self,
50        range: Option<Range<usize>>,
51        text: &str,
52        window: &mut Window,
53        cx: &mut Context<Self>,
54    );
55
56    /// See [`InputHandler::replace_and_mark_text_in_range`] for details
57    fn replace_and_mark_text_in_range(
58        &mut self,
59        range: Option<Range<usize>>,
60        new_text: &str,
61        new_selected_range: Option<Range<usize>>,
62        window: &mut Window,
63        cx: &mut Context<Self>,
64    );
65
66    /// See [`InputHandler::bounds_for_range`] for details
67    fn bounds_for_range(
68        &mut self,
69        range_utf16: Range<usize>,
70        element_bounds: Bounds<Pixels>,
71        window: &mut Window,
72        cx: &mut Context<Self>,
73    ) -> Option<Bounds<Pixels>>;
74
75    /// See [`InputHandler::character_index_for_point`] for details
76    fn character_index_for_point(
77        &mut self,
78        point: crate::Point<Pixels>,
79        window: &mut Window,
80        cx: &mut Context<Self>,
81    ) -> Option<usize>;
82
83    /// See [`InputHandler::set_selected_text_range`] for details
84    fn set_selected_text_range(
85        &mut self,
86        _range_utf16: Range<usize>,
87        _window: &mut Window,
88        _cx: &mut Context<Self>,
89    ) {
90    }
91
92    /// See [`InputHandler::text_length_utf16`] for details
93    fn text_length_utf16(
94        &mut self,
95        _window: &mut Window,
96        _cx: &mut Context<Self>,
97    ) -> Option<usize> {
98        None
99    }
100
101    /// See [`InputHandler::accepts_text_input`] for details
102    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
103        true
104    }
105}
106
107/// The canonical implementation of [`crate::PlatformInputHandler`]. Call [`Window::handle_input`]
108/// with an instance during your element's paint.
109pub struct ElementInputHandler<V> {
110    view: Entity<V>,
111    element_bounds: Bounds<Pixels>,
112}
113
114impl<V: 'static> ElementInputHandler<V> {
115    /// Used in [`Element::paint`][element_paint] with the element's bounds, a `Window`, and a `App` context.
116    ///
117    /// [element_paint]: crate::Element::paint
118    pub fn new(element_bounds: Bounds<Pixels>, view: Entity<V>) -> Self {
119        ElementInputHandler {
120            view,
121            element_bounds,
122        }
123    }
124}
125
126impl<V: EntityInputHandler> InputHandler for ElementInputHandler<V> {
127    fn selected_text_range(
128        &mut self,
129        ignore_disabled_input: bool,
130        window: &mut Window,
131        cx: &mut App,
132    ) -> Option<UTF16Selection> {
133        self.view.update(cx, |view, cx| {
134            view.selected_text_range(ignore_disabled_input, window, cx)
135        })
136    }
137
138    fn marked_text_range(&mut self, window: &mut Window, cx: &mut App) -> Option<Range<usize>> {
139        self.view
140            .update(cx, |view, cx| view.marked_text_range(window, cx))
141    }
142
143    fn text_for_range(
144        &mut self,
145        range_utf16: Range<usize>,
146        adjusted_range: &mut Option<Range<usize>>,
147        window: &mut Window,
148        cx: &mut App,
149    ) -> Option<String> {
150        self.view.update(cx, |view, cx| {
151            view.text_for_range(range_utf16, adjusted_range, window, cx)
152        })
153    }
154
155    fn replace_text_in_range(
156        &mut self,
157        replacement_range: Option<Range<usize>>,
158        text: &str,
159        window: &mut Window,
160        cx: &mut App,
161    ) {
162        self.view.update(cx, |view, cx| {
163            view.replace_text_in_range(replacement_range, text, window, cx)
164        });
165    }
166
167    fn replace_and_mark_text_in_range(
168        &mut self,
169        range_utf16: Option<Range<usize>>,
170        new_text: &str,
171        new_selected_range: Option<Range<usize>>,
172        window: &mut Window,
173        cx: &mut App,
174    ) {
175        self.view.update(cx, |view, cx| {
176            view.replace_and_mark_text_in_range(
177                range_utf16,
178                new_text,
179                new_selected_range,
180                window,
181                cx,
182            )
183        });
184    }
185
186    fn unmark_text(&mut self, window: &mut Window, cx: &mut App) {
187        self.view
188            .update(cx, |view, cx| view.unmark_text(window, cx));
189    }
190
191    fn paste(&mut self, item: ClipboardItem, window: &mut Window, cx: &mut App) {
192        self.view
193            .update(cx, |view, cx| view.paste(item, window, cx));
194    }
195
196    fn bounds_for_range(
197        &mut self,
198        range_utf16: Range<usize>,
199        window: &mut Window,
200        cx: &mut App,
201    ) -> Option<Bounds<Pixels>> {
202        self.view.update(cx, |view, cx| {
203            view.bounds_for_range(range_utf16, self.element_bounds, window, cx)
204        })
205    }
206
207    fn character_index_for_point(
208        &mut self,
209        point: crate::Point<Pixels>,
210        window: &mut Window,
211        cx: &mut App,
212    ) -> Option<usize> {
213        self.view.update(cx, |view, cx| {
214            view.character_index_for_point(point, window, cx)
215        })
216    }
217
218    fn set_selected_text_range(
219        &mut self,
220        range_utf16: Range<usize>,
221        window: &mut Window,
222        cx: &mut App,
223    ) {
224        self.view.update(cx, |view, cx| {
225            view.set_selected_text_range(range_utf16, window, cx)
226        })
227    }
228
229    fn element_bounds(&mut self, _window: &mut Window, _cx: &mut App) -> Option<Bounds<Pixels>> {
230        Some(self.element_bounds)
231    }
232
233    fn text_length_utf16(&mut self, window: &mut Window, cx: &mut App) -> Option<usize> {
234        self.view
235            .update(cx, |view, cx| view.text_length_utf16(window, cx))
236    }
237
238    fn accepts_text_input(&mut self, window: &mut Window, cx: &mut App) -> bool {
239        self.view
240            .update(cx, |view, cx| view.accepts_text_input(window, cx))
241    }
242
243    fn prefers_ime_for_printable_keys(&mut self, window: &mut Window, cx: &mut App) -> bool {
244        self.view
245            .update(cx, |view, cx| view.accepts_text_input(window, cx))
246    }
247}