diff --git a/app/qml/BooksBookView.qml b/app/qml/BooksBookView.qml index a050652..71081ab 100644 --- a/app/qml/BooksBookView.qml +++ b/app/qml/BooksBookView.qml @@ -84,6 +84,13 @@ SilicaFlickable { if (footnoteView) footnoteView.hide() } + function bzzz() { + if (!hapticFeedback) { + hapticFeedback = hapticFeedbackComponent.createObject(root) + } + hapticFeedback.play() + } + onOrientationChanged: { if (footnoteView) { footnoteView.cancel() @@ -94,10 +101,7 @@ SilicaFlickable { onSelectingChanged: { if (selecting) { - if (!hapticFeedback) { - hapticFeedback = hapticFeedbackComponent.createObject(root) - } - hapticFeedback.play() + bzzz() } else if (!selectionEmpty) { notification.publish() } @@ -105,21 +109,25 @@ SilicaFlickable { Component { id: linkMenuComponent + BooksLinkMenu { } } Component { id: imageViewComponent + BooksImageView { } } Component { id: footnoteViewComponent + BooksFootnoteView { } } Component { id: hapticFeedbackComponent + ThemeEffect { effect: ThemeEffect.Press } } @@ -127,27 +135,32 @@ SilicaFlickable { MenuItem { //% "Back to library" text: qsTrId("harbour-books-book-view-back") + onClicked: root.closeBook() } } BookModel { id: bookModel + book: root.book ? root.book : null size: bookViewWatcher.size leftMargin: Theme.horizontalPageMargin rightMargin: Theme.horizontalPageMargin topMargin: Theme.itemSizeSmall bottomMargin: Theme.itemSizeSmall + onJumpToPage: bookView.jumpTo(page) } Notification { id: notification + //: Pop-up notification //% "Copied to clipboard" previewBody: qsTrId("harbour-books-book-view-copied_to_clipboard") expireTimeout: 2000 + Component.onCompleted: { if ("icon" in notification) { notification.icon = "icon-s-clipboard" @@ -157,6 +170,7 @@ SilicaFlickable { SilicaListView { id: bookView + model: bookModel anchors.fill: parent flickDeceleration: maximumFlickVelocity @@ -167,12 +181,14 @@ SilicaFlickable { opacity: loading ? 0 : 1 visible: opacity > 0 interactive: root.interactive + readonly property real maxContentX: Math.max(0, contentWidth - width) readonly property int currentPage: stackModel.currentPage property bool completed Component.onCompleted: { bookViewWatcher.positionViewAtIndex(currentPage) + pager.setPage(currentPage) completed = true } @@ -180,6 +196,7 @@ SilicaFlickable { if (completed && !moving && !scrollAnimation.running) { bookViewWatcher.positionViewAtIndex(currentPage) } + pager.setPage(currentPage) } onCurrentIndexChanged: { @@ -189,17 +206,19 @@ SilicaFlickable { } onMovingChanged: { - if (!moving) { + if (!moving && currentIndex >= 0) { updateModel() } } delegate: BooksPageView { id: pageView + width: bookView.width height: bookView.height - model: bookModel - page: index + bookModel: bookView.model + page: model.pageIndex + bookPos: model.bookPos leftMargin: bookModel.leftMargin rightMargin: bookModel.rightMargin topMargin: bookModel.topMargin @@ -210,6 +229,7 @@ SilicaFlickable { pageNumberVisible: _currentState.page currentPage: ListView.isCurrentItem title: bookModel.title + onJumpToPage: bookView.jumpTo(page) onPushPosition: stackModel.pushPosition(position) // bookView.jumpTo(page) onPageClicked: { @@ -248,17 +268,11 @@ SilicaFlickable { } } - property int jumpingTo: -1 function jumpTo(page) { - if (book && page >=0 && page !== currentIndex) { - jumpingTo = page + if (book && page >=0) { + console.log("showing page", page) bookViewWatcher.positionViewAtIndex(page) - pager.currentPage = page - jumpingTo = -1 - if (currentIndex !== page) { - console.log("oops, still at", currentPage) - resetPager.restart() - } + stackModel.currentPage = page } } @@ -282,19 +296,18 @@ SilicaFlickable { function updateModel() { hideViews() - stackModel.currentPage = currentIndex - if (!pager.pressed) { - pager.currentPage = currentIndex - } + stackModel.currentPage = bookViewWatcher.currentIndex } ListWatcher { id: bookViewWatcher + listView: bookView } NumberAnimation { id: scrollAnimation + target: bookView property: "contentX" duration: 500 @@ -303,17 +316,9 @@ SilicaFlickable { Behavior on opacity { FadeAnimation {} } - Timer { - id: resetPager - interval: 0 - onTriggered: { - console.log("resetting pager to", bookView.currentIndex) - pager.currentPage = bookView.currentIndex - } - } - BooksPageTools { id: pageTools + anchors { top: parent.top left: parent.left @@ -323,13 +328,16 @@ SilicaFlickable { rightMargin: bookModel.rightMargin opacity: _currentState.tools ? 1 : 0 visible: opacity > 0 && book && bookModel.pageCount && !loading - Behavior on opacity { FadeAnimation {} } + onIncreaseFontSize: bookModel.increaseFontSize() onDecreaseFontSize: bookModel.decreaseFontSize() + + Behavior on opacity { FadeAnimation {} } } BooksPager { id: pager + anchors { left: parent.left right: parent.right @@ -341,15 +349,19 @@ SilicaFlickable { stack: stackModel pageCount: bookModel.pageCount width: parent.width - opacity: (_currentState.pager && book && bookModel.pageCount) ? 0.75 : 0 + opacity: (_currentState.pager && pageCount) ? 0.75 : 0 visible: opacity > 0 + onPageChanged: bookView.jumpTo(page) + onFeedback: bzzz() + Behavior on opacity { FadeAnimation {} } } } BooksTitleLabel { id: titleLabel + anchors { top: parent.top left: parent.left @@ -365,6 +377,7 @@ SilicaFlickable { BusyIndicator { id: busyIndicator + anchors.centerIn: parent size: BusyIndicatorSize.Large running: loading @@ -384,10 +397,12 @@ SilicaFlickable { bottom: parent.bottom horizontalCenter: parent.horizontalCenter } - onClicked: root.closeBook() enabled: loading && bookModel.resetReason === BookModel.ReasonLoading visible: opacity > 0 opacity: enabled ? 1.0 : 0.0 + + onClicked: root.closeBook() + Behavior on opacity { FadeAnimation { } } } @@ -402,7 +417,6 @@ SilicaFlickable { color: Theme.highlightColor opacity: loading ? 1 : 0 visible: opacity > 0 - Behavior on opacity { FadeAnimation {} } text: bookModel ? (bookModel.resetReason == BookModel.ReasonLoading ? //% "Loading..." qsTrId("harbour-books-book-view-loading") : @@ -414,10 +428,11 @@ SilicaFlickable { qsTrId("harbour-books-book-view-applying_smaller_fonts") : //% "Formatting..." qsTrId("harbour-books-book-view-formatting")) : "" + + Behavior on opacity { FadeAnimation {} } } - function performAction(action) - { + function performAction(action) { switch (action) { case BooksSettings.ActionPreviousPage: bookView.prevPage() @@ -431,8 +446,10 @@ SilicaFlickable { MediaKey { enabled: viewActive && haveVolumeUpAction key: Qt.Key_VolumeUp + onPressed: volumeUpAction() onRepeat: volumeUpAction() + function volumeUpAction() { performAction(Settings.volumeUpAction) } @@ -441,8 +458,10 @@ SilicaFlickable { MediaKey { enabled: viewActive && haveVolumeDownAction key: Qt.Key_VolumeDown + onPressed: volumeDownAction() onRepeat: volumeDownAction() + function volumeDownAction() { performAction(Settings.volumeDownAction) } @@ -455,6 +474,7 @@ SilicaFlickable { Resource { id: volumeKeysResource + type: Resource.ScaleButton optional: true } diff --git a/app/qml/BooksPageView.qml b/app/qml/BooksPageView.qml index 801ebbf..6ca844a 100644 --- a/app/qml/BooksPageView.qml +++ b/app/qml/BooksPageView.qml @@ -42,8 +42,9 @@ Rectangle { color: Settings.pageBackgroundColor - property alias model: widget.model property alias page: widget.page + property alias bookPos: widget.bookPos + property alias bookModel: widget.model property alias leftMargin: widget.leftMargin property alias rightMargin: widget.rightMargin property alias topMargin: widget.topMargin diff --git a/app/qml/BooksPager.qml b/app/qml/BooksPager.qml index dbff847..5608724 100644 --- a/app/qml/BooksPager.qml +++ b/app/qml/BooksPager.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2017 Jolla Ltd. - Contact: Slava Monich + Copyright (C) 2015-2020 Jolla Ltd. + Copyright (C) 2015-2020 Slava Monich You may use this file under the terms of BSD license as follows: @@ -8,14 +8,15 @@ modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Jolla Ltd nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + 3. Neither the names of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -36,6 +37,7 @@ import harbour.books 1.0 Item { id: root + height: slider.height property var stack @@ -45,10 +47,24 @@ Item { readonly property bool canGoForward: haveHistory && (stack.currentIndex < (stack.count - 1)) property real leftMargin: Theme.horizontalPageMargin property real rightMargin: Theme.horizontalPageMargin - property alias currentPage: slider.value property alias pressed: slider.pressed + property bool _externalChange signal pageChanged(var page) + signal feedback() + + function clearStack() { + if (haveHistory) { + stack.clear() + feedback() + } + } + + function setPage(page) { + _externalChange = true + slider.value = page + _externalChange = false + } states: [ State { @@ -71,23 +87,25 @@ Item { MouseArea { id: navigateBackArea + property bool down: pressed && containsMouse width: navigateBack.width + root.leftMargin height: navigateBack.height + visible: navigateBack.visible anchors { left: parent.left verticalCenter: parent.verticalCenter } onClicked: stack.back() - onPressAndHold: stack.clear() + onPressAndHold: clearStack() } IconButton { id: navigateBack + icon.source: "image://theme/icon-m-left?" + Settings.primaryPageToolColor opacity: canGoBack ? 1 : 0 visible: opacity > 0 - Behavior on opacity { FadeAnimation {} } down: navigateBackArea.down || (pressed && containsMouse) anchors { left: parent.left @@ -95,56 +113,58 @@ Item { verticalCenter: parent.verticalCenter } onClicked: stack.back() - onPressAndHold: stack.clear() + onPressAndHold: clearStack() + Behavior on opacity { FadeAnimation {} } } BooksPageSlider { id: slider - anchors { - bottom: parent.bottom - } + + anchors.bottom: parent.bottom width: parent.width - 2*x stepSize: 1 minimumValue: 0 maximumValue: pageCount > 0 ? pageCount - 1 : 0 - valueText: "" - label: "" leftMargin: Theme.horizontalPageMargin rightMargin: Theme.horizontalPageMargin primaryColor: Settings.primaryPageToolColor secondaryColor: Settings.primaryPageToolColor highlightColor: Settings.highlightPageToolColor secondaryHighlightColor: Settings.highlightPageToolColor - onSliderValueChanged: root.pageChanged(value) + onMaximumValueChanged: _updateHighlightToValue() + onSliderValueChanged: if (!_externalChange) pageChanged(value) Behavior on x { SmoothedAnimation { duration: 250 } } } MouseArea { id: navigateForwardArea + property bool down: pressed && containsMouse width: navigateForward.width + root.rightMargin height: navigateForward.height + visible: navigateForward.visible anchors { right: parent.right verticalCenter: parent.verticalCenter } onClicked: stack.forward() - onPressAndHold: stack.clear() + onPressAndHold: clearStack() } IconButton { id: navigateForward + icon.source: "image://theme/icon-m-right?" + Settings.primaryPageToolColor down: navigateForwardArea.down || (pressed && containsMouse) opacity: canGoForward ? 1 : 0 visible: opacity > 0 - Behavior on opacity { FadeAnimation {} } anchors { right: parent.right rightMargin: root.rightMargin verticalCenter: parent.verticalCenter } onClicked: stack.forward() - onPressAndHold: stack.clear() + onPressAndHold: clearStack() + Behavior on opacity { FadeAnimation {} } } } diff --git a/app/qml/BooksStorageView.qml b/app/qml/BooksStorageView.qml index 1ebf842..7ac1891 100644 --- a/app/qml/BooksStorageView.qml +++ b/app/qml/BooksStorageView.qml @@ -1,6 +1,6 @@ /* - Copyright (C) 2015-2019 Jolla Ltd. - Copyright (C) 2015-2019 Slava Monich + Copyright (C) 2015-2020 Jolla Ltd. + Copyright (C) 2015-2020 Slava Monich You may use this file under the terms of BSD license as follows: @@ -172,6 +172,7 @@ SilicaFlickable { flickDeceleration: maximumFlickVelocity orientation: ListView.Horizontal snapMode: ListView.SnapOneItem + highlightRangeMode: ListView.StrictlyEnforceRange spacing: Theme.paddingMedium interactive: !dragInProgress && !dragScrollAnimation.running diff --git a/app/src/BooksBookModel.cpp b/app/src/BooksBookModel.cpp index 1a5adee..d7e5dee 100644 --- a/app/src/BooksBookModel.cpp +++ b/app/src/BooksBookModel.cpp @@ -299,7 +299,8 @@ void BooksBookModel::PagingTask::performTask() // ========================================================================== enum BooksBookModelRole { - BooksBookModelPageIndex = Qt::UserRole + BooksBookModelPageIndex = Qt::UserRole, + BooksBookModelBookPos }; BooksBookModel::BooksBookModel(QObject* aParent) : @@ -528,11 +529,23 @@ void BooksBookModel::setBottomMargin(int aMargin) } } +void BooksBookModel::emitBookPosChanged() +{ + const int n = pageCount(); + if (n > 0) { + const QModelIndex topLeft(index(0)); + const QModelIndex bottomRight(index(n - 1)); + const QVector roles(1, BooksBookModelBookPos); + Q_EMIT dataChanged(topLeft, bottomRight, roles); + } +} + void BooksBookModel::updateModel(int aPrevPageCount) { const int newPageCount = pageCount(); if (aPrevPageCount != newPageCount) { HDEBUG(aPrevPageCount << "->" << newPageCount); + emitBookPosChanged(); if (newPageCount > aPrevPageCount) { beginInsertRows(QModelIndex(), aPrevPageCount, newPageCount-1); endInsertRows(); @@ -695,6 +708,7 @@ QHash BooksBookModel::roleNames() const { QHash roles; roles.insert(BooksBookModelPageIndex, "pageIndex"); + roles.insert(BooksBookModelBookPos, "bookPos"); return roles; } @@ -705,10 +719,13 @@ int BooksBookModel::rowCount(const QModelIndex&) const QVariant BooksBookModel::data(const QModelIndex& aIndex, int aRole) const { - const int i = aIndex.row(); - if (i >= 0 && i < pageCount()) { - switch (aRole) { - case BooksBookModelPageIndex: return i; + const int row = aIndex.row(); + if (row >= 0 && row < pageCount()) { + switch ((BooksBookModelRole)aRole) { + case BooksBookModelPageIndex: + return row; + case BooksBookModelBookPos: + return QVariant::fromValue(iData->iPageMarks.at(row)); } } return QVariant(); diff --git a/app/src/BooksBookModel.h b/app/src/BooksBookModel.h index 429d17a..d37b10b 100644 --- a/app/src/BooksBookModel.h +++ b/app/src/BooksBookModel.h @@ -124,14 +124,15 @@ public: int fontSizeAdjust() const; // QAbstractListModel - virtual QHash roleNames() const; - virtual int rowCount(const QModelIndex& aParent) const; - virtual QVariant data(const QModelIndex& aIndex, int aRole) const; + virtual QHash roleNames() const Q_DECL_OVERRIDE; + virtual int rowCount(const QModelIndex& aParent) const Q_DECL_OVERRIDE; + virtual QVariant data(const QModelIndex& aIndex, int aRole) const Q_DECL_OVERRIDE; private: void updateSize(); void updateModel(int aPrevPageCount); void startReset(ResetReason aReason = ReasonUnknown, bool aFull = true); + void emitBookPosChanged(); private Q_SLOTS: void onResetProgress(int aProgress); @@ -141,11 +142,11 @@ private Q_SLOTS: void onHashChanged(); Q_SIGNALS: + void loadingChanged() Q_DECL_OVERRIDE; void sizeChanged(); void bookChanged(); void bookModelChanged(); void titleChanged(); - void loadingChanged(); void pageCountChanged(); void pageMarksChanged(); void progressChanged(); diff --git a/app/src/BooksListWatcher.cpp b/app/src/BooksListWatcher.cpp index 67313ea..8b65e44 100644 --- a/app/src/BooksListWatcher.cpp +++ b/app/src/BooksListWatcher.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2017 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -27,7 +27,7 @@ * 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 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ``USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -49,7 +49,7 @@ BooksListWatcher::BooksListWatcher(QObject* aParent) : iContentY(0), iListView(NULL), iCenterMode(-1), - iPositionIsChanging(false), + iPositionIsChanging(0), iResizeTimer(new QTimer(this)) { iResizeTimer->setSingleShot(true); @@ -121,6 +121,7 @@ void BooksListWatcher::positionViewAtIndex(int aIndex) if (iListView) { HDEBUG(aIndex); doPositionViewAtIndex(aIndex); + updateCurrentIndex(); } } @@ -146,21 +147,15 @@ void BooksListWatcher::doPositionViewAtIndex(int aIndex) iCenterMode = 1; } } - iPositionIsChanging = true; + iPositionIsChanging++; positionViewAtIndex(aIndex, iCenterMode); - // This is probably a bug in QQuickListView - it first calculates - // the item position and then starts instantiating the delegates. - // If there are no delegates yet, then the average item size is zero - // and the resulting item position will always turn out to be zero. - // So if we are trying to position the list at a non-zero index and - // instead we got positioned at zero, try it again. - if (aIndex > 0 && getCurrentIndex() == 0) { + const int currentIndex = getCurrentIndex(); + if (currentIndex != aIndex) { // Didn't work from the first try, give it another go - HDEBUG("retrying..."); + HDEBUG("still" << currentIndex << ", retrying..."); positionViewAtIndex(aIndex, iCenterMode); } - iPositionIsChanging = false; - updateCurrentIndex(); + iPositionIsChanging--; } void BooksListWatcher::positionViewAtIndex(int aIndex, int aMode) @@ -208,10 +203,12 @@ int BooksListWatcher::getCurrentIndex() void BooksListWatcher::tryToRestoreCurrentIndex() { HASSERT(!iPositionIsChanging); - const int index = getCurrentIndex(); - if (iCurrentIndex != index) { - if (iCurrentIndex >= 0) { + if (iCurrentIndex >= 0 && !iPositionIsChanging) { + const int index = getCurrentIndex(); + if (iCurrentIndex != index) { + HDEBUG(index << "->" << iCurrentIndex); doPositionViewAtIndex(iCurrentIndex); + HDEBUG(getCurrentIndex()); } } } @@ -219,9 +216,9 @@ void BooksListWatcher::tryToRestoreCurrentIndex() void BooksListWatcher::updateCurrentIndex() { HASSERT(!iPositionIsChanging); - if (contentWidth() > 0 || contentHeight() > 0) { + if (!iPositionIsChanging && (contentWidth() > 0 || contentHeight() > 0)) { const int index = getCurrentIndex(); - if (iCurrentIndex != index) { + if (iCurrentIndex != index && index >= 0) { iCurrentIndex = index; HDEBUG(index << contentWidth() << "x" << contentHeight()); Q_EMIT currentIndexChanged(); @@ -234,7 +231,7 @@ void BooksListWatcher::updateCurrentIndex() void BooksListWatcher::updateSize() { const QSize size(iListView->width(), iListView->height()); - HDEBUG(size); + HDEBUG(size << getCurrentIndex()); if (iSize != size) { const QSize oldSize(iSize); iSize = size; @@ -282,7 +279,7 @@ void BooksListWatcher::onContentXChanged() { HASSERT(sender() == iListView); iContentX = contentX(); - if (!iPositionIsChanging) { + if (!iPositionIsChanging && !iResizeTimer->isActive()) { updateCurrentIndex(); } } @@ -291,7 +288,7 @@ void BooksListWatcher::onContentYChanged() { HASSERT(sender() == iListView); iContentY = contentY(); - if (!iPositionIsChanging) { + if (!iPositionIsChanging && !iResizeTimer->isActive()) { updateCurrentIndex(); } } @@ -299,7 +296,7 @@ void BooksListWatcher::onContentYChanged() void BooksListWatcher::onContentSizeChanged() { HASSERT(sender() == iListView); - if (!iPositionIsChanging) { + if (!iPositionIsChanging && !iResizeTimer->isActive()) { tryToRestoreCurrentIndex(); updateCurrentIndex(); } diff --git a/app/src/BooksListWatcher.h b/app/src/BooksListWatcher.h index 9e96239..e4ed8ae 100644 --- a/app/src/BooksListWatcher.h +++ b/app/src/BooksListWatcher.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015-2017 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2015-2020 Jolla Ltd. + * Copyright (C) 2015-2020 Slava Monich * * You may use this file under the terms of the BSD license as follows: * @@ -8,15 +8,15 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Jolla Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -96,7 +96,7 @@ private: qreal iContentY; QQuickItem* iListView; int iCenterMode; - bool iPositionIsChanging; + int iPositionIsChanging; QTimer* iResizeTimer; }; diff --git a/app/src/BooksPageWidget.cpp b/app/src/BooksPageWidget.cpp index 2aca7e5..1c035c5 100644 --- a/app/src/BooksPageWidget.cpp +++ b/app/src/BooksPageWidget.cpp @@ -546,7 +546,7 @@ void BooksPageWidget::setPressed(bool aPressed) if (iPressed != aPressed) { iPressed = aPressed; if (!iPressed && iSelecting) { - HDEBUG("leaving selection mode"); + HDEBUG("page" << iPage << "leaving selection mode"); iSelecting = false; Q_EMIT selectingChanged(); } @@ -558,7 +558,7 @@ void BooksPageWidget::setCurrentPage(bool aCurrentPage) { if (iCurrentPage != aCurrentPage) { iCurrentPage = aCurrentPage; - HDEBUG(iCurrentPage); + HDEBUG("page" << iPage << iCurrentPage); if (!iCurrentPage) clearSelection(); Q_EMIT currentPageChanged(); } @@ -578,19 +578,11 @@ void BooksPageWidget::setModel(BooksBookModel* aModel) } #endif // HARBOUR_DEBUG iTextStyle = iModel->textStyle(); - iPageMark = iModel->pageMark(iPage); - connect(iModel, SIGNAL(bookModelChanged()), - SLOT(onBookModelChanged())); connect(iModel, SIGNAL(destroyed()), SLOT(onBookModelDestroyed())); - connect(iModel, SIGNAL(pageMarksChanged()), - SLOT(onBookModelPageMarksChanged())); - connect(iModel, SIGNAL(loadingChanged()), - SLOT(onBookModelLoadingChanged())); connect(iModel, SIGNAL(textStyleChanged()), SLOT(onTextStyleChanged())); } else { - iPageMark.invalidate(); iTextStyle = BooksTextStyle::defaults(); } resetView(); @@ -613,14 +605,6 @@ void BooksPageWidget::onColorsChanged() scheduleRepaint(); } -void BooksPageWidget::onBookModelChanged() -{ - HDEBUG(iModel->title()); - BooksLoadingSignalBlocker block(this); - iPageMark = iModel->pageMark(iPage); - resetView(); -} - void BooksPageWidget::onBookModelDestroyed() { HDEBUG("model destroyed"); @@ -631,46 +615,26 @@ void BooksPageWidget::onBookModelDestroyed() resetView(); } -void BooksPageWidget::onBookModelPageMarksChanged() -{ - const BooksPos pos = iModel->pageMark(iPage); - if (iPageMark != pos) { - BooksLoadingSignalBlocker block(this); - iPageMark = pos; - HDEBUG("page" << iPage); - resetView(); - } -} - -void BooksPageWidget::onBookModelLoadingChanged() -{ - BooksLoadingSignalBlocker block(this); - if (!iModel->loading()) { - HDEBUG("page" << iPage); - const BooksPos pos = iModel->pageMark(iPage); - if (iPageMark != pos) { - iPageMark = pos; - resetView(); - } - } -} - void BooksPageWidget::setPage(int aPage) { if (iPage != aPage) { BooksLoadingSignalBlocker block(this); iPage = aPage; HDEBUG(iPage); - const BooksPos pos = iModel->pageMark(iPage); - if (iPageMark != pos) { - iPageMark = pos; - resetView(); - } - resetView(); Q_EMIT pageChanged(); } } +void BooksPageWidget::setBookPos(const BooksPos& aBookPos) +{ + if (iBookPos != aBookPos) { + iBookPos = aBookPos; + HDEBUG("page" << iPage << iBookPos); + resetView(); + Q_EMIT bookPosChanged(); + } +} + void BooksPageWidget::setLeftMargin(int aMargin) { if (iMargins.iLeft != aMargin) { @@ -717,7 +681,7 @@ void BooksPageWidget::paint(QPainter* aPainter) HDEBUG("page" << iPage); aPainter->drawImage(0, 0, iImage); iEmpty = false; - } else if (iPage >= 0 && iPageMark.valid() && !iData.isNull()) { + } else if (iPage >= 0 && iBookPos.valid() && !iData.isNull()) { if (!iRenderTask) { HDEBUG("page" << iPage << "(scheduled)"); scheduleRepaint(); @@ -755,18 +719,19 @@ void BooksPageWidget::resetView() iFootnoteTask->release(this); iFootnoteTask = NULL; } + iImage = QImage(); iData.reset(); - if (iPage >= 0 && iPageMark.valid() && + if (iPage >= 0 && iBookPos.valid() && width() > 0 && height() > 0 && iModel) { shared_ptr textModel = iModel->bookTextModel(); if (!textModel.isNull()) { (iResetTask = new ResetTask(iTaskQueue->pool(), textModel, iTextStyle, - width(), height(), iMargins, iPageMark))-> + width(), height(), iMargins, iBookPos))-> submit(this, SLOT(onResetTaskDone())); cancelRepaint(); } } - if (!iResetTask && !iEmpty) { + if (!iEmpty) { update(); } } @@ -788,8 +753,7 @@ void BooksPageWidget::scheduleRepaint() const int h = height(); if (w > 0 && h > 0 && !iData.isNull() && !iData->iView.isNull()) { const shared_ptr view(iData->iView); - BooksSettings* settings = iSettings.data(); - view->setInvertColors(settings->invertColors()); + view->setInvertColors(iSettings->invertColors()); (iRenderTask = new RenderTask(iTaskQueue->pool(), iData, w, h))-> submit(this, SLOT(onRenderTaskDone())); } else { @@ -1013,6 +977,8 @@ void BooksPageWidget::onWidthChanged() HVERBOSE((int)width()); // Width change will probably be followed by height change iResizeTimer->start(); + iImage = QImage(); + update(); } void BooksPageWidget::onHeightChanged() @@ -1024,6 +990,8 @@ void BooksPageWidget::onHeightChanged() updateSize(); } else { iResizeTimer->start(); + iImage = QImage(); + update(); } } diff --git a/app/src/BooksPageWidget.h b/app/src/BooksPageWidget.h index 434f728..b39e678 100644 --- a/app/src/BooksPageWidget.h +++ b/app/src/BooksPageWidget.h @@ -62,6 +62,7 @@ class BooksPageWidget: public QQuickPaintedItem, private BooksLoadingProperty Q_PROPERTY(int topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged) Q_PROPERTY(int bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged) Q_PROPERTY(BooksBookModel* model READ model WRITE setModel NOTIFY modelChanged) + Q_PROPERTY(BooksPos bookPos READ bookPos WRITE setBookPos NOTIFY bookPosChanged) public: class Data; @@ -85,6 +86,9 @@ public: BooksBookModel* model() const; void setModel(BooksBookModel* aModel); + const BooksPos& bookPos() const; + void setBookPos(const BooksPos& aBookPos); + int leftMargin() const; int rightMargin() const; int topMargin() const; @@ -103,13 +107,14 @@ public: Q_INVOKABLE void clearSelection(); Q_SIGNALS: - void loadingChanged(); + void loadingChanged() Q_DECL_OVERRIDE; void pressedChanged(); void selectingChanged(); void selectionEmptyChanged(); void currentPageChanged(); void pageChanged(); void modelChanged(); + void bookPosChanged(); void leftMarginChanged(); void rightMarginChanged(); void topMarginChanged(); @@ -125,10 +130,7 @@ private Q_SLOTS: void onWidthChanged(); void onHeightChanged(); void onResizeTimeout(); - void onBookModelChanged(); void onBookModelDestroyed(); - void onBookModelPageMarksChanged(); - void onBookModelLoadingChanged(); void onTextStyleChanged(); void onColorsChanged(); void onResetTaskDone(); @@ -141,7 +143,7 @@ private Q_SLOTS: void onFootnoteTaskDone(); private: - void paint(QPainter *painter); + void paint(QPainter *painter) Q_DECL_OVERRIDE; void updateSize(); void resetView(); void releaseExtendSelectionTasks(); @@ -160,7 +162,7 @@ private: QSharedPointer iSettings; shared_ptr iTaskQueue; shared_ptr iTextStyle; - BooksPos iPageMark; + BooksPos iBookPos; QTimer* iResizeTimer; BooksBookModel* iModel; BooksMargins iMargins; @@ -192,6 +194,8 @@ inline bool BooksPageWidget::currentPage() const { return iCurrentPage; } inline int BooksPageWidget::page() const { return iPage; } +inline const BooksPos& BooksPageWidget::bookPos() const + { return iBookPos; } inline BooksBookModel* BooksPageWidget::model() const { return iModel; } inline int BooksPageWidget::leftMargin() const