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        self.edited(
87            Edit {
88                start: range.start,
89                old_end: range.end,
90                new_end: range.start + new_text.len(),
91            },
92            cx,
93        );
94        cx.notify();
95    }
96
97    fn replace_and_mark_text_in_range(
98        &mut self,
99        range_utf16: Option<Range<usize>>,
100        new_text: &str,
101        new_selected_range_utf16: Option<Range<usize>>,
102        _window: &mut Window,
103        cx: &mut Context<Self>,
104    ) {
105        let range = range_utf16
106            .as_ref()
107            .map(|range_utf16| self.range_from_utf16(range_utf16))
108            .or(self.marked_range.clone())
109            .unwrap_or(self.selected_range.clone());
110
111        // The composing text is cased too, so what an IME is showing is what
112        // committing it will leave behind.
113        let new_text = self.case.apply(new_text);
114        self.content =
115            (self.content[0..range.start].to_owned() + &new_text + &self.content[range.end..])
116                .into();
117        self.marked_range =
118            (!new_text.is_empty()).then(|| range.start..range.start + new_text.len());
119        self.selected_range =
120            composition_selection(&new_text, range.start, new_selected_range_utf16);
121        self.selection_reversed = false;
122
123        self.caret_moved();
124        self.edited(
125            Edit {
126                start: range.start,
127                old_end: range.end,
128                new_end: range.start + new_text.len(),
129            },
130            cx,
131        );
132        cx.notify();
133    }
134
135    fn bounds_for_range(
136        &mut self,
137        range_utf16: Range<usize>,
138        bounds: Bounds<Pixels>,
139        _window: &mut Window,
140        _cx: &mut Context<Self>,
141    ) -> Option<Bounds<Pixels>> {
142        let range = self.range_from_utf16(&range_utf16);
143        // The IME panel anchors under the composing text, so this has to be the
144        // row that text is on, not the whole field. `bounds` is what
145        // `last_bounds` is set from, so this is the same origin
146        // [`TextField::offset_bounds`] measures from.
147        self.row_bounds(bounds.origin - self.scroll, range, self.line_height())
148    }
149
150    fn character_index_for_point(
151        &mut self,
152        point: Point<Pixels>,
153        _window: &mut Window,
154        _cx: &mut Context<Self>,
155    ) -> Option<usize> {
156        self.last_bounds?.localize(&point)?;
157        let origin = self.text_origin()?;
158        let offset = self.offset_at(point - origin, self.line_height());
159        Some(self.offset_to_utf16(offset))
160    }
161}