Closing animation + in/out anim delays + ScrollMenu was_clicked()

This commit is contained in:
mars 2022-07-10 08:17:53 -06:00
parent cc4f064587
commit 7eb0983ee9
2 changed files with 88 additions and 33 deletions

View File

@ -4,7 +4,8 @@ use keyframe::EasingFunction;
pub struct Animation<F> {
time: f32,
duration: f32,
delay: f32,
in_delay: f32,
out_delay: f32,
from: f32,
to: f32,
function: F,
@ -18,7 +19,8 @@ impl<F: EasingFunction> Animation<F> {
duration,
from,
to,
delay: 0.0,
in_delay: 0.0,
out_delay: 0.0,
function,
direction: false,
}
@ -75,14 +77,20 @@ impl<F: EasingFunction> Animation<F> {
pub fn ease_toggle(&mut self) {
if self.is_active() {
self.time = self.duration - self.time;
} else if self.direction {
self.time = -self.out_delay;
} else {
self.time = -self.delay;
self.time = -self.in_delay;
}
self.direction = !self.direction;
}
pub fn set_delay(&mut self, delay: f32) {
self.delay = delay;
pub fn set_in_delay(&mut self, delay: f32) {
self.in_delay = delay;
}
pub fn set_out_delay(&mut self, delay: f32) {
self.out_delay = delay;
}
}

View File

@ -94,6 +94,8 @@ impl Widget for RoundButton {
pub enum ScrollMenuState {
Opening,
Idle,
Closing,
Closed,
}
pub struct ScrollMenuButton<T> {
@ -107,23 +109,30 @@ pub struct ScrollMenu<T> {
pub spacing: f32,
pub scroll_anim: Animation<EaseInOutQuint>,
pub state: ScrollMenuState,
pub was_clicked: Option<usize>,
}
impl<T> ScrollMenu<T> {
pub fn new(buttons: Vec<T>, spacing: f32) -> Self {
let inter_button_delay = 0.05;
let max_delay = buttons.len() as f32 * inter_button_delay;
let buttons: Vec<_> = buttons
.into_iter()
.enumerate()
.map(|(i, widget)| {
let duration = 0.25;
let delay = i as f32 * 0.05;
let in_delay = i as f32 * inter_button_delay;
let out_delay = max_delay - in_delay;
let mut slide_anim = Animation::new(EaseOut, duration, 0.25, 0.0);
slide_anim.set_delay(delay);
slide_anim.set_in_delay(in_delay);
slide_anim.set_out_delay(out_delay);
slide_anim.ease_in();
let mut opacity_anim = Animation::new(EaseOut, duration, 0.0, 1.0);
opacity_anim.set_delay(delay);
opacity_anim.set_in_delay(in_delay);
opacity_anim.set_out_delay(out_delay);
opacity_anim.ease_in();
ScrollMenuButton {
@ -139,6 +148,24 @@ impl<T> ScrollMenu<T> {
spacing,
scroll_anim: Animation::new(EaseInOutQuint, 0.2, 0.0, 0.0),
state: ScrollMenuState::Opening,
was_clicked: None,
}
}
pub fn was_clicked(&self) -> Option<usize> {
self.was_clicked
}
pub fn scroll_to(&mut self, button_id: usize) {
self.scroll_anim.ease_to(button_id as f32);
}
pub fn close(&mut self) {
self.state = ScrollMenuState::Closing;
for button in self.buttons.iter_mut() {
button.slide_anim.ease_out();
button.opacity_anim.ease_out();
}
}
@ -148,48 +175,54 @@ impl<T> ScrollMenu<T> {
cb(button, i, y);
}
}
fn animate_buttons(&mut self, dt: f32) -> bool {
let mut all_slid = true;
self.for_buttons(|button, _i, _y| {
button.slide_anim.update(dt);
button.opacity_anim.update(dt);
if button.slide_anim.is_active() {
all_slid = false;
}
});
all_slid
}
}
impl<T: Widget + Button> Widget for ScrollMenu<T> {
fn update(&mut self, dt: f32) {
self.was_clicked = None;
match self.state {
ScrollMenuState::Idle => {
self.scroll_anim.update(dt);
let mut scroll_to = None;
self.for_buttons(|button, i, _y| {
if button.widget.was_clicked() {
scroll_to = Some(i);
}
self.for_buttons(|button, _i, _y| {
button.widget.update(dt);
});
if let Some(to) = scroll_to {
self.scroll_anim.ease_to(to as f32);
}
}
ScrollMenuState::Opening => {
let mut all_slid = true;
self.for_buttons(|button, _i, _y| {
button.slide_anim.update(dt);
button.opacity_anim.update(dt);
if button.slide_anim.is_active() {
all_slid = false;
}
});
if all_slid {
if self.animate_buttons(dt) {
self.state = ScrollMenuState::Idle;
}
}
ScrollMenuState::Closing => {
if self.animate_buttons(dt) {
self.state = ScrollMenuState::Closed;
}
}
ScrollMenuState::Closed => {}
}
}
fn draw(&mut self, ctx: &DrawContext) {
if self.state == ScrollMenuState::Closed {
return;
}
ctx.draw_triangle(
Vec2::new(self.spacing, 0.0),
Vec2::new(self.spacing + 0.05, 0.05),
@ -221,10 +254,18 @@ impl<T: Widget + Button> Widget for ScrollMenu<T> {
return;
}
self.for_buttons(|button, _i, y| {
let mut was_clicked = None;
self.for_buttons(|button, i, y| {
let at = at - Vec2::new(0.0, y);
button.widget.on_cursor_event(kind, at);
})
if button.widget.was_clicked() {
was_clicked = Some(i);
}
});
self.was_clicked = was_clicked;
}
}
@ -248,6 +289,12 @@ impl Default for MainMenu {
impl Widget for MainMenu {
fn update(&mut self, dt: f32) {
match self.menu.was_clicked() {
None => {},
Some(0) => self.menu.close(),
Some(button) => self.menu.scroll_to(button),
};
self.menu.update(dt);
}