Hovering tooltip window, bit a bad API

This commit is contained in:
Emil Ernerfeldt 2018-12-28 23:29:24 +01:00
parent 1e24095154
commit 79f64d2066
5 changed files with 107 additions and 30 deletions

View file

@ -37,7 +37,12 @@ impl GuiSettings for App {
gui.input().screen_size.y, gui.input().screen_size.y,
)); ));
gui.checkbox("checkbox", &mut self.checked); // TODO: add tooltip text with: gui.button("click me").tooltip_text("tooltip")
if gui.checkbox("checkbox", &mut self.checked).hovered {
gui.tooltip_text(
"This is a multiline tooltip that explains the checkbox you are hovering.\nThis is the second line.\nThis is the third.",
);
}
gui.horizontal(|gui| { gui.horizontal(|gui| {
if gui.radio("First", self.selected_alternative == 0).clicked { if gui.radio("First", self.selected_alternative == 0).clicked {
@ -64,8 +69,7 @@ impl GuiSettings for App {
gui.slider_f32("stroke_width", &mut self.stroke_width, 0.0, 10.0); gui.slider_f32("stroke_width", &mut self.stroke_width, 0.0, 10.0);
}); });
gui.commands gui.add_paint_command(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
.push(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
corner_radius: self.corner_radius, corner_radius: self.corner_radius,
fill_color: Some(srgba(136, 136, 136, 255)), fill_color: Some(srgba(136, 136, 136, 255)),
pos: vec2(300.0, 100.0), pos: vec2(300.0, 100.0),
@ -77,9 +81,9 @@ impl GuiSettings for App {
}])); }]));
gui.foldable("LayoutOptions", |gui| { gui.foldable("LayoutOptions", |gui| {
let mut options = gui.options; let mut options = gui.options().clone();
options.show_gui(gui); options.show_gui(gui);
gui.options = options; gui.set_options(options);
}); });
} }
} }
@ -93,6 +97,8 @@ impl GuiSettings for crate::layout::LayoutOptions {
gui.slider_f32("char_size.y", &mut self.char_size.y, 0.0, 20.0); gui.slider_f32("char_size.y", &mut self.char_size.y, 0.0, 20.0);
gui.slider_f32("item_spacing.x", &mut self.item_spacing.x, 0.0, 10.0); gui.slider_f32("item_spacing.x", &mut self.item_spacing.x, 0.0, 10.0);
gui.slider_f32("item_spacing.y", &mut self.item_spacing.y, 0.0, 10.0); gui.slider_f32("item_spacing.y", &mut self.item_spacing.y, 0.0, 10.0);
gui.slider_f32("window_padding.x", &mut self.window_padding.x, 0.0, 10.0);
gui.slider_f32("window_padding.y", &mut self.window_padding.y, 0.0, 10.0);
gui.slider_f32("indent", &mut self.indent, 0.0, 100.0); gui.slider_f32("indent", &mut self.indent, 0.0, 100.0);
gui.slider_f32("width", &mut self.width, 0.0, 1000.0); gui.slider_f32("width", &mut self.width, 0.0, 1000.0);
gui.slider_f32("button_padding.x", &mut self.button_padding.x, 0.0, 20.0); gui.slider_f32("button_padding.x", &mut self.button_padding.x, 0.0, 20.0);

View file

@ -12,7 +12,7 @@ impl Emgui {
pub fn new_frame(&mut self, new_input: RawInput) { pub fn new_frame(&mut self, new_input: RawInput) {
let gui_input = GuiInput::from_last_and_new(&self.last_input, &new_input); let gui_input = GuiInput::from_last_and_new(&self.last_input, &new_input);
self.last_input = new_input; self.last_input = new_input;
self.layout.new_frae(gui_input); self.layout.new_frame(gui_input);
} }
pub fn paint(&mut self) -> Vec<PaintCmd> { pub fn paint(&mut self) -> Vec<PaintCmd> {

View file

@ -10,7 +10,10 @@ pub struct LayoutOptions {
/// All text is monospace! /// All text is monospace!
pub char_size: Vec2, pub char_size: Vec2,
// Horizontal and vertical spacing between widgets /// Horizontal and vertical padding within a window frame.
pub window_padding: Vec2,
/// Horizontal and vertical spacing between widgets
pub item_spacing: Vec2, pub item_spacing: Vec2,
/// Indent foldable regions etc by this much. /// Indent foldable regions etc by this much.
@ -32,6 +35,7 @@ impl Default for LayoutOptions {
LayoutOptions { LayoutOptions {
char_size: vec2(7.2, 14.0), char_size: vec2(7.2, 14.0),
item_spacing: vec2(8.0, 4.0), item_spacing: vec2(8.0, 4.0),
window_padding: vec2(6.0, 6.0),
indent: 21.0, indent: 21.0,
width: 250.0, width: 250.0,
button_padding: vec2(5.0, 3.0), button_padding: vec2(5.0, 3.0),
@ -108,15 +112,15 @@ impl Layouter {
type Id = u64; type Id = u64;
/// TODO: non-pub
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct Layout { pub struct Layout {
pub options: LayoutOptions, // TODO: remove pub options: LayoutOptions,
input: GuiInput, input: GuiInput,
memory: Memory, memory: Memory,
id: Id, id: Id,
layouter: Layouter, layouter: Layouter,
pub commands: Vec<GuiCmd>, // TODO: remove pub graphics: Vec<GuiCmd>,
hovering_graphics: Vec<GuiCmd>,
} }
impl Layout { impl Layout {
@ -124,13 +128,22 @@ impl Layout {
&self.input &self.input
} }
pub fn gui_commands(&self) -> &[GuiCmd] { pub fn gui_commands(&self) -> impl Iterator<Item = &GuiCmd> {
&self.commands self.graphics.iter().chain(self.hovering_graphics.iter())
}
pub fn options(&self) -> &LayoutOptions {
&self.options
}
pub fn set_options(&mut self, options: LayoutOptions) {
self.options = options;
} }
// TODO: move // TODO: move
pub fn new_frae(&mut self, gui_input: GuiInput) { pub fn new_frame(&mut self, gui_input: GuiInput) {
self.commands.clear(); self.graphics.clear();
self.hovering_graphics.clear();
self.layouter = Default::default(); self.layouter = Default::default();
self.input = gui_input; self.input = gui_input;
if !gui_input.mouse_down { if !gui_input.mouse_down {
@ -147,7 +160,7 @@ impl Layout {
let text_cursor = self.layouter.cursor + self.options.button_padding; let text_cursor = self.layouter.cursor + self.options.button_padding;
let (rect, interact) = let (rect, interact) =
self.reserve_interactive_space(id, text_size + 2.0 * self.options.button_padding); self.reserve_interactive_space(id, text_size + 2.0 * self.options.button_padding);
self.commands.push(GuiCmd::Button { interact, rect }); self.graphics.push(GuiCmd::Button { interact, rect });
self.add_text(text_cursor, text); self.add_text(text_cursor, text);
interact interact
} }
@ -169,7 +182,7 @@ impl Layout {
if interact.clicked { if interact.clicked {
*checked = !*checked; *checked = !*checked;
} }
self.commands.push(GuiCmd::Checkbox { self.graphics.push(GuiCmd::Checkbox {
checked: *checked, checked: *checked,
interact, interact,
rect, rect,
@ -200,7 +213,7 @@ impl Layout {
+ text_size + text_size
+ self.options.button_padding, + self.options.button_padding,
); );
self.commands.push(GuiCmd::RadioButton { self.graphics.push(GuiCmd::RadioButton {
checked, checked,
interact, interact,
rect, rect,
@ -240,7 +253,7 @@ impl Layout {
); );
} }
self.commands.push(GuiCmd::Slider { self.graphics.push(GuiCmd::Slider {
interact, interact,
max, max,
min, min,
@ -284,7 +297,7 @@ impl Layout {
} }
let open = self.memory.open_foldables.contains(&id); let open = self.memory.open_foldables.contains(&id);
self.commands.push(GuiCmd::FoldableHeader { self.graphics.push(GuiCmd::FoldableHeader {
interact, interact,
rect, rect,
open, open,
@ -320,6 +333,42 @@ impl Layout {
self.layouter.reserve_space(horizontal_layouter.size); self.layouter.reserve_space(horizontal_layouter.size);
} }
// ------------------------------------------------------------------------
// Free painting. It is up to the caller to make sure there is room for these.
pub fn add_paint_command(&mut self, cmd: GuiCmd) {
self.graphics.push(cmd);
}
// ------------------------------------------------------------------------
/// Show some text in a window under mouse position.
pub fn tooltip_text<S: Into<String>>(&mut self, text: S) {
let window_pos = self.input.mouse_pos + vec2(16.0, 16.0);
// TODO: less copying
let mut popup_layout = Layout {
options: self.options,
input: self.input,
memory: self.memory.clone(), // TODO: Arc
id: self.id,
layouter: Default::default(),
graphics: vec![],
hovering_graphics: vec![],
};
popup_layout.layouter.cursor = window_pos + self.options.window_padding;
popup_layout.label(text);
// TODO: handle the last item_spacing in a nicer way
let inner_size = popup_layout.layouter.size - self.options.item_spacing;
let outer_size = inner_size + 2.0 * self.options.window_padding;
let rect = Rect::from_min_size(window_pos, outer_size);
self.hovering_graphics.push(GuiCmd::Window { rect });
self.hovering_graphics
.extend(popup_layout.gui_commands().cloned());
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
fn reserve_space_default_spacing(&mut self, size: Vec2) -> Rect { fn reserve_space_default_spacing(&mut self, size: Vec2) -> Rect {
@ -380,7 +429,7 @@ impl Layout {
fn add_text(&mut self, pos: Vec2, text: Vec<TextFragment>) { fn add_text(&mut self, pos: Vec2, text: Vec<TextFragment>) {
for fragment in text { for fragment in text {
self.commands.push(GuiCmd::Text { self.graphics.push(GuiCmd::Text {
pos: pos + vec2(fragment.rect.pos.x, fragment.rect.center().y), pos: pos + vec2(fragment.rect.pos.x, fragment.rect.center().y),
style: TextStyle::Label, style: TextStyle::Label,
text: fragment.text, text: fragment.text,

View file

@ -255,10 +255,28 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
text, text,
}); });
} }
GuiCmd::Window { rect } => {
out_commands.push(PaintCmd::Rect {
corner_radius: 5.0,
fill_color: Some(style.background_fill_color()),
outline: Some(Outline {
color: srgba(255, 255, 255, 255), // TODO
width: 1.0,
}),
pos: rect.pos,
size: rect.size,
});
}
} }
} }
pub fn into_paint_commands(gui_commands: &[GuiCmd], style: &Style) -> Vec<PaintCmd> { pub fn into_paint_commands<'a, GuiCmdIterator>(
gui_commands: GuiCmdIterator,
style: &Style,
) -> Vec<PaintCmd>
where
GuiCmdIterator: Iterator<Item = &'a GuiCmd>,
{
let mut paint_commands = vec![]; let mut paint_commands = vec![];
for gui_cmd in gui_commands { for gui_cmd in gui_commands {
translate_cmd(&mut paint_commands, style, gui_cmd.clone()) translate_cmd(&mut paint_commands, style, gui_cmd.clone())

View file

@ -119,6 +119,10 @@ pub enum GuiCmd {
style: TextStyle, style: TextStyle,
text: String, text: String,
}, },
/// Background of e.g. a popup
Window {
rect: Rect,
},
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------