Draft input_method support
This commit is contained in:
parent
599d8b560b
commit
7db5256b72
13 changed files with 420 additions and 27 deletions
|
|
@ -564,6 +564,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
shell.update_caret_info(local_shell.caret_info());
|
||||
|
||||
// Then finally react to them here
|
||||
for message in local_messages {
|
||||
|
|
@ -742,6 +743,8 @@ where
|
|||
published_message_to_shell = true;
|
||||
|
||||
// Unfocus the input
|
||||
let mut local_messages = Vec::new();
|
||||
let mut local_shell = Shell::new(&mut local_messages);
|
||||
self.text_input.update(
|
||||
&mut tree.children[0],
|
||||
Event::Mouse(mouse::Event::ButtonPressed(
|
||||
|
|
@ -751,9 +754,10 @@ where
|
|||
mouse::Cursor::Unavailable,
|
||||
renderer,
|
||||
clipboard,
|
||||
&mut Shell::new(&mut vec![]),
|
||||
&mut local_shell,
|
||||
viewport,
|
||||
);
|
||||
shell.update_caret_info(local_shell.caret_info());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
shell.update_caret_info(local_shell.caret_info());
|
||||
|
||||
if !local_messages.is_empty() {
|
||||
let mut heads = self.state.take().unwrap().into_heads();
|
||||
|
|
@ -640,6 +641,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
shell.update_caret_info(local_shell.caret_info());
|
||||
|
||||
if !local_messages.is_empty() {
|
||||
let mut inner =
|
||||
|
|
|
|||
|
|
@ -33,8 +33,9 @@ use crate::core::widget::operation::{self, Operation};
|
|||
use crate::core::widget::tree::{self, Tree};
|
||||
use crate::core::window;
|
||||
use crate::core::{
|
||||
self, Background, Clipboard, Color, Element, Event, Layout, Length,
|
||||
Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector, Widget,
|
||||
self, Background, CaretInfo, Clipboard, Color, Element, Event, Layout,
|
||||
Length, Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector,
|
||||
Widget,
|
||||
};
|
||||
use crate::runtime::task::{self, Task};
|
||||
use crate::runtime::Action;
|
||||
|
|
@ -729,6 +730,7 @@ where
|
|||
let translation =
|
||||
state.translation(self.direction, bounds, content_bounds);
|
||||
|
||||
let children_may_have_caret = shell.caret_info().is_none();
|
||||
self.content.as_widget_mut().update(
|
||||
&mut tree.children[0],
|
||||
event.clone(),
|
||||
|
|
@ -743,6 +745,19 @@ where
|
|||
..bounds
|
||||
},
|
||||
);
|
||||
|
||||
if children_may_have_caret {
|
||||
if let Some(caret_info) = shell.caret_info() {
|
||||
shell.update_caret_info(Some(CaretInfo {
|
||||
position: Point::new(
|
||||
caret_info.position.x - translation.x,
|
||||
caret_info.position.y - translation.y,
|
||||
),
|
||||
input_method_allowed: caret_info
|
||||
.input_method_allowed,
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if matches!(
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
//! ```
|
||||
use crate::core::alignment;
|
||||
use crate::core::clipboard::{self, Clipboard};
|
||||
use crate::core::input_method;
|
||||
use crate::core::keyboard;
|
||||
use crate::core::keyboard::key;
|
||||
use crate::core::layout::{self, Layout};
|
||||
|
|
@ -46,8 +47,8 @@ use crate::core::widget::operation;
|
|||
use crate::core::widget::{self, Widget};
|
||||
use crate::core::window;
|
||||
use crate::core::{
|
||||
Background, Border, Color, Element, Event, Length, Padding, Pixels, Point,
|
||||
Rectangle, Shell, Size, SmolStr, Theme, Vector,
|
||||
Background, Border, CaretInfo, Color, Element, Event, Length, Padding,
|
||||
Pixels, Point, Rectangle, Shell, Size, SmolStr, Theme, Vector,
|
||||
};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
|
@ -322,6 +323,46 @@ where
|
|||
self.class = class.into();
|
||||
self
|
||||
}
|
||||
|
||||
fn caret_rect(
|
||||
&self,
|
||||
tree: &widget::Tree,
|
||||
renderer: &Renderer,
|
||||
layout: Layout<'_>,
|
||||
) -> Option<Rectangle> {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
let internal = self.content.0.borrow_mut();
|
||||
let state = tree.state.downcast_ref::<State<Highlighter>>();
|
||||
|
||||
let text_bounds = bounds.shrink(self.padding);
|
||||
let translation = text_bounds.position() - Point::ORIGIN;
|
||||
|
||||
if let Some(_) = state.focus.as_ref() {
|
||||
let position = match internal.editor.cursor() {
|
||||
Cursor::Caret(position) => position,
|
||||
Cursor::Selection(ranges) => ranges
|
||||
.first()
|
||||
.cloned()
|
||||
.unwrap_or(Rectangle::default())
|
||||
.position(),
|
||||
};
|
||||
Some(Rectangle::new(
|
||||
position + translation,
|
||||
Size::new(
|
||||
1.0,
|
||||
self.line_height
|
||||
.to_absolute(
|
||||
self.text_size
|
||||
.unwrap_or_else(|| renderer.default_size()),
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The content of a [`TextEditor`].
|
||||
|
|
@ -605,7 +646,7 @@ where
|
|||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
_renderer: &Renderer,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
_viewport: &Rectangle,
|
||||
|
|
@ -701,6 +742,11 @@ where
|
|||
}));
|
||||
shell.capture_event();
|
||||
}
|
||||
Update::Commit(text) => {
|
||||
shell.publish(on_edit(Action::Edit(Edit::Paste(
|
||||
Arc::new(text),
|
||||
))));
|
||||
}
|
||||
Update::Binding(binding) => {
|
||||
fn apply_binding<
|
||||
H: text::Highlighter,
|
||||
|
|
@ -825,6 +871,19 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
shell.update_caret_info(if state.is_focused() {
|
||||
let rect = self
|
||||
.caret_rect(tree, renderer, layout)
|
||||
.unwrap_or(Rectangle::default());
|
||||
let bottom_left = Point::new(rect.x, rect.y + rect.height);
|
||||
Some(CaretInfo {
|
||||
position: bottom_left,
|
||||
input_method_allowed: true,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
});
|
||||
|
||||
if is_redraw {
|
||||
self.last_status = Some(status);
|
||||
} else if self
|
||||
|
|
@ -1129,6 +1188,7 @@ enum Update<Message> {
|
|||
Drag(Point),
|
||||
Release,
|
||||
Scroll(f32),
|
||||
Commit(String),
|
||||
Binding(Binding<Message>),
|
||||
}
|
||||
|
||||
|
|
@ -1191,6 +1251,9 @@ impl<Message> Update<Message> {
|
|||
}
|
||||
_ => None,
|
||||
},
|
||||
Event::InputMethod(input_method::Event::Commit(text)) => {
|
||||
Some(Update::Commit(text))
|
||||
}
|
||||
Event::Keyboard(keyboard::Event::KeyPressed {
|
||||
key,
|
||||
modifiers,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ mod value;
|
|||
pub mod cursor;
|
||||
|
||||
pub use cursor::Cursor;
|
||||
use iced_runtime::core::input_method;
|
||||
pub use value::Value;
|
||||
|
||||
use editor::Editor;
|
||||
|
|
@ -56,8 +57,8 @@ use crate::core::widget::operation::{self, Operation};
|
|||
use crate::core::widget::tree::{self, Tree};
|
||||
use crate::core::window;
|
||||
use crate::core::{
|
||||
Background, Border, Color, Element, Event, Layout, Length, Padding, Pixels,
|
||||
Point, Rectangle, Shell, Size, Theme, Vector, Widget,
|
||||
Background, Border, CaretInfo, Color, Element, Event, Layout, Length,
|
||||
Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector, Widget,
|
||||
};
|
||||
use crate::runtime::task::{self, Task};
|
||||
use crate::runtime::Action;
|
||||
|
|
@ -391,6 +392,58 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn caret_rect(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
layout: Layout<'_>,
|
||||
value: Option<&Value>,
|
||||
) -> Option<Rectangle> {
|
||||
let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>();
|
||||
let value = value.unwrap_or(&self.value);
|
||||
|
||||
let secure_value = self.is_secure.then(|| value.secure());
|
||||
let value = secure_value.as_ref().unwrap_or(value);
|
||||
|
||||
let mut children_layout = layout.children();
|
||||
let text_bounds = children_layout.next().unwrap().bounds();
|
||||
|
||||
if let Some(_) = state
|
||||
.is_focused
|
||||
.as_ref()
|
||||
.filter(|focus| focus.is_window_focused)
|
||||
{
|
||||
let caret_index = match state.cursor.state(value) {
|
||||
cursor::State::Index(position) => position,
|
||||
cursor::State::Selection { start, end } => {
|
||||
let left = start.min(end);
|
||||
left
|
||||
}
|
||||
};
|
||||
let text = state.value.raw();
|
||||
let (caret_x, offset) = measure_cursor_and_scroll_offset(
|
||||
text,
|
||||
text_bounds,
|
||||
caret_index,
|
||||
);
|
||||
|
||||
let alignment_offset = alignment_offset(
|
||||
text_bounds.width,
|
||||
text.min_width(),
|
||||
self.alignment,
|
||||
);
|
||||
|
||||
let x = (text_bounds.x + caret_x).floor();
|
||||
Some(Rectangle {
|
||||
x: (alignment_offset - offset) + x,
|
||||
y: text_bounds.y,
|
||||
width: 1.0,
|
||||
height: text_bounds.height,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
|
||||
/// [`Value`] if provided.
|
||||
///
|
||||
|
|
@ -1197,6 +1250,31 @@ where
|
|||
|
||||
state.keyboard_modifiers = *modifiers;
|
||||
}
|
||||
Event::InputMethod(input_method::Event::Commit(string)) => {
|
||||
let state = state::<Renderer>(tree);
|
||||
|
||||
if let Some(focus) = &mut state.is_focused {
|
||||
let Some(on_input) = &self.on_input else {
|
||||
return;
|
||||
};
|
||||
|
||||
state.is_pasting = None;
|
||||
|
||||
let mut editor =
|
||||
Editor::new(&mut self.value, &mut state.cursor);
|
||||
|
||||
editor.paste(Value::new(&string));
|
||||
|
||||
let message = (on_input)(editor.contents());
|
||||
shell.publish(message);
|
||||
|
||||
focus.updated_at = Instant::now();
|
||||
|
||||
update_cache(state, &self.value);
|
||||
|
||||
shell.capture_event();
|
||||
}
|
||||
}
|
||||
Event::Window(window::Event::Unfocused) => {
|
||||
let state = state::<Renderer>(tree);
|
||||
|
||||
|
|
@ -1256,6 +1334,19 @@ where
|
|||
Status::Active
|
||||
};
|
||||
|
||||
shell.update_caret_info(if state.is_focused() {
|
||||
let rect = self
|
||||
.caret_rect(tree, layout, Some(&self.value))
|
||||
.unwrap_or(Rectangle::with_size(Size::<f32>::default()));
|
||||
let bottom_left = Point::new(rect.x, rect.y + rect.height);
|
||||
Some(CaretInfo {
|
||||
position: bottom_left,
|
||||
input_method_allowed: true,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
});
|
||||
|
||||
if let Event::Window(window::Event::RedrawRequested(_now)) = event {
|
||||
self.last_status = Some(status);
|
||||
} else if self
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue