205 lines
4.7 KiB
Rust
205 lines
4.7 KiB
Rust
// Copyright (c) 2022 Marceline Cramer
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
use super::prelude::*;
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
macro_rules! impl_shell_inner {
|
|
($shell:ident) => {
|
|
impl<T> Deref for $shell<T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &T {
|
|
&self.inner
|
|
}
|
|
}
|
|
|
|
impl<T> DerefMut for $shell<T> {
|
|
fn deref_mut(&mut self) -> &mut T {
|
|
&mut self.inner
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
pub struct Reveal<T> {
|
|
inner: T,
|
|
slide_anim: Animation<EaseIn>,
|
|
opacity_anim: Animation<Linear, u8>,
|
|
state: bool,
|
|
}
|
|
|
|
impl_shell_inner!(Reveal);
|
|
|
|
impl<T: Widget> Reveal<T> {
|
|
pub fn new(inner: T, slide: f32, duration: f32) -> Self {
|
|
Self {
|
|
inner,
|
|
slide_anim: Animation::new(EaseIn, duration, slide, 0.0),
|
|
opacity_anim: Animation::new(Linear, duration, 0, 0xff),
|
|
state: false,
|
|
}
|
|
}
|
|
|
|
pub fn get_offset(&self) -> Vec2 {
|
|
Vec2::new(self.slide_anim.get(), 0.0)
|
|
}
|
|
|
|
pub fn show(&mut self) {
|
|
self.state = true;
|
|
self.slide_anim.ease_in();
|
|
self.opacity_anim.ease_in();
|
|
}
|
|
|
|
pub fn hide(&mut self) {
|
|
self.state = false;
|
|
self.slide_anim.ease_out();
|
|
self.opacity_anim.ease_out();
|
|
}
|
|
}
|
|
|
|
impl<T: Widget> Widget for Reveal<T> {
|
|
fn update(&mut self, dt: f32) {
|
|
self.slide_anim.update(dt);
|
|
self.opacity_anim.update(dt);
|
|
self.inner.update(dt);
|
|
}
|
|
|
|
fn draw(&mut self, ctx: &DrawContext) {
|
|
let ctx = ctx.with_offset(Vec2::new(self.slide_anim.get(), 0.0));
|
|
let ctx = if self.opacity_anim.is_active() {
|
|
ctx.with_opacity(self.opacity_anim.get())
|
|
} else if self.state {
|
|
ctx
|
|
} else {
|
|
return;
|
|
};
|
|
|
|
self.inner.draw(&ctx);
|
|
}
|
|
|
|
fn on_cursor_event(&mut self, kind: CursorEventKind, mut at: Vec2) {
|
|
if !self.state || self.opacity_anim.is_active() {
|
|
return;
|
|
}
|
|
|
|
at -= Vec2::new(self.slide_anim.get(), 0.0);
|
|
self.inner.on_cursor_event(kind, at);
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub enum OffsetAlignment {
|
|
Start,
|
|
End,
|
|
Center,
|
|
Anchor,
|
|
}
|
|
|
|
impl OffsetAlignment {
|
|
pub fn align(&self, start: f32, end: f32) -> f32 {
|
|
match self {
|
|
OffsetAlignment::Start => start,
|
|
OffsetAlignment::End => end,
|
|
OffsetAlignment::Center => (start + end) / 2.0,
|
|
OffsetAlignment::Anchor => 0.0,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Offset<T> {
|
|
inner: T,
|
|
offset: Vec2,
|
|
}
|
|
|
|
impl_shell_inner!(Offset);
|
|
|
|
impl<T> Offset<T> {
|
|
pub fn new(inner: T, offset: Vec2) -> Self {
|
|
Self { inner, offset }
|
|
}
|
|
|
|
pub fn set_offset(&mut self, offset: Vec2) {
|
|
self.offset = offset;
|
|
}
|
|
}
|
|
|
|
impl<T: RectBounds> Offset<T> {
|
|
pub fn new_aligned(
|
|
inner: T,
|
|
anchor: Vec2,
|
|
hori_align: OffsetAlignment,
|
|
vert_align: OffsetAlignment,
|
|
) -> Self {
|
|
let bounds = inner.get_bounds();
|
|
let x = hori_align.align(bounds.tl.x, bounds.br.x);
|
|
let y = vert_align.align(bounds.br.y, bounds.tl.y);
|
|
let offset = anchor - Vec2::new(x, y);
|
|
Self { inner, offset }
|
|
}
|
|
}
|
|
|
|
impl<T: Widget> Widget for Offset<T> {
|
|
fn update(&mut self, dt: f32) {
|
|
self.inner.update(dt);
|
|
}
|
|
|
|
fn draw(&mut self, ctx: &DrawContext) {
|
|
let ctx = ctx.with_offset(self.offset);
|
|
self.inner.draw(&ctx);
|
|
}
|
|
|
|
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
|
|
let at = at - self.offset;
|
|
self.inner.on_cursor_event(kind, at);
|
|
}
|
|
}
|
|
|
|
pub struct Popup<T> {
|
|
inner: T,
|
|
offset: Vec2,
|
|
}
|
|
|
|
impl_shell_inner!(Popup);
|
|
|
|
impl<T> Popup<T> {
|
|
pub fn new(inner: T, offset: Vec2) -> Self {
|
|
Self { inner, offset }
|
|
}
|
|
|
|
pub fn set_offset(&mut self, offset: Vec2) {
|
|
self.offset = offset;
|
|
}
|
|
}
|
|
|
|
impl<T: RectBounds> Popup<T> {
|
|
pub fn new_aligned(
|
|
inner: T,
|
|
anchor: Vec2,
|
|
hori_align: OffsetAlignment,
|
|
vert_align: OffsetAlignment,
|
|
) -> Self {
|
|
let bounds = inner.get_bounds();
|
|
let x = hori_align.align(bounds.tl.x, bounds.br.x);
|
|
let y = vert_align.align(bounds.br.y, bounds.tl.y);
|
|
let offset = anchor - Vec2::new(x, y);
|
|
Self { inner, offset }
|
|
}
|
|
}
|
|
|
|
impl<T: Widget> Widget for Popup<T> {
|
|
fn update(&mut self, dt: f32) {
|
|
self.inner.update(dt);
|
|
}
|
|
|
|
fn draw(&mut self, ctx: &DrawContext) {
|
|
let ctx = ctx.child_at(self.offset);
|
|
self.inner.draw(&ctx);
|
|
}
|
|
|
|
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
|
|
let at = at - self.offset;
|
|
self.inner.on_cursor_event(kind, at);
|
|
}
|
|
}
|