Writing a Widget
is not hard but it has a steep learning curve as there are several concepts you will need to juggle.
Before going down that path, may I ask why not compose this functionality using existing widgets such as mouse_area
and stack
?
If the issue is reusability, you could create a function that is generic over Message
and looks somewhat like this:
fn my_widget<'a, Message>(
content: &'a str,
footnote: Option<&'a str>,
on_enter: Message,
on_exit: Message,
on_press: Message,
on_release: Message,
) -> Element<'a, Message>
where
Message: Clone + 'static,
{
let footnote = container(match footnote {
Some(footnote) => text(footnote).size(12).into(),
None => Element::from(horizontal_space()),
})
.align_bottom(Fill)
.align_right(Fill)
.width(Fill)
.height(Fill)
.padding(2);
container(
mouse_area(stack![
center(text(content).size(16)).width(Fill).height(Fill),
footnote
])
.on_enter(on_enter)
.on_exit(on_exit)
.on_press(on_press)
.on_release(on_release),
)
.style(container::rounded_box)
.into()
}
A full example is below:
use iced::widget::{center, column, container, horizontal_space, mouse_area, stack, text};
use iced::{Element, Fill, Size, Task};
fn main() -> iced::Result {
iced::application("iced • mouse area example", App::update, App::view)
.window_size(Size::new(400.0, 200.0))
.centered()
.run()
}
#[derive(Debug, Clone)]
enum Message {
MouseEnter,
MouseExit,
MousePress,
MouseRelease,
}
#[derive(Default)]
struct App {
state: &'static str,
}
impl App {
fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::MouseEnter => self.state = "Mouse entered!",
Message::MouseExit => self.state = "Mouse left!",
Message::MousePress => self.state = "Mouse pressed!",
Message::MouseRelease => self.state = "Mouse released!",
}
Task::none()
}
fn view(&self) -> Element<Message> {
center(
column![
my_widget(
"Hover and click me!",
Some("(I'm the footnote)"),
Message::MouseEnter,
Message::MouseExit,
Message::MousePress,
Message::MouseRelease,
),
text(self.state).size(14),
]
.padding(20),
)
.padding(20)
.into()
}
}
fn my_widget<'a, Message>(
content: &'a str,
footnote: Option<&'a str>,
on_enter: Message,
on_exit: Message,
on_press: Message,
on_release: Message,
) -> Element<'a, Message>
where
Message: Clone + 'static,
{
let footnote = container(match footnote {
Some(footnote) => text(footnote).size(12).into(),
None => Element::from(horizontal_space()),
})
.align_bottom(Fill)
.align_right(Fill)
.width(Fill)
.height(Fill)
.padding(2);
container(
mouse_area(stack![
center(text(content).size(16)).width(Fill).height(Fill),
footnote
])
.on_enter(on_enter)
.on_exit(on_exit)
.on_press(on_press)
.on_release(on_release),
)
.style(container::rounded_box)
.into()
}
If you still want to go down the widget path, I can give you some pointers.