mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 10:54:16 +00:00
Refactor string representation for buttons and menus (#592)
* Refactor string representation for buttons and menus * Pass test cases * Update help text
This commit is contained in:
parent
f862abacaf
commit
10ebff5a6f
7 changed files with 462 additions and 357 deletions
|
@ -5,7 +5,6 @@ use lazy_static::lazy_static;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use skyline::nn::hid::GetNpadStyleSet;
|
use skyline::nn::hid::GetNpadStyleSet;
|
||||||
use training_mod_consts::MenuJsonStruct;
|
use training_mod_consts::MenuJsonStruct;
|
||||||
|
|
||||||
use training_mod_tui::AppPage;
|
use training_mod_tui::AppPage;
|
||||||
|
|
||||||
use crate::common::button_config::button_mapping;
|
use crate::common::button_config::button_mapping;
|
||||||
|
@ -95,7 +94,7 @@ enum DirectionButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref QUICK_MENU_APP: Mutex<training_mod_tui::App<'static>> = Mutex::new(
|
pub static ref QUICK_MENU_APP: Mutex<training_mod_tui::App> = Mutex::new(
|
||||||
training_mod_tui::App::new(unsafe { ui_menu(MENU) }, unsafe {
|
training_mod_tui::App::new(unsafe { ui_menu(MENU) }, unsafe {
|
||||||
(
|
(
|
||||||
ui_menu(DEFAULTS_MENU),
|
ui_menu(DEFAULTS_MENU),
|
||||||
|
|
39
src/lib.rs
39
src/lib.rs
|
@ -106,54 +106,25 @@ pub fn main() {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
|
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
|
||||||
notification(
|
notification("Open Menu".to_string(), MENU.menu_open.to_string(), 120);
|
||||||
"Open Menu".to_string(),
|
|
||||||
MENU.menu_open
|
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|button| button.as_str().unwrap())
|
|
||||||
.intersperse(" + ")
|
|
||||||
.collect(),
|
|
||||||
120,
|
|
||||||
);
|
|
||||||
notification(
|
notification(
|
||||||
"Save State".to_string(),
|
"Save State".to_string(),
|
||||||
MENU.save_state_save
|
MENU.save_state_save.to_string(),
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|button| button.as_str().unwrap())
|
|
||||||
.intersperse(" + ")
|
|
||||||
.collect(),
|
|
||||||
120,
|
120,
|
||||||
);
|
);
|
||||||
notification(
|
notification(
|
||||||
"Load State".to_string(),
|
"Load State".to_string(),
|
||||||
MENU.save_state_load
|
MENU.save_state_load.to_string(),
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|button| button.as_str().unwrap())
|
|
||||||
.intersperse(" + ")
|
|
||||||
.collect(),
|
|
||||||
120,
|
120,
|
||||||
);
|
);
|
||||||
notification(
|
notification(
|
||||||
"Input Record".to_string(),
|
"Input Record".to_string(),
|
||||||
MENU.input_record
|
MENU.input_record.to_string(),
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|button| button.as_str().unwrap())
|
|
||||||
.intersperse(" + ")
|
|
||||||
.collect(),
|
|
||||||
120,
|
120,
|
||||||
);
|
);
|
||||||
notification(
|
notification(
|
||||||
"Input Playback".to_string(),
|
"Input Playback".to_string(),
|
||||||
MENU.input_playback
|
MENU.input_playback.to_string(),
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|button| button.as_str().unwrap())
|
|
||||||
.intersperse(" + ")
|
|
||||||
.collect(),
|
|
||||||
120,
|
120,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ unsafe fn render_submenu_page(app: &App, root_pane: &Pane) {
|
||||||
let submenu = &list.items[list_idx];
|
let submenu = &list.items[list_idx];
|
||||||
let is_selected = list.state.selected().filter(|s| *s == list_idx).is_some();
|
let is_selected = list.state.selected().filter(|s| *s == list_idx).is_some();
|
||||||
|
|
||||||
title_text.set_text_string(submenu.submenu_title);
|
title_text.set_text_string(submenu.submenu_title.as_str());
|
||||||
|
|
||||||
// In the actual 'layout.arc' file, every icon image is stacked
|
// In the actual 'layout.arc' file, every icon image is stacked
|
||||||
// into a single container pane, with each image directly on top of another.
|
// into a single container pane, with each image directly on top of another.
|
||||||
|
@ -128,7 +128,7 @@ unsafe fn render_submenu_page(app: &App, root_pane: &Pane) {
|
||||||
.find_pane_by_name_recursive("FooterTxt")
|
.find_pane_by_name_recursive("FooterTxt")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_textbox()
|
.as_textbox()
|
||||||
.set_text_string(submenu.help_text);
|
.set_text_string(submenu.help_text.as_str());
|
||||||
|
|
||||||
title_bg_material.set_white_res_color(BG_LEFT_ON_WHITE_COLOR);
|
title_bg_material.set_white_res_color(BG_LEFT_ON_WHITE_COLOR);
|
||||||
title_bg_material.set_black_res_color(BG_LEFT_ON_BLACK_COLOR);
|
title_bg_material.set_black_res_color(BG_LEFT_ON_BLACK_COLOR);
|
||||||
|
@ -250,7 +250,7 @@ unsafe fn render_slider_page(app: &App, root_pane: &Pane) {
|
||||||
.find_pane_by_name_recursive("Header")
|
.find_pane_by_name_recursive("Header")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_textbox();
|
.as_textbox();
|
||||||
header.set_text_string(title);
|
header.set_text_string(title.as_str());
|
||||||
let min_button = slider_pane
|
let min_button = slider_pane
|
||||||
.find_pane_by_name_recursive("MinButton")
|
.find_pane_by_name_recursive("MinButton")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -411,7 +411,7 @@ pub unsafe fn draw(root_pane: &Pane) {
|
||||||
} else {
|
} else {
|
||||||
tab_selected + 1
|
tab_selected + 1
|
||||||
};
|
};
|
||||||
let tab_titles = [prev_tab, tab_selected, next_tab].map(|idx| app_tabs[idx]);
|
let tab_titles = [prev_tab, tab_selected, next_tab].map(|idx| app_tabs[idx].clone());
|
||||||
|
|
||||||
let is_gcc = (*common::menu::P1_CONTROLLER_STYLE.data_ptr()) == ControllerStyle::GCController;
|
let is_gcc = (*common::menu::P1_CONTROLLER_STYLE.data_ptr()) == ControllerStyle::GCController;
|
||||||
let button_mapping = if is_gcc {
|
let button_mapping = if is_gcc {
|
||||||
|
@ -471,7 +471,7 @@ pub unsafe fn draw(root_pane: &Pane) {
|
||||||
help_pane.set_default_material_colors();
|
help_pane.set_default_material_colors();
|
||||||
help_pane.set_color(255, 255, 0, 255);
|
help_pane.set_color(255, 255, 0, 255);
|
||||||
}
|
}
|
||||||
help_pane.set_text_string(tab_titles[idx]);
|
help_pane.set_text_string(tab_titles[idx].as_str());
|
||||||
});
|
});
|
||||||
[
|
[
|
||||||
(save_defaults_key, "SaveDefaults", "Save Defaults"),
|
(save_defaults_key, "SaveDefaults", "Save Defaults"),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![feature(iter_intersperse)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
|
@ -111,8 +112,8 @@ pub enum SubMenuType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubMenuType {
|
impl SubMenuType {
|
||||||
pub fn from_str(s: &str) -> SubMenuType {
|
pub fn from_string(s: &String) -> SubMenuType {
|
||||||
match s {
|
match s.as_str() {
|
||||||
"toggle" => SubMenuType::TOGGLE,
|
"toggle" => SubMenuType::TOGGLE,
|
||||||
"slider" => SubMenuType::SLIDER,
|
"slider" => SubMenuType::SLIDER,
|
||||||
_ => panic!("Unexpected SubMenuType!"),
|
_ => panic!("Unexpected SubMenuType!"),
|
||||||
|
@ -203,25 +204,25 @@ pub struct Slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
pub struct Toggle<'a> {
|
pub struct Toggle {
|
||||||
pub toggle_value: u32,
|
pub toggle_value: u32,
|
||||||
pub toggle_title: &'a str,
|
pub toggle_title: String,
|
||||||
pub checked: bool,
|
pub checked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
pub struct SubMenu<'a> {
|
pub struct SubMenu {
|
||||||
pub submenu_title: &'a str,
|
pub submenu_title: String,
|
||||||
pub submenu_id: &'a str,
|
pub submenu_id: String,
|
||||||
pub help_text: &'a str,
|
pub help_text: String,
|
||||||
pub is_single_option: bool,
|
pub is_single_option: bool,
|
||||||
pub toggles: Vec<Toggle<'a>>,
|
pub toggles: Vec<Toggle>,
|
||||||
pub slider: Option<Slider>,
|
pub slider: Option<Slider>,
|
||||||
pub _type: &'a str,
|
pub _type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SubMenu<'a> {
|
impl SubMenu {
|
||||||
pub fn add_toggle(&mut self, toggle_value: u32, toggle_title: &'a str, checked: bool) {
|
pub fn add_toggle(&mut self, toggle_value: u32, toggle_title: String, checked: bool) {
|
||||||
self.toggles.push(Toggle {
|
self.toggles.push(Toggle {
|
||||||
toggle_value,
|
toggle_value,
|
||||||
toggle_title,
|
toggle_title,
|
||||||
|
@ -229,12 +230,12 @@ impl<'a> SubMenu<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pub fn new_with_toggles<T: ToggleTrait>(
|
pub fn new_with_toggles<T: ToggleTrait>(
|
||||||
submenu_title: &'a str,
|
submenu_title: String,
|
||||||
submenu_id: &'a str,
|
submenu_id: String,
|
||||||
help_text: &'a str,
|
help_text: String,
|
||||||
is_single_option: bool,
|
is_single_option: bool,
|
||||||
initial_value: &u32,
|
initial_value: &u32,
|
||||||
) -> SubMenu<'a> {
|
) -> SubMenu {
|
||||||
let mut instance = SubMenu {
|
let mut instance = SubMenu {
|
||||||
submenu_title: submenu_title,
|
submenu_title: submenu_title,
|
||||||
submenu_id: submenu_id,
|
submenu_id: submenu_id,
|
||||||
|
@ -242,15 +243,15 @@ impl<'a> SubMenu<'a> {
|
||||||
is_single_option: is_single_option,
|
is_single_option: is_single_option,
|
||||||
toggles: Vec::new(),
|
toggles: Vec::new(),
|
||||||
slider: None,
|
slider: None,
|
||||||
_type: "toggle",
|
_type: "toggle".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let values = T::to_toggle_vals();
|
let values = T::to_toggle_vals();
|
||||||
let titles = T::to_toggle_strs();
|
let titles = T::to_toggle_strings();
|
||||||
for i in 0..values.len() {
|
for i in 0..values.len() {
|
||||||
let checked: bool =
|
let checked: bool =
|
||||||
(values[i] & initial_value) > 0 || (!values[i] == 0 && initial_value == &0);
|
(values[i] & initial_value) > 0 || (!values[i] == 0 && initial_value == &0);
|
||||||
instance.add_toggle(values[i], titles[i], checked);
|
instance.add_toggle(values[i], titles[i].clone(), checked);
|
||||||
}
|
}
|
||||||
// Select the first option if there's nothing selected atm but it's a single option submenu
|
// Select the first option if there's nothing selected atm but it's a single option submenu
|
||||||
if is_single_option && instance.toggles.iter().all(|t| !t.checked) {
|
if is_single_option && instance.toggles.iter().all(|t| !t.checked) {
|
||||||
|
@ -259,12 +260,12 @@ impl<'a> SubMenu<'a> {
|
||||||
instance
|
instance
|
||||||
}
|
}
|
||||||
pub fn new_with_slider<S: SliderTrait>(
|
pub fn new_with_slider<S: SliderTrait>(
|
||||||
submenu_title: &'a str,
|
submenu_title: String,
|
||||||
submenu_id: &'a str,
|
submenu_id: String,
|
||||||
help_text: &'a str,
|
help_text: String,
|
||||||
initial_lower_value: &u32,
|
initial_lower_value: &u32,
|
||||||
initial_upper_value: &u32,
|
initial_upper_value: &u32,
|
||||||
) -> SubMenu<'a> {
|
) -> SubMenu {
|
||||||
let min_max = S::get_limits();
|
let min_max = S::get_limits();
|
||||||
SubMenu {
|
SubMenu {
|
||||||
submenu_title: submenu_title,
|
submenu_title: submenu_title,
|
||||||
|
@ -278,31 +279,31 @@ impl<'a> SubMenu<'a> {
|
||||||
abs_min: min_max.0,
|
abs_min: min_max.0,
|
||||||
abs_max: min_max.1,
|
abs_max: min_max.1,
|
||||||
}),
|
}),
|
||||||
_type: "slider",
|
_type: "slider".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone)]
|
#[derive(Serialize, Clone)]
|
||||||
pub struct Tab<'a> {
|
pub struct Tab {
|
||||||
pub tab_id: &'a str,
|
pub tab_id: String,
|
||||||
pub tab_title: &'a str,
|
pub tab_title: String,
|
||||||
pub tab_submenus: Vec<SubMenu<'a>>,
|
pub tab_submenus: Vec<SubMenu>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tab<'a> {
|
impl Tab {
|
||||||
pub fn add_submenu_with_toggles<T: ToggleTrait>(
|
pub fn add_submenu_with_toggles<T: ToggleTrait>(
|
||||||
&mut self,
|
&mut self,
|
||||||
submenu_title: &'a str,
|
submenu_title: String,
|
||||||
submenu_id: &'a str,
|
submenu_id: String,
|
||||||
help_text: &'a str,
|
help_text: String,
|
||||||
is_single_option: bool,
|
is_single_option: bool,
|
||||||
initial_value: &u32,
|
initial_value: &u32,
|
||||||
) {
|
) {
|
||||||
self.tab_submenus.push(SubMenu::new_with_toggles::<T>(
|
self.tab_submenus.push(SubMenu::new_with_toggles::<T>(
|
||||||
submenu_title,
|
submenu_title.to_string(),
|
||||||
submenu_id,
|
submenu_id.to_string(),
|
||||||
help_text,
|
help_text.to_string(),
|
||||||
is_single_option,
|
is_single_option,
|
||||||
initial_value,
|
initial_value,
|
||||||
));
|
));
|
||||||
|
@ -310,16 +311,16 @@ impl<'a> Tab<'a> {
|
||||||
|
|
||||||
pub fn add_submenu_with_slider<S: SliderTrait>(
|
pub fn add_submenu_with_slider<S: SliderTrait>(
|
||||||
&mut self,
|
&mut self,
|
||||||
submenu_title: &'a str,
|
submenu_title: String,
|
||||||
submenu_id: &'a str,
|
submenu_id: String,
|
||||||
help_text: &'a str,
|
help_text: String,
|
||||||
initial_lower_value: &u32,
|
initial_lower_value: &u32,
|
||||||
initial_upper_value: &u32,
|
initial_upper_value: &u32,
|
||||||
) {
|
) {
|
||||||
self.tab_submenus.push(SubMenu::new_with_slider::<S>(
|
self.tab_submenus.push(SubMenu::new_with_slider::<S>(
|
||||||
submenu_title,
|
submenu_title.to_string(),
|
||||||
submenu_id,
|
submenu_id.to_string(),
|
||||||
help_text,
|
help_text.to_string(),
|
||||||
initial_lower_value,
|
initial_lower_value,
|
||||||
initial_upper_value,
|
initial_upper_value,
|
||||||
))
|
))
|
||||||
|
@ -327,542 +328,555 @@ impl<'a> Tab<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone)]
|
#[derive(Serialize, Clone)]
|
||||||
pub struct UiMenu<'a> {
|
pub struct UiMenu {
|
||||||
pub tabs: Vec<Tab<'a>>,
|
pub tabs: Vec<Tab>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> {
|
pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu {
|
||||||
let mut overall_menu = UiMenu { tabs: Vec::new() };
|
let mut overall_menu = UiMenu { tabs: Vec::new() };
|
||||||
|
|
||||||
let mut mash_tab = Tab {
|
let mut mash_tab = Tab {
|
||||||
tab_id: "mash",
|
tab_id: "mash".to_string(),
|
||||||
tab_title: "Mash Settings",
|
tab_title: "Mash Settings".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
mash_tab.add_submenu_with_toggles::<Action>(
|
mash_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Mash Toggles",
|
"Mash Toggles".to_string(),
|
||||||
"mash_state",
|
"mash_state".to_string(),
|
||||||
"Mash Toggles: Actions to be performed as soon as possible",
|
"Mash Toggles: Actions to be performed as soon as possible".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.mash_state.bits()),
|
&(menu.mash_state.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<Action>(
|
mash_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Followup Toggles",
|
"Followup Toggles".to_string(),
|
||||||
"follow_up",
|
"follow_up".to_string(),
|
||||||
"Followup Toggles: Actions to be performed after a Mash option",
|
"Followup Toggles: Actions to be performed after a Mash option".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.follow_up.bits()),
|
&(menu.follow_up.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<MashTrigger>(
|
mash_tab.add_submenu_with_toggles::<MashTrigger>(
|
||||||
"Mash Triggers",
|
"Mash Triggers".to_string(),
|
||||||
"mash_triggers",
|
"mash_triggers".to_string(),
|
||||||
"Mash triggers: Configure what causes the CPU to perform a Mash option",
|
"Mash triggers: Configure what causes the CPU to perform a Mash option".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.mash_triggers.bits()),
|
&(menu.mash_triggers.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<AttackAngle>(
|
mash_tab.add_submenu_with_toggles::<AttackAngle>(
|
||||||
"Attack Angle",
|
"Attack Angle".to_string(),
|
||||||
"attack_angle",
|
"attack_angle".to_string(),
|
||||||
"Attack Angle: For attacks that can be angled, such as some forward tilts",
|
"Attack Angle: For attacks that can be angled, such as some forward tilts".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.attack_angle.bits()),
|
&(menu.attack_angle.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<ThrowOption>(
|
mash_tab.add_submenu_with_toggles::<ThrowOption>(
|
||||||
"Throw Options",
|
"Throw Options".to_string(),
|
||||||
"throw_state",
|
"throw_state".to_string(),
|
||||||
"Throw Options: Throw to be performed when a grab is landed",
|
"Throw Options: Throw to be performed when a grab is landed".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.throw_state.bits()),
|
&(menu.throw_state.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<MedDelay>(
|
mash_tab.add_submenu_with_toggles::<MedDelay>(
|
||||||
"Throw Delay",
|
"Throw Delay".to_string(),
|
||||||
"throw_delay",
|
"throw_delay".to_string(),
|
||||||
"Throw Delay: How many frames to delay the throw option",
|
"Throw Delay: How many frames to delay the throw option".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.throw_delay.bits()),
|
&(menu.throw_delay.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<MedDelay>(
|
mash_tab.add_submenu_with_toggles::<MedDelay>(
|
||||||
"Pummel Delay",
|
"Pummel Delay".to_string(),
|
||||||
"pummel_delay",
|
"pummel_delay".to_string(),
|
||||||
"Pummel Delay: How many frames after a grab to wait before starting to pummel",
|
"Pummel Delay: How many frames after a grab to wait before starting to pummel".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.pummel_delay.bits()),
|
&(menu.pummel_delay.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<BoolFlag>(
|
mash_tab.add_submenu_with_toggles::<BoolFlag>(
|
||||||
"Falling Aerials",
|
"Falling Aerials".to_string(),
|
||||||
"falling_aerials",
|
"falling_aerials".to_string(),
|
||||||
"Falling Aerials: Should aerials be performed when rising or when falling",
|
"Falling Aerials: Should aerials be performed when rising or when falling".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.falling_aerials.bits()),
|
&(menu.falling_aerials.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<BoolFlag>(
|
mash_tab.add_submenu_with_toggles::<BoolFlag>(
|
||||||
"Full Hop",
|
"Full Hop".to_string(),
|
||||||
"full_hop",
|
"full_hop".to_string(),
|
||||||
"Full Hop: Should the CPU perform a full hop or a short hop",
|
"Full Hop: Should the CPU perform a full hop or a short hop".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.full_hop.bits()),
|
&(menu.full_hop.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<Delay>(
|
mash_tab.add_submenu_with_toggles::<Delay>(
|
||||||
"Aerial Delay",
|
"Aerial Delay".to_string(),
|
||||||
"aerial_delay",
|
"aerial_delay".to_string(),
|
||||||
"Aerial Delay: How long to delay a Mash aerial attack",
|
"Aerial Delay: How long to delay a Mash aerial attack".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.aerial_delay.bits()),
|
&(menu.aerial_delay.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<BoolFlag>(
|
mash_tab.add_submenu_with_toggles::<BoolFlag>(
|
||||||
"Fast Fall",
|
"Fast Fall".to_string(),
|
||||||
"fast_fall",
|
"fast_fall".to_string(),
|
||||||
"Fast Fall: Should the CPU fastfall during a jump",
|
"Fast Fall: Should the CPU fastfall during a jump".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.fast_fall.bits()),
|
&(menu.fast_fall.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<Delay>(
|
mash_tab.add_submenu_with_toggles::<Delay>(
|
||||||
"Fast Fall Delay",
|
"Fast Fall Delay".to_string(),
|
||||||
"fast_fall_delay",
|
"fast_fall_delay".to_string(),
|
||||||
"Fast Fall Delay: How many frames the CPU should delay their fastfall",
|
"Fast Fall Delay: How many frames the CPU should delay their fastfall".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.fast_fall_delay.bits()),
|
&(menu.fast_fall_delay.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<Delay>(
|
mash_tab.add_submenu_with_toggles::<Delay>(
|
||||||
"OoS Offset",
|
"OoS Offset".to_string(),
|
||||||
"oos_offset",
|
"oos_offset".to_string(),
|
||||||
"OoS Offset: How many times the CPU shield can be hit before performing a Mash option",
|
"OoS Offset: How many times the CPU shield can be hit before performing a Mash option"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.oos_offset.bits()),
|
&(menu.oos_offset.bits()),
|
||||||
);
|
);
|
||||||
mash_tab.add_submenu_with_toggles::<Delay>(
|
mash_tab.add_submenu_with_toggles::<Delay>(
|
||||||
"Reaction Time",
|
"Reaction Time".to_string(),
|
||||||
"reaction_time",
|
"reaction_time".to_string(),
|
||||||
"Reaction Time: How many frames to delay before performing a mash option",
|
"Reaction Time: How many frames to delay before performing a mash option".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.reaction_time.bits()),
|
&(menu.reaction_time.bits()),
|
||||||
);
|
);
|
||||||
overall_menu.tabs.push(mash_tab);
|
overall_menu.tabs.push(mash_tab);
|
||||||
|
|
||||||
let mut override_tab = Tab {
|
let mut override_tab = Tab {
|
||||||
tab_id: "override",
|
tab_id: "override".to_string(),
|
||||||
tab_title: "Override Settings",
|
tab_title: "Override Settings".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Ledge Neutral Getup",
|
"Ledge Neutral Getup".to_string(),
|
||||||
"ledge_neutral_override",
|
"ledge_neutral_override".to_string(),
|
||||||
"Neutral Getup Override: Mash Actions to be performed after a Neutral Getup from ledge",
|
"Neutral Getup Override: Mash Actions to be performed after a Neutral Getup from ledge"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.ledge_neutral_override.bits()),
|
&(menu.ledge_neutral_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Ledge Roll",
|
"Ledge Roll".to_string(),
|
||||||
"ledge_roll_override",
|
"ledge_roll_override".to_string(),
|
||||||
"Ledge Roll Override: Mash Actions to be performed after a Roll Getup from ledge",
|
"Ledge Roll Override: Mash Actions to be performed after a Roll Getup from ledge"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.ledge_roll_override.bits()),
|
&(menu.ledge_roll_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Ledge Jump",
|
"Ledge Jump".to_string(),
|
||||||
"ledge_jump_override",
|
"ledge_jump_override".to_string(),
|
||||||
"Ledge Jump Override: Mash Actions to be performed after a Jump Getup from ledge",
|
"Ledge Jump Override: Mash Actions to be performed after a Jump Getup from ledge"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.ledge_jump_override.bits()),
|
&(menu.ledge_jump_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Ledge Attack",
|
"Ledge Attack".to_string(),
|
||||||
"ledge_attack_override",
|
"ledge_attack_override".to_string(),
|
||||||
"Ledge Attack Override: Mash Actions to be performed after a Getup Attack from ledge",
|
"Ledge Attack Override: Mash Actions to be performed after a Getup Attack from ledge"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.ledge_attack_override.bits()),
|
&(menu.ledge_attack_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Tech Action",
|
"Tech Action".to_string(),
|
||||||
"tech_action_override",
|
"tech_action_override".to_string(),
|
||||||
"Tech Action Override: Mash Actions to be performed after any tech action",
|
"Tech Action Override: Mash Actions to be performed after any tech action".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.tech_action_override.bits()),
|
&(menu.tech_action_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Clatter",
|
"Clatter".to_string(),
|
||||||
"clatter_override",
|
"clatter_override".to_string(),
|
||||||
"Clatter Override: Mash Actions to be performed after leaving a clatter situation (grab, bury, etc)",
|
"Clatter Override: Mash Actions to be performed after leaving a clatter situation (grab.to_string(), bury, etc)".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.clatter_override.bits()),
|
&(menu.clatter_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Tumble",
|
"Tumble".to_string(),
|
||||||
"tumble_override",
|
"tumble_override".to_string(),
|
||||||
"Tumble Override: Mash Actions to be performed after exiting a tumble state",
|
"Tumble Override: Mash Actions to be performed after exiting a tumble state".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.tumble_override.bits()),
|
&(menu.tumble_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Hitstun",
|
"Hitstun".to_string(),
|
||||||
"hitstun_override",
|
"hitstun_override".to_string(),
|
||||||
"Hitstun Override: Mash Actions to be performed after exiting a hitstun state",
|
"Hitstun Override: Mash Actions to be performed after exiting a hitstun state".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.hitstun_override.bits()),
|
&(menu.hitstun_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Parry",
|
"Parry".to_string(),
|
||||||
"parry_override",
|
"parry_override".to_string(),
|
||||||
"Parry Override: Mash Actions to be performed after a parry",
|
"Parry Override: Mash Actions to be performed after a parry".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.parry_override.bits()),
|
&(menu.parry_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Shieldstun",
|
"Shieldstun".to_string(),
|
||||||
"shieldstun_override",
|
"shieldstun_override".to_string(),
|
||||||
"Shieldstun Override: Mash Actions to be performed after exiting a shieldstun state",
|
"Shieldstun Override: Mash Actions to be performed after exiting a shieldstun state"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.shieldstun_override.bits()),
|
&(menu.shieldstun_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Footstool",
|
"Footstool".to_string(),
|
||||||
"footstool_override",
|
"footstool_override".to_string(),
|
||||||
"Footstool Override: Mash Actions to be performed after exiting a footstool state",
|
"Footstool Override: Mash Actions to be performed after exiting a footstool state"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.footstool_override.bits()),
|
&(menu.footstool_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Landing",
|
"Landing".to_string(),
|
||||||
"landing_override",
|
"landing_override".to_string(),
|
||||||
"Landing Override: Mash Actions to be performed after landing on the ground",
|
"Landing Override: Mash Actions to be performed after landing on the ground".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.landing_override.bits()),
|
&(menu.landing_override.bits()),
|
||||||
);
|
);
|
||||||
override_tab.add_submenu_with_toggles::<Action>(
|
override_tab.add_submenu_with_toggles::<Action>(
|
||||||
"Ledge Trump",
|
"Ledge Trump".to_string(),
|
||||||
"trump_override",
|
"trump_override".to_string(),
|
||||||
"Ledge Trump Override: Mash Actions to be performed after leaving a ledgetrump state",
|
"Ledge Trump Override: Mash Actions to be performed after leaving a ledgetrump state"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.trump_override.bits()),
|
&(menu.trump_override.bits()),
|
||||||
);
|
);
|
||||||
overall_menu.tabs.push(override_tab);
|
overall_menu.tabs.push(override_tab);
|
||||||
|
|
||||||
let mut defensive_tab = Tab {
|
let mut defensive_tab = Tab {
|
||||||
tab_id: "defensive",
|
tab_id: "defensive".to_string(),
|
||||||
tab_title: "Defensive Settings",
|
tab_title: "Defensive Settings".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
defensive_tab.add_submenu_with_toggles::<Direction>(
|
defensive_tab.add_submenu_with_toggles::<Direction>(
|
||||||
"Airdodge Direction",
|
"Airdodge Direction".to_string(),
|
||||||
"air_dodge_dir",
|
"air_dodge_dir".to_string(),
|
||||||
"Airdodge Direction: Direction to angle airdodges",
|
"Airdodge Direction: Direction to angle airdodges".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.air_dodge_dir.bits()),
|
&(menu.air_dodge_dir.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<Direction>(
|
defensive_tab.add_submenu_with_toggles::<Direction>(
|
||||||
"DI Direction",
|
"DI Direction".to_string(),
|
||||||
"di_state",
|
"di_state".to_string(),
|
||||||
"DI Direction: Direction to angle the directional influence during hitlag",
|
"DI Direction: Direction to angle the directional influence during hitlag".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.di_state.bits()),
|
&(menu.di_state.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<Direction>(
|
defensive_tab.add_submenu_with_toggles::<Direction>(
|
||||||
"SDI Direction",
|
"SDI Direction".to_string(),
|
||||||
"sdi_state",
|
"sdi_state".to_string(),
|
||||||
"SDI Direction: Direction to angle the smash directional influence during hitlag",
|
"SDI Direction: Direction to angle the smash directional influence during hitlag"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.sdi_state.bits()),
|
&(menu.sdi_state.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<SdiFrequency>(
|
defensive_tab.add_submenu_with_toggles::<SdiFrequency>(
|
||||||
"SDI Strength",
|
"SDI Strength".to_string(),
|
||||||
"sdi_strength",
|
"sdi_strength".to_string(),
|
||||||
"SDI Strength: Relative strength of the smash directional influence inputs",
|
"SDI Strength: Relative strength of the smash directional influence inputs".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.sdi_strength as u32),
|
&(menu.sdi_strength as u32),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<ClatterFrequency>(
|
defensive_tab.add_submenu_with_toggles::<ClatterFrequency>(
|
||||||
"Clatter Strength",
|
"Clatter Strength".to_string(),
|
||||||
"clatter_strength",
|
"clatter_strength".to_string(),
|
||||||
"Clatter Strength: Configure how rapidly the CPU will mash out of grabs, buries, etc.",
|
"Clatter Strength: Configure how rapidly the CPU will mash out of grabs, buries, etc."
|
||||||
|
.to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.clatter_strength as u32),
|
&(menu.clatter_strength as u32),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<LedgeOption>(
|
defensive_tab.add_submenu_with_toggles::<LedgeOption>(
|
||||||
"Ledge Options",
|
"Ledge Options".to_string(),
|
||||||
"ledge_state",
|
"ledge_state".to_string(),
|
||||||
"Ledge Options: Actions to be taken when on the ledge",
|
"Ledge Options: Actions to be taken when on the ledge".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.ledge_state.bits()),
|
&(menu.ledge_state.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<LongDelay>(
|
defensive_tab.add_submenu_with_toggles::<LongDelay>(
|
||||||
"Ledge Delay",
|
"Ledge Delay".to_string(),
|
||||||
"ledge_delay",
|
"ledge_delay".to_string(),
|
||||||
"Ledge Delay: How many frames to delay the ledge option",
|
"Ledge Delay: How many frames to delay the ledge option".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.ledge_delay.bits()),
|
&(menu.ledge_delay.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<TechFlags>(
|
defensive_tab.add_submenu_with_toggles::<TechFlags>(
|
||||||
"Tech Options",
|
"Tech Options".to_string(),
|
||||||
"tech_state",
|
"tech_state".to_string(),
|
||||||
"Tech Options: Actions to take when slammed into a hard surface",
|
"Tech Options: Actions to take when slammed into a hard surface".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.tech_state.bits()),
|
&(menu.tech_state.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<MissTechFlags>(
|
defensive_tab.add_submenu_with_toggles::<MissTechFlags>(
|
||||||
"Mistech Options",
|
"Mistech Options".to_string(),
|
||||||
"miss_tech_state",
|
"miss_tech_state".to_string(),
|
||||||
"Mistech Options: Actions to take after missing a tech",
|
"Mistech Options: Actions to take after missing a tech".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.miss_tech_state.bits()),
|
&(menu.miss_tech_state.bits()),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<Shield>(
|
defensive_tab.add_submenu_with_toggles::<Shield>(
|
||||||
"Shield Toggles",
|
"Shield Toggles".to_string(),
|
||||||
"shield_state",
|
"shield_state".to_string(),
|
||||||
"Shield Toggles: CPU Shield Behavior",
|
"Shield Toggles: CPU Shield Behavior".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.shield_state as u32),
|
&(menu.shield_state as u32),
|
||||||
);
|
);
|
||||||
defensive_tab.add_submenu_with_toggles::<Direction>(
|
defensive_tab.add_submenu_with_toggles::<Direction>(
|
||||||
"Shield Tilt",
|
"Shield Tilt".to_string(),
|
||||||
"shield_tilt",
|
"shield_tilt".to_string(),
|
||||||
"Shield Tilt: Direction to tilt the shield",
|
"Shield Tilt: Direction to tilt the shield".to_string(),
|
||||||
false, // TODO: Should this be true?
|
false, // TODO: Should this be true?
|
||||||
&(menu.shield_tilt.bits()),
|
&(menu.shield_tilt.bits()),
|
||||||
);
|
);
|
||||||
|
|
||||||
defensive_tab.add_submenu_with_toggles::<OnOff>(
|
defensive_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Crouch",
|
"Crouch".to_string(),
|
||||||
"crouch",
|
"crouch".to_string(),
|
||||||
"Crouch: Have the CPU crouch when on the ground",
|
"Crouch: Have the CPU crouch when on the ground".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.crouch as u32),
|
&(menu.crouch as u32),
|
||||||
);
|
);
|
||||||
overall_menu.tabs.push(defensive_tab);
|
overall_menu.tabs.push(defensive_tab);
|
||||||
|
|
||||||
let mut save_state_tab = Tab {
|
let mut save_state_tab = Tab {
|
||||||
tab_id: "save_state",
|
tab_id: "save_state".to_string(),
|
||||||
tab_title: "Save States",
|
tab_title: "Save States".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
save_state_tab.add_submenu_with_toggles::<SaveStateMirroring>(
|
save_state_tab.add_submenu_with_toggles::<SaveStateMirroring>(
|
||||||
"Mirroring",
|
"Mirroring".to_string(),
|
||||||
"save_state_mirroring",
|
"save_state_mirroring".to_string(),
|
||||||
"Mirroring: Flips save states in the left-right direction across the stage center",
|
"Mirroring: Flips save states in the left-right direction across the stage center"
|
||||||
|
.to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.save_state_mirroring as u32),
|
&(menu.save_state_mirroring as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Auto Save States",
|
"Auto Save States".to_string(),
|
||||||
"save_state_autoload",
|
"save_state_autoload".to_string(),
|
||||||
"Auto Save States: Load save state when any fighter dies",
|
"Auto Save States: Load save state when any fighter dies".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.save_state_autoload as u32),
|
&(menu.save_state_autoload as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<SaveDamage>(
|
save_state_tab.add_submenu_with_toggles::<SaveDamage>(
|
||||||
"Save Dmg (CPU)",
|
"Save Dmg (CPU)".to_string(),
|
||||||
"save_damage_cpu",
|
"save_damage_cpu".to_string(),
|
||||||
"Save Damage: Should save states retain CPU damage",
|
"Save Damage: Should save states retain CPU damage".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.save_damage_cpu.bits()),
|
&(menu.save_damage_cpu.bits()),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_slider::<DamagePercent>(
|
save_state_tab.add_submenu_with_slider::<DamagePercent>(
|
||||||
"Dmg Range (CPU)",
|
"Dmg Range (CPU)".to_string(),
|
||||||
"save_damage_limits_cpu",
|
"save_damage_limits_cpu".to_string(),
|
||||||
"Limits on random damage to apply to the CPU when loading a save state",
|
"Limits on random damage to apply to the CPU when loading a save state".to_string(),
|
||||||
&(menu.save_damage_limits_cpu.0 as u32),
|
&(menu.save_damage_limits_cpu.0 as u32),
|
||||||
&(menu.save_damage_limits_cpu.1 as u32),
|
&(menu.save_damage_limits_cpu.1 as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<SaveDamage>(
|
save_state_tab.add_submenu_with_toggles::<SaveDamage>(
|
||||||
"Save Dmg (Player)",
|
"Save Dmg (Player)".to_string(),
|
||||||
"save_damage_player",
|
"save_damage_player".to_string(),
|
||||||
"Save Damage: Should save states retain player damage",
|
"Save Damage: Should save states retain player damage".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.save_damage_player.bits() as u32),
|
&(menu.save_damage_player.bits() as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_slider::<DamagePercent>(
|
save_state_tab.add_submenu_with_slider::<DamagePercent>(
|
||||||
"Dmg Range (Player)",
|
"Dmg Range (Player)".to_string(),
|
||||||
"save_damage_limits_player",
|
"save_damage_limits_player".to_string(),
|
||||||
"Limits on random damage to apply to the player when loading a save state",
|
"Limits on random damage to apply to the player when loading a save state".to_string(),
|
||||||
&(menu.save_damage_limits_player.0 as u32),
|
&(menu.save_damage_limits_player.0 as u32),
|
||||||
&(menu.save_damage_limits_player.1 as u32),
|
&(menu.save_damage_limits_player.1 as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Enable Save States",
|
"Enable Save States".to_string(),
|
||||||
"save_state_enable",
|
"save_state_enable".to_string(),
|
||||||
"Save States: Enable save states! Save a state with Shield+Down Taunt, load it with Shield+Up Taunt.",
|
"Save States: Enable save states! Save a state with Shield+Down Taunt, load it with Shield+Up Taunt.".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.save_state_enable as u32),
|
&(menu.save_state_enable as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<SaveStateSlot>(
|
save_state_tab.add_submenu_with_toggles::<SaveStateSlot>(
|
||||||
"Save State Slot",
|
"Save State Slot".to_string(),
|
||||||
"save_state_slot",
|
"save_state_slot".to_string(),
|
||||||
"Save State Slot: Save and load states from different slots.",
|
"Save State Slot: Save and load states from different slots.".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.save_state_slot as u32),
|
&(menu.save_state_slot as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Randomize Slots",
|
"Randomize Slots".to_string(),
|
||||||
"randomize_slots",
|
"randomize_slots".to_string(),
|
||||||
"Randomize Slots: Randomize slot when loading save state.",
|
"Randomize Slots: Randomize slot when loading save state.".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.randomize_slots as u32),
|
&(menu.randomize_slots as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<CharacterItem>(
|
save_state_tab.add_submenu_with_toggles::<CharacterItem>(
|
||||||
"Character Item",
|
"Character Item".to_string(),
|
||||||
"character_item",
|
"character_item".to_string(),
|
||||||
"Character Item: The item to give to the player's fighter when loading a save state",
|
"Character Item: The item to give to the player's fighter when loading a save state"
|
||||||
|
.to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.character_item as u32),
|
&(menu.character_item as u32),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<BuffOption>(
|
save_state_tab.add_submenu_with_toggles::<BuffOption>(
|
||||||
"Buff Options",
|
"Buff Options".to_string(),
|
||||||
"buff_state",
|
"buff_state".to_string(),
|
||||||
"Buff Options: Buff(s) to be applied to the respective fighters when loading a save state",
|
"Buff Options: Buff(s) to be applied to the respective fighters when loading a save state"
|
||||||
|
.to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.buff_state.bits()),
|
&(menu.buff_state.bits()),
|
||||||
);
|
);
|
||||||
save_state_tab.add_submenu_with_toggles::<PlaybackSlot>(
|
save_state_tab.add_submenu_with_toggles::<PlaybackSlot>(
|
||||||
"Save State Playback",
|
"Save State Playback".to_string(),
|
||||||
"save_state_playback",
|
"save_state_playback".to_string(),
|
||||||
"Save State Playback: Choose which slots to playback input recording upon loading a save state",
|
"Save State Playback: Choose which slots to playback input recording upon loading a save state".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.save_state_playback.bits() as u32),
|
&(menu.save_state_playback.bits() as u32),
|
||||||
);
|
);
|
||||||
overall_menu.tabs.push(save_state_tab);
|
overall_menu.tabs.push(save_state_tab);
|
||||||
|
|
||||||
let mut misc_tab = Tab {
|
let mut misc_tab = Tab {
|
||||||
tab_id: "misc",
|
tab_id: "misc".to_string(),
|
||||||
tab_title: "Misc Settings",
|
tab_title: "Misc Settings".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
misc_tab.add_submenu_with_toggles::<OnOff>(
|
misc_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Frame Advantage",
|
"Frame Advantage".to_string(),
|
||||||
"frame_advantage",
|
"frame_advantage".to_string(),
|
||||||
"Frame Advantage: Display the time difference between when the player is actionable and the CPU is actionable",
|
"Frame Advantage: Display the time difference between when the player is actionable and the CPU is actionable".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.frame_advantage as u32),
|
&(menu.frame_advantage as u32),
|
||||||
);
|
);
|
||||||
misc_tab.add_submenu_with_toggles::<OnOff>(
|
misc_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Hitbox Visualization",
|
"Hitbox Visualization".to_string(),
|
||||||
"hitbox_vis",
|
"hitbox_vis".to_string(),
|
||||||
"Hitbox Visualization: Display a visual representation for active hitboxes (hides other visual effects)",
|
"Hitbox Visualization: Display a visual representation for active hitboxes (hides other visual effects)".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.hitbox_vis as u32),
|
&(menu.hitbox_vis as u32),
|
||||||
);
|
);
|
||||||
misc_tab.add_submenu_with_toggles::<Delay>(
|
misc_tab.add_submenu_with_toggles::<Delay>(
|
||||||
"Input Delay",
|
"Input Delay".to_string(),
|
||||||
"input_delay",
|
"input_delay".to_string(),
|
||||||
"Input Delay: Frames to delay player inputs by",
|
"Input Delay: Frames to delay player inputs by".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.input_delay.bits()),
|
&(menu.input_delay.bits()),
|
||||||
);
|
);
|
||||||
misc_tab.add_submenu_with_toggles::<OnOff>(
|
misc_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Stage Hazards",
|
"Stage Hazards".to_string(),
|
||||||
"stage_hazards",
|
"stage_hazards".to_string(),
|
||||||
"Stage Hazards: Turn stage hazards on/off",
|
"Stage Hazards: Turn stage hazards on/off".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.stage_hazards as u32),
|
&(menu.stage_hazards as u32),
|
||||||
);
|
);
|
||||||
misc_tab.add_submenu_with_toggles::<OnOff>(
|
misc_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"HUD",
|
"HUD".to_string(),
|
||||||
"hud",
|
"hud".to_string(),
|
||||||
"HUD: Show/hide elements of the UI",
|
"HUD: Show/hide elements of the UI".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.hud as u32),
|
&(menu.hud as u32),
|
||||||
);
|
);
|
||||||
overall_menu.tabs.push(misc_tab);
|
overall_menu.tabs.push(misc_tab);
|
||||||
|
|
||||||
let mut input_tab = Tab {
|
let mut input_tab = Tab {
|
||||||
tab_id: "input",
|
tab_id: "input".to_string(),
|
||||||
tab_title: "Input Recording",
|
tab_title: "Input Recording".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
input_tab.add_submenu_with_toggles::<RecordSlot>(
|
input_tab.add_submenu_with_toggles::<RecordSlot>(
|
||||||
"Recording Slot",
|
"Recording Slot".to_string(),
|
||||||
"recording_slot",
|
"recording_slot".to_string(),
|
||||||
"Recording Slot: Choose which slot to record into",
|
"Recording Slot: Choose which slot to record into".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.recording_slot as u32),
|
&(menu.recording_slot as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<RecordTrigger>(
|
input_tab.add_submenu_with_toggles::<RecordTrigger>(
|
||||||
"Recording Trigger",
|
"Recording Trigger".to_string(),
|
||||||
"record_trigger",
|
"record_trigger".to_string(),
|
||||||
"Recording Trigger: Whether to begin recording via button combination (Default: Attack+Left Taunt) or upon loading a Save State",
|
format!("Recording Trigger: Whether to begin recording via button combination ({}) or upon loading a Save State", menu.input_record.combination_string()),
|
||||||
false,
|
false,
|
||||||
&(menu.record_trigger.bits() as u32),
|
&(menu.record_trigger.bits() as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<RecordingFrames>(
|
input_tab.add_submenu_with_toggles::<RecordingFrames>(
|
||||||
"Recording Frames",
|
"Recording Frames".to_string(),
|
||||||
"recording_frames",
|
"recording_frames".to_string(),
|
||||||
"Recording Frames: Number of frames to record for in the current slot",
|
"Recording Frames: Number of frames to record for in the current slot".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.recording_frames as u32),
|
&(menu.recording_frames as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<PlaybackSlot>(
|
input_tab.add_submenu_with_toggles::<PlaybackSlot>(
|
||||||
"Playback Button Combination",
|
"Playback Button Combination".to_string(),
|
||||||
"playback_button_combination",
|
"playback_button_combination".to_string(),
|
||||||
"Playback Button Combination: Choose which slots to playback input recording upon pressing button combination (Default: Attack+Right Taunt)",
|
format!("Playback Button Combination: Choose which slots to playback input recording upon pressing button combination ({})", menu.input_playback.combination_string()),
|
||||||
false,
|
false,
|
||||||
&(menu.playback_button_combination.bits() as u32),
|
&(menu.playback_button_combination.bits() as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<HitstunPlayback>(
|
input_tab.add_submenu_with_toggles::<HitstunPlayback>(
|
||||||
"Playback Hitstun Timing",
|
"Playback Hitstun Timing".to_string(),
|
||||||
"hitstun_playback",
|
"hitstun_playback".to_string(),
|
||||||
"Playback Hitstun Timing: When to begin playing back inputs when a hitstun mash trigger occurs",
|
"Playback Hitstun Timing: When to begin playing back inputs when a hitstun mash trigger occurs".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.hitstun_playback as u32),
|
&(menu.hitstun_playback as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<OnOff>(
|
input_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Playback Mash Interrupt",
|
"Playback Mash Interrupt".to_string(),
|
||||||
"playback_mash",
|
"playback_mash".to_string(),
|
||||||
"Playback Mash Interrupt: End input playback when a mash trigger occurs",
|
"Playback Mash Interrupt: End input playback when a mash trigger occurs".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.playback_mash as u32),
|
&(menu.playback_mash as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<OnOff>(
|
input_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Playback Loop",
|
"Playback Loop".to_string(),
|
||||||
"playback_loop",
|
"playback_loop".to_string(),
|
||||||
"Playback Loop: Repeat triggered input playbacks indefinitely",
|
"Playback Loop: Repeat triggered input playbacks indefinitely".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.playback_loop as u32),
|
&(menu.playback_loop as u32),
|
||||||
);
|
);
|
||||||
input_tab.add_submenu_with_toggles::<OnOff>(
|
input_tab.add_submenu_with_toggles::<OnOff>(
|
||||||
"Recording Crop",
|
"Recording Crop".to_string(),
|
||||||
"recording_crop",
|
"recording_crop".to_string(),
|
||||||
"Recording Crop: Remove neutral input frames at the end of your recording",
|
"Recording Crop: Remove neutral input frames at the end of your recording".to_string(),
|
||||||
true,
|
true,
|
||||||
&(menu.recording_crop as u32),
|
&(menu.recording_crop as u32),
|
||||||
);
|
);
|
||||||
overall_menu.tabs.push(input_tab);
|
overall_menu.tabs.push(input_tab);
|
||||||
|
|
||||||
let mut button_tab = Tab {
|
let mut button_tab = Tab {
|
||||||
tab_id: "button",
|
tab_id: "button".to_string(),
|
||||||
tab_title: "Button Config",
|
tab_title: "Button Config".to_string(),
|
||||||
tab_submenus: Vec::new(),
|
tab_submenus: Vec::new(),
|
||||||
};
|
};
|
||||||
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
||||||
"Menu Open",
|
"Menu Open".to_string(),
|
||||||
"menu_open",
|
"menu_open".to_string(),
|
||||||
"Menu Open: Hold: Hold any one button and press the others to trigger",
|
"Menu Open: Hold: Hold any one button and press the others to trigger".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.menu_open.bits() as u32),
|
&(menu.menu_open.bits() as u32),
|
||||||
);
|
);
|
||||||
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
||||||
"Save State Save",
|
"Save State Save".to_string(),
|
||||||
"save_state_save",
|
"save_state_save".to_string(),
|
||||||
"Save State Save: Hold any one button and press the others to trigger",
|
"Save State Save: Hold any one button and press the others to trigger".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.save_state_save.bits() as u32),
|
&(menu.save_state_save.bits() as u32),
|
||||||
);
|
);
|
||||||
|
|
||||||
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
||||||
"Save State Load",
|
"Save State Load".to_string(),
|
||||||
"save_state_load",
|
"save_state_load".to_string(),
|
||||||
"Save State Load: Hold any one button and press the others to trigger",
|
"Save State Load: Hold any one button and press the others to trigger".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.save_state_load.bits() as u32),
|
&(menu.save_state_load.bits() as u32),
|
||||||
);
|
);
|
||||||
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
||||||
"Input Record",
|
"Input Record".to_string(),
|
||||||
"input_record",
|
"input_record".to_string(),
|
||||||
"Input Record: Hold any one button and press the others to trigger",
|
"Input Record: Hold any one button and press the others to trigger".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.input_record.bits() as u32),
|
&(menu.input_record.bits() as u32),
|
||||||
);
|
);
|
||||||
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
button_tab.add_submenu_with_toggles::<ButtonConfig>(
|
||||||
"Input Playback",
|
"Input Playback".to_string(),
|
||||||
"input_playback",
|
"input_playback".to_string(),
|
||||||
"Input Playback: Hold any one button and press the others to trigger",
|
"Input Playback: Hold any one button and press the others to trigger".to_string(),
|
||||||
false,
|
false,
|
||||||
&(menu.input_playback.bits() as u32),
|
&(menu.input_playback.bits() as u32),
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
#[cfg(feature = "smash")]
|
#[cfg(feature = "smash")]
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
use std::fmt;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ fn log_2(x: u32) -> u32 {
|
||||||
pub trait ToggleTrait {
|
pub trait ToggleTrait {
|
||||||
fn to_toggle_strs() -> Vec<&'static str>;
|
fn to_toggle_strs() -> Vec<&'static str>;
|
||||||
fn to_toggle_vals() -> Vec<u32>;
|
fn to_toggle_vals() -> Vec<u32>;
|
||||||
|
fn to_toggle_strings() -> Vec<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SliderTrait {
|
pub trait SliderTrait {
|
||||||
|
@ -81,6 +83,11 @@ 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 u32).collect()
|
all_options.iter().map(|i| i.bits() as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
let all_options = <$e>::all().to_vec();
|
||||||
|
all_options.iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,6 +353,12 @@ impl Shield {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Shield {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToggleTrait for Shield {
|
impl ToggleTrait for Shield {
|
||||||
fn to_toggle_strs() -> Vec<&'static str> {
|
fn to_toggle_strs() -> Vec<&'static str> {
|
||||||
Shield::iter().map(|i| i.as_str().unwrap_or("")).collect()
|
Shield::iter().map(|i| i.as_str().unwrap_or("")).collect()
|
||||||
|
@ -354,6 +367,9 @@ impl ToggleTrait for Shield {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
Shield::iter().map(|i| i as u32).collect()
|
Shield::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
Shield::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save State Mirroring
|
// Save State Mirroring
|
||||||
|
@ -377,6 +393,12 @@ impl SaveStateMirroring {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SaveStateMirroring {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToggleTrait for SaveStateMirroring {
|
impl ToggleTrait for SaveStateMirroring {
|
||||||
fn to_toggle_strs() -> Vec<&'static str> {
|
fn to_toggle_strs() -> Vec<&'static str> {
|
||||||
SaveStateMirroring::iter()
|
SaveStateMirroring::iter()
|
||||||
|
@ -387,6 +409,10 @@ impl ToggleTrait for SaveStateMirroring {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
SaveStateMirroring::iter().map(|i| i as u32).collect()
|
SaveStateMirroring::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
SaveStateMirroring::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
|
@ -420,6 +446,9 @@ impl ToggleTrait for OnOff {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
vec![0, 1]
|
vec![0, 1]
|
||||||
}
|
}
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
vec!["Off".to_string(), "On".to_string()]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -1006,6 +1035,16 @@ impl ToggleTrait for SdiFrequency {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
SdiFrequency::iter().map(|i| i as u32).collect()
|
SdiFrequency::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
SdiFrequency::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SdiFrequency {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
|
@ -1049,6 +1088,16 @@ impl ToggleTrait for ClatterFrequency {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
ClatterFrequency::iter().map(|i| i as u32).collect()
|
ClatterFrequency::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
ClatterFrequency::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ClatterFrequency {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Item Selections
|
/// Item Selections
|
||||||
|
@ -1114,6 +1163,16 @@ impl ToggleTrait for CharacterItem {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
CharacterItem::iter().map(|i| i as u32).collect()
|
CharacterItem::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
CharacterItem::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CharacterItem {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -1251,6 +1310,16 @@ impl ToggleTrait for SaveStateSlot {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
SaveStateSlot::iter().map(|i| i as u32).collect()
|
SaveStateSlot::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
SaveStateSlot::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SaveStateSlot {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input Recording Slot
|
// Input Recording Slot
|
||||||
|
@ -1298,6 +1367,16 @@ impl ToggleTrait for RecordSlot {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
RecordSlot::iter().map(|i| i as u32).collect()
|
RecordSlot::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
RecordSlot::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RecordSlot {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input Playback Slot
|
// Input Playback Slot
|
||||||
|
@ -1371,6 +1450,16 @@ impl ToggleTrait for HitstunPlayback {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
HitstunPlayback::iter().map(|i| i as u32).collect()
|
HitstunPlayback::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
HitstunPlayback::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for HitstunPlayback {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input Recording Trigger Type
|
// Input Recording Trigger Type
|
||||||
|
@ -1462,6 +1551,16 @@ impl ToggleTrait for RecordingFrames {
|
||||||
fn to_toggle_vals() -> Vec<u32> {
|
fn to_toggle_vals() -> Vec<u32> {
|
||||||
RecordingFrames::iter().map(|i| i as u32).collect()
|
RecordingFrames::iter().map(|i| i as u32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_toggle_strings() -> Vec<String> {
|
||||||
|
RecordingFrames::iter().map(|i| i.to_string()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RecordingFrames {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -1508,6 +1607,13 @@ impl ButtonConfig {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
pub fn combination_string(&self) -> String {
|
||||||
|
self.to_vec()
|
||||||
|
.iter()
|
||||||
|
.map(|button| button.as_str().unwrap())
|
||||||
|
.intersperse(" + ")
|
||||||
|
.collect::<String>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extra_bitflag_impls! {ButtonConfig}
|
extra_bitflag_impls! {ButtonConfig}
|
||||||
|
|
|
@ -35,27 +35,29 @@ pub enum AppPage {
|
||||||
/// We should hold a list of SubMenus.
|
/// We should hold a list of SubMenus.
|
||||||
/// The currently selected SubMenu should also have an associated list with necessary information.
|
/// The currently selected SubMenu should also have an associated list with necessary information.
|
||||||
/// We can convert the option types (Toggle, OnOff, Slider) to lists
|
/// We can convert the option types (Toggle, OnOff, Slider) to lists
|
||||||
pub struct App<'a> {
|
pub struct App {
|
||||||
pub tabs: StatefulList<&'a str>,
|
pub tabs: StatefulList<String>,
|
||||||
pub menu_items: HashMap<&'a str, MultiStatefulList<SubMenu<'a>>>,
|
pub menu_items: HashMap<String, MultiStatefulList<SubMenu>>,
|
||||||
pub selected_sub_menu_toggles: MultiStatefulList<Toggle<'a>>,
|
pub selected_sub_menu_toggles: MultiStatefulList<Toggle>,
|
||||||
pub selected_sub_menu_slider: DoubleEndedGauge,
|
pub selected_sub_menu_slider: DoubleEndedGauge,
|
||||||
pub page: AppPage,
|
pub page: AppPage,
|
||||||
pub default_menu: (UiMenu<'a>, String),
|
pub default_menu: (UiMenu, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl<'a> App {
|
||||||
pub fn new(menu: UiMenu<'a>, default_menu: (UiMenu<'a>, String)) -> App<'a> {
|
pub fn new(menu: UiMenu, default_menu: (UiMenu, String)) -> App {
|
||||||
let mut menu_items_stateful = HashMap::new();
|
let mut menu_items_stateful = HashMap::new();
|
||||||
menu.tabs.iter().for_each(|tab| {
|
menu.tabs.iter().for_each(|tab| {
|
||||||
menu_items_stateful.insert(
|
menu_items_stateful.insert(
|
||||||
tab.tab_title,
|
tab.tab_title.clone(),
|
||||||
MultiStatefulList::with_items(tab.tab_submenus.clone(), NUM_LISTS),
|
MultiStatefulList::with_items(tab.tab_submenus.clone(), NUM_LISTS),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
tabs: StatefulList::with_items(menu.tabs.iter().map(|tab| tab.tab_title).collect()),
|
tabs: StatefulList::with_items(
|
||||||
|
menu.tabs.iter().map(|tab| tab.tab_title.clone()).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_slider: DoubleEndedGauge::new(),
|
selected_sub_menu_slider: DoubleEndedGauge::new(),
|
||||||
|
@ -82,7 +84,7 @@ impl<'a> App<'a> {
|
||||||
|
|
||||||
let toggles = selected_sub_menu.toggles.clone();
|
let toggles = selected_sub_menu.toggles.clone();
|
||||||
let slider = selected_sub_menu.slider.clone();
|
let slider = selected_sub_menu.slider.clone();
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_string(&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(
|
||||||
toggles,
|
toggles,
|
||||||
|
@ -117,13 +119,13 @@ impl<'a> App<'a> {
|
||||||
/// Returns the currently selected SubMenu struct
|
/// Returns the currently selected SubMenu struct
|
||||||
///
|
///
|
||||||
/// {
|
/// {
|
||||||
/// submenu_title: &'a str,
|
/// submenu_title: String,
|
||||||
/// submenu_id: &'a str,
|
/// submenu_id: String,
|
||||||
/// help_text: &'a str,
|
/// help_text: String,
|
||||||
/// is_single_option: bool,
|
/// is_single_option: bool,
|
||||||
/// toggles: Vec<Toggle<'a>>,
|
/// toggles: Vec<Toggle<'a>>,
|
||||||
/// slider: Option<Slider>,
|
/// slider: Option<Slider>,
|
||||||
/// _type: &'a str,
|
/// _type: String,
|
||||||
/// }
|
/// }
|
||||||
fn sub_menu_selected(&self) -> &SubMenu {
|
fn sub_menu_selected(&self) -> &SubMenu {
|
||||||
let (list_section, list_idx) = self
|
let (list_section, list_idx) = self
|
||||||
|
@ -141,7 +143,7 @@ impl<'a> App<'a> {
|
||||||
/// Toggles: calls next()
|
/// Toggles: calls next()
|
||||||
/// Slider: Swaps between MinHover and MaxHover
|
/// Slider: Swaps between MinHover and MaxHover
|
||||||
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_string(&self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.next(),
|
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.next(),
|
||||||
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
||||||
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
||||||
|
@ -157,7 +159,7 @@ impl<'a> App<'a> {
|
||||||
/// * Swaps between MinHover and MaxHover
|
/// * Swaps between MinHover and MaxHover
|
||||||
/// * Increments the selected_min/max if possible
|
/// * Increments the selected_min/max if possible
|
||||||
pub fn sub_menu_next_list(&mut self) {
|
pub fn sub_menu_next_list(&mut self) {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_string(&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 => match self.selected_sub_menu_slider.state {
|
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
||||||
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
||||||
|
@ -185,7 +187,7 @@ impl<'a> App<'a> {
|
||||||
/// Toggles: calls previous()
|
/// Toggles: calls previous()
|
||||||
/// Slider: Swaps between MinHover and MaxHover
|
/// Slider: Swaps between MinHover and MaxHover
|
||||||
pub fn sub_menu_previous(&mut self) {
|
pub fn sub_menu_previous(&mut self) {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_string(&self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.previous(),
|
SubMenuType::TOGGLE => self.selected_sub_menu_toggles.previous(),
|
||||||
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
||||||
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
||||||
|
@ -201,7 +203,7 @@ impl<'a> App<'a> {
|
||||||
/// * Swaps between MinHover and MaxHover
|
/// * Swaps between MinHover and MaxHover
|
||||||
/// * Decrements the selected_min/max if possible
|
/// * Decrements the selected_min/max if possible
|
||||||
pub fn sub_menu_previous_list(&mut self) {
|
pub fn sub_menu_previous_list(&mut self) {
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_string(&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 => match self.selected_sub_menu_slider.state {
|
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
||||||
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
GaugeState::MinHover => self.selected_sub_menu_slider.state = GaugeState::MaxHover,
|
||||||
|
@ -232,11 +234,13 @@ impl<'a> App<'a> {
|
||||||
/// 2: Vec(toggle checked, title) for toggles, Vec(nothing) for slider
|
/// 2: Vec(toggle checked, title) for toggles, Vec(nothing) for slider
|
||||||
/// 3: ListState for toggles, ListState::new() for slider
|
/// 3: ListState for toggles, ListState::new() for slider
|
||||||
/// TODO: Refactor return type into a nice struct
|
/// TODO: Refactor return type into a nice struct
|
||||||
pub fn sub_menu_strs_and_states(&self) -> (&str, &str, Vec<(Vec<(bool, &str)>, ListState)>) {
|
pub fn sub_menu_strs_and_states(
|
||||||
|
&self,
|
||||||
|
) -> (String, String, Vec<(Vec<(bool, String)>, ListState)>) {
|
||||||
(
|
(
|
||||||
self.sub_menu_selected().submenu_title,
|
self.sub_menu_selected().submenu_title.clone(),
|
||||||
self.sub_menu_selected().help_text,
|
self.sub_menu_selected().help_text.clone(),
|
||||||
match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
match SubMenuType::from_string(&self.sub_menu_selected()._type) {
|
||||||
SubMenuType::TOGGLE => self
|
SubMenuType::TOGGLE => self
|
||||||
.selected_sub_menu_toggles
|
.selected_sub_menu_toggles
|
||||||
.lists
|
.lists
|
||||||
|
@ -246,7 +250,7 @@ impl<'a> App<'a> {
|
||||||
toggle_list
|
toggle_list
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|toggle| (toggle.checked, toggle.toggle_title))
|
.map(|toggle| (toggle.checked, toggle.toggle_title.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
toggle_list.state.clone(),
|
toggle_list.state.clone(),
|
||||||
)
|
)
|
||||||
|
@ -264,16 +268,16 @@ impl<'a> App<'a> {
|
||||||
/// 1: Help text
|
/// 1: Help text
|
||||||
/// 2: Reference to self.selected_sub_menu_slider
|
/// 2: Reference to self.selected_sub_menu_slider
|
||||||
/// TODO: Refactor return type into a nice struct
|
/// TODO: Refactor return type into a nice struct
|
||||||
pub fn sub_menu_strs_for_slider(&self) -> (&str, &str, &DoubleEndedGauge) {
|
pub fn sub_menu_strs_for_slider(&self) -> (String, String, &DoubleEndedGauge) {
|
||||||
let slider = match SubMenuType::from_str(self.sub_menu_selected()._type) {
|
let slider = match SubMenuType::from_string(&self.sub_menu_selected()._type) {
|
||||||
SubMenuType::SLIDER => &self.selected_sub_menu_slider,
|
SubMenuType::SLIDER => &self.selected_sub_menu_slider,
|
||||||
_ => {
|
_ => {
|
||||||
panic!("Slider not selected!");
|
panic!("Slider not selected!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
self.sub_menu_selected().submenu_title,
|
self.sub_menu_selected().submenu_title.clone(),
|
||||||
self.sub_menu_selected().help_text,
|
self.sub_menu_selected().help_text.clone(),
|
||||||
slider,
|
slider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -298,7 +302,7 @@ impl<'a> App<'a> {
|
||||||
.get_mut(list_idx)
|
.get_mut(list_idx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if self.page == AppPage::SUBMENU {
|
if self.page == AppPage::SUBMENU {
|
||||||
match SubMenuType::from_str(selected_sub_menu._type) {
|
match SubMenuType::from_string(&selected_sub_menu._type) {
|
||||||
// Need to change the slider state to MinHover so the slider shows up initially
|
// Need to change the slider state to MinHover so the slider shows up initially
|
||||||
SubMenuType::SLIDER => {
|
SubMenuType::SLIDER => {
|
||||||
self.page = AppPage::SLIDER;
|
self.page = AppPage::SLIDER;
|
||||||
|
@ -307,7 +311,7 @@ impl<'a> App<'a> {
|
||||||
SubMenuType::TOGGLE => self.page = AppPage::TOGGLE,
|
SubMenuType::TOGGLE => self.page = AppPage::TOGGLE,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match SubMenuType::from_str(selected_sub_menu._type) {
|
match SubMenuType::from_string(&selected_sub_menu._type) {
|
||||||
SubMenuType::TOGGLE => {
|
SubMenuType::TOGGLE => {
|
||||||
let is_single_option = selected_sub_menu.is_single_option;
|
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;
|
||||||
|
@ -404,7 +408,7 @@ impl<'a> App<'a> {
|
||||||
.items
|
.items
|
||||||
.get_mut(list_idx)
|
.get_mut(list_idx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
match SubMenuType::from_str(selected_sub_menu._type) {
|
match SubMenuType::from_string(&selected_sub_menu._type) {
|
||||||
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
|
||||||
GaugeState::MinSelected => {
|
GaugeState::MinSelected => {
|
||||||
self.selected_sub_menu_slider.state = GaugeState::MinHover;
|
self.selected_sub_menu_slider.state = GaugeState::MinHover;
|
||||||
|
@ -455,10 +459,11 @@ impl<'a> App<'a> {
|
||||||
let json = self.to_json();
|
let json = self.to_json();
|
||||||
let mut json_value = serde_json::from_str::<serde_json::Value>(&json).unwrap();
|
let mut json_value = serde_json::from_str::<serde_json::Value>(&json).unwrap();
|
||||||
let selected_sub_menu = self.sub_menu_selected();
|
let selected_sub_menu = self.sub_menu_selected();
|
||||||
let id = selected_sub_menu.submenu_id;
|
let id = selected_sub_menu.submenu_id.clone();
|
||||||
let default_json_value =
|
let default_json_value =
|
||||||
serde_json::from_str::<serde_json::Value>(&self.default_menu.1).unwrap();
|
serde_json::from_str::<serde_json::Value>(&self.default_menu.1).unwrap();
|
||||||
*json_value.get_mut(id).unwrap() = default_json_value.get(id).unwrap().clone();
|
*json_value.get_mut(id.as_str()).unwrap() =
|
||||||
|
default_json_value.get(id.as_str()).unwrap().clone();
|
||||||
let new_menu = serde_json::from_value::<TrainingModpackMenu>(json_value).unwrap();
|
let new_menu = serde_json::from_value::<TrainingModpackMenu>(json_value).unwrap();
|
||||||
*self = App::new(unsafe { ui_menu(new_menu) }, self.default_menu.clone());
|
*self = App::new(unsafe { ui_menu(new_menu) }, self.default_menu.clone());
|
||||||
}
|
}
|
||||||
|
@ -587,7 +592,7 @@ impl<'a> App<'a> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn submenu_ids(&self) -> Vec<&str> {
|
pub fn submenu_ids(&self) -> Vec<String> {
|
||||||
return self
|
return self
|
||||||
.menu_items
|
.menu_items
|
||||||
.values()
|
.values()
|
||||||
|
@ -599,10 +604,10 @@ impl<'a> App<'a> {
|
||||||
sub_stateful_list
|
sub_stateful_list
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|submenu| submenu.submenu_id)
|
.map(|submenu| submenu.submenu_id.clone())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<&str>>();
|
.collect::<Vec<String>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,9 +632,9 @@ fn render_submenu_page<B: Backend>(
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let lines = vec![Spans::from(if stateful_list.state.selected().is_some() {
|
let lines = vec![Spans::from(if stateful_list.state.selected().is_some() {
|
||||||
i.submenu_title.to_owned()
|
i.submenu_title.clone()
|
||||||
} else {
|
} else {
|
||||||
" ".to_owned() + i.submenu_title
|
format!(" {}", i.submenu_title.clone())
|
||||||
})];
|
})];
|
||||||
ListItem::new(lines).style(Style::default().fg(Color::White))
|
ListItem::new(lines).style(Style::default().fg(Color::White))
|
||||||
})
|
})
|
||||||
|
@ -650,14 +655,18 @@ fn render_submenu_page<B: Backend>(
|
||||||
|
|
||||||
let mut state = stateful_list.state.clone();
|
let mut state = stateful_list.state.clone();
|
||||||
if state.selected().is_some() {
|
if state.selected().is_some() {
|
||||||
item_help = Some(stateful_list.items[state.selected().unwrap()].help_text);
|
item_help = Some(
|
||||||
|
stateful_list.items[state.selected().unwrap()]
|
||||||
|
.help_text
|
||||||
|
.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
f.render_stateful_widget(list, list_chunks[list_section], &mut state);
|
f.render_stateful_widget(list, list_chunks[list_section], &mut state);
|
||||||
}
|
}
|
||||||
|
|
||||||
let help_paragraph = Paragraph::new(
|
let help_paragraph = Paragraph::new(
|
||||||
item_help.unwrap_or("").replace('\"', "")
|
item_help.unwrap_or("".to_string()).replace('\"', "")
|
||||||
+ "\nZL/ZR: Next tab | X: Save Defaults | R: Reset All Menus",
|
+ "\nZL/ZR: Next tab | X: Save Defaults | R: Reset All Menus",
|
||||||
)
|
)
|
||||||
.style(Style::default().fg(Color::Cyan));
|
.style(Style::default().fg(Color::Cyan));
|
||||||
|
@ -677,14 +686,20 @@ pub fn render_toggle_page<B: Backend>(
|
||||||
let values_items: Vec<ListItem> = sub_menu_str
|
let values_items: Vec<ListItem> = sub_menu_str
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
ListItem::new(vec![Spans::from(
|
ListItem::new(vec![Spans::from(if s.0 {
|
||||||
(if s.0 { "X " } else { " " }).to_owned() + s.1,
|
format!("X {}", s.1)
|
||||||
)])
|
} else {
|
||||||
|
format!(" {}", s.1)
|
||||||
|
})])
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let values_list = List::new(values_items)
|
let values_list = List::new(values_items)
|
||||||
.block(Block::default().title(if list_section == 0 { title } else { "" }))
|
.block(Block::default().title(if list_section == 0 {
|
||||||
|
title.clone()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}))
|
||||||
.start_corner(Corner::TopLeft)
|
.start_corner(Corner::TopLeft)
|
||||||
.highlight_style(
|
.highlight_style(
|
||||||
Style::default()
|
Style::default()
|
||||||
|
@ -795,10 +810,10 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, tab)| {
|
.map(|(idx, tab)| {
|
||||||
if idx == tab_selected {
|
if idx == tab_selected {
|
||||||
span_selected = Spans::from("> ".to_owned() + tab);
|
span_selected = Spans::from(format!("> {}", tab));
|
||||||
Spans::from("> ".to_owned() + tab)
|
Spans::from(format!("> {}", tab))
|
||||||
} else {
|
} else {
|
||||||
Spans::from(" ".to_owned() + tab)
|
Spans::from(format!(" {}", tab))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -17,17 +17,17 @@ use tui::Terminal;
|
||||||
|
|
||||||
use training_mod_consts::*;
|
use training_mod_consts::*;
|
||||||
|
|
||||||
fn test_backend_setup<'a>(
|
fn test_backend_setup(
|
||||||
ui_menu: UiMenu<'a>,
|
ui_menu: UiMenu,
|
||||||
menu_defaults: (UiMenu<'a>, String),
|
menu_defaults: (UiMenu, String),
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
Terminal<training_mod_tui::TestBackend>,
|
Terminal<training_mod_tui::TestBackend>,
|
||||||
training_mod_tui::App<'a>,
|
training_mod_tui::App,
|
||||||
),
|
),
|
||||||
Box<dyn Error>,
|
Box<dyn Error>,
|
||||||
> {
|
> {
|
||||||
let app = training_mod_tui::App::<'a>::new(ui_menu, menu_defaults);
|
let app = training_mod_tui::App::new(ui_menu, menu_defaults);
|
||||||
let backend = tui::backend::TestBackend::new(120, 15);
|
let backend = tui::backend::TestBackend::new(120, 15);
|
||||||
let terminal = Terminal::new(backend)?;
|
let terminal = Terminal::new(backend)?;
|
||||||
let mut state = tui::widgets::ListState::default();
|
let mut state = tui::widgets::ListState::default();
|
||||||
|
|
Loading…
Reference in a new issue