From 89e768e3a41fff63da125a927d14da3326caab7c Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Sat, 29 Nov 2025 01:52:23 -0800 Subject: [PATCH] Add WIM file selection section --- boot_diags/src/app.rs | 6 +- config/config.json5 | 11 ++- core/src/state.rs | 3 +- deja_vu/src/app.rs | 12 ++-- win_installer/src/app.rs | 91 +++++++++++++++++++++--- win_installer/src/components/wim_scan.rs | 42 +++++------ win_installer/src/wim.rs | 36 +++++++++- 7 files changed, 156 insertions(+), 45 deletions(-) diff --git a/boot_diags/src/app.rs b/boot_diags/src/app.rs index d3e9e89..e804379 100644 --- a/boot_diags/src/app.rs +++ b/boot_diags/src/app.rs @@ -657,8 +657,9 @@ fn build_footer_string(cur_mode: Mode) -> String { | Mode::PEMenu | Mode::PreClone | Mode::PostClone - | Mode::ScanWinImages + | Mode::ScanWinSources | Mode::SelectTableType + | Mode::SelectWinSource | Mode::SelectWinImage | Mode::SetUserName => { panic!("This shouldn't happen?") @@ -774,7 +775,8 @@ fn build_left_items(app: &App) -> Action { | Mode::PreClone | Mode::Clone | Mode::PostClone - | Mode::ScanWinImages + | Mode::ScanWinSources + | Mode::SelectWinSource | Mode::SelectWinImage | Mode::SetUserName => { panic!("This shouldn't happen?") diff --git a/config/config.json5 b/config/config.json5 index 11e6d5b..d9ddca5 100644 --- a/config/config.json5 +++ b/config/config.json5 @@ -188,7 +188,7 @@ "": "Quit", "": "Suspend" }, - "ScanWinImages": { + "ScanWinSources": { "": "Process", "": "FindWimNetwork", "": "Quit", @@ -196,6 +196,15 @@ "": "Quit", "": "Suspend" }, + "SelectWinSource": { + "": "Process", + "": "KeyUp", + "": "KeyDown", + "": "Quit", + "": "Quit", + "": "Quit", + "": "Suspend" + }, "SelectWinImage": { "": "Process", "": "KeyUp", diff --git a/core/src/state.rs b/core/src/state.rs index c0bcadd..e386a1c 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -43,7 +43,8 @@ pub enum Mode { SelectParts, PostClone, // Windows Installer - ScanWinImages, + ScanWinSources, + SelectWinSource, SelectWinImage, SetUserName, // WinPE diff --git a/deja_vu/src/app.rs b/deja_vu/src/app.rs index 75194ad..450f423 100644 --- a/deja_vu/src/app.rs +++ b/deja_vu/src/app.rs @@ -129,7 +129,8 @@ impl App { | Mode::LogView | Mode::PEMenu | Mode::Process - | Mode::ScanWinImages + | Mode::ScanWinSources + | Mode::SelectWinSource | Mode::SelectWinImage | Mode::SetBootMode | Mode::SetUserName => panic!("This shouldn't happen?"), @@ -157,7 +158,8 @@ impl App { | Mode::LogView | Mode::PEMenu | Mode::Process - | Mode::ScanWinImages + | Mode::ScanWinSources + | Mode::SelectWinSource | Mode::SelectWinImage | Mode::SetBootMode | Mode::SetUserName => panic!("This shouldn't happen?"), @@ -639,7 +641,8 @@ fn build_footer_string(cur_mode: Mode) -> String { | Mode::LogView | Mode::PEMenu | Mode::Process - | Mode::ScanWinImages + | Mode::ScanWinSources + | Mode::SelectWinSource | Mode::SelectWinImage | Mode::SetBootMode | Mode::SetUserName => panic!("This shouldn't happen?"), @@ -715,7 +718,8 @@ fn build_left_items(app: &App) -> Action { | Mode::LogView | Mode::PEMenu | Mode::Process - | Mode::ScanWinImages + | Mode::ScanWinSources + | Mode::SelectWinSource | Mode::SelectWinImage | Mode::SetBootMode | Mode::SetUserName => panic!("This shouldn't happen?"), diff --git a/win_installer/src/app.rs b/win_installer/src/app.rs index ad3f845..c476050 100644 --- a/win_installer/src/app.rs +++ b/win_installer/src/app.rs @@ -102,8 +102,9 @@ impl App { Mode::Home | Mode::InstallDrivers => Mode::ScanDisks, Mode::ScanDisks => Mode::SelectDisks, Mode::SelectDisks => Mode::SelectTableType, - Mode::SelectTableType => Mode::ScanWinImages, - Mode::ScanWinImages => Mode::SelectWinImage, + Mode::SelectTableType => Mode::ScanWinSources, + Mode::ScanWinSources => Mode::SelectWinSource, + Mode::SelectWinSource => Mode::SelectWinImage, Mode::SelectWinImage => Mode::SetUserName, Mode::SetUserName => Mode::Confirm, Mode::Confirm => Mode::Process, // i.e. format, apply, etc @@ -144,7 +145,7 @@ impl App { String::from("Scanning Disks..."), ))?; } - Mode::ScanWinImages => self.state.scan_wim_local(), + Mode::ScanWinSources => self.state.scan_wim_local(), Mode::Done => { self.action_tx .send(Action::DisplayPopup(popup::Type::Success, popup::fortune()))?; @@ -297,12 +298,13 @@ impl App { self.action_tx.send(Action::SetMode(Mode::SelectDisks))?; } Mode::SetUserName => { - self.action_tx.send(Action::SetMode(Mode::SelectWinImage))?; + self.action_tx + .send(Action::SetMode(Mode::SelectWinSource))?; } _ => {} }, Action::Process => match self.cur_mode { - Mode::Confirm | Mode::ScanWinImages => { + Mode::Confirm | Mode::ScanWinSources => { self.action_tx.send(Action::NextScreen)?; } Mode::Done => { @@ -338,7 +340,7 @@ impl App { } } } - Mode::SelectWinImage => { + Mode::SelectWinSource => { // TODO: FIXME // PLAN: Abuse Action::Select to send (file_index, image_index) to set all at once // self.state.wim_file_index = TODO; @@ -399,8 +401,9 @@ fn build_footer_string(cur_mode: Mode) -> String { "(Enter) to select / / (i) to install driver / (r) to rescan / (q) to quit", ), Mode::SelectTableType => String::from("(Enter) to select / (b) to go back / (q) to quit"), + Mode::SelectWinSource => String::from("(Enter) to select / (q) to quit"), Mode::SelectWinImage => String::from("(Enter) to select / (q) to quit"), - Mode::ScanWinImages => { + Mode::ScanWinSources => { String::from("(Enter) to continue / (n) to scan network / (q) to quit") } Mode::SetUserName => String::from("(Enter) to continue / (Esc) to go back"), @@ -445,15 +448,25 @@ fn build_left_items(app: &App) -> Action { title = String::from("Processing"); // TODO: FIXME } - Mode::ScanWinImages => { + Mode::ScanWinSources => { select_type = SelectionType::Loop; title = String::from("Scanning"); // TODO: FIXME } + Mode::SelectWinSource => { + select_type = SelectionType::One; + title = String::from("Select Windows Source"); + if let Ok(wim_sources) = app.state.wim_sources.lock() { + wim_sources + .get_file_list() + .iter() + .for_each(|wim_file| items.push(wim_file.path.clone())); + } + } Mode::SelectWinImage => { select_type = SelectionType::One; title = String::from("Select Windows Image"); - // TODO: FIXME, I think this whole section could be better... + // TODO: FIXME } Mode::SelectDisks => { select_type = SelectionType::One; @@ -546,7 +559,65 @@ fn build_right_items(app: &App) -> Action { .iter() .for_each(|disk| items.push(get_disk_description_right(disk, &None))); } - Mode::SelectTableType | Mode::SelectWinImage | Mode::SetUserName | Mode::Confirm => { + Mode::SelectWinSource => { + // Disk Info + let type_str = match app.state.table_type.clone().unwrap() { + PartitionTableType::Guid => "GPT", + PartitionTableType::Legacy => "MBR", + }; + let mut label_dv_lines = vec![ + DVLine { + line_parts: vec![ + String::from("Dest"), + String::from(" (WARNING: ALL DATA WILL BE DELETED!)"), + ], + line_colors: vec![Color::Cyan, Color::Red], + }, + DVLine { + line_parts: vec![format!(" (Will be formatted {type_str})")], + line_colors: vec![Color::Yellow], + }, + DVLine::blank(), + ]; + let disk_list = app.state.disk_list.lock().unwrap(); + if let Some(index) = app.state.disk_index_dest + && let Some(disk) = disk_list.get(index) + { + get_disk_description_right(disk, &None) + .into_iter() + .for_each(|dv_line| label_dv_lines.push(dv_line)); + } + labels.push(label_dv_lines); + + // WIM Info + if let Ok(wim_sources) = app.state.wim_sources.lock() { + wim_sources.get_file_list().iter().for_each(|source| { + let mut wim_dv_lines = vec![ + DVLine { + line_parts: vec![String::from("WIM Info")], + line_colors: vec![Color::Cyan], + }, + DVLine { + line_parts: vec![source.path.clone()], + line_colors: vec![Color::Reset], + }, + DVLine::blank(), + DVLine { + line_parts: vec![String::from("Images")], + line_colors: vec![Color::Blue], + }, + ]; + source.images.iter().for_each(|image| { + wim_dv_lines.push(DVLine { + line_parts: vec![format!("{image}")], + line_colors: vec![Color::Reset], + }) + }); + items.push(wim_dv_lines); + }); + } + } + Mode::SelectTableType | Mode::SetUserName | Mode::Confirm => { // Labels let dest_dv_line = DVLine { line_parts: vec![ diff --git a/win_installer/src/components/wim_scan.rs b/win_installer/src/components/wim_scan.rs index af7ad6d..d2c6caf 100644 --- a/win_installer/src/components/wim_scan.rs +++ b/win_installer/src/components/wim_scan.rs @@ -77,7 +77,7 @@ impl Component for WimScan { } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { - if self.mode != Mode::ScanWinImages { + if self.mode != Mode::ScanWinSources { return Ok(()); } frame.render_widget(Clear, area); @@ -117,36 +117,26 @@ impl Component for WimScan { .iter() .map(|wimfile| ListItem::new(format!("{}\n\n", wimfile.path))), ); - let left_list = List::new(left_list) - .block( - Block::default() - .borders(Borders::ALL) - .padding(Padding::new(1, 1, 1, 1)), - ) - .highlight_spacing(HighlightSpacing::Always) - .highlight_style(Style::new().green().bold()) - .highlight_symbol(" --> ") - .repeat_highlight_symbol(false); + let left_list = List::new(left_list).block( + Block::default() + .borders(Borders::ALL) + .padding(Padding::new(1, 1, 1, 1)), + ); frame.render_widget(left_list, left_body); // Network let mut right_list = Vec::new(); - right_list.extend( - wim_sources - .network - .iter() - .map(|wimfile| ListItem::new(format!("{}\n\n", wimfile.path))), + right_list.extend(wim_sources.network.iter().map(|wimfile| { + ListItem::new(format!( + "{}\n\n", + wimfile.path.split("\\").last().unwrap_or(&wimfile.path) + )) + })); + let right_list = List::new(right_list).block( + Block::default() + .borders(Borders::ALL) + .padding(Padding::new(1, 1, 1, 1)), ); - let right_list = List::new(right_list) - .block( - Block::default() - .borders(Borders::ALL) - .padding(Padding::new(1, 1, 1, 1)), - ) - .highlight_spacing(HighlightSpacing::Always) - .highlight_style(Style::new().green().bold()) - .highlight_symbol(" --> ") - .repeat_highlight_symbol(false); frame.render_widget(right_list, right_body); } diff --git a/win_installer/src/wim.rs b/win_installer/src/wim.rs index c222325..b971569 100644 --- a/win_installer/src/wim.rs +++ b/win_installer/src/wim.rs @@ -62,12 +62,30 @@ static WIN_BUILDS: LazyLock> = LazyLock::new(|| { ]) }); -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct WimFile { pub path: String, pub images: Vec, } +impl WimFile { + pub fn summary(&self) -> String { + let mut s = format!("{self}"); + self.images.iter().for_each(|image| { + let image = format!("\n\t\t{image}"); + s.push_str(&image); + }); + + s + } +} + +impl fmt::Display for WimFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.path.split("\\").last().unwrap_or(&self.path)) + } +} + impl PartialEq for WimFile { fn eq(&self, other: &Self) -> bool { self.path == other.path @@ -144,6 +162,22 @@ impl WimSources { self.network.sort(); } + pub fn get_file(&self, index: usize) -> WimFile { + let num_local = self.local.len(); + let index = if index < num_local { + index + } else { + index - num_local + }; + self.local.get(index).unwrap().clone() + } + + pub fn get_file_list(&self) -> Vec { + let mut list = self.local.clone(); + list.append(&mut self.network.clone()); + list + } + pub fn reset_all(&mut self) { self.local.clear(); self.network.clear();