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.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,22 +69,21 @@ 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),
|
size: vec2(self.width, self.height),
|
||||||
size: vec2(self.width, self.height),
|
outline: Some(Outline {
|
||||||
outline: Some(Outline {
|
width: self.stroke_width,
|
||||||
width: self.stroke_width,
|
color: srgba(255, 255, 255, 255),
|
||||||
color: srgba(255, 255, 255, 255),
|
}),
|
||||||
}),
|
}]));
|
||||||
}]));
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
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,
|
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())
|
||||||
|
|
|
@ -119,6 +119,10 @@ pub enum GuiCmd {
|
||||||
style: TextStyle,
|
style: TextStyle,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
|
/// Background of e.g. a popup
|
||||||
|
Window {
|
||||||
|
rect: Rect,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue