Skip to content

Commit a94984d

Browse files
authored
Merge pull request iced-rs#2424 from iced-rs/feature/image-opacity
Introduce dynamic `opacity` support for `Image` and `Svg`
2 parents 38cf87c + afb4cb9 commit a94984d

File tree

18 files changed

+150
-41
lines changed

18 files changed

+150
-41
lines changed

core/src/image.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,5 +174,6 @@ pub trait Renderer: crate::Renderer {
174174
filter_method: FilterMethod,
175175
bounds: Rectangle,
176176
rotation: Radians,
177+
opacity: f32,
177178
);
178179
}

core/src/renderer/null.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ impl image::Renderer for () {
173173
_filter_method: image::FilterMethod,
174174
_bounds: Rectangle,
175175
_rotation: Radians,
176+
_opacity: f32,
176177
) {
177178
}
178179
}
@@ -188,6 +189,7 @@ impl svg::Renderer for () {
188189
_color: Option<Color>,
189190
_bounds: Rectangle,
190191
_rotation: Radians,
192+
_opacity: f32,
191193
) {
192194
}
193195
}

core/src/svg.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,5 +101,6 @@ pub trait Renderer: crate::Renderer {
101101
color: Option<Color>,
102102
bounds: Rectangle,
103103
rotation: Radians,
104+
opacity: f32,
104105
);
105106
}

examples/ferris/src/main.rs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub fn main() -> iced::Result {
1717

1818
struct Image {
1919
width: f32,
20+
opacity: f32,
2021
rotation: Rotation,
2122
content_fit: ContentFit,
2223
spin: bool,
@@ -26,6 +27,7 @@ struct Image {
2627
#[derive(Debug, Clone, Copy)]
2728
enum Message {
2829
WidthChanged(f32),
30+
OpacityChanged(f32),
2931
RotationStrategyChanged(RotationStrategy),
3032
RotationChanged(Degrees),
3133
ContentFitChanged(ContentFit),
@@ -39,6 +41,9 @@ impl Image {
3941
Message::WidthChanged(width) => {
4042
self.width = width;
4143
}
44+
Message::OpacityChanged(opacity) => {
45+
self.opacity = opacity;
46+
}
4247
Message::RotationStrategyChanged(strategy) => {
4348
self.rotation = match strategy {
4449
RotationStrategy::Floating => {
@@ -97,14 +102,15 @@ impl Image {
97102
.width(self.width)
98103
.content_fit(self.content_fit)
99104
.rotation(self.rotation)
105+
.opacity(self.opacity)
100106
)
101107
.explain(Color::WHITE),
102108
"I am Ferris!"
103109
]
104110
.spacing(20)
105111
.align_items(Alignment::Center);
106112

107-
let sizing = row![
113+
let fit = row![
108114
pick_list(
109115
[
110116
ContentFit::Contain,
@@ -117,19 +123,6 @@ impl Image {
117123
Message::ContentFitChanged
118124
)
119125
.width(Length::Fill),
120-
column![
121-
slider(100.0..=500.0, self.width, Message::WidthChanged),
122-
text(format!("Width: {}px", self.width))
123-
.size(12)
124-
.line_height(1.0)
125-
]
126-
.spacing(2)
127-
.align_items(Alignment::Center)
128-
]
129-
.spacing(10)
130-
.align_items(Alignment::End);
131-
132-
let rotation = row![
133126
pick_list(
134127
[RotationStrategy::Floating, RotationStrategy::Solid],
135128
Some(match self.rotation {
@@ -139,7 +132,21 @@ impl Image {
139132
Message::RotationStrategyChanged,
140133
)
141134
.width(Length::Fill),
142-
column![
135+
]
136+
.spacing(10)
137+
.align_items(Alignment::End);
138+
139+
let properties = row![
140+
with_value(
141+
slider(100.0..=500.0, self.width, Message::WidthChanged),
142+
format!("Width: {}px", self.width)
143+
),
144+
with_value(
145+
slider(0.0..=1.0, self.opacity, Message::OpacityChanged)
146+
.step(0.01),
147+
format!("Opacity: {:.2}", self.opacity)
148+
),
149+
with_value(
143150
row![
144151
slider(
145152
Degrees::RANGE,
@@ -153,20 +160,13 @@ impl Image {
153160
]
154161
.spacing(10)
155162
.align_items(Alignment::Center),
156-
text(format!(
157-
"Rotation: {:.0}°",
158-
f32::from(self.rotation.degrees())
159-
))
160-
.size(12)
161-
.line_height(1.0)
162-
]
163-
.spacing(2)
164-
.align_items(Alignment::Center)
163+
format!("Rotation: {:.0}°", f32::from(self.rotation.degrees()))
164+
)
165165
]
166166
.spacing(10)
167167
.align_items(Alignment::End);
168168

169-
container(column![center(i_am_ferris), sizing, rotation].spacing(10))
169+
container(column![fit, center(i_am_ferris), properties].spacing(10))
170170
.padding(10)
171171
.into()
172172
}
@@ -176,6 +176,7 @@ impl Default for Image {
176176
fn default() -> Self {
177177
Self {
178178
width: 300.0,
179+
opacity: 1.0,
179180
rotation: Rotation::default(),
180181
content_fit: ContentFit::default(),
181182
spin: false,
@@ -198,3 +199,13 @@ impl std::fmt::Display for RotationStrategy {
198199
})
199200
}
200201
}
202+
203+
fn with_value<'a>(
204+
control: impl Into<Element<'a, Message>>,
205+
value: String,
206+
) -> Element<'a, Message> {
207+
column![control.into(), text(value).size(12).line_height(1.0)]
208+
.spacing(2)
209+
.align_items(Alignment::Center)
210+
.into()
211+
}

graphics/src/image.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ pub enum Image {
1818
/// The bounds of the image.
1919
bounds: Rectangle,
2020

21-
/// The rotation of the image in radians
21+
/// The rotation of the image.
2222
rotation: Radians,
23+
24+
/// The opacity of the image.
25+
opacity: f32,
2326
},
2427
/// A vector image.
2528
Vector {
@@ -32,8 +35,11 @@ pub enum Image {
3235
/// The bounds of the image.
3336
bounds: Rectangle,
3437

35-
/// The rotation of the image in radians
38+
/// The rotation of the image.
3639
rotation: Radians,
40+
41+
/// The opacity of the image.
42+
opacity: f32,
3743
},
3844
}
3945

renderer/src/fallback.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,18 @@ where
155155
filter_method: image::FilterMethod,
156156
bounds: Rectangle,
157157
rotation: Radians,
158+
opacity: f32,
158159
) {
159160
delegate!(
160161
self,
161162
renderer,
162-
renderer.draw_image(handle, filter_method, bounds, rotation)
163+
renderer.draw_image(
164+
handle,
165+
filter_method,
166+
bounds,
167+
rotation,
168+
opacity
169+
)
163170
);
164171
}
165172
}
@@ -179,11 +186,12 @@ where
179186
color: Option<Color>,
180187
bounds: Rectangle,
181188
rotation: Radians,
189+
opacity: f32,
182190
) {
183191
delegate!(
184192
self,
185193
renderer,
186-
renderer.draw_svg(handle, color, bounds, rotation)
194+
renderer.draw_svg(handle, color, bounds, rotation, opacity)
187195
);
188196
}
189197
}

tiny_skia/src/engine.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ impl Engine {
551551
filter_method,
552552
bounds,
553553
rotation,
554+
opacity,
554555
} => {
555556
let physical_bounds = *bounds * _transformation;
556557

@@ -574,6 +575,7 @@ impl Engine {
574575
handle,
575576
*filter_method,
576577
*bounds,
578+
*opacity,
577579
_pixels,
578580
transform,
579581
clip_mask,
@@ -585,6 +587,7 @@ impl Engine {
585587
color,
586588
bounds,
587589
rotation,
590+
opacity,
588591
} => {
589592
let physical_bounds = *bounds * _transformation;
590593

@@ -608,6 +611,7 @@ impl Engine {
608611
handle,
609612
*color,
610613
physical_bounds,
614+
*opacity,
611615
_pixels,
612616
transform,
613617
clip_mask,

tiny_skia/src/layer.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,14 @@ impl Layer {
122122
bounds: Rectangle,
123123
transformation: Transformation,
124124
rotation: Radians,
125+
opacity: f32,
125126
) {
126127
let image = Image::Raster {
127128
handle,
128129
filter_method,
129130
bounds: bounds * transformation,
130131
rotation,
132+
opacity,
131133
};
132134

133135
self.images.push(image);
@@ -140,12 +142,14 @@ impl Layer {
140142
bounds: Rectangle,
141143
transformation: Transformation,
142144
rotation: Radians,
145+
opacity: f32,
143146
) {
144147
let svg = Image::Vector {
145148
handle,
146149
color,
147150
bounds: bounds * transformation,
148151
rotation,
152+
opacity,
149153
};
150154

151155
self.images.push(svg);

tiny_skia/src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ impl core::image::Renderer for Renderer {
378378
filter_method: core::image::FilterMethod,
379379
bounds: Rectangle,
380380
rotation: core::Radians,
381+
opacity: f32,
381382
) {
382383
let (layer, transformation) = self.layers.current_mut();
383384
layer.draw_image(
@@ -386,6 +387,7 @@ impl core::image::Renderer for Renderer {
386387
bounds,
387388
transformation,
388389
rotation,
390+
opacity,
389391
);
390392
}
391393
}
@@ -405,9 +407,17 @@ impl core::svg::Renderer for Renderer {
405407
color: Option<Color>,
406408
bounds: Rectangle,
407409
rotation: core::Radians,
410+
opacity: f32,
408411
) {
409412
let (layer, transformation) = self.layers.current_mut();
410-
layer.draw_svg(handle, color, bounds, transformation, rotation);
413+
layer.draw_svg(
414+
handle,
415+
color,
416+
bounds,
417+
transformation,
418+
rotation,
419+
opacity,
420+
);
411421
}
412422
}
413423

tiny_skia/src/raster.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ impl Pipeline {
3131
handle: &raster::Handle,
3232
filter_method: raster::FilterMethod,
3333
bounds: Rectangle,
34+
opacity: f32,
3435
pixels: &mut tiny_skia::PixmapMut<'_>,
3536
transform: tiny_skia::Transform,
3637
clip_mask: Option<&tiny_skia::Mask>,
@@ -56,6 +57,7 @@ impl Pipeline {
5657
image,
5758
&tiny_skia::PixmapPaint {
5859
quality,
60+
opacity,
5961
..Default::default()
6062
},
6163
transform,

0 commit comments

Comments
 (0)