From 339b28b4708450181ff93e1024aec328bac986cb Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 21 Mar 2022 21:44:36 +0100 Subject: [PATCH] Add Frame::outer_margin, and rename Frame::margin to Frame::inner_margin --- CHANGELOG.md | 2 + egui/src/containers/frame.rs | 61 +++++++++++++++--------- egui/src/containers/popup.rs | 2 +- egui/src/containers/window.rs | 4 +- egui/src/style.rs | 30 ++++++++++++ egui/src/widgets/plot/legend.rs | 3 +- egui_demo_lib/src/syntax_highlighting.rs | 2 +- 7 files changed, 78 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3612db70..f8519289 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,11 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w * Added `Frame::canvas` ([#1362](https://github.com/emilk/egui/pull/1362)). * `Context::request_repaint` will wake up UI thread, if integrations has called `Context::set_request_repaint_callback` ([#1366](https://github.com/emilk/egui/pull/1366)). * Added `Ui::push_id` ([#1374](https://github.com/emilk/egui/pull/1374)). +* Added `Frame::outer_margin`. ### Changed 🔧 * `ClippedMesh` has been replaced with `ClippedPrimitive` ([#1351](https://github.com/emilk/egui/pull/1351)). +* Renamed `Frame::margin` to `Frame::inner_margin`. ### Fixed 🐛 * Fixed ComboBoxes always being rendered left-aligned ([#1304](https://github.com/emilk/egui/pull/1304)). diff --git a/egui/src/containers/frame.rs b/egui/src/containers/frame.rs index 7eabe383..8d2430ea 100644 --- a/egui/src/containers/frame.rs +++ b/egui/src/containers/frame.rs @@ -7,8 +7,10 @@ use epaint::*; #[derive(Clone, Copy, Debug, Default, PartialEq)] #[must_use = "You should call .show()"] pub struct Frame { - /// On each side - pub margin: Margin, + /// Margin within the painted frame. + pub inner_margin: Margin, + /// Margin outside the painted frame. + pub outer_margin: Margin, pub rounding: Rounding, pub shadow: Shadow, pub fill: Color32, @@ -23,7 +25,7 @@ impl Frame { /// For when you want to group a few widgets together within a frame. pub fn group(style: &Style) -> Self { Self { - margin: Margin::same(6.0), // symmetric looks best in corners when nesting + inner_margin: Margin::same(6.0), // symmetric looks best in corners when nesting rounding: style.visuals.widgets.noninteractive.rounding, stroke: style.visuals.widgets.noninteractive.bg_stroke, ..Default::default() @@ -32,7 +34,7 @@ impl Frame { pub(crate) fn side_top_panel(style: &Style) -> Self { Self { - margin: Margin::symmetric(8.0, 2.0), + inner_margin: Margin::symmetric(8.0, 2.0), rounding: Rounding::none(), fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), @@ -42,7 +44,7 @@ impl Frame { pub(crate) fn central_panel(style: &Style) -> Self { Self { - margin: Margin::symmetric(8.0, 8.0), + inner_margin: Margin::symmetric(8.0, 8.0), rounding: Rounding::none(), fill: style.visuals.window_fill(), stroke: Default::default(), @@ -52,31 +54,34 @@ impl Frame { pub fn window(style: &Style) -> Self { Self { - margin: style.spacing.window_margin, + inner_margin: style.spacing.window_margin, rounding: style.visuals.window_rounding, shadow: style.visuals.window_shadow, fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), + ..Default::default() } } pub fn menu(style: &Style) -> Self { Self { - margin: Margin::same(1.0), + inner_margin: Margin::same(1.0), rounding: style.visuals.widgets.noninteractive.rounding, shadow: style.visuals.popup_shadow, fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), + ..Default::default() } } pub fn popup(style: &Style) -> Self { Self { - margin: style.spacing.window_margin, + inner_margin: style.spacing.window_margin, rounding: style.visuals.widgets.noninteractive.rounding, shadow: style.visuals.popup_shadow, fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), + ..Default::default() } } @@ -86,7 +91,7 @@ impl Frame { /// and in dark mode this will be very dark. pub fn canvas(style: &Style) -> Self { Self { - margin: Margin::symmetric(10.0, 10.0), + inner_margin: Margin::symmetric(10.0, 10.0), rounding: style.visuals.widgets.noninteractive.rounding, fill: style.visuals.extreme_bg_color, stroke: style.visuals.window_stroke(), @@ -119,12 +124,23 @@ impl Frame { self } - /// Margin on each side of the frame. - pub fn margin(mut self, margin: impl Into) -> Self { - self.margin = margin.into(); + /// Margin within the painted frame. + pub fn inner_margin(mut self, inner_margin: impl Into) -> Self { + self.inner_margin = inner_margin.into(); self } + /// Margin outside the painted frame. + pub fn outer_margin(mut self, outer_margin: impl Into) -> Self { + self.outer_margin = outer_margin.into(); + self + } + + #[deprecated = "Renamed inner_margin in egui 0.18"] + pub fn margin(self, margin: impl Into) -> Self { + self.inner_margin(margin) + } + pub fn shadow(mut self, shadow: Shadow) -> Self { self.shadow = shadow; self @@ -150,8 +166,8 @@ impl Frame { let outer_rect_bounds = ui.available_rect_before_wrap(); let mut inner_rect = outer_rect_bounds; - inner_rect.min += Vec2::new(self.margin.left, self.margin.top); - inner_rect.max -= Vec2::new(self.margin.right, self.margin.bottom); + inner_rect.min += self.outer_margin.left_top() + self.inner_margin.left_top(); + inner_rect.max -= self.outer_margin.right_bottom() + self.inner_margin.right_bottom(); // Make sure we don't shrink to the negative: inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x); @@ -185,7 +201,8 @@ impl Frame { pub fn paint(&self, outer_rect: Rect) -> Shape { let Self { - margin: _, + inner_margin: _, + outer_margin: _, rounding, shadow, fill, @@ -210,15 +227,15 @@ impl Frame { } impl Prepared { - pub fn outer_rect(&self) -> Rect { + fn paint_rect(&self) -> Rect { let mut rect = self.content_ui.min_rect(); - rect.min -= Vec2::new(self.frame.margin.left, self.frame.margin.top); - rect.max += Vec2::new(self.frame.margin.right, self.frame.margin.bottom); + rect.min -= self.frame.inner_margin.left_top(); + rect.max += self.frame.inner_margin.right_bottom(); rect } pub fn end(self, ui: &mut Ui) -> Response { - let outer_rect = self.outer_rect(); + let paint_rect = self.paint_rect(); let Prepared { frame, @@ -226,11 +243,11 @@ impl Prepared { .. } = self; - if ui.is_rect_visible(outer_rect) { - let shape = frame.paint(outer_rect); + if ui.is_rect_visible(paint_rect) { + let shape = frame.paint(paint_rect); ui.painter().set(where_to_put_background, shape); } - ui.allocate_rect(outer_rect, Sense::hover()) + ui.allocate_rect(paint_rect, Sense::hover()) } } diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs index c8cbdb67..fa00f3cf 100644 --- a/egui/src/containers/popup.rs +++ b/egui/src/containers/popup.rs @@ -298,7 +298,7 @@ pub fn popup_below_widget( // Note: we use a separate clip-rect for this area, so the popup can be outside the parent. // See https://github.com/emilk/egui/issues/825 let frame = Frame::popup(ui.style()); - let frame_margin = frame.margin; + let frame_margin = frame.inner_margin + frame.outer_margin; frame .show(ui, |ui| { ui.with_layout(Layout::top_down_justified(Align::LEFT), |ui| { diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index 4e1eb70d..b059d432 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -301,7 +301,9 @@ impl<'open> Window<'open> { } else { 0.0 }; - let margins = frame.margin.sum() + vec2(0.0, title_bar_height); + let margins = frame.outer_margin.sum() + + frame.inner_margin.sum() + + vec2(0.0, title_bar_height); interact( window_interaction, diff --git a/egui/src/style.rs b/egui/src/style.rs index 9024a002..d7ffbabb 100644 --- a/egui/src/style.rs +++ b/egui/src/style.rs @@ -277,6 +277,8 @@ impl Spacing { } } +// ---------------------------------------------------------------------------- + #[derive(Clone, Copy, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Margin { @@ -312,6 +314,20 @@ impl Margin { pub fn sum(&self) -> Vec2 { Vec2::new(self.left + self.right, self.top + self.bottom) } + + pub fn left_top(&self) -> Vec2 { + Vec2::new(self.left, self.top) + } + + pub fn right_bottom(&self) -> Vec2 { + Vec2::new(self.right, self.bottom) + } +} + +impl From for Margin { + fn from(v: f32) -> Self { + Self::same(v) + } } impl From for Margin { @@ -320,6 +336,20 @@ impl From for Margin { } } +impl std::ops::Add for Margin { + type Output = Self; + fn add(self, other: Self) -> Self { + Self { + left: self.left + other.left, + right: self.right + other.right, + top: self.top + other.top, + bottom: self.bottom + other.bottom, + } + } +} + +// ---------------------------------------------------------------------------- + /// How and when interaction happens. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] diff --git a/egui/src/widgets/plot/legend.rs b/egui/src/widgets/plot/legend.rs index 6c60c6a3..41bd9d4f 100644 --- a/egui/src/widgets/plot/legend.rs +++ b/egui/src/widgets/plot/legend.rs @@ -239,11 +239,12 @@ impl Widget for &mut LegendWidget { legend_ui .scope(|ui| { let background_frame = Frame { - margin: vec2(8.0, 4.0).into(), + inner_margin: vec2(8.0, 4.0).into(), rounding: ui.style().visuals.window_rounding, shadow: epaint::Shadow::default(), fill: ui.style().visuals.extreme_bg_color, stroke: ui.style().visuals.window_stroke(), + ..Default::default() } .multiply_with_opacity(config.background_alpha); background_frame diff --git a/egui_demo_lib/src/syntax_highlighting.rs b/egui_demo_lib/src/syntax_highlighting.rs index 765b70b9..e1aca332 100644 --- a/egui_demo_lib/src/syntax_highlighting.rs +++ b/egui_demo_lib/src/syntax_highlighting.rs @@ -277,7 +277,7 @@ impl CodeTheme { ui.data().insert_persisted(selected_id, selected_tt); egui::Frame::group(ui.style()) - .margin(egui::Vec2::splat(2.0)) + .inner_margin(egui::Vec2::splat(2.0)) .show(ui, |ui| { // ui.group(|ui| { ui.style_mut().override_text_style = Some(egui::TextStyle::Small);