// Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later use super::prelude::*; use text::{HorizontalAlignment, Icon, Label, LabelText}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ButtonState { Idle, Clicking, Clicked, Releasing, } #[derive(Clone, Debug)] pub struct RoundButtonStyle { pub radius: f32, pub spacing: f32, pub thickness: f32, pub body_color: Color, pub ring_color: Color, pub icon_color: Color, } pub struct RoundButton { style: RoundButtonStyle, shrink_anim: Animation, was_clicked: bool, state: ButtonState, icon: Option, } impl RoundButton { pub fn new(style: RoundButtonStyle, icon: Option) -> Self { let icon = icon.map(|text| { let scale = style.radius * 1.5; let center = Vec2::ZERO; let color = style.icon_color; Icon::new(text, scale, color, center) }); Self { style, shrink_anim: Animation::new(EaseOutQuint, 0.1, 1.0, 0.0), was_clicked: false, state: ButtonState::Idle, icon, } } pub fn set_text(&mut self, text: &str) { if let Some(icon) = self.icon.as_mut() { icon.set_text(text); } } } 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 RoundButtonStyle { body_color, ring_color, thickness, radius, spacing, .. } = self.style; let center = Vec2::ZERO; let spacing = self.shrink_anim.get() * spacing; ctx.draw_circle(center, radius, body_color); ctx.draw_ring(center, radius + spacing, thickness, ring_color); self.icon.draw(ctx); } fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) { match kind { CursorEventKind::Select => { if at.length() < self.style.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; } } _ => {} } } } #[derive(Clone, Debug)] pub struct RectButtonStyle { pub rounded_corners: CornerFlags, pub radius: f32, pub label_scale_factor: f32, pub label_baseline: f32, pub icon_scale_factor: f32, pub icon_margin_factor: f32, pub inactive_color: Color, pub hover_color: Color, pub selected_color: Color, pub icon_color: Color, pub label_color: Color, } impl Default for RectButtonStyle { fn default() -> Self { Self { rounded_corners: CornerFlags::empty(), radius: 0.0, label_scale_factor: 0.65, label_baseline: 0.25, icon_scale_factor: 0.8, icon_margin_factor: 1.1, inactive_color: THEME.palette.base, hover_color: THEME.palette.base_hover, selected_color: THEME.palette.base_active, icon_color: THEME.palette.black, label_color: THEME.palette.text, } } } pub struct RectButton { pub style: RectButtonStyle, pub rect: Rect, pub was_clicked: bool, pub is_selected: bool, pub is_hovering: bool, pub color_anim: Animation, pub label: Option