use cushy::animation::easings::StandardEasing; use cushy::context::GraphicsContext; use cushy::widget::{MakeWidget, WidgetList}; use cushy::widgets::Canvas; use cushy::Run; use easing_function::Easing; use figures::units::{Lp, Px}; use figures::{IntoSigned, Point, Rect, Size, Zero}; use kludgine::shapes::{PathBuilder, Shape, StrokeOptions}; fn main() -> cushy::Result { StandardEasing::all() .iter() .map(|easing| { let name = format!("Ease{easing:?}"); Canvas::new(|context| { draw_easing_graph(easing, context); }) .expand() .and(name) .into_rows() .contain() .make_widget() }) .collect::>() .chunks(3) .map(|widgets| { WidgetList::from_iter(widgets.iter().map(|w| w.clone().expand())) .into_columns() .height(Lp::inches(3)) }) .collect::() .into_wrap() .pad() .vertical_scroll() .expand() .run() } fn draw_easing_graph(easing: &StandardEasing, context: &mut GraphicsContext<'_, '_, '_, '_>) { let height = context.gfx.size().height.into_signed(); let padding = height / 4; let height = height - padding * 2; let width = context.gfx.size().width.into_signed().get(); let steps = width.max(50); let mut path = PathBuilder::new(Point::new( Px::ZERO, padding + height * (1.0 - easing.ease(0.)), )); for i in 1..=steps { path = path.line_to(Point::new( Px::new(width * i) / steps, padding + height * (1.0 - easing.ease(i as f32 / steps as f32)), )); } let text_color = context.theme().surface.on_color; let bg = context.theme().surface.low_container; let outline = context.theme().surface.outline; context.gfx.draw_shape(&Shape::filled_rect( Rect::new( Point::new(Px::ZERO, padding), Size::new(Px::new(width), height), ), bg, )); context.gfx.draw_shape(&Shape::stroked_rect( Rect::new( Point::new(Px::ZERO, padding), Size::new(Px::new(width), height), ), outline, )); context.gfx.draw_shape( &path .build() .stroke(StrokeOptions::px_wide(1).colored(text_color)), ); }