From e4cbab03010fd1b845754f06282d2d759acbf0e7 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Sun, 20 Sep 2020 19:15:45 +0300 Subject: [PATCH] [app] Made night mode brightness configurable Brightness control is implemented by rendering content with transparent background, providing background as a separate item behind the content and adjusting opacity of the content item according to the selected brightness. --- app/app.pro | 1 + app/qml/Books.js | 5 + app/qml/BooksFootnoteView.qml | 62 +++--- app/qml/BooksPageView.qml | 12 +- app/src/BooksPageWidget.cpp | 58 +++--- app/src/BooksPageWidget.h | 27 ++- app/src/BooksPaintContext.cpp | 71 ++++--- app/src/BooksPaintContext.h | 46 ++--- app/src/BooksSettings.cpp | 183 ++++++++++++++---- app/src/BooksSettings.h | 14 +- app/src/BooksTextView.cpp | 28 ++- app/src/BooksTextView.h | 25 ++- .../zlibrary/core/src/options/ZLOptions.h | 5 +- .../fbreader/zlibrary/core/src/util/ZLColor.h | 29 ++- 14 files changed, 364 insertions(+), 202 deletions(-) create mode 100644 app/qml/Books.js diff --git a/app/app.pro b/app/app.pro index 8dea0ac..515cb87 100644 --- a/app/app.pro +++ b/app/app.pro @@ -53,6 +53,7 @@ OTHER_FILES += \ icons/harbour-books.svg \ harbour-books.desktop \ qml/*.qml \ + qml/*.js \ qml/images/* \ settings/*.qml \ settings/*.json \ diff --git a/app/qml/Books.js b/app/qml/Books.js new file mode 100644 index 0000000..c59d146 --- /dev/null +++ b/app/qml/Books.js @@ -0,0 +1,5 @@ +.pragma library + +function contentOpacity(brightness) { + return 0.5 + brightness * 0.5 +} diff --git a/app/qml/BooksFootnoteView.qml b/app/qml/BooksFootnoteView.qml index 8536716..8fa800e 100644 --- a/app/qml/BooksFootnoteView.qml +++ b/app/qml/BooksFootnoteView.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2016 Jolla Ltd. - Contact: Slava Monich + Copyright (C) 2015-2020 Jolla Ltd. + Copyright (C) 2015-2020 Slava Monich You may use this file under the terms of BSD license as follows: @@ -8,14 +8,15 @@ modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Jolla Ltd nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + 3. Neither the names of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -32,9 +33,13 @@ import QtQuick 2.0 import Sailfish.Silica 1.0 +import harbour.books 1.0 + +import "Books.js" as Books Rectangle { id: root + visible: opacity > 0 opacity: 0.0 anchors.fill: parent @@ -47,7 +52,7 @@ Rectangle { function show(startX,startY,text,url) { flickable.scrollToTop() - image.source = url + content.source = url if (state !== "show") { footnoteItem.scale = 0 footnoteItem.x = startX @@ -77,6 +82,7 @@ Rectangle { Item { id: footnoteItem + x: footnoteX y: footnoteY width: footnote.width @@ -85,42 +91,50 @@ Rectangle { Label { id: footnoteLabel + + anchors { + top: parent.top + bottom: footnote.top + bottomMargin: Theme.paddingMedium + } width: parent.width height: Math.round(root.height - footnote.height/2) - 2*Theme.paddingMedium color: Theme.highlightColor verticalAlignment: Text.AlignBottom maximumLineCount: 4 visible: opacity > 0 + Behavior on opacity { FadeAnimation {} } - anchors { - top: parent.top - bottom: footnote.top - bottomMargin: Theme.paddingMedium - } } Rectangle { id: footnote + radius: Theme.paddingMedium/2 border.color: Settings.invertedPageBackgroundColor color: Settings.pageBackgroundColor - width: image.width + 2*Theme.paddingMedium - height: Math.min(root.height/2, image.height + 2*Theme.paddingMedium) - anchors { - bottom: parent.bottom - } + width: content.width + 2*Theme.paddingMedium + height: Math.min(root.height/2, content.height + 2*Theme.paddingMedium) + anchors.bottom: parent.bottom + SilicaFlickable { id: flickable + anchors { fill: parent margins: Theme.paddingMedium } clip: true - contentWidth: image.width - contentHeight: image.height + contentWidth: content.width + contentHeight: content.height + Image { - id: image + id: content + + opacity: Books.contentOpacity(Settings.brightness) + cache: false } + VerticalScrollDecorator {} } } diff --git a/app/qml/BooksPageView.qml b/app/qml/BooksPageView.qml index 2e3f391..801ebbf 100644 --- a/app/qml/BooksPageView.qml +++ b/app/qml/BooksPageView.qml @@ -35,9 +35,13 @@ import QtQuick 2.0 import Sailfish.Silica 1.0 import harbour.books 1.0 -Item { +import "Books.js" as Books + +Rectangle { id: view + color: Settings.pageBackgroundColor + property alias model: widget.model property alias page: widget.page property alias leftMargin: widget.leftMargin @@ -62,9 +66,12 @@ Item { PageWidget { id: widget + anchors.fill: parent model: bookModel pressed: mouseArea.pressed + opacity: Books.contentOpacity(Settings.brightness) + onBrowserLinkPressed: view.browserLinkPressed(url) onImagePressed: view.imagePressed(imageId, rect) onActiveTouch: pressImage.animate(touchX, touchY) @@ -75,6 +82,7 @@ Item { BooksTitleLabel { id: titleLabel + anchors { top: parent.top left: parent.left @@ -99,6 +107,7 @@ Item { Image { id: pressImage + source: Settings.invertColors ? "images/press-invert.svg" : "images/press.svg" visible: opacity > 0 opacity: 0 @@ -162,6 +171,7 @@ Item { MouseArea { id: mouseArea + anchors.fill: parent onClicked: { if (widget.selectionEmpty) { diff --git a/app/src/BooksPageWidget.cpp b/app/src/BooksPageWidget.cpp index de1312a..2aca7e5 100644 --- a/app/src/BooksPageWidget.cpp +++ b/app/src/BooksPageWidget.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2018 Jolla Ltd. - * Copyright (C) 2015-2018 Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -157,7 +157,7 @@ void BooksPageWidget::RenderTask::performTask() { if (!isCanceled() && !iData.isNull() && !iData->iView.isNull() && iWidth > 0 && iHeight > 0) { - iImage = QImage(iWidth, iHeight, QImage::Format_RGB32); + iImage = QImage(iWidth, iHeight, QImage::Format_ARGB32_Premultiplied); if (!isCanceled()) { QPainter painter(&iImage); iData->paint(&painter); @@ -192,7 +192,7 @@ void BooksPageWidget::ClearSelectionTask::performTask() const ZLTextArea& area = iData->iView->textArea(); if (!area.selectionIsEmpty()) { area.clearSelection(); - iImage = QImage(iWidth, iHeight, QImage::Format_RGB32); + iImage = QImage(iWidth, iHeight, QImage::Format_ARGB32_Premultiplied); if (!isCanceled()) { QPainter painter(&iImage); iData->paint(&painter); @@ -288,10 +288,10 @@ public: FootnoteTask(QThreadPool* aPool, int aX, int aY, int aMaxWidth, int aMaxHeight, QString aPath, QString aLinkText, QString aRef, shared_ptr aTextModel, shared_ptr aTextStyle, - bool aInvertColors) : HarbourTask(aPool), + const BooksSettings* aSettings) : HarbourTask(aPool), iTextModel(aTextModel), iTextStyle(aTextStyle), - iInvertColors(aInvertColors), iX(aX), iY(aY), - iMaxWidth(aMaxWidth), iMaxHeight(aMaxHeight), + iInvertColors(aSettings->invertColors()), + iX(aX), iY(aY), iMaxWidth(aMaxWidth), iMaxHeight(aMaxHeight), iRef(aRef), iLinkText(aLinkText), iPath(aPath) {} ~FootnoteTask(); @@ -354,12 +354,10 @@ void BooksPageWidget::FootnoteTask::performTask() BooksPaintContext paintContext(size.myWidth, size.myHeight); paintContext.setInvertColors(iInvertColors); ZLTextAreaController paintController(paintContext, *this, &cache); - iImage = QImage(size.myWidth, size.myHeight, QImage::Format_RGB32); + iImage = QImage(size.myWidth, size.myHeight, QImage::Format_ARGB32_Premultiplied); QPainter painter(&iImage); paintContext.beginPaint(&painter); - paintContext.clear(iInvertColors ? - BooksTextView::INVERTED_BACKGROUND : - BooksTextView::DEFAULT_BACKGROUND); + paintContext.clear(ZLColor(0 /* transparent */)); paintController.setModel(iTextModel); paintController.preparePaintInfo(); paintController.area().paint(); @@ -512,12 +510,7 @@ BooksPageWidget::BooksPageWidget(QQuickItem* aParent) : iCurrentPage(false), iPage(-1) { - connect(iSettings.data(), - SIGNAL(invertColorsChanged()), - SLOT(onInvertColorsChanged())); - setFillColor(qtColor(iSettings->invertColors() ? - BooksTextView::INVERTED_BACKGROUND : - BooksTextView::DEFAULT_BACKGROUND)); + connect(iSettings.data(), SIGNAL(invertColorsChanged()), SLOT(onColorsChanged())); setFlag(ItemHasContents, true); iResizeTimer->setSingleShot(true); iResizeTimer->setInterval(0); @@ -613,14 +606,11 @@ void BooksPageWidget::onTextStyleChanged() resetView(); } -void BooksPageWidget::onInvertColorsChanged() +void BooksPageWidget::onColorsChanged() { HDEBUG(iPage); HASSERT(sender() == iSettings); - if (!iData.isNull() && !iData->iView.isNull()) { - iData->iView->setInvertColors(iSettings->invertColors()); - scheduleRepaint(); - } + scheduleRepaint(); } void BooksPageWidget::onBookModelChanged() @@ -797,7 +787,9 @@ void BooksPageWidget::scheduleRepaint() const int w = width(); const int h = height(); if (w > 0 && h > 0 && !iData.isNull() && !iData->iView.isNull()) { - iData->iView->setInvertColors(invertColors()); + const shared_ptr view(iData->iView); + BooksSettings* settings = iSettings.data(); + view->setInvertColors(settings->invertColors()); (iRenderTask = new RenderTask(iTaskQueue->pool(), iData, w, h))-> submit(this, SLOT(onRenderTaskDone())); } else { @@ -970,7 +962,7 @@ void BooksPageWidget::onLongPressTaskDone() (iFootnoteTask = new FootnoteTask(iTaskQueue->pool(), task->iX, task->iY, width()*3/4, height()*10, book->path(), task->iLinkText, QString::fromStdString(task->iLink), note, - iTextStyle, iSettings->invertColors()))-> + iTextStyle, iSettings.data()))-> submit(this, SLOT(onFootnoteTaskDone())); } else { HDEBUG("bad footnote" << QString(task->iLink.c_str())); diff --git a/app/src/BooksPageWidget.h b/app/src/BooksPageWidget.h index 8f6fce7..434f728 100644 --- a/app/src/BooksPageWidget.h +++ b/app/src/BooksPageWidget.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2018 Jolla Ltd. - * Copyright (C) 2015-2018 Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -130,7 +130,7 @@ private Q_SLOTS: void onBookModelPageMarksChanged(); void onBookModelLoadingChanged(); void onTextStyleChanged(); - void onInvertColorsChanged(); + void onColorsChanged(); void onResetTaskDone(); void onRenderTaskDone(); void onClearSelectionTaskDone(); @@ -147,7 +147,6 @@ private: void releaseExtendSelectionTasks(); void scheduleRepaint(); void cancelRepaint(); - bool invertColors() const; private: class ResetTask; @@ -205,7 +204,5 @@ inline int BooksPageWidget::bottomMargin() const { return iMargins.iBottom; } inline BooksMargins BooksPageWidget::margins() const { return iMargins; } -inline bool BooksPageWidget::invertColors() const - { return iSettings && iSettings->invertColors(); } #endif // BOOKS_PAGE_WIDGET_H diff --git a/app/src/BooksPaintContext.cpp b/app/src/BooksPaintContext.cpp index 5490da1..5296c85 100644 --- a/app/src/BooksPaintContext.cpp +++ b/app/src/BooksPaintContext.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2018 Jolla Ltd. - * Copyright (C) 2015-2018 Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -243,7 +243,9 @@ void BooksPaintContext::drawFilledCircle(int x, int y, int r) void BooksPaintContext::clear(ZLColor aColor) { if (iPainter) { + iPainter->setCompositionMode(QPainter::CompositionMode_Source); iPainter->fillRect(0, 0, iWidth, iHeight, qtColor(aColor)); + iPainter->setCompositionMode(QPainter::CompositionMode_SourceOver); } } @@ -257,11 +259,15 @@ int BooksPaintContext::height() const return iHeight; } -ZLColor BooksPaintContext::realColor(quint8 aRed, quint8 aGreen, quint8 aBlue, bool aInvert) +ZLColor BooksPaintContext::realColor(uchar aRed, uchar aGreen, uchar aBlue, uchar aAlpha, + bool aInvertColors) { - return aInvert ? - ZLColor(255-aRed, 255-aGreen, 255-aBlue) : - ZLColor(aRed, aGreen, aBlue); + if (aInvertColors) { + aRed = 255 - aRed; + aGreen = 255 - aGreen; + aBlue = 255 - aBlue; + } + return ZLColor(aRed, aGreen, aBlue, aAlpha); } ZLColor BooksPaintContext::realColor(const std::string& aStyle, bool aInvert) @@ -269,33 +275,46 @@ ZLColor BooksPaintContext::realColor(const std::string& aStyle, bool aInvert) static const std::string INTERNAL_HYPERLINK("internal"); static const std::string EXTERNAL_HYPERLINK("external"); static const std::string BOOK_HYPERLINK("book"); + unsigned long argb = ZLColor::rgbValue(0); if (ZLStringUtil::startsWith(aStyle, '#')) { - if (aStyle.length() == 7) { - int i, value = 0; + const size_t len = aStyle.length(); + if (len == 7 || len == 9) { + int i; + unsigned long rgb = 0; for (i=1; i<7; i++) { int nibble = ZLStringUtil::fromHex(aStyle[i]); if (nibble >= 0) { - value <<= 4; - value |= nibble; + rgb <<= 4; + rgb |= nibble; } else { break; } } if (i == 7) { - return realColor(ZLColor(value), aInvert); + if (len == 9) { + int a1 = ZLStringUtil::fromHex(aStyle[7]); + int a2 = ZLStringUtil::fromHex(aStyle[8]); + if (a1 >= 0 && a2 >= 0) { + argb = ZLColor::rgbValue(rgb, (a1 << 4) | a2); + } else { + argb = ZLColor::rgbValue(rgb); + } + } else { + argb = ZLColor::rgbValue(rgb); + } } } } else if (aStyle == INTERNAL_HYPERLINK) { - return realColor(33, 96, 180, aInvert); + argb = ZLColor::rgbValue(0x2160b4); } else if (aStyle == EXTERNAL_HYPERLINK) { - return realColor(33, 96, 180, aInvert); + argb = ZLColor::rgbValue(0x2160b4); } else if (aStyle == BOOK_HYPERLINK) { - return realColor(23, 68, 128, aInvert); + argb = ZLColor::rgbValue(0x174480); } else if (aStyle == ZLTextStyle::SELECTION_BACKGROUND) { - return realColor(60, 139, 255, aInvert); + argb = ZLColor::rgbValue(0x3c8bff); } else if (aStyle == ZLTextStyle::HIGHLIGHTED_TEXT) { - return realColor(60, 139, 255, aInvert); + argb = ZLColor::rgbValue(0x3c8bff); } - return realColor(0, 0, 0, aInvert); + return realColor(ZLColor(argb), aInvert); } diff --git a/app/src/BooksPaintContext.h b/app/src/BooksPaintContext.h index 9e83c3b..892815e 100644 --- a/app/src/BooksPaintContext.h +++ b/app/src/BooksPaintContext.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2016 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Nemo Mobile nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -46,7 +46,6 @@ class QPainter; class BooksPaintContext : public ZLPaintContext { - public: BooksPaintContext(int aWidth, int aHeight); BooksPaintContext(); @@ -88,12 +87,15 @@ public: void drawFilledCircle(int x, int y, int r); void setInvertColors(bool aInvertColors); - static ZLColor realColor(const std::string& aStyle, bool aInvertColors); - static ZLColor realColor(quint8 aRed, quint8 aGreen, quint8 aBlue, bool aInvert); - static ZLColor realColor(const ZLColor aColor, bool aInvert); - ZLColor realColor(const std::string& aStyle) const; - ZLColor realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const; + ZLColor realColor(const ZLColor aColor) const; + ZLColor realColor(const std::string& aStyle) const; + static ZLColor realColor(const std::string& aStyle, bool aInvert); + +private: + ZLColor realColor(uchar aRed, uchar aGreen, uchar aBlue, uchar aAlpha) const; + static ZLColor realColor(uchar aRed, uchar aGreen, uchar aBlue, uchar aAlpha, bool aInvert); + static ZLColor realColor(const ZLColor aColor, bool aInvert); private: QPainter* iPainter; @@ -117,13 +119,13 @@ inline QSize BooksPaintContext::size() const { return QSize(iWidth, iHeight); } inline QColor qtColor(const ZLColor& aColor) - { return QColor(aColor.Red, aColor.Green, aColor.Blue); } + { return QColor(aColor.Red, aColor.Green, aColor.Blue, aColor.Alpha); } inline ZLColor BooksPaintContext::realColor(const ZLColor aColor) const - { return realColor(aColor.Red, aColor.Green, aColor.Blue); } -inline ZLColor BooksPaintContext::realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const - { return realColor(aRed, aGreen, aBlue, iInvertColors); } + { return realColor(aColor.Red, aColor.Green, aColor.Blue, aColor.Alpha); } +inline ZLColor BooksPaintContext::realColor(uchar aRed, uchar aGreen, uchar aBlue, uchar aAlpha) const + { return realColor(aRed, aGreen, aBlue, aAlpha, iInvertColors); } inline ZLColor BooksPaintContext::realColor(const ZLColor aColor, bool aInvert) - { return realColor(aColor.Red, aColor.Green, aColor.Blue, aInvert); } + { return realColor(aColor.Red, aColor.Green, aColor.Blue, aColor.Alpha, aInvert); } inline ZLColor BooksPaintContext::realColor(const std::string& aStyle) const { return realColor(aStyle, iInvertColors); } inline void BooksPaintContext::setInvertColors(bool aInvertColors) diff --git a/app/src/BooksSettings.cpp b/app/src/BooksSettings.cpp index 4660570..7a790e1 100644 --- a/app/src/BooksSettings.cpp +++ b/app/src/BooksSettings.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2019 Jolla Ltd. - * Copyright (C) 2015-2019 Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -32,6 +32,7 @@ */ #include "BooksSettings.h" +#include "BooksPaintContext.h" #include "BooksTextStyle.h" #include "BooksTextView.h" #include "BooksBook.h" @@ -45,6 +46,7 @@ #define DCONF_PATH BOOKS_DCONF_ROOT #define KEY_FONT_SIZE "fontSize" #define KEY_PAGE_DETAILS "pageDetails" +#define KEY_NIGHT_MODE_BRIGHTNESS "nightModeBrightness" #define KEY_PAGE_DETAILS_FIXED "pageDetailsFixed" #define KEY_TURN_PAGE_BY_TAP "turnPageByTap" #define KEY_SAMPLE_BOOK_COPIED "sampleBookCopied" @@ -58,6 +60,7 @@ #define KEY_ORIENTATION "orientation" #define DEFAULT_FONT_SIZE 0 +#define DEFAULT_NIGHT_BRIGHTNESS 1.0 #define DEFAULT_PAGE_DETAILS 0 #define DEFAULT_PAGE_DETAILS_FIXED false #define DEFAULT_TURN_PAGE_BY_TAP false @@ -71,6 +74,8 @@ #define DEFAULT_VOLUME_DOWN_ACTION (BooksSettings::ActionPreviousPage) #define DEFAULT_ORIENTATION (BooksSettings::OrientationAny) +#define DEFAULT_BACKGROUND QColor(Qt::white) +#define INVERTED_BACKGROUND QColor(Qt::black) #define PAGETOOL_COLOR QColor(128,128,128) // any bg #define NORMAL_PAGETOOL_HIGHLIGHT_COLOR QColor(64,64,64) // on white #define INVERTED_PAGETOOL_HIGHLIGHT_COLOR QColor(192,192,192) // on black @@ -220,24 +225,32 @@ class BooksSettings::Private : public QObject { public: Private(BooksSettings* aParent); + BooksSettings* parentSettings() const; bool updateCurrentBook(); bool updateCurrentStorage(); - int currentFontSize() const; + bool updateBrightness(); + bool invertColors() const; + int fontSizeValue() const; int fontSize(int aFontSizeAdjust) const; + qreal brightnessValue() const; + qreal nightModeBrightness() const; QString currentFolder() const; shared_ptr textStyle(int aFontSizeAdjust) const; void setCurrentBook(QObject* aBook); static Action getAction(MGConfItem* aItem, Action aDefault); + static qreal normalizeBrightness(qreal aBrightness); private Q_SLOTS: + void onInvertColorsChanged(); + void onNightModeBrightnessChanged(); void onFontSizeValueChanged(); void onCurrentBookPathChanged(); void onCurrentFolderChanged(); public: static QWeakPointer sSharedInstance; - BooksSettings* iParent; MGConfItem* iFontSizeConf; + MGConfItem* iNightModeBrightnessConf; MGConfItem* iPageDetailsConf; MGConfItem* iPageDetailsFixedConf; MGConfItem* iTurnPageByTapConf; @@ -254,14 +267,15 @@ public: BooksBook* iCurrentBook; QString iCurrentStorageDevice; int iFontSize; + qreal iBrightness; }; QWeakPointer BooksSettings::Private::sSharedInstance; BooksSettings::Private::Private(BooksSettings* aParent) : QObject(aParent), - iParent(aParent), iFontSizeConf(new MGConfItem(DCONF_PATH KEY_FONT_SIZE, this)), + iNightModeBrightnessConf(new MGConfItem(DCONF_PATH KEY_NIGHT_MODE_BRIGHTNESS, this)), iPageDetailsConf(new MGConfItem(DCONF_PATH KEY_PAGE_DETAILS, this)), iPageDetailsFixedConf(new MGConfItem(DCONF_PATH KEY_PAGE_DETAILS_FIXED, this)), iTurnPageByTapConf(new MGConfItem(DCONF_PATH KEY_TURN_PAGE_BY_TAP, this)), @@ -276,33 +290,106 @@ BooksSettings::Private::Private(BooksSettings* aParent) : iRemovableRootConf(new MGConfItem(DCONF_PATH KEY_REMOVABLE_ROOT, this)), iCurrentBook(NULL) { - iFontSize = currentFontSize(); + iFontSize = fontSizeValue(); + iBrightness = brightnessValue(); connect(iFontSizeConf, SIGNAL(valueChanged()), SLOT(onFontSizeValueChanged())); connect(iCurrentFolderConf, SIGNAL(valueChanged()), SLOT(onCurrentFolderChanged())); connect(iCurrentBookPathConf, SIGNAL(valueChanged()), SLOT(onCurrentBookPathChanged())); - connect(iPageDetailsConf, SIGNAL(valueChanged()), iParent, SIGNAL(pageDetailsChanged())); - connect(iPageDetailsFixedConf, SIGNAL(valueChanged()), iParent, SIGNAL(pageDetailsFixedChanged())); - connect(iTurnPageByTapConf, SIGNAL(valueChanged()), iParent, SIGNAL(turnPageByTapChanged())); - connect(iInvertColorsConf, SIGNAL(valueChanged()), iParent, SIGNAL(invertColorsChanged())); - connect(iInvertColorsConf, SIGNAL(valueChanged()), iParent, SIGNAL(pageBackgroundColorChanged())); - connect(iSampleBookCopiedConf, SIGNAL(valueChanged()), iParent, SIGNAL(sampleBookCopiedChanged())); - connect(iKeepDisplayOnConf, SIGNAL(valueChanged()), iParent, SIGNAL(keepDisplayOnChanged())); - connect(iVolumeUpActionConf, SIGNAL(valueChanged()), iParent, SIGNAL(volumeUpActionChanged())); - connect(iVolumeDownActionConf, SIGNAL(valueChanged()), iParent, SIGNAL(volumeDownActionChanged())); - connect(iOrientationConf, SIGNAL(valueChanged()), iParent, SIGNAL(orientationChanged())); - connect(iRemovableRootConf, SIGNAL(valueChanged()), iParent, SIGNAL(removableRootChanged())); + connect(iInvertColorsConf, SIGNAL(valueChanged()), SLOT(onInvertColorsChanged())); + connect(iNightModeBrightnessConf, SIGNAL(valueChanged()), SLOT(onNightModeBrightnessChanged())); + connect(iPageDetailsConf, SIGNAL(valueChanged()), aParent, SIGNAL(pageDetailsChanged())); + connect(iPageDetailsFixedConf, SIGNAL(valueChanged()), aParent, SIGNAL(pageDetailsFixedChanged())); + connect(iTurnPageByTapConf, SIGNAL(valueChanged()), aParent, SIGNAL(turnPageByTapChanged())); + connect(iSampleBookCopiedConf, SIGNAL(valueChanged()), aParent, SIGNAL(sampleBookCopiedChanged())); + connect(iKeepDisplayOnConf, SIGNAL(valueChanged()), aParent, SIGNAL(keepDisplayOnChanged())); + connect(iVolumeUpActionConf, SIGNAL(valueChanged()), aParent, SIGNAL(volumeUpActionChanged())); + connect(iVolumeDownActionConf, SIGNAL(valueChanged()), aParent, SIGNAL(volumeDownActionChanged())); + connect(iOrientationConf, SIGNAL(valueChanged()), aParent, SIGNAL(orientationChanged())); + connect(iRemovableRootConf, SIGNAL(valueChanged()), aParent, SIGNAL(removableRootChanged())); +} + +inline BooksSettings* +BooksSettings::Private::parentSettings() const +{ + return qobject_cast(parent()); +} + +inline bool +BooksSettings::Private::invertColors() const +{ + return iInvertColorsConf->value(DEFAULT_INVERT_COLORS).toBool(); +} + +inline qreal +BooksSettings::Private::normalizeBrightness( + qreal aBrightness) +{ + return (aBrightness < 0) ? 0 : (aBrightness > 1) ? 1 : aBrightness; +} + +qreal +BooksSettings::Private::nightModeBrightness() const +{ + bool ok; + QVariant var(iNightModeBrightnessConf->value(DEFAULT_NIGHT_BRIGHTNESS)); + const qreal value = var.toReal(&ok); + return ok ? normalizeBrightness(value) : DEFAULT_NIGHT_BRIGHTNESS; +} + +inline qreal +BooksSettings::Private::brightnessValue() const +{ + return invertColors() ? nightModeBrightness() : 1.0; +} + +bool +BooksSettings::Private::updateBrightness() +{ + const qreal newBrightness = brightnessValue(); + if (iBrightness != newBrightness) { + iBrightness = newBrightness; + HDEBUG(iBrightness); + return true; + } + return false; +} + +void +BooksSettings::Private::onInvertColorsChanged() +{ + BooksSettings* settings = parentSettings(); + if (updateBrightness()) { + Q_EMIT settings->brightnessChanged(); + } + Q_EMIT settings->invertColorsChanged(); + Q_EMIT settings->pageBackgroundColorChanged(); +} + +void +BooksSettings::Private::onNightModeBrightnessChanged() +{ + BooksSettings* settings = parentSettings(); + if (updateBrightness()) { + Q_EMIT settings->brightnessChanged(); + } + Q_EMIT settings->nightModeBrightnessChanged(); } int -BooksSettings::Private::currentFontSize() const +BooksSettings::Private::fontSizeValue() const { - const int fontSize = iFontSizeConf->value(DEFAULT_FONT_SIZE).toInt(); - if (fontSize < MinFontSize) { - return MinFontSize; - } else if (fontSize > MaxFontSize) { - return MaxFontSize; + bool ok; + const int fontSize = iFontSizeConf->value(DEFAULT_FONT_SIZE).toInt(&ok); + if (ok) { + if (fontSize < MinFontSize) { + return MinFontSize; + } else if (fontSize > MaxFontSize) { + return MaxFontSize; + } else { + return fontSize; + } } else { - return fontSize; + return iFontSize; } } @@ -355,7 +442,7 @@ BooksSettings::Private::setCurrentBook( iCurrentBook = NULL; iCurrentBookPathConf->set(QString()); } - Q_EMIT iParent->currentBookChanged(); + Q_EMIT parentSettings()->currentBookChanged(); } } @@ -407,33 +494,35 @@ BooksSettings::Private::updateCurrentStorage() void BooksSettings::Private::onFontSizeValueChanged() { - const int newSize = currentFontSize(); + const int newSize = fontSizeValue(); HDEBUG(newSize); if (iFontSize != newSize) { iFontSize = newSize; for (int i=0; i<=FontSizeSteps; i++) { iTextStyle[i].reset(); } - Q_EMIT iParent->fontSizeChanged(); - Q_EMIT iParent->textStyleChanged(); + BooksSettings* settings = parentSettings(); + Q_EMIT settings->fontSizeChanged(); + Q_EMIT settings->textStyleChanged(); } } void BooksSettings::Private::onCurrentFolderChanged() { + BooksSettings* settings = parentSettings(); if (updateCurrentStorage()) { - Q_EMIT iParent->currentStorageChanged(); + Q_EMIT settings->currentStorageChanged(); } - Q_EMIT iParent->currentFolderChanged(); - Q_EMIT iParent->relativePathChanged(); + Q_EMIT settings->currentFolderChanged(); + Q_EMIT settings->relativePathChanged(); } void BooksSettings::Private::onCurrentBookPathChanged() { if (updateCurrentBook()) { - Q_EMIT iParent->currentBookChanged(); + Q_EMIT parentSettings()->currentBookChanged(); } } @@ -522,6 +611,26 @@ BooksSettings::fontSize() const return iPrivate->iFontSize; } +void +BooksSettings::setNightModeBrightness( + qreal aValue) +{ + HDEBUG(aValue); + iPrivate->iNightModeBrightnessConf->set(Private::normalizeBrightness(aValue)); +} + +qreal +BooksSettings::brightness() const +{ + return iPrivate->iBrightness; +} + +qreal +BooksSettings::nightModeBrightness() const +{ + return iPrivate->nightModeBrightness(); +} + QString BooksSettings::currentStorage() const { @@ -580,7 +689,7 @@ BooksSettings::setTurnPageByTap( bool BooksSettings::invertColors() const { - return iPrivate->iInvertColorsConf->value(DEFAULT_INVERT_COLORS).toBool(); + return iPrivate->invertColors(); } void @@ -698,7 +807,7 @@ BooksSettings::primaryPageToolColor() const QColor BooksSettings::highlightPageToolColor() const { - return invertColors() ? + return iPrivate->invertColors() ? INVERTED_PAGETOOL_HIGHLIGHT_COLOR : NORMAL_PAGETOOL_HIGHLIGHT_COLOR; } @@ -706,9 +815,9 @@ BooksSettings::highlightPageToolColor() const QColor BooksSettings::pageBackgroundColor() const { - return qtColor(invertColors() ? - BooksTextView::INVERTED_BACKGROUND : - BooksTextView::DEFAULT_BACKGROUND); + return iPrivate->invertColors() ? + INVERTED_BACKGROUND : + DEFAULT_BACKGROUND; } BooksSettings::Orientation diff --git a/app/src/BooksSettings.h b/app/src/BooksSettings.h index ff67c31..04a4759 100644 --- a/app/src/BooksSettings.h +++ b/app/src/BooksSettings.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2019 Jolla Ltd. - * Copyright (C) 2015-2019 Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -47,6 +47,8 @@ class BooksSettings : public QObject Q_ENUMS(Orientation) Q_ENUMS(Action) Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged) + Q_PROPERTY(qreal brightness READ brightness NOTIFY brightnessChanged) + Q_PROPERTY(qreal nightModeBrightness READ nightModeBrightness WRITE setNightModeBrightness NOTIFY nightModeBrightnessChanged) Q_PROPERTY(int pageDetails READ pageDetails WRITE setPageDetails NOTIFY pageDetailsChanged) Q_PROPERTY(bool pageDetailsFixed READ pageDetailsFixed WRITE setPageDetailsFixed NOTIFY pageDetailsFixedChanged) Q_PROPERTY(bool turnPageByTap READ turnPageByTap WRITE setTurnPageByTap NOTIFY turnPageByTapChanged) @@ -99,6 +101,10 @@ public: int fontSize() const; void setFontSize(int aValue); + qreal brightness() const; + qreal nightModeBrightness() const; + void setNightModeBrightness(qreal aValue); + int pageDetails() const; void setPageDetails(int aValue); @@ -108,7 +114,7 @@ public: bool turnPageByTap() const; void setTurnPageByTap(bool aValue); - bool invertColors() const; + bool invertColors() const; // Night mode void setInvertColors(bool aValue); bool sampleBookCopied() const; @@ -140,6 +146,8 @@ public: Q_SIGNALS: void fontSizeChanged(); + void nightModeBrightnessChanged(); + void brightnessChanged(); void textStyleChanged(); void pageDetailsChanged(); void pageDetailsFixedChanged(); diff --git a/app/src/BooksTextView.cpp b/app/src/BooksTextView.cpp index 513a3d0..4158d6f 100644 --- a/app/src/BooksTextView.cpp +++ b/app/src/BooksTextView.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2017 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -38,9 +38,6 @@ #define SUPER ZLTextView -const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255); -const ZLColor BooksTextView::INVERTED_BACKGROUND(0, 0, 0); - BooksTextView::BooksTextView( BooksPaintContext& aContext, shared_ptr aTextStyle, @@ -84,7 +81,8 @@ int BooksTextView::bottomMargin() const ZLColor BooksTextView::backgroundColor() const { - return iPaintContext.realColor(DEFAULT_BACKGROUND); + // Background is provided by QML UI, return fully transparent color + return ZLColor(0); } ZLColor BooksTextView::color(const std::string& aStyle) const diff --git a/app/src/BooksTextView.h b/app/src/BooksTextView.h index c012e3a..8a6cf71 100644 --- a/app/src/BooksTextView.h +++ b/app/src/BooksTextView.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2017 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -51,9 +51,6 @@ public: shared_ptr aTextStyle, BooksMargins aMargin); - static const ZLColor DEFAULT_BACKGROUND; - static const ZLColor INVERTED_BACKGROUND; - public: BooksPos position() const; const BooksPos rewind(); diff --git a/fbreader/fbreader/zlibrary/core/src/options/ZLOptions.h b/fbreader/fbreader/zlibrary/core/src/options/ZLOptions.h index c07f191..e5e1246 100644 --- a/fbreader/fbreader/zlibrary/core/src/options/ZLOptions.h +++ b/fbreader/fbreader/zlibrary/core/src/options/ZLOptions.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015-2020 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -183,8 +184,8 @@ public: void setValue(ZLColor value); private: - mutable long myIntValue; - const long myDefaultIntValue; + mutable unsigned long myIntValue; + const unsigned long myDefaultIntValue; }; class ZLDoubleOption : public ZLOption { diff --git a/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h b/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h index 638a70f..3a60cdf 100644 --- a/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h +++ b/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus - * Copyright (C) 2015 Slava Monich + * Copyright (C) 2015-2020 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,25 +22,34 @@ #define __ZLCOLOR_H__ struct ZLColor { + unsigned char Alpha; unsigned char Red; unsigned char Green; unsigned char Blue; + static const unsigned long ALPHA_MASK = 0xff000000; + + ZLColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a); ZLColor(unsigned char r, unsigned char g, unsigned char b); - ZLColor(long longValue = 0); + ZLColor(unsigned long argb = ALPHA_MASK); - void setIntValue(long longValue); - long intValue(); + void setIntValue(unsigned long argb); + unsigned long intValue(); + static unsigned long rgbValue(unsigned long rgb, unsigned char a = 0xff); + bool equals(const ZLColor color) const; bool operator == (const ZLColor &color) const; bool operator != (const ZLColor &color) const; }; -inline ZLColor::ZLColor(unsigned char r, unsigned char g, unsigned char b) : Red(r), Green(g), Blue(b) {} -inline ZLColor::ZLColor(long longValue) : Red((unsigned char)(longValue >> 16)), Green((unsigned char)(longValue >> 8)), Blue((unsigned char)longValue) {} -inline void ZLColor::setIntValue(long longValue) { Red = (unsigned char)(longValue >> 16); Green = (unsigned char)(longValue >> 8); Blue = (unsigned char)longValue; } -inline long ZLColor::intValue() { return (((long)Red) << 16) + (((long)Green) << 8) + Blue; } -inline bool ZLColor::operator == (const ZLColor &color) const { return (Red == color.Red) && (Green == color.Green) && (Blue == color.Blue); } -inline bool ZLColor::operator != (const ZLColor &color) const { return !operator==(color); } +inline ZLColor::ZLColor(unsigned char r, unsigned char g, unsigned char b) : Alpha(0xff), Red(r), Green(g), Blue(b) {} +inline ZLColor::ZLColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) : Alpha(a), Red(r), Green(g), Blue(b) {} +inline ZLColor::ZLColor(unsigned long argb) : Alpha((unsigned char)(argb >> 24)), Red((unsigned char)(argb >> 16)), Green((unsigned char)(argb >> 8)), Blue((unsigned char)argb) {} +inline void ZLColor::setIntValue(unsigned long argb) { Alpha = (unsigned char)(argb >> 24); Red = (unsigned char)(argb >> 16); Green = (unsigned char)(argb >> 8); Blue = (unsigned char)argb; } +inline unsigned long ZLColor::intValue() { return (((unsigned long)Alpha) << 24) | (((unsigned long)Red) << 16) | (((unsigned long)Green) << 8) | (unsigned long)Blue; } +inline unsigned long ZLColor::rgbValue(unsigned long rgb, unsigned char a) { return (((unsigned long)a) << 24) | rgb; } +inline bool ZLColor::equals(const ZLColor color) const { return (Red == color.Red) && (Green == color.Green) && (Blue == color.Blue) && (Alpha == color.Alpha); } +inline bool ZLColor::operator == (const ZLColor &color) const { return equals(color); } +inline bool ZLColor::operator != (const ZLColor &color) const { return !equals(color); } #endif /* __ZLCOLOR_H__ */