Create foldable areas
This commit is contained in:
parent
500312e878
commit
52eb5bdf2c
5 changed files with 146 additions and 7 deletions
|
@ -75,10 +75,11 @@ impl GuiSettings for App {
|
||||||
}),
|
}),
|
||||||
}]));
|
}]));
|
||||||
|
|
||||||
gui.label("LayoutOptions:");
|
gui.foldable("LayoutOptions", |gui| {
|
||||||
let mut layout_options = gui.layout_options;
|
let mut layout_options = gui.layout_options;
|
||||||
layout_options.show_gui(gui);
|
layout_options.show_gui(gui);
|
||||||
gui.layout_options = layout_options;
|
gui.layout_options = layout_options;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{math::*, types::*};
|
use crate::{math::*, types::*};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -7,6 +9,9 @@ pub struct LayoutOptions {
|
||||||
// Horizontal and vertical spacing between widgets
|
// Horizontal and vertical spacing between widgets
|
||||||
pub item_spacing: Vec2,
|
pub item_spacing: Vec2,
|
||||||
|
|
||||||
|
/// Indent foldable regions etc by this much.
|
||||||
|
pub indent: f32,
|
||||||
|
|
||||||
/// Default width of buttons, sliders etc
|
/// Default width of buttons, sliders etc
|
||||||
pub width: f32,
|
pub width: f32,
|
||||||
|
|
||||||
|
@ -24,6 +29,7 @@ impl Default for LayoutOptions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LayoutOptions {
|
LayoutOptions {
|
||||||
item_spacing: Vec2 { x: 8.0, y: 4.0 },
|
item_spacing: Vec2 { x: 8.0, y: 4.0 },
|
||||||
|
indent: 21.0,
|
||||||
width: 200.0,
|
width: 200.0,
|
||||||
button_height: 24.0,
|
button_height: 24.0,
|
||||||
checkbox_radio_height: 24.0,
|
checkbox_radio_height: 24.0,
|
||||||
|
@ -34,10 +40,13 @@ impl Default for LayoutOptions {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
/// The widget being interacted with (e.g. dragged, in case of a slider).
|
/// The widget being interacted with (e.g. dragged, in case of a slider).
|
||||||
pub active_id: Option<Id>,
|
pub active_id: Option<Id>,
|
||||||
|
|
||||||
|
/// Which foldable regions are open.
|
||||||
|
open_foldables: HashSet<Id>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -186,6 +195,57 @@ impl Layout {
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Areas:
|
||||||
|
|
||||||
|
pub fn foldable<S, F>(&mut self, label: S, add_contents: F) -> InteractInfo
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
F: FnOnce(&mut Layout),
|
||||||
|
{
|
||||||
|
let label: String = label.into();
|
||||||
|
let id = self.get_id(&label);
|
||||||
|
|
||||||
|
let rect = Rect {
|
||||||
|
pos: self.cursor,
|
||||||
|
size: Vec2 {
|
||||||
|
x: self.layout_options.width,
|
||||||
|
y: self.layout_options.button_height,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let interact = self.interactive_rect(id, &rect);
|
||||||
|
self.cursor.y += rect.size.y + self.layout_options.item_spacing.y;
|
||||||
|
|
||||||
|
if interact.clicked {
|
||||||
|
if self.state.open_foldables.contains(&id) {
|
||||||
|
self.state.open_foldables.remove(&id);
|
||||||
|
} else {
|
||||||
|
self.state.open_foldables.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let open = self.state.open_foldables.contains(&id);
|
||||||
|
|
||||||
|
self.commands.push(GuiCmd::FoldableHeader {
|
||||||
|
interact,
|
||||||
|
rect,
|
||||||
|
label,
|
||||||
|
open,
|
||||||
|
});
|
||||||
|
|
||||||
|
if open {
|
||||||
|
// TODO: push/pop id stack
|
||||||
|
let old_x = self.cursor.x;
|
||||||
|
self.cursor.x += self.layout_options.indent;
|
||||||
|
add_contents(self);
|
||||||
|
self.cursor.x = old_x;
|
||||||
|
|
||||||
|
// TODO: paint background?
|
||||||
|
}
|
||||||
|
|
||||||
|
interact
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
fn interactive_rect(&mut self, id: Id, rect: &Rect) -> InteractInfo {
|
fn interactive_rect(&mut self, id: Id, rect: &Rect) -> InteractInfo {
|
||||||
|
|
|
@ -52,9 +52,10 @@ pub fn show_gui(raw_input_json: &str) -> String {
|
||||||
use crate::app::GuiSettings;
|
use crate::app::GuiSettings;
|
||||||
APP.lock().unwrap().show_gui(&mut emgui.layout);
|
APP.lock().unwrap().show_gui(&mut emgui.layout);
|
||||||
|
|
||||||
emgui.layout.label("Style:");
|
|
||||||
let mut style = emgui.style.clone();
|
let mut style = emgui.style.clone();
|
||||||
style.show_gui(&mut emgui.layout);
|
emgui.layout.foldable("Style", |gui| {
|
||||||
|
style.show_gui(gui);
|
||||||
|
});
|
||||||
emgui.style = style;
|
emgui.style = style;
|
||||||
|
|
||||||
let commands = emgui.paint();
|
let commands = emgui.paint();
|
||||||
|
|
70
src/style.rs
70
src/style.rs
|
@ -142,6 +142,76 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
|
||||||
out_commands.push(debug_rect(rect));
|
out_commands.push(debug_rect(rect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GuiCmd::FoldableHeader {
|
||||||
|
interact,
|
||||||
|
label,
|
||||||
|
open,
|
||||||
|
rect,
|
||||||
|
} => {
|
||||||
|
let fill_color = if interact.active {
|
||||||
|
srgba(136, 136, 136, 255)
|
||||||
|
} else if interact.hovered {
|
||||||
|
srgba(100, 100, 100, 255)
|
||||||
|
} else {
|
||||||
|
srgba(68, 68, 68, 255)
|
||||||
|
};
|
||||||
|
|
||||||
|
let stroke_color = if interact.active {
|
||||||
|
srgba(255, 255, 255, 255)
|
||||||
|
} else if interact.hovered {
|
||||||
|
srgba(255, 255, 255, 200)
|
||||||
|
} else {
|
||||||
|
srgba(255, 255, 255, 170)
|
||||||
|
};
|
||||||
|
|
||||||
|
out_commands.push(PaintCmd::Rect {
|
||||||
|
corner_radius: 3.0,
|
||||||
|
fill_color: Some(fill_color),
|
||||||
|
outline: None,
|
||||||
|
pos: rect.pos,
|
||||||
|
size: rect.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: paint a little triangle or arrow or something instead of this
|
||||||
|
|
||||||
|
let box_side = 16.0;
|
||||||
|
let box_rect = Rect::from_center_size(
|
||||||
|
vec2(rect.min().x + box_side * 0.5, rect.center().y),
|
||||||
|
vec2(box_side, box_side),
|
||||||
|
);
|
||||||
|
// Draw a minus:
|
||||||
|
out_commands.push(PaintCmd::Line {
|
||||||
|
points: vec![
|
||||||
|
vec2(box_rect.min().x, box_rect.center().y),
|
||||||
|
vec2(box_rect.max().x, box_rect.center().y),
|
||||||
|
],
|
||||||
|
color: stroke_color,
|
||||||
|
width: style.line_width,
|
||||||
|
});
|
||||||
|
if open {
|
||||||
|
// Draw it as a plus:
|
||||||
|
out_commands.push(PaintCmd::Line {
|
||||||
|
points: vec![
|
||||||
|
vec2(box_rect.center().x, box_rect.min().y),
|
||||||
|
vec2(box_rect.center().x, box_rect.max().y),
|
||||||
|
],
|
||||||
|
color: stroke_color,
|
||||||
|
width: style.line_width,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
out_commands.push(PaintCmd::Text {
|
||||||
|
fill_color: stroke_color,
|
||||||
|
font_name: style.font_name.clone(),
|
||||||
|
font_size: style.font_size,
|
||||||
|
pos: Vec2 {
|
||||||
|
x: box_rect.max().x + 4.0,
|
||||||
|
y: rect.center().y - style.font_size / 2.0,
|
||||||
|
},
|
||||||
|
text: label,
|
||||||
|
text_align: TextAlign::Start,
|
||||||
|
});
|
||||||
|
}
|
||||||
GuiCmd::RadioButton {
|
GuiCmd::RadioButton {
|
||||||
checked,
|
checked,
|
||||||
interact,
|
interact,
|
||||||
|
|
|
@ -102,6 +102,13 @@ pub enum GuiCmd {
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
|
// The header for a foldable region
|
||||||
|
FoldableHeader {
|
||||||
|
interact: InteractInfo,
|
||||||
|
open: bool,
|
||||||
|
rect: Rect,
|
||||||
|
label: String,
|
||||||
|
},
|
||||||
RadioButton {
|
RadioButton {
|
||||||
checked: bool,
|
checked: bool,
|
||||||
interact: InteractInfo,
|
interact: InteractInfo,
|
||||||
|
|
Loading…
Reference in a new issue