mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 13:20:05 -04:00
Merge branch 'master' into cache_galley_lines
This commit is contained in:
@@ -8,20 +8,39 @@ use crate::*;
|
||||
pub struct RectShape {
|
||||
pub rect: Rect,
|
||||
|
||||
/// How rounded the corners are. Use `Rounding::ZERO` for no rounding.
|
||||
pub rounding: Rounding,
|
||||
/// 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.
|
||||
///
|
||||
/// The stroke extends _outside_ the edge of [`Self::rect`],
|
||||
/// i.e. using [`crate::StrokeKind::Outside`].
|
||||
///
|
||||
/// This means the [`Self::visual_bounding_rect`] is `rect.size() + 2.0 * stroke.width`.
|
||||
/// 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.
|
||||
///
|
||||
@@ -50,19 +69,22 @@ fn rect_shape_size() {
|
||||
}
|
||||
|
||||
impl RectShape {
|
||||
/// The stroke extends _outside_ the [`Rect`].
|
||||
/// See also [`Self::filled`] and [`Self::stroke`].
|
||||
#[inline]
|
||||
pub fn new(
|
||||
rect: Rect,
|
||||
rounding: impl Into<Rounding>,
|
||||
corner_radius: impl Into<CornerRadius>,
|
||||
fill_color: impl Into<Color32>,
|
||||
stroke: impl Into<Stroke>,
|
||||
stroke_kind: StrokeKind,
|
||||
) -> Self {
|
||||
Self {
|
||||
rect,
|
||||
rounding: rounding.into(),
|
||||
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(),
|
||||
}
|
||||
@@ -71,17 +93,45 @@ impl RectShape {
|
||||
#[inline]
|
||||
pub fn filled(
|
||||
rect: Rect,
|
||||
rounding: impl Into<Rounding>,
|
||||
corner_radius: impl Into<CornerRadius>,
|
||||
fill_color: impl Into<Color32>,
|
||||
) -> Self {
|
||||
Self::new(rect, rounding, fill_color, Stroke::NONE)
|
||||
Self::new(
|
||||
rect,
|
||||
corner_radius,
|
||||
fill_color,
|
||||
Stroke::NONE,
|
||||
StrokeKind::Outside, // doesn't matter
|
||||
)
|
||||
}
|
||||
|
||||
/// The stroke extends _outside_ the [`Rect`].
|
||||
#[inline]
|
||||
pub fn stroke(rect: Rect, rounding: impl Into<Rounding>, stroke: impl Into<Stroke>) -> Self {
|
||||
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, rounding, fill, stroke)
|
||||
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
|
||||
@@ -112,8 +162,12 @@ impl RectShape {
|
||||
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
let Stroke { width, .. } = self.stroke; // Make sure we remember to update this if we change `stroke` to `PathStroke`
|
||||
self.rect.expand(width + self.blur_width / 2.0)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use emath::{pos2, Align2, Pos2, Rangef, Rect, TSTransform, Vec2};
|
||||
use crate::{
|
||||
stroke::PathStroke,
|
||||
text::{FontId, Fonts, Galley},
|
||||
Color32, Mesh, Rounding, Stroke, TextureId,
|
||||
Color32, CornerRadius, Mesh, Stroke, StrokeKind, TextureId,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -275,23 +275,25 @@ impl Shape {
|
||||
Self::Ellipse(EllipseShape::stroke(center, radius, stroke))
|
||||
}
|
||||
|
||||
/// See also [`Self::rect_stroke`].
|
||||
#[inline]
|
||||
pub fn rect_filled(
|
||||
rect: Rect,
|
||||
rounding: impl Into<Rounding>,
|
||||
corner_radius: impl Into<CornerRadius>,
|
||||
fill_color: impl Into<Color32>,
|
||||
) -> Self {
|
||||
Self::Rect(RectShape::filled(rect, rounding, fill_color))
|
||||
Self::Rect(RectShape::filled(rect, corner_radius, fill_color))
|
||||
}
|
||||
|
||||
/// The stroke extends _outside_ the [`Rect`].
|
||||
/// See also [`Self::rect_filled`].
|
||||
#[inline]
|
||||
pub fn rect_stroke(
|
||||
rect: Rect,
|
||||
rounding: impl Into<Rounding>,
|
||||
corner_radius: impl Into<CornerRadius>,
|
||||
stroke: impl Into<Stroke>,
|
||||
stroke_kind: StrokeKind,
|
||||
) -> Self {
|
||||
Self::Rect(RectShape::stroke(rect, rounding, stroke))
|
||||
Self::Rect(RectShape::stroke(rect, corner_radius, stroke, stroke_kind))
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
@@ -337,7 +339,7 @@ impl Shape {
|
||||
#[inline]
|
||||
pub fn mesh(mesh: impl Into<Arc<Mesh>>) -> Self {
|
||||
let mesh = mesh.into();
|
||||
debug_assert!(mesh.is_valid());
|
||||
debug_assert!(mesh.is_valid(), "Invalid mesh: {mesh:#?}");
|
||||
Self::Mesh(mesh)
|
||||
}
|
||||
|
||||
@@ -449,8 +451,9 @@ impl Shape {
|
||||
}
|
||||
Self::Rect(rect_shape) => {
|
||||
rect_shape.rect = transform * rect_shape.rect;
|
||||
rect_shape.corner_radius *= transform.scaling;
|
||||
rect_shape.stroke.width *= transform.scaling;
|
||||
rect_shape.rounding *= transform.scaling;
|
||||
rect_shape.blur_width *= transform.scaling;
|
||||
}
|
||||
Self::Text(text_shape) => {
|
||||
text_shape.pos = transform * text_shape.pos;
|
||||
@@ -471,17 +474,17 @@ impl Shape {
|
||||
Self::Mesh(mesh) => {
|
||||
Arc::make_mut(mesh).transform(transform);
|
||||
}
|
||||
Self::QuadraticBezier(bezier_shape) => {
|
||||
bezier_shape.points[0] = transform * bezier_shape.points[0];
|
||||
bezier_shape.points[1] = transform * bezier_shape.points[1];
|
||||
bezier_shape.points[2] = transform * bezier_shape.points[2];
|
||||
bezier_shape.stroke.width *= transform.scaling;
|
||||
}
|
||||
Self::CubicBezier(cubic_curve) => {
|
||||
for p in &mut cubic_curve.points {
|
||||
Self::QuadraticBezier(bezier) => {
|
||||
for p in &mut bezier.points {
|
||||
*p = transform * *p;
|
||||
}
|
||||
cubic_curve.stroke.width *= transform.scaling;
|
||||
bezier.stroke.width *= transform.scaling;
|
||||
}
|
||||
Self::CubicBezier(bezier) => {
|
||||
for p in &mut bezier.points {
|
||||
*p = transform * *p;
|
||||
}
|
||||
bezier.stroke.width *= transform.scaling;
|
||||
}
|
||||
Self::Callback(shape) => {
|
||||
shape.rect = transform * shape.rect;
|
||||
@@ -501,7 +504,7 @@ fn points_from_line(
|
||||
shapes: &mut Vec<Shape>,
|
||||
) {
|
||||
let mut position_on_segment = 0.0;
|
||||
path.windows(2).for_each(|window| {
|
||||
for window in path.windows(2) {
|
||||
let (start, end) = (window[0], window[1]);
|
||||
let vector = end - start;
|
||||
let segment_length = vector.length();
|
||||
@@ -511,7 +514,7 @@ fn points_from_line(
|
||||
position_on_segment += spacing;
|
||||
}
|
||||
position_on_segment -= segment_length;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates dashes from a line.
|
||||
@@ -523,12 +526,18 @@ fn dashes_from_line(
|
||||
shapes: &mut Vec<Shape>,
|
||||
dash_offset: f32,
|
||||
) {
|
||||
assert_eq!(dash_lengths.len(), gap_lengths.len());
|
||||
assert_eq!(
|
||||
dash_lengths.len(),
|
||||
gap_lengths.len(),
|
||||
"Mismatched dash and gap lengths, got dash_lengths: {}, gap_lengths: {}",
|
||||
dash_lengths.len(),
|
||||
gap_lengths.len()
|
||||
);
|
||||
let mut position_on_segment = dash_offset;
|
||||
let mut drawing_dash = false;
|
||||
let mut step = 0;
|
||||
let steps = dash_lengths.len();
|
||||
path.windows(2).for_each(|window| {
|
||||
for window in path.windows(2) {
|
||||
let (start, end) = (window[0], window[1]);
|
||||
let vector = end - start;
|
||||
let segment_length = vector.length();
|
||||
@@ -559,5 +568,5 @@ fn dashes_from_line(
|
||||
}
|
||||
|
||||
position_on_segment -= segment_length;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user