pacenotes_installer\wizard\scene/
summary.rs1use windows_sys::Win32::Foundation::{HWND, LPARAM, WPARAM};
2use windows_sys::Win32::UI::Controls as ctl;
3use windows_sys::Win32::UI::WindowsAndMessaging as wm;
4
5pub unsafe extern "system" fn summary_page(
7 dialog: HWND,
8 message: u32,
9 _wparam: WPARAM,
10 lparam: LPARAM,
11) -> isize {
12 match message {
13 wm::WM_INITDIALOG => {
14 crate::wizard::page::adopt_state(dialog, lparam);
15 1
16 }
17 wm::WM_NOTIFY => match crate::wizard::page::notify_code(lparam) {
18 Some(ctl::PSN_SETACTIVE) => {
19 crate::wizard::page::set_sheet_caption(dialog);
20 crate::wizard::page::set_header(dialog, crate::i18n::IDS_S7_TITLE);
21 crate::wizard::page::set_buttons(dialog, ctl::PSWIZB_FINISH);
22 crate::wizard::page::set_next_text(dialog, crate::i18n::IDS_BTN_FINISH);
23 crate::ui::enable(
24 crate::wizard::page::sheet(dialog),
25 crate::ui::IDCANCEL,
26 false,
27 );
28 if let Some(state) = crate::wizard::page::state(dialog) {
29 show_summary(dialog, state);
30 }
31 crate::wizard::page::reply(dialog, 0)
32 }
33 _ => 0,
34 },
35 _ => 0,
36 }
37}
38
39unsafe fn show_summary(dialog: HWND, state: &crate::wizard::state::WizardState) {
43 crate::ui::set_text_raw(
44 dialog,
45 crate::wizard::control_ids::IDC_S7_RESULT,
46 &result_line(state),
47 );
48 crate::ui::set_text_raw(
49 dialog,
50 crate::wizard::control_ids::IDC_S7_DETAIL,
51 &detail_lines(state).join("\r\n"),
52 );
53
54 let log = crate::wizard::control_ids::IDC_S7_LOG;
55 let failed = matches!(
56 state.outcome,
57 Some(crate::worker::Outcome::Failed(_)) | None
58 ) || !state.not_downloaded.is_empty();
59 crate::ui::set_text_raw(dialog, log, &state.log.text());
60 crate::ui::scroll_to_end(dialog, log);
61 crate::ui::show(dialog, log, failed);
62 if !failed {
63 crate::ui::stretch_to_bottom_of(dialog, crate::wizard::control_ids::IDC_S7_DETAIL, log);
64 }
65}
66
67fn result_line(state: &crate::wizard::state::WizardState) -> String {
70 match state.outcome.as_ref() {
71 Some(crate::worker::Outcome::Done { .. })
72 if state.route == crate::wizard::state::Route::Restore =>
73 {
74 let when = state
75 .restore_to
76 .as_ref()
77 .map(|point| pacenotes_installer::restore::human_time(&point.name))
78 .unwrap_or_default();
79 crate::i18n::load_string_arg(crate::i18n::IDS_S7_RESTORED, &when)
80 }
81 Some(crate::worker::Outcome::Done { .. }) => {
82 crate::i18n::load_string(crate::i18n::IDS_S7_OK)
83 }
84 Some(crate::worker::Outcome::Failed(message)) => {
85 crate::i18n::load_string_arg(crate::i18n::IDS_S7_FAILED, message)
86 }
87 Some(crate::worker::Outcome::Cancelled) | None => {
88 crate::i18n::load_string(crate::i18n::IDS_S7_CANCELLED)
89 }
90 }
91}
92
93fn detail_lines(state: &crate::wizard::state::WizardState) -> Vec<String> {
94 let mut lines: Vec<String> = Vec::new();
95 if let Some(game) = state.game {
96 lines.push(crate::i18n::load_string_arg(
97 crate::i18n::IDS_S7_GAME,
98 &format!("{} — {}", game.title(), state.folder),
99 ));
100 }
101 for list in &state.config.lists {
102 if let Some(option) = list.selected.and_then(|index| list.options.get(index)) {
103 let caption =
104 crate::i18n::load_string(super::configuration::category_caption(list.category));
105 lines.push(format!("{caption} {}", option.label));
106 }
107 }
108 if !state.config.extras.is_empty() {
109 let leaves: Vec<&str> = state
110 .config
111 .extras
112 .iter()
113 .map(|key| key.rsplit('/').next().unwrap_or(key))
114 .collect();
115 lines.push(crate::i18n::load_string_arg(
116 crate::i18n::IDS_S7_EXTRAS,
117 &leaves.join(", "),
118 ));
119 }
120 lines.push(if state.downloaded > 0 {
122 crate::i18n::load_string_arg(
123 crate::i18n::IDS_S7_DOWNLOADS,
124 &format!(
125 "{} ({})",
126 state.downloaded,
127 pacenotes_installer::size::human(state.downloaded_bytes)
128 ),
129 )
130 } else {
131 crate::i18n::load_string(crate::i18n::IDS_S7_NOTHING_TODO)
132 });
133 if !state.not_downloaded.is_empty() {
134 let labels: Vec<&str> = state
135 .not_downloaded
136 .iter()
137 .map(|failure| failure.label.as_str())
138 .collect();
139 lines.push(crate::i18n::load_string_arg(
140 crate::i18n::IDS_S7_NOT_DOWNLOADED,
141 &labels.join(", "),
142 ));
143 }
144 if let Some(crate::worker::Outcome::Done { applied, .. }) = &state.outcome {
145 lines.extend(applied_lines(applied));
146 }
147 if let Some(path) = state.log.path() {
148 lines.push(crate::i18n::load_string_arg(
149 crate::i18n::IDS_S7_LOGFILE,
150 &path.display().to_string(),
151 ));
152 }
153 lines
154}
155
156fn applied_lines(applied: &crate::worker::Applied) -> Vec<String> {
159 let mut lines = vec![crate::i18n::load_string_arg(
160 crate::i18n::IDS_S7_CHANGED,
161 &format!(
162 "{} / {}",
163 applied.installed.len(),
164 applied.uninstalled.len()
165 ),
166 )];
167 if !applied.left_alone.is_empty() {
168 lines.push(crate::i18n::load_string_arg(
169 crate::i18n::IDS_S7_LEFT_ALONE,
170 &applied.left_alone.join(", "),
171 ));
172 }
173 if let Some(point) = &applied.restore_point {
174 lines.push(crate::i18n::load_string_arg(
175 crate::i18n::IDS_S7_RESTORE_POINT,
176 point,
177 ));
178 }
179 lines
180}