From e0df3b001730678ec7e0764b9dd73c5f417f7ed7 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Mon, 16 Sep 2024 14:15:49 -0700 Subject: [PATCH] Image opacity support --- CHANGELOG.md | 3 +++ Cargo.lock | 14 +++++++------- src/graphics.rs | 14 ++++++++++---- src/widgets/image.rs | 16 ++++++++++++++-- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32d7b2c..8831a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 resize event. - `PlatformWindow::outer_size` is a new function that returns the window's current outer size. +- `Graphics::draw_texture` and `Graphics::draw_textured_shape` now both accept + an opactiy parameter controlling how opaque the texture should be rendered at. ### Changed @@ -161,6 +163,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 initialized. - `Window::on_file_drop` is a new callback that is invoked when file drop events occur for the window. +- `Image::opacity` allows rendering the image with a given opacity. [139]: https://github.com/khonsulabs/cushy/issues/139 diff --git a/Cargo.lock b/Cargo.lock index 34f09c5..e4ab3c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "appit" @@ -418,9 +418,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.18" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" dependencies = [ "jobserver", "libc", @@ -1311,7 +1311,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kludgine" version = "0.11.0" -source = "git+https://github.com/khonsulabs/kludgine#eccacdaffe4a60d1887a201a68656f0058a12088" +source = "git+https://github.com/khonsulabs/kludgine#186a350402da7068aea248801477376611b5f12a" dependencies = [ "ahash", "alot", @@ -1963,9 +1963,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "orbclient" diff --git a/src/graphics.rs b/src/graphics.rs index f97a167..fd01e7f 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -170,14 +170,18 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> { } /// Draws `texture` at `destination`, scaling as necessary. - pub fn draw_texture(&mut self, texture: &impl TextureSource, destination: Rect) - where + pub fn draw_texture( + &mut self, + texture: &impl TextureSource, + destination: Rect, + opacity: ZeroToOne, + ) where Unit: figures::ScreenUnit + ShaderScalable, i32: From<::Signed>, { let translate = Point::::from_px(self.translation(), self.scale()); self.renderer - .draw_texture(texture, destination + translate, *self.opacity); + .draw_texture(texture, destination + translate, *(self.opacity * opacity)); } /// Draws a shape that was created with texture coordinates, applying the @@ -186,16 +190,18 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> { &mut self, shape: impl Into>, texture: &impl TextureSource, + opacity: ZeroToOne, ) where Unit: Zero + ShaderScalable + figures::ScreenUnit + Copy, i32: From<::Signed>, Shape: ShapeSource + 'shape, { let mut shape = shape.into(); + let effective_opacity = self.opacity * opacity; shape.opacity = Some( shape .opacity - .map_or(*self.opacity, |opacity| opacity * *self.opacity), + .map_or(*effective_opacity, |opacity| opacity * *effective_opacity), ); shape.translation += Point::::from_px(self.translation(), self.scale()); self.renderer.draw_textured_shape(shape, texture); diff --git a/src/widgets/image.rs b/src/widgets/image.rs index dbdde77..004498a 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -5,7 +5,7 @@ use figures::{FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, Size, Zero use kludgine::{AnyTexture, CollectedTexture, LazyTexture, SharedTexture, Texture, TextureRegion}; use crate::animation::ZeroToOne; -use crate::context::LayoutContext; +use crate::context::{LayoutContext, Trackable}; use crate::value::{IntoValue, Source, Value}; use crate::widget::Widget; use crate::ConstraintLimit; @@ -17,6 +17,8 @@ pub struct Image { pub contents: Value, /// The scaling strategy to apply. pub scaling: Value, + /// The opacity to render the image with. + pub opacity: Value, } impl Image { @@ -26,6 +28,7 @@ impl Image { Self { contents: contents.into_value(), scaling: Value::default(), + opacity: Value::Constant(ZeroToOne::ONE), } } @@ -36,6 +39,13 @@ impl Image { self } + /// Applies `opacity` when drawing the image, returns self. + #[must_use] + pub fn opacity(mut self, opacity: impl IntoValue) -> Self { + self.opacity = opacity.into_value(); + self + } + /// Applies the aspect-fit scaling strategy and returns self. /// /// The aspect-fit scaling strategy scales the image to be the largest size @@ -145,9 +155,11 @@ impl Image { impl Widget for Image { fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_>) { + self.contents.invalidate_when_changed(context); + let opacity = self.opacity.get_tracking_redraw(context); self.contents.map(|texture| { let rect = self.calculate_image_rect(texture, context.gfx.size(), context); - context.gfx.draw_texture(texture, rect); + context.gfx.draw_texture(texture, rect, opacity); }); }