1use crate::{App, Bounds, Context, Entity, InputHandler, Pixels, UTF16Selection, Window};
2use std::ops::Range;
3
4/// Implement this trait to allow views to handle textual input when implementing an editor, field, etc.
5///
6/// Once your view implements this trait, you can use it to construct an [`ElementInputHandler<V>`].
7/// This input handler can then be assigned during paint by calling [`WindowContext::handle_input`].
8///
9/// See [`InputHandler`] for details on how to implement each method.
10pub trait EntityInputHandler: 'static + Sized {
11 /// See [`InputHandler::text_for_range`] for details
12 fn text_for_range(
13 &mut self,
14 range: Range<usize>,
15 adjusted_range: &mut Option<Range<usize>>,
16 window: &mut Window,
17 cx: &mut Context<Self>,
18 ) -> Option<String>;
19
20 /// See [`InputHandler::selected_text_range`] for details
21 fn selected_text_range(
22 &mut self,
23 ignore_disabled_input: bool,
24 window: &mut Window,
25 cx: &mut Context<Self>,
26 ) -> Option<UTF16Selection>;
27
28 /// See [`InputHandler::marked_text_range`] for details
29 fn marked_text_range(
30 &self,
31 window: &mut Window,
32 cx: &mut Context<Self>,
33 ) -> Option<Range<usize>>;
34
35 /// See [`InputHandler::unmark_text`] for details
36 fn unmark_text(&mut self, window: &mut Window, cx: &mut Context<Self>);
37
38 /// See [`InputHandler::replace_text_in_range`] for details
39 fn replace_text_in_range(
40 &mut self,
41 range: Option<Range<usize>>,
42 text: &str,
43 window: &mut Window,
44 cx: &mut Context<Self>,
45 );
46
47 /// See [`InputHandler::replace_and_mark_text_in_range`] for details
48 fn replace_and_mark_text_in_range(
49 &mut self,
50 range: Option<Range<usize>>,
51 new_text: &str,
52 new_selected_range: Option<Range<usize>>,
53 window: &mut Window,
54 cx: &mut Context<Self>,
55 );
56
57 /// See [`InputHandler::bounds_for_range`] for details
58 fn bounds_for_range(
59 &mut self,
60 range_utf16: Range<usize>,
61 element_bounds: Bounds<Pixels>,
62 window: &mut Window,
63 cx: &mut Context<Self>,
64 ) -> Option<Bounds<Pixels>>;
65}
66
67/// The canonical implementation of [`PlatformInputHandler`]. Call [`WindowContext::handle_input`]
68/// with an instance during your element's paint.
69pub struct ElementInputHandler<V> {
70 view: Entity<V>,
71 element_bounds: Bounds<Pixels>,
72}
73
74impl<V: 'static> ElementInputHandler<V> {
75 /// Used in [`Element::paint`][element_paint] with the element's bounds and a view context for its
76 /// containing view.
77 ///
78 /// [element_paint]: crate::Element::paint
79 pub fn new(element_bounds: Bounds<Pixels>, view: Entity<V>) -> Self {
80 ElementInputHandler {
81 view,
82 element_bounds,
83 }
84 }
85}
86
87impl<V: EntityInputHandler> InputHandler for ElementInputHandler<V> {
88 fn selected_text_range(
89 &mut self,
90 ignore_disabled_input: bool,
91 window: &mut Window,
92 cx: &mut App,
93 ) -> Option<UTF16Selection> {
94 self.view.update(cx, |view, cx| {
95 view.selected_text_range(ignore_disabled_input, window, cx)
96 })
97 }
98
99 fn marked_text_range(&mut self, window: &mut Window, cx: &mut App) -> Option<Range<usize>> {
100 self.view
101 .update(cx, |view, cx| view.marked_text_range(window, cx))
102 }
103
104 fn text_for_range(
105 &mut self,
106 range_utf16: Range<usize>,
107 adjusted_range: &mut Option<Range<usize>>,
108 window: &mut Window,
109 cx: &mut App,
110 ) -> Option<String> {
111 self.view.update(cx, |view, cx| {
112 view.text_for_range(range_utf16, adjusted_range, window, cx)
113 })
114 }
115
116 fn replace_text_in_range(
117 &mut self,
118 replacement_range: Option<Range<usize>>,
119 text: &str,
120 window: &mut Window,
121 cx: &mut App,
122 ) {
123 self.view.update(cx, |view, cx| {
124 view.replace_text_in_range(replacement_range, text, window, cx)
125 });
126 }
127
128 fn replace_and_mark_text_in_range(
129 &mut self,
130 range_utf16: Option<Range<usize>>,
131 new_text: &str,
132 new_selected_range: Option<Range<usize>>,
133 window: &mut Window,
134 cx: &mut App,
135 ) {
136 self.view.update(cx, |view, cx| {
137 view.replace_and_mark_text_in_range(
138 range_utf16,
139 new_text,
140 new_selected_range,
141 window,
142 cx,
143 )
144 });
145 }
146
147 fn unmark_text(&mut self, window: &mut Window, cx: &mut App) {
148 self.view
149 .update(cx, |view, cx| view.unmark_text(window, cx));
150 }
151
152 fn bounds_for_range(
153 &mut self,
154 range_utf16: Range<usize>,
155 window: &mut Window,
156 cx: &mut App,
157 ) -> Option<Bounds<Pixels>> {
158 self.view.update(cx, |view, cx| {
159 view.bounds_for_range(range_utf16, self.element_bounds, window, cx)
160 })
161 }
162}