use std::cell::Cell;
use frui::{
api::events::{Event, WidgetEvent},
prelude::*,
};
const WIDTH: f64 = 60.0;
const HEIGHT: f64 = 60.0;
const COLOR: Color = Color::rgb8(255, 144, 54);
#[derive(SingleChildWidget)]
pub struct Button<L: Widget, F: Fn()> {
pub label: L,
pub on_click: F,
}
impl<L: Widget, F: Fn()> SingleChildWidget for Button<L, F> {
fn build<'w>(&'w self, _: BuildContext<'w, Self>) -> Self::Widget<'w> {
Center { child: &self.label }
}
fn layout(&self, ctx: RenderContext<Self>, _: Constraints) -> Size {
ctx.child().layout(Constraints {
min_width: 0.,
max_width: WIDTH,
min_height: 0.,
max_height: HEIGHT,
});
Size {
width: WIDTH,
height: HEIGHT,
}
}
fn paint(&self, ctx: RenderContext<Self>, canvas: &mut PaintContext, offset: &Offset) {
let color;
let hover_shade = 0.2;
if ctx.rstate().is_hovered.get() {
let (mut r, mut g, mut b, a) = COLOR.as_rgba8();
r = (r as f32 * (1. - hover_shade)) as u8;
g = (g as f32 * (1. - hover_shade)) as u8;
b = (b as f32 * (1. - hover_shade)) as u8;
color = Color::rgba8(r, g, b, a);
} else {
color = COLOR.clone();
}
let brush = &canvas.solid_brush(color);
PietRenderContext::fill(
canvas,
RoundedRect::new(offset.x, offset.y, offset.x + WIDTH, offset.y + HEIGHT, 15.),
brush,
);
ctx.child().paint(canvas, offset)
}
}
pub struct ButtonRenderState {
pub(crate) is_pressed: Cell<bool>,
pub(crate) is_hovered: Cell<bool>,
}
impl<L: Widget, F: Fn()> RenderState for Button<L, F> {
type State = ButtonRenderState;
fn create_state(&self) -> Self::State {
ButtonRenderState {
is_pressed: Cell::new(false),
is_hovered: Cell::new(false),
}
}
}
impl<L: Widget, F: Fn()> WidgetEvent for Button<L, F> {
fn handle_event(&self, ctx: RenderContext<Self>, event: &Event) -> bool {
match event {
Event::MouseDown(e) => {
if let MouseButton::Left = e.button {
if ctx.point_in_layout_bounds(e.pos) {
ctx.rstate().is_pressed.set(true);
}
}
}
Event::MouseUp(e) => {
if let MouseButton::Left = e.button {
if ctx.rstate().is_pressed.replace(false) {
(self.on_click)();
}
}
}
Event::MouseMove(e) => {
if ctx.point_in_layout_bounds(e.pos) {
if !ctx.rstate().is_hovered.replace(true) {
ctx.schedule_layout();
}
} else {
if ctx.rstate().is_hovered.replace(false) {
ctx.schedule_layout();
}
}
}
_ => {}
};
if let Event::MouseDown(_) | Event::MouseUp(_) | Event::MouseMove(_) = event {
true
} else {
false
}
}
}