ferroui_base/input/text_input/
text_input_method_client.rs1use crate::reactive::{Disposable, IDisposable};
2use crate::utilities::HandlerList;
3use crate::{Rect, Ref, Visual};
4use std::rc::Rc;
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
8pub struct TextSelection {
9 pub start: i32,
10 pub end: i32,
11}
12
13impl TextSelection {
14 pub const fn new(start: i32, end: i32) -> Self {
15 Self { start, end }
16 }
17}
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21#[repr(i32)]
22pub enum ContextMenuAction {
23 Copy = 0,
24 Cut = 1,
25 Paste = 2,
26 SelectAll = 3,
27}
28
29type Event = Rc<HandlerList<dyn Fn()>>;
30
31fn subscribe(event: &Event, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
32 let token = event.add(handler);
33 let event = event.clone();
34 Disposable::create(move || {
35 event.remove(token);
36 })
37}
38
39fn raise(event: &Event) {
40 if event.is_empty() {
41 return;
42 }
43 for (_, handler) in event.snapshot().iter() {
44 handler();
45 }
46}
47
48#[derive(Default)]
51pub struct TextInputMethodClientEvents {
52 text_view_visual_changed: Event,
53 cursor_rectangle_changed: Event,
54 surrounding_text_changed: Event,
55 selection_changed: Event,
56 reset_requested: Event,
57 input_pane_activation_requested: Event,
58}
59
60impl TextInputMethodClientEvents {
61 pub fn new() -> Self {
63 Self::default()
64 }
65}
66
67pub trait TextInputMethodClient {
74 fn events(&self) -> &TextInputMethodClientEvents;
76
77 fn text_view_visual(&self) -> Option<Ref<Visual>>;
80
81 fn supports_preedit(&self) -> bool;
84
85 fn supports_surrounding_text(&self) -> bool;
88
89 fn surrounding_text(&self) -> String;
91
92 fn cursor_rectangle(&self) -> Rect;
94
95 fn selection(&self) -> TextSelection;
97
98 fn set_selection(&self, value: TextSelection);
100
101 fn set_preedit_text(&self, _preedit_text: Option<&str>) {}
103
104 fn execute_context_menu_action(&self, _action: ContextMenuAction) {}
106
107 fn set_preedit_text_with_cursor(&self, preedit_text: Option<&str>, _cursor_pos: Option<i32>) {
110 self.set_preedit_text(preedit_text)
111 }
112
113 fn text_view_visual_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
116 subscribe(&self.events().text_view_visual_changed, handler)
117 }
118
119 fn cursor_rectangle_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
122 subscribe(&self.events().cursor_rectangle_changed, handler)
123 }
124
125 fn surrounding_text_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
128 subscribe(&self.events().surrounding_text_changed, handler)
129 }
130
131 fn selection_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
134 subscribe(&self.events().selection_changed, handler)
135 }
136
137 fn reset_requested(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
140 subscribe(&self.events().reset_requested, handler)
141 }
142
143 fn input_pane_activation_requested(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
146 subscribe(&self.events().input_pane_activation_requested, handler)
147 }
148
149 fn raise_text_view_visual_changed(&self) {
151 raise(&self.events().text_view_visual_changed)
152 }
153
154 fn raise_cursor_rectangle_changed(&self) {
156 raise(&self.events().cursor_rectangle_changed)
157 }
158
159 fn raise_surrounding_text_changed(&self) {
161 raise(&self.events().surrounding_text_changed)
162 }
163
164 fn raise_selection_changed(&self) {
166 raise(&self.events().selection_changed)
167 }
168
169 fn raise_input_pane_activation_requested(&self) {
171 raise(&self.events().input_pane_activation_requested)
172 }
173
174 fn request_reset(&self) {
176 raise(&self.events().reset_requested)
177 }
178}