mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 10:54:16 +00:00
Add rustfmt CI checker and format (#518)
* Add rustfmt CI checker Minimal checker that just runs `cargo fmt --check` on all targets. * rustfmt
This commit is contained in:
parent
67948f7373
commit
5b2e4c7319
22 changed files with 151 additions and 93 deletions
18
.github/workflows/rust.yml
vendored
18
.github/workflows/rust.yml
vendored
|
@ -8,6 +8,24 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
rustfmt_check:
|
||||||
|
name: Code Formatting
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install minimal nightly rust
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: nightly
|
||||||
|
components: rustfmt, clippy
|
||||||
|
default: true
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
- name: rustfmt
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
checker:
|
checker:
|
||||||
name: Check, Clippy, Tests
|
name: Check, Clippy, Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
pub use training_mod_consts::*;
|
pub use training_mod_consts::*;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub unsafe fn config() -> &'static DevConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref DEV_CONFIG : Mutex<DevConfig> = Mutex::new(DevConfig::load_from_toml());
|
pub static ref DEV_CONFIG: Mutex<DevConfig> = Mutex::new(DevConfig::load_from_toml());
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DevConfig {
|
impl DevConfig {
|
||||||
|
@ -46,7 +46,8 @@ impl DevConfig {
|
||||||
let dev_path = DEV_TOML_PATH;
|
let dev_path = DEV_TOML_PATH;
|
||||||
if fs::metadata(dev_path).is_ok() {
|
if fs::metadata(dev_path).is_ok() {
|
||||||
info!("Loading dev.toml configs...");
|
info!("Loading dev.toml configs...");
|
||||||
let dev_config_str = fs::read_to_string(dev_path).unwrap_or_else(|_| panic!("Could not read {}", dev_path));
|
let dev_config_str = fs::read_to_string(dev_path)
|
||||||
|
.unwrap_or_else(|_| panic!("Could not read {}", dev_path));
|
||||||
return toml::from_str(&dev_config_str).expect("Could not parse dev config");
|
return toml::from_str(&dev_config_str).expect("Could not parse dev config");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -84,7 +84,11 @@ pub fn main() {
|
||||||
"Shield + Downtaunt".to_string(),
|
"Shield + Downtaunt".to_string(),
|
||||||
120,
|
120,
|
||||||
);
|
);
|
||||||
notification("Load State".to_string(), "Shield + Uptaunt".to_string(), 120);
|
notification(
|
||||||
|
"Load State".to_string(),
|
||||||
|
"Shield + Uptaunt".to_string(),
|
||||||
|
120,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
hitbox_visualizer::hitbox_visualization();
|
hitbox_visualizer::hitbox_visualization();
|
||||||
|
@ -105,8 +109,9 @@ pub fn main() {
|
||||||
error!("Could not move file from {src_path:#?} to {dest_path:#?} with error {e}")
|
error!("Could not move file from {src_path:#?} to {dest_path:#?} with error {e}")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fs::remove_dir_all(LEGACY_TRAINING_MODPACK_ROOT)
|
fs::remove_dir_all(LEGACY_TRAINING_MODPACK_ROOT).unwrap_or_else(|e| {
|
||||||
.unwrap_or_else(|e| error!("Could not delete legacy Training Modpack folder with error {e}"));
|
error!("Could not delete legacy Training Modpack folder with error {e}")
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Performing version check...");
|
info!("Performing version check...");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use smash::app::{self};
|
use smash::app::{self};
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
static mut DIRECTION: AttackAngle = AttackAngle::UP;
|
static mut DIRECTION: AttackAngle = AttackAngle::UP;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smash::app::{self, ArticleOperationTarget, FighterFacial, FighterUtil, lua_bind::*};
|
use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
use smash::phx::{Hash40, Vector3f};
|
use smash::phx::{Hash40, Vector3f};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use smash::app::BattleObjectModuleAccessor;
|
|
||||||
use smash::app::lua_bind::{ControlModule, EffectModule};
|
use smash::app::lua_bind::{ControlModule, EffectModule};
|
||||||
|
use smash::app::BattleObjectModuleAccessor;
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
use smash::phx::{Hash40, Vector3f};
|
use smash::phx::{Hash40, Vector3f};
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
use crate::training::mash;
|
use crate::training::mash;
|
||||||
|
|
||||||
static mut COUNTER: u32 = 0;
|
static mut COUNTER: u32 = 0;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use skyline::nn::ui2d::ResColor;
|
use skyline::nn::ui2d::ResColor;
|
||||||
use training_mod_consts::OnOff;
|
use training_mod_consts::OnOff;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::FighterId;
|
use crate::common::consts::FighterId;
|
||||||
|
use crate::common::*;
|
||||||
use crate::training::*;
|
use crate::training::*;
|
||||||
|
|
||||||
pub static mut FRAME_ADVANTAGE: i32 = 0;
|
pub static mut FRAME_ADVANTAGE: i32 = 0;
|
||||||
|
@ -57,9 +57,24 @@ fn update_frame_advantage(new_frame_adv: i32) {
|
||||||
format!("{FRAME_ADVANTAGE}"),
|
format!("{FRAME_ADVANTAGE}"),
|
||||||
60,
|
60,
|
||||||
match FRAME_ADVANTAGE {
|
match FRAME_ADVANTAGE {
|
||||||
x if x < 0 => ResColor { r: 200, g: 8, b: 8, a: 255 },
|
x if x < 0 => ResColor {
|
||||||
x if x == 0 => ResColor { r: 0, g: 0, b: 0, a: 255 },
|
r: 200,
|
||||||
_ => ResColor { r: 31, g: 198, b: 0, a: 255 },
|
g: 8,
|
||||||
|
b: 8,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
x if x == 0 => ResColor {
|
||||||
|
r: 0,
|
||||||
|
g: 0,
|
||||||
|
b: 0,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
_ => ResColor {
|
||||||
|
r: 31,
|
||||||
|
g: 198,
|
||||||
|
b: 0,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -83,10 +98,10 @@ pub unsafe fn is_enable_transition_term(
|
||||||
|
|
||||||
if !PLAYER_ACTIONABLE
|
if !PLAYER_ACTIONABLE
|
||||||
&& ((is
|
&& ((is
|
||||||
&& actionable_statuses!()
|
&& actionable_statuses!()
|
||||||
.iter()
|
.iter()
|
||||||
.any(|actionable_transition| *actionable_transition == transition_term))
|
.any(|actionable_transition| *actionable_transition == transition_term))
|
||||||
|| (CancelModule::is_enable_cancel(module_accessor)))
|
|| (CancelModule::is_enable_cancel(module_accessor)))
|
||||||
{
|
{
|
||||||
PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX);
|
PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX);
|
||||||
PLAYER_ACTIONABLE = true;
|
PLAYER_ACTIONABLE = true;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use smash::app::{BattleObjectModuleAccessor, lua_bind::StatusModule};
|
use smash::app::{lua_bind::StatusModule, BattleObjectModuleAccessor};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::OnOff;
|
use crate::common::consts::OnOff;
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
pub unsafe fn mod_get_stick_y(module_accessor: &mut BattleObjectModuleAccessor) -> Option<f32> {
|
pub unsafe fn mod_get_stick_y(module_accessor: &mut BattleObjectModuleAccessor) -> Option<f32> {
|
||||||
if !is_operation_cpu(module_accessor) {
|
if !is_operation_cpu(module_accessor) {
|
||||||
|
@ -12,13 +12,13 @@ pub unsafe fn mod_get_stick_y(module_accessor: &mut BattleObjectModuleAccessor)
|
||||||
|
|
||||||
if MENU.crouch == OnOff::On
|
if MENU.crouch == OnOff::On
|
||||||
&& [
|
&& [
|
||||||
*FIGHTER_STATUS_KIND_WAIT,
|
*FIGHTER_STATUS_KIND_WAIT,
|
||||||
*FIGHTER_STATUS_KIND_SQUAT,
|
*FIGHTER_STATUS_KIND_SQUAT,
|
||||||
*FIGHTER_STATUS_KIND_SQUAT_B,
|
*FIGHTER_STATUS_KIND_SQUAT_B,
|
||||||
*FIGHTER_STATUS_KIND_SQUAT_F,
|
*FIGHTER_STATUS_KIND_SQUAT_F,
|
||||||
*FIGHTER_STATUS_KIND_SQUAT_RV,
|
*FIGHTER_STATUS_KIND_SQUAT_RV,
|
||||||
*FIGHTER_STATUS_KIND_SQUAT_WAIT,
|
*FIGHTER_STATUS_KIND_SQUAT_WAIT,
|
||||||
]
|
]
|
||||||
.contains(&fighter_status_kind)
|
.contains(&fighter_status_kind)
|
||||||
{
|
{
|
||||||
Some(-1.0)
|
Some(-1.0)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use core::f64::consts::PI;
|
use core::f64::consts::PI;
|
||||||
|
|
||||||
use smash::app::{self, lua_bind::*, sv_system};
|
use smash::app::{self, lua_bind::*, sv_system};
|
||||||
use smash::lib::L2CValue;
|
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
use smash::lib::L2CValue;
|
||||||
use smash::lua2cpp::L2CFighterCommon;
|
use smash::lua2cpp::L2CFighterCommon;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
static mut DI_CASE: Direction = Direction::empty();
|
static mut DI_CASE: Direction = Direction::empty();
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,9 @@ pub fn get_frame_count(index: usize) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_idx(index: usize) {
|
pub fn tick_idx(index: usize) {
|
||||||
unsafe { COUNTERS[index] += 1; }
|
unsafe {
|
||||||
|
COUNTERS[index] += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick() {
|
fn tick() {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use smash::app::{self, lua_bind::*};
|
use smash::app::{self, lua_bind::*};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
use crate::training::frame_counter;
|
use crate::training::frame_counter;
|
||||||
use crate::training::mash;
|
use crate::training::mash;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use smash::app::{self, lua_bind::*};
|
use smash::app::{self, lua_bind::*};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
use crate::training::{attack_angle, save_states};
|
use crate::common::*;
|
||||||
use crate::training::character_specific;
|
use crate::training::character_specific;
|
||||||
use crate::training::fast_fall;
|
use crate::training::fast_fall;
|
||||||
use crate::training::frame_counter;
|
use crate::training::frame_counter;
|
||||||
use crate::training::full_hop;
|
use crate::training::full_hop;
|
||||||
use crate::training::shield;
|
use crate::training::shield;
|
||||||
|
use crate::training::{attack_angle, save_states};
|
||||||
|
|
||||||
const DISTANCE_CLOSE_THRESHOLD: f32 = 16.0;
|
const DISTANCE_CLOSE_THRESHOLD: f32 = 16.0;
|
||||||
const DISTANCE_MID_THRESHOLD: f32 = 37.0;
|
const DISTANCE_MID_THRESHOLD: f32 = 37.0;
|
||||||
|
|
|
@ -354,7 +354,8 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
||||||
]
|
]
|
||||||
.contains(&fighter_kind);
|
.contains(&fighter_kind);
|
||||||
|
|
||||||
if MENU.save_state_slot_enable == OnOff::On && !is_operation_cpu(module_accessor)
|
if MENU.save_state_slot_enable == OnOff::On
|
||||||
|
&& !is_operation_cpu(module_accessor)
|
||||||
&& button_config::combo_passes_exclusive(
|
&& button_config::combo_passes_exclusive(
|
||||||
module_accessor,
|
module_accessor,
|
||||||
button_config::ButtonCombo::PrevSaveStateSlot,
|
button_config::ButtonCombo::PrevSaveStateSlot,
|
||||||
|
@ -375,7 +376,8 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if MENU.save_state_slot_enable == OnOff::On && !is_operation_cpu(module_accessor)
|
if MENU.save_state_slot_enable == OnOff::On
|
||||||
|
&& !is_operation_cpu(module_accessor)
|
||||||
&& button_config::combo_passes_exclusive(
|
&& button_config::combo_passes_exclusive(
|
||||||
module_accessor,
|
module_accessor,
|
||||||
button_config::ButtonCombo::NextSaveStateSlot,
|
button_config::ButtonCombo::NextSaveStateSlot,
|
||||||
|
|
|
@ -3,8 +3,8 @@ use core::f64::consts::PI;
|
||||||
use smash::app::{self, lua_bind::*};
|
use smash::app::{self, lua_bind::*};
|
||||||
use smash::Vector2f;
|
use smash::Vector2f;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
use crate::training::directional_influence;
|
use crate::training::directional_influence;
|
||||||
|
|
||||||
static mut COUNTER: u32 = 0;
|
static mut COUNTER: u32 = 0;
|
||||||
|
|
|
@ -2,14 +2,14 @@ use smash::app;
|
||||||
use smash::app::lua_bind::*;
|
use smash::app::lua_bind::*;
|
||||||
use smash::app::sv_system;
|
use smash::app::sv_system;
|
||||||
use smash::hash40;
|
use smash::hash40;
|
||||||
use smash::lib::L2CValue;
|
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
use smash::lib::L2CValue;
|
||||||
use smash::lua2cpp::L2CFighterCommon;
|
use smash::lua2cpp::L2CFighterCommon;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
use crate::training::{frame_counter, save_states};
|
use crate::common::*;
|
||||||
use crate::training::mash;
|
use crate::training::mash;
|
||||||
|
use crate::training::{frame_counter, save_states};
|
||||||
|
|
||||||
// How many hits to hold shield until picking an Out Of Shield option
|
// How many hits to hold shield until picking an Out Of Shield option
|
||||||
static mut MULTI_HIT_OFFSET: u32 = 0;
|
static mut MULTI_HIT_OFFSET: u32 = 0;
|
||||||
|
@ -188,8 +188,9 @@ pub fn should_hold_shield(module_accessor: &mut app::BattleObjectModuleAccessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should hold shield if the state requires it
|
// We should hold shield if the state requires it
|
||||||
if unsafe { save_states::is_loading() } ||
|
if unsafe { save_states::is_loading() }
|
||||||
![Shield::Hold, Shield::Infinite, Shield::Constant].contains(shield_state) {
|
|| ![Shield::Hold, Shield::Infinite, Shield::Constant].contains(shield_state)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use smash::app::{self};
|
use smash::app::{self};
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
static mut STICK_DIRECTION: Direction = Direction::OUT;
|
static mut STICK_DIRECTION: Direction = Direction::OUT;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use smash::app::{self, lua_bind::*};
|
use smash::app::{self, lua_bind::*};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
use crate::common::*;
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
|
use crate::common::*;
|
||||||
use crate::training::frame_counter;
|
use crate::training::frame_counter;
|
||||||
use crate::training::mash;
|
use crate::training::mash;
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,10 @@ pub unsafe fn draw(root_pane: &mut Pane) {
|
||||||
let queue = &mut ui::notifications::QUEUE;
|
let queue = &mut ui::notifications::QUEUE;
|
||||||
let notification = queue.first();
|
let notification = queue.first();
|
||||||
|
|
||||||
root_pane.find_pane_by_name_recursive(display_parent_fmt!(notification_idx))
|
root_pane
|
||||||
.unwrap().set_visible(notification.is_some());
|
.find_pane_by_name_recursive(display_parent_fmt!(notification_idx))
|
||||||
|
.unwrap()
|
||||||
|
.set_visible(notification.is_some());
|
||||||
if notification.is_none() {
|
if notification.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -36,12 +38,16 @@ pub unsafe fn draw(root_pane: &mut Pane) {
|
||||||
let notification = notification.unwrap();
|
let notification = notification.unwrap();
|
||||||
let color = notification.color;
|
let color = notification.color;
|
||||||
|
|
||||||
root_pane.find_pane_by_name_recursive(display_header_fmt!(notification_idx))
|
root_pane
|
||||||
|
.find_pane_by_name_recursive(display_header_fmt!(notification_idx))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_textbox().set_text_string(¬ification.header);
|
.as_textbox()
|
||||||
|
.set_text_string(¬ification.header);
|
||||||
|
|
||||||
let text = root_pane.find_pane_by_name_recursive(display_txt_fmt!(notification_idx))
|
let text = root_pane
|
||||||
.unwrap().as_textbox();
|
.find_pane_by_name_recursive(display_txt_fmt!(notification_idx))
|
||||||
|
.unwrap()
|
||||||
|
.as_textbox();
|
||||||
text.set_text_string(¬ification.message);
|
text.set_text_string(¬ification.message);
|
||||||
text.set_default_material_colors();
|
text.set_default_material_colors();
|
||||||
text.set_color(color.r, color.g, color.b, color.a);
|
text.set_color(color.r, color.g, color.b, color.a);
|
||||||
|
|
|
@ -33,12 +33,17 @@ impl Notification {
|
||||||
pub fn notification(header: String, message: String, len: u32) {
|
pub fn notification(header: String, message: String, len: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let queue = &mut QUEUE;
|
let queue = &mut QUEUE;
|
||||||
queue.push(Notification::new(header, message, len, ResColor {
|
queue.push(Notification::new(
|
||||||
r: 0,
|
header,
|
||||||
g: 0,
|
message,
|
||||||
b: 0,
|
len,
|
||||||
a: 255,
|
ResColor {
|
||||||
}));
|
r: 0,
|
||||||
|
g: 0,
|
||||||
|
b: 0,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ use smash::lib::lua_const::*;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
|
|
||||||
const fn num_bits<T>() -> u32 {
|
const fn num_bits<T>() -> u32 {
|
||||||
(std::mem::size_of::<T>() * 8) as u32
|
(std::mem::size_of::<T>() * 8) as u32
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,13 @@ use tui::widgets::ListState;
|
||||||
pub struct MultiStatefulList<T> {
|
pub struct MultiStatefulList<T> {
|
||||||
pub lists: Vec<StatefulList<T>>,
|
pub lists: Vec<StatefulList<T>>,
|
||||||
pub state: usize,
|
pub state: usize,
|
||||||
pub total_len: usize
|
pub total_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> MultiStatefulList<T> {
|
impl<T: Clone> MultiStatefulList<T> {
|
||||||
pub fn selected_list_item(&mut self) -> &mut T {
|
pub fn selected_list_item(&mut self) -> &mut T {
|
||||||
let (list_section, list_idx) = self.idx_to_list_idx(self.state);
|
let (list_section, list_idx) = self.idx_to_list_idx(self.state);
|
||||||
&mut self
|
&mut self.lists[list_section].items[list_idx]
|
||||||
.lists[list_section]
|
|
||||||
.items[list_idx]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn idx_to_list_idx(&self, idx: usize) -> (usize, usize) {
|
pub fn idx_to_list_idx(&self, idx: usize) -> (usize, usize) {
|
||||||
|
@ -20,10 +18,13 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
|
|
||||||
pub fn idx_to_list_idx_opt(&self, idx: usize) -> Option<(usize, usize)> {
|
pub fn idx_to_list_idx_opt(&self, idx: usize) -> Option<(usize, usize)> {
|
||||||
for list_section in 0..self.lists.len() {
|
for list_section in 0..self.lists.len() {
|
||||||
let list_section_min_idx = (self.total_len as f32 / self.lists.len() as f32).ceil() as usize * list_section;
|
let list_section_min_idx =
|
||||||
|
(self.total_len as f32 / self.lists.len() as f32).ceil() as usize * list_section;
|
||||||
let list_section_max_idx = std::cmp::min(
|
let list_section_max_idx = std::cmp::min(
|
||||||
(self.total_len as f32 / self.lists.len() as f32).ceil() as usize * (list_section + 1),
|
(self.total_len as f32 / self.lists.len() as f32).ceil() as usize
|
||||||
self.total_len);
|
* (list_section + 1),
|
||||||
|
self.total_len,
|
||||||
|
);
|
||||||
if (list_section_min_idx..list_section_max_idx).contains(&idx) {
|
if (list_section_min_idx..list_section_max_idx).contains(&idx) {
|
||||||
return Some((list_section, idx - list_section_min_idx));
|
return Some((list_section, idx - list_section_min_idx));
|
||||||
}
|
}
|
||||||
|
@ -42,37 +43,41 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_items(items: Vec<T>, num_lists: usize) -> MultiStatefulList<T> {
|
pub fn with_items(items: Vec<T>, num_lists: usize) -> MultiStatefulList<T> {
|
||||||
let lists = (0..num_lists).map(|list_section| {
|
let lists = (0..num_lists)
|
||||||
let list_section_min_idx = (items.len() as f32 / num_lists as f32).ceil() as usize * list_section;
|
.map(|list_section| {
|
||||||
let list_section_max_idx = std::cmp::min(
|
let list_section_min_idx =
|
||||||
(items.len() as f32 / num_lists as f32).ceil() as usize * (list_section + 1),
|
(items.len() as f32 / num_lists as f32).ceil() as usize * list_section;
|
||||||
items.len());
|
let list_section_max_idx = std::cmp::min(
|
||||||
let mut state = ListState::default();
|
(items.len() as f32 / num_lists as f32).ceil() as usize * (list_section + 1),
|
||||||
if list_section == 0 {
|
items.len(),
|
||||||
// Enforce state as first of list
|
);
|
||||||
state.select(Some(0));
|
let mut state = ListState::default();
|
||||||
}
|
if list_section == 0 {
|
||||||
StatefulList {
|
// Enforce state as first of list
|
||||||
state,
|
state.select(Some(0));
|
||||||
items: items[list_section_min_idx..list_section_max_idx].to_vec(),
|
}
|
||||||
}
|
StatefulList {
|
||||||
}).collect();
|
state,
|
||||||
|
items: items[list_section_min_idx..list_section_max_idx].to_vec(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let total_len = items.len();
|
let total_len = items.len();
|
||||||
MultiStatefulList {
|
MultiStatefulList {
|
||||||
lists,
|
lists,
|
||||||
total_len,
|
total_len,
|
||||||
state: 0
|
state: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
let (list_section, _) = self.idx_to_list_idx(self.state);
|
let (list_section, _) = self.idx_to_list_idx(self.state);
|
||||||
let (next_list_section, next_list_idx) = self.idx_to_list_idx(self.state+1);
|
let (next_list_section, next_list_idx) = self.idx_to_list_idx(self.state + 1);
|
||||||
|
|
||||||
if list_section != next_list_section {
|
if list_section != next_list_section {
|
||||||
self.lists[list_section].unselect();
|
self.lists[list_section].unselect();
|
||||||
}
|
}
|
||||||
let state= if self.state + 1 >= self.total_len {
|
let state = if self.state + 1 >= self.total_len {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
} else {
|
} else {
|
||||||
(next_list_section, next_list_idx)
|
(next_list_section, next_list_idx)
|
||||||
|
@ -84,10 +89,13 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
|
|
||||||
pub fn previous(&mut self) {
|
pub fn previous(&mut self) {
|
||||||
let (list_section, _) = self.idx_to_list_idx(self.state);
|
let (list_section, _) = self.idx_to_list_idx(self.state);
|
||||||
let (last_list_section, last_list_idx) = (self.lists.len() - 1, self.lists[self.lists.len() - 1].items.len() - 1);
|
let (last_list_section, last_list_idx) = (
|
||||||
|
self.lists.len() - 1,
|
||||||
|
self.lists[self.lists.len() - 1].items.len() - 1,
|
||||||
|
);
|
||||||
|
|
||||||
self.lists[list_section].unselect();
|
self.lists[list_section].unselect();
|
||||||
let state= if self.state == 0 {
|
let state = if self.state == 0 {
|
||||||
(last_list_section, last_list_idx)
|
(last_list_section, last_list_idx)
|
||||||
} else {
|
} else {
|
||||||
let (prev_list_section, prev_list_idx) = self.idx_to_list_idx(self.state - 1);
|
let (prev_list_section, prev_list_idx) = self.idx_to_list_idx(self.state - 1);
|
||||||
|
@ -124,7 +132,7 @@ impl<T: Clone> MultiStatefulList<T> {
|
||||||
list_section - 1
|
list_section - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev_list_idx= if list_idx > self.lists[prev_list_section].items.len() - 1 {
|
let prev_list_idx = if list_idx > self.lists[prev_list_section].items.len() - 1 {
|
||||||
self.lists[prev_list_section].items.len() - 1
|
self.lists[prev_list_section].items.len() - 1
|
||||||
} else {
|
} else {
|
||||||
list_idx
|
list_idx
|
||||||
|
@ -150,10 +158,7 @@ impl<T> StatefulList<T> {
|
||||||
let mut state = ListState::default();
|
let mut state = ListState::default();
|
||||||
// Enforce state as first of list
|
// Enforce state as first of list
|
||||||
state.select(Some(0));
|
state.select(Some(0));
|
||||||
StatefulList {
|
StatefulList { state, items }
|
||||||
state,
|
|
||||||
items,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
|
|
Loading…
Reference in a new issue