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

235 lines
6.2 KiB
Rust

use crate::anim::Animation;
use crate::{Color, CursorEventKind, Vec2};
use canary_script::draw::{CornerFlags, DrawContext, Rect};
use canary_script::{Font, TextLayout};
use keyframe::functions::*;
pub mod button;
pub mod menu;
pub mod scroll;
pub mod shell;
pub mod text;
use button::{Button, RectButton, RectButtonStyle, RoundButton};
use menu::{SlotMenu, SlotMenuEvent, TabMenu};
use scroll::{ScrollBar, ScrollView};
use shell::{Offset, Reveal};
use text::{HorizontalAlignment, Label, LabelText};
#[allow(unused)]
pub trait Widget {
fn update(&mut self, dt: f32) {}
fn draw(&mut self, ctx: &DrawContext) {}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {}
}
impl<T: Widget> Widget for Option<T> {
fn update(&mut self, dt: f32) {
if let Some(inner) = self.as_mut() {
inner.update(dt);
}
}
fn draw(&mut self, ctx: &DrawContext) {
if let Some(inner) = self.as_mut() {
inner.draw(ctx);
}
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
if let Some(inner) = self.as_mut() {
inner.on_cursor_event(kind, at);
}
}
}
pub trait FixedWidth {
fn get_width(&self) -> f32;
}
pub struct MainMenu {
pub menu: SlotMenu<RoundButton>,
pub inventory: Reveal<Offset<TabMenu>>,
pub settings: Reveal<Offset<SettingsMenu>>,
}
impl MainMenu {
pub const SUBMENU_SPACING: f32 = 0.1;
}
impl Default for MainMenu {
fn default() -> Self {
let icon_font = Font::new("Iosevka Nerd Font");
let icons = ["", "", "", "", "", ""];
let mut buttons = Vec::new();
for icon in icons {
let text = LabelText {
font: icon_font,
text: icon.to_string(),
};
let button = RoundButton::new(Some(text));
buttons.push(button);
}
let submenu_spacing_right = Vec2::new(Self::SUBMENU_SPACING, 0.0);
let reveal_slide = -0.02;
let reveal_duration = 0.1;
let inventory = TabMenu::new();
let inventory = Offset::new(inventory, submenu_spacing_right);
let inventory = Reveal::new(inventory, reveal_slide, reveal_duration);
let settings = SettingsMenu::new();
let settings = Offset::new(settings, submenu_spacing_right);
let settings = Reveal::new(settings, reveal_slide, reveal_duration);
Self {
menu: SlotMenu::new(buttons, 0.18),
inventory,
settings,
}
}
}
impl Widget for MainMenu {
fn update(&mut self, dt: f32) {
match self.menu.get_was_clicked() {
None => {}
Some(5) => self.menu.close(),
Some(button) => self.menu.select(button),
};
match self.menu.get_event() {
SlotMenuEvent::SubmenuOpen(0) => self.inventory.show(),
SlotMenuEvent::SubmenuClose(0) => self.inventory.hide(),
SlotMenuEvent::SubmenuOpen(4) => self.settings.show(),
SlotMenuEvent::SubmenuClose(4) => self.settings.hide(),
_ => {}
};
self.menu.update(dt);
self.inventory.update(dt);
self.settings.update(dt);
}
fn draw(&mut self, ctx: &DrawContext) {
self.menu.draw(&ctx);
self.inventory.draw(&ctx);
self.settings.draw(&ctx);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
self.menu.on_cursor_event(kind, at);
self.inventory.on_cursor_event(kind, at);
self.settings.on_cursor_event(kind, at);
}
}
pub struct Inventory {
width: f32,
height: f32,
}
impl Inventory {
pub fn new(available_width: f32) -> (Self, f32) {
let height = 1.28;
(
Self {
width: available_width,
height,
},
height,
)
}
}
impl Widget for Inventory {
fn draw(&mut self, ctx: &DrawContext) {
let box_size = 0.06;
let box_margin = 0.02;
let box_stride = box_size + box_margin;
let grid_width = (self.width / box_stride).floor() as usize;
let grid_height = (self.height / box_stride).floor() as usize;
let grid_offset = Vec2::new(box_margin, box_margin) / 2.0;
for x in 0..grid_width {
for y in 0..grid_height {
let off = Vec2::new(x as f32, y as f32) * box_stride + grid_offset;
let rect = Rect::from_xy_size(off, Vec2::new(box_size, box_size));
let color = Color::MAGENTA;
ctx.draw_rect(rect, color);
}
}
}
}
pub struct SettingsMenu {
pub menu: SlotMenu<RectButton>,
}
impl SettingsMenu {
pub fn new() -> Self {
let icon_font = Font::new("Iosevka Nerd Font");
let label_font = Font::new("Leon Sans");
let button_texts = [
("Graphics", ""),
("Sound", ""),
("Interface", ""),
("Network", ""),
("Account", ""),
];
let button_size = Vec2::new(0.4, 0.1);
let button_rect = Rect::from_xy_size(Vec2::new(0.0, -button_size.y / 2.0), button_size);
let mut buttons = Vec::new();
for (label, icon) in button_texts.iter() {
let label = LabelText {
font: label_font,
text: label.to_string(),
};
let icon = LabelText {
font: icon_font,
text: icon.to_string(),
};
let style = Default::default();
let button = RectButton::new(style, button_rect, Some(label), Some(icon));
buttons.push(button);
}
let menu = SlotMenu::new(buttons, 0.12);
Self { menu }
}
}
impl Widget for SettingsMenu {
fn update(&mut self, dt: f32) {
if let Some(button) = self.menu.get_was_clicked() {
self.menu.select(button);
}
match self.menu.get_event() {
_ => {}
};
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);
}
}