diff --git a/egui/src/style.rs b/egui/src/style.rs index c9ca5785..2c1807f4 100644 --- a/egui/src/style.rs +++ b/egui/src/style.rs @@ -506,10 +506,10 @@ impl Spacing { tooltip_width, } = self; - ui_slider_vec2(ui, item_spacing, 0.0..=10.0, "item_spacing"); - ui_slider_vec2(ui, window_padding, 0.0..=10.0, "window_padding"); - ui_slider_vec2(ui, button_padding, 0.0..=10.0, "button_padding"); - ui_slider_vec2(ui, interact_size, 0.0..=60.0, "interact_size") + ui.add(slider_vec2(item_spacing, 0.0..=10.0, "item_spacing")); + ui.add(slider_vec2(window_padding, 0.0..=10.0, "window_padding")); + ui.add(slider_vec2(button_padding, 0.0..=10.0, "button_padding")); + ui.add(slider_vec2(interact_size, 0.0..=60.0, "interact_size")) .on_hover_text("Minimum size of an interactive widget"); ui.add(Slider::f32(indent, 0.0..=100.0).text("indent")); ui.add(Slider::f32(slider_width, 0.0..=1000.0).text("slider_width")); @@ -694,38 +694,20 @@ impl Visuals { } } -// TODO: improve and standardize ui_slider_vec2 -fn ui_slider_vec2( - ui: &mut Ui, - value: &mut Vec2, +// TODO: improve and standardize `slider_vec2` +fn slider_vec2<'a>( + value: &'a mut Vec2, range: std::ops::RangeInclusive, - text: &str, -) -> Response { - ui.horizontal(|ui| { - /* - let fsw = full slider_width - let ssw = small slider_width - let space = item_spacing.x - let value = interact_size.x; - - fsw + space + value = ssw + space + value + space + ssw + space + value - fsw + space + value = 2 * ssw + 3 * space + 2 * value - fsw + space - value = 2 * ssw + 3 * space - fsw - 2 * space - value = 2 * ssw - ssw = fsw / 2 - space - value / 2 - */ - // let spacing = &ui.spacing(); - // let space = spacing.item_spacing.x; - // let value_w = spacing.interact_size.x; - // let full_slider_width = spacing.slider_width; - // let small_slider_width = full_slider_width / 2.0 - space - value_w / 2.0; - // ui.spacing_mut().slider_width = small_slider_width; - - ui.add(Slider::f32(&mut value.x, range.clone()).text("w")); - ui.add(Slider::f32(&mut value.y, range.clone()).text("h")); - ui.label(text); - }) - .response + text: &'a str, +) -> impl Widget + 'a { + move |ui: &mut crate::Ui| { + ui.horizontal(|ui| { + ui.add(Slider::f32(&mut value.x, range.clone()).text("w")); + ui.add(Slider::f32(&mut value.y, range.clone()).text("h")); + ui.label(text); + }) + .response + } } fn ui_color(ui: &mut Ui, srgba: &mut Color32, text: &str) { diff --git a/egui/src/widgets/mod.rs b/egui/src/widgets/mod.rs index fe1c3fd9..60ca48eb 100644 --- a/egui/src/widgets/mod.rs +++ b/egui/src/widgets/mod.rs @@ -35,6 +35,31 @@ pub trait Widget { fn ui(self, ui: &mut Ui) -> Response; } +/// This enables functions that return `impl Widget`, so that you can +/// create a widget by just returning a lambda from a function. +/// +/// For instance: `ui.add(slider_vec2(&mut vec2));` with: +/// +/// ``` +/// pub fn slider_vec2(value: &mut egui::Vec2) -> impl egui::Widget + '_ { +/// move |ui: &mut egui::Ui| { +/// ui.horizontal(|ui| { +/// ui.add(egui::Slider::f32(&mut value.x, 0.0..=1.0).text("x")); +/// ui.add(egui::Slider::f32(&mut value.y, 0.0..=1.0).text("y")); +/// }) +/// .response +/// } +/// } +/// ``` +impl Widget for F +where + F: FnOnce(&mut Ui) -> Response, +{ + fn ui(self, ui: &mut Ui) -> Response { + self(ui) + } +} + // ---------------------------------------------------------------------------- /// Show a button to reset a value to its default. diff --git a/egui_demo_lib/src/apps/demo/toggle_switch.rs b/egui_demo_lib/src/apps/demo/toggle_switch.rs index 920f29ee..307422bd 100644 --- a/egui_demo_lib/src/apps/demo/toggle_switch.rs +++ b/egui_demo_lib/src/apps/demo/toggle_switch.rs @@ -9,7 +9,12 @@ /// | |.......| /// \_______\_____/ /// ``` -pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { +/// +/// ## Example: +/// ``` ignore +/// toggle_ui(ui, &mut my_bool); +/// ``` +pub fn toggle_ui(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { // Widget code can be broken up in four steps: // 1. Decide a size for the widget // 2. Allocate space for it @@ -58,7 +63,7 @@ pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { /// Here is the same code again, but a bit more compact: #[allow(dead_code)] -fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { +fn toggle_ui_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0); let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::click()); *on ^= response.clicked(); // toggle if clicked @@ -77,14 +82,13 @@ fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { response } -pub fn demo(ui: &mut egui::Ui, on: &mut bool) { - ui.horizontal_wrapped_for_text(egui::TextStyle::Button, |ui| { - toggle(ui, on).on_hover_text("Click to toggle"); - ui.add(crate::__egui_github_link_file!()); - }) - .response - .on_hover_text( - "It's easy to create your own widgets!\n\ - This toggle switch is just one function and 15 lines of code.", - ); +// A wrapper that allows the more idiomatic usage pattern: `ui.add(toggle(&mut my_bool))` +/// iOS-style toggle switch. +/// +/// ## Example: +/// ``` ignore +/// ui.add(toggle(&mut my_bool)); +/// ``` +pub fn toggle(on: &mut bool) -> impl egui::Widget + '_ { + move |ui: &mut egui::Ui| toggle_ui(ui, on) } diff --git a/egui_demo_lib/src/apps/demo/widget_gallery.rs b/egui_demo_lib/src/apps/demo/widget_gallery.rs index c316c1cf..d48f9e9d 100644 --- a/egui_demo_lib/src/apps/demo/widget_gallery.rs +++ b/egui_demo_lib/src/apps/demo/widget_gallery.rs @@ -156,7 +156,10 @@ impl super::View for WidgetGallery { ui.end_row(); ui.label("Custom widget:"); - super::toggle_switch::demo(ui, boolean); + ui.add(super::toggle_switch::toggle(boolean)).on_hover_text( + "It's easy to create your own widgets!\n\ + This toggle switch is just 15 lines of code.", + ); ui.end_row(); ui.label("Plot:");