diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-03 16:23:43 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-04 12:53:37 +0200 |
| commit | 0364f7d48813a350e9c02d78e652f6b58c31abec (patch) | |
| tree | 36241bbef89577ac07dce128be318e9556bbd489 /src/config.cpp | |
| parent | 98c1c615d147bfee3f17d4f420e1512af5a79436 (diff) | |
| download | qtmaildir-0364f7d48813a350e9c02d78e652f6b58c31abec.tar.gz qtmaildir-0364f7d48813a350e9c02d78e652f6b58c31abec.zip | |
feat: own the message-pane zoom and persist it
Zoom was Chromium's, not the application's: the web view handled the
keys natively and never told anyone, so there was no value to save.
qtmaildir now owns it. Zoom in, out and reset are real actions, in the
View menu and rebindable through [keys], and the factor is persisted to
the UI state file. Ctrl+wheel over the body zooms and Ctrl+middle-click
resets, both filtered by ancestry from an application-level filter: the
events are delivered to an internal QQuickWidget the web view creates
lazily, so a filter on the view itself never sees them.
The factor is clamped to 0.5 - 3.0, and NaN, infinity, zero and negative
values fall back to 1.0, since a corrupt state file must not be able to
leave the pane unreadable with no visible way back.
Both risks the plan flagged turned out not to exist, verified by probe
rather than assumed. The application QAction wins over the web view's
native zoom key, so the tracked factor cannot diverge from what is on
screen. And the factor survives setHtml(), so the web view is the single
source of truth and needs no reapply per render.
A third finding is worth recording because it produced a wrong fix
first. A probe using QTest::keyClick() reported Ctrl++ as a dead
binding, and a test was written asserting that. Both were wrong: Ctrl++
is exactly what the '+' key emits on an Italian layout, confirmed
against the real keyboard, and it is the shipped default. Whether a
symbol needs Shift is a property of the layout, not of Qt, and
keyClick() reproduces neither. The test now only checks that every
default parses, and the comment in defaultBindings() says not to
re-derive this from synthetic input.
Ctrl+= is a second binding for reset, skipped when [keys] gives it to
something else.
Also fixes a pre-existing bug the new config key exposed. [general]
entries were read as "general/<key>", which matches nothing: QSettings'
INI backend treats a section literally named [general] as its own
fallback section and strips the prefix. notmuch_config had therefore
never worked. Both keys are now read without it; the file format is
unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/config.cpp')
| -rw-r--r-- | src/config.cpp | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/src/config.cpp b/src/config.cpp index f21bba9..a2caaee 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -52,8 +52,32 @@ void Config::load(const QString &path) { QSettings settings(path, QSettings::IniFormat); + // Keys of [general] are read WITHOUT the "general/" prefix. QSettings' + // INI backend treats a section literally named [general] as its own + // fallback section and strips the prefix, so "general/notmuch_config" + // never matches anything, in any section arrangement (verified on + // Qt 6.11). The file still reads as [general] to the user; only the + // lookup differs. Same family of trap as the [account.work] dot and the + // childKeys() ordering already documented in CLAUDE.md. m_notmuchConfig = - settings.value(QStringLiteral("general/notmuch_config")).toString(); + settings.value(QStringLiteral("notmuch_config")).toString(); + + // Absent is fine and silent: the default is 1.0. Present but unparseable + // is a problem, since the user asked for something and is not getting it. + // The range check lives in MessageView::clampZoom(), the one place that + // knows what the web view can render. + const QVariant zoom = settings.value(QStringLiteral("message_zoom")); + if (zoom.isValid()) { + bool ok = false; + const double value = zoom.toString().toDouble(&ok); + if (ok) { + m_messageZoom = value; + } else { + addProblem(QStringLiteral("Message zoom '%1' is not a number; " + "using the default.") + .arg(zoom.toString())); + } + } m_syncCommand = settings.value(QStringLiteral("sync/command")).toString(); if (m_syncCommand.isEmpty()) { |
