2021-01-01 16:11:05 +00:00
|
|
|
use super::*;
|
2020-12-29 12:40:11 +00:00
|
|
|
use egui::{color::*, *};
|
2020-09-13 19:54:31 +00:00
|
|
|
|
|
|
|
/// Showcase some ui code
|
2021-01-04 00:44:02 +00:00
|
|
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "persistence", serde(default))]
|
2021-05-09 08:53:35 +00:00
|
|
|
pub struct MiscDemoWindow {
|
2020-09-13 19:54:31 +00:00
|
|
|
num_columns: usize,
|
|
|
|
|
|
|
|
widgets: Widgets,
|
|
|
|
colors: ColorWidgets,
|
|
|
|
tree: Tree,
|
|
|
|
box_painting: BoxPainting,
|
|
|
|
}
|
|
|
|
|
2021-05-09 08:53:35 +00:00
|
|
|
impl Default for MiscDemoWindow {
|
|
|
|
fn default() -> MiscDemoWindow {
|
|
|
|
MiscDemoWindow {
|
2020-09-13 19:54:31 +00:00
|
|
|
num_columns: 2,
|
|
|
|
|
|
|
|
widgets: Default::default(),
|
|
|
|
colors: Default::default(),
|
|
|
|
tree: Tree::demo(),
|
|
|
|
box_painting: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-09 08:53:35 +00:00
|
|
|
impl Demo for MiscDemoWindow {
|
2021-02-20 08:18:23 +00:00
|
|
|
fn name(&self) -> &'static str {
|
2021-02-07 13:46:53 +00:00
|
|
|
"✨ Misc Demos"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
|
|
|
Window::new(self.name())
|
|
|
|
.open(open)
|
2021-08-28 11:18:21 +00:00
|
|
|
.vscroll(true)
|
|
|
|
.hscroll(true)
|
2021-02-07 13:46:53 +00:00
|
|
|
.show(ctx, |ui| self.ui(ui));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-09 08:53:35 +00:00
|
|
|
impl View for MiscDemoWindow {
|
2021-02-07 13:46:53 +00:00
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
2021-08-28 11:18:21 +00:00
|
|
|
ui.set_min_width(250.0);
|
|
|
|
|
2020-09-13 19:54:31 +00:00
|
|
|
CollapsingHeader::new("Widgets")
|
|
|
|
.default_open(true)
|
|
|
|
.show(ui, |ui| {
|
|
|
|
self.widgets.ui(ui);
|
|
|
|
});
|
|
|
|
|
|
|
|
CollapsingHeader::new("Colors")
|
2020-09-13 20:07:55 +00:00
|
|
|
.default_open(false)
|
2020-09-13 19:54:31 +00:00
|
|
|
.show(ui, |ui| {
|
|
|
|
self.colors.ui(ui);
|
|
|
|
});
|
|
|
|
|
|
|
|
CollapsingHeader::new("Tree")
|
|
|
|
.default_open(false)
|
|
|
|
.show(ui, |ui| self.tree.ui(ui));
|
|
|
|
|
|
|
|
ui.collapsing("Columns", |ui| {
|
2021-03-27 15:07:18 +00:00
|
|
|
ui.add(Slider::new(&mut self.num_columns, 1..=10).text("Columns"));
|
2020-09-13 19:54:31 +00:00
|
|
|
ui.columns(self.num_columns, |cols| {
|
|
|
|
for (i, col) in cols.iter_mut().enumerate() {
|
2020-12-10 09:15:25 +00:00
|
|
|
col.label(format!("Column {} out of {}", i + 1, self.num_columns));
|
2021-01-25 17:50:19 +00:00
|
|
|
if i + 1 == self.num_columns && col.button("Delete this").clicked() {
|
2020-09-13 19:54:31 +00:00
|
|
|
self.num_columns -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-10-07 07:59:49 +00:00
|
|
|
CollapsingHeader::new("Test box rendering")
|
|
|
|
.default_open(false)
|
|
|
|
.show(ui, |ui| self.box_painting.ui(ui));
|
2020-09-13 19:54:31 +00:00
|
|
|
|
|
|
|
CollapsingHeader::new("Resize")
|
|
|
|
.default_open(false)
|
|
|
|
.show(ui, |ui| {
|
|
|
|
Resize::default().default_height(100.0).show(ui, |ui| {
|
2020-10-10 11:04:40 +00:00
|
|
|
ui.label("This ui can be resized!");
|
|
|
|
ui.label("Just pull the handle on the bottom right");
|
2020-09-13 19:54:31 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
CollapsingHeader::new("Misc")
|
|
|
|
.default_open(false)
|
|
|
|
.show(ui, |ui| {
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("You can pretty easily paint your own small icons:");
|
2020-12-27 10:24:08 +00:00
|
|
|
use std::f32::consts::TAU;
|
2021-05-11 12:56:27 +00:00
|
|
|
let size = Vec2::splat(16.0);
|
|
|
|
let (response, painter) = ui.allocate_painter(size, Sense::hover());
|
|
|
|
let rect = response.rect;
|
2021-01-06 10:03:29 +00:00
|
|
|
let c = rect.center();
|
|
|
|
let r = rect.width() / 2.0 - 1.0;
|
2021-01-03 17:03:11 +00:00
|
|
|
let color = Color32::from_gray(128);
|
2020-09-13 19:54:31 +00:00
|
|
|
let stroke = Stroke::new(1.0, color);
|
|
|
|
painter.circle_stroke(c, r, stroke);
|
|
|
|
painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke);
|
|
|
|
painter.line_segment([c, c + r * Vec2::angled(TAU * 1.0 / 8.0)], stroke);
|
|
|
|
painter.line_segment([c, c + r * Vec2::angled(TAU * 3.0 / 8.0)], stroke);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2021-05-09 08:53:35 +00:00
|
|
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "persistence", serde(default))]
|
|
|
|
pub struct Widgets {
|
|
|
|
angle: f32,
|
|
|
|
password: String,
|
|
|
|
lock_focus: bool,
|
|
|
|
code_snippet: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Widgets {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
angle: std::f32::consts::TAU / 3.0,
|
|
|
|
password: "hunter2".to_owned(),
|
|
|
|
lock_focus: true,
|
|
|
|
code_snippet: "\
|
|
|
|
fn main() {
|
|
|
|
\tprintln!(\"Hello world!\");
|
|
|
|
}
|
|
|
|
"
|
|
|
|
.to_owned(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Widgets {
|
|
|
|
pub fn ui(&mut self, ui: &mut Ui) {
|
|
|
|
let Self {
|
|
|
|
angle,
|
|
|
|
password,
|
|
|
|
lock_focus,
|
|
|
|
code_snippet,
|
|
|
|
} = self;
|
|
|
|
ui.vertical_centered(|ui| {
|
|
|
|
ui.add(crate::__egui_github_link_file_line!());
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.horizontal_wrapped(|ui| {
|
|
|
|
// Trick so we don't have to add spaces in the text below:
|
|
|
|
ui.spacing_mut().item_spacing.x = ui.fonts()[TextStyle::Body].glyph_width(' ');
|
|
|
|
|
|
|
|
ui.add(Label::new("Text can have").text_color(Color32::from_rgb(110, 255, 110)));
|
|
|
|
ui.colored_label(Color32::from_rgb(128, 140, 255), "color"); // Shortcut version
|
|
|
|
ui.label("and tooltips.").on_hover_text(
|
|
|
|
"This is a multiline tooltip that demonstrates that you can easily add tooltips to any element.\nThis is the second line.\nThis is the third.",
|
|
|
|
);
|
|
|
|
|
|
|
|
ui.label("You can mix in other widgets into text, like");
|
|
|
|
let _ = ui.small_button("this button");
|
|
|
|
ui.label(".");
|
|
|
|
|
|
|
|
ui.label("The default font supports all latin and cyrillic characters (ИÅđ…), common math symbols (∫√∞²⅓…), and many emojis (💓🌟🖩…).")
|
|
|
|
.on_hover_text("There is currently no support for right-to-left languages.");
|
|
|
|
ui.label("See the 🔤 Font Book for more!");
|
|
|
|
|
|
|
|
ui.monospace("There is also a monospace font.");
|
|
|
|
});
|
|
|
|
|
|
|
|
let tooltip_ui = |ui: &mut Ui| {
|
|
|
|
ui.heading("The name of the tooltip");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("This tooltip was created with");
|
|
|
|
ui.monospace(".on_hover_ui(...)");
|
|
|
|
});
|
|
|
|
let _ = ui.button("A button you can never press");
|
|
|
|
};
|
|
|
|
ui.label("Tooltips can be more than just simple text.")
|
|
|
|
.on_hover_ui(tooltip_ui);
|
|
|
|
|
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("An angle:");
|
|
|
|
ui.drag_angle(angle);
|
|
|
|
ui.label(format!("≈ {:.3}τ", *angle / std::f32::consts::TAU))
|
|
|
|
.on_hover_text("Each τ represents one turn (τ = 2π)");
|
|
|
|
})
|
|
|
|
.response
|
|
|
|
.on_hover_text("The angle is stored in radians, but presented in degrees");
|
|
|
|
|
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.hyperlink_to("Password:", super::password::url_to_file_source_code())
|
|
|
|
.on_hover_text("See the example code for how to use egui to store UI state");
|
|
|
|
ui.add(super::password::password(password));
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("Code editor:");
|
|
|
|
|
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
ui.checkbox(lock_focus, "Lock focus").on_hover_text(
|
|
|
|
"When checked, pressing TAB will insert a tab instead of moving focus",
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.add(
|
|
|
|
TextEdit::multiline(code_snippet)
|
|
|
|
.code_editor()
|
|
|
|
.lock_focus(*lock_focus),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2021-01-04 00:44:02 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "persistence", serde(default))]
|
2020-09-13 19:54:31 +00:00
|
|
|
struct ColorWidgets {
|
|
|
|
srgba_unmul: [u8; 4],
|
|
|
|
srgba_premul: [u8; 4],
|
|
|
|
rgba_unmul: [f32; 4],
|
|
|
|
rgba_premul: [f32; 4],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ColorWidgets {
|
|
|
|
fn default() -> Self {
|
|
|
|
// Approximately the same color.
|
|
|
|
ColorWidgets {
|
|
|
|
srgba_unmul: [0, 255, 183, 127],
|
|
|
|
srgba_premul: [0, 187, 140, 127],
|
|
|
|
rgba_unmul: [0.0, 1.0, 0.5, 0.5],
|
|
|
|
rgba_premul: [0.0, 0.5, 0.25, 0.5],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ColorWidgets {
|
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
2021-01-02 22:28:10 +00:00
|
|
|
egui::reset_button(ui, self);
|
2020-09-13 19:54:31 +00:00
|
|
|
|
2021-01-17 13:48:59 +00:00
|
|
|
ui.label("egui lets you edit colors stored as either sRGBA or linear RGBA and with or without premultiplied alpha");
|
2020-09-13 19:54:31 +00:00
|
|
|
|
|
|
|
let Self {
|
|
|
|
srgba_unmul,
|
|
|
|
srgba_premul,
|
|
|
|
rgba_unmul,
|
|
|
|
rgba_premul,
|
|
|
|
} = self;
|
|
|
|
|
2020-09-18 21:41:02 +00:00
|
|
|
ui.horizontal(|ui| {
|
2020-09-13 19:54:31 +00:00
|
|
|
ui.color_edit_button_srgba_unmultiplied(srgba_unmul);
|
|
|
|
ui.label(format!(
|
|
|
|
"sRGBA: {} {} {} {}",
|
|
|
|
srgba_unmul[0], srgba_unmul[1], srgba_unmul[2], srgba_unmul[3],
|
|
|
|
));
|
|
|
|
});
|
|
|
|
|
2020-09-18 21:41:02 +00:00
|
|
|
ui.horizontal(|ui| {
|
2020-09-13 19:54:31 +00:00
|
|
|
ui.color_edit_button_srgba_premultiplied(srgba_premul);
|
|
|
|
ui.label(format!(
|
|
|
|
"sRGBA with premultiplied alpha: {} {} {} {}",
|
|
|
|
srgba_premul[0], srgba_premul[1], srgba_premul[2], srgba_premul[3],
|
|
|
|
));
|
|
|
|
});
|
|
|
|
|
2020-09-18 21:41:02 +00:00
|
|
|
ui.horizontal(|ui| {
|
2020-09-13 19:54:31 +00:00
|
|
|
ui.color_edit_button_rgba_unmultiplied(rgba_unmul);
|
|
|
|
ui.label(format!(
|
|
|
|
"Linear RGBA: {:.02} {:.02} {:.02} {:.02}",
|
|
|
|
rgba_unmul[0], rgba_unmul[1], rgba_unmul[2], rgba_unmul[3],
|
|
|
|
));
|
|
|
|
});
|
|
|
|
|
2020-09-18 21:41:02 +00:00
|
|
|
ui.horizontal(|ui| {
|
2020-09-13 19:54:31 +00:00
|
|
|
ui.color_edit_button_rgba_premultiplied(rgba_premul);
|
|
|
|
ui.label(format!(
|
|
|
|
"Linear RGBA with premultiplied alpha: {:.02} {:.02} {:.02} {:.02}",
|
|
|
|
rgba_premul[0], rgba_premul[1], rgba_premul[2], rgba_premul[3],
|
|
|
|
));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2021-01-04 00:44:02 +00:00
|
|
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "persistence", serde(default))]
|
2020-09-13 19:54:31 +00:00
|
|
|
struct BoxPainting {
|
|
|
|
size: Vec2,
|
|
|
|
corner_radius: f32,
|
|
|
|
stroke_width: f32,
|
|
|
|
num_boxes: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for BoxPainting {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2020-12-26 00:38:26 +00:00
|
|
|
size: vec2(64.0, 32.0),
|
2020-09-13 19:54:31 +00:00
|
|
|
corner_radius: 5.0,
|
|
|
|
stroke_width: 2.0,
|
|
|
|
num_boxes: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BoxPainting {
|
|
|
|
pub fn ui(&mut self, ui: &mut Ui) {
|
2021-03-27 15:07:18 +00:00
|
|
|
ui.add(Slider::new(&mut self.size.x, 0.0..=500.0).text("width"));
|
|
|
|
ui.add(Slider::new(&mut self.size.y, 0.0..=500.0).text("height"));
|
|
|
|
ui.add(Slider::new(&mut self.corner_radius, 0.0..=50.0).text("corner_radius"));
|
|
|
|
ui.add(Slider::new(&mut self.stroke_width, 0.0..=10.0).text("stroke_width"));
|
|
|
|
ui.add(Slider::new(&mut self.num_boxes, 0..=8).text("num_boxes"));
|
2020-12-26 00:38:26 +00:00
|
|
|
|
|
|
|
ui.horizontal_wrapped(|ui| {
|
|
|
|
for _ in 0..self.num_boxes {
|
2021-01-06 10:03:29 +00:00
|
|
|
let (rect, _response) = ui.allocate_at_least(self.size, Sense::hover());
|
2020-12-26 00:38:26 +00:00
|
|
|
ui.painter().rect(
|
2021-01-06 10:03:29 +00:00
|
|
|
rect,
|
2020-12-26 00:38:26 +00:00
|
|
|
self.corner_radius,
|
2021-01-03 17:03:11 +00:00
|
|
|
Color32::from_gray(64),
|
2021-01-02 16:18:41 +00:00
|
|
|
Stroke::new(self.stroke_width, Color32::WHITE),
|
2020-12-26 00:38:26 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2020-09-13 19:54:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, PartialEq)]
|
|
|
|
enum Action {
|
|
|
|
Keep,
|
|
|
|
Delete,
|
|
|
|
}
|
|
|
|
|
2021-01-04 00:44:02 +00:00
|
|
|
#[derive(Clone, Default)]
|
|
|
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
2021-08-20 17:04:13 +00:00
|
|
|
struct Tree(String, SubTree);
|
2020-09-13 19:54:31 +00:00
|
|
|
|
|
|
|
impl Tree {
|
|
|
|
pub fn demo() -> Self {
|
2021-08-20 17:04:13 +00:00
|
|
|
Self(
|
|
|
|
String::from("root"),
|
|
|
|
SubTree(vec![
|
|
|
|
SubTree(vec![SubTree::default(); 4]),
|
|
|
|
SubTree(vec![SubTree(vec![SubTree::default(); 2]); 3]),
|
|
|
|
]),
|
|
|
|
)
|
2020-09-13 19:54:31 +00:00
|
|
|
}
|
|
|
|
pub fn ui(&mut self, ui: &mut Ui) -> Action {
|
2021-08-20 17:04:13 +00:00
|
|
|
self.1.ui(ui, 0, "root", &mut self.0)
|
2020-09-13 19:54:31 +00:00
|
|
|
}
|
2021-08-20 17:04:13 +00:00
|
|
|
}
|
2020-09-13 19:54:31 +00:00
|
|
|
|
2021-08-20 17:04:13 +00:00
|
|
|
#[derive(Clone, Default)]
|
|
|
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
struct SubTree(Vec<SubTree>);
|
|
|
|
|
|
|
|
impl SubTree {
|
|
|
|
pub fn ui(
|
|
|
|
&mut self,
|
|
|
|
ui: &mut Ui,
|
|
|
|
depth: usize,
|
|
|
|
name: &str,
|
|
|
|
selected_name: &mut String,
|
|
|
|
) -> Action {
|
|
|
|
let response = CollapsingHeader::new(name)
|
2020-09-13 19:54:31 +00:00
|
|
|
.default_open(depth < 1)
|
2021-08-20 17:04:13 +00:00
|
|
|
.selectable(true)
|
|
|
|
.selected(selected_name.as_str() == name)
|
|
|
|
.show(ui, |ui| self.children_ui(ui, name, depth, selected_name));
|
|
|
|
if response.header_response.clicked() {
|
|
|
|
*selected_name = name.to_string();
|
|
|
|
}
|
|
|
|
response.body_returned.unwrap_or(Action::Keep)
|
2020-09-13 19:54:31 +00:00
|
|
|
}
|
|
|
|
|
2021-08-20 17:04:13 +00:00
|
|
|
fn children_ui(
|
|
|
|
&mut self,
|
|
|
|
ui: &mut Ui,
|
|
|
|
parent_name: &str,
|
|
|
|
depth: usize,
|
|
|
|
selected_name: &mut String,
|
|
|
|
) -> Action {
|
2021-01-02 16:18:41 +00:00
|
|
|
if depth > 0
|
|
|
|
&& ui
|
|
|
|
.add(Button::new("delete").text_color(Color32::RED))
|
2021-01-25 17:50:19 +00:00
|
|
|
.clicked()
|
2021-01-02 16:18:41 +00:00
|
|
|
{
|
2020-09-13 19:54:31 +00:00
|
|
|
return Action::Delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.0 = std::mem::take(self)
|
|
|
|
.0
|
|
|
|
.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.filter_map(|(i, mut tree)| {
|
2021-08-20 17:04:13 +00:00
|
|
|
if tree.ui(
|
|
|
|
ui,
|
|
|
|
depth + 1,
|
|
|
|
&format!("{}/{}", parent_name, i),
|
|
|
|
selected_name,
|
|
|
|
) == Action::Keep
|
|
|
|
{
|
2020-09-13 19:54:31 +00:00
|
|
|
Some(tree)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2021-01-25 17:50:19 +00:00
|
|
|
if ui.button("+").clicked() {
|
2021-08-20 17:04:13 +00:00
|
|
|
self.0.push(SubTree::default());
|
2020-09-13 19:54:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Action::Keep
|
|
|
|
}
|
|
|
|
}
|