input.rs

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