diff --git a/qml/pages/MarginDialog.qml b/qml/pages/MarginDialog.qml index 6b96b7b..09b1e7e 100644 --- a/qml/pages/MarginDialog.qml +++ b/qml/pages/MarginDialog.qml @@ -1,13 +1,22 @@ import QtQuick 2.0 import Sailfish.Silica 1.0 -// Regola i margini laterali del testo nel lettore senza uscire dal libro. -// Il valore viene applicato all'accettazione; il capitolo aperto si ricarica -// con il nuovo margine (il chiamante si occupa del reload). +// Regola i margini del testo nel lettore senza uscire dal libro. +// Anteprima LIVE: ogni variazione degli slider viene inoltrata al lettore via +// previewHandler (runJavaScript sul documento aperto), quindi il testo si +// adatta subito. I valori vengono persistiti solo all'accettazione. Dialog { id: dialog - property int marginValue: 24 + property int marginLr: 24 + property int marginTb: 0 + // funzione chiamata a ogni variazione: previewHandler(marginLr, marginTb) + property var previewHandler: null + + function preview() { + if (dialog.previewHandler) + dialog.previewHandler(dialog.marginLr, dialog.marginTb) + } Column { width: parent.width @@ -18,26 +27,47 @@ Dialog { } Slider { - id: marginSlider + id: lrSlider width: parent.width - label: "Margine laterale" + label: "Margini laterali" minimumValue: 0 maximumValue: 80 stepSize: 4 - value: dialog.marginValue + value: dialog.marginLr valueText: value + " px" - onValueChanged: dialog.marginValue = value + onValueChanged: { + dialog.marginLr = value + dialog.preview() + } + } + + Slider { + id: tbSlider + width: parent.width + label: "Alto e basso" + minimumValue: 0 + maximumValue: 80 + stepSize: 4 + value: dialog.marginTb + valueText: value + " px" + onValueChanged: { + dialog.marginTb = value + dialog.preview() + } } Label { x: Theme.horizontalPageMargin width: parent.width - 2 * Theme.horizontalPageMargin - text: "Il margine viene applicato al capitolo corrente e salvato per tutti i libri." + text: "Le modifiche si applicano subito al testo. Conferma per salvarle per tutti i libri." color: Theme.secondaryColor wrapMode: Text.Wrap font.pixelSize: Theme.fontSizeSmall } } - onAccepted: appSettings.readerMargin = dialog.marginValue + onAccepted: { + appSettings.readerMargin = dialog.marginLr + appSettings.readerMarginV = dialog.marginTb + } } diff --git a/qml/pages/ReaderPage.qml b/qml/pages/ReaderPage.qml index 8f1f656..368cdb9 100644 --- a/qml/pages/ReaderPage.qml +++ b/qml/pages/ReaderPage.qml @@ -43,11 +43,14 @@ Page { MenuItem { text: "Margini del testo" onClicked: { - var dlg = pageStack.push(Qt.resolvedUrl("MarginDialog.qml"), - { marginValue: appSettings.readerMargin }) + var dlg = pageStack.push(Qt.resolvedUrl("MarginDialog.qml"), { + marginLr: appSettings.readerMargin, + marginTb: appSettings.readerMarginV, + previewHandler: page.previewMargins + }) dlg.accepted.connect(function() { - if (page.ready && book.chapterCount() > 0) - loadChapter() + // i valori sono già persistiti da onAccepted; rinfresca subito + applyMarginsJS() }) } } @@ -239,7 +242,7 @@ Page { // e margini) è iniettato nell'HTML dal parser, quindi niente JS post-load function loadChapter() { var html = book.chapterHtml(page.currentChapter, page.fontPx(), - appSettings.readerMargin) + appSettings.readerMargin, appSettings.readerMarginV) if (html.length === 0) { page.errorMessage = "Capitolo non leggibile" page.ready = true @@ -259,6 +262,34 @@ Page { }) } + // JS che sovrascrive i margini sul documento aperto: stile inline con + // 'important' batte lo stylesheet iniettato. Effetto immediato, niente reload. + function marginJs(lr, tb) { + return "var h=document.documentElement,b=document.body;" + + "h.style.setProperty('margin-left','" + lr + "px','important');" + + "h.style.setProperty('margin-right','" + lr + "px','important');" + + "b.style.setProperty('margin-left','" + lr + "px','important');" + + "b.style.setProperty('margin-right','" + lr + "px','important');" + + "b.style.setProperty('margin-top','" + tb + "px','important');" + + "b.style.setProperty('margin-bottom','" + tb + "px','important');" + + "true" + } + + // riapplica i margini salvati nelle impostazioni (senza ricaricare il libro) + function applyMarginsJS() { + if (!web.loaded || !page.ready) + return + web.runJavaScript(marginJs(appSettings.readerMargin, appSettings.readerMarginV), + function() { }) + } + + // anteprima live dal dialogo margini: valori non ancora persistiti + function previewMargins(lr, tb) { + if (!web.loaded || !page.ready) + return + web.runJavaScript(marginJs(lr, tb), function() { }) + } + Component.onCompleted: { page.ready = false if (!book.open(page.epubPath)) { @@ -290,10 +321,10 @@ Page { if (status === PageStatus.Inactive) { maybeSave(true) } else if (status === PageStatus.Active) { - // riapplica font/margini se cambiati nelle impostazioni: - // ricarica il capitolo e ripristina la posizione + // riapplica i margini se cambiati nelle impostazioni: + // via JS sul documento aperto, senza ricaricare il capitolo if (page.ready && book.chapterCount() > 0) - loadChapter() + applyMarginsJS() } } } diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml index c0442f3..8a5b648 100644 --- a/qml/pages/SettingsPage.qml +++ b/qml/pages/SettingsPage.qml @@ -62,7 +62,7 @@ Page { Slider { id: marginSlider width: parent.width - label: "Margini del testo" + label: "Margini laterali" minimumValue: 0 maximumValue: 80 stepSize: 4 @@ -71,6 +71,18 @@ Page { onValueChanged: appSettings.readerMargin = value } + Slider { + id: marginVSlider + width: parent.width + label: "Margine alto e basso" + minimumValue: 0 + maximumValue: 80 + stepSize: 4 + value: appSettings.readerMarginV + valueText: value + " px" + onValueChanged: appSettings.readerMarginV = value + } + SectionHeader { text: "Connessione" } Button { diff --git a/src/epub.cpp b/src/epub.cpp index da9ddc9..558b447 100644 --- a/src/epub.cpp +++ b/src/epub.cpp @@ -406,7 +406,7 @@ QVariantList EpubBook::chapterList() const return list; } -QString EpubBook::chapterHtml(int index, int fontSizePx, int marginPx) const +QString EpubBook::chapterHtml(int index, int fontSizePx, int marginPx, int marginVerticalPx) const { if (index < 0 || index >= m_chapters.size()) return QString(); @@ -415,12 +415,15 @@ QString EpubBook::chapterHtml(int index, int fontSizePx, int marginPx) const return QString(); QString html = QString::fromUtf8(f.readAll()); - // stile di reflow iniettato nel documento: !important vince sui CSS del libro + // stile di reflow iniettato nel documento: !important vince sui CSS del libro. + // I margini si possono aggiornare a caldo via runJavaScript (setProperty con + // 'important' inline), senza ricaricare il capitolo. const QString style = QStringLiteral( "") - .arg(fontSizePx).arg(marginPx); + .arg(fontSizePx).arg(marginPx).arg(marginVerticalPx); const int headEnd = html.indexOf(QStringLiteral(""), 0, Qt::CaseInsensitive); if (headEnd >= 0) html.insert(headEnd, style); diff --git a/src/epub.h b/src/epub.h index 53dfbfb..4520126 100644 --- a/src/epub.h +++ b/src/epub.h @@ -37,7 +37,7 @@ public: // elenco [{index, title}] per la lista capitoli Q_INVOKABLE QVariantList chapterList() const; // HTML del capitolo con lo stile di reflow iniettato (font-size e margini in px) - Q_INVOKABLE QString chapterHtml(int index, int fontSizePx, int marginPx) const; + Q_INVOKABLE QString chapterHtml(int index, int fontSizePx, int marginPx, int marginVerticalPx) const; // base URL (file://) per risolvere immagini/CSS relativi del capitolo Q_INVOKABLE QString chapterBaseUrl(int index) const; diff --git a/src/settings.cpp b/src/settings.cpp index 146059b..0eede03 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -11,7 +11,8 @@ Settings::Settings(QObject *parent) // diagnostica: path reale del file di configurazione e valori letti all'avvio qDebug() << "Settings file:" << m_settings.fileName(); qDebug() << "Settings read: serverUrl=[" << serverUrl() << "] user=[" << username() - << "] ssl=" << ignoreSslErrors() << "margin=" << readerMargin(); + << "] ssl=" << ignoreSslErrors() << "margin=" << readerMargin() + << "marginV=" << readerMarginV(); } QString Settings::serverUrl() const @@ -85,6 +86,20 @@ void Settings::setReaderMargin(int value) emit readerMarginChanged(); } +int Settings::readerMarginV() const +{ + return m_settings.value(QStringLiteral("readerMarginV"), 0).toInt(); +} + +void Settings::setReaderMarginV(int value) +{ + if (value == readerMarginV()) + return; + m_settings.setValue(QStringLiteral("readerMarginV"), value); + m_settings.sync(); + emit readerMarginVChanged(); +} + QString Settings::downloadDir() const { QString dir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); diff --git a/src/settings.h b/src/settings.h index c902527..538245b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -13,6 +13,7 @@ class Settings : public QObject Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors NOTIFY ignoreSslErrorsChanged) Q_PROPERTY(int readerMargin READ readerMargin WRITE setReaderMargin NOTIFY readerMarginChanged) + Q_PROPERTY(int readerMarginV READ readerMarginV WRITE setReaderMarginV NOTIFY readerMarginVChanged) Q_PROPERTY(QString downloadDir READ downloadDir CONSTANT) // derivata da serverUrl (senza slash finale): accesso QML come appSettings.baseUrl Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged) @@ -36,6 +37,10 @@ public: int readerMargin() const; void setReaderMargin(int value); + // margine verticale (alto e basso, simmetrico) del testo nel lettore, in px + int readerMarginV() const; + void setReaderMarginV(int value); + QString downloadDir() const; // Header "Authorization: Basic ..." pronto da usare, vuoto se utente non impostato @@ -57,6 +62,7 @@ signals: void passwordChanged(); void ignoreSslErrorsChanged(); void readerMarginChanged(); + void readerMarginVChanged(); void baseUrlChanged(); private: