[app] Zoom images on long tap

This commit is contained in:
Slava Monich 2016-10-08 19:57:54 +03:00
parent c15d6b840d
commit 4c918861d0
9 changed files with 365 additions and 42 deletions

View file

@ -105,6 +105,7 @@ SOURCES += \
src/BooksCoverWidget.cpp \
src/BooksDialogManager.cpp \
src/BooksHints.cpp \
src/BooksImageProvider.cpp \
src/BooksImportModel.cpp \
src/BooksListWatcher.cpp \
src/BooksLoadingProperty.cpp \
@ -144,6 +145,7 @@ HEADERS += \
src/BooksDefs.h \
src/BooksDialogManager.h \
src/BooksHints.h \
src/BooksImageProvider.h \
src/BooksImportModel.h \
src/BooksItem.h \
src/BooksListWatcher.h \

View file

@ -13,8 +13,8 @@
* 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
* 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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
@ -63,9 +63,10 @@ SilicaFlickable {
qsTrId("harbour-books-book-view-applying_smaller_fonts")
]
interactive: !linkMenu || !linkMenu.visible
interactive: !linkMenu || !linkMenu.visible || !imageView || !imageView.visible
property var linkMenu
property var imageView
Component {
id: linkMenuComponent
@ -73,6 +74,12 @@ SilicaFlickable {
}
}
Component {
id: imageViewComponent
BooksImageView {
}
}
PullDownMenu {
MenuItem {
//% "Back to library"
@ -156,6 +163,15 @@ SilicaFlickable {
root.pageClicked(index)
globalSettings.pageDetails = (globalSettings.pageDetails+ 1) % _visibilityStates.length
}
onImagePressed: {
if (_currentPage == index) {
if (!imageView) {
imageView = imageViewComponent.createObject(root)
}
imageView.source = url
imageView.show()
}
}
onBrowserLinkPressed: {
if (_currentPage == index) {
if (!linkMenu) {

View file

@ -0,0 +1,73 @@
/*
Copyright (C) 2016 Jolla Ltd.
Contact: Slava Monich <slava.monich@jolla.com>
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:
* 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.
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
Rectangle {
id: root
visible: opacity > 0.0
opacity: 0.0
width: parent.width
height: parent.height
color: Theme.rgba(Theme.highlightDimmerColor, 0.9)
property alias source: image.source
readonly property real maxImageWidth: width - 2*Theme.horizontalPageMargin
readonly property real maxImageHeight: height - 2*Theme.paddingLarge
Behavior on opacity { FadeAnimation {} }
Image {
id: image
anchors.centerIn: parent
smooth: true
readonly property bool landscape: sourceSize.width * parent.height > sourceSize.height * parent.width
width: landscape ? maxImageWidth : (maxImageHeight * sourceSize.width / sourceSize.height)
height: landscape ? (maxImageWidth * sourceSize.height / sourceSize.width) : maxImageHeight
}
MouseArea {
anchors.fill: parent
onPressed: {
root.hide()
}
}
function show() {
opacity = 1.0
}
function hide() {
opacity = 0.0
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright (C) 2015 Jolla Ltd.
Copyright (C) 2015-2016 Jolla Ltd.
Contact: Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:
@ -7,14 +7,15 @@
Redistribution and use in source and binary forms, with or without
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 the 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.
* 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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@ -49,6 +50,7 @@ Item {
property bool pageNumberVisible
signal pageClicked()
signal imagePressed(var url, var rect)
signal browserLinkPressed(var url)
PageWidget {
@ -57,6 +59,7 @@ Item {
settings: globalSettings
model: bookModel
onBrowserLinkPressed: view.browserLinkPressed(url)
onImagePressed: view.imagePressed(url, rect)
}
BooksTitleLabel {

View file

@ -0,0 +1,127 @@
/*
* Copyright (C) 2016 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* 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:
*
* * 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.
*
* 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 "BooksImageProvider.h"
#include "image/ZLQtImageManager.h"
#include "HarbourDebug.h"
const QString BooksImageProvider::PROVIDER_ID("bookImage");
BooksImageProvider* BooksImageProvider::gInstance = NULL;
BooksImageProvider*
BooksImageProvider::instance()
{
if (!gInstance) {
new BooksImageProvider;
}
return gInstance;
}
BooksImageProvider::BooksImageProvider(
QObject* aParent) :
QObject(aParent),
QQuickImageProvider(QQuickImageProvider::Image)
{
gInstance = this;
}
BooksImageProvider::~BooksImageProvider()
{
if (gInstance == this) {
gInstance = NULL;
}
}
void
BooksImageProvider::addImage(
QObject* aOwner,
QString aId,
shared_ptr<ZLImageData> aData)
{
if (aOwner && !aId.isEmpty() && !aData.isNull()) {
QMutexLocker locker(&iMutex);
if (!iImageMap.contains(aId)) {
if (!iOwnerMap.contains(aOwner)) {
connect(aOwner, SIGNAL(destroyed(QObject*)),
SLOT(releaseImages(QObject*)));
} else {
QStringList ids = iOwnerMap.value(aOwner);
ids.append(aId);
iOwnerMap.insert(aOwner, ids);
}
}
iImageMap.insert(aId, aData);
}
}
void
BooksImageProvider::releaseImages(
QObject* aOwner)
{
QMutexLocker locker(&iMutex);
const QStringList ids = iOwnerMap.take(aOwner);
const int n = ids.count();
for (int i=0; i<n; i++) {
HDEBUG(ids.at(i));
iImageMap.remove(ids.at(i));
}
}
QImage
BooksImageProvider::requestImage(
const QString& aId,
QSize* aSize,
const QSize& aRequestedSize)
{
QMutexLocker locker(&iMutex);
shared_ptr<ZLImageData> ptr = iImageMap.value(aId);
if (!ptr.isNull()) {
HDEBUG(aId);
const ZLQtImageData& data = (const ZLQtImageData&)*ptr;
const QImage* image = data.image();
HASSERT(image);
if (image) {
if (aRequestedSize.isEmpty() || image->size() == aRequestedSize) {
*aSize = image->size();
return *image;
} else {
*aSize = aRequestedSize;
return image->scaled(aRequestedSize, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
}
}
} else {
HWARN("No such image:" << aId);
}
return QImage();
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2016 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* 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:
*
* * 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.
*
* 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_IMAGE_PROVIDER_H
#define BOOKS_IMAGE_PROVIDER_H
#include "ZLImageManager.h"
#include <QImage>
#include <QMutex>
#include <QQuickImageProvider>
class BooksImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
static const QString PROVIDER_ID;
static BooksImageProvider* instance();
BooksImageProvider(QObject* aParent = NULL);
virtual ~BooksImageProvider();
void addImage(QObject* aOwner, QString aId, shared_ptr<ZLImageData> aData);
virtual QImage requestImage(const QString& aId, QSize* aSize,
const QSize& aRequestedSize);
public Q_SLOTS:
void releaseImages(QObject* aOwner);
private:
QMutex iMutex;
QHash<QString, shared_ptr<ZLImageData> > iImageMap;
QHash<QObject*, QStringList> iOwnerMap;
static BooksImageProvider* gInstance;
};
#endif // BOOKS_IMAGE_PROVIDER_H

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
@ -14,7 +14,7 @@
* 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
* * 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.
*
@ -31,6 +31,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BooksImageProvider.h"
#include "BooksPageWidget.h"
#include "BooksTextStyle.h"
#include "BooksDefs.h"
@ -162,7 +163,7 @@ void BooksPageWidget::RenderTask::performTask()
class BooksPageWidget::LongPressTask : public BooksTask {
public:
LongPressTask(shared_ptr<BooksPageWidget::Data> aData, int aX, int aY) :
iData(aData), iX(aX), iY(aY) {}
iData(aData), iX(aX), iY(aY), iKind(REGULAR) {}
void performTask();
@ -170,9 +171,12 @@ public:
shared_ptr<BooksPageWidget::Data> iData;
int iX;
int iY;
QRect iRect;
ZLTextKind iKind;
std::string iLinkText;
std::string iLink;
std::string iLinkType;
std::string iImageId;
shared_ptr<ZLImageData> iImageData;
};
void BooksPageWidget::LongPressTask::performTask()
@ -180,27 +184,47 @@ void BooksPageWidget::LongPressTask::performTask()
if (!isCanceled()) {
const ZLTextArea& area = iData->iView->textArea();
const ZLTextElementRectangle* rect = area.elementByCoordinates(iX, iY);
if (rect && !isCanceled() &&
((rect->Kind == ZLTextElement::WORD_ELEMENT) ||
(rect->Kind == ZLTextElement::IMAGE_ELEMENT))) {
ZLTextWordCursor cursor = area.startCursor();
cursor.moveToParagraph(rect->ParagraphIndex);
cursor.moveToParagraphStart();
for (int i=0; i<rect->ElementIndex && !isCanceled(); i++) {
const ZLTextElement& element = cursor.element();
if (element.kind() == ZLTextElement::CONTROL_ELEMENT) {
const ZLTextControlEntry& controlEntry =
((const ZLTextControlElement&)element).entry();
if (controlEntry.isHyperlink()) {
const ZLTextHyperlinkControlEntry& hyperLinkEntry =
((const ZLTextHyperlinkControlEntry&)controlEntry);
iKind = hyperLinkEntry.kind();
iLinkText = hyperLinkEntry.label();
iLinkType = hyperLinkEntry.hyperlinkType();
return;
if (rect && !isCanceled()) {
iRect.setLeft(rect->XStart);
iRect.setRight(rect->XEnd);
iRect.setTop(rect->YStart);
iRect.setBottom(rect->YEnd);
if (rect->Kind == ZLTextElement::WORD_ELEMENT) {
ZLTextWordCursor cursor = area.startCursor();
cursor.moveToParagraph(rect->ParagraphIndex);
cursor.moveToParagraphStart();
for (int i=0; i<rect->ElementIndex && !isCanceled(); i++) {
const ZLTextElement& element = cursor.element();
if (element.kind() == ZLTextElement::CONTROL_ELEMENT) {
const ZLTextControlEntry& controlEntry =
((const ZLTextControlElement&)element).entry();
if (controlEntry.isHyperlink()) {
const ZLTextHyperlinkControlEntry& hyperLinkEntry =
((const ZLTextHyperlinkControlEntry&)controlEntry);
iKind = hyperLinkEntry.kind();
iLink = hyperLinkEntry.label();
iLinkType = hyperLinkEntry.hyperlinkType();
HDEBUG("link" << iLink.c_str());
return;
}
}
cursor.nextWord();
}
} else if (rect->Kind == ZLTextElement::IMAGE_ELEMENT) {
ZLTextWordCursor cursor = area.startCursor();
cursor.moveToParagraph(rect->ParagraphIndex);
cursor.moveTo(rect->ElementIndex, 0);
const ZLTextElement& element = cursor.element();
HASSERT(element.kind() == ZLTextElement::IMAGE_ELEMENT);
if (element.kind() == ZLTextElement::IMAGE_ELEMENT) {
const ZLTextImageElement& imageElement =
(const ZLTextImageElement&)element;
iKind = IMAGE;
iImageId = imageElement.id();
iImageData = imageElement.image();
HDEBUG("image element" << iImageId.c_str() <<
iImageData->width() << iImageData->height());
}
cursor.nextWord();
}
}
}
@ -519,18 +543,24 @@ void BooksPageWidget::onRenderTaskDone()
void BooksPageWidget::onLongPressTaskDone()
{
static const std::string HTTP("http://");
static const std::string HTTPS("https://");
HASSERT(sender() == iLongPressTask);
HDEBUG(iLongPressTask->iKind <<
iLongPressTask->iLinkType.c_str() <<
iLongPressTask->iLinkText.c_str());
HDEBUG(iLongPressTask->iKind);
if (iLongPressTask->iKind == EXTERNAL_HYPERLINK &&
(ZLStringUtil::stringStartsWith(iLongPressTask->iLinkText, HTTP) ||
ZLStringUtil::stringStartsWith(iLongPressTask->iLinkText, HTTPS))) {
Q_EMIT browserLinkPressed(QString::fromStdString(iLongPressTask->iLinkText));
if (iLongPressTask->iKind == EXTERNAL_HYPERLINK) {
static const std::string HTTP("http://");
static const std::string HTTPS("https://");
if (ZLStringUtil::stringStartsWith(iLongPressTask->iLink, HTTP) ||
ZLStringUtil::stringStartsWith(iLongPressTask->iLink, HTTPS)) {
QString url(QString::fromStdString(iLongPressTask->iLink));
Q_EMIT browserLinkPressed(url);
}
} else if (iLongPressTask->iKind == IMAGE) {
static const QString PREFIX("image://");
QString id(QString::fromStdString(iLongPressTask->iImageId));
QString url = PREFIX + BooksImageProvider::PROVIDER_ID + "/" + id;
BooksImageProvider::instance()->addImage(iModel, id,
iLongPressTask->iImageData);
Q_EMIT imagePressed(url, iLongPressTask->iRect);
}
iLongPressTask->release(this);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
@ -14,7 +14,7 @@
* 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
* * 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.
*
@ -101,6 +101,7 @@ Q_SIGNALS:
void topMarginChanged();
void bottomMarginChanged();
void browserLinkPressed(QString url);
void imagePressed(QString url, QRect rect);
private Q_SLOTS:
void onWidthChanged();

View file

@ -35,6 +35,7 @@
#include "BooksStorage.h"
#include "BooksPaintContext.h"
#include "BooksDialogManager.h"
#include "BooksImageProvider.h"
#include "HarbourDebug.h"
@ -191,6 +192,8 @@ void ZLibrary::run(ZLApplication* aApp)
QQuickView* view = SailfishApp::createView();
QQmlContext* root = view->rootContext();
root->engine()->addImageProvider(BooksImageProvider::PROVIDER_ID,
new BooksImageProvider(root));
root->setContextProperty("PointsPerInch", booksPPI);
root->setContextProperty("MaximumHintCount", 1);
root->setContextProperty("BooksSettingsMenu",