Add ScrollMenu

This commit is contained in:
mars 2022-07-09 18:24:57 -06:00
parent a962886de2
commit cc4f064587
1 changed files with 133 additions and 33 deletions

View File

@ -9,6 +9,10 @@ pub trait Widget {
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2);
}
pub trait Button {
fn was_clicked(&self) -> bool;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ButtonState {
Idle,
@ -41,8 +45,8 @@ impl Default for RoundButton {
}
}
impl RoundButton {
pub fn was_clicked(&self) -> bool {
impl Button for RoundButton {
fn was_clicked(&self) -> bool {
self.was_clicked
}
}
@ -74,62 +78,114 @@ impl Widget for RoundButton {
self.state = ButtonState::Clicked;
}
}
CursorEventKind::Deselect => if self.state == ButtonState::Clicked {
self.shrink_anim.ease_out();
self.was_clicked = true;
self.state = ButtonState::Idle;
CursorEventKind::Deselect => {
if self.state == ButtonState::Clicked {
self.shrink_anim.ease_out();
self.was_clicked = true;
self.state = ButtonState::Idle;
}
}
_ => {}
}
}
}
pub struct MainMenu {
pub buttons: Vec<RoundButton>,
pub spacing: f32,
pub scroll_anim: Animation<EaseInOutQuint>,
#[derive(Eq, PartialEq)]
pub enum ScrollMenuState {
Opening,
Idle,
}
impl Default for MainMenu {
fn default() -> Self {
let mut buttons = Vec::new();
for _ in 0..5 {
buttons.push(RoundButton::default());
}
pub struct ScrollMenuButton<T> {
pub widget: T,
pub slide_anim: Animation<EaseOut>,
pub opacity_anim: Animation<EaseOut>,
}
pub struct ScrollMenu<T> {
pub buttons: Vec<ScrollMenuButton<T>>,
pub spacing: f32,
pub scroll_anim: Animation<EaseInOutQuint>,
pub state: ScrollMenuState,
}
impl<T> ScrollMenu<T> {
pub fn new(buttons: Vec<T>, spacing: f32) -> Self {
let buttons: Vec<_> = buttons
.into_iter()
.enumerate()
.map(|(i, widget)| {
let duration = 0.25;
let delay = i as f32 * 0.05;
let mut slide_anim = Animation::new(EaseOut, duration, 0.25, 0.0);
slide_anim.set_delay(delay);
slide_anim.ease_in();
let mut opacity_anim = Animation::new(EaseOut, duration, 0.0, 1.0);
opacity_anim.set_delay(delay);
opacity_anim.ease_in();
ScrollMenuButton {
widget,
slide_anim,
opacity_anim,
}
})
.collect();
Self {
buttons,
spacing: 0.2,
spacing,
scroll_anim: Animation::new(EaseInOutQuint, 0.2, 0.0, 0.0),
state: ScrollMenuState::Opening,
}
}
}
impl MainMenu {
pub fn for_buttons(&mut self, mut cb: impl FnMut(&mut RoundButton, usize, f32)) {
pub fn for_buttons(&mut self, mut cb: impl FnMut(&mut ScrollMenuButton<T>, usize, f32)) {
for (i, button) in self.buttons.iter_mut().enumerate() {
let y = (i as f32 - self.scroll_anim.get()) * self.spacing;
let y = (i as f32 - self.scroll_anim.get()) * self.spacing + button.slide_anim.get();
cb(button, i, y);
}
}
}
impl Widget for MainMenu {
impl<T: Widget + Button> Widget for ScrollMenu<T> {
fn update(&mut self, dt: f32) {
self.scroll_anim.update(dt);
match self.state {
ScrollMenuState::Idle => {
self.scroll_anim.update(dt);
let mut scroll_to = None;
let mut scroll_to = None;
self.for_buttons(|button, i, _y| {
if button.was_clicked() {
scroll_to = Some(i);
self.for_buttons(|button, i, _y| {
if button.widget.was_clicked() {
scroll_to = Some(i);
}
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;
button.update(dt);
});
self.for_buttons(|button, _i, _y| {
button.slide_anim.update(dt);
button.opacity_anim.update(dt);
if let Some(to) = scroll_to {
self.scroll_anim.ease_to(to as f32);
if button.slide_anim.is_active() {
all_slid = false;
}
});
if all_slid {
self.state = ScrollMenuState::Idle;
}
}
}
}
@ -148,14 +204,58 @@ impl Widget for MainMenu {
self.for_buttons(|button, _i, y| {
let ctx = ctx.with_offset(Vec2::new(0.0, y));
button.draw(&ctx);
let opacity = button.opacity_anim.get();
let ctx = if opacity != 1.0 {
ctx.with_opacity(opacity)
} else {
ctx
};
button.widget.draw(&ctx);
})
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
if self.state != ScrollMenuState::Idle {
return;
}
self.for_buttons(|button, _i, y| {
let at = at - Vec2::new(0.0, y);
button.on_cursor_event(kind, at);
button.widget.on_cursor_event(kind, at);
})
}
}
pub struct MainMenu {
pub menu: ScrollMenu<RoundButton>,
}
impl Default for MainMenu {
fn default() -> Self {
let mut buttons = Vec::new();
for _ in 0..5 {
let button = RoundButton::default();
buttons.push(button);
}
Self {
menu: ScrollMenu::new(buttons, 0.2),
}
}
}
impl Widget for MainMenu {
fn update(&mut self, dt: f32) {
self.menu.update(dt);
}
fn draw(&mut self, ctx: &DrawContext) {
self.menu.draw(&ctx);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
self.menu.on_cursor_event(kind, at);
}
}