[style] Fade out windows on close

This commit is contained in:
Emil Ernerfeldt 2021-01-20 00:30:07 +01:00
parent 29bb7c9f9d
commit e2217ff63a
7 changed files with 86 additions and 27 deletions

View file

@ -158,6 +158,34 @@ impl Area {
add_contents(&mut content_ui); add_contents(&mut content_ui);
prepared.end(ctx, content_ui) prepared.end(ctx, content_ui)
} }
pub fn show_open_close_animation(&self, ctx: &CtxRef, frame: &Frame, is_open: bool) {
// must be called first so animation managers know the latest state
let visibility_factor = ctx.animate_bool(self.id.with("close_animation"), is_open);
if is_open {
// we actually only show close animations.
// when opening a window we show it right away.
return;
}
if visibility_factor <= 0.0 {
return;
}
let layer_id = LayerId::new(self.order, self.id);
let area_rect = ctx.memory().areas.get(self.id).map(|area| area.rect());
if let Some(area_rect) = area_rect {
let clip_rect = ctx.available_rect();
let painter = Painter::new(ctx.clone(), layer_id, clip_rect);
// shrinkage: looks kinda a bad on its own
// let area_rect =
// Rect::from_center_size(area_rect.center(), visibility_factor * area_rect.size());
let frame = frame.multiply_with_opacity(visibility_factor);
painter.add(frame.paint(area_rect));
}
}
} }
impl Prepared { impl Prepared {

View file

@ -90,6 +90,13 @@ impl Frame {
self.stroke = stroke; self.stroke = stroke;
self self
} }
pub fn multiply_with_opacity(mut self, opacity: f32) -> Self {
self.fill = self.fill.linear_multiply(opacity);
self.stroke.color = self.stroke.color.linear_multiply(opacity);
self.shadow.color = self.shadow.color.linear_multiply(opacity);
self
}
} }
pub struct Prepared { pub struct Prepared {
@ -122,6 +129,31 @@ impl Frame {
prepared.end(ui); prepared.end(ui);
ret ret
} }
pub fn paint(&self, outer_rect: Rect) -> Shape {
let Self {
margin: _,
corner_radius,
shadow,
fill,
stroke,
} = *self;
let frame_shape = Shape::Rect {
rect: outer_rect,
corner_radius,
fill,
stroke,
};
if shadow == Default::default() {
frame_shape
} else {
let shadow = shadow.tessellate(outer_rect, corner_radius);
let shadow = Shape::Triangles(shadow);
Shape::Vec(vec![shadow, frame_shape])
}
}
} }
impl Prepared { impl Prepared {
@ -141,26 +173,9 @@ impl Prepared {
.. ..
} = self; } = self;
let frame_shape = Shape::Rect { let shape = frame.paint(outer_rect);
rect: outer_rect, ui.painter().set(where_to_put_background, shape);
corner_radius: frame.corner_radius,
fill: frame.fill,
stroke: frame.stroke,
};
if frame.shadow == Default::default() {
ui.painter().set(where_to_put_background, frame_shape);
} else {
let shadow = frame.shadow.tessellate(outer_rect, frame.corner_radius);
let shadow = Shape::Triangles(shadow);
ui.painter().set(
where_to_put_background,
Shape::Vec(vec![shadow, frame_shape]),
)
};
ui.advance_cursor_after_rect(outer_rect); ui.advance_cursor_after_rect(outer_rect);
outer_rect outer_rect
} }
} }

View file

@ -224,7 +224,12 @@ impl<'open> Window<'open> {
with_title_bar, with_title_bar,
} = self; } = self;
if matches!(open, Some(false)) && !ctx.memory().everything_is_visible() { let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
let is_open = !matches!(open, Some(false)) || ctx.memory().everything_is_visible();
area.show_open_close_animation(ctx, &frame, is_open);
if !is_open {
return None; return None;
} }
@ -244,8 +249,6 @@ impl<'open> Window<'open> {
let resize = resize.resizable(false); // We move it manually let resize = resize.resizable(false); // We move it manually
let mut resize = resize.id(resize_id); let mut resize = resize.id(resize_id);
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
let mut area = area.begin(ctx); let mut area = area.begin(ctx);
let title_content_spacing = 2.0 * ctx.style().spacing.item_spacing.y; let title_content_spacing = 2.0 * ctx.style().spacing.item_spacing.y;

View file

@ -22,7 +22,7 @@ impl Default for WidgetGallery {
radio: Enum::First, radio: Enum::First,
scalar: 42.0, scalar: 42.0,
string: "Hello World!".to_owned(), string: "Hello World!".to_owned(),
color: (egui::Rgba::from(egui::Color32::LIGHT_BLUE) * 0.5).into(), color: egui::Color32::LIGHT_BLUE.linear_multiply(0.5),
} }
} }
} }

View file

@ -129,6 +129,14 @@ impl Color32 {
pub fn to_tuple(&self) -> (u8, u8, u8, u8) { pub fn to_tuple(&self) -> (u8, u8, u8, u8) {
(self.r(), self.g(), self.b(), self.a()) (self.r(), self.g(), self.b(), self.a())
} }
/// Multiply with 0.5 to make color half as opaque.
pub fn linear_multiply(self, factor: f32) -> Color32 {
debug_assert!(0.0 <= factor && factor <= 1.0);
// As an unfortunate side-effect of using premultiplied alpha
// we need a somewhat expensive conversion to linear space and back.
Rgba::from(self).multiply(factor).into()
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -1,11 +1,15 @@
use super::*; use super::*;
/// A rectangular shadow with a soft penumbra. /// The color and fuzziness of a fuzzy shape.
/// Can be used for a rectangular shadow with a soft penumbra.
#[derive(Clone, Copy, Debug, Default, PartialEq)] #[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Shadow { pub struct Shadow {
// The shadow extends this much outside the rect. /// The shadow extends this much outside the rect.
/// The size of the fuzzy penumbra.
pub extrusion: f32, pub extrusion: f32,
/// Color of the opaque center of the shadow.
pub color: Color32, pub color: Color32,
} }

View file

@ -420,8 +420,9 @@ fn stroke_path(
fn mul_color(color: Color32, factor: f32) -> Color32 { fn mul_color(color: Color32, factor: f32) -> Color32 {
debug_assert!(0.0 <= factor && factor <= 1.0); debug_assert!(0.0 <= factor && factor <= 1.0);
// sRGBA correct fading requires conversion to linear space and back again because of premultiplied alpha // As an unfortunate side-effect of using premultiplied alpha
Rgba::from(color).multiply(factor).into() // we need a somewhat expensive conversion to linear space and back.
color.linear_multiply(factor)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------