4 releases
0.5.0 | Sep 21, 2024 |
---|---|
0.4.0 | Jan 21, 2024 |
0.4.0-rc.0 | Jan 20, 2024 |
#1221 in Rust patterns
342 downloads per month
Used in 2 crates
18KB
301 lines
whiskers-widgets
Part of the vsvg project.
What's this?
This crate implements the UI widget machinery used by the whiskers crate to display the sketch parameter UI.
lib.rs
:
Overview
This crate implements the UI widget machinery used by the whiskers
crate to display the sketch
parameter UI. The main entry point is the [trait@Widget
] trait and the associated macros defined
in whiskers-derive
.
This crate is separate from the main crate to allow other crates (including the vsvg
crate)
to implement the [trait@Widget
] trait for their own types.
Implementing the Widget
trait
For each supported sketch parameter type T
, there must exist a widget type that implements
Widget<T>
and is registered with register_widget_ui!
macro. This module include
the traits and macros needed to support this mechanism, as well as widgets for basic types.
For example, let's consider the [prim@bool
] type:
#[derive(Default)]
pub struct BoolWidget;
impl whiskers_widgets::Widget<bool> for BoolWidget {
fn ui(&self, ui: &mut egui::Ui, label: &str, value: &mut bool) -> egui::Response {
ui.horizontal(|_| {});
ui.checkbox(value, label)
}
}
whiskers_widgets::register_widget_ui!(bool, BoolWidget);
The BoolWidget
type implements the Widget<bool>
trait, which requires the Widget::ui
method, and is registered with the crate::register_widget_ui!
macro. Note that the
Widget::ui
method is called in the context of an 2-column egui::Grid
, so it must contain
exactly two top level UI calls, where the first one typically is the label, and the second the
actual interactive widget. In the case of a checkbox, the label is already embedded in the UI
widget, we leave the first column empty.
The BoolWidget
type is already provided by the crate
crate, but custom widgets can be
implemented for custom types using the same pattern.
Configuring widgets
Many widgets support additional configuration options, which can be set using the
#[param(...)]
attribute of the whiskers_derive::Sketch
macro. This is done by using the
builder pattern on the widget type. For example, here is an extract of NumericWidget
, which
supports numerical types such as [f64
] and [i32
]:
# use egui::emath::Numeric;
# use core::f64;
#[derive(Default)]
pub struct NumericWidget<T: Numeric> {
step: Option<T>,
slider: bool,
/* ... */
}
impl<T: Numeric> NumericWidget<T> {
pub fn step(mut self, step: T) -> Self {
self.step = Some(step);
self
}
pub fn slider(mut self, slider: bool) -> Self {
self.slider = slider;
self
}
}
impl<T: Numeric> whiskers_widgets::Widget<T> for NumericWidget<T> {
/* ... */
# fn ui(&self, ui: &mut egui::Ui, label: &str, value: &mut T) -> bool { todo!(); }
}
whiskers_widgets::register_widget_ui!(f64, NumericWidget<f64>);
/* ... */
# fn main() {}
Now let's consider a hypothetical sketch:
#[sketch_app]
#[derive(Default)]
struct MySketch {
#[param(slider, step = 0.1)]
irregularity: f64,
}
Based on the #[param(...)]
attributes, the whiskers_derive::Sketch
derive macro will
automatically generate the corresponding builder pattern calls:
whiskers_widgets::NumericWidget::<f64>::default().slider(true).step(0.1);
Note that when no value is provided for a key (such as slider
here), a boolean value of
true
is assumed.
Dependencies
~5–10MB
~109K SLoC