1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 21:00:03 -04:00
Files
egui/crates/epaint/src/corner_radius_f32.rs
Emil Ernerfeldt 726b995608 Round the corners of the color picker (#8439)
The color picker's gradients and background checkers now follow the
style's corner radius, giving it a softer look.

This required changing the painting from being Mesh-based to being
texture-based

it's subtle with the default settings:

<img width="286" height="397" alt="Screenshot 2026-08-21 at 15 08 18"
src="https://github.com/user-attachments/assets/3a9d5289-71fb-4f34-8a20-1fe96891ba36"
/>


But you can [increase it](https://github.com/emilk/egui/pull/8445):


<img width="285" height="391" alt="Screenshot 2026-08-21 at 15 08 41"
src="https://github.com/user-attachments/assets/b0dfa7da-5b96-40e0-a80d-1da385d57a1a"
/>


### Before
for reference
<img width="286" height="392" alt="Screenshot 2026-08-21 at 19 08 27"
src="https://github.com/user-attachments/assets/7c754f36-795c-4381-9f9f-1fc8dd9a0264"
/>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 09:28:14 +00:00

295 lines
6.9 KiB
Rust

use crate::CornerRadius;
/// How rounded the corners of things should be, in `f32`.
///
/// This is used for calculations, but storage is usually done with the more compact [`CornerRadius`].
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct CornerRadiusF32 {
/// 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<CornerRadius> for CornerRadiusF32 {
#[inline]
fn from(cr: CornerRadius) -> Self {
Self {
nw: cr.nw as f32,
ne: cr.ne as f32,
sw: cr.sw as f32,
se: cr.se as f32,
}
}
}
impl From<CornerRadiusF32> for CornerRadius {
#[inline]
fn from(cr: CornerRadiusF32) -> Self {
Self {
nw: cr.nw.round() as u8,
ne: cr.ne.round() as u8,
sw: cr.sw.round() as u8,
se: cr.se.round() as u8,
}
}
}
impl Default for CornerRadiusF32 {
#[inline]
fn default() -> Self {
Self::ZERO
}
}
impl From<f32> for CornerRadiusF32 {
#[inline]
fn from(radius: f32) -> Self {
Self {
nw: radius,
ne: radius,
sw: radius,
se: radius,
}
}
}
impl CornerRadiusF32 {
/// 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]
#[must_use]
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]
#[must_use]
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]
#[must_use]
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),
}
}
/// Set the rounding of the two east (right) corners.
#[inline]
#[must_use]
pub fn with_east(self, radius: f32) -> Self {
Self {
ne: radius,
se: radius,
..self
}
}
/// Set the rounding of the two north (top) corners.
#[inline]
#[must_use]
pub fn with_north(self, radius: f32) -> Self {
Self {
nw: radius,
ne: radius,
..self
}
}
/// Set the rounding of the two south (bottom) corners.
#[inline]
#[must_use]
pub fn with_south(self, radius: f32) -> Self {
Self {
sw: radius,
se: radius,
..self
}
}
/// Set the rounding of the two west (left) corners.
#[inline]
#[must_use]
pub fn with_west(self, radius: f32) -> Self {
Self {
nw: radius,
sw: radius,
..self
}
}
}
impl core::ops::Add for CornerRadiusF32 {
type Output = Self;
/// Saturates at zero: no corner radius will go negative.
#[inline]
fn add(self, rhs: Self) -> Self {
Self {
nw: (self.nw + rhs.nw).max(0.0),
ne: (self.ne + rhs.ne).max(0.0),
sw: (self.sw + rhs.sw).max(0.0),
se: (self.se + rhs.se).max(0.0),
}
}
}
impl core::ops::AddAssign for CornerRadiusF32 {
/// Saturates at zero: no corner radius will go negative.
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl core::ops::AddAssign<f32> for CornerRadiusF32 {
/// Saturates at zero: no corner radius will go negative.
#[inline]
fn add_assign(&mut self, rhs: f32) {
*self = *self + Self::same(rhs);
}
}
impl core::ops::Sub for CornerRadiusF32 {
type Output = Self;
/// Saturates at zero: no corner radius will go negative.
#[inline]
fn sub(self, rhs: Self) -> Self {
Self {
nw: (self.nw - rhs.nw).max(0.0),
ne: (self.ne - rhs.ne).max(0.0),
sw: (self.sw - rhs.sw).max(0.0),
se: (self.se - rhs.se).max(0.0),
}
}
}
impl core::ops::SubAssign for CornerRadiusF32 {
/// Saturates at zero: no corner radius will go negative.
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl core::ops::SubAssign<f32> for CornerRadiusF32 {
/// Saturates at zero: no corner radius will go negative.
#[inline]
fn sub_assign(&mut self, rhs: f32) {
*self = *self - Self::same(rhs);
}
}
impl core::ops::Div<f32> for CornerRadiusF32 {
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 core::ops::DivAssign<f32> for CornerRadiusF32 {
#[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 core::ops::Mul<f32> for CornerRadiusF32 {
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 core::ops::MulAssign<f32> for CornerRadiusF32 {
#[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,
};
}
}
#[cfg(test)]
mod tests {
use super::CornerRadiusF32;
#[test]
fn add_and_sub_saturate_at_zero() {
assert_eq!(
CornerRadiusF32::same(2.0) + CornerRadiusF32::same(-5.0),
CornerRadiusF32::ZERO
);
assert_eq!(
CornerRadiusF32::same(2.0) - CornerRadiusF32::same(5.0),
CornerRadiusF32::ZERO
);
let mut cr = CornerRadiusF32::same(1.0);
cr += -3.0;
assert_eq!(cr, CornerRadiusF32::ZERO);
cr -= -2.0;
assert_eq!(cr, CornerRadiusF32::same(2.0));
}
}