[app] Support for footnotes
This commit is contained in:
parent
35757ce03d
commit
e3b0e1c453
17 changed files with 527 additions and 112 deletions
|
@ -27,7 +27,7 @@
|
||||||
<style id="15" partial="true" name="Internal Hyperlink" allowHyphenations="false" hyperlink="internal"/>
|
<style id="15" partial="true" name="Internal Hyperlink" allowHyphenations="false" hyperlink="internal"/>
|
||||||
<style id="37" partial="true" name="External Hyperlink" allowHyphenations="false" hyperlink="external"/>
|
<style id="37" partial="true" name="External Hyperlink" allowHyphenations="false" hyperlink="external"/>
|
||||||
<style id="38" partial="true" name="Link to Another Book" allowHyphenations="false" hyperlink="book"/>
|
<style id="38" partial="true" name="Link to Another Book" allowHyphenations="false" hyperlink="book"/>
|
||||||
<style id="16" partial="true" name="Footnote" fontSizeDelta="-6" vShift="10" allowHyphenations="false" hyperlink="internal"/>
|
<style id="16" partial="true" name="Footnote" fontSizeDelta="-4" vShift="10" allowHyphenations="false" hyperlink="internal"/>
|
||||||
<style id="17" partial="true" name="Emphasis" italic="true"/>
|
<style id="17" partial="true" name="Emphasis" italic="true"/>
|
||||||
<style id="18" partial="true" name="Strong" bold="true"/>
|
<style id="18" partial="true" name="Strong" bold="true"/>
|
||||||
<style id="19" partial="true" name="Subscript" fontSizeDelta="-4" vShift="-4" allowHyphenations="false"/>
|
<style id="19" partial="true" name="Subscript" fontSizeDelta="-4" vShift="-4" allowHyphenations="false"/>
|
||||||
|
|
|
@ -42,6 +42,7 @@ SilicaFlickable {
|
||||||
signal closeBook()
|
signal closeBook()
|
||||||
signal pageClicked(var page)
|
signal pageClicked(var page)
|
||||||
|
|
||||||
|
property int orientation: Orientation.Portrait
|
||||||
property int _currentPage: bookListWatcher.currentIndex
|
property int _currentPage: bookListWatcher.currentIndex
|
||||||
property bool _loading: minLoadingDelay.running || bookModel.loading
|
property bool _loading: minLoadingDelay.running || bookModel.loading
|
||||||
property var _currentState: _visibilityStates[Settings.pageDetails % _visibilityStates.length]
|
property var _currentState: _visibilityStates[Settings.pageDetails % _visibilityStates.length]
|
||||||
|
@ -63,22 +64,33 @@ SilicaFlickable {
|
||||||
qsTrId("harbour-books-book-view-applying_smaller_fonts")
|
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 linkMenu
|
||||||
property var imageView
|
property var imageView
|
||||||
|
property var footnoteView
|
||||||
|
|
||||||
Component {
|
onOrientationChanged: {
|
||||||
id: linkMenuComponent
|
if (footnoteView) {
|
||||||
BooksLinkMenu {
|
footnoteView.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: linkMenuComponent
|
||||||
|
BooksLinkMenu { }
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: imageViewComponent
|
id: imageViewComponent
|
||||||
BooksImageView {
|
BooksImageView { }
|
||||||
imageBackground: Settings.pageBackgroundColor
|
}
|
||||||
}
|
|
||||||
|
Component {
|
||||||
|
id: footnoteViewComponent
|
||||||
|
BooksFootnoteView { }
|
||||||
}
|
}
|
||||||
|
|
||||||
PullDownMenu {
|
PullDownMenu {
|
||||||
|
@ -177,8 +189,15 @@ SilicaFlickable {
|
||||||
if (!linkMenu) {
|
if (!linkMenu) {
|
||||||
linkMenu = linkMenuComponent.createObject(root)
|
linkMenu = linkMenuComponent.createObject(root)
|
||||||
}
|
}
|
||||||
linkMenu.url = url
|
linkMenu.show(url)
|
||||||
linkMenu.show()
|
}
|
||||||
|
}
|
||||||
|
onFootnotePressed: {
|
||||||
|
if (_currentPage == index) {
|
||||||
|
if (!footnoteView) {
|
||||||
|
footnoteView = footnoteViewComponent.createObject(root)
|
||||||
|
}
|
||||||
|
footnoteView.show(touchX,touchY,text,url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
198
app/qml/BooksFootnoteView.qml
Normal file
198
app/qml/BooksFootnoteView.qml
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -40,7 +40,6 @@ Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Theme.rgba(Theme.highlightDimmerColor, 0.9)
|
color: Theme.rgba(Theme.highlightDimmerColor, 0.9)
|
||||||
|
|
||||||
property alias imageBackground: background.color
|
|
||||||
readonly property real maxImageWidth: width - 2*Theme.horizontalPageMargin
|
readonly property real maxImageWidth: width - 2*Theme.horizontalPageMargin
|
||||||
readonly property real maxImageHeight: height - 2*Theme.paddingLarge
|
readonly property real maxImageHeight: height - 2*Theme.paddingLarge
|
||||||
readonly property real finalImageWidth: Math.ceil(image.landscape ? maxImageWidth : (maxImageHeight * image.sourceSize.width / image.sourceSize.height))
|
readonly property real finalImageWidth: Math.ceil(image.landscape ? maxImageWidth : (maxImageHeight * image.sourceSize.width / image.sourceSize.height))
|
||||||
|
@ -53,6 +52,7 @@ Rectangle {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: background
|
id: background
|
||||||
anchors.fill: image
|
anchors.fill: image
|
||||||
|
color: Settings.pageBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
|
|
|
@ -45,7 +45,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool landscape: width > height
|
readonly property bool landscape: width > height
|
||||||
property alias url: linkLabel.text
|
|
||||||
|
|
||||||
Behavior on opacity { FadeAnimation {} }
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
|
||||||
|
@ -131,7 +130,8 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function show() {
|
function show(url) {
|
||||||
|
linkLabel.text = url
|
||||||
opacity = 1.0
|
opacity = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ Page {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: book ? 1 : 0
|
opacity: book ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
orientation: root.orientation
|
||||||
book: Settings.currentBook ? Settings.currentBook : null
|
book: Settings.currentBook ? Settings.currentBook : null
|
||||||
onCloseBook: Settings.currentBook = null
|
onCloseBook: Settings.currentBook = null
|
||||||
Behavior on opacity { FadeAnimation {} }
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
|
|
@ -51,6 +51,7 @@ Item {
|
||||||
|
|
||||||
signal pageClicked()
|
signal pageClicked()
|
||||||
signal imagePressed(var url, var rect)
|
signal imagePressed(var url, var rect)
|
||||||
|
signal footnotePressed(var touchX, var touchY, var text, var url)
|
||||||
signal browserLinkPressed(var url)
|
signal browserLinkPressed(var url)
|
||||||
signal jumpToPage(var page)
|
signal jumpToPage(var page)
|
||||||
|
|
||||||
|
@ -59,9 +60,10 @@ Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
model: bookModel
|
model: bookModel
|
||||||
onBrowserLinkPressed: view.browserLinkPressed(url)
|
onBrowserLinkPressed: view.browserLinkPressed(url)
|
||||||
onImagePressed: view.imagePressed(url, rect)
|
onImagePressed: view.imagePressed(imageId, rect)
|
||||||
onActiveTouch: pressImage.animate(x, y)
|
onActiveTouch: pressImage.animate(touchX, touchY)
|
||||||
onJumpToPage: view.jumpToPage(page)
|
onJumpToPage: view.jumpToPage(page)
|
||||||
|
onShowFootnote: view.footnotePressed(touchX,touchY,text,imageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
BooksTitleLabel {
|
BooksTitleLabel {
|
||||||
|
|
|
@ -348,6 +348,15 @@ shared_ptr<ZLTextModel> BooksBookModel::bookTextModel() const
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<ZLTextModel> BooksBookModel::footnoteModel(const std::string& aId) const
|
||||||
|
{
|
||||||
|
shared_ptr<ZLTextModel> model;
|
||||||
|
if (iData && !iData->iBookModel.isNull()) {
|
||||||
|
model = iData->iBookModel->footnoteModel(aId);
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextModel> BooksBookModel::contentsModel() const
|
shared_ptr<ZLTextModel> BooksBookModel::contentsModel() const
|
||||||
{
|
{
|
||||||
shared_ptr<ZLTextModel> model;
|
shared_ptr<ZLTextModel> model;
|
||||||
|
|
|
@ -120,6 +120,7 @@ public:
|
||||||
shared_ptr<BookModel> bookModel() const;
|
shared_ptr<BookModel> bookModel() const;
|
||||||
shared_ptr<ZLTextModel> bookTextModel() const;
|
shared_ptr<ZLTextModel> bookTextModel() const;
|
||||||
shared_ptr<ZLTextModel> contentsModel() const;
|
shared_ptr<ZLTextModel> contentsModel() const;
|
||||||
|
shared_ptr<ZLTextModel> footnoteModel(const std::string& aId) const;
|
||||||
shared_ptr<ZLTextStyle> textStyle() const { return iTextStyle; }
|
shared_ptr<ZLTextStyle> textStyle() const { return iTextStyle; }
|
||||||
int linkToPage(const std::string& aLink) const;
|
int linkToPage(const std::string& aLink) const;
|
||||||
int fontSizeAdjust() const;
|
int fontSizeAdjust() const;
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BooksImageProvider.h"
|
#include "BooksImageProvider.h"
|
||||||
#include "image/ZLQtImageManager.h"
|
|
||||||
#include "HarbourDebug.h"
|
#include "HarbourDebug.h"
|
||||||
|
|
||||||
const QString BooksImageProvider::PROVIDER_ID("bookImage");
|
const QString BooksImageProvider::PROVIDER_ID("bookImage");
|
||||||
|
@ -66,21 +65,18 @@ void
|
||||||
BooksImageProvider::addImage(
|
BooksImageProvider::addImage(
|
||||||
QObject* aOwner,
|
QObject* aOwner,
|
||||||
QString aId,
|
QString aId,
|
||||||
shared_ptr<ZLImageData> aData)
|
QImage aImage)
|
||||||
{
|
{
|
||||||
if (aOwner && !aId.isEmpty() && !aData.isNull()) {
|
if (aOwner && !aId.isEmpty() && !aImage.isNull()) {
|
||||||
QMutexLocker locker(&iMutex);
|
QMutexLocker locker(&iMutex);
|
||||||
if (!iImageMap.contains(aId)) {
|
QStringList ids = iOwnerMap.value(aOwner);
|
||||||
if (!iOwnerMap.contains(aOwner)) {
|
if (ids.isEmpty()) {
|
||||||
connect(aOwner, SIGNAL(destroyed(QObject*)),
|
connect(aOwner, SIGNAL(destroyed(QObject*)),
|
||||||
SLOT(releaseImages(QObject*)));
|
SLOT(releaseImages(QObject*)));
|
||||||
} else {
|
|
||||||
QStringList ids = iOwnerMap.value(aOwner);
|
|
||||||
ids.append(aId);
|
|
||||||
iOwnerMap.insert(aOwner, ids);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
iImageMap.insert(aId, aData);
|
ids.append(aId);
|
||||||
|
iOwnerMap.insert(aOwner, ids);
|
||||||
|
iImageMap.insert(aId, aImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,21 +100,16 @@ BooksImageProvider::requestImage(
|
||||||
const QSize& aRequestedSize)
|
const QSize& aRequestedSize)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&iMutex);
|
QMutexLocker locker(&iMutex);
|
||||||
shared_ptr<ZLImageData> ptr = iImageMap.value(aId);
|
QImage image = iImageMap.value(aId);
|
||||||
if (!ptr.isNull()) {
|
if (!image.isNull()) {
|
||||||
HDEBUG(aId);
|
HDEBUG(aId << image.size());
|
||||||
const ZLQtImageData& data = (const ZLQtImageData&)*ptr;
|
if (aRequestedSize.isEmpty() || image.size() == aRequestedSize) {
|
||||||
const QImage* image = data.image();
|
*aSize = image.size();
|
||||||
HASSERT(image);
|
return image;
|
||||||
if (image) {
|
} else {
|
||||||
if (aRequestedSize.isEmpty() || image->size() == aRequestedSize) {
|
*aSize = aRequestedSize;
|
||||||
*aSize = image->size();
|
return image.scaled(aRequestedSize, Qt::IgnoreAspectRatio,
|
||||||
return *image;
|
Qt::SmoothTransformation);
|
||||||
} else {
|
|
||||||
*aSize = aRequestedSize;
|
|
||||||
return image->scaled(aRequestedSize, Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HWARN("No such image:" << aId);
|
HWARN("No such image:" << aId);
|
||||||
|
|
|
@ -34,8 +34,6 @@
|
||||||
#ifndef BOOKS_IMAGE_PROVIDER_H
|
#ifndef BOOKS_IMAGE_PROVIDER_H
|
||||||
#define BOOKS_IMAGE_PROVIDER_H
|
#define BOOKS_IMAGE_PROVIDER_H
|
||||||
|
|
||||||
#include "ZLImageManager.h"
|
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QQuickImageProvider>
|
#include <QQuickImageProvider>
|
||||||
|
@ -51,7 +49,7 @@ public:
|
||||||
BooksImageProvider(QObject* aParent = NULL);
|
BooksImageProvider(QObject* aParent = NULL);
|
||||||
virtual ~BooksImageProvider();
|
virtual ~BooksImageProvider();
|
||||||
|
|
||||||
void addImage(QObject* aOwner, QString aId, shared_ptr<ZLImageData> aData);
|
void addImage(QObject* aOwner, QString aId, QImage aImage);
|
||||||
virtual QImage requestImage(const QString& aId, QSize* aSize,
|
virtual QImage requestImage(const QString& aId, QSize* aSize,
|
||||||
const QSize& aRequestedSize);
|
const QSize& aRequestedSize);
|
||||||
|
|
||||||
|
@ -60,7 +58,7 @@ public Q_SLOTS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMutex iMutex;
|
QMutex iMutex;
|
||||||
QHash<QString, shared_ptr<ZLImageData> > iImageMap;
|
QHash<QString, QImage> iImageMap;
|
||||||
QHash<QObject*, QStringList> iOwnerMap;
|
QHash<QObject*, QStringList> iOwnerMap;
|
||||||
static BooksImageProvider* gInstance;
|
static BooksImageProvider* gInstance;
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,12 +37,15 @@
|
||||||
#include "BooksDefs.h"
|
#include "BooksDefs.h"
|
||||||
|
|
||||||
#include "bookmodel/FBTextKind.h"
|
#include "bookmodel/FBTextKind.h"
|
||||||
|
#include "image/ZLQtImageManager.h"
|
||||||
#include "ZLStringUtil.h"
|
#include "ZLStringUtil.h"
|
||||||
|
|
||||||
#include "HarbourDebug.h"
|
#include "HarbourDebug.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
static const QString IMAGE_URL("image://%1/%2");
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// BooksPageWidget::Data
|
// BooksPageWidget::Data
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
@ -141,21 +144,110 @@ public:
|
||||||
shared_ptr<BooksPageWidget::Data> iData;
|
shared_ptr<BooksPageWidget::Data> iData;
|
||||||
int iWidth;
|
int iWidth;
|
||||||
int iHeight;
|
int iHeight;
|
||||||
shared_ptr<QImage> iImage;
|
QImage iImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
void BooksPageWidget::RenderTask::performTask()
|
void BooksPageWidget::RenderTask::performTask()
|
||||||
{
|
{
|
||||||
if (!isCanceled() && !iData.isNull() && !iData->iView.isNull() &&
|
if (!isCanceled() && !iData.isNull() && !iData->iView.isNull() &&
|
||||||
iWidth > 0 && iHeight > 0) {
|
iWidth > 0 && iHeight > 0) {
|
||||||
iImage = new QImage(iWidth, iHeight, QImage::Format_RGB32);
|
iImage = QImage(iWidth, iHeight, QImage::Format_RGB32);
|
||||||
if (!isCanceled()) {
|
if (!isCanceled()) {
|
||||||
QPainter painter(&*iImage);
|
QPainter painter(&iImage);
|
||||||
iData->paint(&painter);
|
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<ZLTextModel> aTextModel, shared_ptr<ZLTextStyle> 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<ZLTextStyle> baseStyle() const;
|
||||||
|
ZLColor color(const std::string& aStyle) const;
|
||||||
|
bool isSelectionEnabled() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
shared_ptr<ZLTextModel> iTextModel;
|
||||||
|
shared_ptr<ZLTextStyle> iTextStyle;
|
||||||
|
bool iInvertColors;
|
||||||
|
int iX;
|
||||||
|
int iY;
|
||||||
|
int iMaxWidth;
|
||||||
|
int iMaxHeight;
|
||||||
|
QString iRef;
|
||||||
|
QString iLinkText;
|
||||||
|
QString iPath;
|
||||||
|
QImage iImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
BooksPageWidget::FootnoteTask::~FootnoteTask()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<ZLTextStyle> 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
|
// BooksPageWidget::PressTask
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
@ -166,6 +258,7 @@ public:
|
||||||
iData(aData), iX(aX), iY(aY), iKind(REGULAR) {}
|
iData(aData), iX(aX), iY(aY), iKind(REGULAR) {}
|
||||||
|
|
||||||
void performTask();
|
void performTask();
|
||||||
|
QString getLinkText(ZLTextWordCursor& aCursor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shared_ptr<BooksPageWidget::Data> iData;
|
shared_ptr<BooksPageWidget::Data> iData;
|
||||||
|
@ -176,9 +269,27 @@ public:
|
||||||
std::string iLink;
|
std::string iLink;
|
||||||
std::string iLinkType;
|
std::string iLinkType;
|
||||||
std::string iImageId;
|
std::string iImageId;
|
||||||
shared_ptr<ZLImageData> 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()
|
void BooksPageWidget::PressTask::performTask()
|
||||||
{
|
{
|
||||||
if (!isCanceled()) {
|
if (!isCanceled()) {
|
||||||
|
@ -219,10 +330,12 @@ void BooksPageWidget::PressTask::performTask()
|
||||||
if (entry.isStart() && !stopped[entry.kind()]) {
|
if (entry.isStart() && !stopped[entry.kind()]) {
|
||||||
const ZLTextHyperlinkControlEntry& link =
|
const ZLTextHyperlinkControlEntry& link =
|
||||||
(ZLTextHyperlinkControlEntry&) entry;
|
(ZLTextHyperlinkControlEntry&) entry;
|
||||||
iKind = link.kind();
|
iKind = kind;
|
||||||
iLink = link.label();
|
iLink = link.label();
|
||||||
iLinkType = link.hyperlinkType();
|
iLinkType = link.hyperlinkType();
|
||||||
HDEBUG("link" << kind << iLink.c_str());
|
iLinkText = getLinkText(cursor);
|
||||||
|
HDEBUG("link" << kind << iLinkText <<
|
||||||
|
iLink.c_str());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -237,11 +350,17 @@ void BooksPageWidget::PressTask::performTask()
|
||||||
if (element.kind() == ZLTextElement::IMAGE_ELEMENT) {
|
if (element.kind() == ZLTextElement::IMAGE_ELEMENT) {
|
||||||
const ZLTextImageElement& imageElement =
|
const ZLTextImageElement& imageElement =
|
||||||
(const ZLTextImageElement&)element;
|
(const ZLTextImageElement&)element;
|
||||||
iKind = IMAGE;
|
shared_ptr<ZLImageData> data = imageElement.image();
|
||||||
iImageId = imageElement.id();
|
if (!data.isNull()) {
|
||||||
iImageData = imageElement.image();
|
const QImage* image = ((ZLQtImageData&)(*data)).image();
|
||||||
HDEBUG("image element" << iImageId.c_str() <<
|
if (image && !image->isNull()) {
|
||||||
iImageData->width() << iImageData->height());
|
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),
|
iRenderTask(NULL),
|
||||||
iPressTask(NULL),
|
iPressTask(NULL),
|
||||||
iLongPressTask(NULL),
|
iLongPressTask(NULL),
|
||||||
|
iFootnoteTask(NULL),
|
||||||
iEmpty(false),
|
iEmpty(false),
|
||||||
iPage(-1)
|
iPage(-1)
|
||||||
{
|
{
|
||||||
|
@ -287,6 +407,7 @@ BooksPageWidget::~BooksPageWidget()
|
||||||
if (iRenderTask) iRenderTask->release(this);
|
if (iRenderTask) iRenderTask->release(this);
|
||||||
if (iPressTask) iPressTask->release(this);
|
if (iPressTask) iPressTask->release(this);
|
||||||
if (iLongPressTask) iLongPressTask->release(this);
|
if (iLongPressTask) iLongPressTask->release(this);
|
||||||
|
if (iFootnoteTask) iFootnoteTask->release(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooksPageWidget::setModel(BooksBookModel* aModel)
|
void BooksPageWidget::setModel(BooksBookModel* aModel)
|
||||||
|
@ -443,7 +564,7 @@ void BooksPageWidget::paint(QPainter* aPainter)
|
||||||
{
|
{
|
||||||
if (!iImage.isNull()) {
|
if (!iImage.isNull()) {
|
||||||
HDEBUG("page" << iPage);
|
HDEBUG("page" << iPage);
|
||||||
aPainter->drawImage(0, 0, *iImage);
|
aPainter->drawImage(0, 0, iImage);
|
||||||
iEmpty = false;
|
iEmpty = false;
|
||||||
} else if (iPage >= 0 && iPageMark.valid() && !iData.isNull()) {
|
} else if (iPage >= 0 && iPageMark.valid() && !iData.isNull()) {
|
||||||
if (!iRenderTask) {
|
if (!iRenderTask) {
|
||||||
|
@ -471,6 +592,18 @@ void BooksPageWidget::resetView()
|
||||||
iResetTask->release(this);
|
iResetTask->release(this);
|
||||||
iResetTask = NULL;
|
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();
|
iData.reset();
|
||||||
if (iPage >= 0 && iPageMark.valid() &&
|
if (iPage >= 0 && iPageMark.valid() &&
|
||||||
width() > 0 && height() > 0 && iModel) {
|
width() > 0 && height() > 0 && iModel) {
|
||||||
|
@ -547,6 +680,31 @@ void BooksPageWidget::onPressTaskDone()
|
||||||
task->release(this);
|
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()
|
void BooksPageWidget::onLongPressTaskDone()
|
||||||
{
|
{
|
||||||
HASSERT(sender() == iLongPressTask);
|
HASSERT(sender() == iLongPressTask);
|
||||||
|
@ -571,28 +729,46 @@ void BooksPageWidget::onLongPressTaskDone()
|
||||||
Q_EMIT jumpToPage(page);
|
Q_EMIT jumpToPage(page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (task->iKind == FOOTNOTE) {
|
||||||
|
if (iModel && task->iLink.length() > 0) {
|
||||||
|
std::string ref = task->iLink.substr(1);
|
||||||
|
shared_ptr<ZLTextModel> 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) {
|
} else if (task->iKind == IMAGE) {
|
||||||
// Make sure that the book path is mixed into the image id to handle
|
// Make sure that the book path is mixed into the image id to handle
|
||||||
// the case of different books having images with identical ids
|
// the case of different books having images with identical ids
|
||||||
QString id = QString::fromStdString(task->iImageId);
|
QString imageId = QString::fromStdString(task->iImageId);
|
||||||
QString path;
|
QString path;
|
||||||
if (iModel) {
|
if (iModel) {
|
||||||
BooksBook* book = iModel->book();
|
BooksBook* book = iModel->book();
|
||||||
if (book) {
|
if (book) {
|
||||||
path = book->path();
|
path = book->path();
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
if (!id.contains(path)) {
|
if (!imageId.contains(path)) {
|
||||||
QString old = id;
|
QString old = imageId;
|
||||||
id = path + ":" + old;
|
imageId = path + ":" + old;
|
||||||
HDEBUG(old << "-> " << id);
|
HDEBUG(old << "-> " << imageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static const QString IMAGE_URL("image://%1/%2");
|
static const QString IMAGE_ID("image/%1");
|
||||||
QString url = IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id);
|
QString id = IMAGE_ID.arg(imageId);
|
||||||
BooksImageProvider::instance()->addImage(iModel, id, task->iImageData);
|
BooksImageProvider::instance()->addImage(iModel, id, task->iImage);
|
||||||
Q_EMIT imagePressed(url, task->iRect);
|
Q_EMIT imagePressed(IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id),
|
||||||
|
task->iRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
task->release(this);
|
task->release(this);
|
||||||
|
@ -601,7 +777,7 @@ void BooksPageWidget::onLongPressTaskDone()
|
||||||
void BooksPageWidget::updateSize()
|
void BooksPageWidget::updateSize()
|
||||||
{
|
{
|
||||||
HDEBUG("page" << iPage << QSize(width(), height()));
|
HDEBUG("page" << iPage << QSize(width(), height()));
|
||||||
iImage.reset();
|
iImage = QImage();
|
||||||
resetView();
|
resetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,9 +97,10 @@ Q_SIGNALS:
|
||||||
void topMarginChanged();
|
void topMarginChanged();
|
||||||
void bottomMarginChanged();
|
void bottomMarginChanged();
|
||||||
void browserLinkPressed(QString url);
|
void browserLinkPressed(QString url);
|
||||||
void imagePressed(QString url, QRect rect);
|
void imagePressed(QString imageId, QRect rect);
|
||||||
void activeTouch(int x, int y);
|
void activeTouch(int touchX, int touchY);
|
||||||
void jumpToPage(int page);
|
void jumpToPage(int page);
|
||||||
|
void showFootnote(int touchX, int touchY, QString text, QString imageId);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onWidthChanged();
|
void onWidthChanged();
|
||||||
|
@ -115,6 +116,7 @@ private Q_SLOTS:
|
||||||
void onRenderTaskDone();
|
void onRenderTaskDone();
|
||||||
void onPressTaskDone();
|
void onPressTaskDone();
|
||||||
void onLongPressTaskDone();
|
void onLongPressTaskDone();
|
||||||
|
void onFootnoteTaskDone();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paint(QPainter *painter);
|
void paint(QPainter *painter);
|
||||||
|
@ -128,6 +130,7 @@ private:
|
||||||
class ResetTask;
|
class ResetTask;
|
||||||
class RenderTask;
|
class RenderTask;
|
||||||
class PressTask;
|
class PressTask;
|
||||||
|
class FootnoteTask;
|
||||||
|
|
||||||
QSharedPointer<BooksSettings> iSettings;
|
QSharedPointer<BooksSettings> iSettings;
|
||||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||||
|
@ -137,11 +140,12 @@ private:
|
||||||
BooksBookModel* iModel;
|
BooksBookModel* iModel;
|
||||||
BooksMargins iMargins;
|
BooksMargins iMargins;
|
||||||
shared_ptr<Data> iData;
|
shared_ptr<Data> iData;
|
||||||
shared_ptr<QImage> iImage;
|
QImage iImage;
|
||||||
ResetTask* iResetTask;
|
ResetTask* iResetTask;
|
||||||
RenderTask* iRenderTask;
|
RenderTask* iRenderTask;
|
||||||
PressTask* iPressTask;
|
PressTask* iPressTask;
|
||||||
PressTask* iLongPressTask;
|
PressTask* iLongPressTask;
|
||||||
|
FootnoteTask* iFootnoteTask;
|
||||||
bool iEmpty;
|
bool iEmpty;
|
||||||
int iPage;
|
int iPage;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -36,6 +36,8 @@
|
||||||
#include "HarbourDebug.h"
|
#include "HarbourDebug.h"
|
||||||
|
|
||||||
#include "ZLImage.h"
|
#include "ZLImage.h"
|
||||||
|
#include "ZLTextStyle.h"
|
||||||
|
#include "ZLStringUtil.h"
|
||||||
#include "image/ZLQtImageManager.h"
|
#include "image/ZLQtImageManager.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@ -255,9 +257,45 @@ int BooksPaintContext::height() const
|
||||||
return iHeight;
|
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(255-aRed, 255-aGreen, 255-aBlue) :
|
||||||
ZLColor(aRed, aGreen, 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);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* 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 drawFilledCircle(int x, int y, int r);
|
||||||
|
|
||||||
void setInvertColors(bool aInvertColors);
|
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(quint8 aRed, quint8 aGreen, quint8 aBlue) const;
|
||||||
ZLColor realColor(const ZLColor aColor) 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); }
|
{ return QColor(aColor.Red, aColor.Green, aColor.Blue); }
|
||||||
inline ZLColor BooksPaintContext::realColor(const ZLColor aColor) const
|
inline ZLColor BooksPaintContext::realColor(const ZLColor aColor) const
|
||||||
{ return realColor(aColor.Red, aColor.Green, aColor.Blue); }
|
{ 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)
|
inline void BooksPaintContext::setInvertColors(bool aInvertColors)
|
||||||
{ iInvertColors = aInvertColors; }
|
{ iInvertColors = aInvertColors; }
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ class BooksSettings : public QObject
|
||||||
Q_PROPERTY(QString removableRoot READ removableRoot NOTIFY removableRootChanged)
|
Q_PROPERTY(QString removableRoot READ removableRoot NOTIFY removableRootChanged)
|
||||||
Q_PROPERTY(QColor primaryPageToolColor READ primaryPageToolColor CONSTANT)
|
Q_PROPERTY(QColor primaryPageToolColor READ primaryPageToolColor CONSTANT)
|
||||||
Q_PROPERTY(QColor highlightPageToolColor READ highlightPageToolColor NOTIFY invertColorsChanged)
|
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(QColor pageBackgroundColor READ pageBackgroundColor NOTIFY pageBackgroundColorChanged)
|
||||||
Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged)
|
Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged)
|
||||||
class TextStyle;
|
class TextStyle;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -34,8 +34,6 @@
|
||||||
#include "BooksTextView.h"
|
#include "BooksTextView.h"
|
||||||
#include "BooksTextStyle.h"
|
#include "BooksTextStyle.h"
|
||||||
|
|
||||||
#include "ZLStringUtil.h"
|
|
||||||
|
|
||||||
#define SUPER ZLTextView
|
#define SUPER ZLTextView
|
||||||
|
|
||||||
const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255);
|
const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255);
|
||||||
|
@ -87,40 +85,9 @@ ZLColor BooksTextView::backgroundColor() const
|
||||||
return iPaintContext.realColor(DEFAULT_BACKGROUND);
|
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");
|
return iPaintContext.realColor(aStyle);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyle> BooksTextView::baseStyle() const
|
shared_ptr<ZLTextStyle> BooksTextView::baseStyle() const
|
||||||
|
|
Loading…
Reference in a new issue