Simplify InputMethod API with only two states
Co-authored-by: rhysd <lin90162@yahoo.co.jp> Co-authored-by: KENZ <KENZ.gelsoft@gmail.com>
This commit is contained in:
parent
97f1db3783
commit
7979125ed7
8 changed files with 113 additions and 100 deletions
|
|
@ -6,14 +6,10 @@ use std::ops::Range;
|
||||||
/// The input method strategy of a widget.
|
/// The input method strategy of a widget.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum InputMethod<T = String> {
|
pub enum InputMethod<T = String> {
|
||||||
/// No input method strategy has been specified.
|
/// Input method is disabled.
|
||||||
None,
|
|
||||||
/// No input method is allowed.
|
|
||||||
Disabled,
|
Disabled,
|
||||||
/// Input methods are allowed, but not open yet.
|
/// Input method is enabled.
|
||||||
Allowed,
|
Enabled {
|
||||||
/// Input method is open.
|
|
||||||
Open {
|
|
||||||
/// The position at which the input method dialog should be placed.
|
/// The position at which the input method dialog should be placed.
|
||||||
position: Point,
|
position: Point,
|
||||||
/// The [`Purpose`] of the input method.
|
/// The [`Purpose`] of the input method.
|
||||||
|
|
@ -91,13 +87,13 @@ impl InputMethod {
|
||||||
/// # use iced_core::input_method::{InputMethod, Purpose, Preedit};
|
/// # use iced_core::input_method::{InputMethod, Purpose, Preedit};
|
||||||
/// # use iced_core::Point;
|
/// # use iced_core::Point;
|
||||||
///
|
///
|
||||||
/// let open = InputMethod::Open {
|
/// let open = InputMethod::Enabled {
|
||||||
/// position: Point::ORIGIN,
|
/// position: Point::ORIGIN,
|
||||||
/// purpose: Purpose::Normal,
|
/// purpose: Purpose::Normal,
|
||||||
/// preedit: Some(Preedit { content: "1".to_owned(), selection: None, text_size: None }),
|
/// preedit: Some(Preedit { content: "1".to_owned(), selection: None, text_size: None }),
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// let open_2 = InputMethod::Open {
|
/// let open_2 = InputMethod::Enabled {
|
||||||
/// position: Point::ORIGIN,
|
/// position: Point::ORIGIN,
|
||||||
/// purpose: Purpose::Secure,
|
/// purpose: Purpose::Secure,
|
||||||
/// preedit: Some(Preedit { content: "2".to_owned(), selection: None, text_size: None }),
|
/// preedit: Some(Preedit { content: "2".to_owned(), selection: None, text_size: None }),
|
||||||
|
|
@ -105,12 +101,6 @@ impl InputMethod {
|
||||||
///
|
///
|
||||||
/// let mut ime = InputMethod::Disabled;
|
/// let mut ime = InputMethod::Disabled;
|
||||||
///
|
///
|
||||||
/// ime.merge(&InputMethod::<String>::Allowed);
|
|
||||||
/// assert_eq!(ime, InputMethod::Allowed);
|
|
||||||
///
|
|
||||||
/// ime.merge(&InputMethod::<String>::Disabled);
|
|
||||||
/// assert_eq!(ime, InputMethod::Allowed);
|
|
||||||
///
|
|
||||||
/// ime.merge(&open);
|
/// ime.merge(&open);
|
||||||
/// assert_eq!(ime, open);
|
/// assert_eq!(ime, open);
|
||||||
///
|
///
|
||||||
|
|
@ -118,22 +108,16 @@ impl InputMethod {
|
||||||
/// assert_eq!(ime, open);
|
/// assert_eq!(ime, open);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn merge<T: AsRef<str>>(&mut self, other: &InputMethod<T>) {
|
pub fn merge<T: AsRef<str>>(&mut self, other: &InputMethod<T>) {
|
||||||
match (&self, other) {
|
if let InputMethod::Enabled { .. } = self {
|
||||||
(InputMethod::Open { .. }, _)
|
return;
|
||||||
| (
|
|
||||||
InputMethod::Allowed,
|
|
||||||
InputMethod::None | InputMethod::Disabled,
|
|
||||||
)
|
|
||||||
| (InputMethod::Disabled, InputMethod::None) => {}
|
|
||||||
_ => {
|
|
||||||
*self = other.to_owned();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*self = other.to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the [`InputMethod`] is open.
|
/// Returns true if the [`InputMethod`] is open.
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_enabled(&self) -> bool {
|
||||||
matches!(self, Self::Open { .. })
|
matches!(self, Self::Enabled { .. })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,14 +128,12 @@ impl<T> InputMethod<T> {
|
||||||
T: AsRef<str>,
|
T: AsRef<str>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Self::None => InputMethod::None,
|
|
||||||
Self::Disabled => InputMethod::Disabled,
|
Self::Disabled => InputMethod::Disabled,
|
||||||
Self::Allowed => InputMethod::Allowed,
|
Self::Enabled {
|
||||||
Self::Open {
|
|
||||||
position,
|
position,
|
||||||
purpose,
|
purpose,
|
||||||
preedit,
|
preedit,
|
||||||
} => InputMethod::Open {
|
} => InputMethod::Enabled {
|
||||||
position: *position,
|
position: *position,
|
||||||
purpose: *purpose,
|
purpose: *purpose,
|
||||||
preedit: preedit.as_ref().map(Preedit::to_owned),
|
preedit: preedit.as_ref().map(Preedit::to_owned),
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ impl<'a, Message> Shell<'a, Message> {
|
||||||
redraw_request: window::RedrawRequest::Wait,
|
redraw_request: window::RedrawRequest::Wait,
|
||||||
is_layout_invalid: false,
|
is_layout_invalid: false,
|
||||||
are_widgets_invalid: false,
|
are_widgets_invalid: false,
|
||||||
input_method: InputMethod::None,
|
input_method: InputMethod::Disabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use cosmic_text::Edit as _;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{self, Arc};
|
use std::sync::{self, Arc, RwLock};
|
||||||
|
|
||||||
/// A multi-line text editor.
|
/// A multi-line text editor.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
|
@ -19,6 +19,7 @@ pub struct Editor(Option<Arc<Internal>>);
|
||||||
|
|
||||||
struct Internal {
|
struct Internal {
|
||||||
editor: cosmic_text::Editor<'static>,
|
editor: cosmic_text::Editor<'static>,
|
||||||
|
cursor: RwLock<Option<Cursor>>,
|
||||||
font: Font,
|
font: Font,
|
||||||
bounds: Size,
|
bounds: Size,
|
||||||
topmost_line_changed: Option<usize>,
|
topmost_line_changed: Option<usize>,
|
||||||
|
|
@ -114,10 +115,14 @@ impl editor::Editor for Editor {
|
||||||
fn cursor(&self) -> editor::Cursor {
|
fn cursor(&self) -> editor::Cursor {
|
||||||
let internal = self.internal();
|
let internal = self.internal();
|
||||||
|
|
||||||
|
if let Ok(Some(cursor)) = internal.cursor.read().as_deref() {
|
||||||
|
return cursor.clone();
|
||||||
|
}
|
||||||
|
|
||||||
let cursor = internal.editor.cursor();
|
let cursor = internal.editor.cursor();
|
||||||
let buffer = buffer_from_editor(&internal.editor);
|
let buffer = buffer_from_editor(&internal.editor);
|
||||||
|
|
||||||
match internal.editor.selection_bounds() {
|
let cursor = match internal.editor.selection_bounds() {
|
||||||
Some((start, end)) => {
|
Some((start, end)) => {
|
||||||
let line_height = buffer.metrics().line_height;
|
let line_height = buffer.metrics().line_height;
|
||||||
let selected_lines = end.line - start.line + 1;
|
let selected_lines = end.line - start.line + 1;
|
||||||
|
|
@ -237,7 +242,12 @@ impl editor::Editor for Editor {
|
||||||
- buffer.scroll().vertical,
|
- buffer.scroll().vertical,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
*internal.cursor.write().expect("Write to cursor cache") =
|
||||||
|
Some(cursor.clone());
|
||||||
|
|
||||||
|
cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_position(&self) -> (usize, usize) {
|
fn cursor_position(&self) -> (usize, usize) {
|
||||||
|
|
@ -259,6 +269,13 @@ impl editor::Editor for Editor {
|
||||||
|
|
||||||
let editor = &mut internal.editor;
|
let editor = &mut internal.editor;
|
||||||
|
|
||||||
|
// Clear cursor cache
|
||||||
|
let _ = internal
|
||||||
|
.cursor
|
||||||
|
.write()
|
||||||
|
.expect("Write to cursor cache")
|
||||||
|
.take();
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
// Motion events
|
// Motion events
|
||||||
Action::Move(motion) => {
|
Action::Move(motion) => {
|
||||||
|
|
@ -527,6 +544,13 @@ impl editor::Editor for Editor {
|
||||||
|
|
||||||
internal.editor.shape_as_needed(font_system.raw(), false);
|
internal.editor.shape_as_needed(font_system.raw(), false);
|
||||||
|
|
||||||
|
// Clear cursor cache
|
||||||
|
let _ = internal
|
||||||
|
.cursor
|
||||||
|
.write()
|
||||||
|
.expect("Write to cursor cache")
|
||||||
|
.take();
|
||||||
|
|
||||||
self.0 = Some(Arc::new(internal));
|
self.0 = Some(Arc::new(internal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -635,6 +659,7 @@ impl Default for Internal {
|
||||||
line_height: 1.0,
|
line_height: 1.0,
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
|
cursor: RwLock::new(None),
|
||||||
font: Font::default(),
|
font: Font::default(),
|
||||||
bounds: Size::ZERO,
|
bounds: Size::ZERO,
|
||||||
topmost_line_changed: None,
|
topmost_line_changed: None,
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ where
|
||||||
|
|
||||||
let mut outdated = false;
|
let mut outdated = false;
|
||||||
let mut redraw_request = window::RedrawRequest::Wait;
|
let mut redraw_request = window::RedrawRequest::Wait;
|
||||||
let mut input_method = InputMethod::None;
|
let mut input_method = InputMethod::Disabled;
|
||||||
|
|
||||||
let mut manual_overlay = ManuallyDrop::new(
|
let mut manual_overlay = ManuallyDrop::new(
|
||||||
self.root
|
self.root
|
||||||
|
|
|
||||||
|
|
@ -729,7 +729,7 @@ where
|
||||||
_ => mouse::Cursor::Unavailable,
|
_ => mouse::Cursor::Unavailable,
|
||||||
};
|
};
|
||||||
|
|
||||||
let had_input_method = shell.input_method().is_open();
|
let had_input_method = shell.input_method().is_enabled();
|
||||||
|
|
||||||
let translation =
|
let translation =
|
||||||
state.translation(self.direction, bounds, content_bounds);
|
state.translation(self.direction, bounds, content_bounds);
|
||||||
|
|
@ -750,7 +750,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
if !had_input_method {
|
if !had_input_method {
|
||||||
if let InputMethod::Open { position, .. } =
|
if let InputMethod::Enabled { position, .. } =
|
||||||
shell.input_method_mut()
|
shell.input_method_mut()
|
||||||
{
|
{
|
||||||
*position = *position - translation;
|
*position = *position - translation;
|
||||||
|
|
|
||||||
|
|
@ -339,10 +339,6 @@ where
|
||||||
return InputMethod::Disabled;
|
return InputMethod::Disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(preedit) = &state.preedit else {
|
|
||||||
return InputMethod::Allowed;
|
|
||||||
};
|
|
||||||
|
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let internal = self.content.0.borrow_mut();
|
let internal = self.content.0.borrow_mut();
|
||||||
|
|
||||||
|
|
@ -363,10 +359,10 @@ where
|
||||||
let position =
|
let position =
|
||||||
cursor + translation + Vector::new(0.0, f32::from(line_height));
|
cursor + translation + Vector::new(0.0, f32::from(line_height));
|
||||||
|
|
||||||
InputMethod::Open {
|
InputMethod::Enabled {
|
||||||
position,
|
position,
|
||||||
purpose: input_method::Purpose::Normal,
|
purpose: input_method::Purpose::Normal,
|
||||||
preedit: Some(preedit.as_ref()),
|
preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -406,10 +406,6 @@ where
|
||||||
return InputMethod::Disabled;
|
return InputMethod::Disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(preedit) = &state.is_ime_open else {
|
|
||||||
return InputMethod::Allowed;
|
|
||||||
};
|
|
||||||
|
|
||||||
let secure_value = self.is_secure.then(|| value.secure());
|
let secure_value = self.is_secure.then(|| value.secure());
|
||||||
let value = secure_value.as_ref().unwrap_or(value);
|
let value = secure_value.as_ref().unwrap_or(value);
|
||||||
|
|
||||||
|
|
@ -433,14 +429,14 @@ where
|
||||||
let x = (text_bounds.x + cursor_x).floor() - scroll_offset
|
let x = (text_bounds.x + cursor_x).floor() - scroll_offset
|
||||||
+ alignment_offset;
|
+ alignment_offset;
|
||||||
|
|
||||||
InputMethod::Open {
|
InputMethod::Enabled {
|
||||||
position: Point::new(x, text_bounds.y + text_bounds.height),
|
position: Point::new(x, text_bounds.y + text_bounds.height),
|
||||||
purpose: if self.is_secure {
|
purpose: if self.is_secure {
|
||||||
input_method::Purpose::Secure
|
input_method::Purpose::Secure
|
||||||
} else {
|
} else {
|
||||||
input_method::Purpose::Normal
|
input_method::Purpose::Normal
|
||||||
},
|
},
|
||||||
preedit: Some(preedit.as_ref()),
|
preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,7 +580,7 @@ where
|
||||||
let draw = |renderer: &mut Renderer, viewport| {
|
let draw = |renderer: &mut Renderer, viewport| {
|
||||||
let paragraph = if text.is_empty()
|
let paragraph = if text.is_empty()
|
||||||
&& state
|
&& state
|
||||||
.is_ime_open
|
.preedit
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|preedit| preedit.content.is_empty())
|
.map(|preedit| preedit.content.is_empty())
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
|
|
@ -1260,7 +1256,7 @@ where
|
||||||
input_method::Event::Opened | input_method::Event::Closed => {
|
input_method::Event::Opened | input_method::Event::Closed => {
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
|
||||||
state.is_ime_open =
|
state.preedit =
|
||||||
matches!(event, input_method::Event::Opened)
|
matches!(event, input_method::Event::Opened)
|
||||||
.then(input_method::Preedit::new);
|
.then(input_method::Preedit::new);
|
||||||
|
|
||||||
|
|
@ -1270,7 +1266,7 @@ where
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
|
||||||
if state.is_focused.is_some() {
|
if state.is_focused.is_some() {
|
||||||
state.is_ime_open = Some(input_method::Preedit {
|
state.preedit = Some(input_method::Preedit {
|
||||||
content: content.to_owned(),
|
content: content.to_owned(),
|
||||||
selection: selection.clone(),
|
selection: selection.clone(),
|
||||||
text_size: self.size,
|
text_size: self.size,
|
||||||
|
|
@ -1340,6 +1336,12 @@ where
|
||||||
millis_until_redraw as u64,
|
millis_until_redraw as u64,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
shell.request_input_method(&self.input_method(
|
||||||
|
state,
|
||||||
|
layout,
|
||||||
|
&self.value,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1363,12 +1365,6 @@ where
|
||||||
|
|
||||||
if let Event::Window(window::Event::RedrawRequested(_now)) = event {
|
if let Event::Window(window::Event::RedrawRequested(_now)) = event {
|
||||||
self.last_status = Some(status);
|
self.last_status = Some(status);
|
||||||
|
|
||||||
shell.request_input_method(&self.input_method(
|
|
||||||
state,
|
|
||||||
layout,
|
|
||||||
&self.value,
|
|
||||||
));
|
|
||||||
} else if self
|
} else if self
|
||||||
.last_status
|
.last_status
|
||||||
.is_some_and(|last_status| status != last_status)
|
.is_some_and(|last_status| status != last_status)
|
||||||
|
|
@ -1528,9 +1524,9 @@ pub struct State<P: text::Paragraph> {
|
||||||
placeholder: paragraph::Plain<P>,
|
placeholder: paragraph::Plain<P>,
|
||||||
icon: paragraph::Plain<P>,
|
icon: paragraph::Plain<P>,
|
||||||
is_focused: Option<Focus>,
|
is_focused: Option<Focus>,
|
||||||
is_ime_open: Option<input_method::Preedit>,
|
|
||||||
is_dragging: bool,
|
is_dragging: bool,
|
||||||
is_pasting: Option<Value>,
|
is_pasting: Option<Value>,
|
||||||
|
preedit: Option<input_method::Preedit>,
|
||||||
last_click: Option<mouse::Click>,
|
last_click: Option<mouse::Click>,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
keyboard_modifiers: keyboard::Modifiers,
|
keyboard_modifiers: keyboard::Modifiers,
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ where
|
||||||
mouse_interaction: mouse::Interaction::None,
|
mouse_interaction: mouse::Interaction::None,
|
||||||
redraw_at: None,
|
redraw_at: None,
|
||||||
preedit: None,
|
preedit: None,
|
||||||
|
ime_state: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -166,6 +167,7 @@ where
|
||||||
pub renderer: P::Renderer,
|
pub renderer: P::Renderer,
|
||||||
pub redraw_at: Option<Instant>,
|
pub redraw_at: Option<Instant>,
|
||||||
preedit: Option<Preedit<P::Renderer>>,
|
preedit: Option<Preedit<P::Renderer>>,
|
||||||
|
ime_state: Option<(Point, input_method::Purpose)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, C> Window<P, C>
|
impl<P, C> Window<P, C>
|
||||||
|
|
@ -206,52 +208,39 @@ where
|
||||||
|
|
||||||
pub fn request_input_method(&mut self, input_method: InputMethod) {
|
pub fn request_input_method(&mut self, input_method: InputMethod) {
|
||||||
match input_method {
|
match input_method {
|
||||||
InputMethod::None => {}
|
|
||||||
InputMethod::Disabled => {
|
InputMethod::Disabled => {
|
||||||
self.raw.set_ime_allowed(false);
|
self.disable_ime();
|
||||||
}
|
}
|
||||||
InputMethod::Allowed | InputMethod::Open { .. } => {
|
InputMethod::Enabled {
|
||||||
self.raw.set_ime_allowed(true);
|
position,
|
||||||
}
|
purpose,
|
||||||
}
|
preedit,
|
||||||
|
} => {
|
||||||
|
self.enable_ime(position, purpose);
|
||||||
|
|
||||||
if let InputMethod::Open {
|
if let Some(preedit) = preedit {
|
||||||
position,
|
if preedit.content.is_empty() {
|
||||||
purpose,
|
self.preedit = None;
|
||||||
preedit,
|
} else if let Some(overlay) = &mut self.preedit {
|
||||||
} = input_method
|
overlay.update(
|
||||||
{
|
position,
|
||||||
self.raw.set_ime_cursor_area(
|
&preedit,
|
||||||
LogicalPosition::new(position.x, position.y),
|
self.state.background_color(),
|
||||||
LogicalSize::new(10, 10), // TODO?
|
&self.renderer,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
let mut overlay = Preedit::new();
|
||||||
|
overlay.update(
|
||||||
|
position,
|
||||||
|
&preedit,
|
||||||
|
self.state.background_color(),
|
||||||
|
&self.renderer,
|
||||||
|
);
|
||||||
|
|
||||||
self.raw.set_ime_purpose(conversion::ime_purpose(purpose));
|
self.preedit = Some(overlay);
|
||||||
|
}
|
||||||
if let Some(preedit) = preedit {
|
|
||||||
if preedit.content.is_empty() {
|
|
||||||
self.preedit = None;
|
|
||||||
} else if let Some(overlay) = &mut self.preedit {
|
|
||||||
overlay.update(
|
|
||||||
position,
|
|
||||||
&preedit,
|
|
||||||
self.state.background_color(),
|
|
||||||
&self.renderer,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let mut overlay = Preedit::new();
|
|
||||||
overlay.update(
|
|
||||||
position,
|
|
||||||
&preedit,
|
|
||||||
self.state.background_color(),
|
|
||||||
&self.renderer,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.preedit = Some(overlay);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.preedit = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,6 +257,31 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enable_ime(&mut self, position: Point, purpose: input_method::Purpose) {
|
||||||
|
if self.ime_state.is_none() {
|
||||||
|
self.raw.set_ime_allowed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ime_state != Some((position, purpose)) {
|
||||||
|
self.raw.set_ime_cursor_area(
|
||||||
|
LogicalPosition::new(position.x, position.y),
|
||||||
|
LogicalSize::new(10, 10), // TODO?
|
||||||
|
);
|
||||||
|
self.raw.set_ime_purpose(conversion::ime_purpose(purpose));
|
||||||
|
|
||||||
|
self.ime_state = Some((position, purpose));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable_ime(&mut self) {
|
||||||
|
if self.ime_state.is_some() {
|
||||||
|
self.raw.set_ime_allowed(false);
|
||||||
|
self.ime_state = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.preedit = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Preedit<Renderer>
|
struct Preedit<Renderer>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue