diff options
| author | 2025-01-10 07:12:31 +0900 | |
|---|---|---|
| committer | 2025-02-02 17:44:13 +0100 | |
| commit | 7db5256b720c3ecbe7c1cce7a1b47fd03151e03a (patch) | |
| tree | ccf08e3f76e27d0871185b786ece83f970dddc77 /winit | |
| parent | 599d8b560bec8036c5ddda62a7bf0a540bdec396 (diff) | |
| download | iced-7db5256b720c3ecbe7c1cce7a1b47fd03151e03a.tar.gz iced-7db5256b720c3ecbe7c1cce7a1b47fd03151e03a.tar.bz2 iced-7db5256b720c3ecbe7c1cce7a1b47fd03151e03a.zip | |
Draft `input_method` support
Diffstat (limited to '')
| -rw-r--r-- | winit/src/conversion.rs | 11 | ||||
| -rw-r--r-- | winit/src/program.rs | 162 | ||||
| -rw-r--r-- | winit/src/program/state.rs | 14 | 
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: | 
