@@ -2798,8 +2798,18 @@ impl ToolkitTabViewer<'_> {
27982798 groups. push ( ( date, vec ! [ ( path, replay) ] ) ) ;
27992799 }
28002800
2801- // Build a map from Id to replay for activation handling
2801+ // Build maps from Id to replay and path for activation and context menu handling
28022802 let mut id_to_replay: HashMap < egui:: Id , Arc < RwLock < Replay > > > = HashMap :: new ( ) ;
2803+ let mut id_to_path: HashMap < egui:: Id , std:: path:: PathBuf > = HashMap :: new ( ) ;
2804+
2805+ // Pre-populate the maps before building the tree
2806+ for ( _date, replays) in & groups {
2807+ for ( path, replay) in replays {
2808+ let id = egui:: Id :: new ( path) ;
2809+ id_to_replay. insert ( id, replay. clone ( ) ) ;
2810+ id_to_path. insert ( id, path. clone ( ) ) ;
2811+ }
2812+ }
28032813
28042814 let tree = egui_ltreeview:: TreeView :: new ( ui. make_persistent_id ( "replay_date_tree" ) ) ;
28052815 let ( _response, actions) = tree. show ( ui, |builder| {
@@ -2823,11 +2833,11 @@ impl ToolkitTabViewer<'_> {
28232833
28242834 let is_open = builder. dir ( egui:: Id :: new ( ( "date_group" , date) ) , format ! ( "{} ({}){}" , date, replays. len( ) , win_rate) ) ;
28252835 if is_open {
2826- for ( path, replay ) in replays {
2836+ for ( path, _replay ) in replays {
28272837 let id = egui:: Id :: new ( path) ;
2828- id_to_replay . insert ( id , replay . clone ( ) ) ;
2838+ let path_clone = path . clone ( ) ;
28292839
2830- let replay_guard = replay . read ( ) ;
2840+ let replay_guard = id_to_replay . get ( & id ) . unwrap ( ) . read ( ) ;
28312841 let ship_name = replay_guard. vehicle_name ( & metadata_provider) ;
28322842 let map_name = replay_guard. map_name ( & metadata_provider) ;
28332843 let game_time = replay_guard. game_time ( ) . to_string ( ) ;
@@ -2843,7 +2853,17 @@ impl ToolkitTabViewer<'_> {
28432853 None => RichText :: new ( label) ,
28442854 } ;
28452855
2846- builder. leaf ( id, label_text) ;
2856+ let node = egui_ltreeview:: NodeBuilder :: leaf ( id) . label ( label_text) . context_menu ( move |ui| {
2857+ if ui. button ( "Copy Path" ) . clicked ( ) {
2858+ ui. ctx ( ) . copy_text ( path_clone. to_string_lossy ( ) . into_owned ( ) ) ;
2859+ ui. close_kind ( UiKind :: Menu ) ;
2860+ }
2861+ if ui. button ( "Show in File Explorer" ) . clicked ( ) {
2862+ util:: open_file_explorer ( & path_clone) ;
2863+ ui. close_kind ( UiKind :: Menu ) ;
2864+ }
2865+ } ) ;
2866+ builder. node ( node) ;
28472867 }
28482868 }
28492869 builder. close_dir ( ) ;
@@ -2904,8 +2924,18 @@ impl ToolkitTabViewer<'_> {
29042924 b_recent. cmp ( a_recent)
29052925 } ) ;
29062926
2907- // Build a map from Id to replay for activation handling
2927+ // Build maps from Id to replay and path for activation and context menu handling
29082928 let mut id_to_replay: HashMap < egui:: Id , Arc < RwLock < Replay > > > = HashMap :: new ( ) ;
2929+ let mut id_to_path: HashMap < egui:: Id , std:: path:: PathBuf > = HashMap :: new ( ) ;
2930+
2931+ // Pre-populate the maps before building the tree
2932+ for ( _ship_name, replays) in & groups {
2933+ for ( path, replay) in replays {
2934+ let id = egui:: Id :: new ( path) ;
2935+ id_to_replay. insert ( id, replay. clone ( ) ) ;
2936+ id_to_path. insert ( id, path. clone ( ) ) ;
2937+ }
2938+ }
29092939
29102940 let tree = egui_ltreeview:: TreeView :: new ( ui. make_persistent_id ( "replay_ship_tree" ) ) ;
29112941 let ( _response, actions) = tree. show ( ui, |builder| {
@@ -2929,11 +2959,11 @@ impl ToolkitTabViewer<'_> {
29292959
29302960 let is_open = builder. dir ( egui:: Id :: new ( ( "ship_group" , ship_name) ) , format ! ( "{} ({}){}" , ship_name, replays. len( ) , win_rate) ) ;
29312961 if is_open {
2932- for ( path, replay ) in replays {
2962+ for ( path, _replay ) in replays {
29332963 let id = egui:: Id :: new ( path) ;
2934- id_to_replay . insert ( id , replay . clone ( ) ) ;
2964+ let path_clone = path . clone ( ) ;
29352965
2936- let replay_guard = replay . read ( ) ;
2966+ let replay_guard = id_to_replay . get ( & id ) . unwrap ( ) . read ( ) ;
29372967 let map_name = replay_guard. map_name ( & metadata_provider) ;
29382968 let game_time = replay_guard. game_time ( ) . to_string ( ) ;
29392969 let battle_result = replay_guard. battle_result ( ) ;
@@ -2947,7 +2977,17 @@ impl ToolkitTabViewer<'_> {
29472977 None => RichText :: new ( label) ,
29482978 } ;
29492979
2950- builder. leaf ( id, label_text) ;
2980+ let node = egui_ltreeview:: NodeBuilder :: leaf ( id) . label ( label_text) . context_menu ( move |ui| {
2981+ if ui. button ( "Copy Path" ) . clicked ( ) {
2982+ ui. ctx ( ) . copy_text ( path_clone. to_string_lossy ( ) . into_owned ( ) ) ;
2983+ ui. close_kind ( UiKind :: Menu ) ;
2984+ }
2985+ if ui. button ( "Show in File Explorer" ) . clicked ( ) {
2986+ util:: open_file_explorer ( & path_clone) ;
2987+ ui. close_kind ( UiKind :: Menu ) ;
2988+ }
2989+ } ) ;
2990+ builder. node ( node) ;
29512991 }
29522992 }
29532993 builder. close_dir ( ) ;
0 commit comments