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