diff --git a/crates/egui/src/containers/collapsing_header.rs b/crates/egui/src/containers/collapsing_header.rs index 5eda61b6..5d12dc79 100644 --- a/crates/egui/src/containers/collapsing_header.rs +++ b/crates/egui/src/containers/collapsing_header.rs @@ -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()) diff --git a/crates/egui/src/containers/combo_box.rs b/crates/egui/src/containers/combo_box.rs index 7bc12c7d..e29b12b4 100644 --- a/crates/egui/src/containers/combo_box.rs +++ b/crates/egui/src/containers/combo_box.rs @@ -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, + ), ); } diff --git a/crates/egui/src/containers/frame.rs b/crates/egui/src/containers/frame.rs index 08b5e5a0..6ce5cbc4 100644 --- a/crates/egui/src/containers/frame.rs +++ b/crates/egui/src/containers/frame.rs @@ -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 diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index 17028e6c..ab2b0c15 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -311,12 +311,7 @@ impl Painter { fill_color: impl Into, stroke: impl Into, ) { - 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, fill_color: impl Into, ) { - 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, stroke: impl Into, ) { - 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()`. diff --git a/crates/egui/src/widgets/button.rs b/crates/egui/src/widgets/button.rs index ca211987..932918ab 100644 --- a/crates/egui/src/widgets/button.rs +++ b/crates/egui/src/widgets/button.rs @@ -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); diff --git a/crates/egui/src/widgets/image.rs b/crates/egui/src/widgets/image.rs index eaf4584d..487af9d3 100644 --- a/crates/egui/src/widgets/image.rs +++ b/crates/egui/src/widgets/image.rs @@ -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) -> 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, + }); } } } diff --git a/crates/egui/src/widgets/plot/items/bar.rs b/crates/egui/src/widgets/plot/items/bar.rs index 4ab6ebc7..7c4dbab0 100644 --- a/crates/egui/src/widgets/plot/items/bar.rs +++ b/crates/egui/src/widgets/plot/items/bar.rs @@ -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); } diff --git a/crates/egui/src/widgets/plot/items/box_elem.rs b/crates/egui/src/widgets/plot/items/box_elem.rs index 3f915108..dab53fd7 100644 --- a/crates/egui/src/widgets/plot/items/box_elem.rs +++ b/crates/egui/src/widgets/plot/items/box_elem.rs @@ -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| { diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 456f3dc1..4bd95337 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -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 --- diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index e92bf9db..3019fa7f 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -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); diff --git a/crates/egui_demo_app/src/frame_history.rs b/crates/egui_demo_app/src/frame_history.rs index 946f8ff9..f85a3a48 100644 --- a/crates/egui_demo_app/src/frame_history.rs +++ b/crates/egui_demo_app/src/frame_history.rs @@ -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(); diff --git a/crates/egui_demo_lib/src/demo/drag_and_drop.rs b/crates/egui_demo_lib/src/demo/drag_and_drop.rs index 23d3daaf..7376d9b4 100644 --- a/crates/egui_demo_lib/src/demo/drag_and_drop.rs +++ b/crates/egui_demo_lib/src/demo/drag_and_drop.rs @@ -64,12 +64,7 @@ pub fn drop_target( 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) diff --git a/crates/egui_glium/examples/native_texture.rs b/crates/egui_glium/examples/native_texture.rs index b19b08f0..94977cd6 100644 --- a/crates/egui_glium/examples/native_texture.rs +++ b/crates/egui_glium/examples/native_texture.rs @@ -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 diff --git a/crates/emath/src/rect.rs b/crates/emath/src/rect.rs index d6d148d2..0d5a1e8c 100644 --- a/crates/emath/src/rect.rs +++ b/crates/emath/src/rect.rs @@ -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 } diff --git a/crates/epaint/src/mesh.rs b/crates/epaint/src/mesh.rs index 62f0de21..266b46a0 100644 --- a/crates/epaint/src/mesh.rs +++ b/crates/epaint/src/mesh.rs @@ -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; diff --git a/crates/epaint/src/shape.rs b/crates/epaint/src/shape.rs index 401f51d8..717cf404 100644 --- a/crates/epaint/src/shape.rs +++ b/crates/epaint/src/shape.rs @@ -282,6 +282,8 @@ impl Shape { pub fn texture_id(&self) -> super::TextureId { if let Shape::Mesh(mesh) = self { mesh.texture_id + } else if let Shape::Rect(rect_shape) = self { + rect_shape.fill_texture_id } else { super::TextureId::default() } @@ -406,6 +408,8 @@ pub struct PathShape { /// Color and thickness of the line. pub stroke: Stroke, + // TODO(emilk): Add texture support either by supplying uv for each point, + // or by some transform from points to uv (e.g. a callback or a linear transform matrix). } impl PathShape { @@ -476,7 +480,7 @@ impl From for Shape { pub struct RectShape { pub rect: Rect, - /// How rounded the corners are. Use `Rounding::none()` for no rounding. + /// How rounded the corners are. Use `Rounding::ZERO` for no rounding. pub rounding: Rounding, /// How to fill the rectangle. @@ -484,9 +488,37 @@ pub struct RectShape { /// The thickness and color of the outline. pub stroke: Stroke, + + /// If the rect should be filled with a texture, which one? + /// + /// The texture is multiplied with [`Self::fill`]. + pub fill_texture_id: TextureId, + + /// What UV coordinates to use for the texture? + /// + /// To display a texture, set [`Self::fill_texture_id`], + /// and set this to `Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0))`. + pub uv: Rect, } impl RectShape { + #[inline] + pub fn new( + rect: Rect, + rounding: impl Into, + fill_color: impl Into, + stroke: impl Into, + ) -> Self { + Self { + rect, + rounding: rounding.into(), + fill: fill_color.into(), + stroke: stroke.into(), + fill_texture_id: Default::default(), + uv: Rect::ZERO, + } + } + #[inline] pub fn filled( rect: Rect, @@ -498,6 +530,8 @@ impl RectShape { rounding: rounding.into(), fill: fill_color.into(), stroke: Default::default(), + fill_texture_id: Default::default(), + uv: Rect::ZERO, } } @@ -508,6 +542,8 @@ impl RectShape { rounding: rounding.into(), fill: Default::default(), stroke: stroke.into(), + fill_texture_id: Default::default(), + uv: Rect::ZERO, } } @@ -549,7 +585,7 @@ pub struct Rounding { impl Default for Rounding { #[inline] fn default() -> Self { - Self::none() + Self::ZERO } } @@ -566,6 +602,14 @@ impl From for Rounding { } impl Rounding { + /// No rounding on any corner. + pub const ZERO: Self = Self { + nw: 0.0, + ne: 0.0, + sw: 0.0, + se: 0.0, + }; + #[inline] pub fn same(radius: f32) -> Self { Self { @@ -577,6 +621,7 @@ impl Rounding { } #[inline] + #[deprecated = "Use Rounding::ZERO"] pub fn none() -> Self { Self { nw: 0.0, diff --git a/crates/epaint/src/tessellator.rs b/crates/epaint/src/tessellator.rs index facb2612..44300cab 100644 --- a/crates/epaint/src/tessellator.rs +++ b/crates/epaint/src/tessellator.rs @@ -492,6 +492,20 @@ impl Path { pub fn fill(&mut self, feathering: f32, color: Color32, out: &mut Mesh) { fill_closed_path(feathering, &mut self.0, color, out); } + + /// Like [`Self::fill`] but with texturing. + /// + /// The `uv_from_pos` is called for each vertex position. + pub fn fill_with_uv( + &mut self, + feathering: f32, + color: Color32, + texture_id: TextureId, + uv_from_pos: impl Fn(Pos2) -> Pos2, + out: &mut Mesh, + ) { + fill_closed_path_with_uv(feathering, &mut self.0, color, texture_id, uv_from_pos, out); + } } pub mod path { @@ -508,7 +522,7 @@ pub mod path { let r = clamp_radius(rounding, rect); - if r == Rounding::none() { + if r == Rounding::ZERO { let min = rect.min; let max = rect.max; path.reserve(4); @@ -728,6 +742,89 @@ fn fill_closed_path(feathering: f32, path: &mut [PathPoint], color: Color32, out } } +/// Like [`fill_closed_path`] but with texturing. +/// +/// The `uv_from_pos` is called for each vertex position. +fn fill_closed_path_with_uv( + feathering: f32, + path: &mut [PathPoint], + color: Color32, + texture_id: TextureId, + uv_from_pos: impl Fn(Pos2) -> Pos2, + out: &mut Mesh, +) { + if color == Color32::TRANSPARENT { + return; + } + + if out.is_empty() { + out.texture_id = texture_id; + } else { + assert_eq!( + out.texture_id, texture_id, + "Mixing different `texture_id` in the same " + ); + } + + let n = path.len() as u32; + if feathering > 0.0 { + if cw_signed_area(path) < 0.0 { + // Wrong winding order - fix: + path.reverse(); + for point in path.iter_mut() { + point.normal = -point.normal; + } + } + + out.reserve_triangles(3 * n as usize); + out.reserve_vertices(2 * n as usize); + let color_outer = Color32::TRANSPARENT; + let idx_inner = out.vertices.len() as u32; + let idx_outer = idx_inner + 1; + + // The fill: + for i in 2..n { + out.add_triangle(idx_inner + 2 * (i - 1), idx_inner, idx_inner + 2 * i); + } + + // The feathering: + let mut i0 = n - 1; + for i1 in 0..n { + let p1 = &path[i1 as usize]; + let dm = 0.5 * feathering * p1.normal; + + let pos = p1.pos - dm; + out.vertices.push(Vertex { + pos, + uv: uv_from_pos(pos), + color, + }); + + let pos = p1.pos + dm; + out.vertices.push(Vertex { + pos, + uv: uv_from_pos(pos), + color: color_outer, + }); + + out.add_triangle(idx_inner + i1 * 2, idx_inner + i0 * 2, idx_outer + 2 * i0); + out.add_triangle(idx_outer + i0 * 2, idx_outer + i1 * 2, idx_inner + 2 * i1); + i0 = i1; + } + } else { + out.reserve_triangles(n as usize); + let idx = out.vertices.len() as u32; + out.vertices.extend(path.iter().map(|p| Vertex { + pos: p.pos, + uv: uv_from_pos(p.pos), + color, + })); + for i in 2..n { + out.add_triangle(idx, idx + i - 1, idx + i); + } + } +} + /// Tessellate the given path as a stroke with thickness. fn stroke_path( feathering: f32, @@ -1304,6 +1401,8 @@ impl Tessellator { rounding, fill, stroke, + fill_texture_id, + uv, } = *rect; if self.options.coarse_tessellation_culling @@ -1345,7 +1444,21 @@ impl Tessellator { path.clear(); path::rounded_rectangle(&mut self.scratchpad_points, rect, rounding); path.add_line_loop(&self.scratchpad_points); - path.fill(self.feathering, fill, out); + + if uv.is_positive() { + // Textured + let uv_from_pos = |p: Pos2| { + pos2( + remap(p.x, rect.x_range(), uv.x_range()), + remap(p.y, rect.y_range(), uv.y_range()), + ) + }; + path.fill_with_uv(self.feathering, fill, fill_texture_id, uv_from_pos, out); + } else { + // Untextured + path.fill(self.feathering, fill, out); + } + path.stroke_closed(self.feathering, stroke, out); } } diff --git a/examples/retained_image/src/crab.png b/examples/retained_image/src/crab.png new file mode 100644 index 00000000..781b2199 Binary files /dev/null and b/examples/retained_image/src/crab.png differ diff --git a/examples/retained_image/src/main.rs b/examples/retained_image/src/main.rs index 148217fc..f96fb964 100644 --- a/examples/retained_image/src/main.rs +++ b/examples/retained_image/src/main.rs @@ -6,7 +6,7 @@ use egui_extras::RetainedImage; fn main() -> Result<(), eframe::Error> { env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). let options = eframe::NativeOptions { - initial_window_size: Some(egui::vec2(300.0, 900.0)), + initial_window_size: Some(egui::vec2(400.0, 1000.0)), ..Default::default() }; eframe::run_native( @@ -18,48 +18,66 @@ fn main() -> Result<(), eframe::Error> { struct MyApp { image: RetainedImage, + rounding: f32, tint: egui::Color32, } impl Default for MyApp { fn default() -> Self { Self { - image: RetainedImage::from_image_bytes( - "rust-logo-256x256.png", - include_bytes!("rust-logo-256x256.png"), - ) - .unwrap(), - tint: egui::Color32::from_rgb(255, 0, 255), + // crab image is CC0, found on https://stocksnap.io/search/crab + image: RetainedImage::from_image_bytes("crab.png", include_bytes!("crab.png")).unwrap(), + rounding: 32.0, + tint: egui::Color32::from_rgb(100, 200, 200), } } } impl eframe::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + let Self { + image, + rounding, + tint, + } = self; + egui::CentralPanel::default().show(ctx, |ui| { ui.heading("This is an image:"); - self.image.show(ui); + image.show(ui); - ui.heading("This is a rotated image with a tint:"); + ui.add_space(32.0); + + ui.heading("This is a tinted image with rounded corners:"); ui.add( - egui::Image::new(self.image.texture_id(ctx), self.image.size_vec2()) - .rotate(45.0_f32.to_radians(), egui::Vec2::splat(0.5)) - .tint(self.tint), + egui::Image::new(image.texture_id(ctx), image.size_vec2()) + .tint(*tint) + .rounding(*rounding), ); ui.horizontal(|ui| { ui.label("Tint:"); egui::color_picker::color_edit_button_srgba( ui, - &mut self.tint, + tint, egui::color_picker::Alpha::BlendOrAdditive, ); + + ui.add_space(16.0); + + ui.label("Rounding:"); + ui.add( + egui::DragValue::new(rounding) + .speed(1.0) + .clamp_range(0.0..=0.5 * image.size_vec2().min_elem()), + ); }); + ui.add_space(32.0); + ui.heading("This is an image you can click:"); ui.add(egui::ImageButton::new( - self.image.texture_id(ctx), - self.image.size_vec2(), + image.texture_id(ctx), + image.size_vec2(), )); }); } diff --git a/examples/retained_image/src/rust-logo-256x256.png b/examples/retained_image/src/rust-logo-256x256.png deleted file mode 100644 index f5ddd63f..00000000 Binary files a/examples/retained_image/src/rust-logo-256x256.png and /dev/null differ diff --git a/examples/retained_image/src/rust-logo-license.txt b/examples/retained_image/src/rust-logo-license.txt deleted file mode 100644 index 7efaf759..00000000 --- a/examples/retained_image/src/rust-logo-license.txt +++ /dev/null @@ -1 +0,0 @@ -Rust logo by Mozilla, from https://github.com/rust-lang/rust-artwork