Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per-corner rounding of rectangles #1206

Merged
merged 5 commits into from
Feb 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions egui/src/containers/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use epaint::*;
pub struct Frame {
/// On each side
pub margin: Vec2,
pub corner_radius: f32,
pub corner_radius: Rounding,
pub shadow: Shadow,
pub fill: Color32,
pub stroke: Stroke,
Expand All @@ -33,7 +33,7 @@ impl Frame {
pub(crate) fn side_top_panel(style: &Style) -> Self {
Self {
margin: Vec2::new(8.0, 2.0),
corner_radius: 0.0,
corner_radius: Rounding::none(),
fill: style.visuals.window_fill(),
stroke: style.visuals.window_stroke(),
..Default::default()
Expand All @@ -43,7 +43,7 @@ impl Frame {
pub(crate) fn central_panel(style: &Style) -> Self {
Self {
margin: Vec2::new(8.0, 8.0),
corner_radius: 0.0,
corner_radius: Rounding::none(),
fill: style.visuals.window_fill(),
stroke: Default::default(),
..Default::default()
Expand Down Expand Up @@ -103,8 +103,8 @@ impl Frame {
self
}

pub fn corner_radius(mut self, corner_radius: f32) -> Self {
self.corner_radius = corner_radius;
pub fn corner_radius(mut self, corner_radius: impl Into<Rounding>) -> Self {
self.corner_radius = corner_radius.into();
self
}

Expand Down
32 changes: 16 additions & 16 deletions egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,36 +705,36 @@ fn paint_frame_interaction(
let mut points = Vec::new();

if interaction.right && !interaction.bottom && !interaction.top {
points.push(pos2(max.x, min.y + cr));
points.push(pos2(max.x, max.y - cr));
points.push(pos2(max.x, min.y + cr.ne));
points.push(pos2(max.x, max.y - cr.se));
}
if interaction.right && interaction.bottom {
points.push(pos2(max.x, min.y + cr));
points.push(pos2(max.x, max.y - cr));
add_circle_quadrant(&mut points, pos2(max.x - cr, max.y - cr), cr, 0.0);
points.push(pos2(max.x, min.y + cr.ne));
points.push(pos2(max.x, max.y - cr.se));
add_circle_quadrant(&mut points, pos2(max.x - cr.se, max.y - cr.se), cr.se, 0.0);
}
if interaction.bottom {
points.push(pos2(max.x - cr, max.y));
points.push(pos2(min.x + cr, max.y));
points.push(pos2(max.x - cr.se, max.y));
points.push(pos2(min.x + cr.sw, max.y));
}
if interaction.left && interaction.bottom {
add_circle_quadrant(&mut points, pos2(min.x + cr, max.y - cr), cr, 1.0);
add_circle_quadrant(&mut points, pos2(min.x + cr.sw, max.y - cr.sw), cr.sw, 1.0);
}
if interaction.left {
points.push(pos2(min.x, max.y - cr));
points.push(pos2(min.x, min.y + cr));
points.push(pos2(min.x, max.y - cr.sw));
points.push(pos2(min.x, min.y + cr.nw));
}
if interaction.left && interaction.top {
add_circle_quadrant(&mut points, pos2(min.x + cr, min.y + cr), cr, 2.0);
add_circle_quadrant(&mut points, pos2(min.x + cr.nw, min.y + cr.nw), cr.nw, 2.0);
}
if interaction.top {
points.push(pos2(min.x + cr, min.y));
points.push(pos2(max.x - cr, min.y));
points.push(pos2(min.x + cr.nw, min.y));
points.push(pos2(max.x - cr.ne, min.y));
}
if interaction.right && interaction.top {
add_circle_quadrant(&mut points, pos2(max.x - cr, min.y + cr), cr, 3.0);
points.push(pos2(max.x, min.y + cr));
points.push(pos2(max.x, max.y - cr));
add_circle_quadrant(&mut points, pos2(max.x - cr.ne, min.y + cr.ne), cr.ne, 3.0);
points.push(pos2(max.x, min.y + cr.ne));
points.push(pos2(max.x, max.y - cr.se));
}
ui.painter().add(Shape::line(points, visuals.bg_stroke));
}
Expand Down
4 changes: 2 additions & 2 deletions egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,8 @@ pub use epaint::{
color, mutex,
text::{FontData, FontDefinitions, FontFamily, FontId},
textures::TexturesDelta,
AlphaImage, ClippedMesh, Color32, ColorImage, ImageData, Rgba, Shape, Stroke, TextureHandle,
TextureId,
AlphaImage, ClippedMesh, Color32, ColorImage, ImageData, Rgba, Rounding, Shape, Stroke,
TextureHandle, TextureId,
};

pub mod text {
Expand Down
24 changes: 17 additions & 7 deletions egui/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
use epaint::{
mutex::{Arc, RwLockReadGuard, RwLockWriteGuard},
text::{Fonts, Galley},
CircleShape, RectShape, Shape, Stroke, TextShape,
CircleShape, RectShape, Rounding, Shape, Stroke, TextShape,
};

/// Helper to paint shapes and text to a specific region on a specific layer.
Expand Down Expand Up @@ -278,31 +278,41 @@ impl Painter {
pub fn rect(
&self,
rect: Rect,
corner_radius: f32,
corner_radius: impl Into<Rounding>,
fill_color: impl Into<Color32>,
stroke: impl Into<Stroke>,
) {
self.add(RectShape {
rect,
corner_radius,
corner_radius: corner_radius.into(),
fill: fill_color.into(),
stroke: stroke.into(),
});
}

pub fn rect_filled(&self, rect: Rect, corner_radius: f32, fill_color: impl Into<Color32>) {
pub fn rect_filled(
&self,
rect: Rect,
corner_radius: impl Into<Rounding>,
fill_color: impl Into<Color32>,
) {
self.add(RectShape {
rect,
corner_radius,
corner_radius: corner_radius.into(),
fill: fill_color.into(),
stroke: Default::default(),
});
}

pub fn rect_stroke(&self, rect: Rect, corner_radius: f32, stroke: impl Into<Stroke>) {
pub fn rect_stroke(
&self,
rect: Rect,
corner_radius: impl Into<Rounding>,
stroke: impl Into<Stroke>,
) {
self.add(RectShape {
rect,
corner_radius,
corner_radius: corner_radius.into(),
fill: Default::default(),
stroke: stroke.into(),
});
Expand Down
43 changes: 27 additions & 16 deletions egui/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![allow(clippy::if_same_then_else)]

use crate::{color::*, emath::*, FontFamily, FontId, Response, RichText, WidgetText};
use epaint::{mutex::Arc, Shadow, Stroke};
use epaint::{mutex::Arc, Rounding, Shadow, Stroke};
use std::collections::BTreeMap;

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -344,7 +344,7 @@ pub struct Visuals {
/// Background color behind code-styled monospaced labels.
pub code_bg_color: Color32,

pub window_corner_radius: f32,
pub window_corner_radius: Rounding,
pub window_shadow: Shadow,

pub popup_shadow: Shadow,
Expand Down Expand Up @@ -453,7 +453,7 @@ pub struct WidgetVisuals {
pub bg_stroke: Stroke,

/// Button frames etc.
pub corner_radius: f32,
pub corner_radius: Rounding,

/// Stroke and text color of the interactive part of a component (button text, slider grab, check-mark, …).
pub fg_stroke: Stroke,
Expand Down Expand Up @@ -566,7 +566,7 @@ impl Visuals {
faint_bg_color: Color32::from_gray(24),
extreme_bg_color: Color32::from_gray(10),
code_bg_color: Color32::from_gray(64),
window_corner_radius: 6.0,
window_corner_radius: Rounding::same(6.0),
window_shadow: Shadow::big_dark(),
popup_shadow: Shadow::small_dark(),
resize_corner_size: 12.0,
Expand Down Expand Up @@ -629,35 +629,35 @@ impl Widgets {
bg_fill: Color32::from_gray(27), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // separators, indentation lines, windows outlines
fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // normal text color
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 0.0,
},
inactive: WidgetVisuals {
bg_fill: Color32::from_gray(60), // button background
bg_stroke: Default::default(),
fg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // button text
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 0.0,
},
hovered: WidgetVisuals {
bg_fill: Color32::from_gray(70),
bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button
fg_stroke: Stroke::new(1.5, Color32::from_gray(240)),
corner_radius: 3.0,
corner_radius: Rounding::same(3.0),
expansion: 1.0,
},
active: WidgetVisuals {
bg_fill: Color32::from_gray(55),
bg_stroke: Stroke::new(1.0, Color32::WHITE),
fg_stroke: Stroke::new(2.0, Color32::WHITE),
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 1.0,
},
open: WidgetVisuals {
bg_fill: Color32::from_gray(27),
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)),
fg_stroke: Stroke::new(1.0, Color32::from_gray(210)),
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 0.0,
},
}
Expand All @@ -669,35 +669,35 @@ impl Widgets {
bg_fill: Color32::from_gray(235), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // separators, indentation lines, windows outlines
fg_stroke: Stroke::new(1.0, Color32::from_gray(100)), // normal text color
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 0.0,
},
inactive: WidgetVisuals {
bg_fill: Color32::from_gray(215), // button background
bg_stroke: Default::default(),
fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // button text
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 0.0,
},
hovered: WidgetVisuals {
bg_fill: Color32::from_gray(210),
bg_stroke: Stroke::new(1.0, Color32::from_gray(105)), // e.g. hover over window edge or button
fg_stroke: Stroke::new(1.5, Color32::BLACK),
corner_radius: 3.0,
corner_radius: Rounding::same(3.0),
expansion: 1.0,
},
active: WidgetVisuals {
bg_fill: Color32::from_gray(165),
bg_stroke: Stroke::new(1.0, Color32::BLACK),
fg_stroke: Stroke::new(2.0, Color32::BLACK),
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 1.0,
},
open: WidgetVisuals {
bg_fill: Color32::from_gray(220),
bg_stroke: Stroke::new(1.0, Color32::from_gray(160)),
fg_stroke: Stroke::new(1.0, Color32::BLACK),
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
expansion: 0.0,
},
}
Expand Down Expand Up @@ -949,7 +949,12 @@ impl WidgetVisuals {
} = self;
ui_color(ui, bg_fill, "bg_fill");
stroke_ui(ui, bg_stroke, "bg_stroke");
ui.add(Slider::new(corner_radius, 0.0..=10.0).text("corner_radius"));

ui.add(Slider::new(&mut corner_radius.nw, 0.0..=10.0).text("corner_radius_nw"));
ui.add(Slider::new(&mut corner_radius.ne, 0.0..=10.0).text("corner_radius_ne"));
ui.add(Slider::new(&mut corner_radius.sw, 0.0..=10.0).text("corner_radius_sw"));
ui.add(Slider::new(&mut corner_radius.se, 0.0..=10.0).text("corner_radius_se"));

stroke_ui(ui, fg_stroke, "fg_stroke (text)");
ui.add(Slider::new(expansion, -5.0..=5.0).text("expansion"))
.on_hover_text("make shapes this much larger");
Expand Down Expand Up @@ -1024,7 +1029,13 @@ impl Visuals {
// Common shortcuts
ui_color(ui, &mut widgets.noninteractive.bg_fill, "Fill");
stroke_ui(ui, &mut widgets.noninteractive.bg_stroke, "Outline");
ui.add(Slider::new(window_corner_radius, 0.0..=20.0).text("Rounding"));

ui.label("Rounding");
ui.add(Slider::new(&mut window_corner_radius.nw, 0.0..=20.0).text("Top Left"));
ui.add(Slider::new(&mut window_corner_radius.ne, 0.0..=20.0).text("Top Right"));
ui.add(Slider::new(&mut window_corner_radius.sw, 0.0..=20.0).text("Bottom Left"));
ui.add(Slider::new(&mut window_corner_radius.se, 0.0..=20.0).text("Bottom Right"));

shadow_ui(ui, window_shadow, "Shadow");
shadow_ui(ui, popup_shadow, "Shadow (small menus and popups)");
});
Expand Down
7 changes: 6 additions & 1 deletion egui/src/widgets/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,12 @@ impl Widget for ImageButton {
if ui.is_rect_visible(rect) {
let (expansion, corner_radius, fill, stroke) = if selected {
let selection = ui.visuals().selection;
(-padding, 0.0, selection.bg_fill, selection.stroke)
(
-padding,
Rounding::none(),
selection.bg_fill,
selection.stroke,
)
} else if frame {
let visuals = ui.style().interact(&response);
let expansion = if response.hovered {
Expand Down
10 changes: 8 additions & 2 deletions egui/src/widgets/color_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn show_hsva(ui: &mut Ui, color: Hsva, desired_size: Vec2) -> Response {
} else {
ui.painter().add(RectShape {
rect,
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
fill: color.into(),
stroke: Stroke::new(3.0, color.to_opaque()),
});
Expand Down Expand Up @@ -90,7 +90,13 @@ fn color_button(ui: &mut Ui, color: Color32, open: bool) -> Response {
ui.painter().rect_filled(left_half, 0.0, color);
ui.painter().rect_filled(right_half, 0.0, color.to_opaque());

let corner_radius = visuals.corner_radius.at_most(2.0);
let corner_radius = Rounding {
nw: visuals.corner_radius.nw.at_most(2.0),
ne: visuals.corner_radius.ne.at_most(2.0),
sw: visuals.corner_radius.sw.at_most(2.0),
se: visuals.corner_radius.se.at_most(2.0),
};

ui.painter()
.rect_stroke(rect, corner_radius, (2.0, visuals.bg_fill)); // fill is intentional, because default style has no border
}
Expand Down
4 changes: 2 additions & 2 deletions egui/src/widgets/plot/items/bar.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::emath::NumExt;
use crate::epaint::{Color32, RectShape, Shape, Stroke};
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};

use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
use crate::plot::{BarChart, ScreenTransform, Value};
Expand Down Expand Up @@ -129,7 +129,7 @@ impl Bar {
let rect = transform.rect_from_values(&self.bounds_min(), &self.bounds_max());
let rect = Shape::Rect(RectShape {
rect,
corner_radius: 0.0,
corner_radius: Rounding::none(),
fill,
stroke,
});
Expand Down
4 changes: 2 additions & 2 deletions egui/src/widgets/plot/items/box_elem.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::emath::NumExt;
use crate::epaint::{Color32, RectShape, Shape, Stroke};
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};

use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
use crate::plot::{BoxPlot, ScreenTransform, Value};
Expand Down Expand Up @@ -152,7 +152,7 @@ impl BoxElem {
);
let rect = Shape::Rect(RectShape {
rect,
corner_radius: 0.0,
corner_radius: Rounding::none(),
fill,
stroke,
});
Expand Down
2 changes: 1 addition & 1 deletion egui/src/widgets/plot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ impl Plot {
if show_background {
ui.painter().sub_region(rect).add(epaint::RectShape {
rect,
corner_radius: 2.0,
corner_radius: Rounding::same(2.0),
fill: ui.visuals().extreme_bg_color,
stroke: ui.visuals().widgets.noninteractive.bg_stroke,
});
Expand Down
2 changes: 1 addition & 1 deletion epaint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub use {
image::{AlphaImage, ColorImage, ImageData, ImageDelta},
mesh::{Mesh, Mesh16, Vertex},
shadow::Shadow,
shape::{CircleShape, PathShape, RectShape, Shape, TextShape},
shape::{CircleShape, PathShape, RectShape, Rounding, Shape, TextShape},
stats::PaintStats,
stroke::Stroke,
tessellator::{tessellate_shapes, TessellationOptions, Tessellator},
Expand Down
Loading