summaryrefslogtreecommitdiffstats
path: root/winit
diff options
context:
space:
mode:
authorLibravatar KENZ <KENZ.gelsoft@gmail.com>2025-01-10 07:12:31 +0900
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2025-02-02 17:44:13 +0100
commit7db5256b720c3ecbe7c1cce7a1b47fd03151e03a (patch)
treeccf08e3f76e27d0871185b786ece83f970dddc77 /winit
parent599d8b560bec8036c5ddda62a7bf0a540bdec396 (diff)
downloadiced-7db5256b720c3ecbe7c1cce7a1b47fd03151e03a.tar.gz
iced-7db5256b720c3ecbe7c1cce7a1b47fd03151e03a.tar.bz2
iced-7db5256b720c3ecbe7c1cce7a1b47fd03151e03a.zip
Draft `input_method` support
Diffstat (limited to 'winit')
-rw-r--r--winit/src/conversion.rs11
-rw-r--r--winit/src/program.rs162
-rw-r--r--winit/src/program/state.rs14
3 files changed, 171 insertions, 16 deletions
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 462be65b..a289f060 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -2,6 +2,7 @@
//!
//! [`winit`]: https://github.com/rust-windowing/winit
//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/0.13/runtime
+use crate::core::input_method;
use crate::core::keyboard;
use crate::core::mouse;
use crate::core::touch;
@@ -283,6 +284,16 @@ pub fn window_event(
self::modifiers(new_modifiers.state()),
)))
}
+ WindowEvent::Ime(ime) => {
+ use winit::event::Ime;
+ println!("ime event: {:?}", ime);
+ Some(Event::InputMethod(match ime {
+ Ime::Enabled => input_method::Event::Enabled,
+ Ime::Preedit(s, size) => input_method::Event::Preedit(s, size),
+ Ime::Commit(s) => input_method::Event::Commit(s),
+ Ime::Disabled => input_method::Event::Disabled,
+ }))
+ }
WindowEvent::Focused(focused) => Some(Event::Window(if focused {
window::Event::Focused
} else {
diff --git a/winit/src/program.rs b/winit/src/program.rs
index d8436212..688d6731 100644
--- a/winit/src/program.rs
+++ b/winit/src/program.rs
@@ -3,6 +3,8 @@ mod state;
mod window_manager;
pub use state::State;
+use winit::dpi::LogicalPosition;
+use winit::dpi::LogicalSize;
use crate::conversion;
use crate::core;
@@ -579,6 +581,8 @@ async fn run_instance<P, C>(
let mut clipboard = Clipboard::unconnected();
let mut compositor_receiver: Option<oneshot::Receiver<_>> = None;
+ let mut preedit = Preedit::<P>::new();
+
debug.startup_finished();
loop {
@@ -873,17 +877,27 @@ async fn run_instance<P, C>(
});
if let user_interface::State::Updated {
- redraw_request: Some(redraw_request),
+ redraw_request,
+ caret_info,
} = ui_state
{
match redraw_request {
- window::RedrawRequest::NextFrame => {
+ Some(window::RedrawRequest::NextFrame) => {
window.raw.request_redraw();
window.redraw_at = None;
}
- window::RedrawRequest::At(at) => {
+ Some(window::RedrawRequest::At(at)) => {
window.redraw_at = Some(at);
}
+ None => {}
+ }
+
+ if let Some(caret_info) = caret_info {
+ update_input_method(
+ window,
+ &mut preedit,
+ &caret_info,
+ );
}
}
@@ -1032,24 +1046,37 @@ async fn run_instance<P, C>(
window.raw.request_redraw();
match ui_state {
- #[cfg(not(
- feature = "unconditional-rendering"
- ))]
user_interface::State::Updated {
- redraw_request: Some(redraw_request),
- } => match redraw_request {
- window::RedrawRequest::NextFrame => {
- window.raw.request_redraw();
- window.redraw_at = None;
+ redraw_request: _redraw_request,
+ caret_info,
+ } => {
+ #[cfg(not(
+ feature = "unconditional-rendering"
+ ))]
+ match _redraw_request {
+ Some(
+ window::RedrawRequest::NextFrame,
+ ) => {
+ window.raw.request_redraw();
+ window.redraw_at = None;
+ }
+ Some(window::RedrawRequest::At(at)) => {
+ window.redraw_at = Some(at);
+ }
+ None => {}
}
- window::RedrawRequest::At(at) => {
- window.redraw_at = Some(at);
+
+ if let Some(caret_info) = caret_info {
+ update_input_method(
+ window,
+ &mut preedit,
+ &caret_info,
+ );
}
- },
+ }
user_interface::State::Outdated => {
uis_stale = true;
}
- user_interface::State::Updated { .. } => {}
}
for (event, status) in window_events
@@ -1138,6 +1165,111 @@ async fn run_instance<P, C>(
let _ = ManuallyDrop::into_inner(user_interfaces);
}
+fn update_input_method<P, C>(
+ window: &mut crate::program::window_manager::Window<P, C>,
+ preedit: &mut Preedit<P>,
+ caret_info: &crate::core::CaretInfo,
+) where
+ P: Program,
+ C: Compositor<Renderer = P::Renderer> + 'static,
+{
+ window.raw.set_ime_allowed(caret_info.input_method_allowed);
+ window.raw.set_ime_cursor_area(
+ LogicalPosition::new(caret_info.position.x, caret_info.position.y),
+ LogicalSize::new(10, 10),
+ );
+
+ let text = window.state.preedit();
+ if !text.is_empty() {
+ preedit.update(text.as_str(), &window.renderer);
+ preedit.fill(
+ &mut window.renderer,
+ window.state.text_color(),
+ window.state.background_color(),
+ caret_info.position,
+ );
+ }
+}
+
+struct Preedit<P: Program> {
+ content: Option<<P::Renderer as core::text::Renderer>::Paragraph>,
+}
+
+impl<P: Program> Preedit<P> {
+ fn new() -> Self {
+ Self { content: None }
+ }
+
+ fn update(&mut self, text: &str, renderer: &P::Renderer) {
+ use core::text::Paragraph as _;
+ use core::text::Renderer as _;
+
+ self.content = Some(
+ <P::Renderer as core::text::Renderer>::Paragraph::with_text(
+ core::Text::<&str, <P::Renderer as core::text::Renderer>::Font> {
+ content: text,
+ bounds: Size::INFINITY,
+ size: renderer.default_size(),
+ line_height: core::text::LineHeight::default(),
+ font: renderer.default_font(),
+ horizontal_alignment: core::alignment::Horizontal::Left,
+ vertical_alignment: core::alignment::Vertical::Top, //Bottom,
+ shaping: core::text::Shaping::Advanced,
+ wrapping: core::text::Wrapping::None,
+ },
+ ),
+ );
+ }
+
+ fn fill(
+ &self,
+ renderer: &mut P::Renderer,
+ fore_color: core::Color,
+ bg_color: core::Color,
+ caret_position: Point,
+ ) {
+ use core::text::Paragraph as _;
+ use core::text::Renderer as _;
+ use core::Renderer as _;
+
+ let Some(ref content) = self.content else {
+ return;
+ };
+ if content.min_width() < 1.0 {
+ return;
+ }
+
+ let top_left = Point::new(
+ caret_position.x,
+ caret_position.y - content.min_height(),
+ );
+ let bounds = core::Rectangle::new(top_left, content.min_bounds());
+ renderer.with_layer(bounds, |renderer| {
+ renderer.fill_quad(
+ core::renderer::Quad {
+ bounds,
+ ..Default::default()
+ },
+ core::Background::Color(bg_color),
+ );
+
+ let underline = 2.;
+ renderer.fill_quad(
+ core::renderer::Quad {
+ bounds: bounds.shrink(core::Padding {
+ top: bounds.height - underline,
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ core::Background::Color(fore_color),
+ );
+
+ renderer.fill_paragraph(content, top_left, fore_color, bounds);
+ });
+ }
+}
+
/// Builds a window's [`UserInterface`] for the [`Program`].
fn build_user_interface<'a, P: Program>(
program: &'a P,
diff --git a/winit/src/program/state.rs b/winit/src/program/state.rs
index e883d04a..2b5710ac 100644
--- a/winit/src/program/state.rs
+++ b/winit/src/program/state.rs
@@ -4,7 +4,7 @@ use crate::core::{Color, Size};
use crate::graphics::Viewport;
use crate::program::Program;
-use winit::event::{Touch, WindowEvent};
+use winit::event::{Ime, Touch, WindowEvent};
use winit::window::Window;
use std::fmt::{Debug, Formatter};
@@ -22,6 +22,7 @@ where
modifiers: winit::keyboard::ModifiersState,
theme: P::Theme,
style: theme::Style,
+ preedit: String,
}
impl<P: Program> Debug for State<P>
@@ -73,6 +74,7 @@ where
modifiers: winit::keyboard::ModifiersState::default(),
theme,
style,
+ preedit: String::default(),
}
}
@@ -136,6 +138,11 @@ where
self.style.text_color
}
+ /// TODO
+ pub fn preedit(&self) -> String {
+ self.preedit.clone()
+ }
+
/// Processes the provided window event and updates the [`State`] accordingly.
pub fn update(
&mut self,
@@ -179,6 +186,11 @@ where
WindowEvent::ModifiersChanged(new_modifiers) => {
self.modifiers = new_modifiers.state();
}
+ WindowEvent::Ime(ime) => {
+ if let Ime::Preedit(text, _) = ime {
+ self.preedit = text.clone();
+ }
+ }
#[cfg(feature = "debug")]
WindowEvent::KeyboardInput {
event: