Browse Source

Style tweaks (#2406)

* Note the namechange of egui::color to egui::ecolor

* Use a solid triangle for collapsing headers and windows

* Add Shadow::NONE

* Add Visuals::panel_fill, window_fill and window_stroke

* Bug fix: ComboBox::width sets the outer width of the ComboBox

* egui_extras::Table: add functions to access the `Ui` for the header/body

* ComboBox: use solid triangle

* Tweak default menu margin

* Nudge panel separator lines so they stay visible

* Update changelogs
pull/2416/head
Emil Ernerfeldt 2 years ago
committed by GitHub
parent
commit
da0a178701
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 7
      crates/egui/src/containers/collapsing_header.rs
  3. 29
      crates/egui/src/containers/combo_box.rs
  4. 4
      crates/egui/src/containers/frame.rs
  5. 10
      crates/egui/src/containers/panel.rs
  6. 173
      crates/egui/src/style.rs
  7. 2
      crates/egui/src/ui.rs
  8. 2
      crates/egui/src/widgets/plot/legend.rs
  9. 2
      crates/egui_demo_app/src/wrap_app.rs
  10. 5
      crates/egui_demo_lib/src/demo/drag_and_drop.rs
  11. 14
      crates/egui_extras/src/table.rs
  12. 5
      crates/epaint/src/shadow.rs

3
CHANGELOG.md

@ -25,6 +25,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
* Added `Area::pivot` and `Window::pivot` which controls what part of the window to position ([#2303](https://github.com/emilk/egui/pull/2303)).
* Added support for [thin space](https://en.wikipedia.org/wiki/Thin_space).
* Added optional integration with [AccessKit](https://accesskit.dev/) for implementing platform accessibility APIs ([#2294](https://github.com/emilk/egui/pull/2294)).
* Added `panel_fill`, `window_fill` and `window_stroke` to `Visuals` for your theming pleasure ([#2406](https://github.com/emilk/egui/pull/2406)).
* Plots:
* Allow linking plot cursors ([#1722](https://github.com/emilk/egui/pull/1722)).
* Added `Plot::auto_bounds_x/y` and `Plot::reset` ([#2029](https://github.com/emilk/egui/pull/2029)).
@ -36,6 +37,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
* Panels always have a separator line, but no stroke on other sides. Their spacing has also changed slightly ([#2261](https://github.com/emilk/egui/pull/2261)).
* Tooltips are only shown when mouse pointer is still ([#2263](https://github.com/emilk/egui/pull/2263)).
* Make it slightly easier to click buttons ([#2304](https://github.com/emilk/egui/pull/2304)).
* `egui::color` has been renamed `egui::ecolor` ([#2399](https://github.com/emilk/egui/pull/2399)).
### Fixed 🐛
* ⚠️ BREAKING: Fix text being too small ([#2069](https://github.com/emilk/egui/pull/2069)).
@ -52,6 +54,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
* Fix bug in `plot::Line::fill` ([#2275](https://github.com/emilk/egui/pull/2275)).
* Only emit `changed` events in `radio_value` and `selectable_value` if the value actually changed ([#2343](https://github.com/emilk/egui/pull/2343)).
* Fixed sizing bug in `Grid` ([#2384](https://github.com/emilk/egui/pull/2384)).
* `ComboBox::width` now correctly sets the outer width ([#2406](https://github.com/emilk/egui/pull/2406)).
## 0.19.0 - 2022-08-20

7
crates/egui/src/containers/collapsing_header.rs

@ -311,7 +311,6 @@ impl<'ui, HeaderRet> HeaderResponse<'ui, HeaderRet> {
/// Paint the arrow icon that indicated if the region is open or not
pub fn paint_default_icon(ui: &mut Ui, openness: f32, response: &Response) {
let visuals = ui.style().interact(response);
let stroke = visuals.fg_stroke;
let rect = response.rect;
@ -325,7 +324,11 @@ pub fn paint_default_icon(ui: &mut Ui, openness: f32, response: &Response) {
*p = rect.center() + rotation * (*p - rect.center());
}
ui.painter().add(Shape::closed_line(points, stroke));
ui.painter().add(Shape::convex_polygon(
points,
visuals.fg_stroke.color,
Stroke::NONE,
));
}
/// A function that paints an icon indicating if the region is open or not

29
crates/egui/src/containers/combo_box.rs

@ -77,7 +77,7 @@ impl ComboBox {
}
}
/// Set the width of the button and menu
/// Set the outer width of the button and menu.
pub fn width(mut self, width: f32) -> Self {
self.width = Some(width);
self
@ -261,15 +261,20 @@ fn combo_box_dyn<'c, R>(
AboveOrBelow::Above
};
let margin = ui.spacing().button_padding;
let button_response = button_frame(ui, button_id, is_popup_open, Sense::click(), |ui| {
// We don't want to change width when user selects something new
let full_minimum_width = wrap_enabled
.then(|| ui.available_width() - ui.spacing().item_spacing.x * 2.0)
.unwrap_or_else(|| ui.spacing().slider_width);
let full_minimum_width = if wrap_enabled {
ui.available_width() - ui.spacing().item_spacing.x * 2.0
} else {
ui.spacing().slider_width - 2.0 * margin.x
};
let icon_size = Vec2::splat(ui.spacing().icon_width);
let wrap_width = wrap_enabled
.then(|| ui.available_width() - ui.spacing().item_spacing.x - icon_size.x)
.unwrap_or(f32::INFINITY);
let wrap_width = if wrap_enabled {
ui.available_width() - ui.spacing().item_spacing.x - icon_size.x
} else {
f32::INFINITY
};
let galley =
selected_text.into_galley(ui, Some(wrap_enabled), wrap_width, TextStyle::Button);
@ -396,16 +401,18 @@ fn paint_default_icon(
match above_or_below {
AboveOrBelow::Above => {
// Upward pointing triangle
painter.add(Shape::closed_line(
painter.add(Shape::convex_polygon(
vec![rect.left_bottom(), rect.right_bottom(), rect.center_top()],
visuals.fg_stroke,
visuals.fg_stroke.color,
Stroke::NONE,
));
}
AboveOrBelow::Below => {
// Downward pointing triangle
painter.add(Shape::closed_line(
painter.add(Shape::convex_polygon(
vec![rect.left_top(), rect.right_top(), rect.center_bottom()],
visuals.fg_stroke,
visuals.fg_stroke.color,
Stroke::NONE,
));
}
}

4
crates/egui/src/containers/frame.rs

@ -45,7 +45,7 @@ impl Frame {
pub fn side_top_panel(style: &Style) -> Self {
Self {
inner_margin: Margin::symmetric(8.0, 2.0),
fill: style.visuals.window_fill(),
fill: style.visuals.panel_fill,
..Default::default()
}
}
@ -53,7 +53,7 @@ impl Frame {
pub fn central_panel(style: &Style) -> Self {
Self {
inner_margin: Margin::same(8.0),
fill: style.visuals.window_fill(),
fill: style.visuals.panel_fill,
..Default::default()
}
}

10
crates/egui/src/containers/panel.rs

@ -306,7 +306,10 @@ impl SidePanel {
Stroke::NONE
};
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
let resize_x = side.opposite().side_x(rect);
// In the meantime: nudge the line so its inside the panel, so it won't be covered by neighboring panel
// (hence the shrink).
let resize_x = side.opposite().side_x(rect.shrink(1.0));
let resize_x = ui.painter().round_to_pixel(resize_x);
ui.painter().vline(resize_x, rect.y_range(), stroke);
}
@ -755,7 +758,10 @@ impl TopBottomPanel {
Stroke::NONE
};
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
let resize_y = side.opposite().side_y(rect);
// In the meantime: nudge the line so its inside the panel, so it won't be covered by neighboring panel
// (hence the shrink).
let resize_y = side.opposite().side_y(rect.shrink(1.0));
let resize_y = ui.painter().round_to_pixel(resize_y);
ui.painter().hline(rect.x_range(), resize_y, stroke);
}

173
crates/egui/src/style.rs

@ -360,6 +360,10 @@ impl Margin {
pub fn right_bottom(&self) -> Vec2 {
vec2(self.right, self.bottom)
}
pub fn is_same(&self) -> bool {
self.left == self.right && self.left == self.top && self.left == self.bottom
}
}
impl From<f32> for Margin {
@ -464,6 +468,11 @@ pub struct Visuals {
pub window_rounding: Rounding,
pub window_shadow: Shadow,
pub window_fill: Color32,
pub window_stroke: Stroke,
/// Panel background color
pub panel_fill: Color32,
pub popup_shadow: Shadow,
@ -495,7 +504,7 @@ impl Visuals {
}
pub fn weak_text_color(&self) -> Color32 {
crate::ecolor::tint_color_towards(self.text_color(), self.window_fill())
self.gray_out(self.text_color())
}
#[inline(always)]
@ -506,12 +515,25 @@ impl Visuals {
/// Window background color.
#[inline(always)]
pub fn window_fill(&self) -> Color32 {
self.widgets.noninteractive.bg_fill
self.window_fill
}
#[inline(always)]
pub fn window_stroke(&self) -> Stroke {
self.widgets.noninteractive.bg_stroke
self.window_stroke
}
/// When fading out things, we fade the colors towards this.
// TODO(emilk): replace with an alpha
#[inline(always)]
pub fn fade_out_to_color(&self) -> Color32 {
self.widgets.noninteractive.bg_fill
}
/// Returned a "grayed out" version of the given color.
#[inline(always)]
pub fn gray_out(&self, color: Color32) -> Color32 {
crate::ecolor::tint_color_towards(color, self.fade_out_to_color())
}
}
@ -651,7 +673,7 @@ impl Default for Spacing {
Self {
item_spacing: vec2(8.0, 3.0),
window_margin: Margin::same(6.0),
menu_margin: Margin::same(1.0),
menu_margin: Margin::same(6.0),
button_padding: vec2(4.0, 1.0),
indent: 18.0, // match checkbox/radio-button with `button_padding.x + icon_width + icon_spacing`
interact_size: vec2(40.0, 18.0),
@ -694,8 +716,14 @@ impl Visuals {
code_bg_color: Color32::from_gray(64),
warn_fg_color: Color32::from_rgb(255, 143, 0), // orange
error_fg_color: Color32::from_rgb(255, 0, 0), // red
window_rounding: Rounding::same(6.0),
window_shadow: Shadow::big_dark(),
window_fill: Color32::from_gray(27),
window_stroke: Stroke::new(1.0, Color32::from_gray(60)),
panel_fill: Color32::from_gray(27),
popup_shadow: Shadow::small_dark(),
resize_corner_size: 12.0,
text_cursor_width: 2.0,
@ -718,7 +746,13 @@ impl Visuals {
code_bg_color: Color32::from_gray(230),
warn_fg_color: Color32::from_rgb(255, 100, 0), // slightly orange red. it's difficult to find a warning color that pops on bright background.
error_fg_color: Color32::from_rgb(255, 0, 0), // red
window_shadow: Shadow::big_light(),
window_fill: Color32::from_gray(248),
window_stroke: Stroke::new(1.0, Color32::from_gray(190)),
panel_fill: Color32::from_gray(248),
popup_shadow: Shadow::small_light(),
..Self::dark()
}
@ -757,8 +791,8 @@ impl Widgets {
pub fn dark() -> Self {
Self {
noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(27), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // separators, indentation lines, windows outlines
bg_fill: Color32::from_gray(27),
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // separators, indentation lines
fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // normal text color
rounding: Rounding::same(2.0),
expansion: 0.0,
@ -797,8 +831,8 @@ impl Widgets {
pub fn light() -> Self {
Self {
noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(248), // window background - should be distinct from TextEdit background
bg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // separators, indentation lines, windows outlines
bg_fill: Color32::from_gray(248),
bg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // separators, indentation lines
fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // normal text color
rounding: Rounding::same(2.0),
expansion: 0.0,
@ -954,64 +988,8 @@ impl Spacing {
ui.add(slider_vec2(item_spacing, 0.0..=20.0, "Item spacing"));
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.clone())
.prefix("bottom: "),
);
ui.label("Window margins y");
});
ui.horizontal(|ui| {
ui.add(
DragValue::new(&mut menu_margin.left)
.clamp_range(margin_range.clone())
.prefix("left: "),
);
ui.add(
DragValue::new(&mut menu_margin.right)
.clamp_range(margin_range.clone())
.prefix("right: "),
);
ui.label("Menu margins x");
});
ui.horizontal(|ui| {
ui.add(
DragValue::new(&mut menu_margin.top)
.clamp_range(margin_range.clone())
.prefix("top: "),
);
ui.add(
DragValue::new(&mut menu_margin.bottom)
.clamp_range(margin_range)
.prefix("bottom: "),
);
ui.label("Menu margins y");
});
margin_ui(ui, "Window margin:", window_margin);
margin_ui(ui, "Menu margin:", menu_margin);
ui.add(slider_vec2(button_padding, 0.0..=20.0, "Button padding"));
ui.add(slider_vec2(interact_size, 4.0..=60.0, "Interact size"))
@ -1079,6 +1057,55 @@ impl Spacing {
}
}
fn margin_ui(ui: &mut Ui, text: &str, margin: &mut Margin) {
let margin_range = 0.0..=20.0;
ui.horizontal(|ui| {
ui.label(text);
let mut same = margin.is_same();
ui.checkbox(&mut same, "Same");
if same {
let mut value = margin.left;
ui.add(DragValue::new(&mut value).clamp_range(margin_range.clone()));
*margin = Margin::same(value);
} else {
if margin.is_same() {
// HACK: prevent collapse:
margin.right = margin.left + 1.0;
margin.bottom = margin.left + 2.0;
margin.top = margin.left + 3.0;
}
ui.add(
DragValue::new(&mut margin.left)
.clamp_range(margin_range.clone())
.prefix("L: "),
)
.on_hover_text("Left margin");
ui.add(
DragValue::new(&mut margin.right)
.clamp_range(margin_range.clone())
.prefix("R: "),
)
.on_hover_text("Right margin");
ui.add(
DragValue::new(&mut margin.top)
.clamp_range(margin_range.clone())
.prefix("T: "),
)
.on_hover_text("Top margin");
ui.add(
DragValue::new(&mut margin.bottom)
.clamp_range(margin_range)
.prefix("B: "),
)
.on_hover_text("Bottom margin");
}
});
}
impl Interaction {
pub fn ui(&mut self, ui: &mut crate::Ui) {
let Self {
@ -1210,9 +1237,16 @@ impl Visuals {
code_bg_color,
warn_fg_color,
error_fg_color,
window_rounding,
window_shadow,
window_fill,
window_stroke,
panel_fill,
popup_shadow,
resize_corner_size,
text_cursor_width,
text_cursor_preview,
@ -1223,7 +1257,8 @@ impl Visuals {
ui.collapsing("Background Colors", |ui| {
ui_color(ui, &mut widgets.inactive.bg_fill, "Buttons");
ui_color(ui, &mut widgets.noninteractive.bg_fill, "Windows");
ui_color(ui, window_fill, "Windows");
ui_color(ui, panel_fill, "Panels");
ui_color(ui, faint_bg_color, "Faint accent").on_hover_text(
"Used for faint accentuation of interactive things, like striped grids.",
);
@ -1233,8 +1268,8 @@ impl Visuals {
ui.collapsing("Window", |ui| {
// Common shortcuts
ui_color(ui, &mut widgets.noninteractive.bg_fill, "Fill");
stroke_ui(ui, &mut widgets.noninteractive.bg_stroke, "Outline");
ui_color(ui, window_fill, "Fill");
stroke_ui(ui, window_stroke, "Outline");
rounding_ui(ui, window_rounding);

2
crates/egui/src/ui.rs

@ -239,7 +239,7 @@ impl Ui {
self.enabled &= enabled;
if !self.enabled && self.is_visible() {
self.painter
.set_fade_to_color(Some(self.visuals().window_fill()));
.set_fade_to_color(Some(self.visuals().fade_out_to_color()));
}
}

2
crates/egui/src/widgets/plot/legend.rs

@ -239,7 +239,7 @@ impl Widget for &mut LegendWidget {
let background_frame = Frame {
inner_margin: vec2(8.0, 4.0).into(),
rounding: ui.style().visuals.window_rounding,
shadow: epaint::Shadow::default(),
shadow: epaint::Shadow::NONE,
fill: ui.style().visuals.extreme_bg_color,
stroke: ui.style().visuals.window_stroke(),
..Default::default()

2
crates/egui_demo_app/src/wrap_app.rs

@ -176,7 +176,7 @@ impl eframe::App for WrapApp {
}
fn clear_color(&self, visuals: &egui::Visuals) -> egui::Rgba {
visuals.window_fill().into()
visuals.panel_fill.into()
}
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {

5
crates/egui_demo_lib/src/demo/drag_and_drop.rs

@ -58,9 +58,8 @@ pub fn drop_target<R>(
let mut fill = style.bg_fill;
let mut stroke = style.bg_stroke;
if is_being_dragged && !can_accept_what_is_being_dragged {
// gray out:
fill = ecolor::tint_color_towards(fill, ui.visuals().window_fill());
stroke.color = ecolor::tint_color_towards(stroke.color, ui.visuals().window_fill());
fill = ui.visuals().gray_out(fill);
stroke.color = ui.visuals().gray_out(stroke.color);
}
ui.painter().set(

14
crates/egui_extras/src/table.rs

@ -516,6 +516,13 @@ pub struct Table<'a> {
}
impl<'a> Table<'a> {
/// Access the contained [`egui::Ui`].
///
/// You can use this to e.g. modify the [`egui::Style`] with [`egui::Ui::style_mut`].
pub fn ui_mut(&mut self) -> &mut egui::Ui {
self.ui
}
/// Create table body after adding a header row
pub fn body<F>(self, add_body_contents: F)
where
@ -724,6 +731,13 @@ pub struct TableBody<'a> {
}
impl<'a> TableBody<'a> {
/// Access the contained [`egui::Ui`].
///
/// You can use this to e.g. modify the [`egui::Style`] with [`egui::Ui::style_mut`].
pub fn ui_mut(&mut self) -> &mut egui::Ui {
self.layout.ui
}
/// Where in screen-space is the table body?
pub fn max_rect(&self) -> Rect {
self.layout

5
crates/epaint/src/shadow.rs

@ -14,6 +14,11 @@ pub struct Shadow {
}
impl Shadow {
pub const NONE: Self = Self {
extrusion: 0.0,
color: Color32::TRANSPARENT,
};
/// Tooltips, menus, …, for dark mode.
pub fn small_dark() -> Self {
Self {

Loading…
Cancel
Save