@@ -94,6 +94,10 @@ struct callbacks_impl : public install_callbacks,
94
94
HWND kill_button{NULL };
95
95
HWND continue_button{NULL };
96
96
HWND cancel_button{NULL };
97
+ std::wstring update_btn_label;
98
+ std::wstring remind_btn_label;
99
+ std::wstring continue_label;
100
+ std::wstring cancel_label;
97
101
98
102
HFONT main_font{NULL };
99
103
RECT progress_label_rect{0 };
@@ -116,6 +120,7 @@ struct callbacks_impl : public install_callbacks,
116
120
bool should_continue{false };
117
121
bool notify_restart{false };
118
122
bool finished_downloading{false };
123
+ bool prompting{false };
119
124
LPCWSTR label_format{L" Downloading {} of {} - {:.2f} MB/s" };
120
125
121
126
callbacks_impl (const callbacks_impl &) = delete ;
@@ -164,6 +169,8 @@ struct callbacks_impl : public install_callbacks,
164
169
void update_file (std::string &filename) final {}
165
170
void update_finished (std::string &filename) final {}
166
171
void updater_complete () final {}
172
+
173
+ bool prompt_user (const char *pVersion, const char *pDetails);
167
174
};
168
175
169
176
callbacks_impl::callbacks_impl (HINSTANCE hInstance, int nCmdShow)
@@ -233,8 +240,10 @@ callbacks_impl::callbacks_impl(HINSTANCE hInstance, int nCmdShow)
233
240
std::wstring checking_packages_label = ConvertToUtf16WS (boost::locale::translate (" Checking packages..." ));
234
241
std::wstring blockers_list_label = ConvertToUtf16WS (boost::locale::translate (" Blockers list" ));
235
242
std::wstring stop_all_label = ConvertToUtf16WS (boost::locale::translate (" Stop all" ));
236
- std::wstring continue_label = ConvertToUtf16WS (boost::locale::translate (" Continue" ));
237
- std::wstring cancel_label = ConvertToUtf16WS (boost::locale::translate (" Cancel" ));
243
+ continue_label = ConvertToUtf16WS (boost::locale::translate (" Continue" ));
244
+ cancel_label = ConvertToUtf16WS (boost::locale::translate (" Cancel" ));
245
+ update_btn_label = ConvertToUtf16WS (boost::locale::translate (" Upgrade" ));
246
+ remind_btn_label = ConvertToUtf16WS (boost::locale::translate (" Later" ));
238
247
239
248
progress_label = CreateWindow (WC_STATIC, checking_packages_label.c_str (), WS_CHILD | WS_VISIBLE, x_pos, ui_padding, x_size, ui_basic_height, frame,
240
249
NULL , NULL , NULL );
@@ -766,6 +775,116 @@ void callbacks_impl::updater_start()
766
775
SetWindowTextW (progress_label, copying_label.c_str ());
767
776
}
768
777
778
+ bool callbacks_impl::prompt_user (const char *pVersion, const char *pDetails)
779
+ {
780
+ const wchar_t *wc_dash = L" -" ;
781
+ const wchar_t *wc_hash = L" #" ;
782
+ const wchar_t *wc_bullet = L" \r\n \u2022 " ;
783
+ const wchar_t *wc_break = L" \r\n " ;
784
+ std::wstring wc_version = ConvertToUtf16WS (boost::locale::translate (pVersion));
785
+ std::wstring wc_label = ConvertToUtf16WS (boost::locale::translate (" There's an update available to install: " ));
786
+ wc_label.insert (wc_label.size () - 1 , wc_version); // account for null terminator
787
+ std::wstring wc_details = ConvertToUtf16WS (boost::locale::translate (pDetails));
788
+
789
+ // tag to heading conversion
790
+ std::list<std::pair<std::wstring, std::wstring>> tagsToHeadings;
791
+ tagsToHeadings.push_back (std::make_pair (L" #hotfixes" , L" Hotfix Changes" ));
792
+ tagsToHeadings.push_back (std::make_pair (L" #features" , L" New Features" ));
793
+ tagsToHeadings.push_back (std::make_pair (L" #generalfixes" , L" General Fixes" ));
794
+
795
+ // format detail string: insert 2 breaks at start -> 1 to have heading on its own line, 1 for spacing, one after heading for spacing
796
+ size_t replacePos = 0 ;
797
+ for (const auto &tagHeadingPair : tagsToHeadings) {
798
+ replacePos = wc_details.find (tagHeadingPair.first );
799
+ if (replacePos != std::wstring::npos) {
800
+ wc_details.replace (replacePos, tagHeadingPair.first .size (), tagHeadingPair.second );
801
+ if (replacePos != 0 ) {
802
+ wc_details.insert (replacePos, wc_break);
803
+ replacePos += +wcslen (wc_break);
804
+ }
805
+ wc_details.insert (replacePos, wc_break);
806
+ wc_details.insert (replacePos + wcslen (wc_break) + tagHeadingPair.second .size (), wc_break);
807
+ }
808
+ }
809
+ // if # isn't followed by a known heading, leave as-is to display custom heading
810
+ int endHeading = 0 ;
811
+ replacePos = wc_details.find (wc_hash);
812
+ while (replacePos != std::wstring::npos) {
813
+ wc_details.insert (replacePos, wc_break);
814
+ wc_details.replace (replacePos + wcslen (wc_break), wcslen (wc_hash), wc_break);
815
+ endHeading = wc_details.find (wc_dash, replacePos);
816
+ if (endHeading != std::wstring::npos) {
817
+ wc_details.insert (endHeading, wc_break);
818
+ }
819
+ replacePos = wc_details.find (wc_hash, replacePos + wcslen (wc_break));
820
+ }
821
+ // replace '-' with end line + spacing + bullet + spacing
822
+ replacePos = wc_details.find (wc_dash);
823
+ while (replacePos != std::wstring::npos) {
824
+ wc_details.replace (replacePos, wcslen (wc_dash), wc_bullet);
825
+ replacePos = wc_details.find (wc_dash, replacePos + wcslen (wc_bullet));
826
+ }
827
+ // line break at end to look nicer
828
+ wc_details.insert (wc_details.length (), wc_break);
829
+
830
+ prompting = true ;
831
+ ShowWindow (frame, SW_SHOWNORMAL);
832
+ ShowWindow (progress_worker, SW_HIDE);
833
+ HDC hdc = GetDC (frame);
834
+ HFONT hfontOld = (HFONT)SelectObject (hdc, main_font);
835
+
836
+ DrawText (hdc, wc_label.c_str (), -1 , &progress_label_rect, DT_CALCRECT | DT_NOCLIP);
837
+ progress_label_rect.right -= progress_label_rect.left ;
838
+ blockers_list_rect = {0 };
839
+ DrawText (hdc, wc_details.c_str (), -1 , &blockers_list_rect, DT_CALCRECT | DT_NOCLIP | DT_EDITCONTROL);
840
+
841
+ ReleaseDC (frame, hdc);
842
+ SelectObject (hdc, hfontOld);
843
+
844
+ ShowWindow (blockers_list, SW_SHOW);
845
+ ShowWindow (continue_button, SW_SHOW);
846
+ ShowWindow (cancel_button, SW_SHOW);
847
+ repostionUI ();
848
+
849
+ SetWindowTextW (progress_label, wc_label.c_str ());
850
+ SetWindowTextW (blockers_list, wc_details.c_str ());
851
+ SetWindowTextW (continue_button, update_btn_label.c_str ());
852
+ SetWindowTextW (cancel_button, remind_btn_label.c_str ());
853
+
854
+ MSG msg;
855
+ bool shouldUpdate = false ;
856
+ while (GetMessage (&msg, NULL , 0 , 0 )) {
857
+ if (!IsDialogMessage (frame, &msg)) {
858
+ TranslateMessage (&msg);
859
+ DispatchMessage (&msg);
860
+ }
861
+ if (should_cancel) {
862
+ should_cancel = false ;
863
+ shouldUpdate = false ;
864
+ break ;
865
+ }
866
+ if (should_continue) {
867
+ should_continue = false ;
868
+ shouldUpdate = true ;
869
+ break ;
870
+ }
871
+ }
872
+
873
+ // reset UI elements
874
+ ShowWindow (frame, SW_HIDE);
875
+ ShowWindow (blockers_list, SW_HIDE);
876
+ ShowWindow (continue_button, SW_HIDE);
877
+ ShowWindow (cancel_button, SW_HIDE);
878
+ SetWindowTextW (blockers_list, L" " );
879
+ SetWindowTextW (progress_label, L" " );
880
+ SetWindowTextW (continue_button, continue_label.c_str ());
881
+ SetWindowTextW (cancel_button, cancel_label.c_str ());
882
+
883
+ prompting = false ;
884
+ return shouldUpdate;
885
+ }
886
+
887
+
769
888
LRESULT CALLBACK ProgressLabelWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
770
889
{
771
890
switch (msg) {
@@ -956,6 +1075,11 @@ extern "C" int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpC
956
1075
return 0 ;
957
1076
}
958
1077
1078
+ if (!cb_impl.prompt_user (params.version .c_str (), params.details .c_str ())) {
1079
+ handle_exit ();
1080
+ return 1 ;
1081
+ }
1082
+
959
1083
auto client_deleter = [](struct update_client *client) { destroy_update_client (client); };
960
1084
961
1085
std::unique_ptr<struct update_client , decltype(client_deleter)> client (create_update_client (¶ms), client_deleter);
0 commit comments