Per-side margins with new struct Margin (#1219)
This commit is contained in:
parent
603ec82a5e
commit
2802e03526
8 changed files with 102 additions and 22 deletions
|
@ -39,6 +39,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
|
||||||
* `TextStyle` is no longer `Copy` ([#1154](https://github.com/emilk/egui/pull/1154)).
|
* `TextStyle` is no longer `Copy` ([#1154](https://github.com/emilk/egui/pull/1154)).
|
||||||
* Replaced `TextEdit::text_style` with `TextEdit::font` ([#1154](https://github.com/emilk/egui/pull/1154)).
|
* Replaced `TextEdit::text_style` with `TextEdit::font` ([#1154](https://github.com/emilk/egui/pull/1154)).
|
||||||
* Replaced `corner_radius: f32` with `rounding: Rounding`, allowing per-corner rounding settings ([#1206](https://github.com/emilk/egui/pull/1206)).
|
* Replaced `corner_radius: f32` with `rounding: Rounding`, allowing per-corner rounding settings ([#1206](https://github.com/emilk/egui/pull/1206)).
|
||||||
|
* Replaced Frame's `margin: Vec2` with `margin: Margin`, allowing for different margins on opposing sides ([#1219](https://github.com/emilk/egui/pull/1219)).
|
||||||
* `Plot::highlight` now takes a `bool` argument ([#1159](https://github.com/emilk/egui/pull/1159)).
|
* `Plot::highlight` now takes a `bool` argument ([#1159](https://github.com/emilk/egui/pull/1159)).
|
||||||
* `ScrollArea::show` now returns a `ScrollAreaOutput`, so you might need to add `.inner` after the call to it ([#1166](https://github.com/emilk/egui/pull/1166)).
|
* `ScrollArea::show` now returns a `ScrollAreaOutput`, so you might need to add `.inner` after the call to it ([#1166](https://github.com/emilk/egui/pull/1166)).
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,55 @@
|
||||||
use crate::{layers::ShapeIdx, *};
|
use crate::{layers::ShapeIdx, *};
|
||||||
use epaint::*;
|
use epaint::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub struct Margin {
|
||||||
|
pub left: f32,
|
||||||
|
pub right: f32,
|
||||||
|
pub top: f32,
|
||||||
|
pub bottom: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Margin {
|
||||||
|
#[inline]
|
||||||
|
pub fn same(margin: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
left: margin,
|
||||||
|
right: margin,
|
||||||
|
top: margin,
|
||||||
|
bottom: margin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Margins with the same size on opposing sides
|
||||||
|
#[inline]
|
||||||
|
pub fn symmetric(x: f32, y: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
left: x,
|
||||||
|
right: x,
|
||||||
|
top: y,
|
||||||
|
bottom: y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Total margins on both sides
|
||||||
|
pub fn sum(&self) -> Vec2 {
|
||||||
|
Vec2::new(self.left + self.right, self.top + self.bottom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec2> for Margin {
|
||||||
|
fn from(v: Vec2) -> Self {
|
||||||
|
Self::symmetric(v.x, v.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Color and margin of a rectangular background of a [`Ui`].
|
/// Color and margin of a rectangular background of a [`Ui`].
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
#[must_use = "You should call .show()"]
|
#[must_use = "You should call .show()"]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
/// On each side
|
/// On each side
|
||||||
pub margin: Vec2,
|
pub margin: Margin,
|
||||||
pub rounding: Rounding,
|
pub rounding: Rounding,
|
||||||
pub shadow: Shadow,
|
pub shadow: Shadow,
|
||||||
pub fill: Color32,
|
pub fill: Color32,
|
||||||
|
@ -23,7 +66,7 @@ impl Frame {
|
||||||
/// For when you want to group a few widgets together within a frame.
|
/// For when you want to group a few widgets together within a frame.
|
||||||
pub fn group(style: &Style) -> Self {
|
pub fn group(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::splat(6.0), // symmetric looks best in corners when nesting
|
margin: Margin::same(6.0), // symmetric looks best in corners when nesting
|
||||||
rounding: style.visuals.widgets.noninteractive.rounding,
|
rounding: style.visuals.widgets.noninteractive.rounding,
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -32,7 +75,7 @@ impl Frame {
|
||||||
|
|
||||||
pub(crate) fn side_top_panel(style: &Style) -> Self {
|
pub(crate) fn side_top_panel(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(8.0, 2.0),
|
margin: Margin::symmetric(8.0, 2.0),
|
||||||
rounding: Rounding::none(),
|
rounding: Rounding::none(),
|
||||||
fill: style.visuals.window_fill(),
|
fill: style.visuals.window_fill(),
|
||||||
stroke: style.visuals.window_stroke(),
|
stroke: style.visuals.window_stroke(),
|
||||||
|
@ -42,7 +85,7 @@ impl Frame {
|
||||||
|
|
||||||
pub(crate) fn central_panel(style: &Style) -> Self {
|
pub(crate) fn central_panel(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(8.0, 8.0),
|
margin: Margin::symmetric(8.0, 8.0),
|
||||||
rounding: Rounding::none(),
|
rounding: Rounding::none(),
|
||||||
fill: style.visuals.window_fill(),
|
fill: style.visuals.window_fill(),
|
||||||
stroke: Default::default(),
|
stroke: Default::default(),
|
||||||
|
@ -52,7 +95,7 @@ impl Frame {
|
||||||
|
|
||||||
pub fn window(style: &Style) -> Self {
|
pub fn window(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: style.spacing.window_padding,
|
margin: style.spacing.window_margin,
|
||||||
rounding: style.visuals.window_rounding,
|
rounding: style.visuals.window_rounding,
|
||||||
shadow: style.visuals.window_shadow,
|
shadow: style.visuals.window_shadow,
|
||||||
fill: style.visuals.window_fill(),
|
fill: style.visuals.window_fill(),
|
||||||
|
@ -62,7 +105,7 @@ impl Frame {
|
||||||
|
|
||||||
pub fn menu(style: &Style) -> Self {
|
pub fn menu(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::splat(1.0),
|
margin: Margin::same(1.0),
|
||||||
rounding: style.visuals.widgets.noninteractive.rounding,
|
rounding: style.visuals.widgets.noninteractive.rounding,
|
||||||
shadow: style.visuals.popup_shadow,
|
shadow: style.visuals.popup_shadow,
|
||||||
fill: style.visuals.window_fill(),
|
fill: style.visuals.window_fill(),
|
||||||
|
@ -72,7 +115,7 @@ impl Frame {
|
||||||
|
|
||||||
pub fn popup(style: &Style) -> Self {
|
pub fn popup(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: style.spacing.window_padding,
|
margin: style.spacing.window_margin,
|
||||||
rounding: style.visuals.widgets.noninteractive.rounding,
|
rounding: style.visuals.widgets.noninteractive.rounding,
|
||||||
shadow: style.visuals.popup_shadow,
|
shadow: style.visuals.popup_shadow,
|
||||||
fill: style.visuals.window_fill(),
|
fill: style.visuals.window_fill(),
|
||||||
|
@ -83,7 +126,7 @@ impl Frame {
|
||||||
/// dark canvas to draw on
|
/// dark canvas to draw on
|
||||||
pub fn dark_canvas(style: &Style) -> Self {
|
pub fn dark_canvas(style: &Style) -> Self {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(10.0, 10.0),
|
margin: Margin::symmetric(10.0, 10.0),
|
||||||
rounding: style.visuals.widgets.noninteractive.rounding,
|
rounding: style.visuals.widgets.noninteractive.rounding,
|
||||||
fill: Color32::from_black_alpha(250),
|
fill: Color32::from_black_alpha(250),
|
||||||
stroke: style.visuals.window_stroke(),
|
stroke: style.visuals.window_stroke(),
|
||||||
|
@ -109,7 +152,7 @@ impl Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Margin on each side of the frame.
|
/// Margin on each side of the frame.
|
||||||
pub fn margin(mut self, margin: impl Into<Vec2>) -> Self {
|
pub fn margin(mut self, margin: impl Into<Margin>) -> Self {
|
||||||
self.margin = margin.into();
|
self.margin = margin.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -137,7 +180,10 @@ impl Frame {
|
||||||
pub fn begin(self, ui: &mut Ui) -> Prepared {
|
pub fn begin(self, ui: &mut Ui) -> Prepared {
|
||||||
let where_to_put_background = ui.painter().add(Shape::Noop);
|
let where_to_put_background = ui.painter().add(Shape::Noop);
|
||||||
let outer_rect_bounds = ui.available_rect_before_wrap();
|
let outer_rect_bounds = ui.available_rect_before_wrap();
|
||||||
let mut inner_rect = outer_rect_bounds.shrink2(self.margin);
|
|
||||||
|
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);
|
||||||
|
|
||||||
// Make sure we don't shrink to the negative:
|
// Make sure we don't shrink to the negative:
|
||||||
inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x);
|
inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x);
|
||||||
|
@ -197,7 +243,10 @@ impl Frame {
|
||||||
|
|
||||||
impl Prepared {
|
impl Prepared {
|
||||||
pub fn outer_rect(&self) -> Rect {
|
pub fn outer_rect(&self) -> Rect {
|
||||||
self.content_ui.min_rect().expand2(self.frame.margin)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end(self, ui: &mut Ui) -> Response {
|
pub fn end(self, ui: &mut Ui) -> Response {
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub use {
|
||||||
area::Area,
|
area::Area,
|
||||||
collapsing_header::{CollapsingHeader, CollapsingResponse},
|
collapsing_header::{CollapsingHeader, CollapsingResponse},
|
||||||
combo_box::*,
|
combo_box::*,
|
||||||
frame::Frame,
|
frame::{Frame, Margin},
|
||||||
panel::{CentralPanel, SidePanel, TopBottomPanel},
|
panel::{CentralPanel, SidePanel, TopBottomPanel},
|
||||||
popup::*,
|
popup::*,
|
||||||
resize::Resize,
|
resize::Resize,
|
||||||
|
|
|
@ -302,7 +302,7 @@ pub fn popup_below_widget<R>(
|
||||||
frame
|
frame
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
ui.with_layout(Layout::top_down_justified(Align::LEFT), |ui| {
|
ui.with_layout(Layout::top_down_justified(Align::LEFT), |ui| {
|
||||||
ui.set_width(widget_response.rect.width() - 2.0 * frame_margin.x);
|
ui.set_width(widget_response.rect.width() - frame_margin.sum().x);
|
||||||
add_contents(ui)
|
add_contents(ui)
|
||||||
})
|
})
|
||||||
.inner
|
.inner
|
||||||
|
|
|
@ -178,7 +178,7 @@ impl Resize {
|
||||||
.at_least(self.min_size)
|
.at_least(self.min_size)
|
||||||
.at_most(self.max_size)
|
.at_most(self.max_size)
|
||||||
.at_most(
|
.at_most(
|
||||||
ui.input().screen_rect().size() - 2.0 * ui.spacing().window_padding, // hack for windows
|
ui.input().screen_rect().size() - ui.spacing().window_margin.sum(), // hack for windows
|
||||||
);
|
);
|
||||||
|
|
||||||
State {
|
State {
|
||||||
|
|
|
@ -301,7 +301,7 @@ impl<'open> Window<'open> {
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
let margins = 2.0 * frame.margin + vec2(0.0, title_bar_height);
|
let margins = frame.margin.sum() + vec2(0.0, title_bar_height);
|
||||||
|
|
||||||
interact(
|
interact(
|
||||||
window_interaction,
|
window_interaction,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#![allow(clippy::if_same_then_else)]
|
#![allow(clippy::if_same_then_else)]
|
||||||
|
|
||||||
use crate::{color::*, emath::*, FontFamily, FontId, Response, RichText, WidgetText};
|
use crate::{color::*, emath::*, FontFamily, FontId, Margin, Response, RichText, WidgetText};
|
||||||
use epaint::{mutex::Arc, Rounding, Shadow, Stroke};
|
use epaint::{mutex::Arc, Rounding, Shadow, Stroke};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
@ -220,8 +220,8 @@ pub struct Spacing {
|
||||||
/// widgets `A` and `B` you need to change `item_spacing` before adding `A`.
|
/// widgets `A` and `B` you need to change `item_spacing` before adding `A`.
|
||||||
pub item_spacing: Vec2,
|
pub item_spacing: Vec2,
|
||||||
|
|
||||||
/// Horizontal and vertical padding within a window frame.
|
/// Horizontal and vertical margins within a window frame.
|
||||||
pub window_padding: Vec2,
|
pub window_margin: Margin,
|
||||||
|
|
||||||
/// Button size is text size plus this on each side
|
/// Button size is text size plus this on each side
|
||||||
pub button_padding: Vec2,
|
pub button_padding: Vec2,
|
||||||
|
@ -528,7 +528,7 @@ impl Default for Spacing {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
item_spacing: vec2(8.0, 3.0),
|
item_spacing: vec2(8.0, 3.0),
|
||||||
window_padding: Vec2::splat(6.0),
|
window_margin: Margin::same(6.0),
|
||||||
button_padding: vec2(4.0, 1.0),
|
button_padding: vec2(4.0, 1.0),
|
||||||
indent: 18.0, // match checkbox/radio-button with `button_padding.x + icon_width + icon_spacing`
|
indent: 18.0, // match checkbox/radio-button with `button_padding.x + icon_width + icon_spacing`
|
||||||
interact_size: vec2(40.0, 18.0),
|
interact_size: vec2(40.0, 18.0),
|
||||||
|
@ -803,7 +803,7 @@ impl Spacing {
|
||||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||||
let Self {
|
let Self {
|
||||||
item_spacing,
|
item_spacing,
|
||||||
window_padding,
|
window_margin,
|
||||||
button_padding,
|
button_padding,
|
||||||
indent,
|
indent,
|
||||||
interact_size,
|
interact_size,
|
||||||
|
@ -818,7 +818,37 @@ impl Spacing {
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.add(slider_vec2(item_spacing, 0.0..=20.0, "Item spacing"));
|
ui.add(slider_vec2(item_spacing, 0.0..=20.0, "Item spacing"));
|
||||||
ui.add(slider_vec2(window_padding, 0.0..=20.0, "Window padding"));
|
|
||||||
|
let margin_range = 0.0..=20.0;
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add(
|
||||||
|
DragValue::new(&mut window_margin.left)
|
||||||
|
.clamp_range(margin_range.clone())
|
||||||
|
.prefix("left: "),
|
||||||
|
);
|
||||||
|
ui.add(
|
||||||
|
DragValue::new(&mut window_margin.right)
|
||||||
|
.clamp_range(margin_range.clone())
|
||||||
|
.prefix("right: "),
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.label("Window margins x");
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add(
|
||||||
|
DragValue::new(&mut window_margin.top)
|
||||||
|
.clamp_range(margin_range.clone())
|
||||||
|
.prefix("top: "),
|
||||||
|
);
|
||||||
|
ui.add(
|
||||||
|
DragValue::new(&mut window_margin.bottom)
|
||||||
|
.clamp_range(margin_range)
|
||||||
|
.prefix("bottom: "),
|
||||||
|
);
|
||||||
|
ui.label("Window margins y");
|
||||||
|
});
|
||||||
|
|
||||||
ui.add(slider_vec2(button_padding, 0.0..=20.0, "Button padding"));
|
ui.add(slider_vec2(button_padding, 0.0..=20.0, "Button padding"));
|
||||||
ui.add(slider_vec2(interact_size, 4.0..=60.0, "Interact size"))
|
ui.add(slider_vec2(interact_size, 4.0..=60.0, "Interact size"))
|
||||||
.on_hover_text("Minimum size of an interactive widget");
|
.on_hover_text("Minimum size of an interactive widget");
|
||||||
|
|
|
@ -239,7 +239,7 @@ impl Widget for &mut LegendWidget {
|
||||||
legend_ui
|
legend_ui
|
||||||
.scope(|ui| {
|
.scope(|ui| {
|
||||||
let background_frame = Frame {
|
let background_frame = Frame {
|
||||||
margin: vec2(8.0, 4.0),
|
margin: vec2(8.0, 4.0).into(),
|
||||||
rounding: ui.style().visuals.window_rounding,
|
rounding: ui.style().visuals.window_rounding,
|
||||||
shadow: epaint::Shadow::default(),
|
shadow: epaint::Shadow::default(),
|
||||||
fill: ui.style().visuals.extreme_bg_color,
|
fill: ui.style().visuals.extreme_bg_color,
|
||||||
|
|
Loading…
Reference in a new issue