Add `Ui::set_opacity` (#3965)
Closes <https://github.com/emilk/egui/issues/3473>.
This commit is contained in:
parent
34e8af87d4
commit
2feb1440be
|
|
@ -28,6 +28,11 @@ pub struct Painter {
|
||||||
/// If set, all shapes will have their colors modified to be closer to this.
|
/// If set, all shapes will have their colors modified to be closer to this.
|
||||||
/// This is used to implement grayed out interfaces.
|
/// This is used to implement grayed out interfaces.
|
||||||
fade_to_color: Option<Color32>,
|
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 {
|
impl Painter {
|
||||||
|
|
@ -38,6 +43,7 @@ impl Painter {
|
||||||
layer_id,
|
layer_id,
|
||||||
clip_rect,
|
clip_rect,
|
||||||
fade_to_color: None,
|
fade_to_color: None,
|
||||||
|
opacity_factor: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,6 +55,7 @@ impl Painter {
|
||||||
layer_id,
|
layer_id,
|
||||||
clip_rect: self.clip_rect,
|
clip_rect: self.clip_rect,
|
||||||
fade_to_color: None,
|
fade_to_color: None,
|
||||||
|
opacity_factor: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,6 +69,7 @@ impl Painter {
|
||||||
layer_id: self.layer_id,
|
layer_id: self.layer_id,
|
||||||
clip_rect: rect.intersect(self.clip_rect),
|
clip_rect: rect.intersect(self.clip_rect),
|
||||||
fade_to_color: self.fade_to_color,
|
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;
|
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 {
|
pub(crate) fn is_visible(&self) -> bool {
|
||||||
self.fade_to_color != Some(Color32::TRANSPARENT)
|
self.fade_to_color != Some(Color32::TRANSPARENT)
|
||||||
}
|
}
|
||||||
|
|
@ -151,13 +165,16 @@ impl Painter {
|
||||||
if let Some(fade_to_color) = self.fade_to_color {
|
if let Some(fade_to_color) = self.fade_to_color {
|
||||||
tint_shape_towards(shape, 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.
|
/// It is up to the caller to make sure there is room for this.
|
||||||
/// Can be used for free painting.
|
/// Can be used for free painting.
|
||||||
/// NOTE: all coordinates are screen coordinates!
|
/// NOTE: all coordinates are screen coordinates!
|
||||||
pub fn add(&self, shape: impl Into<Shape>) -> ShapeIdx {
|
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))
|
self.paint_list(|l| l.add(self.clip_rect, Shape::Noop))
|
||||||
} else {
|
} else {
|
||||||
let mut shape = shape.into();
|
let mut shape = shape.into();
|
||||||
|
|
@ -170,10 +187,10 @@ impl Painter {
|
||||||
///
|
///
|
||||||
/// Calling this once is generally faster than calling [`Self::add`] multiple times.
|
/// Calling this once is generally faster than calling [`Self::add`] multiple times.
|
||||||
pub fn extend<I: IntoIterator<Item = Shape>>(&self, shapes: I) {
|
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;
|
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| {
|
let shapes = shapes.into_iter().map(|mut shape| {
|
||||||
self.transform_shape(&mut shape);
|
self.transform_shape(&mut shape);
|
||||||
shape
|
shape
|
||||||
|
|
@ -181,7 +198,7 @@ impl Painter {
|
||||||
self.paint_list(|l| l.extend(self.clip_rect, shapes));
|
self.paint_list(|l| l.extend(self.clip_rect, shapes));
|
||||||
} else {
|
} else {
|
||||||
self.paint_list(|l| l.extend(self.clip_rect, shapes));
|
self.paint_list(|l| l.extend(self.clip_rect, shapes));
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify an existing [`Shape`].
|
/// 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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`].
|
/// Read the [`Layout`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn layout(&self) -> &Layout {
|
pub fn layout(&self) -> &Layout {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ pub struct WidgetGallery {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
boolean: bool,
|
boolean: bool,
|
||||||
|
opacity: f32,
|
||||||
radio: Enum,
|
radio: Enum,
|
||||||
scalar: f32,
|
scalar: f32,
|
||||||
string: String,
|
string: String,
|
||||||
|
|
@ -28,6 +29,7 @@ impl Default for WidgetGallery {
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
visible: true,
|
visible: true,
|
||||||
|
opacity: 1.0,
|
||||||
boolean: false,
|
boolean: false,
|
||||||
radio: Enum::First,
|
radio: Enum::First,
|
||||||
scalar: 42.0,
|
scalar: 42.0,
|
||||||
|
|
@ -61,6 +63,7 @@ impl super::View for WidgetGallery {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.add_enabled_ui(self.enabled, |ui| {
|
ui.add_enabled_ui(self.enabled, |ui| {
|
||||||
ui.set_visible(self.visible);
|
ui.set_visible(self.visible);
|
||||||
|
ui.set_opacity(self.opacity);
|
||||||
|
|
||||||
egui::Grid::new("my_grid")
|
egui::Grid::new("my_grid")
|
||||||
.num_columns(2)
|
.num_columns(2)
|
||||||
|
|
@ -79,6 +82,12 @@ impl super::View for WidgetGallery {
|
||||||
if self.visible {
|
if self.visible {
|
||||||
ui.checkbox(&mut self.enabled, "Interactive")
|
ui.checkbox(&mut self.enabled, "Interactive")
|
||||||
.on_hover_text("Uncheck to inspect how the widgets look when disabled.");
|
.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 {
|
let Self {
|
||||||
enabled: _,
|
enabled: _,
|
||||||
visible: _,
|
visible: _,
|
||||||
|
opacity: _,
|
||||||
boolean,
|
boolean,
|
||||||
radio,
|
radio,
|
||||||
scalar,
|
scalar,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue