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] with the element's bounds and a view context for its
47 /// containing view.
48 pub fn new(element_bounds: Bounds<Pixels>, view: View<V>, cx: &mut WindowContext) -> Self {
49 ElementInputHandler {
50 view,
51 element_bounds,
52 cx: cx.to_async(),
53 }
54 }
55}
56
57impl<V: InputHandler> PlatformInputHandler for ElementInputHandler<V> {
58 fn selected_text_range(&mut self) -> Option<Range<usize>> {
59 self.view
60 .update(&mut self.cx, |view, cx| view.selected_text_range(cx))
61 .ok()
62 .flatten()
63 }
64
65 fn marked_text_range(&mut self) -> Option<Range<usize>> {
66 self.view
67 .update(&mut self.cx, |view, cx| view.marked_text_range(cx))
68 .ok()
69 .flatten()
70 }
71
72 fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String> {
73 self.view
74 .update(&mut self.cx, |view, cx| {
75 view.text_for_range(range_utf16, cx)
76 })
77 .ok()
78 .flatten()
79 }
80
81 fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str) {
82 self.view
83 .update(&mut self.cx, |view, cx| {
84 view.replace_text_in_range(replacement_range, text, cx)
85 })
86 .ok();
87 }
88
89 fn replace_and_mark_text_in_range(
90 &mut self,
91 range_utf16: Option<Range<usize>>,
92 new_text: &str,
93 new_selected_range: Option<Range<usize>>,
94 ) {
95 self.view
96 .update(&mut self.cx, |view, cx| {
97 view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
98 })
99 .ok();
100 }
101
102 fn unmark_text(&mut self) {
103 self.view
104 .update(&mut self.cx, |view, cx| view.unmark_text(cx))
105 .ok();
106 }
107
108 fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> {
109 self.view
110 .update(&mut self.cx, |view, cx| {
111 view.bounds_for_range(range_utf16, self.element_bounds, cx)
112 })
113 .ok()
114 .flatten()
115 }
116}