mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-20 08:54:15 +00:00
Web Menu Improvements (#214)
* Add workflow_dispatch * Fix menu items that are too wide * Add logic to goBackHook() to only exit if all submenus are closed, and otherwise to close the submenus * Display question icons * Complete into_string() for Action, Delay, and BoolFlag structs * Update into_string() for Direction, Shield, OnOff, Action, Delay, BoolFlag, and SdiStrength to address compiler warnings * Fix menu items that are too wide * Add logic to goBackHook() to only exit if all submenus are closed, and otherwise to close the submenus * Display question icons * Complete into_string() for Action, Delay, and BoolFlag structs * Update into_string() for Direction, Shield, OnOff, Action, Delay, BoolFlag, and SdiStrength to address compiler warnings * Complete into_string() for LongDelay * Reformat menu.html and fix tag pairs * Add onoff submenu type in HTML * Add onoff submenu type * Add push line to add_sub_menu_onoff * Refactor settings export to use jQuery.param() * Set initial menu settings per URL GET parameters * Add macro to build URL parameter string * Fix bitflag export error * Write menu file when modpack is loaded * Fix OnOff displays * Remove dev files Co-authored-by: asimon-1 <asimon1@protonmail.com>
This commit is contained in:
parent
6b87295216
commit
8757bb9a0e
5 changed files with 630 additions and 312 deletions
|
@ -55,6 +55,21 @@ macro_rules! extra_bitflag_impls {
|
||||||
let all_options = <$e>::all().to_vec();
|
let all_options = <$e>::all().to_vec();
|
||||||
all_options.iter().map(|i| i.bits() as usize).collect()
|
all_options.iter().map(|i| i.bits() as usize).collect()
|
||||||
}
|
}
|
||||||
|
pub fn to_url_param(&self) -> String {
|
||||||
|
let mut vec = self.to_vec();
|
||||||
|
let mut s = String::new();
|
||||||
|
let mut first = true;
|
||||||
|
while !vec.is_empty() {
|
||||||
|
let field = vec.pop().unwrap().bits();
|
||||||
|
if !first {
|
||||||
|
s.push_str(",");
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
s.push_str(&field.to_string());
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +122,7 @@ impl Direction {
|
||||||
Direction::DOWN_IN => 6,
|
Direction::DOWN_IN => 6,
|
||||||
Direction::DOWN => 7,
|
Direction::DOWN => 7,
|
||||||
Direction::DOWN_OUT => 8,
|
Direction::DOWN_OUT => 8,
|
||||||
|
Direction::NEUTRAL => 0,
|
||||||
Direction::LEFT => 5,
|
Direction::LEFT => 5,
|
||||||
Direction::RIGHT => 1,
|
Direction::RIGHT => 1,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
|
@ -123,6 +139,7 @@ impl Direction {
|
||||||
Direction::DOWN_IN => "Down and In",
|
Direction::DOWN_IN => "Down and In",
|
||||||
Direction::DOWN => "Down",
|
Direction::DOWN => "Down",
|
||||||
Direction::DOWN_OUT => "Down and Away",
|
Direction::DOWN_OUT => "Down and Away",
|
||||||
|
Direction::NEUTRAL => "Neutral",
|
||||||
Direction::LEFT => "Left",
|
Direction::LEFT => "Left",
|
||||||
Direction::RIGHT => "Right",
|
Direction::RIGHT => "Right",
|
||||||
_ => "",
|
_ => "",
|
||||||
|
@ -235,7 +252,15 @@ impl Shield {
|
||||||
Shield::Infinite => "Infinite",
|
Shield::Infinite => "Infinite",
|
||||||
Shield::Hold => "Hold",
|
Shield::Hold => "Hold",
|
||||||
Shield::Constant => "Constant",
|
Shield::Constant => "Constant",
|
||||||
_ => "",
|
}.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_url_param(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Shield::None => "0",
|
||||||
|
Shield::Infinite => "1",
|
||||||
|
Shield::Hold => "2",
|
||||||
|
Shield::Constant => "3",
|
||||||
}.to_string()
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +311,13 @@ impl OnOff {
|
||||||
match self {
|
match self {
|
||||||
OnOff::Off => "Off",
|
OnOff::Off => "Off",
|
||||||
OnOff::On => "On",
|
OnOff::On => "On",
|
||||||
_ => ""
|
}.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_url_param(&self) -> String {
|
||||||
|
match self {
|
||||||
|
OnOff::Off => "0",
|
||||||
|
OnOff::On => "1",
|
||||||
}.to_string()
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,8 +366,34 @@ impl Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_string(self) -> String {
|
pub fn into_string(self) -> String {
|
||||||
// TODO: add
|
match self {
|
||||||
return self.to_string()
|
Action::AIR_DODGE => "Airdodge",
|
||||||
|
Action::JUMP => "Jump",
|
||||||
|
Action::SHIELD => "Shield",
|
||||||
|
Action::SPOT_DODGE => "Spotdodge",
|
||||||
|
Action::ROLL_F => "Roll Forwards",
|
||||||
|
Action::ROLL_B => "Roll Backwards",
|
||||||
|
Action::NAIR => "Neutral Aerial",
|
||||||
|
Action::FAIR => "Forward Aerial",
|
||||||
|
Action::BAIR => "Backward Aerial",
|
||||||
|
Action::UAIR => "Up Aerial",
|
||||||
|
Action::DAIR => "Down Aerial",
|
||||||
|
Action::NEUTRAL_B => "Neutral Special",
|
||||||
|
Action::SIDE_B => "Side Special",
|
||||||
|
Action::UP_B => "Up Special",
|
||||||
|
Action::DOWN_B => "Down Special",
|
||||||
|
Action::F_SMASH => "Forward Smash",
|
||||||
|
Action::U_SMASH => "Up Smash",
|
||||||
|
Action::D_SMASH => "Down Smash",
|
||||||
|
Action::JAB => "Jab",
|
||||||
|
Action::F_TILT => "Forward Tilt",
|
||||||
|
Action::U_TILT => "Up Tilt",
|
||||||
|
Action::D_TILT => "Down Tilt",
|
||||||
|
Action::GRAB => "Grab",
|
||||||
|
Action::DASH => "Dash",
|
||||||
|
Action::DASH_ATTACK => "Dash Attack",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,8 +459,40 @@ bitflags! {
|
||||||
|
|
||||||
impl Delay {
|
impl Delay {
|
||||||
pub fn into_string(self) -> String {
|
pub fn into_string(self) -> String {
|
||||||
// TODO: add
|
match self {
|
||||||
return self.to_string()
|
Delay::D0 => "0",
|
||||||
|
Delay::D1 => "1",
|
||||||
|
Delay::D2 => "2",
|
||||||
|
Delay::D3 => "3",
|
||||||
|
Delay::D4 => "4",
|
||||||
|
Delay::D5 => "5",
|
||||||
|
Delay::D6 => "6",
|
||||||
|
Delay::D7 => "7",
|
||||||
|
Delay::D8 => "8",
|
||||||
|
Delay::D9 => "9",
|
||||||
|
Delay::D10 => "10",
|
||||||
|
Delay::D11 => "11",
|
||||||
|
Delay::D12 => "12",
|
||||||
|
Delay::D13 => "13",
|
||||||
|
Delay::D14 => "14",
|
||||||
|
Delay::D15 => "15",
|
||||||
|
Delay::D16 => "16",
|
||||||
|
Delay::D17 => "17",
|
||||||
|
Delay::D18 => "18",
|
||||||
|
Delay::D19 => "19",
|
||||||
|
Delay::D20 => "20",
|
||||||
|
Delay::D21 => "21",
|
||||||
|
Delay::D22 => "22",
|
||||||
|
Delay::D23 => "23",
|
||||||
|
Delay::D24 => "24",
|
||||||
|
Delay::D25 => "25",
|
||||||
|
Delay::D26 => "26",
|
||||||
|
Delay::D27 => "27",
|
||||||
|
Delay::D28 => "28",
|
||||||
|
Delay::D29 => "29",
|
||||||
|
Delay::D30 => "30",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_delay(&self) -> u32 {
|
pub fn into_delay(&self) -> u32 {
|
||||||
|
@ -451,8 +540,40 @@ bitflags! {
|
||||||
|
|
||||||
impl LongDelay {
|
impl LongDelay {
|
||||||
pub fn into_string(self) -> String {
|
pub fn into_string(self) -> String {
|
||||||
// TODO: Is this used for the menu?
|
match self {
|
||||||
return self.to_string()
|
LongDelay::D0 => "0",
|
||||||
|
LongDelay::D10 => "1",
|
||||||
|
LongDelay::D20 => "2",
|
||||||
|
LongDelay::D30 => "3",
|
||||||
|
LongDelay::D40 => "4",
|
||||||
|
LongDelay::D50 => "5",
|
||||||
|
LongDelay::D60 => "6",
|
||||||
|
LongDelay::D70 => "7",
|
||||||
|
LongDelay::D80 => "8",
|
||||||
|
LongDelay::D90 => "9",
|
||||||
|
LongDelay::D100 => "10",
|
||||||
|
LongDelay::D110 => "11",
|
||||||
|
LongDelay::D120 => "12",
|
||||||
|
LongDelay::D130 => "13",
|
||||||
|
LongDelay::D140 => "14",
|
||||||
|
LongDelay::D150 => "15",
|
||||||
|
LongDelay::D160 => "16",
|
||||||
|
LongDelay::D170 => "17",
|
||||||
|
LongDelay::D180 => "18",
|
||||||
|
LongDelay::D190 => "19",
|
||||||
|
LongDelay::D200 => "20",
|
||||||
|
LongDelay::D210 => "21",
|
||||||
|
LongDelay::D220 => "22",
|
||||||
|
LongDelay::D230 => "23",
|
||||||
|
LongDelay::D240 => "24",
|
||||||
|
LongDelay::D250 => "25",
|
||||||
|
LongDelay::D260 => "26",
|
||||||
|
LongDelay::D270 => "27",
|
||||||
|
LongDelay::D280 => "28",
|
||||||
|
LongDelay::D290 => "29",
|
||||||
|
LongDelay::D300 => "30",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_longdelay(&self) -> u32 {
|
pub fn into_longdelay(&self) -> u32 {
|
||||||
|
@ -480,8 +601,10 @@ impl BoolFlag {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_string(self) -> String {
|
pub fn into_string(self) -> String {
|
||||||
// TODO: add
|
match self {
|
||||||
return self.to_string()
|
BoolFlag::TRUE => "True",
|
||||||
|
_ => "False",
|
||||||
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,12 +632,57 @@ impl SdiStrength {
|
||||||
SdiStrength::Normal => "Normal",
|
SdiStrength::Normal => "Normal",
|
||||||
SdiStrength::Medium => "Medium",
|
SdiStrength::Medium => "Medium",
|
||||||
SdiStrength::High => "High",
|
SdiStrength::High => "High",
|
||||||
_ => ""
|
}.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_url_param(&self) -> String {
|
||||||
|
match self {
|
||||||
|
SdiStrength::Normal => "0",
|
||||||
|
SdiStrength::Medium => "1",
|
||||||
|
SdiStrength::High => "2",
|
||||||
}.to_string()
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For input delay
|
||||||
|
trait to_url_param {
|
||||||
|
fn to_url_param(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl to_url_param for i32 {
|
||||||
|
fn to_url_param(&self) -> String {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Macro to build the url parameter string
|
||||||
|
macro_rules! url_params {
|
||||||
|
(
|
||||||
|
pub struct $e:ident {
|
||||||
|
$(pub $field_name:ident: $field_type:ty,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
pub struct $e {
|
||||||
|
$(pub $field_name: $field_type,)*
|
||||||
|
}
|
||||||
|
impl $e {
|
||||||
|
pub fn to_url_params(&self) -> String {
|
||||||
|
let mut s = "?".to_string();
|
||||||
|
$(
|
||||||
|
s.push_str(stringify!($field_name));
|
||||||
|
s.push_str(&"=");
|
||||||
|
s.push_str(&self.$field_name.to_url_param());
|
||||||
|
s.push_str(&"&");
|
||||||
|
)*
|
||||||
|
s.pop();
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
url_params! {
|
||||||
pub struct TrainingModpackMenu {
|
pub struct TrainingModpackMenu {
|
||||||
pub hitbox_vis: OnOff,
|
pub hitbox_vis: OnOff,
|
||||||
pub stage_hazards: OnOff,
|
pub stage_hazards: OnOff,
|
||||||
|
@ -543,6 +711,7 @@ pub struct TrainingModpackMenu {
|
||||||
pub input_delay: i32,
|
pub input_delay: i32,
|
||||||
pub save_damage: OnOff,
|
pub save_damage: OnOff,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! set_by_str {
|
macro_rules! set_by_str {
|
||||||
($obj:ident, $s:ident, $(($field:ident = $rhs:expr))*) => {
|
($obj:ident, $s:ident, $(($field:ident = $rhs:expr))*) => {
|
||||||
|
@ -557,34 +726,30 @@ macro_rules! set_by_str {
|
||||||
impl TrainingModpackMenu {
|
impl TrainingModpackMenu {
|
||||||
pub fn set(&mut self, s: &str, val: u32) {
|
pub fn set(&mut self, s: &str, val: u32) {
|
||||||
set_by_str!(self, s,
|
set_by_str!(self, s,
|
||||||
(di_state = Direction::from_bits(val))
|
(aerial_delay = Delay::from_bits(val))
|
||||||
(sdi_state = Direction::from_bits(val))
|
|
||||||
(shield_tilt = Direction::from_bits(val))
|
|
||||||
(air_dodge_dir = Direction::from_bits(val))
|
(air_dodge_dir = Direction::from_bits(val))
|
||||||
|
(attack_angle = AttackAngle::from_bits(val))
|
||||||
(mash_state = Action::from_bits(val))
|
|
||||||
(follow_up = Action::from_bits(val))
|
|
||||||
|
|
||||||
(ledge_state = LedgeOption::from_bits(val))
|
|
||||||
(ledge_delay = LongDelay::from_bits(val))
|
|
||||||
(tech_state = TechFlags::from_bits(val))
|
|
||||||
(miss_tech_state = MissTechFlags::from_bits(val))
|
|
||||||
|
|
||||||
(shield_state = num::FromPrimitive::from_u32(val))
|
|
||||||
(defensive_state = Defensive::from_bits(val))
|
(defensive_state = Defensive::from_bits(val))
|
||||||
|
(di_state = Direction::from_bits(val))
|
||||||
|
(falling_aerials = BoolFlag::from_bits(val))
|
||||||
|
(fast_fall_delay = Delay::from_bits(val))
|
||||||
|
(fast_fall = BoolFlag::from_bits(val))
|
||||||
|
(follow_up = Action::from_bits(val))
|
||||||
|
(full_hop = BoolFlag::from_bits(val))
|
||||||
|
(hitbox_vis = OnOff::from_val(val))
|
||||||
|
(input_delay = Some(val as i32))
|
||||||
|
(ledge_delay = LongDelay::from_bits(val))
|
||||||
|
(ledge_state = LedgeOption::from_bits(val))
|
||||||
|
(mash_in_neutral = OnOff::from_val(val))
|
||||||
|
(mash_state = Action::from_bits(val))
|
||||||
|
(miss_tech_state = MissTechFlags::from_bits(val))
|
||||||
(oos_offset = Delay::from_bits(val))
|
(oos_offset = Delay::from_bits(val))
|
||||||
(reaction_time = Delay::from_bits(val))
|
(reaction_time = Delay::from_bits(val))
|
||||||
|
(sdi_state = Direction::from_bits(val))
|
||||||
(fast_fall = BoolFlag::from_bits(val))
|
(shield_state = num::FromPrimitive::from_u32(val))
|
||||||
(fast_fall_delay = Delay::from_bits(val))
|
(shield_tilt = Direction::from_bits(val))
|
||||||
(falling_aerials = BoolFlag::from_bits(val))
|
|
||||||
(aerial_delay = Delay::from_bits(val))
|
|
||||||
(full_hop = BoolFlag::from_bits(val))
|
|
||||||
|
|
||||||
(hitbox_vis = OnOff::from_val(val))
|
|
||||||
(stage_hazards = OnOff::from_val(val))
|
(stage_hazards = OnOff::from_val(val))
|
||||||
|
(tech_state = TechFlags::from_bits(val))
|
||||||
(input_delay = Some(val as i32))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
use skyline::info::get_program_id;
|
||||||
use skyline::nn::hid::NpadHandheldState;
|
use skyline::nn::hid::NpadHandheldState;
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
use skyline_web::{Background, BootDisplay, Webpage};
|
use skyline_web::{Background, BootDisplay, Webpage};
|
||||||
use ramhorns::{Template, Content};
|
use ramhorns::{Template, Content};
|
||||||
|
|
||||||
|
@ -34,12 +35,28 @@ impl<'a> Toggle<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct OnOffSelector<'a> {
|
||||||
|
title: &'a str,
|
||||||
|
checked: &'a str
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>OnOffSelector<'a> {
|
||||||
|
pub fn new(title: &'a str, checked: bool) -> OnOffSelector<'a> {
|
||||||
|
OnOffSelector {
|
||||||
|
title: title,
|
||||||
|
checked: if checked { "is-appear "} else { "is-hidden" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Content)]
|
#[derive(Content)]
|
||||||
struct SubMenu<'a> {
|
struct SubMenu<'a> {
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
id: &'a str,
|
id: &'a str,
|
||||||
toggles: Vec<Toggle<'a>>,
|
toggles: Vec<Toggle<'a>>,
|
||||||
sliders: Vec<Slider>,
|
sliders: Vec<Slider>,
|
||||||
|
onoffselector: Vec<OnOffSelector<'a>>,
|
||||||
index: usize,
|
index: usize,
|
||||||
check_against: usize
|
check_against: usize
|
||||||
}
|
}
|
||||||
|
@ -70,6 +87,15 @@ impl<'a> SubMenu<'a> {
|
||||||
value
|
value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_onoffselector(&mut self, title: &'a str, checked: bool) {
|
||||||
|
// TODO: Is there a more elegant way to do this?
|
||||||
|
// The HTML only supports a single onoffselector but the SubMenu stores it as a Vec
|
||||||
|
self.onoffselector.push(OnOffSelector{
|
||||||
|
title: title,
|
||||||
|
checked: if checked { "is-appear "} else { "is-hidden" }
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Content)]
|
#[derive(Content)]
|
||||||
|
@ -92,6 +118,7 @@ impl<'a> Menu<'a> {
|
||||||
id: id,
|
id: id,
|
||||||
toggles: Vec::new(),
|
toggles: Vec::new(),
|
||||||
sliders: Vec::new(),
|
sliders: Vec::new(),
|
||||||
|
onoffselector: Vec::new(),
|
||||||
index: self.max_idx() + 1,
|
index: self.max_idx() + 1,
|
||||||
check_against: check_against
|
check_against: check_against
|
||||||
};
|
};
|
||||||
|
@ -113,6 +140,7 @@ impl<'a> Menu<'a> {
|
||||||
id: id,
|
id: id,
|
||||||
toggles: Vec::new(),
|
toggles: Vec::new(),
|
||||||
sliders: Vec::new(),
|
sliders: Vec::new(),
|
||||||
|
onoffselector: Vec::new(),
|
||||||
index: self.max_idx() + 1,
|
index: self.max_idx() + 1,
|
||||||
check_against: check_against
|
check_against: check_against
|
||||||
};
|
};
|
||||||
|
@ -125,6 +153,21 @@ impl<'a> Menu<'a> {
|
||||||
|
|
||||||
self.sub_menus.push(sub_menu);
|
self.sub_menus.push(sub_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_sub_menu_onoff(&mut self, title: &'a str, id: &'a str, check_against: usize, checked: bool) {
|
||||||
|
let mut sub_menu = SubMenu {
|
||||||
|
title: title,
|
||||||
|
id: id,
|
||||||
|
toggles: Vec::new(),
|
||||||
|
sliders: Vec::new(),
|
||||||
|
onoffselector: Vec::new(),
|
||||||
|
index: self.max_idx() + 1,
|
||||||
|
check_against: check_against
|
||||||
|
};
|
||||||
|
|
||||||
|
sub_menu.add_onoffselector(title, checked);
|
||||||
|
self.sub_menus.push(sub_menu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! add_bitflag_submenu {
|
macro_rules! add_bitflag_submenu {
|
||||||
|
@ -145,13 +188,13 @@ macro_rules! add_bitflag_submenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_menu_from_url(s: &str) {
|
pub fn set_menu_from_url(s: &str) {
|
||||||
let base_url_len = "http://localhost/".len();
|
let base_url_len = "http://localhost/?".len();
|
||||||
let total_len = s.len();
|
let total_len = s.len();
|
||||||
|
|
||||||
let ss: String = s.chars().skip(base_url_len).take(total_len - base_url_len).collect();
|
let ss: String = s.chars().skip(base_url_len).take(total_len - base_url_len).collect();
|
||||||
|
|
||||||
for toggle_values in ss.split("&") {
|
for toggle_values in ss.split("&") {
|
||||||
let toggle_value_split = toggle_values.split("?").collect::<Vec<&str>>();
|
let toggle_value_split = toggle_values.split("=").collect::<Vec<&str>>();
|
||||||
let toggle = toggle_value_split[0];
|
let toggle = toggle_value_split[0];
|
||||||
if toggle == "" { continue; }
|
if toggle == "" { continue; }
|
||||||
|
|
||||||
|
@ -161,7 +204,7 @@ pub fn set_menu_from_url(s: &str) {
|
||||||
for toggle_val in toggle_vals.split(",") {
|
for toggle_val in toggle_vals.split(",") {
|
||||||
if toggle_val == "" { continue; }
|
if toggle_val == "" { continue; }
|
||||||
|
|
||||||
let mut val = toggle_val.parse::<u32>().unwrap();
|
let val = toggle_val.parse::<u32>().unwrap();
|
||||||
bits = bits | val;
|
bits = bits | val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +220,7 @@ pub unsafe fn menu_condition(module_accessor: &mut smash::app::BattleObjectModul
|
||||||
ControlModule::check_button_on_trriger(module_accessor, *CONTROL_PAD_BUTTON_APPEAL_HI)
|
ControlModule::check_button_on_trriger(module_accessor, *CONTROL_PAD_BUTTON_APPEAL_HI)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn render_menu() -> String {
|
pub unsafe fn write_menu() {
|
||||||
let tpl = Template::new(include_str!("../templates/menu.html")).unwrap();
|
let tpl = Template::new(include_str!("../templates/menu.html")).unwrap();
|
||||||
|
|
||||||
let mut overall_menu = Menu {
|
let mut overall_menu = Menu {
|
||||||
|
@ -236,52 +279,50 @@ pub unsafe fn render_menu() -> String {
|
||||||
// SDI strength
|
// SDI strength
|
||||||
|
|
||||||
|
|
||||||
// TODO: OnOff flags... need a different sort of submenu.
|
// OnOff flags
|
||||||
overall_menu.add_sub_menu(
|
overall_menu.add_sub_menu_onoff(
|
||||||
"Hitbox Visualization",
|
"Hitbox Visualization",
|
||||||
"hitbox_vis",
|
"hitbox_vis",
|
||||||
MENU.hitbox_vis as usize,
|
MENU.hitbox_vis as usize,
|
||||||
[
|
(MENU.hitbox_vis as usize & OnOff::On as usize) != 0
|
||||||
("Off", OnOff::Off as usize),
|
|
||||||
("On", OnOff::On as usize),
|
|
||||||
].to_vec(),
|
|
||||||
[].to_vec()
|
|
||||||
);
|
);
|
||||||
overall_menu.add_sub_menu(
|
|
||||||
|
overall_menu.add_sub_menu_onoff(
|
||||||
"Stage Hazards",
|
"Stage Hazards",
|
||||||
"stage_hazards",
|
"stage_hazards",
|
||||||
MENU.stage_hazards as usize,
|
MENU.stage_hazards as usize,
|
||||||
[
|
(MENU.stage_hazards as usize & OnOff::On as usize) != 0
|
||||||
("Off", OnOff::Off as usize),
|
|
||||||
("On", OnOff::On as usize),
|
|
||||||
].to_vec(),
|
|
||||||
[].to_vec()
|
|
||||||
);
|
);
|
||||||
overall_menu.add_sub_menu(
|
overall_menu.add_sub_menu_onoff(
|
||||||
"Mash In Neutral",
|
"Mash In Neutral",
|
||||||
"mash_in_neutral",
|
"mash_in_neutral",
|
||||||
MENU.mash_in_neutral as usize,
|
MENU.mash_in_neutral as usize,
|
||||||
[
|
(MENU.mash_in_neutral as usize & OnOff::On as usize) != 0
|
||||||
("Off", OnOff::Off as usize),
|
|
||||||
("On", OnOff::On as usize),
|
|
||||||
].to_vec(),
|
|
||||||
[].to_vec()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let data = tpl.render(&overall_menu);
|
||||||
|
|
||||||
|
// Now that we have the html, write it to file
|
||||||
tpl.render(&overall_menu)
|
// From skyline-web
|
||||||
|
let program_id = get_program_id();
|
||||||
|
let htdocs_dir = "contents";
|
||||||
|
let path = Path::new("sd:/atmosphere/contents")
|
||||||
|
.join(&format!("{:016X}", program_id))
|
||||||
|
.join(&format!("manual_html/html-document/{}.htdocs/", htdocs_dir))
|
||||||
|
.join("index.html");
|
||||||
|
fs::write(path, data).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn spawn_menu() {
|
pub unsafe fn spawn_menu() {
|
||||||
let data = render_menu();
|
let fname = "index.html";
|
||||||
|
let params = MENU.to_url_params();
|
||||||
|
|
||||||
let response = Webpage::new()
|
let response = Webpage::new()
|
||||||
.background(Background::BlurredScreenshot)
|
.background(Background::BlurredScreenshot)
|
||||||
.file("index.html", &data)
|
|
||||||
.htdocs_dir("contents")
|
.htdocs_dir("contents")
|
||||||
.boot_display(BootDisplay::BlurredScreenshot)
|
.boot_display(BootDisplay::BlurredScreenshot)
|
||||||
.boot_icon(true)
|
.boot_icon(true)
|
||||||
|
.start_page(&format!("{}{}", fname, params))
|
||||||
.open()
|
.open()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
/* Full width for opened lists */
|
/* Full width for opened lists */
|
||||||
.is-opened .question-outer {
|
.is-opened .question-outer {
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overwrite margin on the last child to avoid overlap*/
|
/* Overwrite margin on the last child to avoid overlap*/
|
||||||
|
@ -58,6 +58,17 @@
|
||||||
.l-qa:last-child .qa.is-opened {
|
.l-qa:last-child .qa.is-opened {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fade icons slightly */
|
||||||
|
img.question-icon {
|
||||||
|
opacity: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override excessive question width on focus */
|
||||||
|
.is-focused .question-message span:nth-child(1) {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -71,17 +82,15 @@
|
||||||
|
|
||||||
<div class="l-header">
|
<div class="l-header">
|
||||||
<div class="l-header-title">
|
<div class="l-header-title">
|
||||||
<div class="header-title f-u-bold"><span data-msgcom="true" data-msgid="textbox_id-10020">Ultimate Training
|
<div class="header-title f-u-bold"><span data-msgcom="true" data-msgid="textbox_id-10020">Ultimate
|
||||||
|
Training
|
||||||
Modpack Menu</span></div>
|
Modpack Menu</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<a id="ret-button" tabindex="-1" class="header-decoration" href="javascript:goBackHook();"
|
<a id="ret-button" tabindex="-1" class="header-decoration" href="javascript:goBackHook();" nx-se-disabled="">
|
||||||
nx-se-disabled="">
|
|
||||||
<div class="ret-icon-wrapper">
|
<div class="ret-icon-wrapper">
|
||||||
<img class="ret-icon-shadow is-appear" ref="./help/img/icon/m_retnormal.svg"
|
<img class="ret-icon-shadow is-appear" ref="./help/img/icon/m_retnormal.svg" src="./help/img/icon/m_retnormal.svg">
|
||||||
src="./help/img/icon/m_retnormal.svg">
|
<img class="ret-icon is-appear" ref="./help/img/icon/m_retnormal.svg" src="./help/img/icon/m_retnormal.svg">
|
||||||
<img class="ret-icon is-appear" ref="./help/img/icon/m_retnormal.svg"
|
|
||||||
src="./help/img/icon/m_retnormal.svg">
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -108,13 +117,15 @@
|
||||||
-->
|
-->
|
||||||
{{#sub_menus}}
|
{{#sub_menus}}
|
||||||
<div class="l-qa">
|
<div class="l-qa">
|
||||||
<a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this)"
|
{{^onoffselector}}
|
||||||
onblur="defocusQA(this)" onclick="openAnswer(this)" nx-se-disabled="">
|
<a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this)" onblur="defocusQA(this)" onclick="openAnswer(this)" nx-se-disabled="">
|
||||||
<div class="question-outer">
|
<div class="question-outer">
|
||||||
<div class="question-border">
|
<div class="question-border">
|
||||||
<div id="question-{{id}}" class="question scuffle-thema">
|
<div id="question-{{id}}" class="question scuffle-thema">
|
||||||
<img class="question-icon" ref="./{{id}}.svg" />
|
<img class="question-icon" ref="./{{id}}.svg" src="./{{id}}.svg" />
|
||||||
<p class="question-message f-u-bold"><span data-msgid="textbox_id-7">{{title}}</span></p>
|
<p class="question-message f-u-bold">
|
||||||
|
<span data-msgid="textbox_id-7">{{title}}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -123,57 +134,77 @@
|
||||||
<ul class="l-grid" id="{{id}}">
|
<ul class="l-grid" id="{{id}}">
|
||||||
{{#toggles}}
|
{{#toggles}}
|
||||||
<li class="l-item" val="{{value}}">
|
<li class="l-item" val="{{value}}">
|
||||||
<div class="keyword-button-outer"> <a tabindex="{{index}}"
|
<div class="keyword-button-outer">
|
||||||
class="flex-button keyword-button scuffle-thema" href="javascript:void(0)"
|
<a tabindex="{{index}}" class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);" nx-se-disabled="">
|
||||||
onclick="clickToggle(this);" nx-se-disabled="">
|
<div class="button-icon-wrapper">
|
||||||
<div class="button-icon-wrapper"> <img class="button-icon {{checked}}"
|
<img class="button-icon toggle {{checked}}" ref="./check.svg" src="./check.svg">
|
||||||
ref="./check.svg" src="./check.svg">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="button-msg-wrapper">
|
<div class="button-msg-wrapper">
|
||||||
<div class="keyword-message f-u-bold">{{title}}</div>
|
<div class="keyword-message f-u-bold">
|
||||||
|
{{title}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</a> </div>
|
|
||||||
</li>
|
</li>
|
||||||
{{/toggles}}
|
{{/toggles}}
|
||||||
{{#sliders}}
|
{{#sliders}}
|
||||||
<li class="l-item" val="{{value}}">
|
<li class="l-item" val="{{value}}">
|
||||||
<div class="keyword-button-outer"> <a tabindex="{{index}}"
|
<div class="keyword-button-outer">
|
||||||
class="flex-button keyword-button scuffle-thema" href="javascript:void(0)"
|
<a tabindex="{{index}}" class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);" nx-se-disabled="">
|
||||||
onclick="clickToggle(this);" nx-se-disabled="">
|
<div class="button-icon-wrapper">
|
||||||
<div class="button-icon-wrapper"> <img class="button-icon {{checked}}"
|
<img class="button-icon toggle {{checked}}" ref="./check.svg" src="./check.svg">
|
||||||
ref="./check.svg" src="./check.svg">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="button-msg-wrapper">
|
<div class="button-msg-wrapper">
|
||||||
<div class="keyword-message f-u-bold">
|
<div class="keyword-message f-u-bold">
|
||||||
<div name='range_slider'
|
<div name='range_slider' oninput="this.nextElementSibling.value = this.value">
|
||||||
oninput="this.nextElementSibling.value = this.value">
|
|
||||||
</div>
|
</div>
|
||||||
<output>{{value}}</output>
|
<output>{{value}}</output>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a> </div>
|
</a>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{/sliders}}
|
{{/sliders}}
|
||||||
{{#range_sliders}}
|
{{#range_sliders}}
|
||||||
<li class="l-item" val="{{value}}">
|
<li class="l-item" val="{{value}}">
|
||||||
<div class="keyword-button-outer"> <a tabindex="{{index}}"
|
<div class="keyword-button-outer">
|
||||||
class="flex-button keyword-button scuffle-thema" href="javascript:void(0)"
|
<a tabindex="{{index}}" class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);" nx-se-disabled="">
|
||||||
onclick="clickToggle(this);" nx-se-disabled="">
|
<div class="button-icon-wrapper">
|
||||||
<div class="button-icon-wrapper"> <img class="button-icon {{checked}}"
|
<img class="button-icon toggle {{checked}}" ref="./check.svg" src="./check.svg">
|
||||||
ref="./check.svg" src="./check.svg">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="button-msg-wrapper">
|
<div class="button-msg-wrapper">
|
||||||
<div class="keyword-message f-u-bold">
|
<div class="keyword-message f-u-bold">
|
||||||
<div name="{{id}}">
|
<div name="{{id}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a> </div>
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{/range_sliders}}
|
{{/range_sliders}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
{{/onoffselector}}
|
||||||
|
{{#onoffselector}}
|
||||||
|
<a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this)" onblur="defocusQA(this)" onclick="clickToggle(this)" nx-se-disabled="">
|
||||||
|
<div class="question-outer">
|
||||||
|
<div class="question-border">
|
||||||
|
<div id="question-{{id}}" class="question scuffle-thema">
|
||||||
|
<div id="{{id}}" class="onoff">
|
||||||
|
<img class="question-icon" style="z-index: 1;" ref="./{{id}}.svg" src="./{{id}}.svg" />
|
||||||
|
<div><img class="question-icon toggle {{checked}}" style="z-index: 2;" ref="./check.svg" src="./check.svg" /></div>
|
||||||
|
<p class="keyword-message f-u-bold">
|
||||||
|
{{title}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{/onoffselector}}
|
||||||
</div>
|
</div>
|
||||||
{{/sub_menus}}
|
{{/sub_menus}}
|
||||||
|
|
||||||
|
@ -199,8 +230,10 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function goBackHook() {
|
function goBackHook() {
|
||||||
// Use this function to check menu settings on exit, return through localhost
|
// If any submenus are open, close them
|
||||||
|
// Otherwise if all submenus are closed, exit the menu and return to the game
|
||||||
|
if ($(".qa.is-opened").length == 0) {
|
||||||
|
// If all submenus are closed, exit and return through localhost
|
||||||
$('.is-focused').addClass('is-pause-anim')
|
$('.is-focused').addClass('is-pause-anim')
|
||||||
$('#ret-button').addClass('is-focus')
|
$('#ret-button').addClass('is-focus')
|
||||||
|
|
||||||
|
@ -215,23 +248,47 @@
|
||||||
|
|
||||||
var url = "http://localhost/"
|
var url = "http://localhost/"
|
||||||
|
|
||||||
$(".l-grid").each(function () {
|
var settings = [];
|
||||||
var section = this.id;
|
|
||||||
|
|
||||||
url += section + "?"
|
// Collect settings for toggles
|
||||||
|
$("ul.l-grid").each(function () {
|
||||||
|
var section = this.id;
|
||||||
|
var val = "";
|
||||||
|
|
||||||
var children = this.children;
|
var children = this.children;
|
||||||
for (var i = 0; i < children.length; i++) {
|
for (var i = 0; i < children.length; i++) {
|
||||||
var child = children[i];
|
var child = children[i];
|
||||||
if (child.innerHTML.includes("is-appear")) {
|
if (child.innerHTML.includes("is-appear")) {
|
||||||
url += child.getAttribute("val") + ",";
|
val += child.getAttribute("val") + ",";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url += "&"
|
settings.push({
|
||||||
|
name: section,
|
||||||
|
value: val
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
location.href = url;
|
// Collect settings for OnOffs
|
||||||
|
$("div.onoff").each(function () {
|
||||||
|
var section = this.id;
|
||||||
|
var val = "";
|
||||||
|
if (this.innerHTML.includes("is-appear")) {
|
||||||
|
val = "1"
|
||||||
|
} else {
|
||||||
|
val = "0"
|
||||||
|
}
|
||||||
|
settings.push({
|
||||||
|
name: section,
|
||||||
|
value: val
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
location.href = url + "?" + decodeURIComponent($.param(settings));
|
||||||
|
} else {
|
||||||
|
// Close any open submenus
|
||||||
|
$(".qa.is-opened").each(function () { openAnswer(this); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickToggle(e) {
|
function clickToggle(e) {
|
||||||
|
@ -242,6 +299,57 @@
|
||||||
toggleImage.innerHTML = toggleImage.innerHTML.replace("is-hidden", "is-appear");
|
toggleImage.innerHTML = toggleImage.innerHTML.replace("is-hidden", "is-appear");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParams(url) {
|
||||||
|
var regex = /[?&]([^=#]+)=([^&#]*)/g,
|
||||||
|
params = {},
|
||||||
|
match;
|
||||||
|
while(match = regex.exec(url)) {
|
||||||
|
params[match[1]] = match[2];
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSettings() {
|
||||||
|
// Get settings from the URL GET parameters
|
||||||
|
const settings = getParams(document.URL);
|
||||||
|
|
||||||
|
// Set Toggles
|
||||||
|
$("ul.l-grid").each(function () {
|
||||||
|
var section = this.id;
|
||||||
|
var section_setting = decodeURIComponent(settings[section]);
|
||||||
|
|
||||||
|
var children = $(this).children("li");
|
||||||
|
for (var i = 0; i < children.length; i++) {
|
||||||
|
var child = children[i];
|
||||||
|
var e = $(child).find("img.toggle")[0];
|
||||||
|
if (section_setting.split(",").includes(child.getAttribute("val"))) {
|
||||||
|
e.classList.add("is-appear");
|
||||||
|
e.classList.remove("is-hidden");
|
||||||
|
} else {
|
||||||
|
e.classList.remove("is-appear");
|
||||||
|
e.classList.add("is-hidden");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set OnOffs
|
||||||
|
$("div.onoff").each(function () {
|
||||||
|
var section = this.id;
|
||||||
|
var section_setting = decodeURIComponent(settings[section]);
|
||||||
|
var e = $(this).find("img.toggle")[0];
|
||||||
|
if (section_setting == "1") {
|
||||||
|
e.classList.add("is-appear");
|
||||||
|
e.classList.remove("is-hidden");
|
||||||
|
} else {
|
||||||
|
e.classList.remove("is-appear");
|
||||||
|
e.classList.add("is-hidden");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
window.onload = setSettings;
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,17 @@
|
||||||
|
|
||||||
/// This will run and render the default menu in your default HTML opening program, ideally Chrome.
|
/// This will run and render the default menu in your default HTML opening program, ideally Chrome.
|
||||||
#[test]
|
#[test]
|
||||||
fn render_menu() {
|
fn write_menu() {
|
||||||
unsafe {
|
unsafe {
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use crate::common::menu::render_menu;
|
use crate::common::menu::write_menu;
|
||||||
|
|
||||||
let folder_path = "../contents.htdocs";
|
let folder_path = "../contents.htdocs";
|
||||||
let path = "../contents.htdocs/index.html";
|
let path = "../contents.htdocs/index.html";
|
||||||
|
|
||||||
assert!(std::path::Path::new(folder_path).exists(), "Needs required folder: ../contents.htdocs!");
|
assert!(std::path::Path::new(folder_path).exists(), "Needs required folder: ../contents.htdocs!");
|
||||||
|
|
||||||
std::fs::write(path, render_menu()).unwrap();
|
std::fs::write(path, write_menu()).unwrap();
|
||||||
|
|
||||||
let (cmd, args) = if wsl::is_wsl() || cfg!(target_os = "windows") {
|
let (cmd, args) = if wsl::is_wsl() || cfg!(target_os = "windows") {
|
||||||
("cmd.exe", ["/C", "start", path])
|
("cmd.exe", ["/C", "start", path])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::common::{is_training_mode, FIGHTER_MANAGER_ADDR, STAGE_MANAGER_ADDR};
|
use crate::common::{is_training_mode, menu, FIGHTER_MANAGER_ADDR, STAGE_MANAGER_ADDR};
|
||||||
use crate::hitbox_visualizer;
|
use crate::hitbox_visualizer;
|
||||||
use skyline::nn::ro::LookupSymbol;
|
use skyline::nn::ro::LookupSymbol;
|
||||||
use skyline::nn::hid::*;
|
use skyline::nn::hid::*;
|
||||||
|
@ -387,4 +387,8 @@ pub fn training_mods() {
|
||||||
fast_fall::init();
|
fast_fall::init();
|
||||||
mash::init();
|
mash::init();
|
||||||
ledge::init();
|
ledge::init();
|
||||||
|
|
||||||
|
println!("[Training Modpack] Writing menu file index.html");
|
||||||
|
unsafe { menu::write_menu(); }
|
||||||
|
println!("[Training Modpack] Wrote menu file.");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue