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, *};
// 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)]
pub struct Memory {
/// The widget being interacted with (e.g. dragged, in case of a slider).
pub(crate) active_id: Option<Id>,
/// Which foldable regions are open.
pub(crate) open_foldables: HashSet<Id>,
pub(crate) foldables: HashMap<Id, FoldableState>,
windows: HashMap<Id, WindowState>,

View file

@ -166,23 +166,21 @@ impl Region {
Some(id),
);
let open = {
let state = {
let mut memory = self.ctx.memory.lock();
let mut state = memory.foldables.entry(id).or_default();
if interact.clicked {
if memory.open_foldables.contains(&id) {
memory.open_foldables.remove(&id);
} else {
memory.open_foldables.insert(id);
}
state.open = !state.open;
state.toggle_time = self.ctx.input.time;
}
memory.open_foldables.contains(&id)
*state
};
let fill_color = self.style.interact_fill_color(&interact);
let stroke_color = self.style.interact_stroke_color(&interact);
self.add_paint_cmd(PaintCmd::Rect {
corner_radius: 5.0,
corner_radius: self.style.interaction_corner_radius,
fill_color,
outline: Some(Outline::new(1.0, color::WHITE)),
rect: interact.rect,
@ -198,7 +196,8 @@ impl Region {
color: stroke_color,
width: self.style.line_width,
});
if !open {
if !state.open {
// Draw it as a plus:
self.add_paint_cmd(PaintCmd::Line {
points: vec![
@ -217,7 +216,39 @@ impl Region {
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);
}