From 3f84836c203be1f25584ba090fb5a39b0325a047 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Jan 2019 14:26:02 +0100 Subject: [PATCH] Add rect field to InteractInfo struct --- emigui/src/layout.rs | 49 +++++++++++++++++++------------------ emigui/src/math.rs | 4 +++ emigui/src/painter.rs | 9 +++---- emigui/src/style.rs | 55 ++++++++++++++---------------------------- emigui/src/types.rs | 11 +++------ emigui/src/widgets.rs | 31 ++++++++++++------------ emigui_wasm/src/app.rs | 3 +-- 7 files changed, 73 insertions(+), 89 deletions(-) diff --git a/emigui/src/layout.rs b/emigui/src/layout.rs index 26c627d3..ae86ed41 100644 --- a/emigui/src/layout.rs +++ b/emigui/src/layout.rs @@ -19,14 +19,17 @@ pub struct LayoutOptions { /// Horizontal and vertical padding within a window frame. pub window_padding: Vec2, + /// Button size is text size plus this on each side + pub button_padding: Vec2, + /// Horizontal and vertical spacing between widgets pub item_spacing: Vec2, /// Indent foldable regions etc by this much. pub indent: f32, - /// Button size is text size plus this on each side - pub button_padding: Vec2, + /// Anything clickable is (at least) this wide. + pub clickable_diameter: f32, /// Checkboxed, radio button and foldables have an icon at the start. /// The text starts after this many pixels. @@ -36,10 +39,11 @@ pub struct LayoutOptions { impl Default for LayoutOptions { fn default() -> Self { LayoutOptions { - item_spacing: vec2(8.0, 4.0), window_padding: vec2(6.0, 6.0), - indent: 21.0, button_padding: vec2(5.0, 3.0), + item_spacing: vec2(8.0, 4.0), + indent: 21.0, + clickable_diameter: 10.0, start_icon_width: 20.0, } } @@ -58,6 +62,9 @@ pub struct GuiResponse { /// The mouse is interacting with this thing (e.g. dragging it) pub active: bool, + /// The region of the screen we are talking about + pub rect: Rect, + /// Used for showing a popup (if any) data: Arc, } @@ -308,7 +315,7 @@ impl Region { let font = &self.fonts()[text_style]; let (text, text_size) = font.layout_multiline(&text, self.width()); let text_cursor = self.cursor + self.options().button_padding; - let (rect, interact) = self.reserve_space( + let interact = self.reserve_space( vec2( self.available_space.x, text_size.y + 2.0 * self.options().button_padding.y, @@ -328,11 +335,7 @@ impl Region { memory.open_foldables.contains(&id) }; - self.add_graphic(GuiCmd::FoldableHeader { - interact, - rect, - open, - }); + self.add_graphic(GuiCmd::FoldableHeader { interact, open }); self.add_text( text_cursor + vec2(self.options().start_icon_width, 0.0), text_style, @@ -366,7 +369,7 @@ impl Region { }; add_contents(&mut child_region); let size = child_region.bounding_size; - self.reserve_space_inner(indent + size); + self.reserve_space_without_padding(indent + size); } /// A horizontally centered region of the given width. @@ -398,7 +401,7 @@ impl Region { }; add_contents(&mut child_region); let size = child_region.bounding_size; - self.reserve_space_inner(size); + self.reserve_space_without_padding(size); } /// Temporarily split split a vertical layout into several columns. @@ -436,7 +439,7 @@ impl Region { max_height = size.y.max(max_height); } - self.reserve_space_inner(vec2(self.available_space.x, max_height)); + self.reserve_space_without_padding(vec2(self.available_space.x, max_height)); result } @@ -448,16 +451,14 @@ impl Region { // ------------------------------------------------------------------------ - pub fn reserve_space( - &mut self, - size: Vec2, - interaction_id: Option, - ) -> (Rect, InteractInfo) { + pub fn reserve_space(&mut self, size: Vec2, interaction_id: Option) -> InteractInfo { let rect = Rect { pos: self.cursor, size, }; - self.reserve_space_inner(size + self.options().item_spacing); + + self.reserve_space_without_padding(size + self.options().item_spacing); + let hovered = rect.contains(self.input().mouse_pos); let clicked = hovered && self.input().mouse_clicked; let active = if interaction_id.is_some() { @@ -470,17 +471,17 @@ impl Region { false }; - let interact = InteractInfo { + InteractInfo { + rect, hovered, clicked, active, - }; - (rect, interact) + } } // TODO: Return a Rect /// Reserve this much space and move the cursor. - pub fn reserve_space_inner(&mut self, size: Vec2) { + pub fn reserve_space_without_padding(&mut self, size: Vec2) { if self.dir == Direction::Horizontal { self.cursor.x += size.x; self.available_space.x -= size.x; @@ -524,10 +525,12 @@ impl Region { } pub fn response(&mut self, interact: InteractInfo) -> GuiResponse { + // TODO: unify GuiResponse and InteractInfo. They are the same thing! GuiResponse { hovered: interact.hovered, clicked: interact.clicked, active: interact.active, + rect: interact.rect, data: self.data.clone(), } } diff --git a/emigui/src/math.rs b/emigui/src/math.rs index 7d300666..d5571598 100644 --- a/emigui/src/math.rs +++ b/emigui/src/math.rs @@ -128,6 +128,10 @@ impl Rect { pub fn max(&self) -> Vec2 { self.pos + self.size } + + pub fn size(&self) -> Vec2 { + self.size + } } pub fn lerp(min: f32, max: f32, t: f32) -> f32 { diff --git a/emigui/src/painter.rs b/emigui/src/painter.rs index f8909335..b663fa51 100644 --- a/emigui/src/painter.rs +++ b/emigui/src/painter.rs @@ -272,16 +272,15 @@ impl Painter { corner_radius, fill_color, outline, - pos, - size, + rect, } => { path_points.clear(); path_normals.clear(); - let min = *pos; - let max = *pos + *size; + let min = rect.min(); + let max = rect.max(); - let cr = corner_radius.min(size.x * 0.5).min(size.y * 0.5); + let cr = corner_radius.min(rect.size.x * 0.5).min(rect.size.y * 0.5); if cr <= 0.0 { path_points.push(vec2(min.x, min.y)); diff --git a/emigui/src/style.rs b/emigui/src/style.rs index 914dd9b4..e45c7851 100644 --- a/emigui/src/style.rs +++ b/emigui/src/style.rs @@ -72,8 +72,7 @@ fn debug_rect(rect: Rect) -> PaintCmd { color: srgba(255, 255, 255, 255), width: 1.0, }), - pos: rect.pos, - size: rect.size, + rect, } } @@ -81,30 +80,24 @@ fn debug_rect(rect: Rect) -> PaintCmd { fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { match cmd { GuiCmd::PaintCommands(mut commands) => out_commands.append(&mut commands), - GuiCmd::Button { interact, rect } => { + GuiCmd::Button { interact } => { out_commands.push(PaintCmd::Rect { corner_radius: 5.0, fill_color: Some(style.interact_fill_color(&interact)), outline: None, - pos: rect.pos, - size: rect.size, + rect: interact.rect, }); if style.debug_rects { - out_commands.push(debug_rect(rect)); + out_commands.push(debug_rect(interact.rect)); } } - GuiCmd::Checkbox { - checked, - interact, - rect, - } => { - let (small_icon_rect, big_icon_rect) = style.icon_rectangles(&rect); + GuiCmd::Checkbox { checked, interact } => { + let (small_icon_rect, big_icon_rect) = style.icon_rectangles(&interact.rect); out_commands.push(PaintCmd::Rect { corner_radius: 3.0, fill_color: Some(style.interact_fill_color(&interact)), outline: None, - pos: big_icon_rect.pos, - size: big_icon_rect.size, + rect: big_icon_rect, }); let stroke_color = style.interact_stroke_color(&interact); @@ -122,14 +115,10 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { } if style.debug_rects { - out_commands.push(debug_rect(rect)); + out_commands.push(debug_rect(interact.rect)); } } - GuiCmd::FoldableHeader { - interact, - open, - rect, - } => { + GuiCmd::FoldableHeader { interact, open } => { let fill_color = style.interact_fill_color(&interact); let stroke_color = style.interact_stroke_color(&interact); @@ -137,13 +126,12 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { corner_radius: 3.0, fill_color: Some(fill_color), outline: None, - pos: rect.pos, - size: rect.size, + rect: interact.rect, }); // TODO: paint a little triangle or arrow or something instead of this - let (small_icon_rect, _) = style.icon_rectangles(&rect); + let (small_icon_rect, _) = style.icon_rectangles(&interact.rect); // Draw a minus: out_commands.push(PaintCmd::Line { points: vec![ @@ -165,15 +153,11 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { }); } } - GuiCmd::RadioButton { - checked, - interact, - rect, - } => { + GuiCmd::RadioButton { checked, interact } => { let fill_color = style.interact_fill_color(&interact); let stroke_color = style.interact_stroke_color(&interact); - let (small_icon_rect, big_icon_rect) = style.icon_rectangles(&rect); + let (small_icon_rect, big_icon_rect) = style.icon_rectangles(&interact.rect); out_commands.push(PaintCmd::Circle { center: big_icon_rect.center(), @@ -192,16 +176,16 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { } if style.debug_rects { - out_commands.push(debug_rect(rect)); + out_commands.push(debug_rect(interact.rect)); } } GuiCmd::Slider { interact, max, min, - rect, value, } => { + let rect = interact.rect; let thin_rect = Rect::from_center_size(rect.center(), vec2(rect.size.x, 6.0)); let marker_center_x = remap_clamp(value, min, max, rect.min().x, rect.max().x); @@ -214,16 +198,14 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { corner_radius: 2.0, fill_color: Some(style.background_fill_color()), outline: None, - pos: thin_rect.pos, - size: thin_rect.size, + rect: thin_rect, }); out_commands.push(PaintCmd::Rect { corner_radius: 3.0, fill_color: Some(style.interact_fill_color(&interact)), outline: None, - pos: marker_rect.pos, - size: marker_rect.size, + rect: marker_rect, }); if style.debug_rects { @@ -253,8 +235,7 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { color: srgba(255, 255, 255, 255), // TODO width: 1.0, }), - pos: rect.pos, - size: rect.size, + rect: rect, }); } } diff --git a/emigui/src/types.rs b/emigui/src/types.rs index ac876ddf..b67387cd 100644 --- a/emigui/src/types.rs +++ b/emigui/src/types.rs @@ -89,6 +89,9 @@ pub struct InteractInfo { /// The mouse is interacting with this thing (e.g. dragging it) pub active: bool, + + /// The region of the screen we are talking about + pub rect: Rect, } #[derive(Clone, Debug, Serialize)] @@ -97,29 +100,24 @@ pub enum GuiCmd { /// The background for a button Button { interact: InteractInfo, - rect: Rect, }, Checkbox { checked: bool, interact: InteractInfo, - rect: Rect, }, /// The header button background for a foldable region FoldableHeader { interact: InteractInfo, open: bool, - rect: Rect, }, RadioButton { checked: bool, interact: InteractInfo, - rect: Rect, }, Slider { interact: InteractInfo, max: f32, min: f32, - rect: Rect, value: f32, }, /// Paint a single line of mono-space text. @@ -167,8 +165,7 @@ pub enum PaintCmd { corner_radius: f32, fill_color: Option, outline: Option, - pos: Vec2, - size: Vec2, + rect: Rect, }, /// Paint a single line of text Text { diff --git a/emigui/src/widgets.rs b/emigui/src/widgets.rs index a702f774..233ddb91 100644 --- a/emigui/src/widgets.rs +++ b/emigui/src/widgets.rs @@ -42,7 +42,7 @@ impl Widget for Label { let font = ®ion.fonts()[self.text_style]; let (text, text_size) = font.layout_multiline(&self.text, region.width()); region.add_text(region.cursor(), self.text_style, text); - let (_, interact) = region.reserve_space(text_size, None); + let interact = region.reserve_space(text_size, None); region.response(interact) } } @@ -66,9 +66,9 @@ impl Widget for Button { let font = ®ion.fonts()[text_style]; let (text, text_size) = font.layout_multiline(&self.text, region.width()); let text_cursor = region.cursor() + region.options().button_padding; - let (rect, interact) = + let interact = region.reserve_space(text_size + 2.0 * region.options().button_padding, Some(id)); - region.add_graphic(GuiCmd::Button { interact, rect }); + region.add_graphic(GuiCmd::Button { interact }); region.add_text(text_cursor, text_style, text); region.response(interact) } @@ -100,7 +100,7 @@ impl<'a> Widget for Checkbox<'a> { let text_cursor = region.cursor() + region.options().button_padding + vec2(region.options().start_icon_width, 0.0); - let (rect, interact) = region.reserve_space( + let interact = region.reserve_space( region.options().button_padding + vec2(region.options().start_icon_width, 0.0) + text_size @@ -113,7 +113,6 @@ impl<'a> Widget for Checkbox<'a> { region.add_graphic(GuiCmd::Checkbox { checked: *self.checked, interact, - rect, }); region.add_text(text_cursor, text_style, text); region.response(interact) @@ -150,7 +149,7 @@ impl Widget for RadioButton { let text_cursor = region.cursor() + region.options().button_padding + vec2(region.options().start_icon_width, 0.0); - let (rect, interact) = region.reserve_space( + let interact = region.reserve_space( region.options().button_padding + vec2(region.options().start_icon_width, 0.0) + text_size @@ -160,7 +159,6 @@ impl Widget for RadioButton { region.add_graphic(GuiCmd::RadioButton { checked: self.checked, interact, - rect, }); region.add_text(text_cursor, text_style, text); region.response(interact) @@ -218,24 +216,28 @@ impl<'a> Widget for Slider<'a> { if text_on_top { let (text, text_size) = font.layout_multiline(&full_text, region.width()); region.add_text(region.cursor(), text_style, text); - region.reserve_space_inner(text_size); + region.reserve_space_without_padding(text_size); naked.add_to(region) } else { region.columns(2, |columns| { - columns[1].add(label(full_text)); - naked.add_to(&mut columns[0]) + let response = naked.add_to(&mut columns[0]); + columns[1].available_space.y = response.rect.size().y; + columns[1].add(label(full_text)); // TODO: centered! + response }) } } else { + let height = font.line_spacing().max(region.options().clickable_diameter); + let value = self.value; let min = self.min; let max = self.max; debug_assert!(min <= max); let id = region.combined_id(self.id); - let (slider_rect, interact) = region.reserve_space( + let interact = region.reserve_space( Vec2 { x: region.available_space.x, - y: font.line_spacing(), + y: height, }, id, ); @@ -243,8 +245,8 @@ impl<'a> Widget for Slider<'a> { if interact.active { *value = remap_clamp( region.input().mouse_pos.x, - slider_rect.min().x, - slider_rect.max().x, + interact.rect.min().x, + interact.rect.max().x, min, max, ); @@ -254,7 +256,6 @@ impl<'a> Widget for Slider<'a> { interact, max, min, - rect: slider_rect, value: *value, }); diff --git a/emigui_wasm/src/app.rs b/emigui_wasm/src/app.rs index 9d75d77b..b47c8933 100644 --- a/emigui_wasm/src/app.rs +++ b/emigui_wasm/src/app.rs @@ -82,8 +82,7 @@ impl App { gui.add_graphic(GuiCmd::PaintCommands(vec![PaintCmd::Rect { corner_radius: self.corner_radius, fill_color: Some(srgba(136, 136, 136, 255)), - pos, - size: self.size, + rect: Rect::from_min_size(pos, self.size), outline: Some(Outline { width: self.stroke_width, color: srgba(255, 255, 255, 255),