use crate::reactive::{Disposable, IDisposable};
use crate::utilities::HandlerList;
use crate::{Rect, Ref, Visual};
use std::rc::Rc;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct TextSelection {
pub start: i32,
pub end: i32,
}
impl TextSelection {
pub const fn new(start: i32, end: i32) -> Self {
Self { start, end }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum ContextMenuAction {
Copy = 0,
Cut = 1,
Paste = 2,
SelectAll = 3,
}
type Event = Rc<HandlerList<dyn Fn()>>;
fn subscribe(event: &Event, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
let token = event.add(handler);
let event = event.clone();
Disposable::create(move || {
event.remove(token);
})
}
fn raise(event: &Event) {
if event.is_empty() {
return;
}
for (_, handler) in event.snapshot().iter() {
handler();
}
}
#[derive(Default)]
pub struct TextInputMethodClientEvents {
text_view_visual_changed: Event,
cursor_rectangle_changed: Event,
surrounding_text_changed: Event,
selection_changed: Event,
reset_requested: Event,
input_pane_activation_requested: Event,
}
impl TextInputMethodClientEvents {
pub fn new() -> Self {
Self::default()
}
}
pub trait TextInputMethodClient {
fn events(&self) -> &TextInputMethodClientEvents;
fn text_view_visual(&self) -> Option<Ref<Visual>>;
fn supports_preedit(&self) -> bool;
fn supports_surrounding_text(&self) -> bool;
fn surrounding_text(&self) -> String;
fn cursor_rectangle(&self) -> Rect;
fn selection(&self) -> TextSelection;
fn set_selection(&self, value: TextSelection);
fn set_preedit_text(&self, _preedit_text: Option<&str>) {}
fn execute_context_menu_action(&self, _action: ContextMenuAction) {}
fn set_preedit_text_with_cursor(&self, preedit_text: Option<&str>, _cursor_pos: Option<i32>) {
self.set_preedit_text(preedit_text)
}
fn text_view_visual_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
subscribe(&self.events().text_view_visual_changed, handler)
}
fn cursor_rectangle_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
subscribe(&self.events().cursor_rectangle_changed, handler)
}
fn surrounding_text_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
subscribe(&self.events().surrounding_text_changed, handler)
}
fn selection_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
subscribe(&self.events().selection_changed, handler)
}
fn reset_requested(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
subscribe(&self.events().reset_requested, handler)
}
fn input_pane_activation_requested(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
subscribe(&self.events().input_pane_activation_requested, handler)
}
fn raise_text_view_visual_changed(&self) {
raise(&self.events().text_view_visual_changed)
}
fn raise_cursor_rectangle_changed(&self) {
raise(&self.events().cursor_rectangle_changed)
}
fn raise_surrounding_text_changed(&self) {
raise(&self.events().surrounding_text_changed)
}
fn raise_selection_changed(&self) {
raise(&self.events().selection_changed)
}
fn raise_input_pane_activation_requested(&self) {
raise(&self.events().input_pane_activation_requested)
}
fn request_reset(&self) {
raise(&self.events().reset_requested)
}
}