Skip to main content

ui/input/
ime.rs

1use super::*;
2
3impl EntityInputHandler for TextField {
4    fn text_for_range(
5        &mut self,
6        range_utf16: Range<usize>,
7        actual_range: &mut Option<Range<usize>>,
8        _window: &mut Window,
9        _cx: &mut Context<Self>,
10    ) -> Option<String> {
11        let range = self.range_from_utf16(&range_utf16);
12        actual_range.replace(self.range_to_utf16(&range));
13        Some(self.content[range].to_string())
14    }
15
16    fn selected_text_range(
17        &mut self,
18        _ignore_disabled_input: bool,
19        _window: &mut Window,
20        _cx: &mut Context<Self>,
21    ) -> Option<UTF16Selection> {
22        Some(UTF16Selection {
23            range: self.range_to_utf16(&self.selected_range),
24            reversed: self.selection_reversed,
25        })
26    }
27
28    fn marked_text_range(
29        &self,
30        _window: &mut Window,
31        _cx: &mut Context<Self>,
32    ) -> Option<Range<usize>> {
33        self.marked_range
34            .as_ref()
35            .map(|range| self.range_to_utf16(range))
36    }
37
38    fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
39        self.marked_range = None;
40    }
41
42    fn replace_text_in_range(
43        &mut self,
44        range_utf16: Option<Range<usize>>,
45        new_text: &str,
46        _: &mut Window,
47        cx: &mut Context<Self>,
48    ) {
49        let range = range_utf16
50            .as_ref()
51            .map(|range_utf16| self.range_from_utf16(range_utf16))
52            .or(self.marked_range.clone())
53            .unwrap_or(self.selected_range.clone());
54
55        // Every edit lands here — typing, deleting, cut, paste, and the IME
56        // *committing*. Not `replace_and_mark_text_in_range`, which is the
57        // composing path: provisional text must not become undo steps, or every
58        // keystroke of Chinese input would be one.
59        let kind = if new_text.is_empty() {
60            EditKind::Delete
61        } else {
62            EditKind::Insert
63        };
64        // A delete grows leftwards, so its group continues at the range's end;
65        // an insert continues at its start.
66        self.push_undo(
67            kind,
68            if new_text.is_empty() {
69                range.end
70            } else {
71                range.start
72            },
73        );
74
75        // Cased here rather than on the way out: the caret is placed from this
76        // string's length, and a case that changes it (`ß` uppercases to two
77        // bytes) would leave the caret off by the difference.
78        let new_text = self.case.apply(new_text);
79        self.content =
80            (self.content[0..range.start].to_owned() + &new_text + &self.content[range.end..])
81                .into();
82        self.selected_range = range.start + new_text.len()..range.start + new_text.len();
83        self.marked_range.take();
84        self.last_edit = Some((kind, self.selected_range.end));
85        self.caret_moved();
86        cx.emit(FieldEvent::Changed);
87        cx.notify();
88    }
89
90    fn replace_and_mark_text_in_range(
91        &mut self,
92        range_utf16: Option<Range<usize>>,
93        new_text: &str,
94        new_selected_range_utf16: Option<Range<usize>>,
95        _window: &mut Window,
96        cx: &mut Context<Self>,
97    ) {
98        let range = range_utf16
99            .as_ref()
100            .map(|range_utf16| self.range_from_utf16(range_utf16))
101            .or(self.marked_range.clone())
102            .unwrap_or(self.selected_range.clone());
103
104        // The composing text is cased too, so what an IME is showing is what
105        // committing it will leave behind.
106        let new_text = self.case.apply(new_text);
107        self.content =
108            (self.content[0..range.start].to_owned() + &new_text + &self.content[range.end..])
109                .into();
110        self.marked_range =
111            (!new_text.is_empty()).then(|| range.start..range.start + new_text.len());
112        self.selected_range =
113            composition_selection(&new_text, range.start, new_selected_range_utf16);
114        self.selection_reversed = false;
115
116        self.caret_moved();
117        cx.emit(FieldEvent::Changed);
118        cx.notify();
119    }
120
121    fn bounds_for_range(
122        &mut self,
123        range_utf16: Range<usize>,
124        bounds: Bounds<Pixels>,
125        _window: &mut Window,
126        _cx: &mut Context<Self>,
127    ) -> Option<Bounds<Pixels>> {
128        let range = self.range_from_utf16(&range_utf16);
129        // The IME panel anchors under the composing text, so this has to be the
130        // row that text is on, not the whole field. `bounds` is what
131        // `last_bounds` is set from, so this is the same origin
132        // [`TextField::offset_bounds`] measures from.
133        self.row_bounds(bounds.origin - self.scroll, range, self.line_height())
134    }
135
136    fn character_index_for_point(
137        &mut self,
138        point: Point<Pixels>,
139        _window: &mut Window,
140        _cx: &mut Context<Self>,
141    ) -> Option<usize> {
142        self.last_bounds?.localize(&point)?;
143        let origin = self.text_origin()?;
144        let offset = offset_for_position(&self.last_layout, point - origin, self.line_height());
145        Some(self.offset_to_utf16(offset))
146    }
147}