use std::{io::Error, marker::PhantomData};
use crate::{
input::{Event, EventStatus},
render::{Margin, Position, RenderContext, Size},
widget::{EventContext, LayoutInfo, RenderInfo, Widget},
};
pub struct Wrapper<Message, Content, L, R>
where
Content: Widget<Message, LayoutInfo = L, RenderInfo = R>,
L: LayoutInfo,
R: RenderInfo,
{
content: Content,
phantom_message: PhantomData<Message>,
padding: Margin,
}
pub struct WrapperLayout<L: LayoutInfo> {
padding: Margin,
child_layout: L,
}
impl<L: LayoutInfo> LayoutInfo for WrapperLayout<L> {
fn bounds(&self) -> Size {
self.child_layout.bounds().add_margin(&self.padding)
}
}
impl<Message, Content, L, R> Wrapper<Message, Content, L, R>
where
Content: Widget<Message, LayoutInfo = L, RenderInfo = R>,
L: LayoutInfo,
R: RenderInfo,
{
pub fn new(content: Content) -> Self {
Self {
content,
phantom_message: PhantomData,
padding: Margin::default(),
}
}
pub fn with_padding(mut self, padding: Margin) -> Self {
self.padding = padding;
self
}
}
impl<Message, Content, L, R> Widget<Message> for Wrapper<Message, Content, L, R>
where
Content: Widget<Message, LayoutInfo = L, RenderInfo = R>,
L: LayoutInfo,
R: RenderInfo,
{
type LayoutInfo = WrapperLayout<L>;
type RenderInfo = R;
fn render(
&self,
position: Position,
layout: &Self::LayoutInfo,
context: &mut dyn RenderContext,
) -> std::io::Result<Self::RenderInfo> {
let position = position.offset_u16(self.padding.left(), self.padding.top());
if let Some(position) = position {
self.content.render(position, &layout.child_layout, context)
} else {
Err(Error::other("Invalid position"))
}
}
fn layout(&self, available_size: Size) -> Self::LayoutInfo {
let available_size = available_size.sub_margin(&self.padding);
let child_layout = self.content.layout(available_size);
WrapperLayout {
child_layout,
padding: self.padding.clone(),
}
}
fn on_event(
&mut self,
event: &Event,
render_info: &Self::RenderInfo,
event_context: &mut dyn EventContext<Message>,
) -> EventStatus {
self.content.on_event(event, render_info, event_context)
}
}