Release v0.6.54: adjustable pencil smoothing and unsaved settings state

This commit is contained in:
agrynco committed 2026-11-06 14:46:53 +02:00
1 parent 727dc96908
commit 63b7b879a3
14 files changed
+318 -18

No files matched your search

+40 -1
View File
@@ -968,7 +968,9 @@ struct SettingsView
int selection = -1;
bool filling{};
std::vector<std::vector<HWND>> pages;
bool ready{}, refreshing{};
};
void updateSettingsState(HWND w, SettingsView *v);
void selectSettingsPage(HWND w, SettingsView *v)
{
int selected = TabCtrl_GetCurSel(GetDlgItem(w, 260));
@@ -1169,6 +1171,7 @@ void fillSettings(HWND w, SettingsView *v)
v->selection = 0;
fillLayouts(w, v);
v->filling = false;
updateSettingsState(w, v);
}
int integer(HWND w, int id)
{
@@ -1298,7 +1301,10 @@ LRESULT CALLBACK autoOptionsProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
auto words = parseCommaList(text);
std::sort(words.begin(), words.end());
words.erase(std::unique(words.begin(), words.end()), words.end());
draft.autoWords[language] = std::move(words);
// Opening and accepting an untouched empty dictionary must not
// introduce a new entry and mark Settings as changed.
if (!words.empty() || draft.autoWords.contains(language))
draft.autoWords[language] = std::move(words);
}
draft.autoExcluded = parseCommaList(value(w, 404));
draft.autoPrefixChars = value(w, 408);
@@ -1535,6 +1541,27 @@ bool settingsChanged(HWND w, SettingsView *v)
return true;
}
}
void updateSettingsState(HWND w, SettingsView *v)
{
if (!v || !v->ready || v->filling || v->refreshing) return;
v->refreshing = true;
bool changed = settingsChanged(w, v);
EnableWindow(GetDlgItem(w, IDOK), changed);
const wchar_t *text = changed ? L"Unsaved changes — click Save to apply." : L"No unsaved changes.";
if (value(w, 261) != text) value(w, 261, text);
v->refreshing = false;
}
// Refresh after commands have updated controls/drafts, including early returns.
// Saving can destroy Settings, so retrieve its state only if it still exists.
struct SettingsStateRefresh
{
HWND window;
~SettingsStateRefresh()
{
if (IsWindow(window))
updateSettingsState(window, reinterpret_cast<SettingsView *>(GetWindowLongPtrW(window, GWLP_USERDATA)));
}
};
void closeSettings(HWND w, SettingsView *v)
{
if (settingsChanged(w, v))
@@ -1583,6 +1610,12 @@ LRESULT CALLBACK settingsProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_ENABLE:
if (wp) updateSettingsState(w, v);
break;
case WM_ACTIVATE:
if (LOWORD(wp) != WA_INACTIVE) updateSettingsState(w, v);
break;
case WM_NOTIFY:
if (((NMHDR *)lp)->idFrom == 260 && ((NMHDR *)lp)->code == TCN_SELCHANGE)
{
@@ -1592,6 +1625,7 @@ LRESULT CALLBACK settingsProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
break;
case WM_COMMAND:
{
SettingsStateRefresh refresh{w};
int id = LOWORD(wp);
if (id == 220 && HIWORD(wp) == LBN_SELCHANGE && !v->filling)
{
@@ -1627,6 +1661,7 @@ LRESULT CALLBACK settingsProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
}
if (id == IDOK)
{
if (!settingsChanged(w, v)) return 0;
if (v->app->busy)
throw std::runtime_error("Wait for the current text operation to finish");
v->app->applySettings(collectSettings(w, v));
@@ -1846,6 +1881,7 @@ LRESULT CALLBACK snippetProc(HWND w, UINT msg, WPARAM wp, LPARAM lp)
{
auto *parent = (SettingsView *)GetWindowLongPtrW(v->app->settingsWindow, GWLP_USERDATA);
parent->draft.snippets = s.snippets;
updateSettingsState(v->app->settingsWindow, parent);
}
DestroyWindow(w);
return 0;
@@ -2069,11 +2105,14 @@ void showSettings(App &app, bool visible)
checkbox(w, L"Write lo&g", 208, 24, 378, 210);
page();
control(w, L"STATIC", L"No unsaved changes.", 0, 261, 18, 430, 684, 24);
button(w, L"Impo&rt...", 250, 18, 466, 125);
button(w, L"&Export...", 251, 155, 466, 125);
button(w, L"&Save", IDOK, 490, 466, 100);
button(w, L"&Cancel", IDCANCEL, 602, 466, 100);
fillSettings(w, v);
v->ready = true;
updateSettingsState(w, v);
TabCtrl_SetCurSel(tabs, 0);
selectSettingsPage(w, v);
if (visible)