struct SyncConflictView { HWND parent; App *app; std::vector conflicts; std::map choices; }; void showConflictValues(HWND w, SyncConflictView *v) { int selected = (int)SendDlgItemMessageW(w, 620, LB_GETCURSEL, 0, 0); if (selected < 0 || selected >= (int)v->conflicts.size()) return; const auto &c = v->conflicts[selected]; value(w, 621, syncValueText(c.local)); value(w, 622, syncValueText(c.remote)); } LRESULT CALLBACK syncConflictsProc(HWND w, UINT msg, WPARAM wp, LPARAM lp) { if (msg == WM_DPICHANGED) { resizeForDpi(w, wp, lp); return 0; } auto *v = reinterpret_cast(GetWindowLongPtrW(w, GWLP_USERDATA)); if (!v) return DefWindowProcW(w, msg, wp, lp); try { if (msg == WM_COMMAND) { int id = LOWORD(wp); if (id == 620 && HIWORD(wp) == LBN_SELCHANGE) { showConflictValues(w, v); return 0; } if (id == 623 || id == 624) { int selected = (int)SendDlgItemMessageW(w, 620, LB_GETCURSEL, 0, 0); if (selected < 0 || selected >= (int)v->conflicts.size()) return 0; v->choices[selected] = id == 623; auto text = v->conflicts[selected].label + (id == 623 ? L" [This PC]" : L" [Server]"); SendDlgItemMessageW(w, 620, LB_DELETESTRING, selected, 0); SendDlgItemMessageW(w, 620, LB_INSERTSTRING, selected, (LPARAM)text.c_str()); SendDlgItemMessageW(w, 620, LB_SETCURSEL, selected, 0); return 0; } if (id == IDOK) { if (v->choices.empty()) throw std::runtime_error("Select a setting and choose This PC or Server first."); std::vector choices; for (const auto &[index, local] : v->choices) choices.push_back({v->conflicts.at(index), local}); auto status = v->app->syncCommand(4, choices); value(v->parent, 608, status); if (status != L"Connecting to OpenBao...") throw std::runtime_error(utf8(status)); DestroyWindow(w); return 0; } if (id == IDCANCEL) { DestroyWindow(w); return 0; } } } catch (const std::exception &e) { error(w, e); return 0; } if (msg == WM_CLOSE) { DestroyWindow(w); return 0; } if (msg == WM_NCDESTROY) { EnableWindow(v->parent, TRUE); SetForegroundWindow(v->parent); disposeFont(w); delete v; SetWindowLongPtrW(w, GWLP_USERDATA, 0); } return DefWindowProcW(w, msg, wp, lp); } void showSyncConflicts(HWND parent, App &app) { auto conflicts = decodeSyncConflicts(app.syncConflictData()); if (conflicts.empty()) { value(parent, 608, L"No pending conflicts. Run Sync to check for changes."); return; } HWND w = makeWindow(app, L"KSwitcher.SyncConflicts", L"Resolve individual settings", syncConflictsProc, 800, 560); SetWindowLongPtrW(w, GWLP_HWNDPARENT, (LONG_PTR)parent); auto *v = new SyncConflictView{parent, &app, std::move(conflicts), {}}; SetWindowLongPtrW(w, GWLP_USERDATA, (LONG_PTR)v); label(w, L"Choose a value for each conflicting setting. Other changes are already synchronized.", 18, 16, 760); control(w, L"LISTBOX", L"", WS_TABSTOP | WS_VSCROLL | LBS_NOTIFY | WS_BORDER, 620, 18, 48, 760, 130); for (const auto &c : v->conflicts) SendDlgItemMessageW(w, 620, LB_ADDSTRING, 0, (LPARAM)c.label.c_str()); label(w, L"This PC", 18, 190, 360); label(w, L"Server", 410, 190, 368); edit(w, 621, 18, 220, 368, 180, ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL); edit(w, 622, 410, 220, 368, 180, ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL); button(w, L"Use this &PC for selected setting", 623, 18, 412, 368); button(w, L"Use &server for selected setting", 624, 410, 412, 368); label(w, L"Unselected conflicts stay pending. Changed values will be checked again before saving.", 18, 454, 760); button(w, L"&Apply choices", IDOK, 526, 488, 140); button(w, L"&Cancel", IDCANCEL, 678, 488, 100); SendDlgItemMessageW(w, 620, LB_SETCURSEL, 0, 0); showConflictValues(w, v); EnableWindow(parent, FALSE); showRequestedWindow(w); SetForegroundWindow(w); }