use iced::advanced::input_method;
use iced::advanced::widget::{Widget, tree};
use iced::advanced::{Renderer, Shell};
use iced::{Event, Length, Rectangle, Size, Vector, mouse, window};
#[derive(Debug, Clone)]
pub struct ImeRequester {
enabled: bool,
cursor: Rectangle,
preedit: Option<input_method::Preedit<String>>,
}
impl ImeRequester {
pub fn new(
enabled: bool,
cursor: Rectangle,
preedit: Option<input_method::Preedit<String>>,
) -> Self {
Self { enabled, cursor, preedit }
}
}
impl<Message> Widget<Message, iced::Theme, iced::Renderer> for ImeRequester
where
iced::Renderer: Renderer,
{
fn size(&self) -> Size<Length> {
Size::new(Length::Shrink, Length::Shrink)
}
fn layout(
&mut self,
_tree: &mut tree::Tree,
_renderer: &iced::Renderer,
_limits: &iced::advanced::layout::Limits,
) -> iced::advanced::layout::Node {
iced::advanced::layout::Node::new(Size::new(0.0, 0.0))
}
fn draw(
&self,
_tree: &tree::Tree,
_renderer: &mut iced::Renderer,
_theme: &iced::Theme,
_style: &iced::advanced::renderer::Style,
_layout: iced::advanced::layout::Layout<'_>,
_cursor: mouse::Cursor,
_viewport: &Rectangle,
) {
}
fn tag(&self) -> tree::Tag {
tree::Tag::stateless()
}
fn state(&self) -> tree::State {
tree::State::None
}
fn update(
&mut self,
_tree: &mut tree::Tree,
event: &Event,
layout: iced::advanced::layout::Layout<'_>,
_cursor: mouse::Cursor,
_renderer: &iced::Renderer,
_clipboard: &mut dyn iced::advanced::Clipboard,
shell: &mut Shell<'_, Message>,
_viewport: &Rectangle,
) {
if let Event::Window(window::Event::RedrawRequested(_)) = event {
if self.enabled {
let position = layout.bounds().position();
let cursor_rect = Rectangle {
x: self.cursor.x + position.x,
y: self.cursor.y + position.y,
width: self.cursor.width,
height: self.cursor.height,
};
let ime = input_method::InputMethod::Enabled {
cursor: cursor_rect,
purpose: input_method::Purpose::Normal,
preedit: self
.preedit
.as_ref()
.map(input_method::Preedit::as_ref),
};
shell.request_input_method(&ime);
} else {
let disabled: input_method::InputMethod<&str> =
input_method::InputMethod::Disabled;
shell.request_input_method(&disabled);
}
}
}
fn mouse_interaction(
&self,
_tree: &tree::Tree,
_layout: iced::advanced::layout::Layout<'_>,
_cursor: mouse::Cursor,
_viewport: &Rectangle,
_renderer: &iced::Renderer,
) -> mouse::Interaction {
mouse::Interaction::None
}
fn overlay<'a>(
&'a mut self,
_tree: &'a mut tree::Tree,
_layout: iced::advanced::layout::Layout<'a>,
_renderer: &iced::Renderer,
_viewport: &Rectangle,
_translation: Vector,
) -> Option<iced::overlay::Element<'a, Message, iced::Theme, iced::Renderer>>
{
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use iced::{Length, Point, Size};
#[test]
fn test_ime_requester_initialization() {
let cursor =
Rectangle::new(Point::new(10.0, 10.0), Size::new(2.0, 20.0));
let preedit = Some(input_method::Preedit {
content: "test".to_string(),
selection: None,
text_size: None,
});
let requester = ImeRequester::new(true, cursor, preedit);
assert!(requester.enabled, "Should be enabled");
assert_eq!(requester.cursor, cursor, "Cursor rect should match");
if let Some(p) = requester.preedit {
assert_eq!(p.content, "test", "Preedit content should match");
} else {
assert!(requester.preedit.is_some(), "Preedit should be Some");
}
}
#[test]
fn test_ime_requester_layout_properties() {
let cursor = Rectangle::new(Point::new(0.0, 0.0), Size::new(0.0, 0.0));
let requester = ImeRequester::new(false, cursor, None);
let size =
<ImeRequester as Widget<(), iced::Theme, iced::Renderer>>::size(
&requester,
);
assert_eq!(size.width, Length::Shrink, "Width should be Shrink");
assert_eq!(size.height, Length::Shrink, "Height should be Shrink");
assert_eq!(
<ImeRequester as Widget<(), iced::Theme, iced::Renderer>>::tag(
&requester
),
tree::Tag::stateless(),
"Widget should be stateless"
);
assert!(matches!(
<ImeRequester as Widget<(), iced::Theme, iced::Renderer>>::state(&requester),
tree::State::None
), "Widget state should be None");
}
}