Add `Ui::set_opacity` (#3965)

Closes <https://github.com/emilk/egui/issues/3473>.
This commit is contained in:
YgorSouza 2024-02-16 10:39:30 +01:00 committed by GitHub
parent 34e8af87d4
commit 2feb1440be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 4 deletions

View File

@ -28,6 +28,11 @@ pub struct Painter {
/// If set, all shapes will have their colors modified to be closer to this.
/// This is used to implement grayed out interfaces.
fade_to_color: Option<Color32>,
/// If set, all shapes will have their colors modified with [`Color32::gamma_multiply`] with
/// this value as the factor.
/// This is used to make interfaces semi-transparent.
opacity_factor: f32,
}
impl Painter {
@ -38,6 +43,7 @@ impl Painter {
layer_id,
clip_rect,
fade_to_color: None,
opacity_factor: 1.0,
}
}
@ -49,6 +55,7 @@ impl Painter {
layer_id,
clip_rect: self.clip_rect,
fade_to_color: None,
opacity_factor: 1.0,
}
}
@ -62,6 +69,7 @@ impl Painter {
layer_id: self.layer_id,
clip_rect: rect.intersect(self.clip_rect),
fade_to_color: self.fade_to_color,
opacity_factor: self.opacity_factor,
}
}
@ -75,6 +83,12 @@ impl Painter {
self.fade_to_color = fade_to_color;
}
pub(crate) fn set_opacity(&mut self, opacity: f32) {
if opacity.is_finite() {
self.opacity_factor = opacity.clamp(0.0, 1.0);
}
}
pub(crate) fn is_visible(&self) -> bool {
self.fade_to_color != Some(Color32::TRANSPARENT)
}
@ -151,13 +165,16 @@ impl Painter {
if let Some(fade_to_color) = self.fade_to_color {
tint_shape_towards(shape, fade_to_color);
}
if self.opacity_factor < 1.0 {
multiply_opacity(shape, self.opacity_factor);
}
}
/// It is up to the caller to make sure there is room for this.
/// Can be used for free painting.
/// NOTE: all coordinates are screen coordinates!
pub fn add(&self, shape: impl Into<Shape>) -> ShapeIdx {
if self.fade_to_color == Some(Color32::TRANSPARENT) {
if self.fade_to_color == Some(Color32::TRANSPARENT) || self.opacity_factor == 0.0 {
self.paint_list(|l| l.add(self.clip_rect, Shape::Noop))
} else {
let mut shape = shape.into();
@ -170,10 +187,10 @@ impl Painter {
///
/// Calling this once is generally faster than calling [`Self::add`] multiple times.
pub fn extend<I: IntoIterator<Item = Shape>>(&self, shapes: I) {
if self.fade_to_color == Some(Color32::TRANSPARENT) {
if self.fade_to_color == Some(Color32::TRANSPARENT) || self.opacity_factor == 0.0 {
return;
}
if self.fade_to_color.is_some() {
if self.fade_to_color.is_some() || self.opacity_factor < 1.0 {
let shapes = shapes.into_iter().map(|mut shape| {
self.transform_shape(&mut shape);
shape
@ -181,7 +198,7 @@ impl Painter {
self.paint_list(|l| l.extend(self.clip_rect, shapes));
} else {
self.paint_list(|l| l.extend(self.clip_rect, shapes));
};
}
}
/// Modify an existing [`Shape`].
@ -496,3 +513,11 @@ fn tint_shape_towards(shape: &mut Shape, target: Color32) {
}
});
}
fn multiply_opacity(shape: &mut Shape, opacity: f32) {
epaint::shape_transform::adjust_colors(shape, &|color| {
if *color != Color32::PLACEHOLDER {
*color = color.gamma_multiply(opacity);
}
});
}

View File

@ -277,6 +277,26 @@ impl Ui {
}
}
/// Make the widget in this [`Ui`] semi-transparent.
///
/// `opacity` must be between 0.0 and 1.0, where 0.0 means fully transparent (i.e., invisible)
/// and 1.0 means fully opaque (i.e., the same as not calling the method at all).
///
/// ### Example
/// ```
/// # egui::__run_test_ui(|ui| {
/// ui.group(|ui| {
/// ui.set_opacity(0.5);
/// if ui.button("Half-transparent button").clicked() {
/// /* … */
/// }
/// });
/// # });
/// ```
pub fn set_opacity(&mut self, opacity: f32) {
self.painter.set_opacity(opacity);
}
/// Read the [`Layout`].
#[inline]
pub fn layout(&self) -> &Layout {

View File

@ -12,6 +12,7 @@ pub struct WidgetGallery {
enabled: bool,
visible: bool,
boolean: bool,
opacity: f32,
radio: Enum,
scalar: f32,
string: String,
@ -28,6 +29,7 @@ impl Default for WidgetGallery {
Self {
enabled: true,
visible: true,
opacity: 1.0,
boolean: false,
radio: Enum::First,
scalar: 42.0,
@ -61,6 +63,7 @@ impl super::View for WidgetGallery {
fn ui(&mut self, ui: &mut egui::Ui) {
ui.add_enabled_ui(self.enabled, |ui| {
ui.set_visible(self.visible);
ui.set_opacity(self.opacity);
egui::Grid::new("my_grid")
.num_columns(2)
@ -79,6 +82,12 @@ impl super::View for WidgetGallery {
if self.visible {
ui.checkbox(&mut self.enabled, "Interactive")
.on_hover_text("Uncheck to inspect how the widgets look when disabled.");
(ui.add(
egui::DragValue::new(&mut self.opacity)
.speed(0.01)
.clamp_range(0.0..=1.0),
) | ui.label("Opacity"))
.on_hover_text("Reduce this value to make widgets semi-transparent");
}
});
@ -99,6 +108,7 @@ impl WidgetGallery {
let Self {
enabled: _,
visible: _,
opacity: _,
boolean,
radio,
scalar,