Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support images with rounded corners #3257

Merged
merged 4 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions crates/egui/src/containers/collapsing_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
12 changes: 6 additions & 6 deletions crates/egui/src/containers/combo_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
),
);
}

Expand Down
7 changes: 1 addition & 6 deletions crates/egui/src/containers/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 3 additions & 18 deletions crates/egui/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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()`.
Expand Down
16 changes: 9 additions & 7 deletions crates/egui/src/widgets/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -535,7 +535,7 @@ impl Widget for ImageButton {
let selection = ui.visuals().selection;
(
Vec2::ZERO,
Rounding::none(),
Rounding::ZERO,
selection.bg_fill,
selection.stroke,
)
Expand All @@ -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);
Expand Down
44 changes: 39 additions & 5 deletions crates/egui/src/widgets/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct Image {
tint: Color32,
sense: Sense,
rotation: Option<(Rot2, Vec2)>,
rounding: Rounding,
}

impl Image {
Expand All @@ -54,6 +55,7 @@ impl Image {
tint: Color32::WHITE,
sense: Sense::hover(),
rotation: None,
rounding: Rounding::ZERO,
}
}

Expand Down Expand Up @@ -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
}
}
Expand All @@ -111,6 +131,7 @@ impl Image {
tint,
sense: _,
rotation,
rounding,
} = self;

if *bg_fill != Default::default() {
Expand All @@ -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,
});
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions crates/egui/src/widgets/plot/items/bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
7 changes: 1 addition & 6 deletions crates/egui/src/widgets/plot/items/box_elem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down
14 changes: 8 additions & 6 deletions crates/egui/src/widgets/plot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ---
Expand Down
38 changes: 17 additions & 21 deletions crates/egui/src/widgets/text_edit/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions crates/egui_demo_app/src/frame_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ impl FrameHistory {
let to_screen = emath::RectTransform::from_to(graph_rect, rect);

let mut shapes = Vec::with_capacity(3 + 2 * history.len());
shapes.push(Shape::Rect(epaint::RectShape {
shapes.push(Shape::Rect(epaint::RectShape::new(
rect,
rounding: style.rounding,
fill: ui.visuals().extreme_bg_color,
stroke: ui.style().noninteractive().bg_stroke,
}));
style.rounding,
ui.visuals().extreme_bg_color,
ui.style().noninteractive().bg_stroke,
)));

let rect = rect.shrink(4.0);
let color = ui.visuals().text_color();
Expand Down
7 changes: 1 addition & 6 deletions crates/egui_demo_lib/src/demo/drag_and_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,7 @@ pub fn drop_target<R>(

ui.painter().set(
where_to_put_background,
epaint::RectShape {
rounding: style.rounding,
fill,
stroke,
rect,
},
epaint::RectShape::new(rect, style.rounding, fill, stroke),
);

InnerResponse::new(ret, response)
Expand Down
2 changes: 1 addition & 1 deletion crates/egui_glium/examples/native_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() {

let mut egui_glium = egui_glium::EguiGlium::new(&display, &event_loop);

let png_data = include_bytes!("../../../examples/retained_image/src/rust-logo-256x256.png");
let png_data = include_bytes!("../../../examples/retained_image/src/crab.png");
let image = load_glium_image(png_data);
let image_size = egui::vec2(image.width as f32, image.height as f32);
// Load to gpu memory
Expand Down
6 changes: 6 additions & 0 deletions crates/emath/src/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ impl Rect {
max: pos2(f32::NAN, f32::NAN),
};

/// A [`Rect`] filled with zeroes.
pub const ZERO: Self = Self {
min: Pos2::ZERO,
max: Pos2::ZERO,
};

#[inline(always)]
pub const fn from_min_max(min: Pos2, max: Pos2) -> Self {
Rect { min, max }
Expand Down
6 changes: 3 additions & 3 deletions crates/epaint/src/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,13 @@ impl Mesh {
pub fn append_ref(&mut self, other: &Mesh) {
crate::epaint_assert!(other.is_valid());

if !self.is_empty() {
if self.is_empty() {
self.texture_id = other.texture_id;
} else {
assert_eq!(
self.texture_id, other.texture_id,
"Can't merge Mesh using different textures"
);
} else {
self.texture_id = other.texture_id;
}

let index_offset = self.vertices.len() as u32;
Expand Down
Loading
Loading