Added Collapse widget

Also tweaked progress bar animation
This commit is contained in:
Jonathan Johnson 2023-11-22 15:46:58 -08:00
parent 3e651c2964
commit 15480ba68b
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
6 changed files with 169 additions and 11 deletions

26
examples/collapse.rs Normal file
View file

@ -0,0 +1,26 @@
use gooey::value::Dynamic;
use gooey::widget::MakeWidget;
use gooey::widgets::checkbox::Checkable;
use gooey::Run;
const EXPLANATION: &str =
"The collapse widget allows showing and hiding another widget based on a Dynamic<bool>.";
fn main() -> gooey::Result {
let collapse = Dynamic::new(false);
collapse
.clone()
.into_checkbox("Collapse")
.and(
"Content Above"
.contain()
.and(EXPLANATION.collapse_vertically(collapse))
.and("Content Below".contain())
.into_rows(),
)
.into_columns()
.centered()
.expand()
.run()
}

View file

@ -505,7 +505,7 @@ impl TreeData {
fn invalidate(&mut self, id: LotId, include_hierarchy: bool) {
let mut node = &mut self.nodes[id];
while node.layout.is_some() {
loop {
node.layout = None;
node.last_layout_query = None;

View file

@ -28,8 +28,8 @@ use crate::utils::IgnorePoison;
use crate::value::{IntoDynamic, IntoValue, Value};
use crate::widgets::checkbox::{Checkable, CheckboxState};
use crate::widgets::{
Align, Button, Checkbox, Container, Expand, Resize, Scroll, Space, Stack, Style, Themed,
ThemedMode,
Align, Button, Checkbox, Collapse, Container, Expand, Resize, Scroll, Space, Stack, Style,
Themed, ThemedMode,
};
use crate::window::{RunningWindow, ThemeMode, Window, WindowBehavior};
use crate::{ConstraintLimit, Run};
@ -865,6 +865,23 @@ pub trait MakeWidget: Sized {
fn themed_mode(self, mode: impl IntoValue<ThemeMode>) -> ThemedMode {
ThemedMode::new(mode, self)
}
/// Returns a widget that collapses `self` horizontally based on the dynamic boolean value.
///
/// This widget will be collapsed when the dynamic contains `true`, and
/// revealed when the dynamic contains `false`.
fn collapse_horizontally(self, collapse_when: impl IntoDynamic<bool>) -> Collapse {
Collapse::horizontal(collapse_when, self)
}
/// Returns a widget that collapses `self` vertically based on the dynamic
/// boolean value.
///
/// This widget will be collapsed when the dynamic contains `true`, and
/// revealed when the dynamic contains `false`.
fn collapse_vertically(self, collapse_when: impl IntoDynamic<bool>) -> Collapse {
Collapse::vertical(collapse_when, self)
}
}
/// A type that can create a [`WidgetInstance`] with a preallocated

View file

@ -4,6 +4,7 @@ mod align;
pub mod button;
mod canvas;
pub mod checkbox;
mod collapse;
pub mod container;
mod custom;
mod data;
@ -27,6 +28,7 @@ pub use align::Align;
pub use button::Button;
pub use canvas::Canvas;
pub use checkbox::Checkbox;
pub use collapse::Collapse;
pub use container::Container;
pub use custom::Custom;
pub use data::Data;

113
src/widgets/collapse.rs Normal file
View file

@ -0,0 +1,113 @@
use std::time::Duration;
use kludgine::figures::units::Px;
use kludgine::figures::Size;
use crate::animation::easings::{EaseInQuadradic, EaseOutQuadradic};
use crate::animation::{AnimationHandle, AnimationTarget, EasingFunction, Spawn};
use crate::context::LayoutContext;
use crate::value::{Dynamic, IntoDynamic};
use crate::widget::{MakeWidget, WidgetRef, WrappedLayout, WrapperWidget};
use crate::ConstraintLimit;
/// A widget that collapses/hides its contents based on a [`Dynamic<bool>`].
#[derive(Debug)]
pub struct Collapse {
child: WidgetRef,
collapse: Dynamic<bool>,
size: Dynamic<Px>,
collapse_animation: Option<CollapseAnimation>,
vertical: bool,
}
impl Collapse {
/// Returns a widget that collapses `child` vertically based on the dynamic
/// boolean value.
///
/// This widget will be collapsed when the dynamic contains `true`, and
/// revealed when the dynamic contains `false`.
pub fn vertical(collapse_when: impl IntoDynamic<bool>, child: impl MakeWidget) -> Self {
Self {
collapse: collapse_when.into_dynamic(),
child: WidgetRef::new(child),
size: Dynamic::default(),
vertical: true,
collapse_animation: None,
}
}
/// Returns a widget that collapses `child` horizontally based on the
/// dynamic boolean value.
///
/// This widget will be collapsed when the dynamic contains `true`, and
/// revealed when the dynamic contains `false`.
pub fn horizontal(collapse_when: impl IntoDynamic<bool>, child: impl MakeWidget) -> Self {
Self {
collapse: collapse_when.into_dynamic(),
child: WidgetRef::new(child),
size: Dynamic::default(),
vertical: false,
collapse_animation: None,
}
}
fn note_child_size(&mut self, size: Px, context: &mut LayoutContext<'_, '_, '_, '_, '_>) {
let (easing, target) = if self.collapse.get_tracking_invalidate(context) {
(EasingFunction::from(EaseOutQuadradic), Px::ZERO)
} else {
(EasingFunction::from(EaseInQuadradic), size)
};
match &self.collapse_animation {
Some(state) if state.target == target => {}
_ => {
// If this is our first setup, immediately give the child the
// space they request.
let duration = if self.collapse_animation.is_some() {
Duration::from_millis(250)
} else {
Duration::ZERO
};
self.collapse_animation = Some(CollapseAnimation {
target,
_handle: self
.size
.transition_to(target)
.over(duration)
.with_easing(easing)
.spawn(),
});
}
}
}
}
impl WrapperWidget for Collapse {
fn child_mut(&mut self) -> &mut WidgetRef {
&mut self.child
}
fn position_child(
&mut self,
size: Size<Px>,
_available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> WrappedLayout {
let clip_size = self.size.get_tracking_invalidate(context);
if self.vertical {
self.note_child_size(size.height, context);
Size::new(size.width, clip_size)
} else {
self.note_child_size(size.width, context);
Size::new(clip_size, size.height)
}
.into()
}
}
#[derive(Debug)]
struct CollapseAnimation {
target: Px,
_handle: AnimationHandle,
}

View file

@ -5,7 +5,7 @@ use std::time::Duration;
use kludgine::figures::Ranged;
use crate::animation::easings::EaseInOutQuadradic;
use crate::animation::easings::{EaseInOutQuadradic, EaseOutQuadradic};
use crate::animation::{
AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne,
};
@ -90,25 +90,25 @@ fn update_progress_bar(
)
.immediately()
.and_then(
end.transition_to(ZeroToOne::new(0.66))
end.transition_to(ZeroToOne::new(0.75))
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
.with_easing(EaseOutQuadradic),
)
.and_then(
start
.transition_to(ZeroToOne::new(0.33))
.transition_to(ZeroToOne::new(0.25))
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
.with_easing(EaseOutQuadradic),
)
.and_then(
end.transition_to(ZeroToOne::ONE)
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
.over(Duration::from_millis(250))
.with_easing(EaseOutQuadradic),
)
.and_then(
start
.transition_to(ZeroToOne::ONE)
.over(Duration::from_millis(500))
.over(Duration::from_millis(250))
.with_easing(EaseInOutQuadradic),
)
.cycle()