diff --git a/app/data/default/styles.xml b/app/data/default/styles.xml
index 464da94..dc8aae2 100644
--- a/app/data/default/styles.xml
+++ b/app/data/default/styles.xml
@@ -27,7 +27,7 @@
-
+
diff --git a/app/qml/BooksBookView.qml b/app/qml/BooksBookView.qml
index 68c3593..8cf1b8a 100644
--- a/app/qml/BooksBookView.qml
+++ b/app/qml/BooksBookView.qml
@@ -42,6 +42,7 @@ SilicaFlickable {
signal closeBook()
signal pageClicked(var page)
+ property int orientation: Orientation.Portrait
property int _currentPage: bookListWatcher.currentIndex
property bool _loading: minLoadingDelay.running || bookModel.loading
property var _currentState: _visibilityStates[Settings.pageDetails % _visibilityStates.length]
@@ -63,22 +64,33 @@ SilicaFlickable {
qsTrId("harbour-books-book-view-applying_smaller_fonts")
]
- interactive: (!linkMenu || !linkMenu.visible) && (!imageView || !imageView.visible)
+ interactive: (!linkMenu || !linkMenu.visible) &&
+ (!imageView || !imageView.visible) &&
+ (!footnoteView || !footnoteView.visible)
property var linkMenu
property var imageView
+ property var footnoteView
- Component {
- id: linkMenuComponent
- BooksLinkMenu {
+ onOrientationChanged: {
+ if (footnoteView) {
+ footnoteView.cancel()
}
}
+ Component {
+ id: linkMenuComponent
+ BooksLinkMenu { }
+ }
+
Component {
id: imageViewComponent
- BooksImageView {
- imageBackground: Settings.pageBackgroundColor
- }
+ BooksImageView { }
+ }
+
+ Component {
+ id: footnoteViewComponent
+ BooksFootnoteView { }
}
PullDownMenu {
@@ -177,8 +189,15 @@ SilicaFlickable {
if (!linkMenu) {
linkMenu = linkMenuComponent.createObject(root)
}
- linkMenu.url = url
- linkMenu.show()
+ linkMenu.show(url)
+ }
+ }
+ onFootnotePressed: {
+ if (_currentPage == index) {
+ if (!footnoteView) {
+ footnoteView = footnoteViewComponent.createObject(root)
+ }
+ footnoteView.show(touchX,touchY,text,url)
}
}
}
diff --git a/app/qml/BooksFootnoteView.qml b/app/qml/BooksFootnoteView.qml
new file mode 100644
index 0000000..8536716
--- /dev/null
+++ b/app/qml/BooksFootnoteView.qml
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2016 Jolla Ltd.
+ Contact: 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:
+
+ * 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
+ opacity: 0.0
+ anchors.fill: parent
+ color: Theme.rgba(Theme.highlightDimmerColor, 0.9)
+
+ readonly property real footnoteX: Math.round((root.width-footnoteItem.width)/2)
+ readonly property real footnoteY: Theme.paddingMedium
+
+ Behavior on opacity { FadeAnimation {} }
+
+ function show(startX,startY,text,url) {
+ flickable.scrollToTop()
+ image.source = url
+ if (state !== "show") {
+ footnoteItem.scale = 0
+ footnoteItem.x = startX
+ footnoteItem.y = startY
+ footnoteLabel.text = text
+ state = "show"
+ }
+ }
+
+ function cancel() {
+ state = "cancel"
+ }
+
+ function hide() {
+ state = "hide"
+ }
+
+ Connections {
+ target: Settings
+ onInvertColorsChanged: cancel()
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: root.hide()
+ }
+
+ Item {
+ id: footnoteItem
+ x: footnoteX
+ y: footnoteY
+ width: footnote.width
+ height: Math.round(root.height + footnote.height)/2 - Theme.paddingMedium
+ transformOrigin: Item.TopLeft
+
+ Label {
+ id: footnoteLabel
+ width: parent.width
+ height: Math.round(root.height - footnote.height/2) - 2*Theme.paddingMedium
+ color: Theme.highlightColor
+ verticalAlignment: Text.AlignBottom
+ maximumLineCount: 4
+ visible: opacity > 0
+ Behavior on opacity { FadeAnimation {} }
+ anchors {
+ top: parent.top
+ bottom: footnote.top
+ bottomMargin: Theme.paddingMedium
+ }
+ }
+
+ Rectangle {
+ id: footnote
+ radius: Theme.paddingMedium/2
+ border.color: Settings.invertedPageBackgroundColor
+ color: Settings.pageBackgroundColor
+ width: image.width + 2*Theme.paddingMedium
+ height: Math.min(root.height/2, image.height + 2*Theme.paddingMedium)
+ anchors {
+ bottom: parent.bottom
+ }
+ SilicaFlickable {
+ id: flickable
+ anchors {
+ fill: parent
+ margins: Theme.paddingMedium
+ }
+ clip: true
+ contentWidth: image.width
+ contentHeight: image.height
+ Image {
+ id: image
+ }
+ VerticalScrollDecorator {}
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "invisible"
+ PropertyChanges {
+ target: root
+ opacity: 0
+ }
+ PropertyChanges {
+ target: footnoteItem
+ scale: 0
+ }
+ },
+ State {
+ name: "hide"
+ extend: "invisible"
+ },
+ State {
+ name: "cancel"
+ extend: "invisible"
+ PropertyChanges {
+ target: footnoteItem
+ transformOrigin: Item.Center
+ }
+ },
+ State {
+ name: "show"
+ PropertyChanges {
+ target: root
+ opacity: 1
+ }
+ PropertyChanges {
+ target: footnoteItem
+ x: footnoteX
+ y: footnoteY
+ scale: 1
+ transformOrigin: Item.TopLeft
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "*"
+ to: "show"
+ NumberAnimation {
+ properties: "opacity,x,y,scale"
+ duration: 200
+ easing.type: Easing.InOutQuad
+ }
+ },
+ Transition {
+ from: "show"
+ to: "hide"
+ NumberAnimation {
+ properties: "opacity,x,y,scale"
+ duration: 200
+ easing.type: Easing.InOutQuad
+ }
+ },
+ Transition {
+ from: "show"
+ to: "cancel"
+ NumberAnimation {
+ properties: "opacity,scale"
+ duration: 200
+ easing.type: Easing.InOutQuad
+ }
+ }
+ ]
+}
diff --git a/app/qml/BooksImageView.qml b/app/qml/BooksImageView.qml
index dd77be7..f19a00b 100644
--- a/app/qml/BooksImageView.qml
+++ b/app/qml/BooksImageView.qml
@@ -40,7 +40,6 @@ Rectangle {
anchors.fill: parent
color: Theme.rgba(Theme.highlightDimmerColor, 0.9)
- property alias imageBackground: background.color
readonly property real maxImageWidth: width - 2*Theme.horizontalPageMargin
readonly property real maxImageHeight: height - 2*Theme.paddingLarge
readonly property real finalImageWidth: Math.ceil(image.landscape ? maxImageWidth : (maxImageHeight * image.sourceSize.width / image.sourceSize.height))
@@ -53,6 +52,7 @@ Rectangle {
Rectangle {
id: background
anchors.fill: image
+ color: Settings.pageBackgroundColor
}
Image {
diff --git a/app/qml/BooksLinkMenu.qml b/app/qml/BooksLinkMenu.qml
index 4ab96f3..0cec27f 100644
--- a/app/qml/BooksLinkMenu.qml
+++ b/app/qml/BooksLinkMenu.qml
@@ -45,7 +45,6 @@ Rectangle {
}
readonly property bool landscape: width > height
- property alias url: linkLabel.text
Behavior on opacity { FadeAnimation {} }
@@ -131,7 +130,8 @@ Rectangle {
}
}
- function show() {
+ function show(url) {
+ linkLabel.text = url
opacity = 1.0
}
diff --git a/app/qml/BooksMainPage.qml b/app/qml/BooksMainPage.qml
index 18345a6..7cbc9bb 100644
--- a/app/qml/BooksMainPage.qml
+++ b/app/qml/BooksMainPage.qml
@@ -61,6 +61,7 @@ Page {
anchors.fill: parent
opacity: book ? 1 : 0
visible: opacity > 0
+ orientation: root.orientation
book: Settings.currentBook ? Settings.currentBook : null
onCloseBook: Settings.currentBook = null
Behavior on opacity { FadeAnimation {} }
diff --git a/app/qml/BooksPageView.qml b/app/qml/BooksPageView.qml
index 34a1c8c..844abf4 100644
--- a/app/qml/BooksPageView.qml
+++ b/app/qml/BooksPageView.qml
@@ -51,6 +51,7 @@ Item {
signal pageClicked()
signal imagePressed(var url, var rect)
+ signal footnotePressed(var touchX, var touchY, var text, var url)
signal browserLinkPressed(var url)
signal jumpToPage(var page)
@@ -59,9 +60,10 @@ Item {
anchors.fill: parent
model: bookModel
onBrowserLinkPressed: view.browserLinkPressed(url)
- onImagePressed: view.imagePressed(url, rect)
- onActiveTouch: pressImage.animate(x, y)
+ onImagePressed: view.imagePressed(imageId, rect)
+ onActiveTouch: pressImage.animate(touchX, touchY)
onJumpToPage: view.jumpToPage(page)
+ onShowFootnote: view.footnotePressed(touchX,touchY,text,imageId)
}
BooksTitleLabel {
diff --git a/app/src/BooksBookModel.cpp b/app/src/BooksBookModel.cpp
index 41b2c44..3ecfc8d 100644
--- a/app/src/BooksBookModel.cpp
+++ b/app/src/BooksBookModel.cpp
@@ -348,6 +348,15 @@ shared_ptr BooksBookModel::bookTextModel() const
return model;
}
+shared_ptr BooksBookModel::footnoteModel(const std::string& aId) const
+{
+ shared_ptr model;
+ if (iData && !iData->iBookModel.isNull()) {
+ model = iData->iBookModel->footnoteModel(aId);
+ }
+ return model;
+}
+
shared_ptr BooksBookModel::contentsModel() const
{
shared_ptr model;
diff --git a/app/src/BooksBookModel.h b/app/src/BooksBookModel.h
index 42be433..e24a000 100644
--- a/app/src/BooksBookModel.h
+++ b/app/src/BooksBookModel.h
@@ -120,6 +120,7 @@ public:
shared_ptr bookModel() const;
shared_ptr bookTextModel() const;
shared_ptr contentsModel() const;
+ shared_ptr footnoteModel(const std::string& aId) const;
shared_ptr textStyle() const { return iTextStyle; }
int linkToPage(const std::string& aLink) const;
int fontSizeAdjust() const;
diff --git a/app/src/BooksImageProvider.cpp b/app/src/BooksImageProvider.cpp
index 0477e66..84a51ff 100644
--- a/app/src/BooksImageProvider.cpp
+++ b/app/src/BooksImageProvider.cpp
@@ -32,7 +32,6 @@
*/
#include "BooksImageProvider.h"
-#include "image/ZLQtImageManager.h"
#include "HarbourDebug.h"
const QString BooksImageProvider::PROVIDER_ID("bookImage");
@@ -66,21 +65,18 @@ void
BooksImageProvider::addImage(
QObject* aOwner,
QString aId,
- shared_ptr aData)
+ QImage aImage)
{
- if (aOwner && !aId.isEmpty() && !aData.isNull()) {
+ if (aOwner && !aId.isEmpty() && !aImage.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);
- }
+ QStringList ids = iOwnerMap.value(aOwner);
+ if (ids.isEmpty()) {
+ connect(aOwner, SIGNAL(destroyed(QObject*)),
+ SLOT(releaseImages(QObject*)));
}
- iImageMap.insert(aId, aData);
+ ids.append(aId);
+ iOwnerMap.insert(aOwner, ids);
+ iImageMap.insert(aId, aImage);
}
}
@@ -104,21 +100,16 @@ BooksImageProvider::requestImage(
const QSize& aRequestedSize)
{
QMutexLocker locker(&iMutex);
- shared_ptr 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);
- }
+ QImage image = iImageMap.value(aId);
+ if (!image.isNull()) {
+ HDEBUG(aId << image.size());
+ 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);
diff --git a/app/src/BooksImageProvider.h b/app/src/BooksImageProvider.h
index ee77fde..6c0ede6 100644
--- a/app/src/BooksImageProvider.h
+++ b/app/src/BooksImageProvider.h
@@ -34,8 +34,6 @@
#ifndef BOOKS_IMAGE_PROVIDER_H
#define BOOKS_IMAGE_PROVIDER_H
-#include "ZLImageManager.h"
-
#include
#include
#include
@@ -51,7 +49,7 @@ public:
BooksImageProvider(QObject* aParent = NULL);
virtual ~BooksImageProvider();
- void addImage(QObject* aOwner, QString aId, shared_ptr aData);
+ void addImage(QObject* aOwner, QString aId, QImage aImage);
virtual QImage requestImage(const QString& aId, QSize* aSize,
const QSize& aRequestedSize);
@@ -60,7 +58,7 @@ public Q_SLOTS:
private:
QMutex iMutex;
- QHash > iImageMap;
+ QHash iImageMap;
QHash iOwnerMap;
static BooksImageProvider* gInstance;
};
diff --git a/app/src/BooksPageWidget.cpp b/app/src/BooksPageWidget.cpp
index d5eea61..718240f 100644
--- a/app/src/BooksPageWidget.cpp
+++ b/app/src/BooksPageWidget.cpp
@@ -37,12 +37,15 @@
#include "BooksDefs.h"
#include "bookmodel/FBTextKind.h"
+#include "image/ZLQtImageManager.h"
#include "ZLStringUtil.h"
#include "HarbourDebug.h"
#include
+static const QString IMAGE_URL("image://%1/%2");
+
// ==========================================================================
// BooksPageWidget::Data
// ==========================================================================
@@ -141,21 +144,110 @@ public:
shared_ptr iData;
int iWidth;
int iHeight;
- shared_ptr iImage;
+ QImage iImage;
};
void BooksPageWidget::RenderTask::performTask()
{
if (!isCanceled() && !iData.isNull() && !iData->iView.isNull() &&
iWidth > 0 && iHeight > 0) {
- iImage = new QImage(iWidth, iHeight, QImage::Format_RGB32);
+ iImage = QImage(iWidth, iHeight, QImage::Format_RGB32);
if (!isCanceled()) {
- QPainter painter(&*iImage);
+ QPainter painter(&iImage);
iData->paint(&painter);
}
}
}
+// ==========================================================================
+// BooksPageWidget::FootnoteTask
+// ==========================================================================
+
+class BooksPageWidget::FootnoteTask : public BooksTask, ZLTextArea::Properties {
+public:
+ FootnoteTask(int aX, int aY, int aMaxWidth, int aMaxHeight,
+ QString aPath, QString aLinkText, QString aRef,
+ shared_ptr aTextModel, shared_ptr aTextStyle,
+ bool aInvertColors) :
+ iTextModel(aTextModel), iTextStyle(aTextStyle),
+ iInvertColors(aInvertColors), iX(aX), iY(aY),
+ iMaxWidth(aMaxWidth), iMaxHeight(aMaxHeight),
+ iRef(aRef), iLinkText(aLinkText), iPath(aPath) {}
+ ~FootnoteTask();
+
+ void performTask();
+
+ // ZLTextArea::Properties
+ shared_ptr baseStyle() const;
+ ZLColor color(const std::string& aStyle) const;
+ bool isSelectionEnabled() const;
+
+public:
+ shared_ptr iTextModel;
+ shared_ptr iTextStyle;
+ bool iInvertColors;
+ int iX;
+ int iY;
+ int iMaxWidth;
+ int iMaxHeight;
+ QString iRef;
+ QString iLinkText;
+ QString iPath;
+ QImage iImage;
+};
+
+BooksPageWidget::FootnoteTask::~FootnoteTask()
+{
+}
+
+shared_ptr BooksPageWidget::FootnoteTask::baseStyle() const
+{
+ return iTextStyle;
+}
+
+ZLColor BooksPageWidget::FootnoteTask::color(const std::string& aStyle) const
+{
+ return BooksPaintContext::realColor(aStyle, iInvertColors);
+}
+
+bool BooksPageWidget::FootnoteTask::isSelectionEnabled() const
+{
+ return false;
+}
+
+void BooksPageWidget::FootnoteTask::performTask()
+{
+ if (!isCanceled()) {
+ // Determine the size of the footnote canvas
+ ZLTextParagraphCursorCache cache;
+ BooksPaintContext sizeContext(iMaxWidth, iMaxHeight);
+ ZLTextAreaController sizeController(sizeContext, *this, &cache);
+ ZLSize size;
+ sizeController.setModel(iTextModel);
+ sizeController.preparePaintInfo();
+ sizeController.area().paint(&size);
+ if (!size.isEmpty() && !isCanceled()) {
+ // Now actually paint it
+ 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);
+ ZLTextAreaController paintController(paintContext, *this, &cache);
+ iImage = QImage(size.myWidth, size.myHeight, QImage::Format_RGB32);
+ QPainter painter(&iImage);
+ paintContext.beginPaint(&painter);
+ paintContext.clear(iInvertColors ?
+ BooksTextView::INVERTED_BACKGROUND :
+ BooksTextView::DEFAULT_BACKGROUND);
+ paintController.setModel(iTextModel);
+ paintController.preparePaintInfo();
+ paintController.area().paint();
+ paintContext.endPaint();
+ }
+ }
+}
+
// ==========================================================================
// BooksPageWidget::PressTask
// ==========================================================================
@@ -166,6 +258,7 @@ public:
iData(aData), iX(aX), iY(aY), iKind(REGULAR) {}
void performTask();
+ QString getLinkText(ZLTextWordCursor& aCursor);
public:
shared_ptr iData;
@@ -176,9 +269,27 @@ public:
std::string iLink;
std::string iLinkType;
std::string iImageId;
- shared_ptr iImageData;
+ QString iLinkText;
+ QImage iImage;
};
+QString BooksPageWidget::PressTask::getLinkText(ZLTextWordCursor& aCursor)
+{
+ QString text;
+ while (!aCursor.isEndOfParagraph() && !isCanceled() &&
+ aCursor.element().kind() != ZLTextElement::WORD_ELEMENT) {
+ aCursor.nextWord();
+ }
+ while (!aCursor.isEndOfParagraph() && !isCanceled() &&
+ aCursor.element().kind() == ZLTextElement::WORD_ELEMENT) {
+ const ZLTextWord& word = (ZLTextWord&)aCursor.element();
+ if (!text.isEmpty()) text.append(' ');
+ text.append(QString::fromUtf8(word.Data, word.Size));
+ aCursor.nextWord();
+ }
+ return text;
+}
+
void BooksPageWidget::PressTask::performTask()
{
if (!isCanceled()) {
@@ -219,10 +330,12 @@ void BooksPageWidget::PressTask::performTask()
if (entry.isStart() && !stopped[entry.kind()]) {
const ZLTextHyperlinkControlEntry& link =
(ZLTextHyperlinkControlEntry&) entry;
- iKind = link.kind();
+ iKind = kind;
iLink = link.label();
iLinkType = link.hyperlinkType();
- HDEBUG("link" << kind << iLink.c_str());
+ iLinkText = getLinkText(cursor);
+ HDEBUG("link" << kind << iLinkText <<
+ iLink.c_str());
}
return;
}
@@ -237,11 +350,17 @@ void BooksPageWidget::PressTask::performTask()
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());
+ shared_ptr data = imageElement.image();
+ if (!data.isNull()) {
+ const QImage* image = ((ZLQtImageData&)(*data)).image();
+ if (image && !image->isNull()) {
+ iKind = IMAGE;
+ iImage = *image;
+ iImageId = imageElement.id();
+ HDEBUG("image element" << iImageId.c_str() <<
+ iImage.width() << iImage.height());
+ }
+ }
}
}
}
@@ -263,6 +382,7 @@ BooksPageWidget::BooksPageWidget(QQuickItem* aParent) :
iRenderTask(NULL),
iPressTask(NULL),
iLongPressTask(NULL),
+ iFootnoteTask(NULL),
iEmpty(false),
iPage(-1)
{
@@ -287,6 +407,7 @@ BooksPageWidget::~BooksPageWidget()
if (iRenderTask) iRenderTask->release(this);
if (iPressTask) iPressTask->release(this);
if (iLongPressTask) iLongPressTask->release(this);
+ if (iFootnoteTask) iFootnoteTask->release(this);
}
void BooksPageWidget::setModel(BooksBookModel* aModel)
@@ -443,7 +564,7 @@ void BooksPageWidget::paint(QPainter* aPainter)
{
if (!iImage.isNull()) {
HDEBUG("page" << iPage);
- aPainter->drawImage(0, 0, *iImage);
+ aPainter->drawImage(0, 0, iImage);
iEmpty = false;
} else if (iPage >= 0 && iPageMark.valid() && !iData.isNull()) {
if (!iRenderTask) {
@@ -471,6 +592,18 @@ void BooksPageWidget::resetView()
iResetTask->release(this);
iResetTask = NULL;
}
+ if (iPressTask) {
+ iPressTask->release(this);
+ iPressTask = NULL;
+ }
+ if (iLongPressTask) {
+ iLongPressTask->release(this);
+ iLongPressTask = NULL;
+ }
+ if (iFootnoteTask) {
+ iFootnoteTask->release(this);
+ iFootnoteTask = NULL;
+ }
iData.reset();
if (iPage >= 0 && iPageMark.valid() &&
width() > 0 && height() > 0 && iModel) {
@@ -547,6 +680,31 @@ void BooksPageWidget::onPressTaskDone()
task->release(this);
}
+void BooksPageWidget::onFootnoteTaskDone()
+{
+ HASSERT(sender() == iFootnoteTask);
+
+ FootnoteTask* task = iFootnoteTask;
+ iFootnoteTask = NULL;
+ if (!task->iImage.isNull()) {
+ // 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");
+ QString id = FOOTNOTE_ID.arg(task->iPath, task->iRef).
+ arg(iPage).arg(task->iInvertColors ? INVERTED : NORMAL).
+ arg(task->iImage.width()).arg(task->iImage.height());
+ QString url = IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id);
+ HDEBUG(url);
+ BooksImageProvider::instance()->addImage(iModel, id, task->iImage);
+ Q_EMIT showFootnote(task->iX, task->iY, task->iLinkText, url);
+ }
+
+ task->release(this);
+}
+
void BooksPageWidget::onLongPressTaskDone()
{
HASSERT(sender() == iLongPressTask);
@@ -571,28 +729,46 @@ void BooksPageWidget::onLongPressTaskDone()
Q_EMIT jumpToPage(page);
}
}
+ } else if (task->iKind == FOOTNOTE) {
+ if (iModel && task->iLink.length() > 0) {
+ std::string ref = task->iLink.substr(1);
+ shared_ptr note = iModel->footnoteModel(ref);
+ BooksBook* book = iModel->book();
+ if (!note.isNull() && book) {
+ // Render the footnote
+ HDEBUG("footnote" << ref.c_str());
+ if (iFootnoteTask) iFootnoteTask->release(this);
+ iFootnoteTask = new FootnoteTask(task->iX, task->iY,
+ width()*3/4, height()*10, book->path(), task->iLinkText,
+ QString::fromStdString(ref), note, iTextStyle,
+ iSettings->invertColors());
+ iTaskQueue->submit(iFootnoteTask, this,
+ SLOT(onFootnoteTaskDone()));
+ }
+ }
} else if (task->iKind == IMAGE) {
// Make sure that the book path is mixed into the image id to handle
// the case of different books having images with identical ids
- QString id = QString::fromStdString(task->iImageId);
+ QString imageId = QString::fromStdString(task->iImageId);
QString path;
if (iModel) {
BooksBook* book = iModel->book();
if (book) {
path = book->path();
if (!path.isEmpty()) {
- if (!id.contains(path)) {
- QString old = id;
- id = path + ":" + old;
- HDEBUG(old << "-> " << id);
+ if (!imageId.contains(path)) {
+ QString old = imageId;
+ imageId = path + ":" + old;
+ HDEBUG(old << "-> " << imageId);
}
}
}
}
- static const QString IMAGE_URL("image://%1/%2");
- QString url = IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id);
- BooksImageProvider::instance()->addImage(iModel, id, task->iImageData);
- Q_EMIT imagePressed(url, task->iRect);
+ static const QString IMAGE_ID("image/%1");
+ QString id = IMAGE_ID.arg(imageId);
+ BooksImageProvider::instance()->addImage(iModel, id, task->iImage);
+ Q_EMIT imagePressed(IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id),
+ task->iRect);
}
task->release(this);
@@ -601,7 +777,7 @@ void BooksPageWidget::onLongPressTaskDone()
void BooksPageWidget::updateSize()
{
HDEBUG("page" << iPage << QSize(width(), height()));
- iImage.reset();
+ iImage = QImage();
resetView();
}
diff --git a/app/src/BooksPageWidget.h b/app/src/BooksPageWidget.h
index 0671284..9b40c5e 100644
--- a/app/src/BooksPageWidget.h
+++ b/app/src/BooksPageWidget.h
@@ -97,9 +97,10 @@ Q_SIGNALS:
void topMarginChanged();
void bottomMarginChanged();
void browserLinkPressed(QString url);
- void imagePressed(QString url, QRect rect);
- void activeTouch(int x, int y);
+ void imagePressed(QString imageId, QRect rect);
+ void activeTouch(int touchX, int touchY);
void jumpToPage(int page);
+ void showFootnote(int touchX, int touchY, QString text, QString imageId);
private Q_SLOTS:
void onWidthChanged();
@@ -115,6 +116,7 @@ private Q_SLOTS:
void onRenderTaskDone();
void onPressTaskDone();
void onLongPressTaskDone();
+ void onFootnoteTaskDone();
private:
void paint(QPainter *painter);
@@ -128,6 +130,7 @@ private:
class ResetTask;
class RenderTask;
class PressTask;
+ class FootnoteTask;
QSharedPointer iSettings;
shared_ptr iTaskQueue;
@@ -137,11 +140,12 @@ private:
BooksBookModel* iModel;
BooksMargins iMargins;
shared_ptr iData;
- shared_ptr iImage;
+ QImage iImage;
ResetTask* iResetTask;
RenderTask* iRenderTask;
PressTask* iPressTask;
PressTask* iLongPressTask;
+ FootnoteTask* iFootnoteTask;
bool iEmpty;
int iPage;
};
diff --git a/app/src/BooksPaintContext.cpp b/app/src/BooksPaintContext.cpp
index e621696..d9a374d 100644
--- a/app/src/BooksPaintContext.cpp
+++ b/app/src/BooksPaintContext.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2016 Jolla Ltd.
* Contact: Slava Monich
*
* You may use this file under the terms of the BSD license as follows:
@@ -36,6 +36,8 @@
#include "HarbourDebug.h"
#include "ZLImage.h"
+#include "ZLTextStyle.h"
+#include "ZLStringUtil.h"
#include "image/ZLQtImageManager.h"
#include
@@ -255,9 +257,45 @@ int BooksPaintContext::height() const
return iHeight;
}
-ZLColor BooksPaintContext::realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const
+ZLColor BooksPaintContext::realColor(quint8 aRed, quint8 aGreen, quint8 aBlue, bool aInvert)
{
- return iInvertColors ?
+ return aInvert ?
ZLColor(255-aRed, 255-aGreen, 255-aBlue) :
ZLColor(aRed, aGreen, aBlue);
}
+
+ZLColor BooksPaintContext::realColor(const std::string& aStyle, bool aInvert)
+{
+ static const std::string INTERNAL_HYPERLINK("internal");
+ static const std::string EXTERNAL_HYPERLINK("external");
+ static const std::string BOOK_HYPERLINK("book");
+
+ if (ZLStringUtil::startsWith(aStyle, '#')) {
+ if (aStyle.length() == 7) {
+ int i, value = 0;
+ for (i=1; i<7; i++) {
+ int nibble = ZLStringUtil::fromHex(aStyle[i]);
+ if (nibble >= 0) {
+ value <<= 4;
+ value |= nibble;
+ } else {
+ break;
+ }
+ }
+ if (i == 7) {
+ return realColor(ZLColor(value), aInvert);
+ }
+ }
+ } else if (aStyle == INTERNAL_HYPERLINK) {
+ return realColor(33, 96, 180, aInvert);
+ } else if (aStyle == EXTERNAL_HYPERLINK) {
+ return realColor(33, 96, 180, aInvert);
+ } else if (aStyle == BOOK_HYPERLINK) {
+ return realColor(23, 68, 128, aInvert);
+ } else if (aStyle == ZLTextStyle::SELECTION_BACKGROUND) {
+ return realColor(82, 131, 194, aInvert);
+ } else if (aStyle == ZLTextStyle::HIGHLIGHTED_TEXT) {
+ return realColor(60, 139, 255, aInvert);
+ }
+ return realColor(0, 0, 0, aInvert);
+}
diff --git a/app/src/BooksPaintContext.h b/app/src/BooksPaintContext.h
index 5777ef5..9e83c3b 100644
--- a/app/src/BooksPaintContext.h
+++ b/app/src/BooksPaintContext.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2016 Jolla Ltd.
* Contact: Slava Monich
*
* You may use this file under the terms of the BSD license as follows:
@@ -88,6 +88,10 @@ public:
void drawFilledCircle(int x, int y, int r);
void setInvertColors(bool aInvertColors);
+ static ZLColor realColor(const std::string& aStyle, bool aInvertColors);
+ static ZLColor realColor(quint8 aRed, quint8 aGreen, quint8 aBlue, bool aInvert);
+ static ZLColor realColor(const ZLColor aColor, bool aInvert);
+ ZLColor realColor(const std::string& aStyle) const;
ZLColor realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const;
ZLColor realColor(const ZLColor aColor) const;
@@ -116,6 +120,12 @@ inline QColor qtColor(const ZLColor& aColor)
{ return QColor(aColor.Red, aColor.Green, aColor.Blue); }
inline ZLColor BooksPaintContext::realColor(const ZLColor aColor) const
{ return realColor(aColor.Red, aColor.Green, aColor.Blue); }
+inline ZLColor BooksPaintContext::realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const
+ { return realColor(aRed, aGreen, aBlue, iInvertColors); }
+inline ZLColor BooksPaintContext::realColor(const ZLColor aColor, bool aInvert)
+ { return realColor(aColor.Red, aColor.Green, aColor.Blue, aInvert); }
+inline ZLColor BooksPaintContext::realColor(const std::string& aStyle) const
+ { return realColor(aStyle, iInvertColors); }
inline void BooksPaintContext::setInvertColors(bool aInvertColors)
{ iInvertColors = aInvertColors; }
diff --git a/app/src/BooksSettings.h b/app/src/BooksSettings.h
index 41a10b4..8359efb 100644
--- a/app/src/BooksSettings.h
+++ b/app/src/BooksSettings.h
@@ -55,6 +55,7 @@ class BooksSettings : public QObject
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)
class TextStyle;
diff --git a/app/src/BooksTextView.cpp b/app/src/BooksTextView.cpp
index a29dd9d..90025a7 100644
--- a/app/src/BooksTextView.cpp
+++ b/app/src/BooksTextView.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2016 Jolla Ltd.
* Contact: Slava Monich
*
* You may use this file under the terms of the BSD license as follows:
@@ -34,8 +34,6 @@
#include "BooksTextView.h"
#include "BooksTextStyle.h"
-#include "ZLStringUtil.h"
-
#define SUPER ZLTextView
const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255);
@@ -87,40 +85,9 @@ ZLColor BooksTextView::backgroundColor() const
return iPaintContext.realColor(DEFAULT_BACKGROUND);
}
-ZLColor BooksTextView::color(const std::string &aStyle) const
+ZLColor BooksTextView::color(const std::string& aStyle) const
{
- static const std::string INTERNAL_HYPERLINK("internal");
- static const std::string EXTERNAL_HYPERLINK("external");
- static const std::string BOOK_HYPERLINK("book");
-
- if (ZLStringUtil::startsWith(aStyle, '#')) {
- if (aStyle.length() == 7) {
- int i, value = 0;
- for (i=1; i<7; i++) {
- int nibble = ZLStringUtil::fromHex(aStyle[i]);
- if (nibble >= 0) {
- value <<= 4;
- value |= nibble;
- } else {
- break;
- }
- }
- if (i == 7) {
- return iPaintContext.realColor(ZLColor(value));
- }
- }
- } else if (aStyle == INTERNAL_HYPERLINK) {
- return iPaintContext.realColor(33, 96, 180);
- } else if (aStyle == EXTERNAL_HYPERLINK) {
- return iPaintContext.realColor(33, 96, 180);
- } else if (aStyle == BOOK_HYPERLINK) {
- return iPaintContext.realColor(23, 68, 128);
- } else if (aStyle == ZLTextStyle::SELECTION_BACKGROUND) {
- return iPaintContext.realColor(82, 131, 194);
- } else if (aStyle == ZLTextStyle::HIGHLIGHTED_TEXT) {
- return iPaintContext.realColor(60, 139, 255);
- }
- return iPaintContext.realColor(0, 0, 0);
+ return iPaintContext.realColor(aStyle);
}
shared_ptr BooksTextView::baseStyle() const