@@ -3194,14 +3194,56 @@ impl<'a> VulkanEngine<'a> {
31943194 out_track_info_rect = Some ( rect) ;
31953195 } else {
31963196 columns[ 2 ] . style_mut ( ) . visuals . override_text_color = Some ( egui:: Color32 :: from_gray ( 235 ) ) ; // Slightly lighter for contrast
3197- columns[ 2 ] . heading ( "Track Info" ) ;
3197+ let heading_text = if state. playlist . len ( ) > 1 {
3198+ format ! ( "Track Info ({}/{})" , state. playlist_index + 1 , state. playlist. len( ) )
3199+ } else {
3200+ "Track Info" . to_string ( )
3201+ } ;
3202+ columns[ 2 ] . heading ( heading_text) ;
31983203 columns[ 2 ] . separator ( ) ;
3204+
3205+ let render_smooth_marquee = |ui : & mut egui:: Ui , text : & str , size : f32 , is_title : bool | {
3206+ let available_width = ui. available_width ( ) ;
3207+ let font_id = egui:: FontId :: proportional ( size) ;
3208+ let color = ui. style ( ) . visuals . override_text_color . unwrap_or ( egui:: Color32 :: from_gray ( 235 ) ) ;
3209+ let text_color = if is_title { egui:: Color32 :: WHITE } else { color } ;
3210+
3211+ let galley = ui. painter ( ) . layout_no_wrap ( text. to_string ( ) , font_id, text_color) ;
3212+ let text_width = galley. rect . width ( ) ;
3213+ let height = galley. rect . height ( ) ;
3214+
3215+ let ( rect, _response) = ui. allocate_exact_size ( egui:: vec2 ( available_width, height) , egui:: Sense :: hover ( ) ) ;
3216+ let painter = ui. painter ( ) . with_clip_rect ( rect) ;
3217+
3218+ if text_width > available_width {
3219+ let max_scroll = text_width - available_width;
3220+ let scroll_duration = max_scroll / 35.0 ; // 35 pixels per second
3221+ let total_period = 2.0 + scroll_duration + 2.0 + scroll_duration;
3222+ let t = ( state. current_seconds as f32 ) % total_period;
3223+
3224+ let offset = if t < 2.0 {
3225+ 0.0
3226+ } else if t < 2.0 + scroll_duration {
3227+ let progress = ( t - 2.0 ) / scroll_duration;
3228+ progress * max_scroll
3229+ } else if t < 2.0 + scroll_duration + 2.0 {
3230+ max_scroll
3231+ } else {
3232+ let progress = ( t - ( 2.0 + scroll_duration + 2.0 ) ) / scroll_duration;
3233+ max_scroll - ( progress * max_scroll)
3234+ } ;
3235+
3236+ painter. galley ( rect. min + egui:: vec2 ( -offset, 0.0 ) , galley, text_color) ;
3237+ } else {
3238+ painter. galley ( rect. min , galley, text_color) ;
3239+ }
3240+ } ;
3241+
31993242 let current_path_str = if state. playlist_index < state. playlist . len ( ) {
32003243 state. playlist [ state. playlist_index ] . clone ( )
32013244 } else {
32023245 state. song_title . clone ( )
32033246 } ;
3204-
32053247 let is_network = current_path_str. starts_with ( "http://" ) || current_path_str. starts_with ( "https://" ) ;
32063248 let file_name = if is_network {
32073249 state. song_title . clone ( )
@@ -3211,48 +3253,64 @@ impl<'a> VulkanEngine<'a> {
32113253 let file_dir = if is_network {
32123254 current_path_str
32133255 } else {
3214- std:: path:: Path :: new ( & current_path_str) . parent ( ) . unwrap_or ( std:: path:: Path :: new ( "" ) ) . to_string_lossy ( ) . to_string ( )
3215- } ;
3216-
3217- columns[ 2 ] . horizontal ( |ui| { ui. label ( "File/Title" ) ; ui. label ( & file_name) ; } ) ;
3218- columns[ 2 ] . horizontal ( |ui| { ui. label ( "Artist" ) ; ui. label ( & state. artist ) ; } ) ;
3219- columns[ 2 ] . horizontal ( |ui| { ui. label ( if is_network { "URL" } else { "Path" } ) ; ui. label ( & file_dir) ; } ) ;
3220- if state. playlist . len ( ) > 1 {
3221- columns[ 2 ] . horizontal ( |ui| { ui. label ( "Playlist" ) ; ui. label ( format ! ( "{} / {}" , state. playlist_index + 1 , state. playlist. len( ) ) ) ; } ) ;
3222- }
3223- if state. playlist_index + 1 < state. playlist . len ( ) {
3224- let next_path = std:: path:: Path :: new ( & state. playlist [ state. playlist_index + 1 ] ) ;
3225- let next_song = next_path. file_name ( ) . unwrap_or_default ( ) . to_string_lossy ( ) . to_string ( ) ;
3226- let max_len = 30 ;
3227- let display_str = if next_song. chars ( ) . count ( ) > max_len {
3228- let chars_count = next_song. chars ( ) . count ( ) ;
3229- let offset = ( state. current_seconds * 4.0 ) as usize % ( chars_count + 10 ) ;
3230- if offset < chars_count {
3231- let mut padded = next_song. clone ( ) ;
3232- padded. push_str ( " " ) ;
3233- padded. push_str ( & next_song) ;
3234- padded. chars ( ) . skip ( offset) . take ( max_len) . collect :: < String > ( )
3256+ let abs_path = if std:: path:: Path :: new ( & current_path_str) . is_absolute ( ) {
3257+ std:: path:: PathBuf :: from ( & current_path_str)
3258+ } else if let Ok ( cwd) = std:: env:: current_dir ( ) {
3259+ cwd. join ( & current_path_str)
3260+ } else {
3261+ std:: path:: PathBuf :: from ( & current_path_str)
3262+ } ;
3263+ let path_str = abs_path. to_string_lossy ( ) . to_string ( ) ;
3264+ if let Ok ( home) = std:: env:: var ( "HOME" ) {
3265+ if path_str. starts_with ( & home) {
3266+ path_str. replacen ( & home, "~" , 1 )
32353267 } else {
3236- next_song. chars ( ) . take ( max_len) . collect :: < String > ( )
3268+ path_str
3269+ }
3270+ } else if let Ok ( home) = std:: env:: var ( "USERPROFILE" ) {
3271+ if path_str. starts_with ( & home) {
3272+ path_str. replacen ( & home, "%USERPROFILE%" , 1 )
3273+ } else {
3274+ path_str
32373275 }
32383276 } else {
3239- next_song
3240- } ;
3241- columns[ 2 ] . horizontal ( |ui| { ui. label ( "Next Song:" ) ; ui. label ( display_str) ; } ) ;
3242- }
3277+ path_str
3278+ }
3279+ } ;
3280+
3281+ // 1. Title/File Name (Prominent at top, smooth marquee if long)
3282+ render_smooth_marquee ( & mut columns[ 2 ] , & file_name, 15.0 , true ) ;
3283+
3284+ // 2. Artist
3285+ columns[ 2 ] . horizontal ( |ui| { ui. label ( "Artist" ) ; ui. label ( & state. artist ) ; } ) ;
3286+
3287+ // 3. Path / URL (Smooth marquee if long, stretches to the right edge)
3288+ let path_label = if is_network { "URL" } else { "Path" } ;
3289+ columns[ 2 ] . horizontal ( |ui| {
3290+ ui. label ( path_label) ;
3291+ render_smooth_marquee ( ui, & file_dir, 14.0 , false ) ;
3292+ } ) ;
3293+
3294+ // 4. Type
32433295 columns[ 2 ] . horizontal ( |ui| { ui. label ( "Type" ) ; ui. label ( & state. module_type ) ; } ) ;
3296+
3297+ // 5. Video
32443298 if let Some ( video) = & state. video_info {
32453299 if video == "Unsupported Codec" {
32463300 columns[ 2 ] . horizontal ( |ui| { ui. label ( "Video" ) ; ui. label ( video) ; } ) ;
32473301 } else {
32483302 columns[ 2 ] . horizontal ( |ui| { ui. label ( "Video" ) ; ui. label ( format ! ( "{} (Video stream available)" , video) ) ; } ) ;
32493303 }
32503304 }
3305+
3306+ // 6. Track layout parameters
32513307 if state. bpm > 0 { columns[ 2 ] . horizontal ( |ui| { ui. label ( "BPM" ) ; ui. label ( format ! ( "{}" , state. bpm) ) ; } ) ; }
32523308 if state. speed > 0 { columns[ 2 ] . horizontal ( |ui| { ui. label ( "Speed" ) ; ui. label ( format ! ( "{}" , state. speed) ) ; } ) ; }
32533309 if state. num_patterns > 0 { columns[ 2 ] . horizontal ( |ui| { ui. label ( "Patterns" ) ; ui. label ( format ! ( "{}" , state. num_patterns) ) ; } ) ; }
32543310 if state. num_instruments > 0 { columns[ 2 ] . horizontal ( |ui| { ui. label ( "Instruments" ) ; ui. label ( format ! ( "{}" , state. num_instruments) ) ; } ) ; }
32553311 if state. num_samples > 0 { columns[ 2 ] . horizontal ( |ui| { ui. label ( "Samples" ) ; ui. label ( format ! ( "{}" , state. num_samples) ) ; } ) ; }
3312+
3313+ // 7. Audio technical parameters
32563314 columns[ 2 ] . horizontal ( |ui| { ui. label ( "Sample Rate" ) ; ui. label ( format ! ( "{} Hz" , state. current_sample_rate as u32 ) ) ; } ) ;
32573315 columns[ 2 ] . horizontal ( |ui| { ui. label ( "Bitrate" ) ; ui. label ( state. bitrate . map ( |b| format ! ( "{} kbps" , b) ) . unwrap_or_else ( || "Unknown" . to_string ( ) ) ) ; } ) ;
32583316 columns[ 2 ] . horizontal ( |ui| {
@@ -3277,6 +3335,17 @@ impl<'a> VulkanEngine<'a> {
32773335 ui. label ( format ! ( "{:.1}s" , state. duration_seconds) ) ;
32783336 }
32793337 } ) ;
3338+
3339+ // 8. Next Song (placed at the bottom, smooth marquee if long)
3340+ if state. playlist_index + 1 < state. playlist . len ( ) {
3341+ let next_path = std:: path:: Path :: new ( & state. playlist [ state. playlist_index + 1 ] ) ;
3342+ let next_song = next_path. file_name ( ) . unwrap_or_default ( ) . to_string_lossy ( ) . to_string ( ) ;
3343+ columns[ 2 ] . horizontal ( |ui| {
3344+ ui. label ( "Next Song:" ) ;
3345+ render_smooth_marquee ( ui, & next_song, 14.0 , false ) ;
3346+ } ) ;
3347+ }
3348+
32803349 out_track_info_rect = Some ( columns[ 2 ] . min_rect ( ) ) ;
32813350 }
32823351 } ) ;
0 commit comments