epaint/shapes/rect_shape.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
use std::sync::Arc;
use crate::*;
/// How to paint a rectangle.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct RectShape {
pub rect: Rect,
/// How rounded the corners of the rectangle are.
///
/// Use [`CornerRadius::ZERO`] for for sharp corners.
///
/// This is the corner radii of the rectangle.
/// If there is a stroke, then the stroke will have an inner and outer corner radius,
/// and those will depend on [`StrokeKind`] and the stroke width.
///
/// For [`StrokeKind::Inside`], the outside of the stroke coincides with the rectangle,
/// so the rounding will in this case specify the outer corner radius.
pub corner_radius: CornerRadius,
/// How to fill the rectangle.
pub fill: Color32,
/// The thickness and color of the outline.
///
/// Whether or not the stroke is inside or outside the edge of [`Self::rect`],
/// is controlled by [`Self::stroke_kind`].
pub stroke: Stroke,
/// Is the stroke on the inside, outside, or centered on the rectangle?
///
/// If you want to perfectly tile rectangles, use [`StrokeKind::Inside`].
pub stroke_kind: StrokeKind,
/// Snap the rectangle to pixels?
///
/// Rounding produces sharper rectangles.
///
/// If `None`, [`crate::TessellationOptions::round_rects_to_pixels`] will be used.
pub round_to_pixels: Option<bool>,
/// If larger than zero, the edges of the rectangle
/// (for both fill and stroke) will be blurred.
///
/// This can be used to produce shadows and glow effects.
///
/// The blur is currently implemented using a simple linear blur in sRGBA gamma space.
pub blur_width: f32,
/// Controls texturing, if any.
///
/// Since most rectangles do not have a texture, this is optional and in an `Arc`,
/// so that [`RectShape`] is kept small..
pub brush: Option<Arc<Brush>>,
}
#[test]
fn rect_shape_size() {
assert_eq!(
std::mem::size_of::<RectShape>(), 48,
"RectShape changed size! If it shrank - good! Update this test. If it grew - bad! Try to find a way to avoid it."
);
assert!(
std::mem::size_of::<RectShape>() <= 64,
"RectShape is getting way too big!"
);
}
impl RectShape {
/// See also [`Self::filled`] and [`Self::stroke`].
#[inline]
pub fn new(
rect: Rect,
corner_radius: impl Into<CornerRadius>,
fill_color: impl Into<Color32>,
stroke: impl Into<Stroke>,
stroke_kind: StrokeKind,
) -> Self {
Self {
rect,
corner_radius: corner_radius.into(),
fill: fill_color.into(),
stroke: stroke.into(),
stroke_kind,
round_to_pixels: None,
blur_width: 0.0,
brush: Default::default(),
}
}
#[inline]
pub fn filled(
rect: Rect,
corner_radius: impl Into<CornerRadius>,
fill_color: impl Into<Color32>,
) -> Self {
Self::new(
rect,
corner_radius,
fill_color,
Stroke::NONE,
StrokeKind::Outside, // doesn't matter
)
}
#[inline]
pub fn stroke(
rect: Rect,
corner_radius: impl Into<CornerRadius>,
stroke: impl Into<Stroke>,
stroke_kind: StrokeKind,
) -> Self {
let fill = Color32::TRANSPARENT;
Self::new(rect, corner_radius, fill, stroke, stroke_kind)
}
/// Set if the stroke is on the inside, outside, or centered on the rectangle.
#[inline]
pub fn with_stroke_kind(mut self, stroke_kind: StrokeKind) -> Self {
self.stroke_kind = stroke_kind;
self
}
/// Snap the rectangle to pixels?
///
/// Rounding produces sharper rectangles.
///
/// If `None`, [`crate::TessellationOptions::round_rects_to_pixels`] will be used.
#[inline]
pub fn with_round_to_pixels(mut self, round_to_pixels: bool) -> Self {
self.round_to_pixels = Some(round_to_pixels);
self
}
/// If larger than zero, the edges of the rectangle
/// (for both fill and stroke) will be blurred.
///
/// This can be used to produce shadows and glow effects.
///
/// The blur is currently implemented using a simple linear blur in `sRGBA` gamma space.
#[inline]
pub fn with_blur_width(mut self, blur_width: f32) -> Self {
self.blur_width = blur_width;
self
}
/// Set the texture to use when painting this rectangle, if any.
#[inline]
pub fn with_texture(mut self, fill_texture_id: TextureId, uv: Rect) -> Self {
self.brush = Some(Arc::new(Brush {
fill_texture_id,
uv,
}));
self
}
/// The visual bounding rectangle (includes stroke width)
#[inline]
pub fn visual_bounding_rect(&self) -> Rect {
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
Rect::NOTHING
} else {
let expand = match self.stroke_kind {
StrokeKind::Inside => 0.0,
StrokeKind::Middle => self.stroke.width / 2.0,
StrokeKind::Outside => self.stroke.width,
};
self.rect.expand(expand + self.blur_width / 2.0)
}
}
/// The texture to use when painting this rectangle, if any.
///
/// If no texture is set, this will return [`TextureId::default`].
pub fn fill_texture_id(&self) -> TextureId {
self.brush
.as_ref()
.map_or_else(TextureId::default, |brush| brush.fill_texture_id)
}
}
impl From<RectShape> for Shape {
#[inline(always)]
fn from(shape: RectShape) -> Self {
Self::Rect(shape)
}
}