canary-rs/crates/sao-ui-rs/src/widgets/button.rs

200 lines
5.2 KiB
Rust
Raw Normal View History

2022-07-21 21:19:57 +00:00
use super::*;
pub trait Button {
fn was_clicked(&self) -> bool;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ButtonState {
Idle,
Clicking,
Clicked,
Releasing,
}
pub struct RoundButton {
pos: Vec2,
radius: f32,
spacing: f32,
thickness: f32,
shrink_anim: Animation<EaseOutQuint>,
was_clicked: bool,
state: ButtonState,
label: Option<Label>,
}
impl RoundButton {
pub fn new(label: Option<LabelText>) -> Self {
let radius = 0.05;
let label = label.map(|text| {
let scale = radius * 1.5;
let alignment = HorizontalAlignment::Center;
let left = -radius;
let right = radius;
let baseline = 0.0;
let color = Color::BLACK;
let center_y = true;
Label::new(
text, alignment, scale, color, left, right, baseline, center_y,
)
});
Self {
pos: Default::default(),
radius,
spacing: 0.01,
thickness: 0.002,
shrink_anim: Animation::new(EaseOutQuint, 0.1, 1.0, 0.0),
was_clicked: false,
state: ButtonState::Idle,
label,
}
}
}
impl Button for RoundButton {
fn was_clicked(&self) -> bool {
self.was_clicked
}
}
impl Widget for RoundButton {
fn update(&mut self, dt: f32) {
self.shrink_anim.update(dt);
self.was_clicked = false;
}
fn draw(&mut self, ctx: &DrawContext) {
let color = Color {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
};
let spacing = self.shrink_anim.get() * self.spacing;
ctx.draw_circle(self.pos, self.radius, color);
ctx.draw_ring(self.pos, self.radius + spacing, self.thickness, color);
if let Some(label) = self.label.as_mut() {
label.draw(ctx);
}
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
match kind {
CursorEventKind::Select => {
if self.pos.distance(at) < self.radius {
self.shrink_anim.ease_in();
self.state = ButtonState::Clicked;
}
}
CursorEventKind::Deselect => {
if self.state == ButtonState::Clicked {
self.shrink_anim.ease_out();
self.was_clicked = true;
self.state = ButtonState::Idle;
}
}
_ => {}
}
}
}
pub struct RectButton {
pub rect: Rect,
pub rounded_corners: CornerFlags,
pub radius: f32,
pub was_clicked: bool,
pub is_selected: bool,
pub is_hovering: bool,
pub color_anim: Animation<EaseInQuad, Color>,
}
impl Button for RectButton {
fn was_clicked(&self) -> bool {
self.was_clicked
}
}
impl RectButton {
pub const INACTIVE_COLOR: Color = Color::new(1., 1., 1., 0.2);
pub const HOVER_COLOR: Color = Color::new(1., 1., 1., 0.8);
pub const SELECTED_COLOR: Color = Color::new(1., 1., 0., 1.);
pub fn new(rect: Rect, rounded_corners: CornerFlags, radius: f32) -> Self {
Self {
rect,
rounded_corners,
radius,
was_clicked: false,
is_selected: false,
is_hovering: false,
color_anim: Animation::new(
EaseInQuad,
0.05,
Self::INACTIVE_COLOR,
Self::INACTIVE_COLOR,
),
}
}
}
impl Widget for RectButton {
fn update(&mut self, dt: f32) {
self.was_clicked = false;
self.color_anim.update(dt);
}
fn draw(&mut self, ctx: &DrawContext) {
ctx.draw_partially_rounded_rect(
self.rounded_corners,
self.rect,
self.radius,
self.color_anim.get(),
);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
let is_on = self.rect.contains_point(at);
match kind {
CursorEventKind::Hover | CursorEventKind::Drag => {
if is_on {
if !self.is_hovering && !self.is_selected {
self.color_anim.ease_to(Self::HOVER_COLOR);
}
self.is_hovering = true;
} else {
if self.is_hovering && !self.is_selected {
self.color_anim.ease_to(Self::INACTIVE_COLOR);
}
self.is_hovering = false;
}
}
CursorEventKind::Select => {
if is_on {
self.is_selected = true;
self.color_anim.ease_to(Self::SELECTED_COLOR);
}
}
CursorEventKind::Deselect => {
if self.is_selected {
self.was_clicked = true;
self.is_selected = false;
if self.is_hovering {
self.color_anim.ease_to(Self::HOVER_COLOR);
} else {
self.color_anim.ease_to(Self::INACTIVE_COLOR);
}
}
}
}
}
}