Browse Source

Create foldable areas

pull/1/head
Emil Ernerfeldt 6 years ago
parent
commit
52eb5bdf2c
  1. 9
      src/app.rs
  2. 62
      src/layout.rs
  3. 5
      src/lib.rs
  4. 70
      src/style.rs
  5. 7
      src/types.rs

9
src/app.rs

@ -75,10 +75,11 @@ impl GuiSettings for App {
}),
}]));
gui.label("LayoutOptions:");
let mut layout_options = gui.layout_options;
layout_options.show_gui(gui);
gui.layout_options = layout_options;
gui.foldable("LayoutOptions", |gui| {
let mut layout_options = gui.layout_options;
layout_options.show_gui(gui);
gui.layout_options = layout_options;
});
}
}

62
src/layout.rs

@ -1,3 +1,5 @@
use std::collections::HashSet;
use crate::{math::*, types::*};
// ----------------------------------------------------------------------------
@ -7,6 +9,9 @@ pub struct LayoutOptions {
// Horizontal and vertical spacing between widgets
pub item_spacing: Vec2,
/// Indent foldable regions etc by this much.
pub indent: f32,
/// Default width of buttons, sliders etc
pub width: f32,
@ -24,6 +29,7 @@ impl Default for LayoutOptions {
fn default() -> Self {
LayoutOptions {
item_spacing: Vec2 { x: 8.0, y: 4.0 },
indent: 21.0,
width: 200.0,
button_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 {
/// The widget being interacted with (e.g. dragged, in case of a slider).
pub active_id: Option<Id>,
/// Which foldable regions are open.
open_foldables: HashSet<Id>,
}
// ----------------------------------------------------------------------------
@ -186,6 +195,57 @@ impl Layout {
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 {

5
src/lib.rs

@ -52,9 +52,10 @@ pub fn show_gui(raw_input_json: &str) -> String {
use crate::app::GuiSettings;
APP.lock().unwrap().show_gui(&mut emgui.layout);
emgui.layout.label("Style:");
let mut style = emgui.style.clone();
style.show_gui(&mut emgui.layout);
emgui.layout.foldable("Style", |gui| {
style.show_gui(gui);
});
emgui.style = style;
let commands = emgui.paint();

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));
}
}
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 {
checked,
interact,

7
src/types.rs

@ -102,6 +102,13 @@ pub enum GuiCmd {
rect: Rect,
text: String,
},
// The header for a foldable region
FoldableHeader {
interact: InteractInfo,
open: bool,
rect: Rect,
label: String,
},
RadioButton {
checked: bool,
interact: InteractInfo,

Loading…
Cancel
Save