1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-24 02:44:17 +00:00

Change Menu Buttons and Help Text; HUD Off Outside Training (#488)

* Avoid making layouts invisible outside training mode with HUD off

* Switch menu buttons around; change defaults resetting texts

* Fix unused feature import
This commit is contained in:
jugeeya 2023-02-20 21:45:33 -08:00 committed by GitHub
parent 7fb93ea309
commit d05f8ce918
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 206 additions and 158 deletions

View file

@ -80,6 +80,7 @@ pub struct ButtonPresses {
pub a: ButtonPress,
pub b: ButtonPress,
pub x: ButtonPress,
pub y: ButtonPress,
pub r: ButtonPress,
pub l: ButtonPress,
pub zr: ButtonPress,
@ -133,6 +134,11 @@ pub static mut BUTTON_PRESSES: ButtonPresses = ButtonPresses {
is_pressed: false,
lockout_frames: 0,
},
y: ButtonPress {
prev_frame_is_pressed: false,
is_pressed: false,
lockout_frames: 0,
},
r: ButtonPress {
prev_frame_is_pressed: false,
is_pressed: false,
@ -180,7 +186,6 @@ pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32
let update_count = (*state).updateCount;
let flags = (*state).Flags;
if QUICK_MENU_ACTIVE {
if (*state).Buttons & (1 << 0) > 0 {
BUTTON_PRESSES.a.is_pressed = true;
}
@ -190,6 +195,9 @@ pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32
if (*state).Buttons & (1 << 2) > 0 {
BUTTON_PRESSES.x.is_pressed = true;
}
if (*state).Buttons & (1 << 3) > 0 {
BUTTON_PRESSES.y.is_pressed = true;
}
if (*state).Buttons & (1 << 6) > 0 {
BUTTON_PRESSES.l.is_pressed = true;
}
@ -239,6 +247,12 @@ lazy_static! {
);
}
pub unsafe fn p1_controller_is_gcc() -> bool {
let p1_controller_id = crate::training::input_delay::p1_controller_id();
let p1_style_set = GetNpadStyleSet(&p1_controller_id as *const _);
(p1_style_set.flags & (1 << 5)) > 0
}
pub unsafe fn quick_menu_loop() {
loop {
std::thread::sleep(std::time::Duration::from_secs(10));
@ -262,6 +276,8 @@ pub unsafe fn quick_menu_loop() {
continue;
}
let is_gcc = p1_controller_is_gcc();
let app = &mut *QUICK_MENU_APP.data_ptr();
button_presses.a.read_press().then(|| {
app.on_a();
@ -282,23 +298,39 @@ pub unsafe fn quick_menu_loop() {
}
});
button_presses.x.read_press().then(|| {
app.on_x();
app.save_defaults();
received_input = true;
});
button_presses.y.read_press().then(|| {
app.reset_current_submenu();
received_input = true;
});
button_presses.l.read_press().then(|| {
app.on_l();
if is_gcc {
app.previous_tab();
}
received_input = true;
});
button_presses.r.read_press().then(|| {
app.on_r();
if is_gcc {
app.next_tab();
} else {
app.reset_all_submenus();
}
received_input = true;
});
button_presses.zl.read_press().then(|| {
app.on_zl();
if !is_gcc {
app.previous_tab();
}
received_input = true;
});
button_presses.zr.read_press().then(|| {
app.on_zr();
if !is_gcc {
app.next_tab();
} else {
app.reset_all_submenus();
}
received_input = true;
});
button_presses.left.read_press().then(|| {

View file

@ -1,7 +1,6 @@
use std::collections::HashMap;
use lazy_static::lazy_static;
use skyline::nn::hid::GetNpadStyleSet;
use skyline::nn::ui2d::*;
use smash::ui2d::{SmashPane, SmashTextBox};
use training_mod_tui::gauge::GaugeState;
@ -55,12 +54,18 @@ const BG_LEFT_SELECTED_WHITE_COLOR: ResColor = ResColor {
};
lazy_static! {
static ref GCC_BUTTON_MAPPING: HashMap<&'static str, u16> =
HashMap::from([("L", 0xE204), ("R", 0xE205), ("X", 0xE206), ("Z", 0xE208)]);
static ref GCC_BUTTON_MAPPING: HashMap<&'static str, u16> = HashMap::from([
("L", 0xE204),
("R", 0xE205),
("X", 0xE206),
("Y", 0xE207),
("Z", 0xE208)
]);
static ref PROCON_BUTTON_MAPPING: HashMap<&'static str, u16> = HashMap::from([
("L", 0xE0E4),
("R", 0xE0E5),
("X", 0xE0E2),
("Y", 0xE0E3),
("ZL", 0xE0E6),
("ZR", 0xE0E7)
]);
@ -138,7 +143,7 @@ unsafe fn render_submenu_page(app: &App, root_pane: &mut Pane) {
title_text.text_shadow_enable(false);
title_text.text_outline_enable(false);
title_text.set_color(178, 199, 211, 255);
}
@ -194,11 +199,15 @@ unsafe fn render_toggle_page(app: &App, root_pane: &mut Pane) {
});
title_text.set_text_string(name);
menu_button.find_pane_by_name_recursive("check")
menu_button
.find_pane_by_name_recursive("check")
.unwrap()
.set_visible(true);
menu_button.find_pane_by_name_recursive("Icon").unwrap().set_visible(*checked);
menu_button
.find_pane_by_name_recursive("Icon")
.unwrap()
.set_visible(*checked);
let title_bg_material = &mut *title_bg.material;
@ -403,17 +412,16 @@ pub unsafe fn draw(root_pane: &mut Pane) {
};
let tab_titles = [prev_tab, tab_selected, next_tab].map(|idx| app_tabs[idx]);
let p1_controller_id = crate::training::input_delay::p1_controller_id();
let p1_style_set = GetNpadStyleSet(&p1_controller_id as *const _);
let is_gcc = (p1_style_set.flags & (1 << 5)) > 0;
let is_gcc = common::menu::p1_controller_is_gcc();
let button_mapping = if is_gcc {
GCC_BUTTON_MAPPING.clone()
} else {
PROCON_BUTTON_MAPPING.clone()
};
let (x_key, l_key, r_key, zl_key, zr_key, z_key) = (
let (x_key, y_key, l_key, r_key, zl_key, zr_key, z_key) = (
button_mapping.get("X"),
button_mapping.get("Y"),
button_mapping.get("L"),
button_mapping.get("R"),
button_mapping.get("ZL"),
@ -423,9 +431,9 @@ pub unsafe fn draw(root_pane: &mut Pane) {
let (left_tab_key, right_tab_key, save_defaults_key, reset_current_key, reset_all_key) =
if is_gcc {
(None, z_key, x_key, l_key, r_key)
(l_key, r_key, x_key, y_key, z_key)
} else {
(zl_key, zr_key, x_key, l_key, r_key)
(zl_key, zr_key, x_key, y_key, r_key)
};
[
@ -465,12 +473,12 @@ pub unsafe fn draw(root_pane: &mut Pane) {
help_pane.set_text_string(tab_titles[idx]);
});
[
(save_defaults_key, "SaveDefaults"),
(reset_current_key, "ResetCurrentDefaults"),
(reset_all_key, "ResetAllDefaults"),
(save_defaults_key, "SaveDefaults", "Save Defaults"),
(reset_current_key, "ResetCurrentDefaults", "Reset Current"),
(reset_all_key, "ResetAllDefaults", "Reset All"),
]
.iter()
.for_each(|(key, name)| {
.for_each(|(key, name, title)| {
let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap();
let icon_pane = key_help_pane
@ -483,26 +491,11 @@ pub unsafe fn draw(root_pane: &mut Pane) {
*it = *key.unwrap();
*(it.add(1)) = 0x0;
// PascalCase to Title Case
let title_case = name
.chars()
.fold(vec![], |mut acc, ch| {
if ch.is_uppercase() {
acc.push(String::new());
}
if let Some(last) = acc.last_mut() {
last.push(ch);
}
acc
})
.into_iter()
.collect::<Vec<String>>()
.join(" ");
key_help_pane
.find_pane_by_name_recursive("set_txt_help")
.unwrap()
.as_textbox()
.set_text_string(title_case.as_str());
.set_text_string(title);
});
match app.page {

View file

@ -1,3 +1,4 @@
#[cfg(feature = "layout_arc_from_file")]
use byte_unit::MEBIBYTE;
use sarc::SarcFile;
use skyline::nn::ui2d::*;
@ -22,6 +23,8 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
// InfluencedAlpha means "Should my children panes' alpha be influenced by mine, as the parent?"
root_pane.flags |= 1 << PaneFlag::InfluencedAlpha as u8;
root_pane.set_visible(MENU.hud == OnOff::On);
} else {
root_pane.set_visible(true);
}
damage::draw(root_pane, layout_name);

View file

@ -1,4 +1,6 @@
use training_mod_consts::{MenuJsonStruct, Slider, SubMenu, SubMenuType, Toggle, UiMenu, ui_menu, TrainingModpackMenu};
use training_mod_consts::{
ui_menu, MenuJsonStruct, Slider, SubMenu, SubMenuType, Toggle, TrainingModpackMenu, UiMenu,
};
use tui::{
backend::Backend,
layout::{Constraint, Corner, Direction, Layout, Rect},
@ -8,8 +10,8 @@ use tui::{
Frame,
};
use serde_json::{json, Map};
use std::collections::HashMap;
use serde_json::{Map, json};
pub use tui::{backend::TestBackend, style::Color, Terminal};
pub mod gauge;
@ -25,7 +27,7 @@ pub enum AppPage {
SUBMENU,
TOGGLE,
SLIDER,
CONFIRMATION
CONFIRMATION,
}
/// We should hold a list of SubMenus.
@ -58,7 +60,7 @@ impl<'a> App<'a> {
selected_sub_menu_toggles: MultiStatefulList::with_items(vec![], 0),
selected_sub_menu_slider: DoubleEndedGauge::new(),
page: AppPage::SUBMENU,
default_menu: default_menu
default_menu: default_menu,
};
app.set_sub_menu_items();
app
@ -224,15 +226,13 @@ impl<'a> App<'a> {
}
/// Returns information about the currently selected submenu
///
///
/// 0: Submenu Title
/// 1: Submenu Help Text
/// 2: Vec(toggle checked, title) for toggles, Vec(nothing) for slider
/// 3: ListState for toggles, ListState::new() for slider
/// 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) -> (&str, &str, Vec<(Vec<(bool, &str)>, ListState)>) {
(
self.sub_menu_selected().submenu_title,
self.sub_menu_selected().help_text,
@ -293,8 +293,7 @@ impl<'a> App<'a> {
.get(tab_selected)
.unwrap()
.idx_to_list_idx(self.menu_items.get(tab_selected).unwrap().state);
let selected_sub_menu = self.menu_items.get_mut(tab_selected).unwrap().lists
[list_section]
let selected_sub_menu = self.menu_items.get_mut(tab_selected).unwrap().lists[list_section]
.items
.get_mut(list_idx)
.unwrap();
@ -305,7 +304,7 @@ impl<'a> App<'a> {
self.page = AppPage::SLIDER;
self.selected_sub_menu_slider.state = GaugeState::MinHover;
}
SubMenuType::TOGGLE => self.page = AppPage::TOGGLE
SubMenuType::TOGGLE => self.page = AppPage::TOGGLE,
}
} else {
match SubMenuType::from_str(selected_sub_menu._type) {
@ -323,7 +322,9 @@ impl<'a> App<'a> {
if !o.checked {
o.checked = true;
} else {
if is_single_option { return; }
if is_single_option {
return;
}
o.checked = false;
}
} else if is_single_option {
@ -341,7 +342,9 @@ impl<'a> App<'a> {
if !o.checked {
o.checked = true;
} else {
if is_single_option { return; }
if is_single_option {
return;
}
o.checked = false;
}
} else if is_single_option {
@ -358,7 +361,7 @@ impl<'a> App<'a> {
}
GaugeState::MinSelected => {
self.selected_sub_menu_slider.state = GaugeState::MinHover;
selected_sub_menu.slider = Some(Slider{
selected_sub_menu.slider = Some(Slider {
selected_min: self.selected_sub_menu_slider.selected_min,
selected_max: self.selected_sub_menu_slider.selected_max,
abs_min: self.selected_sub_menu_slider.abs_min,
@ -367,7 +370,7 @@ impl<'a> App<'a> {
}
GaugeState::MaxSelected => {
self.selected_sub_menu_slider.state = GaugeState::MaxHover;
selected_sub_menu.slider = Some(Slider{
selected_sub_menu.slider = Some(Slider {
selected_min: self.selected_sub_menu_slider.selected_min,
selected_max: self.selected_sub_menu_slider.selected_max,
abs_min: self.selected_sub_menu_slider.abs_min,
@ -405,7 +408,7 @@ impl<'a> App<'a> {
SubMenuType::SLIDER => match self.selected_sub_menu_slider.state {
GaugeState::MinSelected => {
self.selected_sub_menu_slider.state = GaugeState::MinHover;
selected_sub_menu.slider = Some(Slider{
selected_sub_menu.slider = Some(Slider {
selected_min: self.selected_sub_menu_slider.selected_min,
selected_max: self.selected_sub_menu_slider.selected_max,
abs_min: self.selected_sub_menu_slider.abs_min,
@ -416,7 +419,7 @@ impl<'a> App<'a> {
}
GaugeState::MaxSelected => {
self.selected_sub_menu_slider.state = GaugeState::MaxHover;
selected_sub_menu.slider = Some(Slider{
selected_sub_menu.slider = Some(Slider {
selected_min: self.selected_sub_menu_slider.selected_min,
selected_max: self.selected_sub_menu_slider.selected_max,
abs_min: self.selected_sub_menu_slider.abs_min,
@ -434,23 +437,27 @@ impl<'a> App<'a> {
}
/// Save defaults command
pub fn on_x(&mut self) {
pub fn save_defaults(&mut self) {
if self.page == AppPage::SUBMENU {
let json = self.to_json();
unsafe {
self.default_menu = (ui_menu(serde_json::from_str::<TrainingModpackMenu>(&json).unwrap()), json);
self.default_menu = (
ui_menu(serde_json::from_str::<TrainingModpackMenu>(&json).unwrap()),
json,
);
}
}
}
/// Reset current submenu to defaults
pub fn on_l(&mut self) {
pub fn reset_current_submenu(&mut self) {
if self.page == AppPage::TOGGLE || self.page == AppPage::SLIDER {
let json = self.to_json();
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 default_json_value = serde_json::from_str::<serde_json::Value>(&self.default_menu.1).unwrap();
let default_json_value =
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();
let new_menu = serde_json::from_value::<TrainingModpackMenu>(json_value).unwrap();
*self = App::new(unsafe { ui_menu(new_menu) }, self.default_menu.clone());
@ -458,18 +465,18 @@ impl<'a> App<'a> {
}
/// Reset all menus to defaults
pub fn on_r(&mut self) {
pub fn reset_all_submenus(&mut self) {
*self = App::new(self.default_menu.0.clone(), self.default_menu.clone());
}
pub fn on_zl(&mut self) {
pub fn previous_tab(&mut self) {
if self.page == AppPage::SUBMENU {
self.tabs.previous();
self.set_sub_menu_items();
}
}
pub fn on_zr(&mut self) {
pub fn next_tab(&mut self) {
if self.page == AppPage::SUBMENU {
self.tabs.next();
self.set_sub_menu_items();
@ -571,35 +578,40 @@ impl<'a> App<'a> {
serde_json::to_string(&settings).unwrap()
}
/// Returns the current menu selections and the default menu selections.
pub fn get_menu_selections(&self) -> String {
serde_json::to_string(
&MenuJsonStruct {
serde_json::to_string(&MenuJsonStruct {
menu: serde_json::from_str(self.to_json().as_str()).unwrap(),
defaults_menu: serde_json::from_str(self.default_menu.1.clone().as_str()).unwrap(),
}).unwrap()
})
.unwrap()
}
pub fn submenu_ids(&self) -> Vec<&str> {
return self.menu_items
.values()
.flat_map(|multi_stateful_list| {
multi_stateful_list
.lists
.iter()
.flat_map(|sub_stateful_list| {
sub_stateful_list
.items
.iter()
.map(|submenu| submenu.submenu_id)
})
})
.collect::<Vec<&str>>();
return self
.menu_items
.values()
.flat_map(|multi_stateful_list| {
multi_stateful_list
.lists
.iter()
.flat_map(|sub_stateful_list| {
sub_stateful_list
.items
.iter()
.map(|submenu| submenu.submenu_id)
})
})
.collect::<Vec<&str>>();
}
}
fn render_submenu_page<B: Backend>(f: &mut Frame<B>, app: &mut App, list_chunks: Vec<Rect>, help_chunk: Rect) {
fn render_submenu_page<B: Backend>(
f: &mut Frame<B>,
app: &mut App,
list_chunks: Vec<Rect>,
help_chunk: Rect,
) {
let tab_selected = app.tab_selected();
let mut item_help = None;
for (list_section, stateful_list) in app
@ -648,11 +660,16 @@ fn render_submenu_page<B: Backend>(f: &mut Frame<B>, app: &mut App, list_chunks:
item_help.unwrap_or("").replace('\"', "")
+ "\nZL/ZR: Next tab | X: Save Defaults | R: Reset All Menus",
)
.style(Style::default().fg(Color::Cyan));
.style(Style::default().fg(Color::Cyan));
f.render_widget(help_paragraph, help_chunk);
}
pub fn render_toggle_page<B: Backend>(f: &mut Frame<B>, app: &mut App, list_chunks: Vec<Rect>, help_chunk: Rect) {
pub fn render_toggle_page<B: Backend>(
f: &mut Frame<B>,
app: &mut App,
list_chunks: Vec<Rect>,
help_chunk: Rect,
) {
let (title, help_text, mut sub_menu_str_lists) = app.sub_menu_strs_and_states();
for list_section in 0..sub_menu_str_lists.len() {
let sub_menu_str = sub_menu_str_lists[list_section].0.clone();
@ -677,15 +694,17 @@ pub fn render_toggle_page<B: Backend>(f: &mut Frame<B>, app: &mut App, list_chun
.highlight_symbol(">> ");
f.render_stateful_widget(values_list, list_chunks[list_section], sub_menu_state);
}
let help_paragraph = Paragraph::new(
help_text.replace('\"', "") + "\nL: Reset Current Menu",
)
let help_paragraph = Paragraph::new(help_text.replace('\"', "") + "\nL: Reset Current Menu")
.style(Style::default().fg(Color::Cyan));
f.render_widget(help_paragraph, help_chunk);
}
pub fn render_slider_page<B: Backend>(f: &mut Frame<B>, app: &mut App, vertical_chunk: Rect, help_chunk: Rect) {
pub fn render_slider_page<B: Backend>(
f: &mut Frame<B>,
app: &mut App,
vertical_chunk: Rect,
help_chunk: Rect,
) {
let (_title, help_text, gauge_vals) = app.sub_menu_strs_for_slider();
let abs_min = gauge_vals.abs_min;
let abs_max = gauge_vals.abs_max;
@ -693,9 +712,18 @@ pub fn render_slider_page<B: Backend>(f: &mut Frame<B>, app: &mut App, vertical_
let selected_max = gauge_vals.selected_max;
let lbl_ratio = 0.95; // Needed so that the upper limit label is visible
let constraints = [
Constraint::Ratio((lbl_ratio * (selected_min-abs_min) as f32) as u32, abs_max-abs_min),
Constraint::Ratio((lbl_ratio * (selected_max-selected_min) as f32) as u32, abs_max-abs_min),
Constraint::Ratio((lbl_ratio * (abs_max-selected_max) as f32) as u32, abs_max-abs_min),
Constraint::Ratio(
(lbl_ratio * (selected_min - abs_min) as f32) as u32,
abs_max - abs_min,
),
Constraint::Ratio(
(lbl_ratio * (selected_max - selected_min) as f32) as u32,
abs_max - abs_min,
),
Constraint::Ratio(
(lbl_ratio * (abs_max - selected_max) as f32) as u32,
abs_max - abs_min,
),
Constraint::Min(3), // For upper limit label
];
let gauge_chunks = Layout::default()
@ -703,12 +731,7 @@ pub fn render_slider_page<B: Backend>(f: &mut Frame<B>, app: &mut App, vertical_
.constraints(constraints)
.split(vertical_chunk);
let slider_lbls = [
abs_min,
selected_min,
selected_max,
abs_max,
];
let slider_lbls = [abs_min, selected_min, selected_max, abs_max];
for (idx, lbl) in slider_lbls.iter().enumerate() {
let mut line_set = tui::symbols::line::NORMAL;
line_set.horizontal = "-";
@ -721,24 +744,16 @@ pub fn render_slider_page<B: Backend>(f: &mut Frame<B>, app: &mut App, vertical_
if idx == 1 {
// Slider between selected_min and selected_max
match gauge_vals.state {
GaugeState::MinHover => {
gauge = gauge.style(Style::default().fg(Color::Red))
}
GaugeState::MinSelected => {
gauge = gauge.style(Style::default().fg(Color::Green))
}
GaugeState::MinHover => gauge = gauge.style(Style::default().fg(Color::Red)),
GaugeState::MinSelected => gauge = gauge.style(Style::default().fg(Color::Green)),
_ => {}
}
gauge = gauge.gauge_style(Style::default().fg(Color::Yellow).bg(Color::Black));
} else if idx == 2 {
// Slider between selected_max and abs_max
match gauge_vals.state {
GaugeState::MaxHover => {
gauge = gauge.style(Style::default().fg(Color::Red))
}
GaugeState::MaxSelected => {
gauge = gauge.style(Style::default().fg(Color::Green))
}
GaugeState::MaxHover => gauge = gauge.style(Style::default().fg(Color::Red)),
GaugeState::MaxSelected => gauge = gauge.style(Style::default().fg(Color::Green)),
_ => {}
}
} else if idx == 3 {
@ -762,9 +777,7 @@ pub fn render_slider_page<B: Backend>(f: &mut Frame<B>, app: &mut App, vertical_
f.render_widget(gauge, gauge_chunks[idx]);
}
let help_paragraph = Paragraph::new(
help_text.replace('\"', "") + "\nL: Reset Current Menu",
)
let help_paragraph = Paragraph::new(help_text.replace('\"', "") + "\nL: Reset Current Menu")
.style(Style::default().fg(Color::Cyan));
f.render_widget(help_paragraph, help_chunk);
}
@ -846,22 +859,20 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
// is not publicly exposed, and the attribute defaults to true.
// https://github.com/fdehau/tui-rs/blob/v0.19.0/src/layout.rs#L121
let vertical_chunks: Vec<Rect> = vertical_chunks
.iter()
.map(|chunk| {
Layout::default()
.direction(Direction::Horizontal)
.constraints(
[
Constraint::Length(NX_TUI_WIDTH), // Width of the TUI terminal
Constraint::Min(0), // Fill the remainder margin
]
.as_ref(),
)
.split(*chunk)[0]
}
)
.collect();
.iter()
.map(|chunk| {
Layout::default()
.direction(Direction::Horizontal)
.constraints(
[
Constraint::Length(NX_TUI_WIDTH), // Width of the TUI terminal
Constraint::Min(0), // Fill the remainder margin
]
.as_ref(),
)
.split(*chunk)[0]
})
.collect();
let list_chunks = Layout::default()
.direction(Direction::Horizontal)
@ -881,6 +892,6 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
AppPage::SUBMENU => render_submenu_page(f, app, list_chunks, vertical_chunks[2]),
AppPage::SLIDER => render_slider_page(f, app, vertical_chunks[1], vertical_chunks[2]),
AppPage::TOGGLE => render_toggle_page(f, app, list_chunks, vertical_chunks[2]),
AppPage::CONFIRMATION => todo!()
AppPage::CONFIRMATION => todo!(),
}
}
}

View file

@ -5,21 +5,28 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
#[cfg(feature = "has_terminal")]
use tui::backend::CrosstermBackend;
use std::error::Error;
#[cfg(feature = "has_terminal")]
use std::{
io,
time::{Duration, Instant},
};
use std::error::Error;
#[cfg(feature = "has_terminal")]
use tui::backend::CrosstermBackend;
use tui::Terminal;
use training_mod_consts::*;
fn test_backend_setup<'a>(ui_menu: UiMenu<'a>, menu_defaults: (UiMenu<'a>, String)) -> Result<
(Terminal<training_mod_tui::TestBackend>, training_mod_tui::App<'a>),
Box<dyn Error>> {
fn test_backend_setup<'a>(
ui_menu: UiMenu<'a>,
menu_defaults: (UiMenu<'a>, String),
) -> Result<
(
Terminal<training_mod_tui::TestBackend>,
training_mod_tui::App<'a>,
),
Box<dyn Error>,
> {
let app = training_mod_tui::App::<'a>::new(ui_menu, menu_defaults);
let backend = tui::backend::TestBackend::new(75, 15);
let terminal = Terminal::new(backend)?;
@ -103,7 +110,7 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
// Return to submenu selection
app.on_b();
// Save Defaults
app.on_x();
app.save_defaults();
// Enter Mash Toggles again
app.on_a();
// Unset Mash Airdodge
@ -127,7 +134,7 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
);
// Reset current menu alone to defaults
app.on_l();
app.reset_current_submenu();
let menu_json = app.get_menu_selections();
let menu_struct = serde_json::from_str::<MenuJsonStruct>(&menu_json).unwrap();
let menu = menu_struct.menu;
@ -155,7 +162,7 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
// Return to submenu selection
app.on_b();
// Save defaults
app.on_x();
app.save_defaults();
// Go back in and unset Jump
app.on_a();
app.on_down();
@ -163,7 +170,7 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
// Return to submenu selection
app.on_b();
// Reset all to defaults
app.on_r();
app.reset_all_submenus();
let menu_json = app.get_menu_selections();
let menu_struct = serde_json::from_str::<MenuJsonStruct>(&menu_json).unwrap();
let menu = menu_struct.menu;
@ -177,7 +184,6 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
"The menu should have Mash Airdodge off and Followup Jump on"
);
Ok(())
}
@ -192,16 +198,19 @@ fn main() -> Result<(), Box<dyn Error>> {
menu_defaults = (ui_menu(MENU), serde_json::to_string(&MENU).unwrap());
}
#[cfg(not(feature = "has_terminal"))] {
#[cfg(not(feature = "has_terminal"))]
{
let (mut terminal, mut app) = test_backend_setup(menu, menu_defaults)?;
if inputs.is_some() {
inputs.unwrap().split(",").for_each(|input| {
match input.to_uppercase().as_str() {
"X" => app.on_x(),
"L" => app.on_l(),
"R" => app.on_r(),
"O" => app.on_zl(),
"P" => app.on_zr(),
inputs
.unwrap()
.split(",")
.for_each(|input| match input.to_uppercase().as_str() {
"X" => app.save_defaults(),
"Y" => app.reset_current_submenu(),
"Z" => app.reset_all_submenus(),
"L" => app.previous_tab(),
"R" => app.next_tab(),
"A" => app.on_a(),
"B" => app.on_b(),
"UP" => app.on_up(),
@ -209,8 +218,7 @@ fn main() -> Result<(), Box<dyn Error>> {
"LEFT" => app.on_left(),
"RIGHT" => app.on_right(),
_ => {}
}
})
})
}
let frame_res = terminal.draw(|f| training_mod_tui::ui(f, &mut app))?;
let menu_json = app.get_menu_selections();
@ -226,7 +234,8 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("Menu:\n{menu_json}");
}
#[cfg(feature = "has_terminal")] {
#[cfg(feature = "has_terminal")]
{
let app = training_mod_tui::App::new(menu, menu_defaults);
// setup terminal
@ -281,11 +290,11 @@ fn run_app<B: tui::backend::Backend>(
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') => return Ok(menu_json),
KeyCode::Char('x') => app.on_x(),
KeyCode::Char('p') => app.on_zr(),
KeyCode::Char('o') => app.on_zl(),
KeyCode::Char('r') => app.on_r(),
KeyCode::Char('l') => app.on_l(),
KeyCode::Char('x') => app.save_defaults(),
KeyCode::Char('p') => app.reset_current_submenu(),
KeyCode::Char('o') => app.reset_all_submenus(),
KeyCode::Char('r') => app.next_tab(),
KeyCode::Char('l') => app.previous_tab(),
KeyCode::Left => app.on_left(),
KeyCode::Right => app.on_right(),
KeyCode::Down => app.on_down(),