canary-rs/scripts/sao-ui/src/main_menu.rs

314 lines
8.6 KiB
Rust

// Copyright (c) 2022 Marceline Cramer
// SPDX-License-Identifier: AGPL-3.0-or-later
use crate::widgets::prelude::*;
use crate::{DrawContext, Rect};
use button::{RectButton, RoundButton, RoundButtonStyle};
use dialog::{Dialog, DialogInfo, DialogResponse, DialogStyle};
use menu::{SlotMenu, SlotMenuEvent, TabMenu};
use palette::Palette;
use shell::{Offset, OffsetAlignment, Popup, Reveal};
use text::LabelText;
pub struct MainMenuPanel {
panel: Panel,
menu: MainMenu,
}
impl PanelImpl for MainMenuPanel {
fn update(&mut self, dt: f32) {
Widget::update(&mut self.menu, dt);
}
fn draw(&mut self) {
let ctx = DrawContext::new(self.panel);
Widget::draw(&mut self.menu, &ctx);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
Widget::on_cursor_event(&mut self.menu, kind, at.into());
}
fn on_resize(&mut self, _size: Vec2) {}
fn on_message(&mut self, msg: Message) {}
}
impl MainMenuPanel {
pub fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl> {
Box::new(Self {
panel,
menu: MainMenu::default(),
})
}
}
pub struct MainMenu {
pub menu: Offset<SlotMenu<RoundButton>>,
pub player_info: Reveal<Offset<PlayerInfo>>,
pub inventory: Reveal<Offset<TabMenu>>,
pub palette: Reveal<Offset<Palette>>,
pub settings: Reveal<Offset<SettingsMenu>>,
}
impl MainMenu {
pub const ANCHOR: Vec2 = Vec2::new(100.0, 100.0);
pub const SUBMENU_SPACING: f32 = 15.0;
}
impl Default for MainMenu {
fn default() -> Self {
let icon_font = Font::new(crate::ICON_FONT);
let icons = ["", "", "", "", "", ""];
let button_style = RoundButtonStyle {
radius: 7.5,
spacing: 1.5,
thickness: 0.4,
body_color: THEME.palette.surface,
ring_color: THEME.palette.surface,
icon_color: THEME.palette.text,
};
let mut buttons = Vec::new();
for icon in icons {
let text = LabelText {
font: icon_font,
text: icon.to_string(),
};
let button = RoundButton::new(button_style.clone(), Some(text));
buttons.push(button);
}
let menu = SlotMenu::new(buttons, 30.0);
let menu = Offset::new(menu, Self::ANCHOR);
let submenu_spacing = Vec2::new(Self::SUBMENU_SPACING, 0.0);
let submenu_spacing_left = Self::ANCHOR - submenu_spacing;
let submenu_spacing_right = Self::ANCHOR + submenu_spacing;
let reveal_slide = -5.0;
let reveal_duration = 0.1;
let player_info = PlayerInfo::new();
let player_info = Offset::new_aligned(
player_info,
submenu_spacing_left,
OffsetAlignment::End,
OffsetAlignment::Center,
);
let player_info = Reveal::new(player_info, -reveal_slide, reveal_duration);
let inventory = TabMenu::new();
let inventory = Offset::new(inventory, submenu_spacing_right);
let inventory = Reveal::new(inventory, reveal_slide, reveal_duration);
let palette = Palette::new(Default::default());
let palette = Offset::new_aligned(
palette,
submenu_spacing_left,
OffsetAlignment::End,
OffsetAlignment::Center,
);
let palette = Reveal::new(palette, -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,
player_info,
inventory,
palette,
settings,
}
}
}
impl Container for MainMenu {
fn with_children(&mut self, mut f: impl FnMut(&mut dyn Widget)) {
f(&mut self.menu);
f(&mut self.player_info);
f(&mut self.inventory);
f(&mut self.palette);
f(&mut self.settings);
}
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.player_info.show();
self.inventory.show();
}
SlotMenuEvent::SubmenuClose(0) => {
self.player_info.hide();
self.inventory.hide();
}
SlotMenuEvent::SubmenuOpen(4) => {
self.palette.show();
self.settings.show();
}
SlotMenuEvent::SubmenuClose(4) => {
self.palette.hide();
self.settings.hide();
}
_ => {}
};
}
}
pub struct PlayerInfo {
width: f32,
height: f32,
rounding: f32,
color: Color,
}
impl PlayerInfo {
pub fn new() -> Self {
Self {
width: 70.0,
height: 120.0,
rounding: 5.0,
color: THEME.palette.surface,
}
}
}
impl RectBounds for PlayerInfo {
fn get_bounds(&self) -> Rect {
Rect::from_xy_size(Vec2::ZERO, Vec2::new(self.width, self.height))
}
}
impl Widget for PlayerInfo {
fn draw(&mut self, ctx: &DrawContext) {
ctx.draw_rounded_rect(self.get_bounds(), self.rounding, self.color);
}
}
pub struct Inventory {
width: f32,
height: f32,
}
impl Inventory {
pub fn new(available_width: f32) -> (Self, f32) {
let height = 1024.0;
(
Self {
width: available_width,
height,
},
height,
)
}
}
impl Widget for Inventory {
fn draw(&mut self, ctx: &DrawContext) {
let box_size = 12.0;
let box_margin = 4.0;
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 {
menu: SlotMenu<RectButton>,
log_out_dialog: Option<Popup<Dialog>>,
}
impl SettingsMenu {
pub fn new() -> Self {
let icon_font = Font::new(crate::ICON_FONT);
let label_font = Font::new(crate::DISPLAY_FONT);
let button_texts = [
("Graphics", ""),
("Sound", ""),
("Interface", ""),
("Network", ""),
("Account", ""),
("Log Out", ""),
];
let button_size = Vec2::new(90.0, 20.0);
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, 25.0);
Self {
menu,
log_out_dialog: None,
}
}
}
impl Container for SettingsMenu {
fn with_children(&mut self, mut f: impl FnMut(&mut dyn Widget)) {
f(&mut self.menu);
f(&mut self.log_out_dialog);
}
fn update(&mut self, _dt: f32) {
if let Some(button) = self.menu.get_was_clicked() {
self.menu.select(button);
}
match self.menu.get_event() {
SlotMenuEvent::SubmenuOpen(5) => {
let style = DialogStyle::default();
let info = DialogInfo {
title: "ha jk".to_string(),
content: "lmao u wish".to_string(),
responses: [DialogResponse::Yes, DialogResponse::No].to_vec(),
};
let dialog = Dialog::new(style, &info);
let dialog = Popup::new(dialog, Vec2::ZERO);
let _ = self.log_out_dialog.insert(dialog);
}
_ => {}
};
}
}