Animate foldable regions

This commit is contained in:
Emil Ernerfeldt 2020-04-21 14:47:17 +02:00
parent 0ed578341b
commit 9be5537418
2 changed files with 59 additions and 12 deletions

View file

@ -1,14 +1,30 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use crate::{window::WindowState, *}; use crate::{window::WindowState, *};
// TODO: move together with foldable code into own file
#[derive(Clone, Copy, Debug)]
pub struct FoldableState {
pub open: bool,
pub toggle_time: f64,
}
impl Default for FoldableState {
fn default() -> Self {
Self {
open: false,
toggle_time: -std::f64::INFINITY,
}
}
}
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct Memory { pub struct Memory {
/// The widget being interacted with (e.g. dragged, in case of a slider). /// The widget being interacted with (e.g. dragged, in case of a slider).
pub(crate) active_id: Option<Id>, pub(crate) active_id: Option<Id>,
/// Which foldable regions are open. /// Which foldable regions are open.
pub(crate) open_foldables: HashSet<Id>, pub(crate) foldables: HashMap<Id, FoldableState>,
windows: HashMap<Id, WindowState>, windows: HashMap<Id, WindowState>,

View file

@ -166,23 +166,21 @@ impl Region {
Some(id), Some(id),
); );
let open = { let state = {
let mut memory = self.ctx.memory.lock(); let mut memory = self.ctx.memory.lock();
let mut state = memory.foldables.entry(id).or_default();
if interact.clicked { if interact.clicked {
if memory.open_foldables.contains(&id) { state.open = !state.open;
memory.open_foldables.remove(&id); state.toggle_time = self.ctx.input.time;
} else {
memory.open_foldables.insert(id);
}
} }
memory.open_foldables.contains(&id) *state
}; };
let fill_color = self.style.interact_fill_color(&interact); let fill_color = self.style.interact_fill_color(&interact);
let stroke_color = self.style.interact_stroke_color(&interact); let stroke_color = self.style.interact_stroke_color(&interact);
self.add_paint_cmd(PaintCmd::Rect { self.add_paint_cmd(PaintCmd::Rect {
corner_radius: 5.0, corner_radius: self.style.interaction_corner_radius,
fill_color, fill_color,
outline: Some(Outline::new(1.0, color::WHITE)), outline: Some(Outline::new(1.0, color::WHITE)),
rect: interact.rect, rect: interact.rect,
@ -198,7 +196,8 @@ impl Region {
color: stroke_color, color: stroke_color,
width: self.style.line_width, width: self.style.line_width,
}); });
if !open {
if !state.open {
// Draw it as a plus: // Draw it as a plus:
self.add_paint_cmd(PaintCmd::Line { self.add_paint_cmd(PaintCmd::Line {
points: vec![ points: vec![
@ -217,7 +216,39 @@ impl Region {
None, None,
); );
if open { let animation_time = self.style().animation_time;
let time_since_toggle = (self.ctx.input.time - state.toggle_time) as f32;
if time_since_toggle < animation_time {
self.indent(id, |region| {
// animation time
let max_height = if state.open {
remap(
time_since_toggle,
0.0,
animation_time,
50.0, // Get instant feedback
1500.0, // We don't expect to get bigger than this
)
} else {
remap_clamp(
time_since_toggle,
0.0,
animation_time,
50.0, // TODO: state.open_height
0.0,
)
};
region
.clip_rect
.set_height(region.clip_rect.height().min(max_height));
add_contents(region);
region.bounding_size.y = region.bounding_size.y.min(max_height);
});
} else if state.open {
self.indent(id, add_contents); self.indent(id, add_contents);
} }