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 Widget for Option { 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, pub inventory: Reveal>, pub settings: Reveal>, } impl MainMenu { pub const SUBMENU_SPACING: f32 = 0.1; } impl Default for MainMenu { fn default() -> Self { let icon_font = Font::new("Leon Sans"); 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, } impl SettingsMenu { pub fn new() -> Self { let 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 text in button_texts.iter() { let text = LabelText { font, text: text.to_string(), }; let style = Default::default(); let button = RectButton::new(style, Some(text), button_rect); 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); } }