Use `u8` in `Rounding`, and introduce `Roundingf` (#5563)
* Part of https://github.com/emilk/egui/issues/4019 As part of the work on adding a custom `Border` to everything, I want to make sure that the size of `RectShape`, `Frame` and the future `Border` is kept small (for performance reasons). This PR changes the storage of the corner radius of rectangles from four `f32` (one for each corner) into four `u8`. This mean the corner radius can only be an integer in the range 0-255 (in ui points). This should be enough for most people. If you want to manipulate rounding using `f32`, there is a new `Roundingf` to fill that niche.
This commit is contained in:
parent
3ffe1ed774
commit
249f8bcb93
|
|
@ -1230,7 +1230,7 @@ egui_extras::install_image_loaders(egui_ctx);
|
|||
* [Tweaked the default visuals style](https://github.com/emilk/egui/pull/450).
|
||||
* Plot: Renamed `Curve` to `Line`.
|
||||
* `TopPanel::top` is now `TopBottomPanel::top`.
|
||||
* `SidePanel::left` no longet takes the default width by argument, but by a builder call.
|
||||
* `SidePanel::left` no longer takes the default width by argument, but by a builder call.
|
||||
* `SidePanel::left` is resizable by default.
|
||||
|
||||
### 🐛 Fixed
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use crate::{
|
|||
TextStyle, Ui, UiKind, Vec2b, WidgetInfo, WidgetRect, WidgetText, WidgetType,
|
||||
};
|
||||
use emath::GuiRounding as _;
|
||||
use epaint::{emath, pos2, vec2, Galley, Pos2, Rect, RectShape, Rounding, Shape, Stroke, Vec2};
|
||||
use epaint::{
|
||||
emath, pos2, vec2, Galley, Pos2, Rect, RectShape, Rounding, Roundingf, Shape, Stroke, Vec2,
|
||||
};
|
||||
|
||||
use super::scroll_area::ScrollBarVisibility;
|
||||
use super::{area, resize, Area, Frame, Resize, ScrollArea};
|
||||
|
|
@ -486,8 +488,9 @@ impl<'open> Window<'open> {
|
|||
let style = ctx.style();
|
||||
let spacing = window_margin.top + window_margin.bottom;
|
||||
let height = ctx.fonts(|f| title.font_height(f, &style)) + spacing;
|
||||
window_frame.rounding.ne = window_frame.rounding.ne.clamp(0.0, height / 2.0);
|
||||
window_frame.rounding.nw = window_frame.rounding.nw.clamp(0.0, height / 2.0);
|
||||
let half_height = (height / 2.0).round() as _;
|
||||
window_frame.rounding.ne = window_frame.rounding.ne.clamp(0, half_height);
|
||||
window_frame.rounding.nw = window_frame.rounding.nw.clamp(0, half_height);
|
||||
(height, spacing)
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
|
|
@ -603,8 +606,8 @@ impl<'open> Window<'open> {
|
|||
let mut round = window_frame.rounding;
|
||||
|
||||
if !is_collapsed {
|
||||
round.se = 0.0;
|
||||
round.sw = 0.0;
|
||||
round.se = 0;
|
||||
round.sw = 0;
|
||||
}
|
||||
|
||||
area_content_ui.painter().set(
|
||||
|
|
@ -682,6 +685,7 @@ fn paint_resize_corner(
|
|||
};
|
||||
|
||||
// Adjust the corner offset to accommodate for window rounding
|
||||
let radius = radius as f32;
|
||||
let offset =
|
||||
((2.0_f32.sqrt() * (1.0 + radius) - radius) * 45.0_f32.to_radians().cos()).max(2.0);
|
||||
|
||||
|
|
@ -1022,7 +1026,7 @@ fn paint_frame_interaction(ui: &Ui, rect: Rect, interaction: ResizeInteraction)
|
|||
bottom = interaction.bottom.hover;
|
||||
}
|
||||
|
||||
let rounding = ui.visuals().window_rounding;
|
||||
let rounding = Roundingf::from(ui.visuals().window_rounding);
|
||||
let Rect { min, max } = rect;
|
||||
|
||||
let mut points = Vec::new();
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@ impl Visuals {
|
|||
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_rounding: Rounding::same(6),
|
||||
window_shadow: Shadow {
|
||||
offset: vec2(10.0, 20.0),
|
||||
blur: 15.0,
|
||||
|
|
@ -1302,7 +1302,7 @@ impl Visuals {
|
|||
window_stroke: Stroke::new(1.0, Color32::from_gray(60)),
|
||||
window_highlight_topmost: true,
|
||||
|
||||
menu_rounding: Rounding::same(6.0),
|
||||
menu_rounding: Rounding::same(6),
|
||||
|
||||
panel_fill: Color32::from_gray(27),
|
||||
|
||||
|
|
@ -1412,7 +1412,7 @@ impl Widgets {
|
|||
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),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 0.0,
|
||||
},
|
||||
inactive: WidgetVisuals {
|
||||
|
|
@ -1420,7 +1420,7 @@ impl Widgets {
|
|||
bg_fill: Color32::from_gray(60), // checkbox background
|
||||
bg_stroke: Default::default(),
|
||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // button text
|
||||
rounding: Rounding::same(2.0),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 0.0,
|
||||
},
|
||||
hovered: WidgetVisuals {
|
||||
|
|
@ -1428,7 +1428,7 @@ impl Widgets {
|
|||
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)),
|
||||
rounding: Rounding::same(3.0),
|
||||
rounding: Rounding::same(3),
|
||||
expansion: 1.0,
|
||||
},
|
||||
active: WidgetVisuals {
|
||||
|
|
@ -1436,7 +1436,7 @@ impl Widgets {
|
|||
bg_fill: Color32::from_gray(55),
|
||||
bg_stroke: Stroke::new(1.0, Color32::WHITE),
|
||||
fg_stroke: Stroke::new(2.0, Color32::WHITE),
|
||||
rounding: Rounding::same(2.0),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 1.0,
|
||||
},
|
||||
open: WidgetVisuals {
|
||||
|
|
@ -1444,7 +1444,7 @@ impl Widgets {
|
|||
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)),
|
||||
rounding: Rounding::same(2.0),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 0.0,
|
||||
},
|
||||
}
|
||||
|
|
@ -1457,7 +1457,7 @@ impl Widgets {
|
|||
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),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 0.0,
|
||||
},
|
||||
inactive: WidgetVisuals {
|
||||
|
|
@ -1465,7 +1465,7 @@ impl Widgets {
|
|||
bg_fill: Color32::from_gray(230), // checkbox background
|
||||
bg_stroke: Default::default(),
|
||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // button text
|
||||
rounding: Rounding::same(2.0),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 0.0,
|
||||
},
|
||||
hovered: WidgetVisuals {
|
||||
|
|
@ -1473,7 +1473,7 @@ impl Widgets {
|
|||
bg_fill: Color32::from_gray(220),
|
||||
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),
|
||||
rounding: Rounding::same(3.0),
|
||||
rounding: Rounding::same(3),
|
||||
expansion: 1.0,
|
||||
},
|
||||
active: WidgetVisuals {
|
||||
|
|
@ -1481,7 +1481,7 @@ impl Widgets {
|
|||
bg_fill: Color32::from_gray(165),
|
||||
bg_stroke: Stroke::new(1.0, Color32::BLACK),
|
||||
fg_stroke: Stroke::new(2.0, Color32::BLACK),
|
||||
rounding: Rounding::same(2.0),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 1.0,
|
||||
},
|
||||
open: WidgetVisuals {
|
||||
|
|
@ -1489,7 +1489,7 @@ impl Widgets {
|
|||
bg_fill: Color32::from_gray(220),
|
||||
bg_stroke: Stroke::new(1.0, Color32::from_gray(160)),
|
||||
fg_stroke: Stroke::new(1.0, Color32::BLACK),
|
||||
rounding: Rounding::same(2.0),
|
||||
rounding: Rounding::same(2),
|
||||
expansion: 0.0,
|
||||
},
|
||||
}
|
||||
|
|
@ -2420,9 +2420,16 @@ impl Widget for &mut Rounding {
|
|||
|
||||
// Apply the checkbox:
|
||||
if same {
|
||||
*self = Rounding::same((self.nw + self.ne + self.sw + self.se) / 4.0);
|
||||
} else if self.is_same() {
|
||||
self.se *= 1.00001; // prevent collapsing into sameness
|
||||
*self = Rounding::from(self.average());
|
||||
} else {
|
||||
// Make sure we aren't same:
|
||||
if self.is_same() {
|
||||
if self.average() == 0.0 {
|
||||
self.se = 1;
|
||||
} else {
|
||||
self.se -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ fn color_button(ui: &mut Ui, color: Color32, open: bool) -> Response {
|
|||
|
||||
show_color_at(ui.painter(), color, rect);
|
||||
|
||||
let rounding = visuals.rounding.at_most(2.0); // Can't do more rounding because the background grid doesn't do any rounding
|
||||
let rounding = visuals.rounding.at_most(2); // Can't do more rounding because the background grid doesn't do any rounding
|
||||
ui.painter()
|
||||
.rect_stroke(rect, rounding, (2.0, visuals.bg_fill)); // fill is intentional, because default style has no border
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ impl Widget for ProgressBar {
|
|||
let rounding = rounding.unwrap_or_else(|| corner_radius.into());
|
||||
ui.painter()
|
||||
.rect(outer_rect, rounding, visuals.extreme_bg_color, Stroke::NONE);
|
||||
let min_width = 2.0 * rounding.sw.at_least(rounding.nw).at_most(corner_radius);
|
||||
let min_width =
|
||||
2.0 * f32::max(rounding.sw as _, rounding.nw as _).at_most(corner_radius);
|
||||
let filled_width = (outer_rect.width() * progress).at_least(min_width);
|
||||
let inner_rect =
|
||||
Rect::from_min_size(outer_rect.min, vec2(filled_width, outer_rect.height()));
|
||||
|
|
|
|||
|
|
@ -780,10 +780,10 @@ impl<'a> Slider<'a> {
|
|||
// The trailing rect has to be drawn differently depending on the orientation.
|
||||
match self.orientation {
|
||||
SliderOrientation::Horizontal => {
|
||||
trailing_rail_rect.max.x = center.x + rounding.nw;
|
||||
trailing_rail_rect.max.x = center.x + rounding.nw as f32;
|
||||
}
|
||||
SliderOrientation::Vertical => {
|
||||
trailing_rail_rect.min.y = center.y - rounding.se;
|
||||
trailing_rail_rect.min.y = center.y - rounding.se as f32;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ impl crate::View for PanZoom {
|
|||
.show(ui.ctx(), |ui| {
|
||||
ui.set_clip_rect(transform.inverse() * rect);
|
||||
egui::Frame::default()
|
||||
.rounding(egui::Rounding::same(4.0))
|
||||
.rounding(egui::Rounding::same(4))
|
||||
.inner_margin(egui::Margin::same(8.0))
|
||||
.stroke(ui.ctx().style().visuals.window_stroke)
|
||||
.fill(ui.style().visuals.panel_fill)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ pub mod image;
|
|||
mod margin;
|
||||
mod mesh;
|
||||
pub mod mutex;
|
||||
mod rounding;
|
||||
mod roundingf;
|
||||
mod shadow;
|
||||
mod shape;
|
||||
pub mod shape_transform;
|
||||
|
|
@ -47,10 +49,12 @@ pub use self::{
|
|||
image::{ColorImage, FontImage, ImageData, ImageDelta},
|
||||
margin::Margin,
|
||||
mesh::{Mesh, Mesh16, Vertex},
|
||||
rounding::Rounding,
|
||||
roundingf::Roundingf,
|
||||
shadow::Shadow,
|
||||
shape::{
|
||||
CircleShape, EllipseShape, PaintCallback, PaintCallbackInfo, PathShape, RectShape,
|
||||
Rounding, Shape, TextShape,
|
||||
CircleShape, EllipseShape, PaintCallback, PaintCallbackInfo, PathShape, RectShape, Shape,
|
||||
TextShape,
|
||||
},
|
||||
stats::PaintStats,
|
||||
stroke::{PathStroke, Stroke, StrokeKind},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,220 @@
|
|||
/// How rounded the corners of things should be.
|
||||
///
|
||||
/// The rounding uses `u8` to save space,
|
||||
/// so the amount of rounding is limited to integers in the range `[0, 255]`.
|
||||
///
|
||||
/// For calculations, you may want to use [`crate::Roundingf`] instead, which uses `f32`.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Rounding {
|
||||
/// Radius of the rounding of the North-West (left top) corner.
|
||||
pub nw: u8,
|
||||
|
||||
/// Radius of the rounding of the North-East (right top) corner.
|
||||
pub ne: u8,
|
||||
|
||||
/// Radius of the rounding of the South-West (left bottom) corner.
|
||||
pub sw: u8,
|
||||
|
||||
/// Radius of the rounding of the South-East (right bottom) corner.
|
||||
pub se: u8,
|
||||
}
|
||||
|
||||
impl Default for Rounding {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Rounding {
|
||||
#[inline]
|
||||
fn from(radius: u8) -> Self {
|
||||
Self::same(radius)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Rounding {
|
||||
#[inline]
|
||||
fn from(radius: f32) -> Self {
|
||||
Self::same(radius.round() as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rounding {
|
||||
/// No rounding on any corner.
|
||||
pub const ZERO: Self = Self {
|
||||
nw: 0,
|
||||
ne: 0,
|
||||
sw: 0,
|
||||
se: 0,
|
||||
};
|
||||
|
||||
/// Same rounding on all four corners.
|
||||
#[inline]
|
||||
pub const fn same(radius: u8) -> Self {
|
||||
Self {
|
||||
nw: radius,
|
||||
ne: radius,
|
||||
sw: radius,
|
||||
se: radius,
|
||||
}
|
||||
}
|
||||
|
||||
/// Do all corners have the same rounding?
|
||||
#[inline]
|
||||
pub fn is_same(self) -> bool {
|
||||
self.nw == self.ne && self.nw == self.sw && self.nw == self.se
|
||||
}
|
||||
|
||||
/// Make sure each corner has a rounding of at least this.
|
||||
#[inline]
|
||||
pub fn at_least(self, min: u8) -> Self {
|
||||
Self {
|
||||
nw: self.nw.max(min),
|
||||
ne: self.ne.max(min),
|
||||
sw: self.sw.max(min),
|
||||
se: self.se.max(min),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure each corner has a rounding of at most this.
|
||||
#[inline]
|
||||
pub fn at_most(self, max: u8) -> Self {
|
||||
Self {
|
||||
nw: self.nw.min(max),
|
||||
ne: self.ne.min(max),
|
||||
sw: self.sw.min(max),
|
||||
se: self.se.min(max),
|
||||
}
|
||||
}
|
||||
|
||||
/// Average rounding of the corners.
|
||||
pub fn average(&self) -> f32 {
|
||||
(self.nw as f32 + self.ne as f32 + self.sw as f32 + self.se as f32) / 4.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
nw: self.nw + rhs.nw,
|
||||
ne: self.ne + rhs.ne,
|
||||
sw: self.sw + rhs.sw,
|
||||
se: self.se + rhs.se,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for Rounding {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = Self {
|
||||
nw: self.nw + rhs.nw,
|
||||
ne: self.ne + rhs.ne,
|
||||
sw: self.sw + rhs.sw,
|
||||
se: self.se + rhs.se,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign<u8> for Rounding {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: u8) {
|
||||
*self = Self {
|
||||
nw: self.nw.saturating_add(rhs),
|
||||
ne: self.ne.saturating_add(rhs),
|
||||
sw: self.sw.saturating_add(rhs),
|
||||
se: self.se.saturating_add(rhs),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
nw: self.nw.saturating_sub(rhs.nw),
|
||||
ne: self.ne.saturating_sub(rhs.ne),
|
||||
sw: self.sw.saturating_sub(rhs.sw),
|
||||
se: self.se.saturating_sub(rhs.se),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for Rounding {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = Self {
|
||||
nw: self.nw.saturating_sub(rhs.nw),
|
||||
ne: self.ne.saturating_sub(rhs.ne),
|
||||
sw: self.sw.saturating_sub(rhs.sw),
|
||||
se: self.se.saturating_sub(rhs.se),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign<u8> for Rounding {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: u8) {
|
||||
*self = Self {
|
||||
nw: self.nw.saturating_sub(rhs),
|
||||
ne: self.ne.saturating_sub(rhs),
|
||||
sw: self.sw.saturating_sub(rhs),
|
||||
se: self.se.saturating_sub(rhs),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Div<f32> for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: f32) -> Self {
|
||||
Self {
|
||||
nw: (self.nw as f32 / rhs) as u8,
|
||||
ne: (self.ne as f32 / rhs) as u8,
|
||||
sw: (self.sw as f32 / rhs) as u8,
|
||||
se: (self.se as f32 / rhs) as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DivAssign<f32> for Rounding {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: (self.nw as f32 / rhs) as u8,
|
||||
ne: (self.ne as f32 / rhs) as u8,
|
||||
sw: (self.sw as f32 / rhs) as u8,
|
||||
se: (self.se as f32 / rhs) as u8,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<f32> for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn mul(self, rhs: f32) -> Self {
|
||||
Self {
|
||||
nw: (self.nw as f32 * rhs) as u8,
|
||||
ne: (self.ne as f32 * rhs) as u8,
|
||||
sw: (self.sw as f32 * rhs) as u8,
|
||||
se: (self.se as f32 * rhs) as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::MulAssign<f32> for Rounding {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: (self.nw as f32 * rhs) as u8,
|
||||
ne: (self.ne as f32 * rhs) as u8,
|
||||
sw: (self.sw as f32 * rhs) as u8,
|
||||
se: (self.se as f32 * rhs) as u8,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
use crate::Rounding;
|
||||
|
||||
/// How rounded the corners of things should be, in `f32`.
|
||||
///
|
||||
/// This is used for calculations, but storage is usually done with the more compact [`Rounding`].
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Roundingf {
|
||||
/// Radius of the rounding of the North-West (left top) corner.
|
||||
pub nw: f32,
|
||||
|
||||
/// Radius of the rounding of the North-East (right top) corner.
|
||||
pub ne: f32,
|
||||
|
||||
/// Radius of the rounding of the South-West (left bottom) corner.
|
||||
pub sw: f32,
|
||||
|
||||
/// Radius of the rounding of the South-East (right bottom) corner.
|
||||
pub se: f32,
|
||||
}
|
||||
|
||||
impl From<Rounding> for Roundingf {
|
||||
#[inline]
|
||||
fn from(rounding: Rounding) -> Self {
|
||||
Self {
|
||||
nw: rounding.nw as f32,
|
||||
ne: rounding.ne as f32,
|
||||
sw: rounding.sw as f32,
|
||||
se: rounding.se as f32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Roundingf> for Rounding {
|
||||
#[inline]
|
||||
fn from(rounding: Roundingf) -> Self {
|
||||
Self {
|
||||
nw: rounding.nw.round() as u8,
|
||||
ne: rounding.ne.round() as u8,
|
||||
sw: rounding.sw.round() as u8,
|
||||
se: rounding.se.round() as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Roundingf {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Roundingf {
|
||||
#[inline]
|
||||
fn from(radius: f32) -> Self {
|
||||
Self {
|
||||
nw: radius,
|
||||
ne: radius,
|
||||
sw: radius,
|
||||
se: radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Roundingf {
|
||||
/// No rounding on any corner.
|
||||
pub const ZERO: Self = Self {
|
||||
nw: 0.0,
|
||||
ne: 0.0,
|
||||
sw: 0.0,
|
||||
se: 0.0,
|
||||
};
|
||||
|
||||
/// Same rounding on all four corners.
|
||||
#[inline]
|
||||
pub const fn same(radius: f32) -> Self {
|
||||
Self {
|
||||
nw: radius,
|
||||
ne: radius,
|
||||
sw: radius,
|
||||
se: radius,
|
||||
}
|
||||
}
|
||||
|
||||
/// Do all corners have the same rounding?
|
||||
#[inline]
|
||||
pub fn is_same(&self) -> bool {
|
||||
self.nw == self.ne && self.nw == self.sw && self.nw == self.se
|
||||
}
|
||||
|
||||
/// Make sure each corner has a rounding of at least this.
|
||||
#[inline]
|
||||
pub fn at_least(&self, min: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw.max(min),
|
||||
ne: self.ne.max(min),
|
||||
sw: self.sw.max(min),
|
||||
se: self.se.max(min),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure each corner has a rounding of at most this.
|
||||
#[inline]
|
||||
pub fn at_most(&self, max: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw.min(max),
|
||||
ne: self.ne.min(max),
|
||||
sw: self.sw.min(max),
|
||||
se: self.se.min(max),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Roundingf {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
nw: self.nw + rhs.nw,
|
||||
ne: self.ne + rhs.ne,
|
||||
sw: self.sw + rhs.sw,
|
||||
se: self.se + rhs.se,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for Roundingf {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = Self {
|
||||
nw: self.nw + rhs.nw,
|
||||
ne: self.ne + rhs.ne,
|
||||
sw: self.sw + rhs.sw,
|
||||
se: self.se + rhs.se,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign<f32> for Roundingf {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw + rhs,
|
||||
ne: self.ne + rhs,
|
||||
sw: self.sw + rhs,
|
||||
se: self.se + rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Roundingf {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
nw: self.nw - rhs.nw,
|
||||
ne: self.ne - rhs.ne,
|
||||
sw: self.sw - rhs.sw,
|
||||
se: self.se - rhs.se,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for Roundingf {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = Self {
|
||||
nw: self.nw - rhs.nw,
|
||||
ne: self.ne - rhs.ne,
|
||||
sw: self.sw - rhs.sw,
|
||||
se: self.se - rhs.se,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign<f32> for Roundingf {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw - rhs,
|
||||
ne: self.ne - rhs,
|
||||
sw: self.sw - rhs,
|
||||
se: self.se - rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Div<f32> for Roundingf {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw / rhs,
|
||||
ne: self.ne / rhs,
|
||||
sw: self.sw / rhs,
|
||||
se: self.se / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DivAssign<f32> for Roundingf {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw / rhs,
|
||||
ne: self.ne / rhs,
|
||||
sw: self.sw / rhs,
|
||||
se: self.se / rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<f32> for Roundingf {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn mul(self, rhs: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw * rhs,
|
||||
ne: self.ne * rhs,
|
||||
sw: self.sw * rhs,
|
||||
se: self.se * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::MulAssign<f32> for Roundingf {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw * rhs,
|
||||
ne: self.ne * rhs,
|
||||
sw: self.sw * rhs,
|
||||
se: self.se * rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ impl Shadow {
|
|||
} = *self;
|
||||
|
||||
let rect = rect.translate(offset).expand(spread);
|
||||
let rounding = rounding.into() + Rounding::same(spread.abs());
|
||||
let rounding = rounding.into() + Rounding::from(spread.abs());
|
||||
|
||||
RectShape::filled(rect, rounding, color).with_blur_width(blur)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::{any::Any, sync::Arc};
|
|||
use crate::{
|
||||
stroke::PathStroke,
|
||||
text::{FontId, Fonts, Galley},
|
||||
Color32, Mesh, Stroke, TextureId,
|
||||
Color32, Mesh, Rounding, Stroke, TextureId,
|
||||
};
|
||||
use emath::{pos2, Align2, Pos2, Rangef, Rect, TSTransform, Vec2};
|
||||
|
||||
|
|
@ -779,214 +779,6 @@ impl From<RectShape> for Shape {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
/// How rounded the corners of things should be
|
||||
pub struct Rounding {
|
||||
/// Radius of the rounding of the North-West (left top) corner.
|
||||
pub nw: f32,
|
||||
|
||||
/// Radius of the rounding of the North-East (right top) corner.
|
||||
pub ne: f32,
|
||||
|
||||
/// Radius of the rounding of the South-West (left bottom) corner.
|
||||
pub sw: f32,
|
||||
|
||||
/// Radius of the rounding of the South-East (right bottom) corner.
|
||||
pub se: f32,
|
||||
}
|
||||
|
||||
impl Default for Rounding {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Rounding {
|
||||
#[inline]
|
||||
fn from(radius: f32) -> Self {
|
||||
Self {
|
||||
nw: radius,
|
||||
ne: radius,
|
||||
sw: radius,
|
||||
se: radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rounding {
|
||||
/// No rounding on any corner.
|
||||
pub const ZERO: Self = Self {
|
||||
nw: 0.0,
|
||||
ne: 0.0,
|
||||
sw: 0.0,
|
||||
se: 0.0,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
pub const fn same(radius: f32) -> Self {
|
||||
Self {
|
||||
nw: radius,
|
||||
ne: radius,
|
||||
sw: radius,
|
||||
se: radius,
|
||||
}
|
||||
}
|
||||
|
||||
/// Do all corners have the same rounding?
|
||||
#[inline]
|
||||
pub fn is_same(&self) -> bool {
|
||||
self.nw == self.ne && self.nw == self.sw && self.nw == self.se
|
||||
}
|
||||
|
||||
/// Make sure each corner has a rounding of at least this.
|
||||
#[inline]
|
||||
pub fn at_least(&self, min: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw.max(min),
|
||||
ne: self.ne.max(min),
|
||||
sw: self.sw.max(min),
|
||||
se: self.se.max(min),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure each corner has a rounding of at most this.
|
||||
#[inline]
|
||||
pub fn at_most(&self, max: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw.min(max),
|
||||
ne: self.ne.min(max),
|
||||
sw: self.sw.min(max),
|
||||
se: self.se.min(max),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
nw: self.nw + rhs.nw,
|
||||
ne: self.ne + rhs.ne,
|
||||
sw: self.sw + rhs.sw,
|
||||
se: self.se + rhs.se,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for Rounding {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = Self {
|
||||
nw: self.nw + rhs.nw,
|
||||
ne: self.ne + rhs.ne,
|
||||
sw: self.sw + rhs.sw,
|
||||
se: self.se + rhs.se,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign<f32> for Rounding {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw + rhs,
|
||||
ne: self.ne + rhs,
|
||||
sw: self.sw + rhs,
|
||||
se: self.se + rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
Self {
|
||||
nw: self.nw - rhs.nw,
|
||||
ne: self.ne - rhs.ne,
|
||||
sw: self.sw - rhs.sw,
|
||||
se: self.se - rhs.se,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for Rounding {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = Self {
|
||||
nw: self.nw - rhs.nw,
|
||||
ne: self.ne - rhs.ne,
|
||||
sw: self.sw - rhs.sw,
|
||||
se: self.se - rhs.se,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign<f32> for Rounding {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw - rhs,
|
||||
ne: self.ne - rhs,
|
||||
sw: self.sw - rhs,
|
||||
se: self.se - rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Div<f32> for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw / rhs,
|
||||
ne: self.ne / rhs,
|
||||
sw: self.sw / rhs,
|
||||
se: self.se / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DivAssign<f32> for Rounding {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw / rhs,
|
||||
ne: self.ne / rhs,
|
||||
sw: self.sw / rhs,
|
||||
se: self.se / rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<f32> for Rounding {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn mul(self, rhs: f32) -> Self {
|
||||
Self {
|
||||
nw: self.nw * rhs,
|
||||
ne: self.ne * rhs,
|
||||
sw: self.sw * rhs,
|
||||
se: self.se * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::MulAssign<f32> for Rounding {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: f32) {
|
||||
*self = Self {
|
||||
nw: self.nw * rhs,
|
||||
ne: self.ne * rhs,
|
||||
sw: self.sw * rhs,
|
||||
se: self.se * rhs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// How to paint some text on screen.
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ impl Path {
|
|||
|
||||
pub mod path {
|
||||
//! Helpers for constructing paths
|
||||
use crate::shape::Rounding;
|
||||
use crate::Rounding;
|
||||
use emath::{pos2, Pos2, Rect};
|
||||
|
||||
/// overwrites existing points
|
||||
|
|
@ -548,6 +548,8 @@ pub mod path {
|
|||
// Duplicated vertices can happen when one side is all rounding, with no straight edge between.
|
||||
let eps = f32::EPSILON * rect.size().max_elem();
|
||||
|
||||
let r = crate::Roundingf::from(r);
|
||||
|
||||
add_circle_quadrant(path, pos2(max.x - r.se, max.y - r.se), r.se, 0.0); // south east
|
||||
|
||||
if rect.width() <= r.se + r.sw + eps {
|
||||
|
|
@ -628,7 +630,7 @@ pub mod path {
|
|||
let half_width = rect.width() * 0.5;
|
||||
let half_height = rect.height() * 0.5;
|
||||
let max_cr = half_width.min(half_height);
|
||||
rounding.at_most(max_cr).at_least(0.0)
|
||||
rounding.at_most(max_cr.floor() as _).at_least(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1741,7 +1743,7 @@ impl Tessellator {
|
|||
.at_most(rect.size().min_elem() - eps)
|
||||
.at_least(0.0);
|
||||
|
||||
rounding += Rounding::same(0.5 * blur_width);
|
||||
rounding += Rounding::from(0.5 * blur_width);
|
||||
|
||||
self.feathering = self.feathering.max(blur_width);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue