2020-08-31 05:55:07 +00:00
|
|
|
//! Source code example of how to create your own widget.
|
2020-09-11 15:17:43 +00:00
|
|
|
//! This is meant to be read as a tutorial, hence the plethora of comments.
|
2020-08-31 05:55:07 +00:00
|
|
|
|
2020-09-11 15:17:43 +00:00
|
|
|
/// iOS-style toggle switch:
|
|
|
|
///
|
|
|
|
/// ``` text
|
|
|
|
/// _____________
|
|
|
|
/// / /.....\
|
|
|
|
/// | |.......|
|
|
|
|
/// \_______\_____/
|
|
|
|
/// ```
|
2021-02-20 10:58:08 +00:00
|
|
|
///
|
|
|
|
/// ## Example:
|
|
|
|
/// ``` ignore
|
|
|
|
/// toggle_ui(ui, &mut my_bool);
|
|
|
|
/// ```
|
|
|
|
pub fn toggle_ui(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
2020-09-11 15:17:43 +00:00
|
|
|
// Widget code can be broken up in four steps:
|
|
|
|
// 1. Decide a size for the widget
|
|
|
|
// 2. Allocate space for it
|
|
|
|
// 3. Handle interactions with the widget (if any)
|
|
|
|
// 4. Paint the widget
|
|
|
|
|
|
|
|
// 1. Deciding widget size:
|
|
|
|
// You can query the `ui` how much space is available,
|
2021-02-20 10:28:00 +00:00
|
|
|
// but in this example we have a fixed size widget based on the height of a standard button:
|
|
|
|
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0);
|
2020-09-11 15:17:43 +00:00
|
|
|
|
|
|
|
// 2. Allocating space:
|
2020-12-26 18:14:13 +00:00
|
|
|
// This is where we get a region of the screen assigned.
|
|
|
|
// We also tell the Ui to sense clicks in the allocated region.
|
2021-02-28 16:17:37 +00:00
|
|
|
let (rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
|
2021-03-07 18:32:27 +00:00
|
|
|
if response.gained_kb_focus() {
|
|
|
|
// Inform accessibility systems that the widget is selected:
|
|
|
|
ui.output()
|
|
|
|
.push_gained_focus_event(egui::WidgetType::Checkbox, "");
|
|
|
|
}
|
2020-08-31 05:55:07 +00:00
|
|
|
|
2021-02-28 16:17:37 +00:00
|
|
|
// 3. Interact: Time to check for clicks!
|
2021-01-25 17:50:19 +00:00
|
|
|
if response.clicked() {
|
2020-08-31 05:55:07 +00:00
|
|
|
*on = !*on;
|
2021-02-28 16:17:37 +00:00
|
|
|
response.mark_changed(); // report back that the value changed
|
2020-08-31 05:55:07 +00:00
|
|
|
}
|
|
|
|
|
2020-09-11 15:17:43 +00:00
|
|
|
// 4. Paint!
|
2021-01-17 13:48:59 +00:00
|
|
|
// First let's ask for a simple animation from egui.
|
|
|
|
// egui keeps track of changes in the boolean associated with the id and
|
2020-09-11 15:17:43 +00:00
|
|
|
// returns an animated value in the 0-1 range for how much "on" we are.
|
2020-12-26 18:14:13 +00:00
|
|
|
let how_on = ui.ctx().animate_bool(response.id, *on);
|
2020-09-11 15:17:43 +00:00
|
|
|
// We will follow the current style by asking
|
2020-08-31 05:55:07 +00:00
|
|
|
// "how should something that is being interacted with be painted?".
|
2020-09-11 15:17:43 +00:00
|
|
|
// This will, for instance, give us different colors when the widget is hovered or clicked.
|
2021-02-20 10:28:00 +00:00
|
|
|
let visuals = ui.style().interact_selectable(&response, *on);
|
2020-09-11 15:17:43 +00:00
|
|
|
// All coordinates are in absolute screen coordinates so we use `rect` to place the elements.
|
2021-01-12 19:50:54 +00:00
|
|
|
let rect = rect.expand(visuals.expansion);
|
2020-08-31 05:55:07 +00:00
|
|
|
let radius = 0.5 * rect.height();
|
2021-02-20 10:28:00 +00:00
|
|
|
ui.painter()
|
|
|
|
.rect(rect, radius, visuals.bg_fill, visuals.bg_stroke);
|
2020-09-11 15:17:43 +00:00
|
|
|
// Paint the circle, animating it from left to right with `how_on`:
|
2020-12-29 12:40:11 +00:00
|
|
|
let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on);
|
|
|
|
let center = egui::pos2(circle_x, rect.center().y);
|
2020-10-10 04:52:33 +00:00
|
|
|
ui.painter()
|
2021-01-15 21:20:26 +00:00
|
|
|
.circle(center, 0.75 * radius, visuals.bg_fill, visuals.fg_stroke);
|
2020-08-31 05:55:07 +00:00
|
|
|
|
2020-09-11 15:17:43 +00:00
|
|
|
// All done! Return the interaction response so the user can check what happened
|
|
|
|
// (hovered, clicked, ...) and maybe show a tooltip:
|
2020-08-31 05:55:07 +00:00
|
|
|
response
|
|
|
|
}
|
|
|
|
|
2020-10-10 10:33:48 +00:00
|
|
|
/// Here is the same code again, but a bit more compact:
|
|
|
|
#[allow(dead_code)]
|
2021-02-20 10:58:08 +00:00
|
|
|
fn toggle_ui_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
2021-02-20 10:28:00 +00:00
|
|
|
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0);
|
2021-02-28 16:17:37 +00:00
|
|
|
let (rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
|
2021-03-07 18:32:27 +00:00
|
|
|
if response.gained_kb_focus() {
|
|
|
|
ui.output()
|
|
|
|
.push_gained_focus_event(egui::WidgetType::Checkbox, "");
|
|
|
|
}
|
2021-02-28 16:17:37 +00:00
|
|
|
if response.clicked() {
|
|
|
|
*on = !*on;
|
|
|
|
response.mark_changed();
|
|
|
|
}
|
2020-10-10 10:33:48 +00:00
|
|
|
|
2020-12-26 18:14:13 +00:00
|
|
|
let how_on = ui.ctx().animate_bool(response.id, *on);
|
2021-02-20 10:28:00 +00:00
|
|
|
let visuals = ui.style().interact_selectable(&response, *on);
|
2021-01-12 19:50:54 +00:00
|
|
|
let rect = rect.expand(visuals.expansion);
|
2020-10-10 10:33:48 +00:00
|
|
|
let radius = 0.5 * rect.height();
|
2021-02-20 10:28:00 +00:00
|
|
|
ui.painter()
|
|
|
|
.rect(rect, radius, visuals.bg_fill, visuals.bg_stroke);
|
2020-12-29 12:40:11 +00:00
|
|
|
let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on);
|
|
|
|
let center = egui::pos2(circle_x, rect.center().y);
|
2020-10-10 10:33:48 +00:00
|
|
|
ui.painter()
|
2021-01-15 21:20:26 +00:00
|
|
|
.circle(center, 0.75 * radius, visuals.bg_fill, visuals.fg_stroke);
|
2020-10-10 10:33:48 +00:00
|
|
|
|
|
|
|
response
|
|
|
|
}
|
|
|
|
|
2021-02-20 10:58:08 +00:00
|
|
|
// 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)
|
2020-08-31 05:55:07 +00:00
|
|
|
}
|
2021-02-20 11:07:15 +00:00
|
|
|
|
|
|
|
pub fn url_to_file_source_code() -> String {
|
|
|
|
format!("https://github.com/emilk/egui/blob/master/{}", file!())
|
|
|
|
}
|