mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 06:40:06 -04:00
Support images with rounded corners (#3257)
* Add `Rect::ZERO` * Add `Rounding::ZERO` * Add `RectShape::new` * Add `Image::rounding` to support images with rounded corners
This commit is contained in:
@@ -555,13 +555,12 @@ impl CollapsingHeader {
|
||||
let visuals = ui.style().interact_selectable(&header_response, selected);
|
||||
|
||||
if ui.visuals().collapsing_header_frame || show_background {
|
||||
ui.painter().add(epaint::RectShape {
|
||||
rect: header_response.rect.expand(visuals.expansion),
|
||||
rounding: visuals.rounding,
|
||||
fill: visuals.weak_bg_fill,
|
||||
stroke: visuals.bg_stroke,
|
||||
// stroke: Default::default(),
|
||||
});
|
||||
ui.painter().add(epaint::RectShape::new(
|
||||
header_response.rect.expand(visuals.expansion),
|
||||
visuals.rounding,
|
||||
visuals.weak_bg_fill,
|
||||
visuals.bg_stroke,
|
||||
));
|
||||
}
|
||||
|
||||
if selected || selectable && (header_response.hovered() || header_response.has_focus())
|
||||
|
||||
@@ -383,12 +383,12 @@ fn button_frame(
|
||||
|
||||
ui.painter().set(
|
||||
where_to_put_background,
|
||||
epaint::RectShape {
|
||||
rect: outer_rect.expand(visuals.expansion),
|
||||
rounding: visuals.rounding,
|
||||
fill: visuals.weak_bg_fill,
|
||||
stroke: visuals.bg_stroke,
|
||||
},
|
||||
epaint::RectShape::new(
|
||||
outer_rect.expand(visuals.expansion),
|
||||
visuals.rounding,
|
||||
visuals.weak_bg_fill,
|
||||
visuals.bg_stroke,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -235,12 +235,7 @@ impl Frame {
|
||||
stroke,
|
||||
} = *self;
|
||||
|
||||
let frame_shape = Shape::Rect(epaint::RectShape {
|
||||
rect: outer_rect,
|
||||
rounding,
|
||||
fill,
|
||||
stroke,
|
||||
});
|
||||
let frame_shape = Shape::Rect(epaint::RectShape::new(outer_rect, rounding, fill, stroke));
|
||||
|
||||
if shadow == Default::default() {
|
||||
frame_shape
|
||||
|
||||
@@ -311,12 +311,7 @@ impl Painter {
|
||||
fill_color: impl Into<Color32>,
|
||||
stroke: impl Into<Stroke>,
|
||||
) {
|
||||
self.add(RectShape {
|
||||
rect,
|
||||
rounding: rounding.into(),
|
||||
fill: fill_color.into(),
|
||||
stroke: stroke.into(),
|
||||
});
|
||||
self.add(RectShape::new(rect, rounding, fill_color, stroke));
|
||||
}
|
||||
|
||||
pub fn rect_filled(
|
||||
@@ -325,12 +320,7 @@ impl Painter {
|
||||
rounding: impl Into<Rounding>,
|
||||
fill_color: impl Into<Color32>,
|
||||
) {
|
||||
self.add(RectShape {
|
||||
rect,
|
||||
rounding: rounding.into(),
|
||||
fill: fill_color.into(),
|
||||
stroke: Default::default(),
|
||||
});
|
||||
self.add(RectShape::filled(rect, rounding, fill_color));
|
||||
}
|
||||
|
||||
pub fn rect_stroke(
|
||||
@@ -339,12 +329,7 @@ impl Painter {
|
||||
rounding: impl Into<Rounding>,
|
||||
stroke: impl Into<Stroke>,
|
||||
) {
|
||||
self.add(RectShape {
|
||||
rect,
|
||||
rounding: rounding.into(),
|
||||
fill: Default::default(),
|
||||
stroke: stroke.into(),
|
||||
});
|
||||
self.add(RectShape::stroke(rect, rounding, stroke));
|
||||
}
|
||||
|
||||
/// Show an arrow starting at `origin` and going in the direction of `vec`, with the length `vec.length()`.
|
||||
|
||||
@@ -318,12 +318,12 @@ impl<'a> Widget for Checkbox<'a> {
|
||||
// let visuals = ui.style().interact_selectable(&response, *checked); // too colorful
|
||||
let visuals = ui.style().interact(&response);
|
||||
let (small_icon_rect, big_icon_rect) = ui.spacing().icon_rectangles(rect);
|
||||
ui.painter().add(epaint::RectShape {
|
||||
rect: big_icon_rect.expand(visuals.expansion),
|
||||
rounding: visuals.rounding,
|
||||
fill: visuals.bg_fill,
|
||||
stroke: visuals.bg_stroke,
|
||||
});
|
||||
ui.painter().add(epaint::RectShape::new(
|
||||
big_icon_rect.expand(visuals.expansion),
|
||||
visuals.rounding,
|
||||
visuals.bg_fill,
|
||||
visuals.bg_stroke,
|
||||
));
|
||||
|
||||
if *checked {
|
||||
// Check mark:
|
||||
@@ -535,7 +535,7 @@ impl Widget for ImageButton {
|
||||
let selection = ui.visuals().selection;
|
||||
(
|
||||
Vec2::ZERO,
|
||||
Rounding::none(),
|
||||
Rounding::ZERO,
|
||||
selection.bg_fill,
|
||||
selection.stroke,
|
||||
)
|
||||
@@ -552,6 +552,8 @@ impl Widget for ImageButton {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let image = image.rounding(rounding); // apply rounding to the image
|
||||
|
||||
// Draw frame background (for transparent images):
|
||||
ui.painter()
|
||||
.rect_filled(rect.expand2(expansion), rounding, fill);
|
||||
|
||||
@@ -42,6 +42,7 @@ pub struct Image {
|
||||
tint: Color32,
|
||||
sense: Sense,
|
||||
rotation: Option<(Rot2, Vec2)>,
|
||||
rounding: Rounding,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
@@ -54,6 +55,7 @@ impl Image {
|
||||
tint: Color32::WHITE,
|
||||
sense: Sense::hover(),
|
||||
rotation: None,
|
||||
rounding: Rounding::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +91,26 @@ impl Image {
|
||||
/// Origin is a vector in normalized UV space ((0,0) in top-left, (1,1) bottom right).
|
||||
///
|
||||
/// To rotate about the center you can pass `Vec2::splat(0.5)` as the origin.
|
||||
///
|
||||
/// Due to limitations in the current implementation,
|
||||
/// this will turn off rounding of the image.
|
||||
pub fn rotate(mut self, angle: f32, origin: Vec2) -> Self {
|
||||
self.rotation = Some((Rot2::from_angle(angle), origin));
|
||||
self.rounding = Rounding::ZERO; // incompatible with rotation
|
||||
self
|
||||
}
|
||||
|
||||
/// Round the corners of the image.
|
||||
///
|
||||
/// The default is no rounding ([`Rounding::ZERO`]).
|
||||
///
|
||||
/// Due to limitations in the current implementation,
|
||||
/// this will turn off any rotation of the image.
|
||||
pub fn rounding(mut self, rounding: impl Into<Rounding>) -> Self {
|
||||
self.rounding = rounding.into();
|
||||
if self.rounding != Rounding::ZERO {
|
||||
self.rotation = None; // incompatible with rounding
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -111,6 +131,7 @@ impl Image {
|
||||
tint,
|
||||
sense: _,
|
||||
rotation,
|
||||
rounding,
|
||||
} = self;
|
||||
|
||||
if *bg_fill != Default::default() {
|
||||
@@ -119,14 +140,27 @@ impl Image {
|
||||
ui.painter().add(Shape::mesh(mesh));
|
||||
}
|
||||
|
||||
{
|
||||
// TODO(emilk): builder pattern for Mesh
|
||||
if let Some((rot, origin)) = rotation {
|
||||
// TODO(emilk): implement this using `PathShape` (add texture support to it).
|
||||
// This will also give us anti-aliasing of rotated images.
|
||||
egui_assert!(
|
||||
*rounding == Rounding::ZERO,
|
||||
"Image had both rounding and rotation. Please pick only one"
|
||||
);
|
||||
|
||||
let mut mesh = Mesh::with_texture(*texture_id);
|
||||
mesh.add_rect_with_uv(rect, *uv, *tint);
|
||||
if let Some((rot, origin)) = rotation {
|
||||
mesh.rotate(*rot, rect.min + *origin * *size);
|
||||
}
|
||||
mesh.rotate(*rot, rect.min + *origin * *size);
|
||||
ui.painter().add(Shape::mesh(mesh));
|
||||
} else {
|
||||
ui.painter().add(RectShape {
|
||||
rect,
|
||||
rounding: *rounding,
|
||||
fill: *tint,
|
||||
stroke: Stroke::NONE,
|
||||
fill_texture_id: *texture_id,
|
||||
uv: *uv,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,12 +127,7 @@ impl Bar {
|
||||
};
|
||||
|
||||
let rect = transform.rect_from_values(&self.bounds_min(), &self.bounds_max());
|
||||
let rect = Shape::Rect(RectShape {
|
||||
rect,
|
||||
rounding: Rounding::none(),
|
||||
fill,
|
||||
stroke,
|
||||
});
|
||||
let rect = Shape::Rect(RectShape::new(rect, Rounding::ZERO, fill, stroke));
|
||||
|
||||
shapes.push(rect);
|
||||
}
|
||||
|
||||
@@ -150,12 +150,7 @@ impl BoxElem {
|
||||
&self.point_at(self.argument - self.box_width / 2.0, self.spread.quartile1),
|
||||
&self.point_at(self.argument + self.box_width / 2.0, self.spread.quartile3),
|
||||
);
|
||||
let rect = Shape::Rect(RectShape {
|
||||
rect,
|
||||
rounding: Rounding::none(),
|
||||
fill,
|
||||
stroke,
|
||||
});
|
||||
let rect = Shape::Rect(RectShape::new(rect, Rounding::ZERO, fill, stroke));
|
||||
shapes.push(rect);
|
||||
|
||||
let line_between = |v1, v2| {
|
||||
|
||||
@@ -864,12 +864,14 @@ impl Plot {
|
||||
|
||||
// Background
|
||||
if show_background {
|
||||
ui.painter().with_clip_rect(rect).add(epaint::RectShape {
|
||||
rect,
|
||||
rounding: Rounding::same(2.0),
|
||||
fill: ui.visuals().extreme_bg_color,
|
||||
stroke: ui.visuals().widgets.noninteractive.bg_stroke,
|
||||
});
|
||||
ui.painter()
|
||||
.with_clip_rect(rect)
|
||||
.add(epaint::RectShape::new(
|
||||
rect,
|
||||
Rounding::same(2.0),
|
||||
ui.visuals().extreme_bg_color,
|
||||
ui.visuals().widgets.noninteractive.bg_stroke,
|
||||
));
|
||||
}
|
||||
|
||||
// --- Legend ---
|
||||
|
||||
@@ -368,31 +368,27 @@ impl<'t> TextEdit<'t> {
|
||||
let frame_rect = frame_rect.expand(visuals.expansion);
|
||||
let shape = if is_mutable {
|
||||
if output.response.has_focus() {
|
||||
epaint::RectShape {
|
||||
rect: frame_rect,
|
||||
rounding: visuals.rounding,
|
||||
// fill: ui.visuals().selection.bg_fill,
|
||||
fill: ui.visuals().extreme_bg_color,
|
||||
stroke: ui.visuals().selection.stroke,
|
||||
}
|
||||
epaint::RectShape::new(
|
||||
frame_rect,
|
||||
visuals.rounding,
|
||||
ui.visuals().extreme_bg_color,
|
||||
ui.visuals().selection.stroke,
|
||||
)
|
||||
} else {
|
||||
epaint::RectShape {
|
||||
rect: frame_rect,
|
||||
rounding: visuals.rounding,
|
||||
fill: ui.visuals().extreme_bg_color,
|
||||
stroke: visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop".
|
||||
}
|
||||
epaint::RectShape::new(
|
||||
frame_rect,
|
||||
visuals.rounding,
|
||||
ui.visuals().extreme_bg_color,
|
||||
visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop".
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let visuals = &ui.style().visuals.widgets.inactive;
|
||||
epaint::RectShape {
|
||||
rect: frame_rect,
|
||||
rounding: visuals.rounding,
|
||||
// fill: ui.visuals().extreme_bg_color,
|
||||
// fill: visuals.bg_fill,
|
||||
fill: Color32::TRANSPARENT,
|
||||
stroke: visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop".
|
||||
}
|
||||
epaint::RectShape::stroke(
|
||||
frame_rect,
|
||||
visuals.rounding,
|
||||
visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop".
|
||||
)
|
||||
};
|
||||
|
||||
ui.painter().set(where_to_put_background, shape);
|
||||
|
||||
Reference in New Issue
Block a user