diff --git a/eframe/examples/image.rs b/eframe/examples/image.rs index 5b890220..0edcf605 100644 --- a/eframe/examples/image.rs +++ b/eframe/examples/image.rs @@ -4,7 +4,10 @@ use eframe::egui; use egui_extras::RetainedImage; fn main() { - let options = eframe::NativeOptions::default(); + let options = eframe::NativeOptions { + initial_window_size: Some(egui::vec2(500.0, 900.0)), + ..Default::default() + }; eframe::run_native( "Show an image with eframe/egui", options, @@ -34,6 +37,12 @@ impl eframe::App for MyApp { ui.heading("This is an image:"); self.image.show(ui); + ui.heading("This is a rotated image:"); + 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)), + ); + ui.heading("This is an image you can click:"); ui.add(egui::ImageButton::new( self.image.texture_id(ctx), diff --git a/egui/src/widgets/image.rs b/egui/src/widgets/image.rs index 61ea0d9a..889fbdc9 100644 --- a/egui/src/widgets/image.rs +++ b/egui/src/widgets/image.rs @@ -1,4 +1,5 @@ use crate::*; +use emath::Rot2; /// An widget to show an image of a given size. /// @@ -36,6 +37,7 @@ pub struct Image { bg_fill: Color32, tint: Color32, sense: Sense, + rotation: Option<(Rot2, Vec2)>, } impl Image { @@ -47,6 +49,7 @@ impl Image { bg_fill: Default::default(), tint: Color32::WHITE, sense: Sense::hover(), + rotation: None, } } @@ -75,6 +78,17 @@ impl Image { self.sense = sense; self } + + /// Rotate the image about an origin by some angle + /// + /// Positive angle is clockwise. + /// 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. + pub fn rotate(mut self, angle: f32, origin: Vec2) -> Self { + self.rotation = Some((Rot2::from_angle(angle), origin)); + self + } } impl Image { @@ -88,10 +102,11 @@ impl Image { let Self { texture_id, uv, - size: _, + size, bg_fill, tint, sense: _, + rotation, } = self; if *bg_fill != Default::default() { @@ -104,6 +119,9 @@ impl Image { // TODO: builder pattern for Mesh 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); + } ui.painter().add(Shape::mesh(mesh)); } } diff --git a/epaint/src/mesh.rs b/epaint/src/mesh.rs index 7a5e0dcd..c14f41fa 100644 --- a/epaint/src/mesh.rs +++ b/epaint/src/mesh.rs @@ -254,6 +254,15 @@ impl Mesh { v.pos += delta; } } + + /// Rotate by some angle about an origin, in-place. + /// + /// Origin is a position in screen space. + pub fn rotate(&mut self, rot: Rot2, origin: Pos2) { + for v in &mut self.vertices { + v.pos = origin + rot * (v.pos - origin); + } + } } // ----------------------------------------------------------------------------