mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-28 04:44:06 +00:00
Tabbed Web Menu (#333)
* Web menu refactor * Fix some menu items * Fixes for quick_menu, general clippy fixes * Revert small testing change * Add quick menu SVG * Fix defaults saving/loading * Log the last URL from the web menu Co-authored-by: jugeeya <jugeeya@live.com>
This commit is contained in:
parent
6da6aa41b7
commit
a6bed95de3
11 changed files with 1137 additions and 1466 deletions
|
@ -66,10 +66,10 @@ pub unsafe fn write_menu() {
|
||||||
|
|
||||||
const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.conf";
|
const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.conf";
|
||||||
|
|
||||||
pub fn set_menu_from_url(orig_last_url: &str) {
|
pub fn set_menu_from_url(last_url: &str) {
|
||||||
let last_url = &orig_last_url.replace("&save_defaults=1", "");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MENU = get_menu_from_url(MENU, last_url);
|
MENU = get_menu_from_url(MENU, last_url, false);
|
||||||
|
DEFAULTS_MENU = get_menu_from_url(MENU, last_url, true);
|
||||||
|
|
||||||
if MENU.quick_menu == OnOff::Off {
|
if MENU.quick_menu == OnOff::Off {
|
||||||
if is_emulator() {
|
if is_emulator() {
|
||||||
|
@ -83,17 +83,6 @@ pub fn set_menu_from_url(orig_last_url: &str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if last_url.len() != orig_last_url.len() {
|
|
||||||
// Save as default
|
|
||||||
unsafe {
|
|
||||||
DEFAULT_MENU = MENU;
|
|
||||||
write_menu();
|
|
||||||
}
|
|
||||||
let menu_defaults_conf_path = "sd:/TrainingModpack/training_modpack_menu_defaults.conf";
|
|
||||||
std::fs::write(menu_defaults_conf_path, last_url)
|
|
||||||
.expect("Failed to write default menu conf file");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::write(MENU_CONF_PATH, last_url).expect("Failed to write menu conf file");
|
std::fs::write(MENU_CONF_PATH, last_url).expect("Failed to write menu conf file");
|
||||||
unsafe {
|
unsafe {
|
||||||
EVENT_QUEUE.push(Event::menu_open(last_url.to_string()));
|
EVENT_QUEUE.push(Event::menu_open(last_url.to_string()));
|
||||||
|
@ -115,19 +104,22 @@ pub fn spawn_menu() {
|
||||||
|
|
||||||
if !quick_menu {
|
if !quick_menu {
|
||||||
let fname = "training_menu.html";
|
let fname = "training_menu.html";
|
||||||
let params = unsafe { MENU.to_url_params() };
|
unsafe {
|
||||||
|
let params = MENU.to_url_params(false);
|
||||||
|
let default_params = DEFAULTS_MENU.to_url_params(true);
|
||||||
let page_response = Webpage::new()
|
let page_response = Webpage::new()
|
||||||
.background(Background::BlurredScreenshot)
|
.background(Background::BlurredScreenshot)
|
||||||
.htdocs_dir("training_modpack")
|
.htdocs_dir("training_modpack")
|
||||||
.boot_display(BootDisplay::BlurredScreenshot)
|
.boot_display(BootDisplay::BlurredScreenshot)
|
||||||
.boot_icon(true)
|
.boot_icon(true)
|
||||||
.start_page(&format!("{}{}", fname, params))
|
.start_page(&format!("{}?{}&{}", fname, params, default_params))
|
||||||
.open()
|
.open()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let orig_last_url = page_response.get_last_url().unwrap();
|
let last_url = page_response.get_last_url().unwrap();
|
||||||
|
println!("Received URL from web menu: {}", last_url);
|
||||||
set_menu_from_url(orig_last_url);
|
set_menu_from_url(last_url);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
QUICK_MENU_ACTIVE = true;
|
QUICK_MENU_ACTIVE = true;
|
||||||
|
|
|
@ -9,8 +9,8 @@ use smash::app::{self, lua_bind::*};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
pub use crate::common::consts::MENU;
|
pub use crate::common::consts::MENU;
|
||||||
pub static mut DEFAULT_MENU: TrainingModpackMenu = crate::common::consts::DEFAULT_MENU;
|
pub static mut DEFAULTS_MENU: TrainingModpackMenu = crate::common::consts::DEFAULTS_MENU;
|
||||||
pub static mut BASE_MENU: TrainingModpackMenu = unsafe { DEFAULT_MENU };
|
pub static mut BASE_MENU: TrainingModpackMenu = unsafe { DEFAULTS_MENU };
|
||||||
pub static mut FIGHTER_MANAGER_ADDR: usize = 0;
|
pub static mut FIGHTER_MANAGER_ADDR: usize = 0;
|
||||||
pub static mut STAGE_MANAGER_ADDR: usize = 0;
|
pub static mut STAGE_MANAGER_ADDR: usize = 0;
|
||||||
|
|
||||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -71,7 +71,7 @@ pub fn render_text_to_screen(s: &str) {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
macro_rules! log {
|
macro_rules! log {
|
||||||
($($arg:tt)*) => {
|
($($arg:tt)*) => {
|
||||||
print!("{}{}", "[Training Modpack] ".green(), format!($($arg)*));
|
println!("{}{}", "[Training Modpack] ".green(), format!($($arg)*));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +105,8 @@ pub fn main() {
|
||||||
if menu_conf.starts_with(b"http://localhost") {
|
if menu_conf.starts_with(b"http://localhost") {
|
||||||
log!("Previous menu found, loading from training_modpack_menu.conf");
|
log!("Previous menu found, loading from training_modpack_menu.conf");
|
||||||
unsafe {
|
unsafe {
|
||||||
MENU = get_menu_from_url(MENU, std::str::from_utf8(&menu_conf).unwrap());
|
MENU = get_menu_from_url(MENU, std::str::from_utf8(&menu_conf).unwrap(), false);
|
||||||
if is_emulator() {
|
DEFAULTS_MENU = get_menu_from_url(DEFAULTS_MENU, std::str::from_utf8(&menu_conf).unwrap(), true);
|
||||||
MENU.quick_menu = OnOff::On;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log!("Previous menu found but is invalid.");
|
log!("Previous menu found but is invalid.");
|
||||||
|
@ -117,31 +115,9 @@ pub fn main() {
|
||||||
log!("No previous menu file found.");
|
log!("No previous menu file found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let menu_defaults_conf_path = "sd:/TrainingModpack/training_modpack_menu_defaults.conf";
|
|
||||||
log!("Checking for previous menu defaults in training_modpack_menu_defaults.conf...");
|
|
||||||
if fs::metadata(menu_defaults_conf_path).is_ok() {
|
|
||||||
let menu_defaults_conf = fs::read(menu_defaults_conf_path).unwrap();
|
|
||||||
if menu_defaults_conf.starts_with(b"http://localhost") {
|
|
||||||
log!("Menu defaults found, loading from training_modpack_menu_defaults.conf");
|
|
||||||
unsafe {
|
|
||||||
DEFAULT_MENU = get_menu_from_url(
|
|
||||||
DEFAULT_MENU,
|
|
||||||
std::str::from_utf8(&menu_defaults_conf).unwrap(),
|
|
||||||
);
|
|
||||||
if is_emulator() {
|
|
||||||
DEFAULT_MENU.quick_menu = OnOff::On;
|
|
||||||
}
|
|
||||||
crate::menu::write_menu();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log!("Previous menu defaults found but are invalid.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log!("No previous menu defaults found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_emulator() {
|
if is_emulator() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
DEFAULTS_MENU.quick_menu = OnOff::On;
|
||||||
MENU.quick_menu = OnOff::On;
|
MENU.quick_menu = OnOff::On;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,6 +171,7 @@ pub fn main() {
|
||||||
// Leave menu.
|
// Leave menu.
|
||||||
menu::QUICK_MENU_ACTIVE = false;
|
menu::QUICK_MENU_ACTIVE = false;
|
||||||
crate::menu::set_menu_from_url(url.as_str());
|
crate::menu::set_menu_from_url(url.as_str());
|
||||||
|
println!("URL: {}", url.as_str());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
button_presses.zl.read_press().then(|| {
|
button_presses.zl.read_press().then(|| {
|
||||||
|
|
|
@ -20,337 +20,261 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.answer-border-outer {
|
.tab-list-container {
|
||||||
margin-top: 5px;
|
overflow: hidden;
|
||||||
}
|
background-color: #555;
|
||||||
|
|
||||||
.button-icon {
|
|
||||||
height: 53px;
|
|
||||||
margin-left: 4px;
|
|
||||||
width: 53px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-icon-wrapper {
|
|
||||||
align-items: center;
|
|
||||||
background: #000000;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 58px;
|
justify-content: flex-start;
|
||||||
margin-left: -1px;
|
width: 100%;
|
||||||
width: 80px;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-msg-wrapper {
|
.tab-list-container p {
|
||||||
width: 259px;
|
color: #fff;
|
||||||
|
width: 130px;
|
||||||
|
height: fit-content;
|
||||||
|
margin: 0px 10px 0px 10px;
|
||||||
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-display {
|
|
||||||
margin: 10px 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-display::after {
|
.tab-list {
|
||||||
/* Displayed Checkbox (unchecked) */
|
overflow: hidden;
|
||||||
color: white;
|
|
||||||
content: "\E14C";
|
|
||||||
}
|
|
||||||
|
|
||||||
.defaults-checkbox-container {
|
|
||||||
/* Save Defaults Container */
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: flex-start;
|
||||||
justify-content: center;
|
width: 100%;
|
||||||
margin-top: 10px;
|
|
||||||
position: fixed;
|
|
||||||
right: 50px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-button {
|
.tab-list button {
|
||||||
align-items: center;
|
background-color: inherit;
|
||||||
display: inline-flex;
|
float: left;
|
||||||
flex: 1;
|
border: none;
|
||||||
justify-content: center;
|
outline: none;
|
||||||
text-align: center;
|
cursor: pointer;
|
||||||
vertical-align: middle;
|
padding: 14px 16px;
|
||||||
|
color: #fff;
|
||||||
|
margin: 5px 0px 0px 8px;
|
||||||
|
border-radius: 8px 8px 0px 0px;
|
||||||
|
font-size: large;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.tab-list button:hover {
|
||||||
align-items: center;
|
background: #797979;
|
||||||
background: #000000;
|
}
|
||||||
|
|
||||||
|
.tab-list button.active {
|
||||||
|
color: #000;
|
||||||
|
background: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 73px;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: space-evenly;
|
||||||
position: fixed;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
body {
|
||||||
align-items: center;
|
background: none;
|
||||||
background: #000000;
|
font-family: "nintendo_ext_003", "nintendo_udsgr_std_003";
|
||||||
border-bottom: 7px solid #000000;
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overwrite padding from keyword stuff. */
|
||||||
|
.l-main-content {
|
||||||
|
padding: 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle alignment of items in the header */
|
||||||
|
.l-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 65px;
|
justify-content: space-between;
|
||||||
}
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
.header-decoration {
|
height: 80px;
|
||||||
align-items: center;
|
z-index: 100;
|
||||||
background: #a80114;
|
background: #000;
|
||||||
display: inline-flex;
|
box-shadow: 0px 1px 1px #000;
|
||||||
height: 65px;
|
|
||||||
padding-left: 21px;
|
|
||||||
width: 101px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-desc {
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
color: #f46264;
|
color: #f46264;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
line-height: 2.5;
|
line-height: 2.5;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
word-break: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-appear {
|
.header-label {
|
||||||
opacity: 1;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: end;
|
||||||
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-focused .question-border::before {
|
.header-label > p {
|
||||||
background: #000000;
|
color: #fff;
|
||||||
box-shadow: none;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-focused .question-message {
|
.return-icon-container {
|
||||||
color: #FFFFFF;
|
width: 101px;
|
||||||
text-shadow: 2px 0 0 #000, -2px 0 0 #000, 0 2px 0 #000, 0 -2px 0 #000, 1px 1px #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000;
|
height: 65px;
|
||||||
|
padding-left: 21px;
|
||||||
|
background: #a80114;
|
||||||
|
border-radius: 0px 0px 15px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-focused .question.scuffle-thema {
|
.return-icon {
|
||||||
background: #df1624;
|
width: 58px;
|
||||||
|
height: 58px;
|
||||||
|
padding-left: 7px;
|
||||||
|
filter: drop-shadow(3px 5px 2px rgba(0, 0, 0, 0.8));
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-focused .scuffle-thema {
|
/* Center Icons */
|
||||||
background: #df1624;
|
.question::before {
|
||||||
|
width: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-hidden {
|
/* Footer */
|
||||||
display: none;
|
.footer {
|
||||||
}
|
position: fixed;
|
||||||
|
|
||||||
.is-opened .question {
|
|
||||||
bottom: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-opened .question-border::before {
|
|
||||||
background: #000000;
|
|
||||||
bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-opened .question-outer {
|
|
||||||
height: 86px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.keyword-button {
|
|
||||||
background: #d9e4ea;
|
|
||||||
border: solid 4px #2e3c45;
|
|
||||||
box-shadow: 1px 1px 6px rgba(24, 24, 24, 0.6);
|
|
||||||
box-sizing: border-box;
|
|
||||||
height: 66px;
|
|
||||||
justify-content: flex-start;
|
|
||||||
position: relative;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.keyword-button-outer {
|
|
||||||
border: 5px solid transparent;
|
|
||||||
will-change: transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
.keyword-message {
|
|
||||||
color: #2b3940;
|
|
||||||
font-size: 22px;
|
|
||||||
padding: 0px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-footer {
|
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
width: 100%;
|
background: #000;
|
||||||
}
|
|
||||||
|
|
||||||
.l-grid {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
justify-content: center;
|
||||||
}
|
align-items: center;
|
||||||
|
height: 73px;
|
||||||
.l-header {
|
|
||||||
box-shadow: 0px 1px 1px #000000;
|
|
||||||
display: flex;
|
|
||||||
left: 0px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
color: #fff;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-header-title {
|
/* Save Defaults Container */
|
||||||
align-items: center;
|
.defaults-checkbox-container {
|
||||||
|
position: fixed;
|
||||||
|
right: 50px;
|
||||||
|
margin-top: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
left: 0px;
|
flex-direction: column;
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
width: 1280px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-item {
|
|
||||||
margin: 0px 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-main-content {
|
|
||||||
/* Overwrite padding from keyword stuff. */
|
|
||||||
padding: 0px 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-qa {
|
|
||||||
/* Column size */
|
|
||||||
flex-basis: 33%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-qa:last-child .qa {
|
|
||||||
/* Overwrite margin on the last child to avoid overlap with footer */
|
|
||||||
margin-bottom: 75px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-qa:last-child .qa.is-opened {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.qa {
|
|
||||||
display: block;
|
|
||||||
will-change: scroll-position;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-focused {
|
|
||||||
background: linear-gradient(90deg, rgb(255, 109, 0) 0%, rgb(255, 255, 0) 65%, rgb(255, 109, 0) 70%);
|
|
||||||
will-change: animation;
|
|
||||||
animation: background-slide 650ms linear infinite normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question {
|
|
||||||
align-items: center;
|
|
||||||
background: #d9e4ea;
|
|
||||||
bottom: 11px;
|
|
||||||
display: flex;
|
|
||||||
left: 11px;
|
|
||||||
padding: 0px 30px 0px 94px;
|
|
||||||
position: absolute;
|
|
||||||
right: 28px;
|
|
||||||
top: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-border::before {
|
|
||||||
background: #2e3c45;
|
|
||||||
bottom: 6px;
|
|
||||||
box-shadow: 3px 3px 3px rgba(24, 24, 24, 0.5);
|
|
||||||
content: '';
|
|
||||||
left: 6px;
|
|
||||||
position: absolute;
|
|
||||||
right: 6px;
|
|
||||||
top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-icon {
|
|
||||||
bottom: 0px;
|
|
||||||
height: 60px;
|
|
||||||
left: 2px;
|
|
||||||
position: absolute;
|
|
||||||
top: 2px;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-message {
|
|
||||||
color: #2b3940;
|
|
||||||
font-size: 23px;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-message span {
|
|
||||||
display: block;
|
|
||||||
letter-spacing: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-outer {
|
|
||||||
height: 86px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question::before {
|
|
||||||
width: 70px;
|
|
||||||
background: #000000;
|
|
||||||
bottom: 0px;
|
|
||||||
content: '';
|
|
||||||
left: 0px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ret-icon {
|
|
||||||
display: inline-block;
|
|
||||||
height: 58px;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
width: 58px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ret-icon-wrapper {
|
|
||||||
margin-left: -4px;
|
|
||||||
position: relative;
|
|
||||||
will-change: transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Checkbox element (hidden) */
|
||||||
#saveDefaults {
|
#saveDefaults {
|
||||||
/* Checkbox element (hidden) */
|
|
||||||
left: -100vw;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
left: -100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox-display {
|
||||||
|
margin: 10px 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Displayed Checkbox (unchecked) */
|
||||||
|
.checkbox-display::after {
|
||||||
|
content: "\E14C";
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Displayed Checkbox (checked) */
|
||||||
#saveDefaults:checked~.checkbox-display::after {
|
#saveDefaults:checked~.checkbox-display::after {
|
||||||
/* Displayed Checkbox (checked) */
|
|
||||||
content: "\E14B";
|
content: "\E14B";
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
.menu-item {
|
||||||
text-decoration: none;
|
/* Container div for menu link and menu list */
|
||||||
|
width: 30%;
|
||||||
|
margin: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
.menu-button, .menu-item > div button {
|
||||||
background: none;
|
/* Item styling */
|
||||||
width: 1280px;
|
background-color: #d9e4ea;
|
||||||
}
|
border: solid black;
|
||||||
|
border-width: 3px 20px 3px 3px;
|
||||||
body, div, th, td, p, ul, ol, dl, dt, dd, img, h1, h2, h3, h4, h5, h6, footer, header, nav, p, section, span, figure {
|
|
||||||
margin: 0px;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
word-break: normal;
|
box-shadow: 3px 3px 3px #18181880;
|
||||||
font-family: "nintendo_ext_003", "nintendo_udsgr_std_003";
|
display: flex;
|
||||||
|
height: 60px;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
img, svg {
|
.menu-item > div button {
|
||||||
opacity: 0;
|
z-index: 1;
|
||||||
|
width: 22%;
|
||||||
|
margin: 4px 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.question-icon:not(.toggle) {
|
.modal p {
|
||||||
/* Fade icons slightly */
|
font-size: 18px !important;
|
||||||
opacity: 0.75;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
.menu-icon {
|
||||||
letter-spacing: 0.01px;
|
background-color: black;
|
||||||
|
flex-basis: auto;
|
||||||
|
width: 60px;
|
||||||
|
height: 48px;
|
||||||
|
border: solid black;
|
||||||
|
border-right-width: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul, ol {
|
.menu-icon img {
|
||||||
list-style-type: none;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-item p {
|
||||||
|
font-size: 23px;
|
||||||
|
color: #2b3940;
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px 0px 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item > div {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: fixed;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-content: flex-start;
|
||||||
|
top: 80px;
|
||||||
|
bottom: 73px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
margin-top: 0px;
|
||||||
|
background-color: rgba(100, 100, 100, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
background: rgb(255,70,2);
|
||||||
|
background: linear-gradient(45deg, rgba(255,70,2,1) 20%, rgba(255,215,0,1) 46%, rgba(255,215,0,1) 54%, rgba(255,70,2,1) 80%);
|
||||||
|
background-size: 500% 100%;
|
||||||
|
will-change: animation;
|
||||||
|
animation: translate-anim 5s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus > p {
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: -1px -1px 1px #000, 1px -1px 1px #000, -1px 1px 1px #000, 1px 1px 1px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes translate-anim {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 0%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 100% 0%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
29
src/static/img/quick_menu.svg
Normal file
29
src/static/img/quick_menu.svg
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="80"
|
||||||
|
height="80"
|
||||||
|
viewBox="0 0 21.166666 21.166667"
|
||||||
|
version="1.1"
|
||||||
|
id="svg5"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<g
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:2.11667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 1.8552457,17.110952 8.469829,10.496369 1.8552457,3.8817854"
|
||||||
|
id="path1904" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:2.11667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 7.22203,17.110952 13.836612,10.49637 7.22203,3.8817855"
|
||||||
|
id="path1904-3" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:2.11667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 12.588812,17.110952 19.203396,10.496369 12.588812,3.8817854"
|
||||||
|
id="path1904-2" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,22 +1,23 @@
|
||||||
var isNx = (typeof window.nx !== 'undefined');
|
var isNx = (typeof window.nx !== 'undefined');
|
||||||
var prevQuestionMsg = null;
|
var defaults_prefix = "__";
|
||||||
var prevFocusedElm = null;
|
|
||||||
|
|
||||||
if (isNx) {
|
if (isNx) {
|
||||||
window.nx.footer.setAssign('B', '', goBackHook, {se: ''});
|
window.nx.footer.setAssign('B', '', close_or_exit, {se: ''});
|
||||||
window.nx.footer.setAssign('X', '', resetSubmenu, {se: ''});
|
window.nx.footer.setAssign('X', '', resetCurrentSubmenu, {se: ''});
|
||||||
window.nx.footer.setAssign('L', '', resetAllSubmenus, {se: ''});
|
window.nx.footer.setAssign('L', '', resetAllSubmenus, {se: ''});
|
||||||
window.nx.footer.setAssign('R', '', toggleSaveDefaults, {se: ''});
|
window.nx.footer.setAssign('R', '', saveDefaults, {se: ''});
|
||||||
|
window.nx.footer.setAssign('ZR', '', cycleNextTab, {se: ''});
|
||||||
|
window.nx.footer.setAssign('ZL', '', cyclePrevTab, {se: ''});
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("body").addEventListener('keypress', (event) => {
|
document.addEventListener('keypress', (event) => {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case "b":
|
case "b":
|
||||||
console.log("b");
|
console.log("b");
|
||||||
goBackHook();
|
close_or_exit();
|
||||||
break;
|
break;
|
||||||
case "x":
|
case "x":
|
||||||
console.log("x");
|
console.log("x");
|
||||||
resetSubmenu();
|
resetCurrentSubmenu();
|
||||||
break;
|
break;
|
||||||
case "l":
|
case "l":
|
||||||
console.log("l");
|
console.log("l");
|
||||||
|
@ -24,20 +25,87 @@ if (isNx) {
|
||||||
break;
|
break;
|
||||||
case "r":
|
case "r":
|
||||||
console.log("r");
|
console.log("r");
|
||||||
toggleSaveDefaults();
|
saveDefaults();
|
||||||
|
break;
|
||||||
|
case "p":
|
||||||
|
console.log("p");
|
||||||
|
cycleNextTab();
|
||||||
|
break;
|
||||||
|
case "o":
|
||||||
|
console.log("o");
|
||||||
|
cyclePrevTab();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = setSettings;
|
window.onload = onLoad;
|
||||||
|
var settings = new Map();
|
||||||
|
var lastFocusedItem = document.querySelector(".menu-item > button");
|
||||||
|
|
||||||
function isTextNode(node) {
|
function onLoad() {
|
||||||
return node.nodeType == Node.TEXT_NODE
|
// Activate the first tab
|
||||||
|
openTab(document.querySelector("button.tab-button"));
|
||||||
|
|
||||||
|
// Extract URL params and set appropriate settings
|
||||||
|
setSettingsFromURL();
|
||||||
|
setSubmenusFromSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openTab(e) {
|
||||||
|
var tab_id = e.id.replace("button", "tab");
|
||||||
|
var selected_tab = document.getElementById(tab_id);
|
||||||
|
|
||||||
|
|
||||||
|
// Hide all content for all tabs
|
||||||
|
closeAllItems();
|
||||||
|
tabcontent = document.getElementsByClassName("tab-content");
|
||||||
|
Array.from(tabcontent).forEach(element => {
|
||||||
|
element.classList.add("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Get all elements with class="tablinks" and remove the class "active"
|
||||||
|
tablinks = document.getElementsByClassName("tab-button");
|
||||||
|
Array.from(tablinks).forEach(element => {
|
||||||
|
element.classList.remove("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show the current tab, and add an "active" class to the button that opened the tab
|
||||||
|
e.classList.add("active");
|
||||||
|
selected_tab.classList.remove("hide");
|
||||||
|
selected_tab.querySelector("button").focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openItem(e) {
|
||||||
|
playSound("SeWebMenuListOpen");
|
||||||
|
var modal = e.parentElement.querySelector(".modal");
|
||||||
|
modal.classList.toggle("hide");
|
||||||
|
modal.querySelector("button").focus();
|
||||||
|
lastFocusedItem = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeAllItems() {
|
||||||
|
var modals = document.querySelectorAll(".modal");
|
||||||
|
Array.from(modals).forEach(element => {
|
||||||
|
element.classList.add("hide");
|
||||||
|
});
|
||||||
|
lastFocusedItem.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleOption(e) {
|
||||||
|
playSound("SeSelectCheck");
|
||||||
|
if (e.parentElement.classList.contains("single-option")) {
|
||||||
|
selectSingleOption(e);
|
||||||
|
} else {
|
||||||
|
var img = e.querySelector("img");
|
||||||
|
img.classList.toggle("hide");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closestClass(elem, class_) {
|
function closestClass(elem, class_) {
|
||||||
// Returns the closest anscestor (including self) with the given class
|
// Returns the closest ancestor (including self) with the given class
|
||||||
|
// TODO: Consider removing
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
// Reached the end of the DOM
|
// Reached the end of the DOM
|
||||||
return null
|
return null
|
||||||
|
@ -49,46 +117,6 @@ function closestClass(elem, class_) {
|
||||||
return closestClass(elem.parentElement, class_);
|
return closestClass(elem.parentElement, class_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElementByXpath(path) {
|
|
||||||
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
function focusQA(e) {
|
|
||||||
playSound("SeSelectUncheck");
|
|
||||||
prevFocusedElm = e;
|
|
||||||
e.classList.add("is-focused");
|
|
||||||
}
|
|
||||||
|
|
||||||
function defocusQA(e) {
|
|
||||||
if (prevFocusedElm) {
|
|
||||||
prevFocusedElm.classList.remove('is-focused');
|
|
||||||
|
|
||||||
}
|
|
||||||
if (prevQuestionMsg) {
|
|
||||||
prevQuestionMsg.remove();
|
|
||||||
prevQuestionMsg = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleAnswer(e) {
|
|
||||||
playSound("SeToggleBtnOn");
|
|
||||||
e.classList.toggle("is-opened");
|
|
||||||
|
|
||||||
// Toggle visibility of child answers
|
|
||||||
[].forEach.call(e.childNodes, function (child) {
|
|
||||||
if (!isTextNode(child) && child.classList.contains("answer-border-outer")) {
|
|
||||||
child.classList.toggle("is-hidden");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Toggle visibility of sibling answers
|
|
||||||
var sibling = e.nextElementSibling;
|
|
||||||
if (sibling.classList.contains("answer-border-outer")) {
|
|
||||||
sibling.classList.toggle("is-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function playSound(label) {
|
function playSound(label) {
|
||||||
// Valid labels:
|
// Valid labels:
|
||||||
// SeToggleBtnFocus
|
// SeToggleBtnFocus
|
||||||
|
@ -129,164 +157,120 @@ function playSound(label) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goBackHook() {
|
function exit() {
|
||||||
// If any submenus are open, close them
|
|
||||||
// Otherwise if all submenus are closed, exit the menu and return to the game
|
|
||||||
|
|
||||||
if (document.querySelectorAll(".qa.is-opened").length == 0) {
|
|
||||||
// If all submenus are closed, exit and return through localhost
|
|
||||||
playSound("SeFooterDecideBack");
|
playSound("SeFooterDecideBack");
|
||||||
var url = "http://localhost/";
|
setSettingsFromMenu();
|
||||||
|
var url = buildURLFromSettings();
|
||||||
var settings = new Map();
|
|
||||||
|
|
||||||
// Collect settings for toggles
|
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll("ul.l-grid"), function (toggle) {
|
|
||||||
var section = toggle.id;
|
|
||||||
var val = "";
|
|
||||||
|
|
||||||
[].forEach.call(toggle.childNodes, function (child) {
|
|
||||||
if (!isTextNode(child) && child.querySelectorAll(".is-appear").length) {
|
|
||||||
val += child.getAttribute("val") + ",";
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
settings.set(section,val);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collect settings for OnOffs
|
|
||||||
[].forEach.call(document.querySelectorAll("div.onoff"), function (onoff) {
|
|
||||||
var section = onoff.id;
|
|
||||||
var val = "";
|
|
||||||
if (onoff.querySelectorAll(".is-appear").length) {
|
|
||||||
val = "1";
|
|
||||||
} else {
|
|
||||||
val = "0";
|
|
||||||
}
|
|
||||||
settings.set(section,val);
|
|
||||||
});
|
|
||||||
|
|
||||||
url += "?";
|
|
||||||
settings.forEach((val, section) => { url += section + "=" + val + "&" } );
|
|
||||||
|
|
||||||
if (document.getElementById("saveDefaults").checked) {
|
|
||||||
url += "save_defaults=1";
|
|
||||||
} else {
|
|
||||||
url = url.slice(0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNx) {
|
if (isNx) {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
} else {
|
} else {
|
||||||
console.log(url);
|
console.log(url);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
function close_or_exit() {
|
||||||
|
// If any submenus are open, close them
|
||||||
|
// Otherwise if all submenus are closed, exit the menu and return to the game
|
||||||
|
|
||||||
|
if (document.querySelector(".modal:not(.hide)")) {
|
||||||
// Close any open submenus
|
// Close any open submenus
|
||||||
[].forEach.call(document.querySelectorAll(".qa.is-opened"), function (submenu) { toggleAnswer(submenu); });
|
console.log("Closing Items");
|
||||||
|
closeAllItems();
|
||||||
|
} else {
|
||||||
|
// If all submenus are closed, exit and return through localhost
|
||||||
|
console.log("Exiting");
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickToggle(e) {
|
function setSettingsFromURL() {
|
||||||
playSound("SeCheckboxOn");
|
|
||||||
var toggleOptions = e.querySelector(".toggle");
|
|
||||||
if (e.querySelector(".is-single-option")) { // Single-option submenu
|
|
||||||
// Deselect all submenu options
|
|
||||||
closestClass(e, "l-qa").querySelector(".toggle").classList.remove("is-appear");
|
|
||||||
closestClass(e, "l-qa").querySelector(".toggle").classList.add("is-hidden");
|
|
||||||
// Then set the current one as the active setting
|
|
||||||
toggleOptions.classList.add("is-appear");
|
|
||||||
toggleOptions.classList.remove("is-hidden");
|
|
||||||
} else { // Multi-option submenu
|
|
||||||
toggleOptions.classList.toggle("is-appear");
|
|
||||||
toggleOptions.classList.toggle("is-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParams(url) {
|
|
||||||
var regex = /[?&]([^=#]+)=([^&#]*)/g,
|
var regex = /[?&]([^=#]+)=([^&#]*)/g,
|
||||||
params = {},
|
|
||||||
match;
|
match;
|
||||||
while (match = regex.exec(url)) {
|
while (match = regex.exec(document.URL)) {
|
||||||
params[match[1]] = match[2];
|
settings.set(match[1], match[2]);
|
||||||
}
|
}
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSettings() {
|
function setSettingsFromMenu() {
|
||||||
// Get settings from the URL GET parameters
|
var section;
|
||||||
const settings = getParams(document.URL);
|
var mask;
|
||||||
|
[].forEach.call(document.querySelectorAll(".menu-item"), function (menuItem) {
|
||||||
|
section = menuItem.id;
|
||||||
|
mask = getMaskFromSubmenu(menuItem);
|
||||||
|
settings.set(section, mask);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Set Toggles
|
function buildURLFromSettings() {
|
||||||
[].forEach.call(document.querySelectorAll("ul.l-grid"), function (toggle) {
|
var url = "http://localhost/";
|
||||||
var section = toggle.id;
|
url += "?";
|
||||||
var section_setting = decodeURIComponent(settings[section]);
|
settings.forEach((val, key) => { url += key + "=" + String(val) + "&" } );
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
[].forEach.call(toggle.querySelectorAll("li"), function (child) {
|
function selectSingleOption(e) {
|
||||||
var e = child.querySelector("img.toggle");
|
// Deselect all options in the submenu
|
||||||
if (section_setting.split(",").includes(child.getAttribute("val"))) {
|
parent = closestClass(e, "single-option");
|
||||||
e.classList.add("is-appear");
|
siblings = parent.querySelectorAll(".menu-icon img");
|
||||||
e.classList.remove("is-hidden");
|
[].forEach.call(siblings, function (sibling) {
|
||||||
|
sibling.classList.add("hide");
|
||||||
|
});
|
||||||
|
e.querySelector(".menu-icon img").classList.remove("hide");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSubmenusFromSettings() {
|
||||||
|
[].forEach.call(document.querySelectorAll(".menu-item"), function (menuItem) {
|
||||||
|
var section = menuItem.id;
|
||||||
|
var section_mask = decodeURIComponent(settings.get(section));
|
||||||
|
setSubmenuByMask(menuItem, section_mask)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSubmenuByMask(menuItem, mask) {
|
||||||
|
[].forEach.call(menuItem.querySelectorAll(".modal .menu-icon img"), function (toggle) {
|
||||||
|
if (isInBitmask(toggle.dataset.val, mask)) {
|
||||||
|
toggle.classList.remove("hide");
|
||||||
} else {
|
} else {
|
||||||
e.classList.remove("is-appear");
|
toggle.classList.add("hide");
|
||||||
e.classList.add("is-hidden");
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set OnOffs
|
|
||||||
[].forEach.call(document.querySelectorAll("div.onoff"), function (onOff) {
|
|
||||||
var section = onOff.id;
|
|
||||||
var section_setting = decodeURIComponent(settings[section]);
|
|
||||||
var e = onOff.querySelector("img.toggle");
|
|
||||||
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");
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetSubmenu() {
|
|
||||||
// Resets any open or focused submenus to the default values
|
|
||||||
playSound("SeToggleBtnOff");
|
|
||||||
[].forEach.call(document.querySelectorAll("[default*='is-appear']"), function (item) {
|
|
||||||
if (isSubmenuFocused(item)) {
|
|
||||||
item.classList.add("is-appear");
|
|
||||||
item.classList.remove("is-hidden");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll("[default*='is-hidden']"), function (item) {
|
// If no setting for a Single Option is set, select the first one
|
||||||
if (isSubmenuFocused(item)) {
|
var isSingleOption = menuItem.querySelectorAll(".modal.single-option").length != 0;
|
||||||
item.classList.remove("is-appear");
|
var isAllDeselected = menuItem.querySelectorAll(".modal .menu-icon img:not(.hide)").length == 0;
|
||||||
item.classList.add("is-hidden");
|
if (isSingleOption & isAllDeselected) {
|
||||||
|
selectSingleOption(menuItem.querySelector(".modal button"));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSubmenuFocused(elem) {
|
function getMaskFromSubmenu(menuItem) {
|
||||||
// Return true if the element is in a submenu which is either focused or opened
|
var val = 0;
|
||||||
return (
|
[].forEach.call(menuItem.querySelectorAll(".modal img:not(.hide)"), function (toggle) {
|
||||||
closestClass(elem, "l-qa").querySelectorAll(".is-opened, .is-focused").length
|
val += parseInt(toggle.dataset.val);
|
||||||
|| closestClass(elem, "is-focused")
|
});
|
||||||
)
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetCurrentSubmenu() {
|
||||||
|
var focus = document.querySelector(".menu-item .modal:not(.hide)");
|
||||||
|
if (!focus) {
|
||||||
|
focus = document.querySelector(":focus");
|
||||||
|
}
|
||||||
|
var menuItem = closestClass(focus, "menu-item");
|
||||||
|
|
||||||
|
var key = defaults_prefix + menuItem.id;
|
||||||
|
var section_mask = decodeURIComponent(settings.get(key));
|
||||||
|
setSubmenuByMask(menuItem, section_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetAllSubmenus() {
|
function resetAllSubmenus() {
|
||||||
// Resets all submenus to the default values
|
// Resets all submenus to the default values
|
||||||
if (confirm("Are you sure that you want to reset all menu settings to the default?")) {
|
if (confirm("Are you sure that you want to reset all menu settings to the default?")) {
|
||||||
playSound("SeToggleBtnOff");
|
[].forEach.call(document.querySelectorAll(".menu-item"), function (menuItem) {
|
||||||
[].forEach.call(document.querySelectorAll("[default*='is-appear']"), function (item) {
|
var key = defaults_prefix + menuItem.id;
|
||||||
item.classList.add("is-appear");
|
var mask = decodeURIComponent(settings.get(key));
|
||||||
item.classList.remove("is-hidden");
|
setSubmenuByMask(menuItem, mask)
|
||||||
});
|
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll("[default*='is-hidden']"), function (item) {
|
|
||||||
item.classList.remove("is-appear");
|
|
||||||
item.classList.add("is-hidden");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,9 +280,42 @@ function setHelpText(text) {
|
||||||
document.getElementById("help-text").innerText = text;
|
document.getElementById("help-text").innerText = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSaveDefaults() {
|
function saveDefaults() {
|
||||||
// Change the status of the Save Defaults checkbox
|
if (confirm("Are you sure that you want to change the default menu settings to the current selections?")) {
|
||||||
playSound("SeCheckboxOn");
|
var key;
|
||||||
var saveDefaultsCheckbox = document.getElementById("saveDefaults");
|
var mask;
|
||||||
saveDefaultsCheckbox.checked = !saveDefaultsCheckbox.checked;
|
[].forEach.call(document.querySelectorAll(".menu-item"), function (menuItem) {
|
||||||
|
key = defaults_prefix + menuItem.id;
|
||||||
|
mask = getMaskFromSubmenu(menuItem);
|
||||||
|
settings.set(key, mask);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInBitmask(val, mask) {
|
||||||
|
// Return true if the value is in the bitmask
|
||||||
|
return (mask & val) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function cycleNextTab() {
|
||||||
|
// Cycle to the next tab
|
||||||
|
var activeTab = document.querySelector(".tab-button.active");
|
||||||
|
var nextTab = activeTab.nextElementSibling;
|
||||||
|
if (!nextTab) {
|
||||||
|
// On the last tab - set the next tab as the first tab in the list
|
||||||
|
nextTab = document.querySelector(".tab-button");
|
||||||
|
}
|
||||||
|
openTab(nextTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cyclePrevTab() {
|
||||||
|
// Cycle to the previous tab
|
||||||
|
var activeTab = document.querySelector(".tab-button.active");
|
||||||
|
var prevTab = activeTab.previousElementSibling;
|
||||||
|
if (!prevTab) {
|
||||||
|
// On the first tab - set the next tab as the last tab in the list
|
||||||
|
tabs = document.querySelectorAll(".tab-button");
|
||||||
|
prevTab = tabs[tabs.length - 1];
|
||||||
|
}
|
||||||
|
openTab(prevTab);
|
||||||
}
|
}
|
|
@ -1,117 +1,59 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
<title>Document</title>
|
<title>Modpack Menu</title>
|
||||||
<link rel="stylesheet" href="./css/training_modpack.css" />
|
<link rel="stylesheet" href="./css/training_modpack.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body id="body">
|
<body>
|
||||||
<script defer src="./js/training_modpack.js"></script>
|
<script defer src="./js/training_modpack.js"></script>
|
||||||
<div class="l-header">
|
<div class="l-header">
|
||||||
<div class="l-header-title">
|
<a id="ret-button" tabindex="-1" class="return-icon-container" href="javascript:goBackHook();">
|
||||||
<div class="header-title"><span>Ultimate Training Modpack Menu</span></div>
|
<img class="return-icon" src="./img/m_retnormal.svg">
|
||||||
</div>
|
|
||||||
<div class="header" style="flex-grow: 1;">
|
|
||||||
<a id="ret-button" tabindex="-1" class="header-decoration" href="javascript:goBackHook();">
|
|
||||||
<div class="ret-icon-wrapper">
|
|
||||||
<img class="ret-icon is-appear" src="./img/m_retnormal.svg">
|
|
||||||
</div>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
<p class="header-title">Ultimate Training Modpack Menu</p>
|
||||||
<div class="header" style="flex-direction: column; justify-content: center; align-items: end; padding-right: 10px;">
|
<div class="header-label">
|
||||||
<p class="header-desc">Reset Current Menu: </p>
|
<p class="header-desc">Reset Current Menu: </p>
|
||||||
<p class="header-desc">Reset All Menus: </p>
|
<p class="header-desc">Reset All Menus: </p>
|
||||||
|
<p class="header-desc">Save Defaults: </p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<div class="tab-list-container">
|
||||||
<br>
|
<p>Prev Tab: </p>
|
||||||
<br>
|
<div class="tab-list">
|
||||||
<br>
|
{{#tabs}}
|
||||||
|
<button class="tab-button active" id="{{tab_id}}_button" onclick="openTab(this)" tabindex="-1">{{tab_title}}</button>
|
||||||
<div class="l-grid">
|
{{/tabs}}
|
||||||
|
|
||||||
<!--
|
|
||||||
Script the part below via templating. Overall structure is perhaps
|
|
||||||
[
|
|
||||||
l-qa qa [id=qa-{{menuName}} tabindex="{{index}}"] {
|
|
||||||
// make question for {{menuName}}
|
|
||||||
// make answer with l-grid : l-item list for options
|
|
||||||
},
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
Remember to set make max keyword size greater than 23!
|
|
||||||
-->
|
|
||||||
{{#sub_menus}}
|
|
||||||
<div class="l-qa">
|
|
||||||
{{^onoffselector}}
|
|
||||||
<a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this);setHelpText({{help_text}})" onblur="defocusQA(this)" onclick="toggleAnswer(this)">
|
|
||||||
<div class="question-outer">
|
|
||||||
<div class="question-border">
|
|
||||||
<div id="question-{{id}}" class="question scuffle-thema">
|
|
||||||
<img class="question-icon" src="./img/{{id}}.svg" />
|
|
||||||
<p class="question-message">
|
|
||||||
<span>{{title}}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p>Next Tab: </p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="tab-content-container">
|
||||||
</a>
|
{{#tabs}}
|
||||||
<div id="answer-border-{{id}}" class="answer-border-outer is-hidden">
|
<div id="{{tab_id}}_tab" class="tab-content">
|
||||||
<div class="l-main">
|
{{#tab_submenus}}
|
||||||
<ul class="l-grid" id="{{id}}">
|
<div class="menu-item" id="{{submenu_id}}">
|
||||||
|
<button class="menu-button" onfocus="setHelpText('{{help_text}}')" onclick="openItem(this)">
|
||||||
|
<div class="menu-icon"><img src="./img/{{submenu_id}}.svg" /></div>
|
||||||
|
<p>{{submenu_title}}</p>
|
||||||
|
</button>
|
||||||
|
<div class="hide modal{{#is_single_option}} single-option{{/is_single_option}}">
|
||||||
{{#toggles}}
|
{{#toggles}}
|
||||||
<li class="l-item" val="{{value}}">
|
<button class="menu-button" onclick="toggleOption(this)">
|
||||||
<div class="keyword-button-outer">
|
<div class="menu-icon"><img class="hide" src="./img/check.svg" data-val="{{toggle_value}}"/></div>
|
||||||
<a tabindex="{{index}}" class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);">
|
<p>{{toggle_title}}</p>
|
||||||
<div class="button-icon-wrapper">
|
</button>
|
||||||
<img class="button-icon toggle {{checked}} {{#is_single_option}}is-single-option{{/is_single_option}}" src="./img/check.svg" default="{{default}}">
|
|
||||||
</div>
|
|
||||||
<div class="button-msg-wrapper">
|
|
||||||
<div class="keyword-message">
|
|
||||||
{{title}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/toggles}}
|
{{/toggles}}
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/onoffselector}}
|
{{/tab_submenus}}
|
||||||
{{#onoffselector}}
|
|
||||||
<a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this);setHelpText({{help_text}})" onblur="defocusQA(this)" onclick="clickToggle(this)">
|
|
||||||
<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;" src="./img/{{id}}.svg" />
|
|
||||||
<div><img class="question-icon toggle {{checked}}" style="z-index: 2;" src="./img/check.svg" default="{{default}}"/></div>
|
|
||||||
<p class="question-message">
|
|
||||||
<span>{{title}}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
{{/tabs}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<footer id="footer" class="footer">
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{{/onoffselector}}
|
|
||||||
</div>
|
|
||||||
{{/sub_menus}}
|
|
||||||
</div>
|
|
||||||
<footer id="footer" class="footer l-footer">
|
|
||||||
<p id="help-text" class="header-desc"></p>
|
<p id="help-text" class="header-desc"></p>
|
||||||
<div class="defaults-checkbox-container">
|
|
||||||
<label class="header-desc" for="saveDefaults">Save defaults: </label>
|
|
||||||
<input type="checkbox" id="saveDefaults">
|
|
||||||
<div class="checkbox-display"></div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
use training_mod_consts::{OnOffSelector, Slider, SubMenu, SubMenuType, Toggle};
|
use training_mod_consts::{Slider, SubMenu, SubMenuType, Toggle, UiMenu};
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::{Backend},
|
backend::{Backend},
|
||||||
layout::{Constraint, Corner, Direction, Layout},
|
layout::{Constraint, Corner, Direction, Layout},
|
||||||
|
@ -22,81 +22,26 @@ pub struct App<'a> {
|
||||||
pub tabs: StatefulList<&'a str>,
|
pub tabs: StatefulList<&'a str>,
|
||||||
pub menu_items: HashMap<&'a str, MultiStatefulList<SubMenu<'a>>>,
|
pub menu_items: HashMap<&'a str, MultiStatefulList<SubMenu<'a>>>,
|
||||||
pub selected_sub_menu_toggles: MultiStatefulList<Toggle<'a>>,
|
pub selected_sub_menu_toggles: MultiStatefulList<Toggle<'a>>,
|
||||||
pub selected_sub_menu_onoff_selectors: MultiStatefulList<OnOffSelector<'a>>,
|
|
||||||
pub selected_sub_menu_sliders: MultiStatefulList<Slider>,
|
pub selected_sub_menu_sliders: MultiStatefulList<Slider>,
|
||||||
pub outer_list: bool
|
pub outer_list: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl<'a> App<'a> {
|
||||||
pub fn new(menu: training_mod_consts::Menu<'a>) -> App<'a> {
|
pub fn new(menu: UiMenu<'a>) -> App<'a> {
|
||||||
let tab_specifiers = vec![
|
|
||||||
("Mash Settings", vec![
|
|
||||||
"Mash Toggles",
|
|
||||||
"Followup Toggles",
|
|
||||||
"Attack Angle",
|
|
||||||
"Ledge Options",
|
|
||||||
"Ledge Delay",
|
|
||||||
"Tech Options",
|
|
||||||
"Miss Tech Options",
|
|
||||||
"Defensive Options",
|
|
||||||
"Aerial Delay",
|
|
||||||
"OoS Offset",
|
|
||||||
"Reaction Time",
|
|
||||||
]),
|
|
||||||
("Defensive Settings", vec![
|
|
||||||
"Fast Fall",
|
|
||||||
"Fast Fall Delay",
|
|
||||||
"Falling Aerials",
|
|
||||||
"Full Hop",
|
|
||||||
"Shield Tilt",
|
|
||||||
"DI Direction",
|
|
||||||
"SDI Direction",
|
|
||||||
"Airdodge Direction",
|
|
||||||
"SDI Strength",
|
|
||||||
"Shield Toggles",
|
|
||||||
"Mirroring",
|
|
||||||
"Throw Options",
|
|
||||||
"Throw Delay",
|
|
||||||
"Pummel Delay",
|
|
||||||
"Buff Options",
|
|
||||||
]),
|
|
||||||
("Other Settings", vec![
|
|
||||||
"Input Delay",
|
|
||||||
"Save States",
|
|
||||||
"Save Damage",
|
|
||||||
"Hitbox Visualization",
|
|
||||||
"Stage Hazards",
|
|
||||||
"Frame Advantage",
|
|
||||||
"Mash In Neutral",
|
|
||||||
"Quick Menu"
|
|
||||||
])
|
|
||||||
];
|
|
||||||
let mut tabs: std::collections::HashMap<&str, Vec<SubMenu>> = std::collections::HashMap::new();
|
|
||||||
tabs.insert("Mash Settings", vec![]);
|
|
||||||
tabs.insert("Defensive Settings", vec![]);
|
|
||||||
tabs.insert("Other Settings", vec![]);
|
|
||||||
|
|
||||||
for sub_menu in menu.sub_menus.iter() {
|
|
||||||
for tab_spec in tab_specifiers.iter() {
|
|
||||||
if tab_spec.1.contains(&sub_menu.title) {
|
|
||||||
tabs.get_mut(tab_spec.0).unwrap().push(sub_menu.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let num_lists = 3;
|
let num_lists = 3;
|
||||||
|
|
||||||
let mut menu_items_stateful = HashMap::new();
|
let mut menu_items_stateful = HashMap::new();
|
||||||
tabs.keys().for_each(|k| {
|
menu.tabs.iter().for_each(|tab| {
|
||||||
menu_items_stateful.insert(
|
menu_items_stateful.insert(
|
||||||
k.clone(),
|
tab.tab_title,
|
||||||
MultiStatefulList::with_items(tabs.get(k).unwrap().clone(), num_lists)
|
MultiStatefulList::with_items(tab.tab_submenus.clone(), num_lists)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
tabs: StatefulList::with_items(tab_specifiers.iter().map(|(tab_title, _)| *tab_title).collect()),
|
tabs: StatefulList::with_items(menu.tabs.iter().map(|tab| tab.tab_title).collect()),
|
||||||
menu_items: menu_items_stateful,
|
menu_items: menu_items_stateful,
|
||||||
selected_sub_menu_toggles: MultiStatefulList::with_items(vec![], 0),
|
selected_sub_menu_toggles: MultiStatefulList::with_items(vec![], 0),
|
||||||
selected_sub_menu_onoff_selectors: MultiStatefulList::with_items(vec![], 0),
|
|
||||||
selected_sub_menu_sliders: MultiStatefulList::with_items(vec![], 0),
|
selected_sub_menu_sliders: MultiStatefulList::with_items(vec![], 0),
|
||||||
outer_list: true
|
outer_list: true
|
||||||
};
|
};
|
||||||
|
@ -109,8 +54,7 @@ impl<'a> App<'a> {
|
||||||
let selected_sub_menu = &self.menu_items.get(self.tab_selected()).unwrap().lists[list_section].items.get(list_idx).unwrap();
|
let selected_sub_menu = &self.menu_items.get(self.tab_selected()).unwrap().lists[list_section].items.get(list_idx).unwrap();
|
||||||
|
|
||||||
let toggles = selected_sub_menu.toggles.clone();
|
let toggles = selected_sub_menu.toggles.clone();
|
||||||
let sliders = selected_sub_menu.sliders.clone();
|
// let sliders = selected_sub_menu.sliders.clone();
|
||||||
let onoffs = selected_sub_menu.onoffselector.clone();
|
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => {
|
SubMenuType::TOGGLE => {
|
||||||
self.selected_sub_menu_toggles = MultiStatefulList::with_items(
|
self.selected_sub_menu_toggles = MultiStatefulList::with_items(
|
||||||
|
@ -118,14 +62,9 @@ impl<'a> App<'a> {
|
||||||
if selected_sub_menu.toggles.len() >= 3 { 3 } else { selected_sub_menu.toggles.len()} )
|
if selected_sub_menu.toggles.len() >= 3 { 3 } else { selected_sub_menu.toggles.len()} )
|
||||||
},
|
},
|
||||||
SubMenuType::SLIDER => {
|
SubMenuType::SLIDER => {
|
||||||
self.selected_sub_menu_sliders = MultiStatefulList::with_items(
|
// self.selected_sub_menu_sliders = MultiStatefulList::with_items(
|
||||||
sliders,
|
// sliders,
|
||||||
if selected_sub_menu.sliders.len() >= 3 { 3 } else { selected_sub_menu.sliders.len()} )
|
// if selected_sub_menu.sliders.len() >= 3 { 3 } else { selected_sub_menu.sliders.len()} )
|
||||||
},
|
|
||||||
SubMenuType::ONOFF => {
|
|
||||||
self.selected_sub_menu_onoff_selectors = MultiStatefulList::with_items(
|
|
||||||
onoffs,
|
|
||||||
if selected_sub_menu.onoffselector.len() >= 3 { 3 } else { selected_sub_menu.onoffselector.len()} )
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -136,14 +75,13 @@ impl<'a> App<'a> {
|
||||||
|
|
||||||
fn sub_menu_selected(&self) -> &SubMenu {
|
fn sub_menu_selected(&self) -> &SubMenu {
|
||||||
let (list_section, list_idx) = self.menu_items.get(self.tab_selected()).unwrap().idx_to_list_idx(self.menu_items.get(self.tab_selected()).unwrap().state);
|
let (list_section, list_idx) = self.menu_items.get(self.tab_selected()).unwrap().idx_to_list_idx(self.menu_items.get(self.tab_selected()).unwrap().state);
|
||||||
&self.menu_items.get(self.tab_selected()).unwrap().lists[list_section].items.get(list_idx).unwrap()
|
self.menu_items.get(self.tab_selected()).unwrap().lists[list_section].items.get(list_idx).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_menu_next(&mut self) {
|
pub fn sub_menu_next(&mut self) {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.next(),
|
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.next(),
|
||||||
SubMenuType::SLIDER => self.selected_sub_menu_sliders.next(),
|
SubMenuType::SLIDER => self.selected_sub_menu_sliders.next(),
|
||||||
SubMenuType::ONOFF => self.selected_sub_menu_onoff_selectors.next(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +89,6 @@ impl<'a> App<'a> {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.next_list(),
|
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.next_list(),
|
||||||
SubMenuType::SLIDER => self.selected_sub_menu_sliders.next_list(),
|
SubMenuType::SLIDER => self.selected_sub_menu_sliders.next_list(),
|
||||||
SubMenuType::ONOFF => self.selected_sub_menu_onoff_selectors.next_list(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +96,6 @@ impl<'a> App<'a> {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.previous(),
|
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.previous(),
|
||||||
SubMenuType::SLIDER => self.selected_sub_menu_sliders.previous(),
|
SubMenuType::SLIDER => self.selected_sub_menu_sliders.previous(),
|
||||||
SubMenuType::ONOFF => self.selected_sub_menu_onoff_selectors.previous(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,30 +103,22 @@ impl<'a> App<'a> {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.previous_list(),
|
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.previous_list(),
|
||||||
SubMenuType::SLIDER => self.selected_sub_menu_sliders.previous_list(),
|
SubMenuType::SLIDER => self.selected_sub_menu_sliders.previous_list(),
|
||||||
SubMenuType::ONOFF => self.selected_sub_menu_onoff_selectors.previous_list(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_menu_strs_and_states(&mut self) -> (&str, &str, Vec<(Vec<(&str, &str)>, ListState)>) {
|
pub fn sub_menu_strs_and_states(&mut self) -> (&str, &str, Vec<(Vec<(bool, &str)>, ListState)>) {
|
||||||
(self.sub_menu_selected().title, self.sub_menu_selected().help_text,
|
(self.sub_menu_selected().submenu_title, self.sub_menu_selected().help_text,
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => {
|
SubMenuType::TOGGLE => {
|
||||||
self.selected_sub_menu_toggles.lists.iter().map(|toggle_list| {
|
self.selected_sub_menu_toggles.lists.iter().map(|toggle_list| {
|
||||||
(toggle_list.items.iter().map(
|
(toggle_list.items.iter().map(
|
||||||
|toggle| (toggle.checked, toggle.title)
|
|toggle| (toggle.checked, toggle.toggle_title)
|
||||||
).collect(), toggle_list.state.clone())
|
).collect(), toggle_list.state.clone())
|
||||||
}).collect()
|
}).collect()
|
||||||
},
|
},
|
||||||
SubMenuType::SLIDER => {
|
SubMenuType::SLIDER => {
|
||||||
vec![(vec![], ListState::default())]
|
vec![(vec![], ListState::default())]
|
||||||
},
|
},
|
||||||
SubMenuType::ONOFF => {
|
|
||||||
self.selected_sub_menu_onoff_selectors.lists.iter().map(|onoff_list| {
|
|
||||||
(onoff_list.items.iter().map(
|
|
||||||
|onoff| (onoff.checked, onoff.title)
|
|
||||||
).collect(), onoff_list.state.clone())
|
|
||||||
}).collect()
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +136,7 @@ impl<'a> App<'a> {
|
||||||
.items.get_mut(list_idx).unwrap();
|
.items.get_mut(list_idx).unwrap();
|
||||||
match SubMenuType::from_str(selected_sub_menu._type) {
|
match SubMenuType::from_str(selected_sub_menu._type) {
|
||||||
SubMenuType::TOGGLE => {
|
SubMenuType::TOGGLE => {
|
||||||
let is_single_option = selected_sub_menu.is_single_option.is_some();
|
let is_single_option = selected_sub_menu.is_single_option;
|
||||||
let state = self.selected_sub_menu_toggles.state;
|
let state = self.selected_sub_menu_toggles.state;
|
||||||
self.selected_sub_menu_toggles.lists.iter_mut()
|
self.selected_sub_menu_toggles.lists.iter_mut()
|
||||||
.map(|list| (list.state.selected(), &mut list.items))
|
.map(|list| (list.state.selected(), &mut list.items))
|
||||||
|
@ -216,42 +144,31 @@ impl<'a> App<'a> {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, o)|
|
.for_each(|(i, o)|
|
||||||
if state.is_some() && i == state.unwrap() {
|
if state.is_some() && i == state.unwrap() {
|
||||||
if o.checked != "is-appear" {
|
if !o.checked {
|
||||||
o.checked = "is-appear";
|
o.checked = true;
|
||||||
} else {
|
} else {
|
||||||
o.checked = "is-hidden";
|
o.checked = false;
|
||||||
}
|
}
|
||||||
} else if is_single_option {
|
} else if is_single_option {
|
||||||
o.checked = "is-hidden";
|
o.checked = false;
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
selected_sub_menu.toggles.iter_mut()
|
selected_sub_menu.toggles.iter_mut()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, o)| {
|
.for_each(|(i, o)| {
|
||||||
if i == state {
|
if i == state {
|
||||||
if o.checked != "is-appear" {
|
if !o.checked {
|
||||||
o.checked = "is-appear";
|
o.checked = true;
|
||||||
} else {
|
} else {
|
||||||
o.checked = "is-hidden";
|
o.checked = false;
|
||||||
}
|
}
|
||||||
} else if is_single_option {
|
} else if is_single_option {
|
||||||
o.checked = "is-hidden";
|
o.checked = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
SubMenuType::ONOFF => {
|
|
||||||
let onoff = self.selected_sub_menu_onoff_selectors.selected_list_item();
|
|
||||||
if onoff.checked != "is-appear" {
|
|
||||||
onoff.checked = "is-appear";
|
|
||||||
} else {
|
|
||||||
onoff.checked = "is-hidden";
|
|
||||||
}
|
|
||||||
selected_sub_menu.onoffselector.iter_mut()
|
|
||||||
.filter(|o| o.title == onoff.title)
|
|
||||||
.for_each(|o| o.checked = onoff.checked);
|
|
||||||
},
|
|
||||||
SubMenuType::SLIDER => {
|
SubMenuType::SLIDER => {
|
||||||
// self.selected_sub_menu_sliders.selected_list_item().checked = "is-appear";
|
// self.selected_sub_menu_sliders.selected_list_item().checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,17 +269,16 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) -> String {
|
||||||
if app.outer_list {
|
if app.outer_list {
|
||||||
let tab_selected = app.tab_selected();
|
let tab_selected = app.tab_selected();
|
||||||
let mut item_help = None;
|
let mut item_help = None;
|
||||||
for list_section in 0..app.menu_items.get(tab_selected).unwrap().lists.len() {
|
for (list_section, stateful_list) in app.menu_items.get(tab_selected).unwrap().lists.iter().enumerate() {
|
||||||
let stateful_list = &app.menu_items.get(tab_selected).unwrap().lists[list_section];
|
|
||||||
let items: Vec<ListItem> = stateful_list
|
let items: Vec<ListItem> = stateful_list
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let lines = vec![Spans::from(
|
let lines = vec![Spans::from(
|
||||||
if stateful_list.state.selected().is_some() {
|
if stateful_list.state.selected().is_some() {
|
||||||
i.title.to_owned()
|
i.submenu_title.to_owned()
|
||||||
} else {
|
} else {
|
||||||
" ".to_owned() + i.title
|
" ".to_owned() + i.submenu_title
|
||||||
})];
|
})];
|
||||||
ListItem::new(lines).style(Style::default().fg(Color::White))
|
ListItem::new(lines).style(Style::default().fg(Color::White))
|
||||||
})
|
})
|
||||||
|
@ -389,7 +305,7 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) -> String {
|
||||||
|
|
||||||
// TODO: Add Save Defaults
|
// TODO: Add Save Defaults
|
||||||
let help_paragraph = Paragraph::new(
|
let help_paragraph = Paragraph::new(
|
||||||
item_help.unwrap_or("").replace("\"", "") +
|
item_help.unwrap_or("").replace('\"', "") +
|
||||||
"\nA: Enter sub-menu | B: Exit menu | ZL/ZR: Next tab"
|
"\nA: Enter sub-menu | B: Exit menu | ZL/ZR: Next tab"
|
||||||
).style(Style::default().fg(Color::Cyan));
|
).style(Style::default().fg(Color::Cyan));
|
||||||
f.render_widget(help_paragraph, vertical_chunks[2]);
|
f.render_widget(help_paragraph, vertical_chunks[2]);
|
||||||
|
@ -401,7 +317,7 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) -> String {
|
||||||
let values_items: Vec<ListItem> = sub_menu_str.iter().map(|s| {
|
let values_items: Vec<ListItem> = sub_menu_str.iter().map(|s| {
|
||||||
ListItem::new(
|
ListItem::new(
|
||||||
vec![
|
vec![
|
||||||
Spans::from((if s.0 == "is-appear" { "X " } else { " " }).to_owned() + s.1)
|
Spans::from((if s.0 { "X " } else { " " }).to_owned() + s.1)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
@ -419,7 +335,7 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
let help_paragraph = Paragraph::new(
|
let help_paragraph = Paragraph::new(
|
||||||
help_text.replace("\"", "") +
|
help_text.replace('\"', "") +
|
||||||
"\nA: Select toggle | B: Exit submenu"
|
"\nA: Select toggle | B: Exit submenu"
|
||||||
).style(Style::default().fg(Color::Cyan));
|
).style(Style::default().fg(Color::Cyan));
|
||||||
f.render_widget(help_paragraph, vertical_chunks[2]);
|
f.render_widget(help_paragraph, vertical_chunks[2]);
|
||||||
|
@ -433,22 +349,17 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) -> String {
|
||||||
for key in app.menu_items.keys() {
|
for key in app.menu_items.keys() {
|
||||||
for list in &app.menu_items.get(key).unwrap().lists {
|
for list in &app.menu_items.get(key).unwrap().lists {
|
||||||
for sub_menu in &list.items {
|
for sub_menu in &list.items {
|
||||||
let mut val = String::new();
|
let val : usize = sub_menu.toggles.iter()
|
||||||
sub_menu.toggles.iter()
|
.filter(|t| t.checked)
|
||||||
.filter(|t| t.checked == "is-appear")
|
.map(|t| t.toggle_value)
|
||||||
.for_each(|t| val.push_str(format!("{},", t.value).as_str()));
|
.sum();
|
||||||
|
|
||||||
sub_menu.onoffselector.iter()
|
settings.insert(sub_menu.submenu_id, val);
|
||||||
.for_each(|o| {
|
|
||||||
val.push_str(
|
|
||||||
format!("{}", if o.checked == "is-appear" { 1 } else { 0 }).as_str())
|
|
||||||
});
|
|
||||||
settings.insert(sub_menu.id, val);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url.push_str("?");
|
url.push('?');
|
||||||
settings.iter()
|
settings.iter()
|
||||||
.for_each(|(section, val)| url.push_str(format!("{}={}&", section, val).as_str()));
|
.for_each(|(section, val)| url.push_str(format!("{}={}&", section, val).as_str()));
|
||||||
url
|
url
|
||||||
|
|
|
@ -49,14 +49,14 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
state.select(Some(0));
|
state.select(Some(0));
|
||||||
}
|
}
|
||||||
StatefulList {
|
StatefulList {
|
||||||
state: state,
|
state,
|
||||||
items: items[list_section_min_idx..list_section_max_idx].to_vec(),
|
items: items[list_section_min_idx..list_section_max_idx].to_vec(),
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
let total_len = items.len();
|
let total_len = items.len();
|
||||||
MultiStatefulList {
|
MultiStatefulList {
|
||||||
lists: lists,
|
lists,
|
||||||
total_len: total_len,
|
total_len,
|
||||||
state: 0
|
state: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,11 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
if list_section != next_list_section {
|
if list_section != next_list_section {
|
||||||
self.lists[list_section].unselect();
|
self.lists[list_section].unselect();
|
||||||
}
|
}
|
||||||
let state;
|
let state= if self.state + 1 >= self.total_len {
|
||||||
if self.state + 1 >= self.total_len {
|
(0, 0)
|
||||||
state = (0, 0);
|
|
||||||
} else {
|
} else {
|
||||||
state = (next_list_section, next_list_idx);
|
(next_list_section, next_list_idx)
|
||||||
}
|
};
|
||||||
|
|
||||||
self.lists[state.0].state.select(Some(state.1));
|
self.lists[state.0].state.select(Some(state.1));
|
||||||
self.state = self.list_idx_to_idx(state);
|
self.state = self.list_idx_to_idx(state);
|
||||||
|
@ -84,13 +83,12 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
let (last_list_section, last_list_idx) = (self.lists.len() - 1, self.lists[self.lists.len() - 1].items.len() - 1);
|
let (last_list_section, last_list_idx) = (self.lists.len() - 1, self.lists[self.lists.len() - 1].items.len() - 1);
|
||||||
|
|
||||||
self.lists[list_section].unselect();
|
self.lists[list_section].unselect();
|
||||||
let state;
|
let state= if self.state == 0 {
|
||||||
if self.state == 0 {
|
(last_list_section, last_list_idx)
|
||||||
state = (last_list_section, last_list_idx);
|
|
||||||
} else {
|
} else {
|
||||||
let (prev_list_section, prev_list_idx) = self.idx_to_list_idx(self.state - 1);
|
let (prev_list_section, prev_list_idx) = self.idx_to_list_idx(self.state - 1);
|
||||||
state = (prev_list_section, prev_list_idx);
|
(prev_list_section, prev_list_idx)
|
||||||
}
|
};
|
||||||
|
|
||||||
self.lists[state.0].state.select(Some(state.1));
|
self.lists[state.0].state.select(Some(state.1));
|
||||||
self.state = self.list_idx_to_idx(state);
|
self.state = self.list_idx_to_idx(state);
|
||||||
|
@ -99,12 +97,11 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
pub fn next_list(&mut self) {
|
pub fn next_list(&mut self) {
|
||||||
let (list_section, list_idx) = self.idx_to_list_idx(self.state);
|
let (list_section, list_idx) = self.idx_to_list_idx(self.state);
|
||||||
let next_list_section = (list_section + 1) % self.lists.len();
|
let next_list_section = (list_section + 1) % self.lists.len();
|
||||||
let next_list_idx;
|
let next_list_idx = if list_idx > self.lists[next_list_section].items.len() - 1 {
|
||||||
if list_idx > self.lists[next_list_section].items.len() - 1 {
|
self.lists[next_list_section].items.len() - 1
|
||||||
next_list_idx = self.lists[next_list_section].items.len() - 1;
|
|
||||||
} else {
|
} else {
|
||||||
next_list_idx = list_idx;
|
list_idx
|
||||||
}
|
};
|
||||||
|
|
||||||
if list_section != next_list_section {
|
if list_section != next_list_section {
|
||||||
self.lists[list_section].unselect();
|
self.lists[list_section].unselect();
|
||||||
|
@ -117,19 +114,17 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
|
|
||||||
pub fn previous_list(&mut self) {
|
pub fn previous_list(&mut self) {
|
||||||
let (list_section, list_idx) = self.idx_to_list_idx(self.state);
|
let (list_section, list_idx) = self.idx_to_list_idx(self.state);
|
||||||
let prev_list_section;
|
let prev_list_section = if list_section == 0 {
|
||||||
if list_section == 0 {
|
self.lists.len() - 1
|
||||||
prev_list_section = self.lists.len() - 1;
|
|
||||||
} else {
|
} else {
|
||||||
prev_list_section = list_section - 1;
|
list_section - 1
|
||||||
}
|
};
|
||||||
|
|
||||||
let prev_list_idx;
|
let prev_list_idx= if list_idx > self.lists[prev_list_section].items.len() - 1 {
|
||||||
if list_idx > self.lists[prev_list_section].items.len() - 1 {
|
self.lists[prev_list_section].items.len() - 1
|
||||||
prev_list_idx = self.lists[prev_list_section].items.len() - 1;
|
|
||||||
} else {
|
} else {
|
||||||
prev_list_idx = list_idx;
|
list_idx
|
||||||
}
|
};
|
||||||
|
|
||||||
if list_section != prev_list_section {
|
if list_section != prev_list_section {
|
||||||
self.lists[list_section].unselect();
|
self.lists[list_section].unselect();
|
||||||
|
@ -152,7 +147,7 @@ impl<T> StatefulList<T> {
|
||||||
// Enforce state as first of list
|
// Enforce state as first of list
|
||||||
state.select(Some(0));
|
state.select(Some(0));
|
||||||
StatefulList {
|
StatefulList {
|
||||||
state: state,
|
state,
|
||||||
items,
|
items,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,10 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut url = String::new();
|
let mut url = String::new();
|
||||||
let frame_res = terminal.draw(|f| url = training_mod_tui::ui(f, &mut app))?;
|
let frame_res = terminal.draw(|f| url = training_mod_tui::ui(f, &mut app))?;
|
||||||
|
|
||||||
for (i, cell) in frame_res.buffer.content().into_iter().enumerate() {
|
for (i, cell) in frame_res.buffer.content().iter().enumerate() {
|
||||||
print!("{}", cell.symbol);
|
print!("{}", cell.symbol);
|
||||||
if i % frame_res.area.width as usize == frame_res.area.width as usize - 1 {
|
if i % frame_res.area.width as usize == frame_res.area.width as usize - 1 {
|
||||||
print!("\n");
|
println!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|
Loading…
Reference in a new issue