Hovering tooltip window, bit a bad API
This commit is contained in:
parent
1e24095154
commit
79f64d2066
5 changed files with 107 additions and 30 deletions
34
src/app.rs
34
src/app.rs
|
@ -37,7 +37,12 @@ impl GuiSettings for App {
|
|||
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| {
|
||||
if gui.radio("First", self.selected_alternative == 0).clicked {
|
||||
|
@ -64,22 +69,21 @@ impl GuiSettings for App {
|
|||
gui.slider_f32("stroke_width", &mut self.stroke_width, 0.0, 10.0);
|
||||
});
|
||||
|
||||
gui.commands
|
||||
.push(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
|
||||
corner_radius: self.corner_radius,
|
||||
fill_color: Some(srgba(136, 136, 136, 255)),
|
||||
pos: vec2(300.0, 100.0),
|
||||
size: vec2(self.width, self.height),
|
||||
outline: Some(Outline {
|
||||
width: self.stroke_width,
|
||||
color: srgba(255, 255, 255, 255),
|
||||
}),
|
||||
}]));
|
||||
gui.add_paint_command(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
|
||||
corner_radius: self.corner_radius,
|
||||
fill_color: Some(srgba(136, 136, 136, 255)),
|
||||
pos: vec2(300.0, 100.0),
|
||||
size: vec2(self.width, self.height),
|
||||
outline: Some(Outline {
|
||||
width: self.stroke_width,
|
||||
color: srgba(255, 255, 255, 255),
|
||||
}),
|
||||
}]));
|
||||
|
||||
gui.foldable("LayoutOptions", |gui| {
|
||||
let mut options = gui.options;
|
||||
let mut options = gui.options().clone();
|
||||
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("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("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("width", &mut self.width, 0.0, 1000.0);
|
||||
gui.slider_f32("button_padding.x", &mut self.button_padding.x, 0.0, 20.0);
|
||||
|
|
|
@ -12,7 +12,7 @@ impl Emgui {
|
|||
pub fn new_frame(&mut self, new_input: RawInput) {
|
||||
let gui_input = GuiInput::from_last_and_new(&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> {
|
||||
|
|
|
@ -10,7 +10,10 @@ pub struct LayoutOptions {
|
|||
/// All text is monospace!
|
||||
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,
|
||||
|
||||
/// Indent foldable regions etc by this much.
|
||||
|
@ -32,6 +35,7 @@ impl Default for LayoutOptions {
|
|||
LayoutOptions {
|
||||
char_size: vec2(7.2, 14.0),
|
||||
item_spacing: vec2(8.0, 4.0),
|
||||
window_padding: vec2(6.0, 6.0),
|
||||
indent: 21.0,
|
||||
width: 250.0,
|
||||
button_padding: vec2(5.0, 3.0),
|
||||
|
@ -108,15 +112,15 @@ impl Layouter {
|
|||
|
||||
type Id = u64;
|
||||
|
||||
/// TODO: non-pub
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Layout {
|
||||
pub options: LayoutOptions, // TODO: remove pub
|
||||
options: LayoutOptions,
|
||||
input: GuiInput,
|
||||
memory: Memory,
|
||||
id: Id,
|
||||
layouter: Layouter,
|
||||
pub commands: Vec<GuiCmd>, // TODO: remove pub
|
||||
graphics: Vec<GuiCmd>,
|
||||
hovering_graphics: Vec<GuiCmd>,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
|
@ -124,13 +128,22 @@ impl Layout {
|
|||
&self.input
|
||||
}
|
||||
|
||||
pub fn gui_commands(&self) -> &[GuiCmd] {
|
||||
&self.commands
|
||||
pub fn gui_commands(&self) -> impl Iterator<Item = &GuiCmd> {
|
||||
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
|
||||
pub fn new_frae(&mut self, gui_input: GuiInput) {
|
||||
self.commands.clear();
|
||||
pub fn new_frame(&mut self, gui_input: GuiInput) {
|
||||
self.graphics.clear();
|
||||
self.hovering_graphics.clear();
|
||||
self.layouter = Default::default();
|
||||
self.input = gui_input;
|
||||
if !gui_input.mouse_down {
|
||||
|
@ -147,7 +160,7 @@ impl Layout {
|
|||
let text_cursor = self.layouter.cursor + self.options.button_padding;
|
||||
let (rect, interact) =
|
||||
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);
|
||||
interact
|
||||
}
|
||||
|
@ -169,7 +182,7 @@ impl Layout {
|
|||
if interact.clicked {
|
||||
*checked = !*checked;
|
||||
}
|
||||
self.commands.push(GuiCmd::Checkbox {
|
||||
self.graphics.push(GuiCmd::Checkbox {
|
||||
checked: *checked,
|
||||
interact,
|
||||
rect,
|
||||
|
@ -200,7 +213,7 @@ impl Layout {
|
|||
+ text_size
|
||||
+ self.options.button_padding,
|
||||
);
|
||||
self.commands.push(GuiCmd::RadioButton {
|
||||
self.graphics.push(GuiCmd::RadioButton {
|
||||
checked,
|
||||
interact,
|
||||
rect,
|
||||
|
@ -240,7 +253,7 @@ impl Layout {
|
|||
);
|
||||
}
|
||||
|
||||
self.commands.push(GuiCmd::Slider {
|
||||
self.graphics.push(GuiCmd::Slider {
|
||||
interact,
|
||||
max,
|
||||
min,
|
||||
|
@ -284,7 +297,7 @@ impl Layout {
|
|||
}
|
||||
let open = self.memory.open_foldables.contains(&id);
|
||||
|
||||
self.commands.push(GuiCmd::FoldableHeader {
|
||||
self.graphics.push(GuiCmd::FoldableHeader {
|
||||
interact,
|
||||
rect,
|
||||
open,
|
||||
|
@ -320,6 +333,42 @@ impl Layout {
|
|||
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 {
|
||||
|
@ -380,7 +429,7 @@ impl Layout {
|
|||
|
||||
fn add_text(&mut self, pos: Vec2, text: Vec<TextFragment>) {
|
||||
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),
|
||||
style: TextStyle::Label,
|
||||
text: fragment.text,
|
||||
|
|
20
src/style.rs
20
src/style.rs
|
@ -255,10 +255,28 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
|
|||
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![];
|
||||
for gui_cmd in gui_commands {
|
||||
translate_cmd(&mut paint_commands, style, gui_cmd.clone())
|
||||
|
|
|
@ -119,6 +119,10 @@ pub enum GuiCmd {
|
|||
style: TextStyle,
|
||||
text: String,
|
||||
},
|
||||
/// Background of e.g. a popup
|
||||
Window {
|
||||
rect: Rect,
|
||||
},
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue