feat(text_input): minimal IME support for COSMIC specific text widgets
This commit is contained in:
parent
0ba668eb52
commit
f6eb314606
1 changed files with 103 additions and 1 deletions
|
|
@ -22,10 +22,11 @@ use iced::Limits;
|
||||||
use iced::clipboard::dnd::{DndAction, DndEvent, OfferEvent, SourceEvent};
|
use iced::clipboard::dnd::{DndAction, DndEvent, OfferEvent, SourceEvent};
|
||||||
use iced::clipboard::mime::AsMimeTypes;
|
use iced::clipboard::mime::AsMimeTypes;
|
||||||
use iced_core::event::{self, Event};
|
use iced_core::event::{self, Event};
|
||||||
|
use iced_core::input_method::{self, InputMethod, Preedit};
|
||||||
use iced_core::mouse::{self, click};
|
use iced_core::mouse::{self, click};
|
||||||
use iced_core::overlay::Group;
|
use iced_core::overlay::Group;
|
||||||
use iced_core::renderer::{self, Renderer as CoreRenderer};
|
use iced_core::renderer::{self, Renderer as CoreRenderer};
|
||||||
use iced_core::text::{self, Paragraph, Renderer, Text};
|
use iced_core::text::{self, Affinity, Paragraph, Renderer, Text};
|
||||||
use iced_core::time::{Duration, Instant};
|
use iced_core::time::{Duration, Instant};
|
||||||
use iced_core::touch;
|
use iced_core::touch;
|
||||||
use iced_core::widget::Id;
|
use iced_core::widget::Id;
|
||||||
|
|
@ -2083,6 +2084,66 @@ pub fn update<'a, Message: Clone + 'static>(
|
||||||
|
|
||||||
state.keyboard_modifiers = *modifiers;
|
state.keyboard_modifiers = *modifiers;
|
||||||
}
|
}
|
||||||
|
Event::InputMethod(event) => {
|
||||||
|
let state = state();
|
||||||
|
|
||||||
|
match event {
|
||||||
|
input_method::Event::Opened | input_method::Event::Closed => {
|
||||||
|
state.preedit = matches!(event, input_method::Event::Opened)
|
||||||
|
.then(input_method::Preedit::new);
|
||||||
|
shell.capture_event();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
input_method::Event::Preedit(content, selection) => {
|
||||||
|
if state.is_focused.is_some() {
|
||||||
|
state.preedit = Some(input_method::Preedit {
|
||||||
|
content: content.to_owned(),
|
||||||
|
selection: selection.clone(),
|
||||||
|
text_size: Some(size.into()),
|
||||||
|
});
|
||||||
|
shell.capture_event();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_method::Event::Commit(text) => {
|
||||||
|
let Some(focus) = &mut state.is_focused else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(on_input) = on_input else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if state.is_read_only {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
LAST_FOCUS_UPDATE.with(|x| x.set(focus.updated_at));
|
||||||
|
|
||||||
|
let mut editor = Editor::new(unsecured_value, &mut state.cursor);
|
||||||
|
editor.paste(Value::new(&text));
|
||||||
|
|
||||||
|
let contents = editor.contents();
|
||||||
|
let unsecured_value = Value::new(&contents);
|
||||||
|
let message = if let Some(paste) = &on_paste {
|
||||||
|
(paste)(contents)
|
||||||
|
} else {
|
||||||
|
(on_input)(contents)
|
||||||
|
};
|
||||||
|
shell.publish(message);
|
||||||
|
|
||||||
|
state.is_pasting = None;
|
||||||
|
let value = if is_secure {
|
||||||
|
unsecured_value.secure()
|
||||||
|
} else {
|
||||||
|
unsecured_value
|
||||||
|
};
|
||||||
|
|
||||||
|
update_cache(state, &value);
|
||||||
|
shell.capture_event();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Event::Window(window::Event::RedrawRequested(now)) => {
|
Event::Window(window::Event::RedrawRequested(now)) => {
|
||||||
let state = state();
|
let state = state();
|
||||||
|
|
||||||
|
|
@ -2095,6 +2156,8 @@ pub fn update<'a, Message: Clone + 'static>(
|
||||||
now.checked_add(Duration::from_millis(millis_until_redraw as u64))
|
now.checked_add(Duration::from_millis(millis_until_redraw as u64))
|
||||||
.unwrap_or(*now),
|
.unwrap_or(*now),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
shell.request_input_method(&input_method(state, text_layout, unsecured_value));
|
||||||
} else if always_active {
|
} else if always_active {
|
||||||
shell.request_redraw();
|
shell.request_redraw();
|
||||||
}
|
}
|
||||||
|
|
@ -2269,6 +2332,43 @@ pub fn update<'a, Message: Clone + 'static>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn input_method<'b>(
|
||||||
|
state: &'b State,
|
||||||
|
text_layout: Layout<'_>,
|
||||||
|
value: &Value,
|
||||||
|
) -> InputMethod<&'b str> {
|
||||||
|
if state.is_focused() {
|
||||||
|
} else {
|
||||||
|
return InputMethod::Disabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
let text_bounds = text_layout.bounds();
|
||||||
|
let cursor_index = match state.cursor.state(value) {
|
||||||
|
cursor::State::Index(position) => position,
|
||||||
|
cursor::State::Selection { start, end } => start.min(end),
|
||||||
|
};
|
||||||
|
let (cursor, offset) = measure_cursor_and_scroll_offset(
|
||||||
|
state.value.raw(),
|
||||||
|
text_bounds,
|
||||||
|
cursor_index,
|
||||||
|
value,
|
||||||
|
state.cursor.affinity(),
|
||||||
|
state.scroll_offset,
|
||||||
|
);
|
||||||
|
InputMethod::Enabled {
|
||||||
|
cursor: Rectangle::new(
|
||||||
|
Point::new(text_bounds.x + cursor - offset, text_bounds.y),
|
||||||
|
Size::new(1.0, text_bounds.height),
|
||||||
|
),
|
||||||
|
purpose: if state.is_secure {
|
||||||
|
input_method::Purpose::Secure
|
||||||
|
} else {
|
||||||
|
input_method::Purpose::Normal
|
||||||
|
},
|
||||||
|
preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
|
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
|
||||||
/// [`Value`] if provided.
|
/// [`Value`] if provided.
|
||||||
///
|
///
|
||||||
|
|
@ -2789,6 +2889,7 @@ pub struct State {
|
||||||
is_pasting: Option<Value>,
|
is_pasting: Option<Value>,
|
||||||
last_click: Option<mouse::Click>,
|
last_click: Option<mouse::Click>,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
|
preedit: Option<Preedit>,
|
||||||
keyboard_modifiers: keyboard::Modifiers,
|
keyboard_modifiers: keyboard::Modifiers,
|
||||||
scroll_offset: f32,
|
scroll_offset: f32,
|
||||||
}
|
}
|
||||||
|
|
@ -2868,6 +2969,7 @@ impl State {
|
||||||
is_pasting: None,
|
is_pasting: None,
|
||||||
last_click: None,
|
last_click: None,
|
||||||
cursor: Cursor::default(),
|
cursor: Cursor::default(),
|
||||||
|
preedit: None,
|
||||||
keyboard_modifiers: keyboard::Modifiers::default(),
|
keyboard_modifiers: keyboard::Modifiers::default(),
|
||||||
scroll_offset: 0.0,
|
scroll_offset: 0.0,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue