From 2a64b91cde5f4a4c89b49aba486a86a7a2d9ea17 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Mon, 10 Oct 2022 03:45:18 +0300 Subject: [PATCH] [app] Made colors configurable --- app/app.pro | 42 +- app/qml/BooksBookView.qml | 6 +- app/qml/BooksFootnoteView.qml | 6 +- app/qml/BooksMain.qml | 10 +- app/qml/BooksMainPage.qml | 6 +- app/qml/BooksPageTools.qml | 14 +- app/qml/BooksPageView.qml | 6 +- app/qml/BooksStorageView.qml | 6 +- app/settings/BooksSettings.qml | 538 +----------------- app/settings/BooksSettingsBase.qml | 698 ++++++++++++++++++++++++ app/settings/BooksSettingsPlugin.cpp | 78 +++ app/settings/SystemSettings.qml | 49 ++ app/settings/harbour-books.json | 14 - app/settings/openrepos-books.json | 14 + app/settings/qmldir | 2 + app/settings/settings.pro | 57 ++ app/src/BooksBook.cpp | 4 +- app/src/BooksBookModel.cpp | 2 +- app/src/BooksColorScheme.cpp | 345 ++++++++++++ app/src/BooksColorScheme.h | 97 ++++ app/src/BooksColorSchemeModel.cpp | 286 ++++++++++ app/src/BooksColorSchemeModel.h | 69 +++ app/src/BooksDefs.h | 19 +- app/src/BooksPageWidget.cpp | 152 +++--- app/src/BooksPaintContext.cpp | 44 +- app/src/BooksPaintContext.h | 87 ++- app/src/BooksSettings.cpp | 214 ++++---- app/src/BooksSettings.h | 29 +- app/src/BooksSettingsBase.cpp | 496 +++++++++++++++++ app/src/BooksSettingsBase.h | 99 ++++ app/src/BooksTextView.h | 7 +- app/src/BooksTypes.h | 23 +- app/src/ZLibrary.cpp | 6 - app/src/main.cpp | 47 +- app/translations/harbour-books-de.ts | 77 ++- app/translations/harbour-books-es.ts | 75 +++ app/translations/harbour-books-fi.ts | 77 ++- app/translations/harbour-books-hu.ts | 75 +++ app/translations/harbour-books-nl.ts | 75 +++ app/translations/harbour-books-pl.ts | 75 +++ app/translations/harbour-books-pt.ts | 75 +++ app/translations/harbour-books-ru.ts | 105 +++- app/translations/harbour-books-sv.ts | 75 +++ app/translations/harbour-books-zh_CN.ts | 75 +++ app/translations/harbour-books.ts | 75 +++ harbour-books.pro | 7 +- rpm/openrepos-books.spec | 5 +- 47 files changed, 3506 insertions(+), 937 deletions(-) create mode 100644 app/settings/BooksSettingsBase.qml create mode 100644 app/settings/BooksSettingsPlugin.cpp create mode 100644 app/settings/SystemSettings.qml delete mode 100644 app/settings/harbour-books.json create mode 100644 app/settings/openrepos-books.json create mode 100644 app/settings/qmldir create mode 100644 app/settings/settings.pro create mode 100644 app/src/BooksColorScheme.cpp create mode 100644 app/src/BooksColorScheme.h create mode 100644 app/src/BooksColorSchemeModel.cpp create mode 100644 app/src/BooksColorSchemeModel.h create mode 100644 app/src/BooksSettingsBase.cpp create mode 100644 app/src/BooksSettingsBase.h diff --git a/app/app.pro b/app/app.pro index 6177333..e7ad092 100644 --- a/app/app.pro +++ b/app/app.pro @@ -55,13 +55,16 @@ OTHER_FILES += \ qml/*.qml \ qml/*.js \ qml/images/* \ - settings/*.qml \ - settings/*.json \ + settings/Books*.qml \ settings/images/* \ data/default/* \ data/zlibrary/core/encodings/* \ data/zlibrary/core/resources/* +app_settings { + OTHER_FILES += settings/SystemSettings.qml +} + TARGET_DATA_DIR = /usr/share/$$TARGET TARGET_DEFAULT_DATA_DIR = $$TARGET_DATA_DIR/data TARGET_ZLIBRARY_DATA_DIR = $$TARGET_DEFAULT_DATA_DIR @@ -107,6 +110,8 @@ INCLUDEPATH += \ SOURCES += \ src/BooksBook.cpp \ src/BooksBookModel.cpp \ + src/BooksColorScheme.cpp \ + src/BooksColorSchemeModel.cpp \ src/BooksConfig.cpp \ src/BooksCoverModel.cpp \ src/BooksCoverWidget.cpp \ @@ -123,6 +128,7 @@ SOURCES += \ src/BooksPos.cpp \ src/BooksSaveTimer.cpp \ src/BooksSettings.cpp \ + src/BooksSettingsBase.cpp \ src/BooksShelf.cpp \ src/BooksStorage.cpp \ src/BooksStorageModel.cpp \ @@ -137,6 +143,8 @@ SOURCES += \ HEADERS += \ src/BooksBook.h \ src/BooksBookModel.h \ + src/BooksColorScheme.h \ + src/BooksColorSchemeModel.h \ src/BooksConfig.h \ src/BooksCoverModel.h \ src/BooksCoverWidget.h \ @@ -155,6 +163,7 @@ HEADERS += \ src/BooksPos.h \ src/BooksSaveTimer.h \ src/BooksSettings.h \ + src/BooksSettingsBase.h \ src/BooksShelf.h \ src/BooksStorage.h \ src/BooksStorageModel.h \ @@ -184,6 +193,7 @@ openrepos { # harbour-lib HEADERS += \ + $$HARBOUR_INCLUDE_DIR/HarbourColorEditorModel.h \ $$HARBOUR_INCLUDE_DIR/HarbourDisplayBlanking.h \ $$HARBOUR_INCLUDE_DIR/HarbourJson.h \ $$HARBOUR_INCLUDE_DIR/HarbourMediaPlugin.h \ @@ -191,12 +201,13 @@ HEADERS += \ $$HARBOUR_INCLUDE_DIR/HarbourPolicyPlugin.h \ $$HARBOUR_INCLUDE_DIR/HarbourSystem.h \ $$HARBOUR_INCLUDE_DIR/HarbourTask.h \ - $$HARBOUR_INCLUDE_DIR/HarbourTheme.h + $$HARBOUR_INCLUDE_DIR/HarbourUtil.h HEADERS += \ $$HARBOUR_SRC_DIR/HarbourMce.h SOURCES += \ + $$HARBOUR_SRC_DIR/HarbourColorEditorModel.cpp \ $$HARBOUR_SRC_DIR/HarbourDisplayBlanking.cpp \ $$HARBOUR_SRC_DIR/HarbourJson.cpp \ $$HARBOUR_SRC_DIR/HarbourMce.cpp \ @@ -205,13 +216,16 @@ SOURCES += \ $$HARBOUR_SRC_DIR/HarbourPolicyPlugin.cpp \ $$HARBOUR_SRC_DIR/HarbourSystem.cpp \ $$HARBOUR_SRC_DIR/HarbourTask.cpp \ - $$HARBOUR_SRC_DIR/HarbourTheme.cpp + $$HARBOUR_SRC_DIR/HarbourUtil.cpp HARBOUR_QML_COMPONENTS = \ - $$HARBOUR_LIB_QML/HarbourFitLabel.qml \ - $$HARBOUR_LIB_QML/HarbourHighlightIcon.qml \ - $$HARBOUR_LIB_QML/HarbourHorizontalSwipeHint.qml \ - $$HARBOUR_LIB_QML/HarbourPressEffect.qml + $$HARBOUR_LIB_QML/HarbourColorEditorDialog.qml \ + $$HARBOUR_LIB_QML/HarbourColorHueItem.qml \ + $$HARBOUR_LIB_QML/HarbourColorPickerDialog.qml \ + $$HARBOUR_LIB_QML/HarbourFitLabel.qml \ + $$HARBOUR_LIB_QML/HarbourHighlightIcon.qml \ + $$HARBOUR_LIB_QML/HarbourHorizontalSwipeHint.qml \ + $$HARBOUR_LIB_QML/HarbourPressEffect.qml OTHER_FILES += $${HARBOUR_QML_COMPONENTS} @@ -233,17 +247,6 @@ for(s, ICON_SIZES) { INSTALLS += $${icon_target} } -# Settings -app_settings { - settings_json.files = settings/$${TARGET}.json - settings_json.path = /usr/share/jolla-settings/entries/ - equals(PREFIX, "openrepos") { - settings_json.extra = sed s/harbour/openrepos/g settings/harbour-$${NAME}.json > $$eval(settings_json.files) - settings_json.CONFIG += no_check_exist - } - INSTALLS += settings_json -} - settings_qml.files = settings/*.qml settings_qml.path = /usr/share/$${TARGET}/settings/ INSTALLS += settings_qml @@ -262,6 +265,7 @@ openrepos { # Translations TRANSLATION_IDBASED=-idbased TRANSLATION_SOURCES = \ + $${_PRO_FILE_PWD_}/src \ $${_PRO_FILE_PWD_}/qml \ $${_PRO_FILE_PWD_}/settings diff --git a/app/qml/BooksBookView.qml b/app/qml/BooksBookView.qml index b2e5934..641e355 100644 --- a/app/qml/BooksBookView.qml +++ b/app/qml/BooksBookView.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2021 Jolla Ltd. - Copyright (C) 2015-2021 Slava Monich + Copyright (C) 2015-2022 Jolla Ltd. + Copyright (C) 2015-2022 Slava Monich You may use this file under the terms of BSD license as follows: @@ -218,7 +218,7 @@ Item { Rectangle { id: loadingBackground anchors.fill: parent - color: HarbourTheme.invertedPrimaryColor + color: HarbourUtil.invertedColor(Theme.primaryColor) visible: loading && opacity > 0 } diff --git a/app/qml/BooksFootnoteView.qml b/app/qml/BooksFootnoteView.qml index 8fa800e..50c6036 100644 --- a/app/qml/BooksFootnoteView.qml +++ b/app/qml/BooksFootnoteView.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2020 Jolla Ltd. - Copyright (C) 2015-2020 Slava Monich + Copyright (C) 2015-2021 Jolla Ltd. + Copyright (C) 2015-2021 Slava Monich You may use this file under the terms of BSD license as follows: @@ -72,7 +72,7 @@ Rectangle { Connections { target: Settings - onInvertColorsChanged: cancel() + onNightModeChanged: cancel() } MouseArea { diff --git a/app/qml/BooksMain.qml b/app/qml/BooksMain.qml index fd25f67..4824e29 100644 --- a/app/qml/BooksMain.qml +++ b/app/qml/BooksMain.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2020 Jolla Ltd. - Copyright (C) 2015-2020 Slava Monich + Copyright (C) 2015-2021 Jolla Ltd. + Copyright (C) 2015-2021 Slava Monich You may use this file under the terms of BSD license as follows: @@ -58,6 +58,12 @@ ApplicationWindow { Settings.keepDisplayOn } + Binding { + target: Settings + property: "theme" + value: Theme + } + initialPage: BooksMainPage { id: mainPage } cover: Component { diff --git a/app/qml/BooksMainPage.qml b/app/qml/BooksMainPage.qml index 0884750..685142e 100644 --- a/app/qml/BooksMainPage.qml +++ b/app/qml/BooksMainPage.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2021 Jolla Ltd. - Copyright (C) 2015-2021 Slava Monich + Copyright (C) 2015-2022 Jolla Ltd. + Copyright (C) 2015-2022 Slava Monich You may use this file under the terms of BSD license as follows: @@ -124,7 +124,7 @@ Page { isCurrentView: currentView === bookView pageActive: page.pageActive book: Settings.currentBook ? Settings.currentBook : null - loadingBackgroundOpacity: HarbourTheme.opacityOverlay * storageView.opacity + loadingBackgroundOpacity: 0.8 /* opacityOverlay */ * storageView.opacity onCloseBook: Settings.currentBook = null onVisibleChanged: if (visible) opacity = 1 diff --git a/app/qml/BooksPageTools.qml b/app/qml/BooksPageTools.qml index a9fa64c..b3c377b 100644 --- a/app/qml/BooksPageTools.qml +++ b/app/qml/BooksPageTools.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2019 Jolla Ltd. - Copyright (C) 2015-2019 Slava Monich + Copyright (C) 2015-2021 Jolla Ltd. + Copyright (C) 2015-2021 Slava Monich You may use this file under the terms of BSD license as follows: @@ -57,7 +57,7 @@ Item { left: parent.left verticalCenter: parent.verticalCenter } - onClicked: Settings.invertColors = !Settings.invertColors + onClicked: Settings.nightMode = !Settings.nightMode Image { id: dayModeImage @@ -68,7 +68,7 @@ Item { verticalCenter: parent.verticalCenter } sourceSize.height: Theme.iconSizeSmall - opacity: Settings.invertColors ? 0.5 : 0 + opacity: Settings.nightMode ? 0.5 : 0 visible: opacity > 0 Behavior on opacity { FadeAnimation {} } } @@ -77,7 +77,7 @@ Item { source: "images/night-mode.svg" anchors.centerIn: dayModeImage sourceSize.height: Theme.iconSizeSmall - opacity: Settings.invertColors ? 0 : 0.25 + opacity: Settings.nightMode ? 0 : 0.25 visible: opacity > 0 Behavior on opacity { FadeAnimation {} } } @@ -101,7 +101,7 @@ Item { verticalCenter: parent.verticalCenter } sourceSize.height: Theme.iconSizeSmall - opacity: Settings.invertColors ? 1 : 0.5 + opacity: Settings.nightMode ? 1 : 0.5 Behavior on opacity { FadeAnimation {} } } onClicked: pageTools.increaseFontSize() @@ -123,7 +123,7 @@ Item { verticalCenter: parent.verticalCenter } sourceSize.height: increaseFontSizeButtonImage.height - opacity: Settings.invertColors ? 1 : 0.5 + opacity: Settings.nightMode ? 1 : 0.5 Behavior on opacity { FadeAnimation {} } } onClicked: pageTools.decreaseFontSize() diff --git a/app/qml/BooksPageView.qml b/app/qml/BooksPageView.qml index 6ca844a..f24aaff 100644 --- a/app/qml/BooksPageView.qml +++ b/app/qml/BooksPageView.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2020 Jolla Ltd. - Copyright (C) 2015-2020 Slava Monich + Copyright (C) 2015-2021 Jolla Ltd. + Copyright (C) 2015-2021 Slava Monich You may use this file under the terms of BSD license as follows: @@ -109,7 +109,7 @@ Rectangle { Image { id: pressImage - source: Settings.invertColors ? "images/press-invert.svg" : "images/press.svg" + source: Settings.nightMode ? "images/press-invert.svg" : "images/press.svg" visible: opacity > 0 opacity: 0 readonly property int maxsize: Math.max(view.width, view.height) diff --git a/app/qml/BooksStorageView.qml b/app/qml/BooksStorageView.qml index 06afc06..4717f6e 100644 --- a/app/qml/BooksStorageView.qml +++ b/app/qml/BooksStorageView.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2021 Jolla Ltd. - Copyright (C) 2015-2021 Slava Monich + Copyright (C) 2015-2022 Jolla Ltd. + Copyright (C) 2015-2022 Slava Monich You may use this file under the terms of BSD license as follows: @@ -113,7 +113,7 @@ Item { pageStack.push(_settingsComponent, { "title" : text, "allowedOrientations": window.allowedOrientations, - "inApp": true + "inApp": true, }) } } diff --git a/app/settings/BooksSettings.qml b/app/settings/BooksSettings.qml index 361b828..c9c7978 100644 --- a/app/settings/BooksSettings.qml +++ b/app/settings/BooksSettings.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2021 Jolla Ltd. - Copyright (C) 2015-2021 Slava Monich + Copyright (C) 2015-2022 Jolla Ltd. + Copyright (C) 2015-2022 Slava Monich You may use this file under the terms of BSD license as follows: @@ -32,530 +32,18 @@ */ import QtQuick 2.0 -import Sailfish.Silica 1.0 -import org.nemomobile.configuration 1.0 +import harbour.books 1.0 -import "../qml/Books.js" as Books -import "../qml/harbour" - -Page { - id: page - - property bool inApp - property alias title: pageHeader.title - readonly property string rootPath: "/apps/" + appName() + "/" - readonly property bool darkOnLight: ('colorScheme' in Theme) && Theme.colorScheme === 1 - readonly property int screenWidth: isPortrait ? Screen.width : Screen.height - readonly property int screenHeight: isPortrait ? Screen.height : Screen.width - readonly property bool landscapeLayout: (screenWidth > screenHeight && Screen.sizeCategory > Screen.Small) || Screen.sizeCategory > Screen.Medium - - // jolla-settings expects these properties: - property var applicationName - property var applicationIcon - - // Deduce package name from the path - function appName() { - var parts = Qt.resolvedUrl("dummy").split('/') - if (parts.length > 2) { - var name = parts[parts.length-3] - if (name.indexOf("-books") >= 0) { - return name - } - } - return "harbour-books" +// In-app settings +BooksSettingsBase { + inApp: true + colorSchemeModel: BooksColorSchemeModel { + Component.onCompleted: colorScheme = Settings.customColorScheme + onColorSchemeChanged: Settings.customColorScheme = colorScheme } - - Loader { - active: inApp // Follow orientation changes - Connections { - target: orientation - onValueChanged: allowedOrientations = - (orientation.value === 1) ? Orientation.Portrait : - (orientation.value === 2) ? Orientation.Landscape : - Orientation.All - } - } - - SilicaFlickable { - anchors.fill: parent - contentHeight: content.height - - // Night mode example (positioned right above the slider) - Rectangle { - opacity: nightModeBrightnessSlider.pressed ? 1.0 : 0 - visible: opacity > 0 - radius: Theme.paddingSmall - width: nightModeExampleLabel.width + 2 * Theme.paddingLarge - height: nightModeExampleLabel.height + 2 * Theme.paddingMedium - readonly property int xMin: nightModeBrightnessSlider.leftMargin - readonly property int xMax: content.width - nightModeBrightnessSlider.rightMargin - width - readonly property int yOffset: landscapeLayout ? (Theme.itemSizeExtraLarge - Theme.itemSizeMedium) : 0 - x: content.x + displayGrid.x + Math.max(Math.min(nightModeBrightnessSlider.sliderLeft + Math.round(nightModeBrightnessSlider.sliderThumbX - width/2.0), xMax), xMin) - y: content.y + displayGrid.y + nightModeBrightnessSlider.y + yOffset - height - z: nightModeBrightnessSlider.z + 1 - color: "black" - border { - color: Theme.highlightColor - width: Math.ceil(radius/5) - } - - Label { - id: nightModeExampleLabel - - anchors.centerIn: parent - color: "white" - opacity: Books.contentOpacity(nightModeBrightness.value) - //: Night mode example label - //% "Night mode" - text: qsTrId("harbour-books-settings-page-night_mode_example") - font { - bold: true - pixelSize: Theme.fontSizeLarge - family: "Times" - } - } - - Behavior on x { SmoothedAnimation { duration: 125 } } - Behavior on opacity { FadeAnimation { duration: 500 } } - } - - Column { - id: content - width: parent.width - - PageHeader { - id: pageHeader - rightMargin: Theme.horizontalPageMargin + (appIcon.visible ? (height - appIcon.padding) : 0) - title: applicationName ? applicationName : - //: Settings page header (app name) - //% "Books" - qsTrId("harbour-books-settings-page-header") - description: inApp ? "" : - //: Settings page header description (app version) - //% "Version %1" - qsTrId("harbour-books-settings-version").arg(Books.version) - - Image { - id: appIcon - readonly property int padding: Theme.paddingLarge - readonly property int size: pageHeader.height - 2 * padding - x: pageHeader.width - width - Theme.horizontalPageMargin - y: padding - width: size - height: size - sourceSize: Qt.size(size,size) - source: applicationIcon ? applicationIcon : "" - visible: appIcon.status === Image.Ready - } - } - - // =============== Display =============== - - SectionHeader { - //: Section header for display settings - //% "Display" - text: qsTrId("harbour-books-settings-page-display-section_header") - } - - Grid { - id: displayGrid - - width: parent.width - columns: landscapeLayout ? 2 : 1 - - readonly property real columnWidth: width/columns - - Slider { - id: fontSizeSlider - - minimumValue: -5 - maximumValue: 15 - stepSize: 1 - width: parent.columnWidth - leftMargin: landscapeLayout ? Theme.horizontalPageMargin : nightModeBrightnessSlider.leftMargin - rightMargin: leftMargin - //: Slider value label for the standard font size - //% "Default" - readonly property string normal: qsTrId("harbour-books-settings-page-font_size_label-default") - //: Slider label - //% "Font size" - label: qsTrId("harbour-books-settings-page-font_size_label") - valueText: (value === 0) ? normal : ((value > 0) ? ("+" + value) : value) - onSliderValueChanged: fontSize.value = value - Component.onCompleted: value = fontSize.value - - ConfigurationValue { - id: fontSize - key: rootPath + "fontSize" - defaultValue: 0 - onValueChanged: fontSizeSlider.value = value - } - } - - Slider { - id: nightModeBrightnessSlider - - width: parent.columnWidth - leftMargin: keepDisplayOnSwitch.leftMargin - Theme.paddingLarge + Theme.itemSizeExtraSmall - rightMargin: leftMargin - //: Slider label - //% "Brightness in night mode" - label: qsTrId("harbour-books-settings-page-night_mode_brightness_label") - stepSize: (maximumValue - minimumValue) / 100.0 - onSliderValueChanged: nightModeBrightness.value = value - value: nightModeBrightness.value - valueText: landscapeLayout ? " " : "" - - readonly property real sliderLeft: x + leftMargin - readonly property real sliderRight: x + width - rightMargin - readonly property real sliderWidth: width - leftMargin - rightMargin - readonly property real sliderThumbX: sliderLeft + (maximumValue > minimumValue) ? (sliderWidth * sliderValue / (maximumValue - minimumValue)) : 0 - readonly property real sliderBarVerticalCenter: Math.round(height - Theme.fontSizeSmall - Theme.paddingSmall - Theme.itemSizeExtraSmall*3/8) - readonly property color highlightColor: highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor - - ConfigurationValue { - id: nightModeBrightness - key: rootPath + "nightModeBrightness" - defaultValue: 1 - } - - HarbourHighlightIcon { - source: "images/brightness.svg" - y: nightModeBrightnessSlider.sliderBarVerticalCenter - Math.round(height/2) - anchors { - left: parent.left - leftMargin: nightModeBrightnessSlider.leftMargin - Theme.paddingSmall - width - } - sourceSize.height: Math.round(Theme.iconSizeSmall * 0.8) - highlightColor: nightModeBrightnessSlider.highlightColor - opacity: (darkOnLight && !nightModeBrightnessSlider.highlighted) ? 0.6 : 1.0 - } - - HarbourHighlightIcon { - source: "images/brightness.svg" - y: nightModeBrightnessSlider.sliderBarVerticalCenter - Math.round(height/2) - anchors { - right: parent.right - rightMargin: nightModeBrightnessSlider.rightMargin - Theme.paddingSmall - width - } - sourceSize.height: Math.round(Theme.iconSizeSmall * 1.2) - highlightColor: nightModeBrightnessSlider.highlightColor - opacity: (darkOnLight && !nightModeBrightnessSlider.highlighted) ? 0.6 : 1.0 - } - } - } - - Grid { - width: parent.width - columns: landscapeLayout ? 2 : 1 - flow: Grid.TopToBottom - - readonly property real columnWidth: width/columns - - Column { - width: parent.columnWidth - - ComboBox { - id: orientationComboBox - - //: Combo box label - //% "Orientation" - label: qsTrId("harbour-books-settings-page-orientation_label") - value: currentItem ? currentItem.text : "" - menu: ContextMenu { - id: orientationMenu - - x: 0 - width: orientationComboBox.width - readonly property int defaultIndex: 0 - MenuItem { - readonly property int value: 0 - //: Combo box value for dynamic orientation - //% "Dynamic" - text: qsTrId("harbour-books-settings-page-orientation-dynamic") - onClicked: orientation.value = value - } - MenuItem { - readonly property int value: 1 - //: Combo box value for portrait orientation - //% "Portrait" - text: qsTrId("harbour-books-settings-page-orientation-portrait") - onClicked: orientation.value = value - } - MenuItem { - readonly property int value: 2 - //: Combo box value for landscape orientation - //% "Landscape" - text: qsTrId("harbour-books-settings-page-orientation-landscape") - onClicked: orientation.value = value - } - } - Component.onCompleted: orientation.updateControls() - ConfigurationValue { - id: orientation - key: rootPath + "orientation" - defaultValue: 0 - onValueChanged: updateControls() - function updateControls() { - var n = orientationMenu.children.length - var index = orientationMenu.defaultIndex - for (var i=0; i + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 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 + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import org.nemomobile.configuration 1.0 + +import "../qml/Books.js" as Books +import "../qml/harbour" + +Page { + id: thisPage + + property bool inApp + property var colorSchemeModel + property var colorEditorModel + property alias title: pageHeader.title + + signal resetColors() + + // jolla-settings expects these properties: + property var applicationName + property var applicationIcon + + // Internal properties + readonly property string _rootPath: "/apps/" + appName() + "/" + readonly property bool _darkOnLight: ('colorScheme' in Theme) && Theme.colorScheme === 1 + readonly property int _screenWidth: isPortrait ? Screen.width : Screen.height + readonly property int _screenHeight: isPortrait ? Screen.height : Screen.width + readonly property bool _landscapeLayout: (_screenWidth > _screenHeight && Screen.sizeCategory > Screen.Small) || Screen.sizeCategory > Screen.Medium + + // Deduce package name from the path + function appName() { + var parts = Qt.resolvedUrl("dummy").split('/') + if (parts.length > 2) { + var name = parts[parts.length-3] + if (name.indexOf("-books") >= 0) { + return name + } + } + return "harbour-books" + } + + Loader { + active: inApp // Follow orientation changes + Connections { + target: orientation + onValueChanged: allowedOrientations = + (orientation.value === 1) ? Orientation.Portrait : + (orientation.value === 2) ? Orientation.Landscape : + Orientation.All + } + } + + SilicaFlickable { + anchors.fill: parent + contentHeight: content.height + + // Night mode example (positioned right above the slider) + Rectangle { + opacity: nightModeBrightnessSlider.pressed ? 1.0 : 0 + visible: opacity > 0 + radius: Theme.paddingSmall + width: nightModeExampleLabel.width + 2 * Theme.paddingLarge + height: nightModeExampleLabel.height + 2 * Theme.paddingMedium + readonly property int xMin: nightModeBrightnessSlider.leftMargin + readonly property int xMax: content.width - nightModeBrightnessSlider.rightMargin - width + readonly property int yOffset: _landscapeLayout ? (Theme.itemSizeExtraLarge - Theme.itemSizeMedium) : 0 + x: content.x + displayGrid.x + Math.max(Math.min(nightModeBrightnessSlider.sliderLeft + Math.round(nightModeBrightnessSlider.sliderThumbX - width/2.0), xMax), xMin) + y: content.y + displayGrid.y + nightModeBrightnessSlider.y + yOffset - height + z: nightModeBrightnessSlider.z + 1 + color: "black" + border { + color: Theme.highlightColor + width: Math.ceil(radius/5) + } + + Label { + id: nightModeExampleLabel + + anchors.centerIn: parent + color: "white" + opacity: Books.contentOpacity(nightModeBrightness.value) + //: Night mode example label + //% "Night mode" + text: qsTrId("harbour-books-settings-page-night_mode_example") + font { + bold: true + pixelSize: Theme.fontSizeLarge + family: "Times" + } + } + + Behavior on x { SmoothedAnimation { duration: 125 } } + Behavior on opacity { FadeAnimation { duration: 500 } } + } + + Column { + id: content + width: parent.width + + PageHeader { + id: pageHeader + rightMargin: Theme.horizontalPageMargin + (appIcon.visible ? (height - appIcon.padding) : 0) + title: applicationName ? applicationName : + //: Settings page header (app name) + //% "Books" + qsTrId("harbour-books-settings-page-header") + description: inApp ? "" : + //: Settings page header description (app version) + //% "Version %1" + qsTrId("harbour-books-settings-version").arg(Books.version) + + Image { + id: appIcon + readonly property int padding: Theme.paddingLarge + readonly property int size: pageHeader.height - 2 * padding + x: pageHeader.width - width - Theme.horizontalPageMargin + y: padding + width: size + height: size + sourceSize: Qt.size(size,size) + source: applicationIcon ? applicationIcon : "" + visible: appIcon.status === Image.Ready + } + } + + // =============== Display =============== + + SectionHeader { + //: Section header for display settings + //% "Display" + text: qsTrId("harbour-books-settings-page-display-section_header") + } + + Grid { + id: displayGrid + + width: parent.width + columns: _landscapeLayout ? 2 : 1 + + readonly property real columnWidth: width/columns + + Slider { + id: fontSizeSlider + + minimumValue: -5 + maximumValue: 15 + stepSize: 1 + width: parent.columnWidth + leftMargin: _landscapeLayout ? Theme.horizontalPageMargin : nightModeBrightnessSlider.leftMargin + rightMargin: leftMargin + //: Slider value label for the standard font size + //% "Default" + readonly property string normal: qsTrId("harbour-books-settings-page-font_size_label-default") + //: Slider label + //% "Font size" + label: qsTrId("harbour-books-settings-page-font_size_label") + valueText: (value === 0) ? normal : ((value > 0) ? ("+" + value) : value) + onSliderValueChanged: fontSize.value = value + Component.onCompleted: value = fontSize.value + + ConfigurationValue { + id: fontSize + key: _rootPath + "fontSize" + defaultValue: 0 + onValueChanged: fontSizeSlider.value = value + } + } + + Slider { + id: nightModeBrightnessSlider + + width: parent.columnWidth + leftMargin: keepDisplayOnSwitch.leftMargin - Theme.paddingLarge + Theme.itemSizeExtraSmall + rightMargin: leftMargin + //: Slider label + //% "Brightness in night mode" + label: qsTrId("harbour-books-settings-page-night_mode_brightness_label") + stepSize: (maximumValue - minimumValue) / 100.0 + onSliderValueChanged: nightModeBrightness.value = value + value: nightModeBrightness.value + valueText: _landscapeLayout ? " " : "" + + readonly property real sliderLeft: x + leftMargin + readonly property real sliderRight: x + width - rightMargin + readonly property real sliderWidth: width - leftMargin - rightMargin + readonly property real sliderThumbX: sliderLeft + (maximumValue > minimumValue) ? (sliderWidth * sliderValue / (maximumValue - minimumValue)) : 0 + readonly property real sliderBarVerticalCenter: Math.round(height - Theme.fontSizeSmall - Theme.paddingSmall - Theme.itemSizeExtraSmall*3/8) + readonly property color highlightColor: highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor + + ConfigurationValue { + id: nightModeBrightness + key: _rootPath + "nightModeBrightness" + defaultValue: 1 + } + + HarbourHighlightIcon { + source: "images/brightness.svg" + y: nightModeBrightnessSlider.sliderBarVerticalCenter - Math.round(height/2) + anchors { + left: parent.left + leftMargin: nightModeBrightnessSlider.leftMargin - Theme.paddingSmall - width + } + sourceSize.height: Math.round(Theme.iconSizeSmall * 0.8) + highlightColor: nightModeBrightnessSlider.highlightColor + opacity: (_darkOnLight && !nightModeBrightnessSlider.highlighted) ? 0.6 : 1.0 + } + + HarbourHighlightIcon { + source: "images/brightness.svg" + y: nightModeBrightnessSlider.sliderBarVerticalCenter - Math.round(height/2) + anchors { + right: parent.right + rightMargin: nightModeBrightnessSlider.rightMargin - Theme.paddingSmall - width + } + sourceSize.height: Math.round(Theme.iconSizeSmall * 1.2) + highlightColor: nightModeBrightnessSlider.highlightColor + opacity: (_darkOnLight && !nightModeBrightnessSlider.highlighted) ? 0.6 : 1.0 + } + } + } + + Grid { + width: parent.width + columns: _landscapeLayout ? 2 : 1 + flow: Grid.TopToBottom + + readonly property real columnWidth: width/columns + + Column { + width: parent.columnWidth + + ComboBox { + id: orientationComboBox + + //: Combo box label + //% "Orientation" + label: qsTrId("harbour-books-settings-page-orientation_label") + value: currentItem ? currentItem.text : "" + menu: ContextMenu { + id: orientationMenu + + x: 0 + width: orientationComboBox.width + readonly property int defaultIndex: 0 + MenuItem { + readonly property int value: 0 + //: Combo box value for dynamic orientation + //% "Dynamic" + text: qsTrId("harbour-books-settings-page-orientation-dynamic") + onClicked: orientation.value = value + } + MenuItem { + readonly property int value: 1 + //: Combo box value for portrait orientation + //% "Portrait" + text: qsTrId("harbour-books-settings-page-orientation-portrait") + onClicked: orientation.value = value + } + MenuItem { + readonly property int value: 2 + //: Combo box value for landscape orientation + //% "Landscape" + text: qsTrId("harbour-books-settings-page-orientation-landscape") + onClicked: orientation.value = value + } + } + Component.onCompleted: orientation.updateControls() + ConfigurationValue { + id: orientation + key: _rootPath + "orientation" + defaultValue: 0 + onValueChanged: updateControls() + function updateControls() { + var n = orientationMenu.children.length + var index = orientationMenu.defaultIndex + for (var i=0; i 0 + clip: true + + readonly property real columnWidth: width/columns + + Repeater { + model: colorSchemeModel + delegate: BackgroundItem { + id: delegate + + width: customColorsGrid.columnWidth + + Rectangle { + id: colorButton + + width: height + height: Theme.itemSizeSmall - 2 * Theme.paddingMedium + color: model.color + border { + width: 1 + color: Theme.primaryColor + } + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: Theme.paddingMedium + } + layer.enabled: delegate.highlighted + layer.effect: HarbourPressEffect { + source: colorButton + } + } + + Label{ + anchors { + verticalCenter: parent.verticalCenter + left: colorButton.right + leftMargin: Theme.paddingMedium + right: parent.right + } + truncationMode: TruncationMode.Fade + text: model.label + } + + onClicked: { + var dialog = pageStack.push(Qt.resolvedUrl("../qml/harbour/HarbourColorPickerDialog.qml"), { + allowedOrientations: thisPage.allowedOrientations, + acceptDestinationAction: PageStackAction.Replace, + colorModel: colorEditorModel, + color: model.color, + //: Pulley menu item + //% "Reset colors" + resetColorsMenuText: qsTrId("harbour-books-color_picker-menu-reset_colors"), + //: Dialog title label + //% "Select color" + acceptText: qsTrId("harbour-books-color_picker-action-select_color"), + //: Dialog title label + //% "Add color" + addColorAcceptText: qsTrId("harbour-books-color_picker-action-add_color"), + //: Hue slider label + //% "Color" + addColorHueSliderText: qsTrId("harbour-books-color_picker-slider-hue"), + //: Brightness slider label + //% "Brightness" + addColorBrightnessSliderText: qsTrId("harbour-books-color_picker-slider-brightness"), + //: Text field description + //% "Hex notation" + addColorHexNotationText: qsTrId("harbour-books-color_picker-text-hex_notation") + }) + dialog.resetColors.connect(thisPage.resetColors) + dialog.accepted.connect(function() { + delegate.setColor(dialog.color) + }) + } + + function setColor(c) { + model.color = c + } + } + } + + Behavior on height { + id: customColorsGridHeightBehavior + + enabled: false + NumberAnimation { duration: 200 } + } + } + + // =============== Memory card =============== + + SectionHeader { + //: Section header for memory card settings + //% "Memory card" + text: qsTrId("harbour-books-settings-page-removable-section_header") + } + + TextField { + id: removableRootField + width: parent.width + labelVisible: false + + Component.onCompleted: text = removableRoot.value + onActiveFocusChanged: removableRoot.value = text + EnterKey.onClicked: thisPage.focus = true + EnterKey.iconSource: "image://theme/icon-m-enter-close" + + ConfigurationValue { + id: removableRoot + key: _rootPath + "removableRoot" + defaultValue: "Books" + onValueChanged: removableRootField.text = value + } + } + + Label { + id: removableRootLabel + //: Settings field label + //% "Books folder" + text: qsTrId("harbour-books-settings-page-removable_root-label") + x: removableRootField.textLeftMargin + width: removableRootField.width - removableRootField.textLeftMargin - removableRootField.textRightMargin + height: text.length ? (implicitHeight + Theme.paddingMedium) : 0 + anchors { + topMargin: -Theme.paddingSmall + bottomMargin: Theme.paddingMedium + } + color: removableRootField.activeFocus ? Theme.highlightColor : Theme.primaryColor + opacity: removableRootField.activeFocus ? 1.0 : 0.6 + elide: Text.ElideRight + font.pixelSize: Theme.fontSizeSmall + } + + Label { + //: Settings field description + //% "Leave the folder name empty to scan the entire memory card for books." + text: qsTrId("harbour-books-settings-page-removable_root-description") + height: text.length ? (implicitHeight + Theme.paddingMedium) : 0 + width: removableRootLabel.width + x: removableRootLabel.x + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.secondaryColor + wrapMode: Text.Wrap + } + } + + VerticalScrollDecorator { } + } +} diff --git a/app/settings/BooksSettingsPlugin.cpp b/app/settings/BooksSettingsPlugin.cpp new file mode 100644 index 0000000..f2b76b1 --- /dev/null +++ b/app/settings/BooksSettingsPlugin.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksColorSchemeModel.h" +#include "BooksSettingsBase.h" + +#include "HarbourColorEditorModel.h" +#include "HarbourDebug.h" + +#include + +#define SETTINGS_QML_PLUGIN "openrepos.books.settings" + +#define SETTINGS_QML_REGISTER_(klass,name) \ + qmlRegisterType(SETTINGS_QML_PLUGIN, 1, 0, name) +#define SETTINGS_QML_REGISTER(klass) \ + SETTINGS_QML_REGISTER_(klass,#klass) + +class BooksSettingsPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID SETTINGS_QML_PLUGIN) + +public: + void initializeEngine(QQmlEngine*, const char*) Q_DECL_OVERRIDE; + void registerTypes(const char*) Q_DECL_OVERRIDE; +}; + +void +BooksSettingsPlugin::initializeEngine( + QQmlEngine*, + const char* aUri) +{ + HDEBUG(aUri); +} + +void +BooksSettingsPlugin::registerTypes( + const char* aUri) +{ + HDEBUG(aUri); + HASSERT(QLatin1String(aUri) == QLatin1String(SETTINGS_QML_PLUGIN)); + SETTINGS_QML_REGISTER_(BooksSettingsBase, "BooksSettings"); + SETTINGS_QML_REGISTER(BooksColorSchemeModel); + SETTINGS_QML_REGISTER(HarbourColorEditorModel); +} + +#include "BooksSettingsPlugin.moc" diff --git a/app/settings/SystemSettings.qml b/app/settings/SystemSettings.qml new file mode 100644 index 0000000..4fdf882 --- /dev/null +++ b/app/settings/SystemSettings.qml @@ -0,0 +1,49 @@ +/* + Copyright (C) 2022 Jolla Ltd. + Copyright (C) 2022 Slava Monich + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 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 + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import QtQuick 2.0 +import openrepos.books.settings 1.0 + +// In-app settings +BooksSettingsBase { + BooksSettings { id: settings } + colorSchemeModel: BooksColorSchemeModel { + Component.onCompleted: colorScheme = settings.customColorScheme + onColorSchemeChanged: settings.customColorScheme = colorScheme + } + colorEditorModel: HarbourColorEditorModel { + Component.onCompleted: colors = settings.availableColors + onColorsChanged: settings.availableColors = colors + } + onResetColors: colorEditorModel.colors = settings.defaultColors +} diff --git a/app/settings/harbour-books.json b/app/settings/harbour-books.json deleted file mode 100644 index 14f0ed7..0000000 --- a/app/settings/harbour-books.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "translation_catalog" : "harbour-books", - "entries": [ - { - "path": "applications/harbour-books.desktop", - "title": "Books", - "type": "page", - "icon": "harbour-books", - "params": { - "source": "/usr/share/harbour-books/settings/BooksSettings.qml" - } - } - ] -} diff --git a/app/settings/openrepos-books.json b/app/settings/openrepos-books.json new file mode 100644 index 0000000..fe0e4aa --- /dev/null +++ b/app/settings/openrepos-books.json @@ -0,0 +1,14 @@ +{ + "translation_catalog" : "openrepos-books", + "entries": [ + { + "path": "applications/openrepos-books.desktop", + "title": "Books", + "type": "page", + "icon": "openrepos-books", + "params": { + "source": "/usr/share/openrepos-books/settings/SystemSettings.qml" + } + } + ] +} diff --git a/app/settings/qmldir b/app/settings/qmldir new file mode 100644 index 0000000..c5760cb --- /dev/null +++ b/app/settings/qmldir @@ -0,0 +1,2 @@ +module openrepos.books.settings +plugin bookssettings diff --git a/app/settings/settings.pro b/app/settings/settings.pro new file mode 100644 index 0000000..c0fcd8b --- /dev/null +++ b/app/settings/settings.pro @@ -0,0 +1,57 @@ +TEMPLATE = lib +TARGET = bookssettings + +# Directories +TARGETPATH = $$[QT_INSTALL_QML]/openrepos/books/settings +APP_SRC_DIR = ../src +HARBOUR_LIB_DIR = ../../harbour-lib +HARBOUR_LIB_INCLUDE_DIR = $$HARBOUR_LIB_DIR/include +HARBOUR_LIB_SRC_DIR = $$HARBOUR_LIB_DIR/src + +QT += qml +CONFIG += qt plugin link_pkgconfig hide_symbols +PKGCONFIG += mlite5 + +DEFINES += OPENREPOS # It's for openrepos build only +QMAKE_CXXFLAGS += -Wno-unused-parameter +INCLUDEPATH += $${APP_SRC_DIR} $${HARBOUR_LIB_INCLUDE_DIR} + +CONFIG(debug, debug|release) { + DEFINES += HARBOUR_DEBUG=1 +} + +target.path = $$TARGETPATH +INSTALLS += target + +import.files = qmldir +import.path = $$TARGETPATH +INSTALLS += import + +settings_json.files = openrepos-books.json +settings_json.path = /usr/share/jolla-settings/entries/ +INSTALLS += settings_json + +SOURCES += \ + BooksSettingsPlugin.cpp \ + $${APP_SRC_DIR}/BooksColorScheme.cpp \ + $${APP_SRC_DIR}/BooksColorSchemeModel.cpp \ + $${APP_SRC_DIR}/BooksSettingsBase.cpp + +HEADERS += \ + $${APP_SRC_DIR}/BooksColorScheme.h \ + $${APP_SRC_DIR}/BooksColorSchemeModel.h \ + $${APP_SRC_DIR}/BooksSettingsBase.h + +OTHER_FILES += \ + settings/*.json + +# harbour-lib + +HEADERS += \ + $${HARBOUR_LIB_INCLUDE_DIR}/HarbourColorEditorModel.h \ + $${HARBOUR_LIB_INCLUDE_DIR}/HarbourDebug.h \ + $${HARBOUR_LIB_INCLUDE_DIR}/HarbourUtil.h + +SOURCES += \ + $${HARBOUR_LIB_SRC_DIR}/HarbourColorEditorModel.cpp \ + $${HARBOUR_LIB_SRC_DIR}/HarbourUtil.cpp diff --git a/app/src/BooksBook.cpp b/app/src/BooksBook.cpp index db3ea1f..510a04c 100644 --- a/app/src/BooksBook.cpp +++ b/app/src/BooksBook.cpp @@ -98,8 +98,8 @@ BooksBook::CoverPaintContext::CoverPaintContext() } } - setWidth(gMaxScreenSize.width()); - setHeight(gMaxScreenSize.height()); + iWidth = gMaxScreenSize.width(); + iHeight = gMaxScreenSize.height(); } void BooksBook::CoverPaintContext::drawImage(int x, int y, const ZLImageData& image) diff --git a/app/src/BooksBookModel.cpp b/app/src/BooksBookModel.cpp index f548b68..d563216 100644 --- a/app/src/BooksBookModel.cpp +++ b/app/src/BooksBookModel.cpp @@ -112,7 +112,7 @@ BooksBookModel::PagingTask::PagingTask(QThreadPool* aPool, HarbourTask(aPool), iBook(aBook), iTextStyle(aModel->textStyle()), - iPaint(aModel->width(), aModel->height()), + iPaint(aModel->width(), aModel->height(), BooksColorScheme()), iMargins(aModel->margins()), iPageMarksFile(pageMarksFile(aModel)), iHash(aModel->book()->hash()), diff --git a/app/src/BooksColorScheme.cpp b/app/src/BooksColorScheme.cpp new file mode 100644 index 0000000..f70bcf6 --- /dev/null +++ b/app/src/BooksColorScheme.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksColorScheme.h" + +#include "HarbourDebug.h" +#include "HarbourUtil.h" + +#include +#include +#include + +#define MEMBER_VAR(Name) i##Name + +// ========================================================================== +// BooksColorScheme::Private +// ========================================================================== + +class BooksColorScheme::Private +{ +public: + struct Colors { + #define MEMBER_DECL(colorName,ColorName,key,default) \ + QRgb MEMBER_VAR(ColorName); + BOOKS_COLORS(MEMBER_DECL) + #undef MEMBER_DECL + bool isDefault() const; + void invert(); + }; + + static const Colors DEFAULT_COLORS; + static const QString DEFAULT_SCHEME_ID; + + Private(const Colors*); + ~Private(); + + void updateSchemeId(); + + static QString generateSchemeId(const Colors*); + static QString defaultSchemeId() { return generateSchemeId(&DEFAULT_COLORS); } + static void parseRgb(QRgb*, const QString&); + static uint rgb(QRgb); + +public: + QAtomicInt iRef; + Colors iColors; + QString iSchemeId; +}; + +const BooksColorScheme::Private::Colors BooksColorScheme::Private::DEFAULT_COLORS = { + #define DEFAULT_INIT(colorName,ColorName,key,default) default, + BOOKS_COLORS(DEFAULT_INIT) + #undef DEFAULT_INIT +}; +const QString BooksColorScheme::Private::DEFAULT_SCHEME_ID + (BooksColorScheme::Private::defaultSchemeId()); + +BooksColorScheme::Private::Private( + const Colors* aColors) : + iRef(1), + iColors(*aColors) +{ + // Note: leaving iSchemeId empty. Caller must do updateSchemeId() +} + +BooksColorScheme::Private::~Private() +{ +} + +QString +BooksColorScheme::Private::generateSchemeId( + const Colors* aColors) +{ + QCryptographicHash md5(QCryptographicHash::Md5); + #define HASH_COLOR(colorName,ColorName,key,default) \ + md5.addData((const char*)&aColors->MEMBER_VAR(ColorName), sizeof(aColors->MEMBER_VAR(ColorName))); + BOOKS_COLORS(HASH_COLOR) + #undef HASH_COLOR + return QString(QLatin1String(md5.result().toHex())); +} + +inline bool +BooksColorScheme::Private::Colors::isDefault() const +{ + return !memcmp(this, &DEFAULT_COLORS, sizeof(Colors)); +} + +void +BooksColorScheme::Private::Colors::invert() +{ + #define INVERT_COLOR(colorName,ColorName,key,default) \ + MEMBER_VAR(ColorName) = HarbourUtil::invertedRgb(MEMBER_VAR(ColorName)); + BOOKS_COLORS(INVERT_COLOR) + #undef INVERT_COLOR +} + +inline +void +BooksColorScheme::Private::updateSchemeId() +{ + iSchemeId = generateSchemeId(&iColors); +} + +void +BooksColorScheme::Private::parseRgb( + QRgb* aRgb, + const QString& aValue) +{ + const int len = aValue.length(); + if (len > 0 && len <= 8) { + uint rgb = 0; + for (int i = 0; i < len; i++) { + const int c = aValue.at(i).unicode(); + if (isxdigit(c)) { + static const uchar hex[] = { + 0, 1, 2, 3, 4, 5, 6, 7, /* 0x30..0x37 */ + 8, 9, 0, 0, 0, 0, 0, 0, /* 0x3a..0x3f */ + 0,10,11,12,13,14,15, 0, /* 0x40..0x47 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x4a..0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40..0x47 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x5a..0x5f */ + 0,10,11,12,13,14,15, 0, /* 0x60..0x66 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* Make it 64 bytes */ + }; + Q_STATIC_ASSERT(sizeof(hex) == 0x40); + rgb = (rgb << 4) | hex[(c - 0x30) & 0x3f]; + } else { + HDEBUG("Not a valid hex string" << aValue); + return; + } + } + *aRgb = rgb; + } +} + +uint +BooksColorScheme::Private::rgb( + QRgb aRgb) +{ + // Strip off opaque alpha + return (qAlpha(aRgb) == 0xff) ? (aRgb & RGB_MASK) : aRgb; +} + +// ========================================================================== +// BooksColorScheme +// ========================================================================== + +BooksColorScheme::BooksColorScheme() : + iPrivate(Q_NULLPTR) +{ +} + +BooksColorScheme::BooksColorScheme( + const QString& aSpec) : + iPrivate(Q_NULLPTR) +{ + QHash map; + const QStringList parts(aSpec.split(QChar(':'), QString::SkipEmptyParts)); + const int n = parts.count(); + for (int i = 0; i < n; i++) { + const QStringList pair(parts.at(i).split(QChar('='), QString::SkipEmptyParts)); + if (pair.count() == 2) { + map.insert(pair.at(0), pair.at(1)); + } + } + + Private::Colors colors = Private::DEFAULT_COLORS; + #define PARSE_KEY(colorName,ColorName,key,default) \ + Private::parseRgb(&colors.MEMBER_VAR(ColorName), map.value(QStringLiteral(#key))); + BOOKS_COLORS(PARSE_KEY) + #undef PARSE_KEY + + if (!colors.isDefault()) { + (iPrivate = new Private(&colors))->updateSchemeId(); + } +} + +BooksColorScheme::BooksColorScheme( + const BooksColorScheme& aScheme) : + iPrivate(aScheme.iPrivate) +{ + if (iPrivate) { + iPrivate->iRef.ref(); + } +} + +BooksColorScheme::~BooksColorScheme() +{ + if (iPrivate && !iPrivate->iRef.deref()) { + delete iPrivate; + } +} + +const QString +BooksColorScheme::schemeId() const +{ + return iPrivate ? iPrivate->iSchemeId : Private::DEFAULT_SCHEME_ID; +} + +BooksColorScheme& +BooksColorScheme::operator=( + const BooksColorScheme& aScheme) +{ + if (iPrivate != aScheme.iPrivate) { + if (iPrivate && !iPrivate->iRef.deref()) { + delete iPrivate; + } + iPrivate = aScheme.iPrivate; + if (iPrivate) { + iPrivate->iRef.ref(); + } + } + return *this; +} + +bool +BooksColorScheme::equals( + const BooksColorScheme& aScheme) const +{ + if (iPrivate == aScheme.iPrivate) { + return true; + } else if (iPrivate && aScheme.iPrivate) { + #define MEMBER_EQUAL(colorName,ColorName,key,default) \ + iPrivate->iColors.MEMBER_VAR(ColorName) == \ + aScheme.iPrivate->iColors.MEMBER_VAR(ColorName) && + return BOOKS_COLORS(MEMBER_EQUAL) true; + #undef MEMBER_EQUAL + } else { + #define METHOD_EQUAL(colorName,ColorName,key,default) \ + colorName() == aScheme.colorName() && + return BOOKS_COLORS(METHOD_EQUAL) true; + #undef METHOD_EQUAL + } +} + +const QString +BooksColorScheme::toString() const +{ + Private::Colors colors = iPrivate ? iPrivate->iColors : Private::DEFAULT_COLORS; + // QString::asprintf requires Qt 5.5 + return QString().sprintf( + #define COLOR_FORMAT(colorName,ColorName,key,def) #key "=%06x:" + BOOKS_COLORS(COLOR_FORMAT) + #undef COLOR_FORMAT + "%s", + #define COLOR_VALUE(colorName,ColorName,key,def) \ + Private::rgb(colors.MEMBER_VAR(ColorName)), + BOOKS_COLORS(COLOR_VALUE) + #undef COLOR_VALUE + ""); +} + +#define GETTER_IMPL(colorName,ColorName,key,default) \ +QRgb BooksColorScheme::colorName() const { \ + return iPrivate ? iPrivate->iColors.MEMBER_VAR(ColorName) : \ + Private::DEFAULT_COLORS.MEMBER_VAR(ColorName); \ +} +BOOKS_COLORS(GETTER_IMPL) +#undef GETTER_IMPL + +#define SETTER_IMPL(colorName,ColorName,key,default) \ +BooksColorScheme BooksColorScheme::with##ColorName(QRgb aColor) const { \ + if (colorName() == aColor) { return *this; } else { \ + BooksColorScheme scheme; \ + if (iPrivate) { \ + Private::Colors colors(iPrivate->iColors); \ + colors.MEMBER_VAR(ColorName) = aColor; \ + if (!colors.isDefault()) { \ + (scheme.iPrivate = new Private(&colors))->updateSchemeId(); \ + } \ + } else { \ + scheme.iPrivate = new Private(&Private::DEFAULT_COLORS); \ + scheme.iPrivate->iColors.MEMBER_VAR(ColorName) = aColor; \ + scheme.iPrivate->updateSchemeId(); \ + } \ + return scheme; \ + } \ +} +BOOKS_COLORS(SETTER_IMPL) +#undef SETTER_IMPL + +BooksColorScheme +BooksColorScheme::inverted() const +{ + BooksColorScheme scheme; + Private::Colors colors = iPrivate ? iPrivate->iColors : Private::DEFAULT_COLORS; + colors.invert(); + if (!colors.isDefault()) { + (scheme.iPrivate = new Private(&colors))->updateSchemeId(); + } + return scheme; +} + +BooksColorScheme +BooksColorScheme::invertedWithSelectionBackground( + QRgb aColor) const +{ + BooksColorScheme scheme; + Private::Colors colors = iPrivate ? iPrivate->iColors : Private::DEFAULT_COLORS; + colors.invert(); + colors.iSelectionBackground = aColor; + if (!colors.isDefault()) { + (scheme.iPrivate = new Private(&colors))->updateSchemeId(); + } + return scheme; +} + +QString +BooksColorScheme::rgbToString( + QRgb aRgb) +{ + // QString::asprintf requires Qt 5.5 + return QString().sprintf("#%02x%02x%02x", + qRed(aRgb), qGreen(aRgb), qBlue(aRgb)); +} diff --git a/app/src/BooksColorScheme.h b/app/src/BooksColorScheme.h new file mode 100644 index 0000000..5a5dbc1 --- /dev/null +++ b/app/src/BooksColorScheme.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BOOKS_COLOR_SCHEME_H +#define BOOKS_COLOR_SCHEME_H + +#include +#include +#include + +// Let preprocessor magic begin! +// color(colorName,ColorName,key,default) +#define BOOKS_COLORS(color) \ + color(background,Background,bg,0xffffff) \ + color(foreground,Foreground,fg,0x000000) \ + color(selectionBackground,SelectionBackground,sb,0x3c8bff) \ + color(highlightedText,HighlightedText,ht,0x3c8bff) \ + color(internalHyperlink,InternalHyperlink,ih,0x2160b4) \ + color(externalHyperlink,ExternalHyperlink,eh,0x2160b4) + +// Container for colors (thread-safe) +class BooksColorScheme +{ +public: + BooksColorScheme(); + BooksColorScheme(const QString&); + BooksColorScheme(const BooksColorScheme&); + ~BooksColorScheme(); + + BooksColorScheme& operator = (const BooksColorScheme&); + bool operator == (const BooksColorScheme&) const; + bool operator != (const BooksColorScheme&) const; + bool equals(const BooksColorScheme&) const; + + const QString schemeId() const; + const QString toString() const; + + // This generates pairs of method declarations, e.g. + // QRgb background() const; + // BooksColorScheme withBackground(QRgb aColor) const; + #define BOOKS_COLORS_DECL(colorName,ColorName,key,default) \ + QRgb colorName() const; \ + inline QString colorName##Color() const { return rgbToString(colorName()); } \ + BooksColorScheme with##ColorName(QRgb) const Q_REQUIRED_RESULT; + BOOKS_COLORS(BOOKS_COLORS_DECL) + #undef BOOKS_COLORS_DECL + + BooksColorScheme inverted() const Q_REQUIRED_RESULT; + BooksColorScheme invertedWithSelectionBackground(QRgb) const Q_REQUIRED_RESULT; + +private: + static QString rgbToString(QRgb); + +private: + class Private; + Private* iPrivate; +}; + +// Inline methods +inline bool BooksColorScheme::operator == (const BooksColorScheme& aScheme) const + { return equals(aScheme); } +inline bool BooksColorScheme::operator != (const BooksColorScheme& aScheme) const + { return !equals(aScheme); } + +Q_DECLARE_METATYPE(BooksColorScheme) + +#endif // BOOKS_COLOR_SCHEME_H diff --git a/app/src/BooksColorSchemeModel.cpp b/app/src/BooksColorSchemeModel.cpp new file mode 100644 index 0000000..136b287 --- /dev/null +++ b/app/src/BooksColorSchemeModel.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksColorSchemeModel.h" + +#include "HarbourDebug.h" + +#include + +// Model roles +#define MODEL_ROLES_(first,role,last) \ + first(Key,key) \ + role(Label,label) \ + last(Color,color) + +#define MODEL_ROLES(role) \ + MODEL_ROLES_(role,role,role) + +// ========================================================================== +// BooksColorSchemeModel::Private +// ========================================================================== + +class BooksColorSchemeModel::Private +{ +public: + struct ColorDescriptor { + const QString iName; + QString (*iLabel)(); + QRgb (BooksColorScheme::*iGetter)() const; + BooksColorScheme (BooksColorScheme::*iSetter)(QRgb) const; + }; + + enum Role { + #define FIRST(X,x) X##Role = Qt::UserRole, + #define ROLE(X,x) X##Role, + #define LAST(X,x) X##Role + MODEL_ROLES_(FIRST,ROLE,LAST) + #undef FIRST + #undef ROLE + #undef LAST + }; + + static const ColorDescriptor COLORS[]; + + #define COLOR_LABEL(colorName,ColorName,key,default) \ + static QString ColorName##Label(); + BOOKS_COLORS(COLOR_LABEL) + #undef COLOR_LABEL + +public: + BooksColorScheme iColorScheme; +}; + +const BooksColorSchemeModel::Private::ColorDescriptor +BooksColorSchemeModel::Private::COLORS[] = { + #define COLOR_DESCRIPTOR(colorName,ColorName,key,default) \ + { QString(#colorName), &BooksColorSchemeModel::Private::ColorName##Label, \ + &BooksColorScheme::colorName, &BooksColorScheme::with##ColorName }, + BOOKS_COLORS(COLOR_DESCRIPTOR) + #undef COLOR_DESCRIPTOR +}; + +#define COLOR_COUNT ((int)\ + (sizeof(BooksColorSchemeModel::Private::COLORS)/ \ + sizeof(BooksColorSchemeModel::Private::COLORS[0]))) + +// Localized labels + +QString +BooksColorSchemeModel::Private::BackgroundLabel() +{ + //: List item label (description of a color scheme element) + //% "Page background" + return qtTrId("harbour-books-color-page_background"); +} + +QString +BooksColorSchemeModel::Private::ForegroundLabel() +{ + //: List item label (description of a color scheme element) + //% "Regular text" + return qtTrId("harbour-books-color-text"); +} + +QString +BooksColorSchemeModel::Private::SelectionBackgroundLabel() +{ + //: List item label (description of a color scheme element) + //% "Selection background" + return qtTrId("harbour-books-color-selection_background"); +} + +QString +BooksColorSchemeModel::Private::HighlightedTextLabel() +{ + //: List item label (description of a color scheme element) + //% "Highlighted text" + return qtTrId("harbour-books-color-highlighted_text"); +} + +QString +BooksColorSchemeModel::Private::InternalHyperlinkLabel() +{ + //: List item label (description of a color scheme element) + //% "Internal hyperlink" + return qtTrId("harbour-books-color-internal_hyperlink"); +} + +QString +BooksColorSchemeModel::Private::ExternalHyperlinkLabel() +{ + //: List item label (description of a color scheme element) + //% "External hyperlink" + return qtTrId("harbour-books-color-external_hyperlink"); +} + +// ========================================================================== +// BooksColorSchemeModel +// ========================================================================== + +BooksColorSchemeModel::BooksColorSchemeModel( + QObject* aParent) : + QAbstractListModel(aParent), + iPrivate(new Private) +{ +} + +BooksColorSchemeModel::~BooksColorSchemeModel() +{ + delete iPrivate; +} + +BooksColorScheme +BooksColorSchemeModel::colorScheme() const +{ + return iPrivate->iColorScheme; +} + +void +BooksColorSchemeModel::setColorScheme( + BooksColorScheme aScheme) +{ + int i, nchanged = 0; + bool changed[COLOR_COUNT]; + const BooksColorScheme* s1 = &iPrivate->iColorScheme; + const BooksColorScheme* s2 = &aScheme; + + for (i = 0; i < COLOR_COUNT; i++) { + const Private::ColorDescriptor* colorDesc = Private::COLORS + i; + + if ((s1->*(colorDesc->iGetter))() != (s2->*(colorDesc->iGetter))()) { + changed[i] = true; + nchanged++; + } else { + changed[i] = false; + } + } + + if (nchanged) { + HDEBUG(aScheme.toString()); + iPrivate->iColorScheme = aScheme; + const QVector roles(1, Private::ColorRole); + for (i = 0; i < COLOR_COUNT && nchanged > 0; i++) { + if (changed[i]) { + const QModelIndex idx(index(i)); + Q_EMIT dataChanged(idx, idx, roles); + nchanged--; + } + } + Q_EMIT colorSchemeChanged(); + } +} + +Qt::ItemFlags +BooksColorSchemeModel::flags( + const QModelIndex& aIndex) const +{ + return QAbstractListModel::flags(aIndex) | Qt::ItemIsEditable; +} + +QHash +BooksColorSchemeModel::roleNames() const +{ + QHash roles; +#define ROLE(X,x) roles.insert(Private::X##Role, #x); +MODEL_ROLES(ROLE) +#undef ROLE + return roles; +} + +int +BooksColorSchemeModel::rowCount( + const QModelIndex& aParent) const +{ + return COLOR_COUNT; +} + +QVariant +BooksColorSchemeModel::data( + const QModelIndex& aIndex, + int aRole) const +{ + const int row = aIndex.row(); + + if (row >= 0 && row < COLOR_COUNT) { + const Private::ColorDescriptor* colorDesc = Private::COLORS + row; + + switch ((Private::Role)aRole) { + case Private::KeyRole: + return colorDesc->iName; + case Private::LabelRole: + return colorDesc->iLabel(); + case Private::ColorRole: + return QColor(((&iPrivate->iColorScheme)->*(colorDesc->iGetter))()); + } + } + return QVariant(); +} + +bool +BooksColorSchemeModel::setData( + const QModelIndex& aIndex, + const QVariant& aValue, + int aRole) +{ + const int row = aIndex.row(); + + if (row >= 0 && row < COLOR_COUNT) { + QColor newColor; + + switch ((Private::Role)aRole) { + case Private::KeyRole: + case Private::LabelRole: + break; + case Private::ColorRole: + newColor = aValue.value(); + if (newColor.isValid()) { + const QRgb rgb = newColor.rgb(); + const Private::ColorDescriptor* colorDesc = Private::COLORS + row; + const BooksColorScheme* scheme = &iPrivate->iColorScheme; + + if ((scheme->*(colorDesc->iGetter))() != rgb) { + const QVector roles(1, Private::ColorRole); + + HDEBUG(colorDesc->iName << newColor); + iPrivate->iColorScheme = (scheme->*(colorDesc->iSetter))(rgb); + Q_EMIT dataChanged(aIndex, aIndex, roles); + Q_EMIT colorSchemeChanged(); + } + return true; + } + break; + } + } + return false; +} diff --git a/app/src/BooksColorSchemeModel.h b/app/src/BooksColorSchemeModel.h new file mode 100644 index 0000000..f923b68 --- /dev/null +++ b/app/src/BooksColorSchemeModel.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BOOKS_COLOR_SCHEME_MODEL_H +#define BOOKS_COLOR_SCHEME_MODEL_H + +#include "BooksColorScheme.h" + +#include + +// Represents BooksColorScheme as a list model +class BooksColorSchemeModel: public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(BooksColorScheme colorScheme READ colorScheme WRITE setColorScheme NOTIFY colorSchemeChanged) + +public: + explicit BooksColorSchemeModel(QObject* aParent = Q_NULLPTR); + ~BooksColorSchemeModel(); + + BooksColorScheme colorScheme() const; + void setColorScheme(BooksColorScheme); + + // QAbstractItemModel + Qt::ItemFlags flags(const QModelIndex&) const Q_DECL_OVERRIDE; + QHash roleNames() const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex& aParent) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex&, int) const Q_DECL_OVERRIDE; + bool setData(const QModelIndex&, const QVariant&, int) Q_DECL_OVERRIDE; + +Q_SIGNALS: + void colorSchemeChanged(); + +private: + class Private; + Private* iPrivate; +}; + +#endif // BOOKS_COLOR_SCHEME_MODEL_H diff --git a/app/src/BooksDefs.h b/app/src/BooksDefs.h index 581c678..50d3157 100644 --- a/app/src/BooksDefs.h +++ b/app/src/BooksDefs.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2021 Jolla Ltd. - * Copyright (C) 2015-2021 Slava Monich + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -58,13 +58,24 @@ #define BOOKS_QML_PLUGIN "harbour.books" #define BOOKS_QML_PLUGIN_V1 1 #define BOOKS_QML_PLUGIN_V2 0 -#define BOOKS_QML_REGISTER(klass,name) \ + +#define BOOKS_QML_REGISTER_(klass,name) \ qmlRegisterType(BOOKS_QML_PLUGIN, BOOKS_QML_PLUGIN_V1, \ BOOKS_QML_PLUGIN_V2, name) -#define BOOKS_QML_REGISTER_SINGLETON(klass,name) \ +#define BOOKS_QML_REGISTER_UNCREATABLE_(klass,name) \ + qmlRegisterUncreatableType(BOOKS_QML_PLUGIN, BOOKS_QML_PLUGIN_V1, \ + BOOKS_QML_PLUGIN_V2, name, QString()) +#define BOOKS_QML_REGISTER_SINGLETON_(klass,name) \ qmlRegisterSingletonType(BOOKS_QML_PLUGIN, BOOKS_QML_PLUGIN_V1, \ BOOKS_QML_PLUGIN_V2, name, klass::createSingleton) +#define BOOKS_QML_REGISTER(klass) \ + BOOKS_QML_REGISTER_(klass,#klass) +#define BOOKS_QML_REGISTER_UNCREATABLE(klass) \ + BOOKS_QML_REGISTER_UNCREATABLE_(klass,#klass) +#define BOOKS_QML_REGISTER_SINGLETON(klass) \ + BOOKS_QML_REGISTER_SINGLETON_(klass,#klass) + #define BOOKS_STATE_FILE_SUFFIX ".state" #define BOOKS_MARKS_FILE_SUFFIX ".marks" diff --git a/app/src/BooksPageWidget.cpp b/app/src/BooksPageWidget.cpp index 0a18bc3..1cd69c3 100644 --- a/app/src/BooksPageWidget.cpp +++ b/app/src/BooksPageWidget.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2020 Jolla Ltd. - * Copyright (C) 2015-2020 Slava Monich + * Copyright (C) 2015-2021 Jolla Ltd. + * Copyright (C) 2015-2021 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -60,7 +60,9 @@ public: Data(shared_ptr aModel, int aWidth, int aHeight) : iModel(aModel), iPaintContext(aWidth, aHeight) {} - bool paint(QPainter* aPainter); + bool paint(QPainter* aPainter, BooksColorScheme aColors); + inline int width() const { return iPaintContext.width(); } + inline int height() const { return iPaintContext.height(); } public: shared_ptr iView; @@ -68,9 +70,10 @@ public: BooksPaintContext iPaintContext; }; -bool BooksPageWidget::Data::paint(QPainter* aPainter) +bool BooksPageWidget::Data::paint(QPainter* aPainter, BooksColorScheme aColors) { if (!iView.isNull()) { + iPaintContext.iColors = aColors; iPaintContext.beginPaint(aPainter); iView->paint(); iPaintContext.endPaint(); @@ -141,26 +144,28 @@ void BooksPageWidget::ResetTask::performTask() class BooksPageWidget::RenderTask : public HarbourTask { public: RenderTask(QThreadPool* aPool, QThread* aTargetThread, Data::Ptr aData, - int aWidth, int aHeight) : HarbourTask(aPool, aTargetThread), - iData(aData), iWidth(aWidth), iHeight(aHeight) {} + BooksColorScheme aColors) : HarbourTask(aPool, aTargetThread), + iData(aData), iColors(aColors) {} void performTask(); public: Data::Ptr iData; - int iWidth; - int iHeight; + BooksColorScheme iColors; QImage iImage; }; void BooksPageWidget::RenderTask::performTask() { - if (!isCanceled() && !iData.isNull() && !iData->iView.isNull() && - iWidth > 0 && iHeight > 0) { - iImage = QImage(iWidth, iHeight, QImage::Format_ARGB32_Premultiplied); - if (!isCanceled()) { - QPainter painter(&iImage); - iData->paint(&painter); + if (!iData.isNull() && !iData->iView.isNull()) { + const int width = iData->width(); + const int height = iData->height(); + if (width > 0 && height > 0) { + iImage = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + if (!isCanceled()) { + QPainter painter(&iImage); + iData->paint(&painter, iColors); + } } } } @@ -171,32 +176,34 @@ void BooksPageWidget::RenderTask::performTask() class BooksPageWidget::ClearSelectionTask : public HarbourTask { public: - ClearSelectionTask(QThreadPool* aPool, Data::Ptr aData, int aWidth, - int aHeight) : HarbourTask(aPool), - iData(aData), iWidth(aWidth), iHeight(aHeight), iImageUpdated(false) {} + ClearSelectionTask(QThreadPool* aPool, Data::Ptr aData, BooksColorScheme aColors) : + HarbourTask(aPool), iData(aData), iColors(aColors), iImageUpdated(false) {} void performTask(); public: Data::Ptr iData; - int iWidth; - int iHeight; + BooksColorScheme iColors; QImage iImage; bool iImageUpdated; }; void BooksPageWidget::ClearSelectionTask::performTask() { - iData->iView->endSelection(); - if (!isCanceled() && iWidth > 0 && iHeight > 0) { - const ZLTextArea& area = iData->iView->textArea(); - if (!area.selectionIsEmpty()) { - area.clearSelection(); - iImage = QImage(iWidth, iHeight, QImage::Format_ARGB32_Premultiplied); - if (!isCanceled()) { - QPainter painter(&iImage); - iData->paint(&painter); - iImageUpdated = true; + if (!iData.isNull() && !iData->iView.isNull()) { + iData->iView->endSelection(); + const int width = iData->width(); + const int height = iData->height(); + if (!isCanceled() && width > 0 && height > 0) { + const ZLTextArea& area = iData->iView->textArea(); + if (!area.selectionIsEmpty()) { + area.clearSelection(); + iImage = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + if (!isCanceled()) { + QPainter painter(&iImage); + iData->paint(&painter, iColors); + iImageUpdated = true; + } } } } @@ -209,8 +216,8 @@ void BooksPageWidget::ClearSelectionTask::performTask() class BooksPageWidget::StartSelectionTask : public HarbourTask { public: StartSelectionTask(QThreadPool* aPool, Data::Ptr aData, int aX, int aY, - int aWidth, int aHeight) : HarbourTask(aPool), - iData(aData), iX(aX), iY(aY), iWidth(aWidth), iHeight(aHeight), + BooksColorScheme aColors) : HarbourTask(aPool), + iData(aData), iX(aX), iY(aY), iColors(aColors), iSelectionEmpty(true) {} void performTask(); @@ -219,22 +226,25 @@ public: Data::Ptr iData; int iX; int iY; - int iWidth; - int iHeight; + BooksColorScheme iColors; QImage iImage; bool iSelectionEmpty; }; void BooksPageWidget::StartSelectionTask::performTask() { - if (!isCanceled() && iWidth > 0 && iHeight > 0) { - iData->iView->startSelection(iX, iY); - iSelectionEmpty = iData->iView->textArea().selectionIsEmpty(); - if (!isCanceled()) { - iImage = QImage(iWidth, iHeight, QImage::Format_RGB32); + if (!iData.isNull() && !iData->iView.isNull()) { + const int width = iData->width(); + const int height = iData->height(); + if (width > 0 && height > 0) { + iData->iView->startSelection(iX, iY); + iSelectionEmpty = iData->iView->textArea().selectionIsEmpty(); if (!isCanceled()) { - QPainter painter(&iImage); - iData->paint(&painter); + iImage = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + if (!isCanceled()) { + QPainter painter(&iImage); + iData->paint(&painter, iColors); + } } } } @@ -247,8 +257,8 @@ void BooksPageWidget::StartSelectionTask::performTask() class BooksPageWidget::ExtendSelectionTask : public HarbourTask { public: ExtendSelectionTask(QThreadPool* aPool, Data::Ptr aData, int aX, int aY, - int aWidth, int aHeight) : HarbourTask(aPool), - iData(aData), iX(aX), iY(aY), iWidth(aWidth), iHeight(aHeight), + BooksColorScheme aColors) : HarbourTask(aPool), + iData(aData), iX(aX), iY(aY), iColors(aColors), iSelectionChanged(false), iSelectionEmpty(true) {} void performTask(); @@ -257,8 +267,7 @@ public: Data::Ptr iData; int iX; int iY; - int iWidth; - int iHeight; + BooksColorScheme iColors; QImage iImage; bool iSelectionChanged; bool iSelectionEmpty; @@ -266,14 +275,18 @@ public: void BooksPageWidget::ExtendSelectionTask::performTask() { - if (!isCanceled() && iWidth > 0 && iHeight > 0) { - iSelectionChanged = iData->iView->extendSelection(iX, iY); - iSelectionEmpty = iData->iView->textArea().selectionIsEmpty(); - if (iSelectionChanged && !isCanceled()) { - iImage = QImage(iWidth, iHeight, QImage::Format_RGB32); - if (!isCanceled()) { - QPainter painter(&iImage); - iData->paint(&painter); + if (!iData.isNull() && !iData->iView.isNull()) { + const int width = iData->width(); + const int height = iData->height(); + if (width > 0 && height > 0) { + iSelectionChanged = iData->iView->extendSelection(iX, iY); + iSelectionEmpty = iData->iView->textArea().selectionIsEmpty(); + if (iSelectionChanged && !isCanceled()) { + iImage = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + if (!isCanceled()) { + QPainter painter(&iImage); + iData->paint(&painter, iColors); + } } } } @@ -290,7 +303,7 @@ public: shared_ptr aTextModel, shared_ptr aTextStyle, const BooksSettings* aSettings) : HarbourTask(aPool), iTextModel(aTextModel), iTextStyle(aTextStyle), - iInvertColors(aSettings->invertColors()), + iColors(aSettings->colorScheme()), iX(aX), iY(aY), iMaxWidth(aMaxWidth), iMaxHeight(aMaxHeight), iRef(aRef), iLinkText(aLinkText), iPath(aPath) {} ~FootnoteTask(); @@ -305,7 +318,7 @@ public: public: shared_ptr iTextModel; shared_ptr iTextStyle; - bool iInvertColors; + BooksColorScheme iColors; int iX; int iY; int iMaxWidth; @@ -327,7 +340,7 @@ shared_ptr BooksPageWidget::FootnoteTask::baseStyle() const ZLColor BooksPageWidget::FootnoteTask::color(const std::string& aStyle) const { - return BooksPaintContext::realColor(aStyle, iInvertColors); + return BooksPaintContext::realColor(aStyle, iColors); } bool BooksPageWidget::FootnoteTask::isSelectionEnabled() const @@ -340,7 +353,7 @@ void BooksPageWidget::FootnoteTask::performTask() if (!isCanceled()) { // Determine the size of the footnote canvas ZLTextParagraphCursorCache cache; - BooksPaintContext sizeContext(iMaxWidth, iMaxHeight); + BooksPaintContext sizeContext(iMaxWidth, iMaxHeight, iColors); ZLTextAreaController sizeController(sizeContext, *this, &cache); ZLSize size; sizeController.setModel(iTextModel); @@ -351,8 +364,7 @@ void BooksPageWidget::FootnoteTask::performTask() size.myWidth = (size.myWidth + 3) & -4; HDEBUG("footnote size:" << size.myWidth << "x" << size.myHeight); cache.clear(); - BooksPaintContext paintContext(size.myWidth, size.myHeight); - paintContext.setInvertColors(iInvertColors); + BooksPaintContext paintContext(size.myWidth, size.myHeight, iColors); ZLTextAreaController paintController(paintContext, *this, &cache); iImage = QImage(size.myWidth, size.myHeight, QImage::Format_ARGB32_Premultiplied); QPainter painter(&iImage); @@ -510,7 +522,7 @@ BooksPageWidget::BooksPageWidget(QQuickItem* aParent) : iCurrentPage(false), iPage(-1) { - connect(iSettings.data(), SIGNAL(invertColorsChanged()), SLOT(onColorsChanged())); + connect(iSettings.data(), SIGNAL(colorSchemeChanged()), SLOT(onColorsChanged())); setFlag(ItemHasContents, true); iResizeTimer->setSingleShot(true); iResizeTimer->setInterval(0); @@ -753,9 +765,9 @@ void BooksPageWidget::scheduleRepaint() const int h = height(); if (w > 0 && h > 0 && !iData.isNull() && !iData->iView.isNull()) { const shared_ptr view(iData->iView); - view->setInvertColors(iSettings->invertColors()); (iRenderTask = new RenderTask(iTaskQueue->pool(), thread(), - iData, w, h))->submit(this, SLOT(onRenderTaskDone())); + iData, iSettings->colorScheme()))-> + submit(this, SLOT(onRenderTaskDone())); } else { update(); } @@ -876,11 +888,9 @@ void BooksPageWidget::onFootnoteTaskDone() // Footnotes with normal and inverted background need to // have different ids so that the cached image with the wrong // background doesn't show up after we invert the colors - static const QString NORMAL("n"); - static const QString INVERTED("i"); - static const QString FOOTNOTE_ID("footnote/%1#%2?p=%3&t=%4&s=%5x%6"); + static const QString FOOTNOTE_ID("footnote/%1#%2?p=%3&c=%4&s=%5x%6"); QString id = FOOTNOTE_ID.arg(task->iPath, task->iRef). - arg(iPage).arg(task->iInvertColors ? INVERTED : NORMAL). + arg(iPage).arg(task->iColors.schemeId()). arg(task->iImage.width()).arg(task->iImage.height()); QString url = IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id); HDEBUG(url); @@ -958,8 +968,8 @@ void BooksPageWidget::onLongPressTaskDone() } else if (!iData.isNull()) { if (iStartSelectionTask) iStartSelectionTask->release(this); (iStartSelectionTask = new StartSelectionTask(iTaskQueue->pool(), iData, - task->iX, task->iY, width(), height()))-> - submit(this, SLOT(onStartSelectionTaskDone())); + task->iX, task->iY, iSettings->colorScheme()))-> + submit(this, SLOT(onStartSelectionTaskDone())); } task->release(this); @@ -1040,8 +1050,8 @@ void BooksPageWidget::handlePositionChanged(int aX, int aY) } } (task = new ExtendSelectionTask(iTaskQueue->pool(), iData, - aX, aY, width(), height()))-> - submit(this, SLOT(onExtendSelectionTaskDone())); + aX, aY, iSettings->colorScheme()))-> + submit(this, SLOT(onExtendSelectionTaskDone())); iExtendSelectionTasks.append(task); } else { // Finger was moved before we entered selection mode @@ -1058,8 +1068,8 @@ void BooksPageWidget::clearSelection() if (!iData.isNull()) { if (iClearSelectionTask) iClearSelectionTask->release(this); (iClearSelectionTask =new ClearSelectionTask(iTaskQueue->pool(), - iData, width(), height()))-> - submit(this, SLOT(onClearSelectionTaskDone())); + iData, iSettings->colorScheme()))-> + submit(this, SLOT(onClearSelectionTaskDone())); } if (iSelecting) { iSelecting = false; diff --git a/app/src/BooksPaintContext.cpp b/app/src/BooksPaintContext.cpp index 5296c85..99f75c4 100644 --- a/app/src/BooksPaintContext.cpp +++ b/app/src/BooksPaintContext.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2020 Jolla Ltd. - * Copyright (C) 2015-2020 Slava Monich + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -48,14 +48,13 @@ static const std::string HELVETICA = "Helvetica"; BooksPaintContext::BooksPaintContext() : - iPainter(NULL), iWidth(0), iHeight(0), - iSpaceWidth(0), iDescent(0), iInvertColors(false) + iPainter(Q_NULLPTR), iSpaceWidth(0), iDescent(0), iWidth(0), iHeight(0) { } -BooksPaintContext::BooksPaintContext(int aWidth, int aHeight) : - iPainter(NULL), iWidth(aWidth), iHeight(aHeight), - iSpaceWidth(0), iDescent(0), iInvertColors(false) +BooksPaintContext::BooksPaintContext(int aWidth, int aHeight, BooksColorScheme aColors) : + iPainter(Q_NULLPTR), iSpaceWidth(0), iDescent(0), + iWidth(aWidth), iHeight(aHeight), iColors(aColors) { } @@ -71,7 +70,7 @@ void BooksPaintContext::beginPaint(QPainter *aPainter) void BooksPaintContext::endPaint() { - iPainter = NULL; + iPainter = Q_NULLPTR; } void BooksPaintContext::fillFamiliesList(std::vector &families) const @@ -259,23 +258,12 @@ int BooksPaintContext::height() const return iHeight; } -ZLColor BooksPaintContext::realColor(uchar aRed, uchar aGreen, uchar aBlue, uchar aAlpha, - bool aInvertColors) -{ - 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) +ZLColor BooksPaintContext::realColor(const std::string& aStyle, BooksColorScheme aColors) { 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); + unsigned long argb = ZLColor::rgbValue(aColors.foreground()); if (ZLStringUtil::startsWith(aStyle, '#')) { const size_t len = aStyle.length(); @@ -306,15 +294,13 @@ ZLColor BooksPaintContext::realColor(const std::string& aStyle, bool aInvert) } } } else if (aStyle == INTERNAL_HYPERLINK) { - argb = ZLColor::rgbValue(0x2160b4); - } else if (aStyle == EXTERNAL_HYPERLINK) { - argb = ZLColor::rgbValue(0x2160b4); - } else if (aStyle == BOOK_HYPERLINK) { - argb = ZLColor::rgbValue(0x174480); + argb = ZLColor::rgbValue(aColors.internalHyperlink()); + } else if (aStyle == EXTERNAL_HYPERLINK || aStyle == BOOK_HYPERLINK) { + argb = ZLColor::rgbValue(aColors.externalHyperlink()); } else if (aStyle == ZLTextStyle::SELECTION_BACKGROUND) { - argb = ZLColor::rgbValue(0x3c8bff); + argb = ZLColor::rgbValue(aColors.selectionBackground()); } else if (aStyle == ZLTextStyle::HIGHLIGHTED_TEXT) { - argb = ZLColor::rgbValue(0x3c8bff); + argb = ZLColor::rgbValue(aColors.highlightedText()); } - return realColor(ZLColor(argb), aInvert); + return ZLColor(argb); } diff --git a/app/src/BooksPaintContext.h b/app/src/BooksPaintContext.h index 892815e..67f2d97 100644 --- a/app/src/BooksPaintContext.h +++ b/app/src/BooksPaintContext.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2020 Jolla Ltd. - * Copyright (C) 2015-2020 Slava Monich + * Copyright (C) 2015-2021 Jolla Ltd. + * Copyright (C) 2015-2021 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -35,6 +35,7 @@ #define BOOKS_PAINT_CONTEXT_H #include "BooksTypes.h" +#include "BooksColorScheme.h" #include "ZLColor.h" #include "ZLPaintContext.h" @@ -46,73 +47,63 @@ class QPainter; class BooksPaintContext : public ZLPaintContext { -public: - BooksPaintContext(int aWidth, int aHeight); +protected: BooksPaintContext(); + +public: + BooksPaintContext(int aWidth, int aHeight, BooksColorScheme aColors = BooksColorScheme()); ~BooksPaintContext(); - void setWidth(int aWidth); - void setHeight(int aHeight); - void setSize(int aWidth, int aHeight); bool isEmpty() const; QSize size() const; - // ZLPaintContext void beginPaint(QPainter* painter); void endPaint(); - int width() const; - int height() const; + // ZLPaintContext + int width() const Q_DECL_OVERRIDE; + int height() const Q_DECL_OVERRIDE; - void clear(ZLColor color); + void clear(ZLColor color) Q_DECL_OVERRIDE; - void fillFamiliesList(std::vector& families) const; - const std::string realFontFamilyName(std::string& fontFamily) const; + void fillFamiliesList(std::vector& families) const Q_DECL_OVERRIDE; + const std::string realFontFamilyName(std::string& fontFamily) const Q_DECL_OVERRIDE; - void setFont(const std::string& family, int size, bool bold, bool italic); - void setColor(ZLColor color, LineStyle style); - void setFillColor(ZLColor color, FillStyle style); + void setFont(const std::string& family, int size, bool bold, bool italic) Q_DECL_OVERRIDE; + void setColor(ZLColor color, LineStyle style) Q_DECL_OVERRIDE; + void setFillColor(ZLColor color, FillStyle style) Q_DECL_OVERRIDE; - int stringWidth(const char* str, int len, bool rtl) const; - int spaceWidth() const; - int stringHeight() const; - int descent() const; - void drawString(int x, int y, const char* str, int len, bool rtl); + int stringWidth(const char* str, int len, bool rtl) const Q_DECL_OVERRIDE; + int spaceWidth() const Q_DECL_OVERRIDE; + int stringHeight() const Q_DECL_OVERRIDE; + int descent() const Q_DECL_OVERRIDE; + void drawString(int x, int y, const char* str, int len, bool rtl) Q_DECL_OVERRIDE; - void drawImage(int x, int y, const ZLImageData& image); - void drawImage(int x, int y, const ZLImageData& image, int width, int height, ScalingType type); + void drawImage(int x, int y, const ZLImageData& image) Q_DECL_OVERRIDE; + void drawImage(int x, int y, const ZLImageData& image, int width, int height, ScalingType type) Q_DECL_OVERRIDE; - void drawLine(int x0, int y0, int x1, int y1); - void fillRectangle(int x0, int y0, int x1, int y1); - void drawFilledCircle(int x, int y, int r); - - void setInvertColors(bool aInvertColors); + void drawLine(int x0, int y0, int x1, int y1) Q_DECL_OVERRIDE; + void fillRectangle(int x0, int y0, int x1, int y1) Q_DECL_OVERRIDE; + void drawFilledCircle(int x, int y, int r) Q_DECL_OVERRIDE; 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); + static ZLColor realColor(const std::string& aStyle, BooksColorScheme aColors); private: QPainter* iPainter; - int iWidth; - int iHeight; mutable int iSpaceWidth; int iDescent; - bool iInvertColors; QFont iFont; + +protected: + int iWidth; + int iHeight; + +public: + BooksColorScheme iColors; }; -inline void BooksPaintContext::setWidth(int aWidth) - { iWidth = aWidth; } -inline void BooksPaintContext::setHeight(int aHeight) - { iHeight = aHeight; } -inline void BooksPaintContext::setSize(int aWidth, int aHeight) - { iWidth = aWidth; iHeight = aHeight; } inline bool BooksPaintContext::isEmpty() const { return (iWidth <= 0 || iHeight <= 0); } inline QSize BooksPaintContext::size() const @@ -120,15 +111,7 @@ inline QSize BooksPaintContext::size() const inline QColor qtColor(const ZLColor& aColor) { 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, 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, aColor.Alpha, aInvert); } inline ZLColor BooksPaintContext::realColor(const std::string& aStyle) const - { return realColor(aStyle, iInvertColors); } -inline void BooksPaintContext::setInvertColors(bool aInvertColors) - { iInvertColors = aInvertColors; } + { return realColor(aStyle, iColors); } #endif /* BOOKS_PAINT_CONTEXT_H */ diff --git a/app/src/BooksSettings.cpp b/app/src/BooksSettings.cpp index b913bc8..39743d4 100644 --- a/app/src/BooksSettings.cpp +++ b/app/src/BooksSettings.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2021 Jolla Ltd. - * Copyright (C) 2015-2021 Slava Monich + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -44,21 +44,21 @@ #include #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" -#define KEY_CURRENT_BOOK "currentBook" -#define KEY_CURRENT_FOLDER "currentFolder" -#define KEY_REMOVABLE_ROOT "removableRoot" -#define KEY_INVERT_COLORS "invertColors" -#define KEY_KEEP_DISPLAY_ON "keepDisplayOn" -#define KEY_BOOK_PULL_DOWN_MENU "bookPullDownMenu" -#define KEY_VOLUME_UP_ACTION "volumeUpAction" -#define KEY_VOLUME_DOWN_ACTION "volumeDownAction" -#define KEY_ORIENTATION "orientation" +#define DCONF_PATH_(x) BOOKS_DCONF_ROOT x +#define KEY_FONT_SIZE DCONF_PATH_("fontSize") +#define KEY_PAGE_DETAILS DCONF_PATH_("pageDetails") +#define KEY_NIGHT_MODE_BRIGHTNESS DCONF_PATH_("nightModeBrightness") +#define KEY_PAGE_DETAILS_FIXED DCONF_PATH_("pageDetailsFixed") +#define KEY_TURN_PAGE_BY_TAP DCONF_PATH_("turnPageByTap") +#define KEY_SAMPLE_BOOK_COPIED DCONF_PATH_("sampleBookCopied") +#define KEY_CURRENT_BOOK DCONF_PATH_("currentBook") +#define KEY_CURRENT_FOLDER DCONF_PATH_("currentFolder") +#define KEY_REMOVABLE_ROOT DCONF_PATH_("removableRoot") +#define KEY_KEEP_DISPLAY_ON DCONF_PATH_("keepDisplayOn") +#define KEY_BOOK_PULL_DOWN_MENU DCONF_PATH_("bookPullDownMenu") +#define KEY_VOLUME_UP_ACTION DCONF_PATH_("volumeUpAction") +#define KEY_VOLUME_DOWN_ACTION DCONF_PATH_("volumeDownAction") +#define KEY_ORIENTATION DCONF_PATH_("orientation") #define DEFAULT_FONT_SIZE 0 #define DEFAULT_NIGHT_BRIGHTNESS 1.0 @@ -69,15 +69,12 @@ #define DEFAULT_CURRENT_BOOK QString() #define DEFAULT_CURRENT_FOLDER QString() #define DEFAULT_REMOVABLE_ROOT "Books" -#define DEFAULT_INVERT_COLORS false #define DEFAULT_KEEP_DISPLAY_ON false #define DEFAULT_BOOK_PULL_DOWN_MENU true #define DEFAULT_VOLUME_UP_ACTION (BooksSettings::ActionNextPage) #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 @@ -94,27 +91,27 @@ public: iFontSize(iDefaultStyle->fontSize() + 2*aFontSizeModifier) { HDEBUG(iFontSize); } - bool isDecorated() const; + bool isDecorated() const Q_DECL_OVERRIDE; - const std::vector &fontFamilies() const; + const std::vector &fontFamilies() const Q_DECL_OVERRIDE; - int fontSize() const; - bool bold() const; - bool italic() const; + int fontSize() const Q_DECL_OVERRIDE; + bool bold() const Q_DECL_OVERRIDE; + bool italic() const Q_DECL_OVERRIDE; - const std::string &colorStyle() const; + const std::string &colorStyle() const Q_DECL_OVERRIDE; - short spaceBefore(const ZLTextStyleEntry::Metrics& aMetrics) const; - short spaceAfter(const ZLTextStyleEntry::Metrics& aMetrics) const; - short lineStartIndent(const ZLTextStyleEntry::Metrics& aMetrics, bool aRtl) const; - short lineEndIndent(const ZLTextStyleEntry::Metrics& aMetrics, bool aRtl) const; - short firstLineIndentDelta(const ZLTextStyleEntry::Metrics& aMetrics) const; - int verticalShift() const; + short spaceBefore(const ZLTextStyleEntry::Metrics&) const Q_DECL_OVERRIDE; + short spaceAfter(const ZLTextStyleEntry::Metrics&) const Q_DECL_OVERRIDE; + short lineStartIndent(const ZLTextStyleEntry::Metrics&, bool) const Q_DECL_OVERRIDE; + short lineEndIndent(const ZLTextStyleEntry::Metrics&, bool) const Q_DECL_OVERRIDE; + short firstLineIndentDelta(const ZLTextStyleEntry::Metrics&) const Q_DECL_OVERRIDE; + int verticalShift() const Q_DECL_OVERRIDE; - ZLTextAlignmentType alignment() const; + ZLTextAlignmentType alignment() const Q_DECL_OVERRIDE; - double lineSpace() const; - bool allowHyphenations() const; + double lineSpace() const Q_DECL_OVERRIDE; + bool allowHyphenations() const Q_DECL_OVERRIDE; private: shared_ptr iDefaultStyle; @@ -222,28 +219,35 @@ BooksSettings::TextStyle::allowHyphenations() const // BooksSettings::Private // ========================================================================== -class BooksSettings::Private : public QObject { +class BooksSettings::Private : public QObject +{ Q_OBJECT public: - Private(BooksSettings* aParent); + // Matches Silica::Theme::ColorScheme + enum ColorScheme { + LightOnDark, + DarkOnLight + }; - BooksSettings* parentSettings() const; + Private(BooksSettings* aParent); + ~Private(); + + BooksSettings* parentObject() const; bool updateCurrentBook(); bool updateCurrentStorage(); 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); + void setCurrentBook(QObject*); + static Action getAction(MGConfItem*, Action); + static qreal normalizeBrightness(qreal); -private Q_SLOTS: - void onInvertColorsChanged(); +public Q_SLOTS: + void onNightModeChanged(); void onNightModeBrightnessChanged(); void onFontSizeValueChanged(); void onCurrentBookPathChanged(); @@ -256,7 +260,6 @@ public: MGConfItem* iPageDetailsConf; MGConfItem* iPageDetailsFixedConf; MGConfItem* iTurnPageByTapConf; - MGConfItem* iInvertColorsConf; MGConfItem* iSampleBookCopiedConf; MGConfItem* iKeepDisplayOnConf; MGConfItem* iBookPullDownMenuConf; @@ -277,29 +280,28 @@ QWeakPointer BooksSettings::Private::sSharedInstance; BooksSettings::Private::Private(BooksSettings* aParent) : QObject(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)), - iInvertColorsConf(new MGConfItem(DCONF_PATH KEY_INVERT_COLORS, this)), - iSampleBookCopiedConf(new MGConfItem(DCONF_PATH KEY_SAMPLE_BOOK_COPIED, this)), - iKeepDisplayOnConf(new MGConfItem(DCONF_PATH KEY_KEEP_DISPLAY_ON, this)), - iBookPullDownMenuConf(new MGConfItem(DCONF_PATH KEY_BOOK_PULL_DOWN_MENU, this)), - iVolumeUpActionConf(new MGConfItem(DCONF_PATH KEY_VOLUME_UP_ACTION, this)), - iVolumeDownActionConf(new MGConfItem(DCONF_PATH KEY_VOLUME_DOWN_ACTION, this)), - iCurrentFolderConf(new MGConfItem(DCONF_PATH KEY_CURRENT_FOLDER, this)), - iCurrentBookPathConf(new MGConfItem(DCONF_PATH KEY_CURRENT_BOOK, this)), - iOrientationConf(new MGConfItem(DCONF_PATH KEY_ORIENTATION, this)), - iRemovableRootConf(new MGConfItem(DCONF_PATH KEY_REMOVABLE_ROOT, this)), - iCurrentBook(NULL) + iFontSizeConf(new MGConfItem(KEY_FONT_SIZE, this)), + iNightModeBrightnessConf(new MGConfItem(KEY_NIGHT_MODE_BRIGHTNESS, this)), + iPageDetailsConf(new MGConfItem(KEY_PAGE_DETAILS, this)), + iPageDetailsFixedConf(new MGConfItem(KEY_PAGE_DETAILS_FIXED, this)), + iTurnPageByTapConf(new MGConfItem(KEY_TURN_PAGE_BY_TAP, this)), + iSampleBookCopiedConf(new MGConfItem(KEY_SAMPLE_BOOK_COPIED, this)), + iKeepDisplayOnConf(new MGConfItem(KEY_KEEP_DISPLAY_ON, this)), + iBookPullDownMenuConf(new MGConfItem(KEY_BOOK_PULL_DOWN_MENU, this)), + iVolumeUpActionConf(new MGConfItem(KEY_VOLUME_UP_ACTION, this)), + iVolumeDownActionConf(new MGConfItem(KEY_VOLUME_DOWN_ACTION, this)), + iCurrentFolderConf(new MGConfItem(KEY_CURRENT_FOLDER, this)), + iCurrentBookPathConf(new MGConfItem(KEY_CURRENT_BOOK, this)), + iOrientationConf(new MGConfItem(KEY_ORIENTATION, this)), + iRemovableRootConf(new MGConfItem(KEY_REMOVABLE_ROOT, this)), + iCurrentBook(Q_NULLPTR) { iFontSize = fontSizeValue(); iBrightness = brightnessValue(); + connect(aParent, SIGNAL(nightModeChanged()), SLOT(onNightModeChanged())); connect(iFontSizeConf, SIGNAL(valueChanged()), SLOT(onFontSizeValueChanged())); connect(iCurrentFolderConf, SIGNAL(valueChanged()), SLOT(onCurrentFolderChanged())); connect(iCurrentBookPathConf, SIGNAL(valueChanged()), SLOT(onCurrentBookPathChanged())); - 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())); @@ -313,16 +315,14 @@ BooksSettings::Private::Private(BooksSettings* aParent) : connect(iRemovableRootConf, SIGNAL(valueChanged()), aParent, SIGNAL(removableRootChanged())); } -inline BooksSettings* -BooksSettings::Private::parentSettings() const +BooksSettings::Private::~Private() { - return qobject_cast(parent()); } -inline bool -BooksSettings::Private::invertColors() const +inline BooksSettings* +BooksSettings::Private::parentObject() const { - return iInvertColorsConf->value(DEFAULT_INVERT_COLORS).toBool(); + return qobject_cast(parent()); } inline qreal @@ -344,7 +344,7 @@ BooksSettings::Private::nightModeBrightness() const inline qreal BooksSettings::Private::brightnessValue() const { - return invertColors() ? nightModeBrightness() : 1.0; + return parentObject()->nightMode() ? nightModeBrightness() : 1.0; } bool @@ -360,20 +360,19 @@ BooksSettings::Private::updateBrightness() } void -BooksSettings::Private::onInvertColorsChanged() +BooksSettings::Private::onNightModeChanged() { - BooksSettings* settings = parentSettings(); + BooksSettings* settings = parentObject(); if (updateBrightness()) { Q_EMIT settings->brightnessChanged(); } - Q_EMIT settings->invertColorsChanged(); - Q_EMIT settings->pageBackgroundColorChanged(); + Q_EMIT settings->highlightPageToolColorChanged(); } void BooksSettings::Private::onNightModeBrightnessChanged() { - BooksSettings* settings = parentSettings(); + BooksSettings* settings = parentObject(); if (updateBrightness()) { Q_EMIT settings->brightnessChanged(); } @@ -444,10 +443,10 @@ BooksSettings::Private::setCurrentBook( (iCurrentBook = book)->retain(); iCurrentBookPathConf->set(book->path()); } else { - iCurrentBook = NULL; + iCurrentBook = Q_NULLPTR; iCurrentBookPathConf->set(QString()); } - Q_EMIT parentSettings()->currentBookChanged(); + Q_EMIT parentObject()->currentBookChanged(); } } @@ -507,7 +506,7 @@ BooksSettings::Private::onFontSizeValueChanged() for (int i=0; i<=FontSizeSteps; i++) { iTextStyle[i].reset(); } - BooksSettings* settings = parentSettings(); + BooksSettings* settings = parentObject(); Q_EMIT settings->fontSizeChanged(); Q_EMIT settings->textStyleChanged(); } @@ -516,7 +515,7 @@ BooksSettings::Private::onFontSizeValueChanged() void BooksSettings::Private::onCurrentFolderChanged() { - BooksSettings* settings = parentSettings(); + BooksSettings* settings = parentObject(); if (updateCurrentStorage()) { Q_EMIT settings->currentStorageChanged(); } @@ -528,7 +527,7 @@ void BooksSettings::Private::onCurrentBookPathChanged() { if (updateCurrentBook()) { - Q_EMIT parentSettings()->currentBookChanged(); + Q_EMIT parentObject()->currentBookChanged(); } } @@ -554,7 +553,7 @@ BooksSettings::Private::getAction( // ========================================================================== BooksSettings::BooksSettings(QObject* aParent) : - QObject(aParent), + BooksSettingsBase(aParent), iPrivate(new Private(this)) { } @@ -692,20 +691,6 @@ BooksSettings::setTurnPageByTap( iPrivate->iTurnPageByTapConf->set(aValue); } -bool -BooksSettings::invertColors() const -{ - return iPrivate->invertColors(); -} - -void -BooksSettings::setInvertColors( - bool aValue) -{ - HDEBUG(aValue); - iPrivate->iInvertColorsConf->set(aValue); -} - bool BooksSettings::keepDisplayOn() const { @@ -800,7 +785,7 @@ BooksSettings::currentFolder() const void BooksSettings::setCurrentFolder( - QString aValue) + const QString aValue) { HDEBUG(aValue); iPrivate->iCurrentFolderConf->set(aValue); @@ -819,28 +804,6 @@ BooksSettings::setCurrentBook( iPrivate->setCurrentBook(aBook); } -QColor -BooksSettings::primaryPageToolColor() const -{ - return PAGETOOL_COLOR; -} - -QColor -BooksSettings::highlightPageToolColor() const -{ - return iPrivate->invertColors() ? - INVERTED_PAGETOOL_HIGHLIGHT_COLOR : - NORMAL_PAGETOOL_HIGHLIGHT_COLOR; -} - -QColor -BooksSettings::pageBackgroundColor() const -{ - return iPrivate->invertColors() ? - INVERTED_BACKGROUND : - DEFAULT_BACKGROUND; -} - BooksSettings::Orientation BooksSettings::orientation() const { @@ -857,8 +820,23 @@ BooksSettings::orientation() const return DEFAULT_ORIENTATION; } +QColor +BooksSettings::primaryPageToolColor() const +{ + return PAGETOOL_COLOR; +} + +QColor +BooksSettings::highlightPageToolColor() const +{ + return nightMode() ? + INVERTED_PAGETOOL_HIGHLIGHT_COLOR : + NORMAL_PAGETOOL_HIGHLIGHT_COLOR; +} + void -BooksSettings::setCurrentBookPath(QString aPath) +BooksSettings::setCurrentBookPath( + QString aPath) { HDEBUG(aPath); iPrivate->iCurrentBookPathConf->set(aPath); diff --git a/app/src/BooksSettings.h b/app/src/BooksSettings.h index 6bd475f..272334a 100644 --- a/app/src/BooksSettings.h +++ b/app/src/BooksSettings.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2021 Jolla Ltd. - * Copyright (C) 2015-2021 Slava Monich + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -34,13 +34,14 @@ #ifndef BOOKS_SETTINGS_H #define BOOKS_SETTINGS_H -#include "BooksTypes.h" +#include "shared_ptr.h" #include "ZLTextStyle.h" -#include -#include + +#include "BooksSettingsBase.h" + #include -class BooksSettings : public QObject +class BooksSettings : public BooksSettingsBase { Q_OBJECT Q_ENUMS(FontSize) @@ -52,7 +53,6 @@ class BooksSettings : public QObject 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) - Q_PROPERTY(bool invertColors READ invertColors WRITE setInvertColors NOTIFY invertColorsChanged) Q_PROPERTY(bool sampleBookCopied READ sampleBookCopied NOTIFY sampleBookCopiedChanged) Q_PROPERTY(bool keepDisplayOn READ keepDisplayOn WRITE setKeepDisplayOn NOTIFY keepDisplayOnChanged) Q_PROPERTY(bool bookPullDownMenu READ bookPullDownMenu WRITE setBookPullDownMenu NOTIFY bookPullDownMenuChanged) @@ -63,11 +63,9 @@ class BooksSettings : public QObject Q_PROPERTY(QString currentStorage READ currentStorage NOTIFY currentStorageChanged) Q_PROPERTY(QString relativePath READ relativePath NOTIFY relativePathChanged) Q_PROPERTY(QString removableRoot READ removableRoot NOTIFY removableRootChanged) - Q_PROPERTY(QColor primaryPageToolColor READ primaryPageToolColor CONSTANT) - Q_PROPERTY(QColor highlightPageToolColor READ highlightPageToolColor NOTIFY invertColorsChanged) - Q_PROPERTY(QColor invertedPageBackgroundColor READ highlightPageToolColor NOTIFY invertColorsChanged) - Q_PROPERTY(QColor pageBackgroundColor READ pageBackgroundColor NOTIFY pageBackgroundColorChanged) Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged) + Q_PROPERTY(QColor primaryPageToolColor READ primaryPageToolColor CONSTANT) + Q_PROPERTY(QColor highlightPageToolColor READ highlightPageToolColor NOTIFY highlightPageToolColorChanged) class TextStyle; public: @@ -115,9 +113,6 @@ public: bool turnPageByTap() const; void setTurnPageByTap(bool aValue); - bool invertColors() const; // Night mode - void setInvertColors(bool aValue); - bool keepDisplayOn() const; void setKeepDisplayOn(bool aValue); @@ -139,12 +134,11 @@ public: QString relativePath() const; QString removableRoot() const; QString currentFolder() const; - void setCurrentFolder(QString aValue); + void setCurrentFolder(const QString aValue); QString currentStorage() const; QColor primaryPageToolColor() const; QColor highlightPageToolColor() const; - QColor pageBackgroundColor() const; Orientation orientation() const; @@ -154,12 +148,12 @@ public Q_SLOTS: Q_SIGNALS: void fontSizeChanged(); void nightModeBrightnessChanged(); + void highlightPageToolColorChanged(); void brightnessChanged(); void textStyleChanged(); void pageDetailsChanged(); void pageDetailsFixedChanged(); void turnPageByTapChanged(); - void invertColorsChanged(); void sampleBookCopiedChanged(); void keepDisplayOnChanged(); void bookPullDownMenuChanged(); @@ -170,7 +164,6 @@ Q_SIGNALS: void currentStorageChanged(); void relativePathChanged(); void removableRootChanged(); - void pageBackgroundColorChanged(); void orientationChanged(); private: diff --git a/app/src/BooksSettingsBase.cpp b/app/src/BooksSettingsBase.cpp new file mode 100644 index 0000000..e2dbe94 --- /dev/null +++ b/app/src/BooksSettingsBase.cpp @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksSettingsBase.h" +#include "BooksDefs.h" + +#include "HarbourDebug.h" +#include "HarbourUtil.h" + +#include + +#define DCONF_PATH BOOKS_DCONF_ROOT +#define DCONF_PATH_(x) BOOKS_DCONF_ROOT x +#define KEY_NIGHT_MODE DCONF_PATH_("invertColors") +#define KEY_CUSTOM_COLOR_SCHEME DCONF_PATH_("customColorScheme") +#define KEY_USE_CUSTOM_COLOR_SCHEME DCONF_PATH_("useCustomColorScheme") +#define KEY_AVAILABLE_COLORS DCONF_PATH_("availableColors") + +#define DEFAULT_NIGHT_MODE false +#define DEFAULT_USE_CUSTOM_COLOR_SCHEME false + +// ========================================================================== +// BooksSettingsBase::Private +// ========================================================================== + +class BooksSettingsBase::Private : public QObject +{ + Q_OBJECT +public: + // Matches Silica::Theme::ColorScheme + enum ColorScheme { + LightOnDark, + DarkOnLight + }; + + static const char* gDefaultColors[]; + + Private(BooksSettingsBase* aParent); + ~Private(); + + BooksSettingsBase* parentObject() const; + static QStringList defaultColors(); + QStringList availableColors() const; + ColorScheme silicaColorScheme() const; + bool darkOnLight() const; + BooksColorScheme nightModeScheme(const BooksColorScheme); + QString customColorSchemeSpec() const; + bool useCustomColorScheme() const; + void setTheme(QObject*); + void updateColorScheme(); + void updateDarkOnLight(); + void updateDefaultHighlightBackgroundColor(); + bool setCustomColorScheme(const BooksColorScheme); + void emitPendingSignals(); + bool nightMode() const; + +public Q_SLOTS: + void onUseCustomColorSchemeChanged(); + void onThemeHighlightBackgroundColorChanged(); + void onThemeColorSchemeChanged(); + void onNightModeChanged(); + void onCustomColorSchemeChanged(); + void onAvailableColorsChanged(); + +public: + MGConfItem* iNightModeConf; + MGConfItem* iCustomColorSchemeConf; + MGConfItem* iUseCustomColorSchemeConf; + MGConfItem* iAvailableColorsConf; + const QStringList iDefaultColors; + QStringList iAvailableColors; + BooksColorScheme iDefaultColorScheme; + BooksColorScheme iDefaultNightModeColorScheme; + BooksColorScheme iCustomColorScheme; + BooksColorScheme iCustomNightModeColorScheme; + BooksColorScheme iColorScheme; + QObject* iTheme; + bool iHaveSilicaColorScheme; + bool iDarkOnLight; + bool iColorSchemeChangePending; + bool iDarkOnLightChangePending; +}; + +const char* BooksSettingsBase::Private::gDefaultColors[] = { + "#000000", "#2160b4", "#3c8bff", + "#007f7f", "#01823f", "#4fb548", + "#c82246", "#f13c27", "#fedc00", + "#f78628", "#7d499b", "#937782", + "#545454", "#a8a8a8", "#ffffff" +}; + +BooksSettingsBase::Private::Private( + BooksSettingsBase* aParent) : + QObject(aParent), + iNightModeConf(new MGConfItem(KEY_NIGHT_MODE, this)), + iCustomColorSchemeConf(new MGConfItem(KEY_CUSTOM_COLOR_SCHEME, this)), + iUseCustomColorSchemeConf(new MGConfItem(KEY_USE_CUSTOM_COLOR_SCHEME, this)), + iAvailableColorsConf(new MGConfItem(KEY_AVAILABLE_COLORS, this)), + iDefaultColors(defaultColors()), + iTheme(Q_NULLPTR), + iHaveSilicaColorScheme(false), + iDarkOnLight(false), + iColorSchemeChangePending(false), + iDarkOnLightChangePending(false) +{ + iDefaultNightModeColorScheme = nightModeScheme(iDefaultColorScheme); + iCustomColorScheme = BooksColorScheme(customColorSchemeSpec()); + iCustomNightModeColorScheme = nightModeScheme(iCustomColorScheme); + connect(iNightModeConf, SIGNAL(valueChanged()), SLOT(onNightModeChanged())); + connect(iCustomColorSchemeConf, SIGNAL(valueChanged()), SLOT(onCustomColorSchemeChanged())); + connect(iUseCustomColorSchemeConf, SIGNAL(valueChanged()), SLOT(onUseCustomColorSchemeChanged())); + connect(iUseCustomColorSchemeConf, SIGNAL(valueChanged()), SLOT(onUseCustomColorSchemeChanged())); + connect(iAvailableColorsConf, SIGNAL(valueChanged()), SLOT(onAvailableColorsChanged())); + iAvailableColors = availableColors(); + HDEBUG("Custom color scheme" << customColorSchemeSpec() << "=>" << iCustomColorScheme.toString()); +} + +BooksSettingsBase::Private::~Private() +{ + if (iTheme) disconnect(iTheme); +} + +BooksSettingsBase* +BooksSettingsBase::Private::parentObject() const +{ + return qobject_cast(parent()); +} + +QStringList +BooksSettingsBase::Private::defaultColors() +{ + QStringList colors; + const uint n = sizeof(gDefaultColors)/sizeof(gDefaultColors[0]); + colors.reserve(n); + for (uint i = 0; i < n; i++) { + colors.append(QLatin1String(gDefaultColors[i])); + } + return colors; +} + +bool +BooksSettingsBase::Private::nightMode() const +{ + return iNightModeConf->value(DEFAULT_NIGHT_MODE).toBool(); +} + +QString +BooksSettingsBase::Private::customColorSchemeSpec() const +{ + return iCustomColorSchemeConf->value().toString(); +} + +bool +BooksSettingsBase::Private::useCustomColorScheme() const +{ + return iUseCustomColorSchemeConf->value(DEFAULT_USE_CUSTOM_COLOR_SCHEME).toBool(); +} + +void +BooksSettingsBase::Private::setTheme( + QObject* aTheme) +{ + if (iTheme != aTheme) { + if (iTheme) disconnect(iTheme); + iTheme = aTheme; + if (iTheme) { + connect(iTheme, + SIGNAL(highlightBackgroundColorChanged()), + SLOT(onThemeHighlightBackgroundColorChanged())); + iHaveSilicaColorScheme = connect(iTheme, + SIGNAL(colorSchemeChanged()), + SLOT(onThemeColorSchemeChanged())); + } else { + iHaveSilicaColorScheme = false; + } + onThemeColorSchemeChanged(); + Q_EMIT parentObject()->themeChanged(); + } +} + +BooksSettingsBase::Private::ColorScheme +BooksSettingsBase::Private::silicaColorScheme() const +{ + if (iHaveSilicaColorScheme) { + bool ok = false; + int value = iTheme->property("colorScheme").toInt(&ok); + if (ok) { + return (ColorScheme)value; + } + } + return LightOnDark; +} + +bool +BooksSettingsBase::Private::darkOnLight() const +{ + return silicaColorScheme() == DarkOnLight; +} + +void +BooksSettingsBase::Private::updateColorScheme() +{ + BooksColorScheme scheme(useCustomColorScheme() ? + (nightMode() ? iCustomNightModeColorScheme : iCustomColorScheme) : + (nightMode() ? iDefaultNightModeColorScheme : iDefaultColorScheme)); + if (iColorScheme != scheme) { + iColorScheme = scheme; + iColorSchemeChangePending = true; + } +} + +void +BooksSettingsBase::Private::updateDarkOnLight() +{ + const bool currentValue = darkOnLight(); + if (iDarkOnLight != currentValue) { + iDarkOnLight = currentValue; + iDarkOnLightChangePending = true; + HDEBUG("darkOnLight" << (iDarkOnLight ? "yes" : "no")); + } +} + +void +BooksSettingsBase::Private::updateDefaultHighlightBackgroundColor() +{ + if (iTheme) { + const QColor highlightBackgroundColor(iTheme-> + property("highlightBackgroundColor").value()); + HDEBUG(highlightBackgroundColor << silicaColorScheme()); + iDefaultColorScheme = iDefaultColorScheme. + withSelectionBackground(((silicaColorScheme() == LightOnDark) ? + highlightBackgroundColor.lighter() : highlightBackgroundColor).rgb()); + } else { + iDefaultColorScheme = BooksColorScheme(); + } + iDefaultNightModeColorScheme = nightModeScheme(iDefaultColorScheme); + updateColorScheme(); +} + +BooksColorScheme +BooksSettingsBase::Private::nightModeScheme( + const BooksColorScheme aColors) +{ + return aColors.invertedWithSelectionBackground(QColor(aColors. + selectionBackground()).darker().rgb()); +} + +void +BooksSettingsBase::Private::onThemeColorSchemeChanged() +{ + updateDefaultHighlightBackgroundColor(); + updateDarkOnLight(); + emitPendingSignals(); +} + +void +BooksSettingsBase::Private::onThemeHighlightBackgroundColorChanged() +{ + updateDefaultHighlightBackgroundColor(); + emitPendingSignals(); +} + +void +BooksSettingsBase::Private::onUseCustomColorSchemeChanged() +{ + updateColorScheme(); + Q_EMIT parentObject()->useCustomColorSchemeChanged(); + emitPendingSignals(); +} + +void +BooksSettingsBase::Private::onCustomColorSchemeChanged() +{ + const BooksColorScheme scheme(customColorSchemeSpec()); + if (iCustomColorScheme != scheme) { + iCustomColorScheme = scheme; + iCustomNightModeColorScheme = nightModeScheme(iCustomColorScheme); + updateColorScheme(); + emitPendingSignals(); + } +} + +void +BooksSettingsBase::Private::emitPendingSignals() +{ + if (iColorSchemeChangePending || iDarkOnLightChangePending) { + const bool colorSchemeChanged = iColorSchemeChangePending; + const bool darkOnLightChanged = iDarkOnLightChangePending; + BooksSettingsBase* settings = parentObject(); + + iColorSchemeChangePending = false; + iDarkOnLightChangePending = false; + if (colorSchemeChanged) { + Q_EMIT settings->colorSchemeChanged(); + } + if (darkOnLightChanged) { + Q_EMIT settings->darkOnLightChanged(); + } + } +} + +bool +BooksSettingsBase::Private::setCustomColorScheme( + const BooksColorScheme aColors) +{ + if (iCustomColorScheme != aColors) { + iCustomColorScheme = aColors; + iCustomNightModeColorScheme = nightModeScheme(aColors); + iCustomColorSchemeConf->set(aColors.toString()); + updateColorScheme(); + emitPendingSignals(); + return true; + } + return false; +} + +void +BooksSettingsBase::Private::onNightModeChanged() +{ + BooksSettingsBase* settings = parentObject(); + updateColorScheme(); + emitPendingSignals(); + Q_EMIT settings->nightModeChanged(); +} + +QStringList +BooksSettingsBase::Private::availableColors() const +{ + return iAvailableColorsConf->value(iDefaultColors).toStringList(); +} + +void +BooksSettingsBase::Private::onAvailableColorsChanged() +{ + const QStringList newColors(availableColors()); + if (iAvailableColors != newColors) { + iAvailableColors = newColors; + Q_EMIT parentObject()->availableColorsChanged(); + } +} + +// ========================================================================== +// BooksSettingsBase +// ========================================================================== + +BooksSettingsBase::BooksSettingsBase( + QObject* aParent) : + QObject(aParent), + iPrivate(new Private(this)) +{ +} + +BooksSettingsBase::~BooksSettingsBase() +{ + delete iPrivate; +} + +QObject* +BooksSettingsBase::theme() const +{ + return iPrivate->iTheme; +} + +void +BooksSettingsBase::setTheme( + QObject* aTheme) +{ + iPrivate->setTheme(aTheme); +} + +bool +BooksSettingsBase::darkOnLight() const +{ + return iPrivate->iDarkOnLight; +} + +bool +BooksSettingsBase::nightMode() const +{ + return iPrivate->nightMode(); +} + +void +BooksSettingsBase::setNightMode( + bool aValue) +{ + HDEBUG(aValue); + iPrivate->iNightModeConf->set(aValue); +} + +QColor +BooksSettingsBase::pageBackgroundColor() const +{ + return QColor(iPrivate->iColorScheme.background()); +} + +QColor +BooksSettingsBase::invertedPageBackgroundColor() const +{ + return QColor(HarbourUtil::invertedRgb(iPrivate->iColorScheme.background())); +} + +BooksColorScheme +BooksSettingsBase::colorScheme() const +{ + return iPrivate->iColorScheme; +} + +BooksColorScheme +BooksSettingsBase::customColorScheme() const +{ + return iPrivate->iCustomColorScheme; +} + +BooksColorScheme +BooksSettingsBase::customNightModeColorScheme() const +{ + return iPrivate->iCustomNightModeColorScheme; +} + +void +BooksSettingsBase::setCustomColorScheme( + const BooksColorScheme aColors) +{ + if (iPrivate->setCustomColorScheme(aColors)) { + Q_EMIT customColorSchemeChanged(); + } +} + +bool +BooksSettingsBase::useCustomColorScheme() const +{ + return iPrivate->useCustomColorScheme(); +} + +void +BooksSettingsBase::setUseCustomColorScheme( + bool aValue) +{ + HDEBUG(aValue); + iPrivate->iUseCustomColorSchemeConf->set(aValue); +} + +const QStringList +BooksSettingsBase::defaultColors() const +{ + return iPrivate->iDefaultColors; +} + +QStringList +BooksSettingsBase::availableColors() const +{ + return iPrivate->iAvailableColors; +} + +void +BooksSettingsBase::setAvailableColors( + const QStringList aColors) +{ + iPrivate->iAvailableColorsConf->set(aColors); + if (iPrivate->iAvailableColors != aColors) { + Q_EMIT availableColorsChanged(); + } +} + +#include "BooksSettingsBase.moc" diff --git a/app/src/BooksSettingsBase.h b/app/src/BooksSettingsBase.h new file mode 100644 index 0000000..e0693f4 --- /dev/null +++ b/app/src/BooksSettingsBase.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2022 Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BOOKS_SETTINGS_BASE_H +#define BOOKS_SETTINGS_BASE_H + +#include "BooksTypes.h" +#include "BooksColorScheme.h" + +#include +#include +#include + +class BooksSettingsBase : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject* theme READ theme WRITE setTheme NOTIFY themeChanged) + Q_PROPERTY(bool darkOnLight READ darkOnLight NOTIFY darkOnLightChanged) + Q_PROPERTY(bool nightMode READ nightMode WRITE setNightMode NOTIFY nightModeChanged) + Q_PROPERTY(QColor pageBackgroundColor READ pageBackgroundColor NOTIFY colorSchemeChanged) + Q_PROPERTY(QColor invertedPageBackgroundColor READ invertedPageBackgroundColor NOTIFY colorSchemeChanged) + Q_PROPERTY(BooksColorScheme colorScheme READ colorScheme NOTIFY colorSchemeChanged) + Q_PROPERTY(BooksColorScheme customColorScheme READ customColorScheme WRITE setCustomColorScheme NOTIFY customColorSchemeChanged) + Q_PROPERTY(BooksColorScheme customNightModeColorScheme READ customNightModeColorScheme NOTIFY customColorSchemeChanged) + Q_PROPERTY(bool useCustomColorScheme READ useCustomColorScheme WRITE setUseCustomColorScheme NOTIFY useCustomColorSchemeChanged) + Q_PROPERTY(QStringList defaultColors READ defaultColors CONSTANT) + Q_PROPERTY(QStringList availableColors READ availableColors WRITE setAvailableColors NOTIFY availableColorsChanged) + +public: + explicit BooksSettingsBase(QObject* aParent = Q_NULLPTR); + ~BooksSettingsBase(); + + QObject* theme() const; + void setTheme(QObject*); + bool darkOnLight() const; + + bool nightMode() const; + void setNightMode(bool); + + QColor pageBackgroundColor() const; + QColor invertedPageBackgroundColor() const; + BooksColorScheme colorScheme() const; + + BooksColorScheme customColorScheme() const; + BooksColorScheme customNightModeColorScheme() const; + void setCustomColorScheme(const BooksColorScheme); + + bool useCustomColorScheme() const; + void setUseCustomColorScheme(bool aValue); + + const QStringList defaultColors() const; + QStringList availableColors() const; + void setAvailableColors(const QStringList); + +Q_SIGNALS: + void themeChanged(); + void darkOnLightChanged(); + void nightModeChanged(); + void colorSchemeChanged(); + void customColorSchemeChanged(); + void useCustomColorSchemeChanged(); + void availableColorsChanged(); + +private: + class Private; + Private* iPrivate; +}; + +#endif // BOOKS_SETTINGS_BASE_H diff --git a/app/src/BooksTextView.h b/app/src/BooksTextView.h index 8a6cf71..3de9a71 100644 --- a/app/src/BooksTextView.h +++ b/app/src/BooksTextView.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2020 Jolla Ltd. - * Copyright (C) 2015-2020 Slava Monich + * Copyright (C) 2015-2021 Jolla Ltd. + * Copyright (C) 2015-2021 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -57,7 +57,6 @@ public: void startSelection(int aX, int aY); bool extendSelection(int aX, int aY); void endSelection(); - void setInvertColors(bool aInvertColors); void gotoPosition(const BooksPos& aPos); bool nextPage(); void paint(); @@ -88,7 +87,5 @@ private: inline BooksPos BooksTextView::position() const { return BooksPos(textArea().startCursor()); } -inline void BooksTextView::setInvertColors(bool aInvertColors) - { iPaintContext.setInvertColors(aInvertColors); } #endif // BOOKS_TEXT_VIEW_H diff --git a/app/src/BooksTypes.h b/app/src/BooksTypes.h index e29696e..3bbde3c 100644 --- a/app/src/BooksTypes.h +++ b/app/src/BooksTypes.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 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 @@ -34,7 +34,6 @@ #ifndef BOOKS_TYPES_H #define BOOKS_TYPES_H -#include "shared_ptr.h" #include class BooksBook; diff --git a/app/src/ZLibrary.cpp b/app/src/ZLibrary.cpp index 4d248b2..50a70cf 100644 --- a/app/src/ZLibrary.cpp +++ b/app/src/ZLibrary.cpp @@ -98,12 +98,6 @@ void ZLibrary::initLocale() } } -ZLPaintContext* ZLibrary::createContext() -{ - HDEBUG("creating context"); - return new BooksPaintContext(); -} - bool ZLibrary::init(int& aArgc, char** &aArgv) { HDEBUG("initializing"); diff --git a/app/src/main.cpp b/app/src/main.cpp index de8efb5..2e24e8b 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2021 Jolla Ltd. - * Copyright (C) 2015-2021 Slava Monich + * Copyright (C) 2015-2022 Jolla Ltd. + * Copyright (C) 2015-2022 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -36,6 +36,8 @@ #include "BooksShelf.h" #include "BooksBook.h" #include "BooksBookModel.h" +#include "BooksColorScheme.h" +#include "BooksColorSchemeModel.h" #include "BooksCoverModel.h" #include "BooksConfig.h" #include "BooksImageProvider.h" @@ -49,11 +51,12 @@ #include "BooksTaskQueue.h" #include "BooksHints.h" +#include "HarbourColorEditorModel.h" #include "HarbourDisplayBlanking.h" #include "HarbourDebug.h" #include "HarbourMediaPlugin.h" #include "HarbourPolicyPlugin.h" -#include "HarbourTheme.h" +#include "HarbourUtil.h" #include "ZLibrary.h" #include "ZLLanguageUtil.h" @@ -81,22 +84,30 @@ Q_DECL_EXPORT int main(int argc, char **argv) { QGuiApplication* app = SailfishApp::application(argc, argv); + qRegisterMetaType(); - BOOKS_QML_REGISTER(BooksShelf, "Shelf"); - BOOKS_QML_REGISTER(BooksBook, "Book"); - BOOKS_QML_REGISTER(BooksBookModel, "BookModel"); - BOOKS_QML_REGISTER(BooksCoverModel, "CoverModel"); - BOOKS_QML_REGISTER(BooksImportModel, "BooksImportModel"); - BOOKS_QML_REGISTER(BooksPathModel, "BooksPathModel"); - BOOKS_QML_REGISTER(BooksPageStack, "BooksPageStack"); - BOOKS_QML_REGISTER(BooksStorageModel, "BookStorage"); - BOOKS_QML_REGISTER(BooksPageWidget, "PageWidget"); - BOOKS_QML_REGISTER(BooksListWatcher, "ListWatcher"); - BOOKS_QML_REGISTER(BooksCoverWidget, "BookCover"); - BOOKS_QML_REGISTER(BooksSettings, "BooksSettings"); - BOOKS_QML_REGISTER(HarbourDisplayBlanking, "DisplayBlanking"); - BOOKS_QML_REGISTER_SINGLETON(HarbourTheme, "HarbourTheme"); - BOOKS_QML_REGISTER_SINGLETON(BooksHints, "BooksHints"); + qRegisterMetaType(); + + // For historical reasons these QML and C++ names don't match: + BOOKS_QML_REGISTER_(BooksShelf, "Shelf"); + BOOKS_QML_REGISTER_(BooksBook, "Book"); + BOOKS_QML_REGISTER_(BooksBookModel, "BookModel"); + BOOKS_QML_REGISTER_(BooksCoverModel, "CoverModel"); + BOOKS_QML_REGISTER_(BooksStorageModel, "BookStorage"); + BOOKS_QML_REGISTER_(BooksPageWidget, "PageWidget"); + BOOKS_QML_REGISTER_(BooksListWatcher, "ListWatcher"); + BOOKS_QML_REGISTER_(BooksCoverWidget, "BookCover"); + BOOKS_QML_REGISTER_(HarbourDisplayBlanking, "DisplayBlanking"); + + // But these do (and I think it's a good idea) + BOOKS_QML_REGISTER(HarbourColorEditorModel); + BOOKS_QML_REGISTER(BooksColorSchemeModel); + BOOKS_QML_REGISTER(BooksImportModel); + BOOKS_QML_REGISTER(BooksPathModel); + BOOKS_QML_REGISTER(BooksPageStack); + BOOKS_QML_REGISTER_SINGLETON(HarbourUtil); + BOOKS_QML_REGISTER_SINGLETON(BooksHints); + BOOKS_QML_REGISTER_UNCREATABLE(BooksSettings); QLocale locale; QTranslator* translator = new QTranslator(app); diff --git a/app/translations/harbour-books-de.ts b/app/translations/harbour-books-de.ts index befd26d..de3922b 100644 --- a/app/translations/harbour-books-de.ts +++ b/app/translations/harbour-books-de.ts @@ -294,6 +294,21 @@ Text switch description Ohne Schiebemenü muss das Buch durch Hochstreichen geschlossen werden. + + Colors + Section header for colors + Farben + + + Use standard colors + Text switch label + Verwende Standardfarben + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Beachte, dass die vom Buch definierten Farben die Standardfarben überschreiben. + Memory card Section header for memory card settings @@ -307,7 +322,67 @@ Leave the folder name empty to scan the entire memory card for books. Settings field description - Lassen Sie den Verzeichnisnamen leer, um die gesamte Speicherkarte für Bücher zu scannen. + Lasse das Feld Verzeichnisname leer, um die gesamte Speicherkarte für Bücher zu scannen. + + + Page background + List item label (description of a color scheme element) + Seitenhintergrund + + + Regular text + List item label (description of a color scheme element) + Normaler Text + + + Selection background + List item label (description of a color scheme element) + Auswahlhintergrund + + + Highlighted text + List item label (description of a color scheme element) + Hervorgehobener Text + + + Internal hyperlink + List item label (description of a color scheme element) + Interner Link + + + External hyperlink + List item label (description of a color scheme element) + Externer Link + + + Reset colors + Pulley menu item + Farben zurücksetzen + + + Select color + Dialog title label + Wähle Farbe + + + Add color + Dialog title label + Füge Farbe + + + Color + Hue slider label + Farbe + + + Brightness + Brightness slider label + Helligkeit + + + Hex notation + Text field description + Hex-Notation diff --git a/app/translations/harbour-books-es.ts b/app/translations/harbour-books-es.ts index d2435c5..820c572 100644 --- a/app/translations/harbour-books-es.ts +++ b/app/translations/harbour-books-es.ts @@ -294,6 +294,21 @@ Text switch description Sin menú actualizable, el libro debe cerrarse deslizándose hacia arriba. + + Colors + Section header for colors + Colores + + + Use standard colors + Text switch label + Usa colores estándar + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Tenga en cuenta que los colores definidos por el libro prevalecen sobre los colores estándar. + Memory card Section header for memory card settings @@ -309,5 +324,65 @@ Settings field description Salir del nombre de la carpeta vacía para escanear la tarjeta de memoria entera en busca de libros. + + Page background + List item label (description of a color scheme element) + Fondo de la página + + + Regular text + List item label (description of a color scheme element) + Texto normal + + + Selection background + List item label (description of a color scheme element) + Fondo de selección + + + Highlighted text + List item label (description of a color scheme element) + Texto resaltado + + + Internal hyperlink + List item label (description of a color scheme element) + Enlace interno + + + External hyperlink + List item label (description of a color scheme element) + Enlace externo + + + Reset colors + Pulley menu item + Restaurar colores + + + Select color + Dialog title label + Seleccionar el color + + + Add color + Dialog title label + Añadir color + + + Color + Hue slider label + Color + + + Brightness + Brightness slider label + Luminosidad + + + Hex notation + Text field description + Hexadecimal + diff --git a/app/translations/harbour-books-fi.ts b/app/translations/harbour-books-fi.ts index 338b9a1..19fa8d0 100644 --- a/app/translations/harbour-books-fi.ts +++ b/app/translations/harbour-books-fi.ts @@ -282,7 +282,7 @@ Tapping near the left edge of the screen returns to the previous page, tapping near the right edge gets you to the next page. Text switch description - + Napauttamalla lähellä näytön vasenta reunaa palaat edelliselle sivulle, napauttamalla lähellä oikeaa reunaa siirryt seuraavalle sivulle. Show pulley menu when the book is open @@ -294,6 +294,21 @@ Text switch description Ilman vetovalikkoa kirja on suljettava pyyhkäisemällä sitä ylös. + + Colors + Section header for colors + Värit + + + Use standard colors + Text switch label + Käytä vakiovärejä + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Pitää mielessä, että kirjassa määritellyt värit syrjäyttävät vakiovärit. + Memory card Section header for memory card settings @@ -309,5 +324,65 @@ Settings field description Jätä kenttä tyhjäksi käyttää kokonaista muistikorttia. + + Page background + List item label (description of a color scheme element) + Sivun tausta + + + Regular text + List item label (description of a color scheme element) + Tavallinen teksti + + + Selection background + List item label (description of a color scheme element) + Valinta tausta + + + Highlighted text + List item label (description of a color scheme element) + Korostettu teksti + + + Internal hyperlink + List item label (description of a color scheme element) + Sisäinen linkki + + + External hyperlink + List item label (description of a color scheme element) + Ulkoinen linkki + + + Reset colors + Pulley menu item + Palauttaa värit alkutilaan + + + Select color + Dialog title label + Valitse väri + + + Add color + Dialog title label + Lisää väri + + + Color + Hue slider label + Väri + + + Brightness + Brightness slider label + Kirkkaus + + + Hex notation + Text field description + Hex-merkintä + diff --git a/app/translations/harbour-books-hu.ts b/app/translations/harbour-books-hu.ts index 059eb71..a9c0703 100644 --- a/app/translations/harbour-books-hu.ts +++ b/app/translations/harbour-books-hu.ts @@ -292,6 +292,21 @@ Text switch description Lehúzható menü nélkül a könyvet felfelé húzással kell bezárni. + + Colors + Section header for colors + Színek + + + Use standard colors + Text switch label + Használjon szabványos színeket + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Vegye figyelembe, hogy a könyv által meghatározott színek felülírják a szabványos színeket. + Memory card Section header for memory card settings @@ -307,5 +322,65 @@ Settings field description Hagyd üresen a mappanevet a teljes memóriakártya könyvek utáni pásztázásához. + + Page background + List item label (description of a color scheme element) + Oldal háttere + + + Regular text + List item label (description of a color scheme element) + Normál szöveg + + + Selection background + List item label (description of a color scheme element) + Kiválasztás háttér + + + Highlighted text + List item label (description of a color scheme element) + Kiemelt szöveg + + + Internal hyperlink + List item label (description of a color scheme element) + Belső hivatkozás + + + External hyperlink + List item label (description of a color scheme element) + Külső hivatkozás + + + Reset colors + Pulley menu item + Állítsa vissza a színeket + + + Select color + Dialog title label + Válasszon színt + + + Add color + Dialog title label + Add színt + + + Color + Hue slider label + Szín + + + Brightness + Brightness slider label + Fényerősség + + + Hex notation + Text field description + Hex jelölés + diff --git a/app/translations/harbour-books-nl.ts b/app/translations/harbour-books-nl.ts index e3b5e83..861f578 100644 --- a/app/translations/harbour-books-nl.ts +++ b/app/translations/harbour-books-nl.ts @@ -294,6 +294,21 @@ Text switch description Zonder uittrekmenu moet het boek worden gesloten door het omhoog te vegen. + + Colors + Section header for colors + Kleuren + + + Use standard colors + Text switch label + Gebruik standaard kleuren + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Houd er rekening mee dat kleuren die door het boek worden gedefinieerd, de standaardkleuren overschrijven. + Memory card Section header for memory card settings @@ -309,5 +324,65 @@ Settings field description Laat de mapnaam leeg om op de volledige geheugenkaart te zoeken naar boeken. + + Page background + List item label (description of a color scheme element) + Pagina achtergrond + + + Regular text + List item label (description of a color scheme element) + Gewone tekst + + + Selection background + List item label (description of a color scheme element) + Selectie achtergrond + + + Highlighted text + List item label (description of a color scheme element) + Gemarkeerde tekst + + + Internal hyperlink + List item label (description of a color scheme element) + Interne link + + + External hyperlink + List item label (description of a color scheme element) + Externe link + + + Reset colors + Pulley menu item + Kleuren resetten + + + Select color + Dialog title label + Selecteer kleur + + + Add color + Dialog title label + Kleur toevoegen + + + Color + Hue slider label + Kleur + + + Brightness + Brightness slider label + Lichtsterkte + + + Hex notation + Text field description + Hex notatie + diff --git a/app/translations/harbour-books-pl.ts b/app/translations/harbour-books-pl.ts index 52ce2d2..f5c00cb 100644 --- a/app/translations/harbour-books-pl.ts +++ b/app/translations/harbour-books-pl.ts @@ -296,6 +296,21 @@ Text switch description Aby zamknąć książkę w przypadku braku menu wysuwanego, należy ją przesunąć w górę o ponad pół ekranu. + + Colors + Section header for colors + Kolory + + + Use standard colors + Text switch label + Użyj standardowych kolorów + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Należy pamiętać, że niektóre lub nawet wszystkie kolory mogą być określone w samej książce, w którym to przypadku schemat kolorów jest ignorowany. + Memory card Section header for memory card settings @@ -311,5 +326,65 @@ Settings field description Pozostaw nazwę katalogu pustą, aby skanować całą kartę pamięci w poszukiwaniu książek. + + Page background + List item label (description of a color scheme element) + Tło strony + + + Regular text + List item label (description of a color scheme element) + Zwykły tekst + + + Selection background + List item label (description of a color scheme element) + Dedykowane tło + + + Highlighted text + List item label (description of a color scheme element) + Wyróżniony tekst + + + Internal hyperlink + List item label (description of a color scheme element) + Link wewnętrzny + + + External hyperlink + List item label (description of a color scheme element) + Link zewnętrzny + + + Reset colors + Pulley menu item + Zresetuj kolory + + + Select color + Dialog title label + Wybierz kolor + + + Add color + Dialog title label + Dodaj kolor + + + Color + Hue slider label + Kolor + + + Brightness + Brightness slider label + Jasność + + + Hex notation + Text field description + Format szesnastkowy + diff --git a/app/translations/harbour-books-pt.ts b/app/translations/harbour-books-pt.ts index 8f8c211..c0ea7e9 100644 --- a/app/translations/harbour-books-pt.ts +++ b/app/translations/harbour-books-pt.ts @@ -294,6 +294,21 @@ Text switch description Sem o menu deslizante, o livro deve ser fechado deslizando-o para cima. + + Colors + Section header for colors + Cores + + + Use standard colors + Text switch label + Use cores padrão + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Observe que as cores definidas pelo livro substituem as cores padrão. + Memory card Section header for memory card settings @@ -309,5 +324,65 @@ Settings field description Deixe este campo vazio para escanear todo o cartão de memória. + + Page background + List item label (description of a color scheme element) + Plano de fundo da página + + + Regular text + List item label (description of a color scheme element) + Texto normal + + + Selection background + List item label (description of a color scheme element) + Plano de fundo da seleção + + + Highlighted text + List item label (description of a color scheme element) + Texto destacado + + + Internal hyperlink + List item label (description of a color scheme element) + Link interno + + + External hyperlink + List item label (description of a color scheme element) + Link externo + + + Reset colors + Pulley menu item + Repor cores + + + Select color + Dialog title label + Selecione a cor + + + Add color + Dialog title label + Adicione cor + + + Color + Hue slider label + Cor + + + Brightness + Brightness slider label + Luminocidade + + + Hex notation + Text field description + Notação hexadecimal + diff --git a/app/translations/harbour-books-ru.ts b/app/translations/harbour-books-ru.ts index 4eafa7d..8c94845 100644 --- a/app/translations/harbour-books-ru.ts +++ b/app/translations/harbour-books-ru.ts @@ -244,23 +244,13 @@ Prevent the display from blanking while reading the book. Text switch description - Не гасить экран, пока открыта книга. Это не очень хорошо для батареи, зато удобно для чтения. Главное - не уснуть. + То есть не гасить экран, пока открыта книга. Это не очень хорошо для батареи, зато удобно для чтения. Главное - не уснуть. Navigation Section header for media keys Навигация - - Turn pages by tapping the screen - Text switch label - Листать страницы касанием экрана - - - Tapping near the left edge of the screen returns to the previous page, tapping near the right edge gets you to the next page. - Text switch description - Касание ближе к левому краю экрана вызывает переход на предыдущую страницу, ближе к правому краю - на следующую. - No action Combo box value for no action @@ -286,10 +276,15 @@ Combo box label Громкость вниз - - Memory card - Section header for memory card settings - Карта памяти + + Turn pages by tapping the screen + Text switch label + Листать страницы касанием экрана + + + Tapping near the left edge of the screen returns to the previous page, tapping near the right edge gets you to the next page. + Text switch description + Касание ближе к левому краю экрана вызывает переход на предыдущую страницу, ближе к правому краю - на следующую. Show pulley menu when the book is open @@ -301,6 +296,26 @@ Text switch description Чтобы закрыть книгу в отсутствие вытягиваемого меню, её надо будет сдвинуть вверх больше, чем на пол-экрана. + + Colors + Section header for colors + Цвета + + + Use standard colors + Text switch label + Использовать стандартные цвета + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Имейте в виду, что некоторые или даже все цвета могут быть прописаны в самой книге и в этом случае цветовая схема игнорируется. + + + Memory card + Section header for memory card settings + Карта памяти + Books folder Settings field label @@ -311,5 +326,65 @@ Settings field description Если оставить имя папки пустым, то можно будет найти книгу в любой папке на карте памяти. Особого смысла в этой настройке нет, просто так исторически сложилось, что по умолчанию книги искались только в папке Books, а теперь можно вообще где угодно. + + Page background + List item label (description of a color scheme element) + Фон страницы + + + Regular text + List item label (description of a color scheme element) + Обычный текст + + + Selection background + List item label (description of a color scheme element) + Выделенный фон + + + Highlighted text + List item label (description of a color scheme element) + Выделенный текст + + + Internal hyperlink + List item label (description of a color scheme element) + Внутренняя ссылка + + + External hyperlink + List item label (description of a color scheme element) + Внешняя ссылка + + + Reset colors + Pulley menu item + Сбросить цвета + + + Select color + Dialog title label + Выбрать цвет + + + Add color + Dialog title label + Добавить цвет + + + Color + Hue slider label + Цвет + + + Brightness + Brightness slider label + Яркость + + + Hex notation + Text field description + Текстовый формат + diff --git a/app/translations/harbour-books-sv.ts b/app/translations/harbour-books-sv.ts index 5c6d73b..a4e7385 100644 --- a/app/translations/harbour-books-sv.ts +++ b/app/translations/harbour-books-sv.ts @@ -294,6 +294,21 @@ Text switch description Utan toppmeny måste boken stängas genom att svepa uppåt. + + Colors + Section header for colors + Färger + + + Use standard colors + Text switch label + Använd standardfärger + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Notera att färger som definieras av boken åsidosätter standardfärgerna. + Memory card Section header for memory card settings @@ -309,5 +324,65 @@ Settings field description Lämna mappnamnet tomt för att söka igenom hela minneskortet efter böcker. + + Page background + List item label (description of a color scheme element) + Sidans bakgrund + + + Regular text + List item label (description of a color scheme element) + Vanlig text + + + Selection background + List item label (description of a color scheme element) + Urval bakgrund + + + Highlighted text + List item label (description of a color scheme element) + Markerad text + + + Internal hyperlink + List item label (description of a color scheme element) + Intern länk + + + External hyperlink + List item label (description of a color scheme element) + Extern länk + + + Reset colors + Pulley menu item + Återställ färger + + + Select color + Dialog title label + Välj färg + + + Add color + Dialog title label + Lägg till färg + + + Color + Hue slider label + Färg + + + Brightness + Brightness slider label + Ljusstyrka + + + Hex notation + Text field description + Hex notation + diff --git a/app/translations/harbour-books-zh_CN.ts b/app/translations/harbour-books-zh_CN.ts index 680e872..58f2519 100644 --- a/app/translations/harbour-books-zh_CN.ts +++ b/app/translations/harbour-books-zh_CN.ts @@ -293,6 +293,21 @@ Text switch description + + Colors + Section header for colors + 颜色 + + + Use standard colors + Text switch label + 使用标准颜色 + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + 请注意,书籍定义的颜色会覆盖标准颜色。 + Memory card Section header for memory card settings @@ -308,5 +323,65 @@ Settings field description 不填写文件夹名称以扫描SD卡中的全部书籍 + + Page background + List item label (description of a color scheme element) + 页面背景 + + + Regular text + List item label (description of a color scheme element) + 常规文本 + + + Selection background + List item label (description of a color scheme element) + 选拔背景 + + + Highlighted text + List item label (description of a color scheme element) + 突出显示的文本 + + + Internal hyperlink + List item label (description of a color scheme element) + 内部链接 + + + External hyperlink + List item label (description of a color scheme element) + 外部链接 + + + Reset colors + Pulley menu item + 重置颜色 + + + Select color + Dialog title label + 选择颜色 + + + Add color + Dialog title label + 添加颜色 + + + Color + Hue slider label + 颜色 + + + Brightness + Brightness slider label + 亮度 + + + Hex notation + Text field description + 十六进制表示法 + diff --git a/app/translations/harbour-books.ts b/app/translations/harbour-books.ts index 140ed3c..b1564c2 100644 --- a/app/translations/harbour-books.ts +++ b/app/translations/harbour-books.ts @@ -294,6 +294,21 @@ Text switch description Without the pulley menu, the book has to be closed by swiping it up. + + Colors + Section header for colors + Colors + + + Use standard colors + Text switch label + Use standard colors + + + Note that colors hardcoded in the book override the color scheme. + Text switch description + Note that colors hardcoded in the book override the color scheme. + Memory card Section header for memory card settings @@ -309,5 +324,65 @@ Settings field description Leave the folder name empty to scan the entire memory card for books. + + Page background + List item label (description of a color scheme element) + Page background + + + Regular text + List item label (description of a color scheme element) + Regular text + + + Selection background + List item label (description of a color scheme element) + Selection background + + + Highlighted text + List item label (description of a color scheme element) + Highlighted text + + + Internal hyperlink + List item label (description of a color scheme element) + Internal hyperlink + + + External hyperlink + List item label (description of a color scheme element) + External hyperlink + + + Reset colors + Pulley menu item + Reset colors + + + Select color + Dialog title label + Select color + + + Add color + Dialog title label + Add color + + + Color + Hue slider label + Color + + + Brightness + Brightness slider label + Brightness + + + Hex notation + Text field description + Hex notation + diff --git a/harbour-books.pro b/harbour-books.pro index f2e5b7a..5ed5448 100644 --- a/harbour-books.pro +++ b/harbour-books.pro @@ -1,7 +1,12 @@ TEMPLATE = subdirs -CONFIG += ordered +CONFIG += ordered app_settings SUBDIRS = fribidi linebreak fbreader app +app_settings { + SUBDIRS += settings + settings.file = app/settings/settings.pro +} + OTHER_FILES += \ README.md \ rpm/*.spec diff --git a/rpm/openrepos-books.spec b/rpm/openrepos-books.spec index 2d8bbfd..814d62c 100644 --- a/rpm/openrepos-books.spec +++ b/rpm/openrepos-books.spec @@ -42,6 +42,8 @@ FBReader-based e-book reader. rm -rf %{buildroot} cd app %qmake5_install +cd settings +%qmake5_install desktop-file-install --delete-original \ --dir %{buildroot}%{_datadir}/applications \ @@ -60,8 +62,9 @@ if [ "$1" == 0 ] ; then \ %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/*/apps/%{name}.png %{_datadir}/translations/%{name}*.qm +%{_datadir}/dbus-1/services/%{name}.service %{_datadir}/jolla-settings/entries/%{name}.json - %{_datadir}/dbus-1/services/%{name}.service +%{_libdir}/qt5/qml/openrepos/books/settings %check make -C test test