use crate::{
input::{Event, EventStatus, MouseEventKind},
render::{Position, RenderContext, Size},
widget::{EventContext, LayoutInfo, RenderInfo, Widget},
};
pub struct Button<Message, Content, L, R>
where
Content: Widget<Message, LayoutInfo = L, RenderInfo = R>,
Message: Clone,
L: LayoutInfo,
R: RenderInfo,
{
content: Content,
on_click: Option<Message>,
is_pressing: bool,
}
impl<Message, Content, L, R> Button<Message, Content, L, R>
where
Content: Widget<Message, LayoutInfo = L, RenderInfo = R>,
Message: Clone,
L: LayoutInfo,
R: RenderInfo,
{
pub fn new(content: Content) -> Self {
Self {
content,
on_click: None,
is_pressing: false,
}
}
pub fn with_content(mut self, content: Content) -> Self {
self.content = content;
self
}
pub fn with_on_press(mut self, on_click: Option<Message>) -> Self {
self.on_click = on_click;
self
}
}
impl<Message, Content, L, R> Widget<Message> for Button<Message, Content, L, R>
where
Content: Widget<Message, LayoutInfo = L, RenderInfo = R>,
Message: Clone,
L: LayoutInfo,
R: RenderInfo,
{
type LayoutInfo = L;
type RenderInfo = R;
fn render(
&self,
position: Position,
layout_info: &Self::LayoutInfo,
context: &mut dyn RenderContext,
) -> std::io::Result<Self::RenderInfo> {
self.content.render(position, layout_info, context)
}
fn layout(&self, available_size: Size) -> Self::LayoutInfo {
self.content.layout(available_size)
}
fn on_event(
&mut self,
event: &Event,
render_info: &Self::RenderInfo,
event_context: &mut dyn EventContext<Message>,
) -> EventStatus {
if let Some(on_click) = self.on_click.clone() {
if let Event::Mouse(ref mouse_event) = event {
match mouse_event.kind {
MouseEventKind::Down(_) => {
let render_position = render_info.position();
let relative_position = mouse_event
.position
.offset_u16_negative(render_position.column, render_position.row);
if let Some(relative_position) = relative_position {
if render_info.bounds().contains(relative_position) {
self.is_pressing = true;
event_context.set_mouse_focus(true);
return EventStatus::Handled;
}
}
}
MouseEventKind::Up(_) => {
if self.is_pressing {
self.is_pressing = false;
event_context.set_mouse_focus(false);
event_context.emit_message(on_click);
return EventStatus::Handled;
}
}
_ => (),
}
}
}
self.content.on_event(event, render_info, event_context)
}
}