mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 02:44:17 +00:00
Use nnsdk and smash upstreams for ui2d (#453)
* A bunch of things * Current progress * Fix for ResAnimationContent * Figure out Parts* * Cleanup, just because * New pane working!!! * New null pane for hierarchy * Success with parent pane * Generate multiple panes * Multiple panes, almost working text color * MaterialColor test, but fails * Forgot bitfield-struct * Vtable for material. Fixes SetWhiteColor! * Refactor color changing, change naming scheme * Just Frame Advantage * Merge * Delete T_test.txt * Delete set_txt_num_01.txt * Delete libtraining_modpack.nro * Format Rust code using rustfmt * Ignore shell scripts in repo languages * General refactor, add basis for quick menu * Small refactor, fix ordering of submenu options * Toggles, sliders * Tons of progress... * Correct dmg updater, remove old quick menu backend * Fix damage percentage display * Small QoL * Format Rust code using rustfmt * More edits. Use Quit Training button as Modpack Menu header * Finish merge * Format Rust code using rustfmt * Use vanilla backgrounds for text options * Format ui_hacks, also always do new percent display * Fix merge * That was the most awful merge ever * Address clippy warnings * Format Rust code using rustfmt * Last impls for resources, small cleanup * Use macro for pane names * Format * Add HUD toggle * Small change * Fix for reentering training mode * Last cleanup * Format Rust code using rustfmt * Try using nnsdk/smash upstream * Format Rust code using rustfmt * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
c1a6f6626d
commit
7ec7928c55
5 changed files with 78 additions and 1004 deletions
|
@ -12,7 +12,6 @@ skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" }
|
|||
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", branch = "no-cache" }
|
||||
skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" }
|
||||
bitflags = "1.2.1"
|
||||
bitfield-struct = "0.1.8"
|
||||
parking_lot = { version = "0.12.0", features = ["nightly"] }
|
||||
lazy_static = "1.4.0"
|
||||
owo-colors = "2.1.0"
|
||||
|
@ -35,6 +34,7 @@ native-tls = { version = "0.2.11", features = ["vendored"] }
|
|||
|
||||
[patch.crates-io]
|
||||
native-tls = { git = "https://github.com/skyline-rs/rust-native-tls", rev = "f202fca" }
|
||||
nnsdk = { git = "https://github.com/ultimate-research/nnsdk-rs" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
|
|
@ -23,7 +23,6 @@ pub mod sdi;
|
|||
pub mod shield;
|
||||
pub mod tech;
|
||||
pub mod throw;
|
||||
pub mod ui;
|
||||
pub mod ui_hacks;
|
||||
|
||||
mod air_dodge_direction;
|
||||
|
|
|
@ -1,565 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use bitfield_struct::bitfield;
|
||||
|
||||
mod resources;
|
||||
pub use resources::*;
|
||||
|
||||
use crate::common::get_player_dmg_digits;
|
||||
use crate::consts::FighterId;
|
||||
|
||||
macro_rules! c_str {
|
||||
($l:tt) => {
|
||||
[$l.as_bytes(), "\u{0}".as_bytes()].concat().as_ptr()
|
||||
};
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ResAnimationContent {
|
||||
name: [skyline::libc::c_char; 28],
|
||||
count: u8,
|
||||
anim_content_type: u8,
|
||||
padding: [skyline::libc::c_char; 2],
|
||||
}
|
||||
|
||||
/**
|
||||
* Block Header Kind
|
||||
*
|
||||
* ANIM_TAG: pat1
|
||||
* ANIM_SHARE: pah1
|
||||
* ANIM_INFO: pai1
|
||||
*/
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ResAnimationBlock {
|
||||
block_header_kind: u32,
|
||||
block_header_size: u32,
|
||||
num_frames: u16,
|
||||
is_loop: bool,
|
||||
pad: [skyline::libc::c_char; 1],
|
||||
file_count: u16,
|
||||
anim_cont_count: u16,
|
||||
anim_cont_offsets_offset: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AnimTransform {
|
||||
res_animation_block: *mut ResAnimationBlock,
|
||||
frame: f32,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl AnimTransform {
|
||||
pub unsafe fn parse_anim_transform(&mut self, layout_name: Option<&str>) {
|
||||
let res_animation_block_data_start = self.res_animation_block as u64;
|
||||
let res_animation_block = &*self.res_animation_block;
|
||||
let mut anim_cont_offsets = (res_animation_block_data_start
|
||||
+ res_animation_block.anim_cont_offsets_offset as u64)
|
||||
as *const u32;
|
||||
for _anim_cont_idx in 0..res_animation_block.anim_cont_count {
|
||||
let anim_cont_offset = *anim_cont_offsets;
|
||||
let res_animation_cont = (res_animation_block_data_start + anim_cont_offset as u64)
|
||||
as *const ResAnimationContent;
|
||||
|
||||
let name = skyline::try_from_c_str((*res_animation_cont).name.as_ptr())
|
||||
.unwrap_or("UNKNOWN".to_string());
|
||||
let anim_type = (*res_animation_cont).anim_content_type;
|
||||
|
||||
// AnimContentType 1 == MATERIAL
|
||||
if name.starts_with("set_dmg_num") && anim_type == 1 {
|
||||
if let Some(layout_name) = layout_name {
|
||||
let (hundreds, tens, ones, dec) = get_player_dmg_digits(match layout_name {
|
||||
"p1" => FighterId::Player,
|
||||
"p2" => FighterId::CPU,
|
||||
_ => panic!("Unknown layout name: {}", layout_name),
|
||||
});
|
||||
|
||||
if name == "set_dmg_num_3" {
|
||||
self.frame = hundreds as f32;
|
||||
}
|
||||
if name == "set_dmg_num_2" {
|
||||
self.frame = tens as f32;
|
||||
}
|
||||
if name == "set_dmg_num_1" {
|
||||
self.frame = ones as f32;
|
||||
}
|
||||
if name == "set_dmg_num_dec" {
|
||||
self.frame = dec as f32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anim_cont_offsets = anim_cont_offsets.add(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct AnimTransformNode {
|
||||
prev: *mut AnimTransformNode,
|
||||
next: *mut AnimTransformNode,
|
||||
}
|
||||
|
||||
impl AnimTransformNode {
|
||||
pub unsafe fn iterate_anim_list(&mut self, layout_name: Option<&str>) {
|
||||
let mut curr = self as *mut AnimTransformNode;
|
||||
let mut _anim_idx = 0;
|
||||
while !curr.is_null() {
|
||||
// Only if valid
|
||||
if curr != (*curr).next {
|
||||
let anim_transform = (curr as *mut u64).add(2) as *mut AnimTransform;
|
||||
anim_transform
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.parse_anim_transform(layout_name);
|
||||
}
|
||||
|
||||
curr = (*curr).next;
|
||||
_anim_idx += 1;
|
||||
if curr == self as *mut AnimTransformNode || curr == (*curr).next {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AnimTransformList {
|
||||
root: AnimTransformNode,
|
||||
}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Pane {
|
||||
vtable: u64,
|
||||
pub link: PaneNode,
|
||||
pub parent: *mut Pane,
|
||||
pub children_list: PaneNode,
|
||||
pub pos_x: f32,
|
||||
pub pos_y: f32,
|
||||
pos_z: f32,
|
||||
rot_x: f32,
|
||||
rot_y: f32,
|
||||
rot_z: f32,
|
||||
pub scale_x: f32,
|
||||
pub scale_y: f32,
|
||||
pub size_x: f32,
|
||||
pub size_y: f32,
|
||||
pub flags: u8,
|
||||
pub alpha: u8,
|
||||
pub global_alpha: u8,
|
||||
base_position: u8,
|
||||
flag_ex: u8,
|
||||
// This is supposed to be 3 bytes padding + flags of 4 bytes + padding of 4 bytes
|
||||
pad: [u8; 3 + 4 + 4 + 8],
|
||||
global_matrix: [[f32; 3]; 4],
|
||||
user_matrix: *const u64,
|
||||
ext_user_data_list: *const u64,
|
||||
pub name: [skyline::libc::c_char; 25],
|
||||
user_data: [skyline::libc::c_char; 9],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PaneFlag {
|
||||
Visible,
|
||||
InfluencedAlpha,
|
||||
LocationAdjust,
|
||||
UserAllocated,
|
||||
IsGlobalMatrixDirty,
|
||||
UserMatrix,
|
||||
UserGlobalMatrix,
|
||||
IsConstantBufferReady,
|
||||
Max,
|
||||
}
|
||||
|
||||
impl Pane {
|
||||
pub unsafe fn find_pane_by_name_recursive(&self, s: &str) -> Option<&mut Pane> {
|
||||
find_pane_by_name_recursive(self, c_str!(s)).as_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn find_pane_by_name(&self, s: &str, recursive: bool) -> Option<&mut Pane> {
|
||||
find_pane_by_name(self, c_str!(s), recursive).as_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn set_text_string(&self, s: &str) {
|
||||
pane_set_text_string(self, c_str!(s));
|
||||
}
|
||||
|
||||
pub unsafe fn remove_child(&self, child: &Pane) {
|
||||
pane_remove_child(self, child as *const Pane);
|
||||
}
|
||||
|
||||
pub unsafe fn append_child(&self, child: &Pane) {
|
||||
pane_append_child(self, child as *const Pane);
|
||||
}
|
||||
|
||||
/// Detach from current parent pane
|
||||
pub unsafe fn detach(&self) {
|
||||
pane_remove_child(self.parent, self as *const Pane);
|
||||
}
|
||||
|
||||
pub unsafe fn as_parts(&mut self) -> *mut Parts {
|
||||
self as *mut Pane as *mut Parts
|
||||
}
|
||||
|
||||
pub unsafe fn as_picture(&mut self) -> &mut Picture {
|
||||
&mut *(self as *mut Pane as *mut Picture)
|
||||
}
|
||||
|
||||
pub unsafe fn as_textbox(&mut self) -> &mut TextBox {
|
||||
&mut *(self as *mut Pane as *mut TextBox)
|
||||
}
|
||||
|
||||
pub unsafe fn set_visible(&mut self, visible: bool) {
|
||||
if visible {
|
||||
self.alpha = 255;
|
||||
self.global_alpha = 255;
|
||||
} else {
|
||||
self.alpha = 0;
|
||||
self.global_alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
self.name
|
||||
.iter()
|
||||
.take_while(|b| **b != 0)
|
||||
.map(|b| *b as char)
|
||||
.collect::<String>()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Parts {
|
||||
pub pane: Pane,
|
||||
// Some IntrusiveList
|
||||
link: PaneNode,
|
||||
pub layout: *mut Layout,
|
||||
}
|
||||
|
||||
impl Deref for Parts {
|
||||
type Target = Pane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Parts {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Picture {
|
||||
pub pane: Pane,
|
||||
pub material: *mut Material,
|
||||
pub vertex_colors: [[u8; 4]; 4],
|
||||
shared_memory: *mut u8,
|
||||
}
|
||||
|
||||
impl Deref for Picture {
|
||||
type Target = Pane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Picture {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield(u16)]
|
||||
pub struct TextBoxBits {
|
||||
#[bits(2)]
|
||||
text_alignment: u8,
|
||||
#[bits(1)]
|
||||
is_ptdirty: u8,
|
||||
shadow_enabled: bool,
|
||||
invisible_border_enabled: bool,
|
||||
double_drawn_border_enabled: bool,
|
||||
width_limit_enabled: bool,
|
||||
per_character_transform_enabled: bool,
|
||||
center_ceiling_enabled: bool,
|
||||
per_character_transform_split_by_char_width: bool,
|
||||
per_character_transform_auto_shadow_alpha: bool,
|
||||
draw_from_right_to_left: bool,
|
||||
per_character_transform_origin_to_center: bool,
|
||||
per_character_transform_fix_space: bool,
|
||||
linefeed_by_character_height_enabled: bool,
|
||||
per_character_transform_split_by_char_width_insert_space_enabled: bool,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TextBox {
|
||||
pub pane: Pane,
|
||||
// Actually a union
|
||||
pub m_text_buf: *mut skyline::libc::c_char,
|
||||
m_p_text_id: *const skyline::libc::c_char,
|
||||
m_text_colors: [[u8; 4]; 2],
|
||||
m_p_font: *const skyline::libc::c_void,
|
||||
m_font_size_x: f32,
|
||||
m_font_size_y: f32,
|
||||
m_line_space: f32,
|
||||
m_char_space: f32,
|
||||
|
||||
// Actually a union
|
||||
m_p_tag_processor: *const skyline::libc::c_char,
|
||||
|
||||
m_text_buf_len: u16,
|
||||
pub m_text_len: u16,
|
||||
|
||||
m_bits: TextBoxBits,
|
||||
m_text_position: u8,
|
||||
|
||||
pub m_is_utf8: bool,
|
||||
|
||||
m_italic_ratio: f32,
|
||||
|
||||
m_shadow_offset_x: f32,
|
||||
m_shadow_offset_y: f32,
|
||||
m_shadow_scale_x: f32,
|
||||
m_shadow_scale_y: f32,
|
||||
m_shadow_top_color: [u8; 4],
|
||||
m_shadow_bottom_color: [u8; 4],
|
||||
m_shadow_italic_ratio: f32,
|
||||
|
||||
m_p_line_width_offset: *const skyline::libc::c_void,
|
||||
|
||||
pub m_p_material: *mut Material,
|
||||
m_p_disp_string_buf: *const skyline::libc::c_void,
|
||||
|
||||
m_p_per_character_transform: *const skyline::libc::c_void,
|
||||
}
|
||||
|
||||
impl TextBox {
|
||||
pub fn set_color(&mut self, r: u8, g: u8, b: u8, a: u8) {
|
||||
let input_color = [r, g, b, a];
|
||||
let mut dirty: bool = false;
|
||||
self.m_text_colors
|
||||
.iter_mut()
|
||||
.for_each(|top_or_bottom_color| {
|
||||
if *top_or_bottom_color != input_color {
|
||||
dirty = true;
|
||||
}
|
||||
*top_or_bottom_color = input_color;
|
||||
});
|
||||
|
||||
if dirty {
|
||||
self.m_bits.set_is_ptdirty(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn set_material_white_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
|
||||
(*self.m_p_material).set_white_color(r, g, b, a);
|
||||
}
|
||||
|
||||
pub unsafe fn set_material_black_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
|
||||
(*self.m_p_material).set_black_color(r, g, b, a);
|
||||
}
|
||||
|
||||
pub unsafe fn set_default_material_colors(&mut self) {
|
||||
self.set_material_white_color(255.0, 255.0, 255.0, 255.0);
|
||||
self.set_material_black_color(0.0, 0.0, 0.0, 255.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TextBox {
|
||||
type Target = Pane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for TextBox {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union MaterialColor {
|
||||
byte_color: [[u8; 4]; 2],
|
||||
p_float_color: *mut *mut f32,
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
impl fmt::Debug for MaterialColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
unsafe {
|
||||
f.debug_struct("MaterialColor")
|
||||
.field("byteColor", &self.byte_color)
|
||||
.field("pFloatColor", &self.p_float_color)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MaterialColorType {
|
||||
BlackColor,
|
||||
WhiteColor,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MaterialFlags {
|
||||
UserAllocated,
|
||||
TextureOnly,
|
||||
ThresholdingAlphaInterpolation,
|
||||
BlackColorFloat,
|
||||
WhiteColorFloat,
|
||||
DynamicAllocatedColorData,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Material {
|
||||
vtable: u64,
|
||||
pub m_colors: MaterialColor,
|
||||
// Actually a struct
|
||||
m_mem_cap: u32,
|
||||
// Actually a struct
|
||||
m_mem_count: u32,
|
||||
m_p_mem: *mut skyline::libc::c_void,
|
||||
m_p_shader_info: *const skyline::libc::c_void,
|
||||
pub m_p_name: *const skyline::libc::c_char,
|
||||
m_vertex_shader_constant_buffer_offset: u32,
|
||||
m_pixel_shader_constant_buffer_offset: u32,
|
||||
m_p_user_shader_constant_buffer_information: *const skyline::libc::c_void,
|
||||
m_p_blend_state: *const skyline::libc::c_void,
|
||||
m_packed_values: u8,
|
||||
m_flag: u8,
|
||||
m_shader_variation: u16,
|
||||
}
|
||||
|
||||
impl Material {
|
||||
pub fn set_color_int(&mut self, idx: usize, r: u8, g: u8, b: u8, a: u8) {
|
||||
let input_color = [r, g, b, a];
|
||||
unsafe {
|
||||
self.m_colors.byte_color[idx] = input_color;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_color_float(&mut self, idx: usize, r: f32, g: f32, b: f32, a: f32) {
|
||||
unsafe {
|
||||
*(*(self.m_colors.p_float_color.add(idx)).add(0)) = r;
|
||||
*(*(self.m_colors.p_float_color.add(idx)).add(1)) = g;
|
||||
*(*(self.m_colors.p_float_color.add(idx)).add(2)) = b;
|
||||
*(*(self.m_colors.p_float_color.add(idx)).add(3)) = a;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_color(&mut self, color_type: MaterialColorType, r: f32, g: f32, b: f32, a: f32) {
|
||||
let (is_float_flag, idx) = if color_type == MaterialColorType::BlackColor {
|
||||
(MaterialFlags::BlackColorFloat as u8, 0)
|
||||
} else {
|
||||
(MaterialFlags::WhiteColorFloat as u8, 1)
|
||||
};
|
||||
if self.m_flag & (0x1 << is_float_flag) != 0 {
|
||||
self.set_color_float(idx, r, g, b, a);
|
||||
} else {
|
||||
self.set_color_int(idx, r as u8, g as u8, b as u8, a as u8);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_white_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
|
||||
self.set_color(MaterialColorType::WhiteColor, r, g, b, a);
|
||||
}
|
||||
|
||||
pub fn set_black_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
|
||||
self.set_color(MaterialColorType::BlackColor, r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Window {
|
||||
pub pane: Pane,
|
||||
// TODO
|
||||
}
|
||||
|
||||
impl Deref for Window {
|
||||
type Target = Pane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Window {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PaneNode {
|
||||
pub prev: *mut PaneNode,
|
||||
pub next: *mut PaneNode,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Group {
|
||||
pane_list: PaneNode,
|
||||
name: *const skyline::libc::c_char,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct GroupContainer {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Layout {
|
||||
vtable: u64,
|
||||
pub anim_trans_list: AnimTransformNode,
|
||||
pub root_pane: *mut Pane,
|
||||
group_container: u64,
|
||||
layout_size: f64,
|
||||
pub layout_name: *const skyline::libc::c_char,
|
||||
}
|
||||
|
||||
#[skyline::from_offset(0x59970)]
|
||||
pub unsafe fn find_pane_by_name_recursive(
|
||||
pane: *const Pane,
|
||||
s: *const skyline::libc::c_char,
|
||||
) -> *mut Pane;
|
||||
|
||||
#[skyline::from_offset(0x583c0)]
|
||||
pub unsafe fn find_pane_by_name(
|
||||
pane: *const Pane,
|
||||
s: *const skyline::libc::c_char,
|
||||
recursive: bool,
|
||||
) -> *mut Pane;
|
||||
|
||||
#[skyline::from_offset(0x37a1270)]
|
||||
pub unsafe fn pane_set_text_string(pane: *const Pane, s: *const skyline::libc::c_char);
|
||||
|
||||
#[skyline::from_offset(0x58290)]
|
||||
pub unsafe fn pane_remove_child(pane: *const Pane, child: *const Pane);
|
||||
|
||||
#[skyline::from_offset(0x58250)]
|
||||
pub unsafe fn pane_append_child(pane: *const Pane, child: *const Pane);
|
||||
|
||||
pub unsafe fn get_typeinfo_name(cls_vtable: u64) -> String {
|
||||
let typeinfo_ptr_addr = (cls_vtable - 8) as *const u64;
|
||||
let typeinfo_addr = *typeinfo_ptr_addr;
|
||||
let typeinfo_name_ptr_addr = (typeinfo_addr + 8) as *const u64;
|
||||
let type_info_name_addr = (*typeinfo_name_ptr_addr) as *const skyline::libc::c_char;
|
||||
skyline::from_c_str(type_info_name_addr)
|
||||
}
|
|
@ -1,425 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
// Maybe needs a vtable.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResVec2 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
impl ResVec2 {
|
||||
pub fn default() -> ResVec2 {
|
||||
ResVec2 { x: 0.0, y: 0.0 }
|
||||
}
|
||||
|
||||
pub fn new(x: f32, y: f32) -> ResVec2 {
|
||||
ResVec2 { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResVec3 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
impl ResVec3 {
|
||||
pub fn default() -> ResVec3 {
|
||||
ResVec3 {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(x: f32, y: f32, z: f32) -> ResVec3 {
|
||||
ResVec3 { x, y, z }
|
||||
}
|
||||
}
|
||||
|
||||
// Maybe needs a vtable.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResColor {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResPane {
|
||||
block_header_kind: u32,
|
||||
block_header_size: u32,
|
||||
flag: u8,
|
||||
base_position: u8,
|
||||
alpha: u8,
|
||||
flag_ex: u8,
|
||||
pub name: [skyline::libc::c_char; 24],
|
||||
pub user_data: [skyline::libc::c_char; 8],
|
||||
pub pos: ResVec3,
|
||||
rot_x: f32,
|
||||
rot_y: f32,
|
||||
rot_z: f32,
|
||||
pub scale_x: f32,
|
||||
pub scale_y: f32,
|
||||
pub size_x: f32,
|
||||
pub size_y: f32,
|
||||
}
|
||||
|
||||
impl ResPane {
|
||||
// For null pane
|
||||
pub fn new(name: &str) -> ResPane {
|
||||
let mut pane = ResPane {
|
||||
block_header_kind: u32::from_le_bytes([b'p', b'a', b'n', b'1']),
|
||||
block_header_size: 84,
|
||||
/// Visible | InfluencedAlpha
|
||||
flag: 0x3,
|
||||
base_position: 0,
|
||||
alpha: 0xFF,
|
||||
flag_ex: 0,
|
||||
name: [0; 24],
|
||||
user_data: [0; 8],
|
||||
pos: ResVec3 {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
},
|
||||
rot_x: 0.0,
|
||||
rot_y: 0.0,
|
||||
rot_z: 0.0,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
size_x: 30.0,
|
||||
size_y: 40.0,
|
||||
};
|
||||
pane.set_name(name);
|
||||
pane
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: &str) {
|
||||
assert!(
|
||||
name.len() <= 24,
|
||||
"Name of pane must be at most 24 characters"
|
||||
);
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(name.as_ptr(), self.name.as_mut_ptr(), name.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pos(&mut self, pos: ResVec3) {
|
||||
self.pos = pos;
|
||||
}
|
||||
|
||||
pub fn set_size(&mut self, size: ResVec2) {
|
||||
self.size_x = size.x;
|
||||
self.size_y = size.y;
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
self.name
|
||||
.iter()
|
||||
.take_while(|b| **b != 0)
|
||||
.map(|b| *b as char)
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
pub fn name_matches(&self, other: &str) -> bool {
|
||||
self.get_name() == other
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum TextBoxFlag {
|
||||
ShadowEnabled,
|
||||
ForceAssignTextLength,
|
||||
InvisibleBorderEnabled,
|
||||
DoubleDrawnBorderEnabled,
|
||||
PerCharacterTransformEnabled,
|
||||
CenterCeilingEnabled,
|
||||
LineWidthOffsetEnabled,
|
||||
ExtendedTagEnabled,
|
||||
PerCharacterTransformSplitByCharWidth,
|
||||
PerCharacterTransformAutoShadowAlpha,
|
||||
DrawFromRightToLeft,
|
||||
PerCharacterTransformOriginToCenter,
|
||||
KeepingFontScaleEnabled,
|
||||
PerCharacterTransformFixSpace,
|
||||
PerCharacterTransformSplitByCharWidthInsertSpaceEnabled,
|
||||
Max,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum TextAlignment {
|
||||
Synchronous,
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
MaxTextAlignment,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResTextBox {
|
||||
pub pane: ResPane,
|
||||
text_buf_bytes: u16,
|
||||
text_str_bytes: u16,
|
||||
material_idx: u16,
|
||||
pub font_idx: u16,
|
||||
text_position: u8,
|
||||
text_alignment: u8,
|
||||
text_box_flag: u16,
|
||||
italic_ratio: f32,
|
||||
text_str_offset: u32,
|
||||
text_cols: [ResColor; 2],
|
||||
font_size: ResVec2,
|
||||
char_space: f32,
|
||||
line_space: f32,
|
||||
text_id_offset: u32,
|
||||
shadow_offset: ResVec2,
|
||||
shadow_scale: ResVec2,
|
||||
shadow_cols: [ResColor; 2],
|
||||
shadow_italic_ratio: f32,
|
||||
line_width_offset_offset: u32,
|
||||
per_character_transform_offset: u32,
|
||||
/* Additional Info
|
||||
uint16_t text[]; // Text.
|
||||
char textId[]; // The text ID.
|
||||
u8 lineWidthOffsetCount; // The quantity of widths and offsets for each line.
|
||||
float lineOffset[]; // The offset for each line.
|
||||
float lineWidth[]; // The width of each line.
|
||||
ResPerCharacterTransform perCharacterTransform // Information for per-character animation.
|
||||
ResAnimationInfo perCharacterTransformAnimationInfo; // Animation information for per-character animation.
|
||||
*/
|
||||
}
|
||||
|
||||
impl Deref for ResTextBox {
|
||||
type Target = ResPane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ResTextBox {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl ResTextBox {
|
||||
pub fn enable_shadow(&mut self) {
|
||||
self.text_box_flag |= 0x1 << TextBoxFlag::ShadowEnabled as u8;
|
||||
}
|
||||
|
||||
pub fn text_alignment(&mut self, align: TextAlignment) {
|
||||
self.text_alignment = align as u8;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResPicture {
|
||||
pub pane: ResPane,
|
||||
vtx_cols: [ResColor; 4],
|
||||
material_idx: u16,
|
||||
tex_coord_count: u8,
|
||||
flags: u8,
|
||||
/* Additional Info
|
||||
ResVec2 texCoords[texCoordCount][VERTEX_MAX];
|
||||
uint32_t shapeBinaryIndex;
|
||||
*/
|
||||
}
|
||||
|
||||
impl Deref for ResPicture {
|
||||
type Target = ResPane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ResPicture {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResPictureWithTex<const TEX_COORD_COUNT: usize> {
|
||||
pub picture: ResPicture,
|
||||
tex_coords: [[ResVec2; TEX_COORD_COUNT]; 4],
|
||||
}
|
||||
|
||||
impl<const TEX_COORD_COUNT: usize> Deref for ResPictureWithTex<TEX_COORD_COUNT> {
|
||||
type Target = ResPane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.picture
|
||||
}
|
||||
}
|
||||
|
||||
impl<const TEX_COORD_COUNT: usize> DerefMut for ResPictureWithTex<TEX_COORD_COUNT> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.picture
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResParts {
|
||||
pub pane: ResPane,
|
||||
pub property_count: u32,
|
||||
magnify: ResVec2,
|
||||
}
|
||||
|
||||
impl Deref for ResParts {
|
||||
type Target = ResPane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ResParts {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct ResPartsProperty {
|
||||
name: [skyline::libc::c_char; 24],
|
||||
usage_flag: u8,
|
||||
basic_usage_flag: u8,
|
||||
material_usage_flag: u8,
|
||||
system_ext_user_data_override_flag: u8,
|
||||
property_offset: u32,
|
||||
ext_user_data_offset: u32,
|
||||
pane_basic_info_offset: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResPartsWithProperty<const PROPERTY_COUNT: usize> {
|
||||
pub parts: ResParts,
|
||||
property_table: [ResPartsProperty; PROPERTY_COUNT],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct ResWindowInflation {
|
||||
left: i16,
|
||||
right: i16,
|
||||
top: i16,
|
||||
bottom: i16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResWindowFrameSize {
|
||||
left: u16,
|
||||
right: u16,
|
||||
top: u16,
|
||||
bottom: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResWindowContent {
|
||||
vtx_cols: [ResColor; 4],
|
||||
material_idx: u16,
|
||||
tex_coord_count: u8,
|
||||
padding: [u8; 1],
|
||||
/* Additional Info
|
||||
nn::util::Float2 texCoords[texCoordCount][VERTEX_MAX];
|
||||
*/
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResWindowContentWithTexCoords<const TEX_COORD_COUNT: usize> {
|
||||
pub window_content: ResWindowContent,
|
||||
// This has to be wrong.
|
||||
// Should be [[ResVec2; TEX_COORD_COUNT]; 4]?
|
||||
tex_coords: [[ResVec3; TEX_COORD_COUNT]; 1],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResWindowFrame {
|
||||
material_idx: u16,
|
||||
texture_flip: u8,
|
||||
padding: [u8; 1],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResWindow {
|
||||
pub pane: ResPane,
|
||||
inflation: ResWindowInflation,
|
||||
frame_size: ResWindowFrameSize,
|
||||
frame_count: u8,
|
||||
window_flags: u8,
|
||||
padding: [u8; 2],
|
||||
content_offset: u32,
|
||||
frame_offset_table_offset: u32,
|
||||
content: ResWindowContent,
|
||||
/* Additional Info
|
||||
|
||||
ResWindowContent content;
|
||||
|
||||
detail::uint32_t frameOffsetTable[frameCount];
|
||||
ResWindowFrame frames;
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
impl Deref for ResWindow {
|
||||
type Target = ResPane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pane
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ResWindow {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.pane
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResWindowWithTexCoordsAndFrames<const TEX_COORD_COUNT: usize, const FRAME_COUNT: usize> {
|
||||
pub window: ResWindow,
|
||||
content: ResWindowContentWithTexCoords<TEX_COORD_COUNT>,
|
||||
frame_offset_table: [u32; FRAME_COUNT],
|
||||
frames: [ResWindowFrame; FRAME_COUNT],
|
||||
}
|
||||
|
||||
impl<const TEX_COORD_COUNT: usize, const FRAME_COUNT: usize> Deref
|
||||
for ResWindowWithTexCoordsAndFrames<TEX_COORD_COUNT, FRAME_COUNT>
|
||||
{
|
||||
type Target = ResPane;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.window
|
||||
}
|
||||
}
|
||||
|
||||
impl<const TEX_COORD_COUNT: usize, const FRAME_COUNT: usize> DerefMut
|
||||
for ResWindowWithTexCoordsAndFrames<TEX_COORD_COUNT, FRAME_COUNT>
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.window
|
||||
}
|
||||
}
|
|
@ -1,10 +1,76 @@
|
|||
use crate::common::{get_player_dmg_digits, is_ready_go, is_training_mode};
|
||||
use crate::consts::FighterId;
|
||||
use crate::training::ui::*;
|
||||
use crate::{common::menu::QUICK_MENU_ACTIVE, training::combo::FRAME_ADVANTAGE};
|
||||
use skyline::nn::ui2d::*;
|
||||
use smash::ui2d::{SmashPane, SmashTextBox};
|
||||
use training_mod_consts::{OnOff, MENU};
|
||||
use training_mod_tui::gauge::GaugeState;
|
||||
|
||||
pub unsafe fn iterate_anim_list(
|
||||
anim_transform_node: &mut AnimTransformNode,
|
||||
layout_name: Option<&str>,
|
||||
) {
|
||||
let mut curr = anim_transform_node as *mut AnimTransformNode;
|
||||
let mut _anim_idx = 0;
|
||||
while !curr.is_null() {
|
||||
// Only if valid
|
||||
if curr != (*curr).next {
|
||||
let anim_transform = (curr as *mut u64).add(2) as *mut AnimTransform;
|
||||
|
||||
parse_anim_transform(anim_transform.as_mut().unwrap(), layout_name);
|
||||
}
|
||||
|
||||
curr = (*curr).next;
|
||||
_anim_idx += 1;
|
||||
if curr == anim_transform_node as *mut AnimTransformNode || curr == (*curr).next {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn parse_anim_transform(anim_transform: &mut AnimTransform, layout_name: Option<&str>) {
|
||||
let res_animation_block_data_start = anim_transform.res_animation_block as u64;
|
||||
let res_animation_block = &*anim_transform.res_animation_block;
|
||||
let mut anim_cont_offsets = (res_animation_block_data_start
|
||||
+ res_animation_block.anim_cont_offsets_offset as u64)
|
||||
as *const u32;
|
||||
for _anim_cont_idx in 0..res_animation_block.anim_cont_count {
|
||||
let anim_cont_offset = *anim_cont_offsets;
|
||||
let res_animation_cont = (res_animation_block_data_start + anim_cont_offset as u64)
|
||||
as *const ResAnimationContent;
|
||||
|
||||
let name = skyline::try_from_c_str((*res_animation_cont).name.as_ptr())
|
||||
.unwrap_or("UNKNOWN".to_string());
|
||||
let anim_type = (*res_animation_cont).anim_content_type;
|
||||
|
||||
// AnimContentType 1 == MATERIAL
|
||||
if name.starts_with("set_dmg_num") && anim_type == 1 {
|
||||
if let Some(layout_name) = layout_name {
|
||||
let (hundreds, tens, ones, dec) = get_player_dmg_digits(match layout_name {
|
||||
"p1" => FighterId::Player,
|
||||
"p2" => FighterId::CPU,
|
||||
_ => panic!("Unknown layout name: {}", layout_name),
|
||||
});
|
||||
|
||||
if name == "set_dmg_num_3" {
|
||||
anim_transform.frame = hundreds as f32;
|
||||
}
|
||||
if name == "set_dmg_num_2" {
|
||||
anim_transform.frame = tens as f32;
|
||||
}
|
||||
if name == "set_dmg_num_1" {
|
||||
anim_transform.frame = ones as f32;
|
||||
}
|
||||
if name == "set_dmg_num_dec" {
|
||||
anim_transform.frame = dec as f32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anim_cont_offsets = anim_cont_offsets.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub static NUM_DISPLAY_PANES: usize = 1;
|
||||
pub static NUM_MENU_TEXT_OPTIONS: usize = 27;
|
||||
pub static NUM_MENU_TEXT_SLIDERS: usize = 4;
|
||||
|
@ -101,9 +167,8 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
if is_training_mode() && is_ready_go() && layout_name == "info_melee" {
|
||||
for player_name in &["p1", "p2"] {
|
||||
if let Some(parent) = root_pane.find_pane_by_name_recursive(player_name) {
|
||||
let _p1_layout_name =
|
||||
skyline::from_c_str((*(*parent.as_parts()).layout).layout_name);
|
||||
let anim_list = &mut (*(*parent.as_parts()).layout).anim_trans_list;
|
||||
let _p1_layout_name = skyline::from_c_str((*parent.as_parts().layout).layout_name);
|
||||
let anim_list = &mut (*parent.as_parts().layout).anim_trans_list;
|
||||
|
||||
let mut has_altered_anim_list = false;
|
||||
let (hundreds, tens, _, _) = get_player_dmg_digits(match *player_name {
|
||||
|
@ -150,7 +215,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
if dmg_num.alpha != 255 || dmg_num.global_alpha != 255 {
|
||||
dmg_num.set_visible(true);
|
||||
if !has_altered_anim_list {
|
||||
anim_list.iterate_anim_list(Some(player_name));
|
||||
iterate_anim_list(anim_list, Some(player_name));
|
||||
has_altered_anim_list = true;
|
||||
}
|
||||
}
|
||||
|
@ -181,12 +246,12 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
}
|
||||
|
||||
if let Some(header) = root_pane.find_pane_by_name_recursive("trMod_disp_0_header") {
|
||||
header.set_text_string("Frame Advantage");
|
||||
header.as_textbox().set_text_string("Frame Advantage");
|
||||
}
|
||||
|
||||
if let Some(text) = root_pane.find_pane_by_name_recursive("trMod_disp_0_txt") {
|
||||
text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str());
|
||||
let text = text.as_textbox();
|
||||
text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str());
|
||||
match FRAME_ADVANTAGE {
|
||||
x if x < 0 => text.set_color(200, 8, 8, 255),
|
||||
x if x == 0 => text.set_color(0, 0, 0, 255),
|
||||
|
@ -207,7 +272,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
|
||||
for quit_txt_s in &["set_txt_00", "set_txt_01"] {
|
||||
if let Some(quit_txt) = quit_button.find_pane_by_name_recursive(quit_txt_s) {
|
||||
quit_txt.set_text_string(if QUICK_MENU_ACTIVE {
|
||||
quit_txt.as_textbox().set_text_string(if QUICK_MENU_ACTIVE {
|
||||
"Modpack Menu"
|
||||
} else {
|
||||
// Awkward. We should get the o.g. translation for non-english games
|
||||
|
@ -270,7 +335,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
(0..NUM_MENU_TABS).for_each(|idx| {
|
||||
root_pane
|
||||
.find_pane_by_name_recursive(format!("trMod_menu_tab_{idx}").as_str())
|
||||
.map(|text| text.set_text_string(tab_titles[idx]));
|
||||
.map(|text| text.as_textbox().set_text_string(tab_titles[idx]));
|
||||
});
|
||||
|
||||
if app.outer_list {
|
||||
|
@ -308,15 +373,15 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
let list = &tab.lists[list_section];
|
||||
let submenu = &list.items[list_idx];
|
||||
let is_selected = list.state.selected().filter(|s| *s == list_idx).is_some();
|
||||
let text = text.as_textbox();
|
||||
text.set_text_string(submenu.submenu_title);
|
||||
text.set_visible(true);
|
||||
let text = text.as_textbox();
|
||||
if is_selected {
|
||||
text.set_color(0x27, 0x4E, 0x13, 255);
|
||||
if let Some(footer) =
|
||||
root_pane.find_pane_by_name_recursive("trMod_menu_footer_txt")
|
||||
{
|
||||
footer.set_text_string(submenu.help_text);
|
||||
footer.as_textbox().set_text_string(submenu.help_text);
|
||||
}
|
||||
} else {
|
||||
text.set_color(255, 255, 255, 255);
|
||||
|
@ -452,7 +517,7 @@ pub unsafe fn layout_build_parts_impl(
|
|||
};
|
||||
}
|
||||
|
||||
let root_pane = &*(*layout).root_pane;
|
||||
let root_pane = &mut *(*layout).root_pane;
|
||||
let block = data as *mut ResPane;
|
||||
let menu_pos = ResVec3::new(-360.0, 440.0, 0.0);
|
||||
|
||||
|
|
Loading…
Reference in a new issue