use druid::kurbo::{Affine, BezPath};
use druid::widget::prelude::*;
use druid::widget::{BackgroundBrush, Painter};
use druid::{Data, Point, Size, Widget};
pub struct Icon {
pub width: u32,
pub height: u32,
pub path: &'static str,
}
impl Icon {
pub fn to_custom_widget<T>(&self, brush: impl Into<BackgroundBrush<T>>) -> IconWidget<T> {
IconWidget::from_icon(self, brush)
}
pub fn to_widget(&self) -> IconWidget<bool> {
let icon_painter = move |ctx: &mut PaintCtx, on: &bool, env: &Env| {
let color = if *on {
env.get(crate::BUTTON_ICON_SELECTED_COLOR)
} else {
env.get(crate::BUTTON_ICON_COLOR)
};
let rect = ctx.size().to_rect();
let rect = ctx
.current_transform()
.inverse()
.transform_rect_bbox(rect)
.with_origin(Point::ZERO);
ctx.fill(rect, &color);
};
self.to_custom_widget(Painter::new(icon_painter))
}
}
pub struct IconWidget<T> {
path: BezPath,
size: Size,
brush: BackgroundBrush<T>,
}
impl<T> IconWidget<T> {
pub fn from_icon(icon: &Icon, brush: impl Into<BackgroundBrush<T>>) -> Self {
IconWidget {
path: BezPath::from_svg(icon.path).unwrap(),
size: Size::new(icon.width as f64, icon.height as f64),
brush: brush.into(),
}
}
}
impl<T: Data> Widget<T> for IconWidget<T> {
fn event(&mut self, _: &mut EventCtx, _: &Event, _: &mut T, _: &Env) {}
fn lifecycle(&mut self, _: &mut LifeCycleCtx, _: &LifeCycle, _: &T, _: &Env) {}
fn update(&mut self, ctx: &mut UpdateCtx, _: &T, _: &T, _: &Env) {
ctx.request_paint();
}
fn layout(&mut self, _: &mut LayoutCtx, bc: &BoxConstraints, _: &T, _: &Env) -> Size {
let max = bc.max();
let width_frac = max.width / self.size.width;
let height_frac = max.height / self.size.height;
let scale = width_frac.min(height_frac);
self.size * scale
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
let scale = ctx.size().width / self.size.width;
ctx.with_save(|ctx| {
ctx.transform(Affine::scale(scale));
ctx.clip(&self.path);
self.brush.paint(ctx, data, env);
});
}
}