1use crate::{
2 AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext, WindowContext,
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 `V` implements this trait, you can use it to construct an [`ElementInputHandler<V>`].
9/// This input handler can then be assigned during paint by calling [`WindowContext::handle_input`].
10pub trait InputHandler: 'static + Sized {
11 fn text_for_range(&mut self, range: Range<usize>, cx: &mut ViewContext<Self>)
12 -> Option<String>;
13 fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
14 fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
15 fn unmark_text(&mut self, cx: &mut ViewContext<Self>);
16 fn replace_text_in_range(
17 &mut self,
18 range: Option<Range<usize>>,
19 text: &str,
20 cx: &mut ViewContext<Self>,
21 );
22 fn replace_and_mark_text_in_range(
23 &mut self,
24 range: Option<Range<usize>>,
25 new_text: &str,
26 new_selected_range: Option<Range<usize>>,
27 cx: &mut ViewContext<Self>,
28 );
29 fn bounds_for_range(
30 &mut self,
31 range_utf16: Range<usize>,
32 element_bounds: Bounds<Pixels>,
33 cx: &mut ViewContext<Self>,
34 ) -> Option<Bounds<Pixels>>;
35}
36
37/// The canonical implementation of [`PlatformInputHandler`]. Call [`WindowContext::handle_input`]
38/// with an instance during your element's paint.
39pub struct ElementInputHandler<V> {
40 view: View<V>,
41 element_bounds: Bounds<Pixels>,
42 cx: AsyncWindowContext,
43}
44
45impl<V: 'static> ElementInputHandler<V> {
46 /// Used in [`Element::paint`][element_paint] with the element's bounds and a view context for its
47 /// containing view.
48 ///
49 /// [element_paint]: crate::Element::paint
50 pub fn new(element_bounds: Bounds<Pixels>, view: View<V>, cx: &mut WindowContext) -> Self {
51 ElementInputHandler {
52 view,
53 element_bounds,
54 cx: cx.to_async(),
55 }
56 }
57}
58
59impl<V: InputHandler> PlatformInputHandler for ElementInputHandler<V> {
60 fn selected_text_range(&mut self) -> Option<Range<usize>> {
61 self.view
62 .update(&mut self.cx, |view, cx| view.selected_text_range(cx))
63 .ok()
64 .flatten()
65 }
66
67 fn marked_text_range(&mut self) -> Option<Range<usize>> {
68 self.view
69 .update(&mut self.cx, |view, cx| view.marked_text_range(cx))
70 .ok()
71 .flatten()
72 }
73
74 fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String> {
75 self.view
76 .update(&mut self.cx, |view, cx| {
77 view.text_for_range(range_utf16, cx)
78 })
79 .ok()
80 .flatten()
81 }
82
83 fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str) {
84 self.view
85 .update(&mut self.cx, |view, cx| {
86 view.replace_text_in_range(replacement_range, text, cx)
87 })
88 .ok();
89 }
90
91 fn replace_and_mark_text_in_range(
92 &mut self,
93 range_utf16: Option<Range<usize>>,
94 new_text: &str,
95 new_selected_range: Option<Range<usize>>,
96 ) {
97 self.view
98 .update(&mut self.cx, |view, cx| {
99 view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
100 })
101 .ok();
102 }
103
104 fn unmark_text(&mut self) {
105 self.view
106 .update(&mut self.cx, |view, cx| view.unmark_text(cx))
107 .ok();
108 }
109
110 fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> {
111 self.view
112 .update(&mut self.cx, |view, cx| {
113 view.bounds_for_range(range_utf16, self.element_bounds, cx)
114 })
115 .ok()
116 .flatten()
117 }
118}