I am trying to implement a custom widget that can take other widgets as children. I am mostly following this guide but I have ran into a couple of issues.
Issue #1 is that when I pass a standard iced button into my custom widget it no longer seems to be emitting messages. The button works just fine when I don’t wrap it in my custom widget. So I am probably doing something wrong, but I am not sure what.
Issue #2 is positioning. I want to align the child widgets to the right hand side of my custom widget (the custom widget is a custom titlebar, so I want the decorations on the right side). Again, I am assuming I am doing something wrong because so far any attempt to use align
or move_to
on the child node has resulted in the child widget not being where I expected it, or not in the window at all.
Widget Code:
pub struct TitleBar<'a, Message, Renderer> {
padding: f32,
close_button: Option<Element<'a, Message, Theme, Renderer>>,
}
impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer>
where
Renderer: iced::advanced::Renderer,
{
pub fn new() -> Self {
Self {
padding: 4.0,
close_button: None,
}
}
pub fn padding(mut self, padding: f32) -> Self {
self.padding = padding;
self
}
pub fn with_close_button(mut self, close_button: Element<'a, Message, Theme, Renderer>) -> Self {
self.close_button = Some(close_button);
self
}
}
impl<'a, Message, Renderer> Widget<Message, Theme, Renderer> for TitleBar<'a, Message, Renderer>
where
Renderer: iced::advanced::Renderer,
{
fn size(&self) -> Size<Length> {
Size {
width: Length::Fill,
height: Length::Shrink,
}
}
fn children(&self) -> Vec<Tree> {
if self.close_button.is_some() {
vec![Tree::new(self.close_button.as_ref().unwrap().as_widget())]
} else {
vec![]
}
}
fn diff(&self, tree: &mut Tree) {
if self.close_button.is_some() {
tree.diff_children(std::slice::from_ref(&self.close_button.as_ref().unwrap()));
}
}
fn layout(
&self,
tree: &mut Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
match &self.close_button {
None => {
layout::Node::new([limits.max().width, self.padding as f32].into())
}
Some(close) => {
let mut close_node =
close
.as_widget()
.layout(&mut tree.children[0], renderer, limits);
let close_node_size = close_node.size().clone();
close_node = close_node.move_to(iced::Point::new(limits.max().width - close_node_size.width - self.padding, self.padding));
let mut size_of_node = close_node.size().expand(Size::new(0.0, 4.0));
size_of_node.width = limits.max().width;
close_node = close_node.align(Alignment::Center, Alignment::Center, size_of_node);
layout::Node::with_children(size_of_node, vec![close_node])
}
}
}
fn draw(
&self,
state: &Tree,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
renderer.fill_quad(
Quad {
bounds: layout.bounds(),
border: Border {
color: Color::from_rgb(0.6, 0.93, 1.0),
width: 0.0,
radius: 0.0.into(),
},
shadow: Shadow::default(),
},
Color::from_rgb(0.0, 0.33, 0.4),
);
if self.close_button.is_some() {
self.close_button.as_ref().unwrap().as_widget().draw(
&state.children[0],
renderer,
theme,
style,
layout.children().next().unwrap(),
cursor,
viewport,
);
}
}
}
impl<'a, Message, Renderer> From<TitleBar<'a, Message, Renderer>> for Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Renderer: 'a + iced::advanced::Renderer,
{
fn from(widget: TitleBar<'a, Message, Renderer>) -> Self {
Self::new(widget)
}
}
And Application code:
impl Application for Editor {
type Executor = iced::executor::Default;
type Message = EditorMessage;
type Theme = iced::Theme;
type Flags = ();
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
(Self{}, Command::none())
}
fn title(&self) -> String {
"Gaia".into()
}
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
match message {
EditorMessage::Close => {
iced::window::close(iced::window::Id::MAIN)
}
_ => {
Command::none()
}
}
}
fn view(&self) -> Element<'_, Self::Message, Self::Theme, Renderer> {
TitleBar::new()
.with_close_button(
button("close")
.width(Length::Fixed(26_f32))
.height(Length::Fixed(26_f32))
.on_press(EditorMessage::Close)
.into()
).into()
}
}
Any help would be appreciated