[app] Implemented text selection (whole words)

The selected text is getting copied to clipboard.
This commit is contained in:
Slava Monich 2017-09-07 19:03:17 +03:00
parent a48fe1d0e4
commit 89775f269e
6 changed files with 432 additions and 54 deletions

View file

@ -41,6 +41,7 @@ SilicaFlickable {
id: root id: root
property variant book property variant book
property bool selecting
signal closeBook() signal closeBook()
signal pageClicked(var page) signal pageClicked(var page)
@ -56,7 +57,8 @@ SilicaFlickable {
{ pager: true, page: true, title: true, tools: true } { pager: true, page: true, title: true, tools: true }
] ]
interactive: (!linkMenu || !linkMenu.visible) && interactive: !selecting &&
(!linkMenu || !linkMenu.visible) &&
(!imageView || !imageView.visible) && (!imageView || !imageView.visible) &&
(!footnoteView || !footnoteView.visible) (!footnoteView || !footnoteView.visible)
@ -168,6 +170,7 @@ SilicaFlickable {
} }
delegate: BooksPageView { delegate: BooksPageView {
id: pageView
width: bookView.width width: bookView.width
height: bookView.height height: bookView.height
model: bookModel model: bookModel
@ -180,15 +183,26 @@ SilicaFlickable {
rightSpaceReserved: pageTools.visible ? pageTools.rightSpaceUsed: 0 rightSpaceReserved: pageTools.visible ? pageTools.rightSpaceUsed: 0
titleVisible: _currentState.title titleVisible: _currentState.title
pageNumberVisible: _currentState.page pageNumberVisible: _currentState.page
currentPage: bookViewWatcher.currentIndex == index
title: bookModel.title title: bookModel.title
onJumpToPage: bookView.jumpTo(page) onJumpToPage: bookView.jumpTo(page)
onPushPosition: stackModel.pushPosition(position) // bookView.jumpTo(page) onPushPosition: stackModel.pushPosition(position) // bookView.jumpTo(page)
onCurrentPageChanged: {
if (currentPage) {
root.selecting = pageView.selecting
}
}
onSelectingChanged: {
if (currentPage) {
root.selecting = pageView.selecting
}
}
onPageClicked: { onPageClicked: {
root.pageClicked(index) root.pageClicked(index)
Settings.pageDetails = (Settings.pageDetails + 1) % _visibilityStates.length Settings.pageDetails = (Settings.pageDetails + 1) % _visibilityStates.length
} }
onImagePressed: { onImagePressed: {
if (bookViewWatcher.currentIndex == index) { if (currentPage) {
if (!imageView) { if (!imageView) {
imageView = imageViewComponent.createObject(root) imageView = imageViewComponent.createObject(root)
} }
@ -196,7 +210,7 @@ SilicaFlickable {
} }
} }
onBrowserLinkPressed: { onBrowserLinkPressed: {
if (bookViewWatcher.currentIndex == index) { if (currentPage) {
if (!linkMenu) { if (!linkMenu) {
linkMenu = linkMenuComponent.createObject(root) linkMenu = linkMenuComponent.createObject(root)
} }

View file

@ -43,6 +43,8 @@ Item {
property alias rightMargin: widget.rightMargin property alias rightMargin: widget.rightMargin
property alias topMargin: widget.topMargin property alias topMargin: widget.topMargin
property alias bottomMargin: widget.bottomMargin property alias bottomMargin: widget.bottomMargin
property alias selecting: widget.selecting
property alias currentPage: widget.currentPage
property alias title: titleLabel.text property alias title: titleLabel.text
property real leftSpaceReserved property real leftSpaceReserved
property real rightSpaceReserved property real rightSpaceReserved
@ -60,6 +62,7 @@ Item {
id: widget id: widget
anchors.fill: parent anchors.fill: parent
model: bookModel model: bookModel
pressed: mouseArea.pressed
onBrowserLinkPressed: view.browserLinkPressed(url) onBrowserLinkPressed: view.browserLinkPressed(url)
onImagePressed: view.imagePressed(imageId, rect) onImagePressed: view.imagePressed(imageId, rect)
onActiveTouch: pressImage.animate(touchX, touchY) onActiveTouch: pressImage.animate(touchX, touchY)
@ -156,9 +159,17 @@ Item {
} }
MouseArea { MouseArea {
id: mouseArea
anchors.fill: parent anchors.fill: parent
onClicked: view.pageClicked() onClicked: {
if (widget.selectionEmpty) {
view.pageClicked()
} else {
widget.clearSelection()
}
}
onPressed: widget.handlePress(mouseX, mouseY) onPressed: widget.handlePress(mouseX, mouseY)
onPressAndHold: widget.handleLongPress(mouseX, mouseY) onPressAndHold: widget.handleLongPress(mouseX, mouseY)
onPositionChanged: widget.handlePositionChanged(mouseX, mouseY)
} }
} }

View file

@ -42,6 +42,8 @@
#include "HarbourDebug.h" #include "HarbourDebug.h"
#include <QGuiApplication>
#include <QClipboard>
#include <QPainter> #include <QPainter>
static const QString IMAGE_URL("image://%1/%2"); static const QString IMAGE_URL("image://%1/%2");
@ -136,7 +138,7 @@ void BooksPageWidget::ResetTask::performTask()
class BooksPageWidget::RenderTask : public BooksTask { class BooksPageWidget::RenderTask : public BooksTask {
public: public:
RenderTask(shared_ptr<BooksPageWidget::Data> aData, int aWidth, int aHeight) : RenderTask(shared_ptr<BooksPageWidget::Data> aData, int aWidth, int aHeight) :
iData(aData), iWidth(aWidth), iHeight(aHeight), iImage(NULL) {} iData(aData), iWidth(aWidth), iHeight(aHeight) {}
void performTask(); void performTask();
@ -159,6 +161,119 @@ void BooksPageWidget::RenderTask::performTask()
} }
} }
// ==========================================================================
// BooksPageWidget::ClearSelectionTask
// ==========================================================================
class BooksPageWidget::ClearSelectionTask : public BooksTask {
public:
ClearSelectionTask(shared_ptr<BooksPageWidget::Data> aData, int aWidth,
int aHeight) : iData(aData), iWidth(aWidth), iHeight(aHeight),
iImageUpdated(false) {}
void performTask();
public:
shared_ptr<BooksPageWidget::Data> iData;
int iWidth;
int iHeight;
QImage iImage;
bool iImageUpdated;
};
void BooksPageWidget::ClearSelectionTask::performTask()
{
iData->iView->endSelection();
if (!isCanceled() && iWidth > 0 && iHeight > 0) {
const ZLTextArea& area = iData->iView->textArea();
if (!area.selectionIsEmpty()) {
area.clearSelection();
iImage = QImage(iWidth, iHeight, QImage::Format_RGB32);
if (!isCanceled()) {
QPainter painter(&iImage);
iData->paint(&painter);
iImageUpdated = true;
}
}
}
}
// ==========================================================================
// BooksPageWidget::StartSelectionTask
// ==========================================================================
class BooksPageWidget::StartSelectionTask : public BooksTask {
public:
StartSelectionTask(shared_ptr<BooksPageWidget::Data> aData, int aX, int aY,
int aWidth, int aHeight) : iData(aData), iX(aX), iY(aY),
iWidth(aWidth), iHeight(aHeight), iSelectionEmpty(true) {}
void performTask();
public:
shared_ptr<BooksPageWidget::Data> iData;
int iX;
int iY;
int iWidth;
int iHeight;
QImage iImage;
bool iSelectionEmpty;
};
void BooksPageWidget::StartSelectionTask::performTask()
{
if (!isCanceled() && iWidth > 0 && iHeight > 0) {
iData->iView->startSelection(iX, iY);
iSelectionEmpty = iData->iView->textArea().selectionIsEmpty();
if (!isCanceled()) {
iImage = QImage(iWidth, iHeight, QImage::Format_RGB32);
if (!isCanceled()) {
QPainter painter(&iImage);
iData->paint(&painter);
}
}
}
}
// ==========================================================================
// BooksPageWidget::ExtendSelectionTask
// ==========================================================================
class BooksPageWidget::ExtendSelectionTask : public BooksTask {
public:
ExtendSelectionTask(shared_ptr<BooksPageWidget::Data> aData, int aX, int aY,
int aWidth, int aHeight) : iData(aData), iX(aX), iY(aY),
iWidth(aWidth), iHeight(aHeight), iSelectionChanged(false),
iSelectionEmpty(true) {}
void performTask();
public:
shared_ptr<BooksPageWidget::Data> iData;
int iX;
int iY;
int iWidth;
int iHeight;
QImage iImage;
bool iSelectionChanged;
bool iSelectionEmpty;
};
void BooksPageWidget::ExtendSelectionTask::performTask()
{
if (!isCanceled() && iWidth > 0 && iHeight > 0) {
iSelectionChanged = iData->iView->extendSelection(iX, iY);
iSelectionEmpty = iData->iView->textArea().selectionIsEmpty();
if (iSelectionChanged && !isCanceled()) {
iImage = QImage(iWidth, iHeight, QImage::Format_RGB32);
if (!isCanceled()) {
QPainter painter(&iImage);
iData->paint(&painter);
}
}
}
}
// ========================================================================== // ==========================================================================
// BooksPageWidget::FootnoteTask // BooksPageWidget::FootnoteTask
// ========================================================================== // ==========================================================================
@ -380,10 +495,16 @@ BooksPageWidget::BooksPageWidget(QQuickItem* aParent) :
iModel(NULL), iModel(NULL),
iResetTask(NULL), iResetTask(NULL),
iRenderTask(NULL), iRenderTask(NULL),
iClearSelectionTask(NULL),
iStartSelectionTask(NULL),
iPressTask(NULL), iPressTask(NULL),
iLongPressTask(NULL), iLongPressTask(NULL),
iFootnoteTask(NULL), iFootnoteTask(NULL),
iEmpty(false), iEmpty(false),
iPressed(false),
iSelecting(false),
iSelectionEmpty(true),
iCurrentPage(false),
iPage(-1) iPage(-1)
{ {
connect(iSettings.data(), connect(iSettings.data(),
@ -403,13 +524,48 @@ BooksPageWidget::BooksPageWidget(QQuickItem* aParent) :
BooksPageWidget::~BooksPageWidget() BooksPageWidget::~BooksPageWidget()
{ {
HDEBUG("page" << iPage); HDEBUG("page" << iPage);
releaseExtendSelectionTasks();
if (iResetTask) iResetTask->release(this); if (iResetTask) iResetTask->release(this);
if (iRenderTask) iRenderTask->release(this); if (iRenderTask) iRenderTask->release(this);
if (iClearSelectionTask) iClearSelectionTask->release(this);
if (iStartSelectionTask) iStartSelectionTask->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); if (iFootnoteTask) iFootnoteTask->release(this);
} }
void BooksPageWidget::releaseExtendSelectionTasks()
{
while (!iExtendSelectionTasks.isEmpty()) {
const int i = iExtendSelectionTasks.count()-1;
iExtendSelectionTasks.at(i)->release(this);
iExtendSelectionTasks.removeAt(i);
}
}
void BooksPageWidget::setPressed(bool aPressed)
{
if (iPressed != aPressed) {
iPressed = aPressed;
if (!iPressed && iSelecting) {
HDEBUG("leaving selection mode");
iSelecting = false;
Q_EMIT selectingChanged();
}
Q_EMIT pressedChanged();
}
}
void BooksPageWidget::setCurrentPage(bool aCurrentPage)
{
if (iCurrentPage != aCurrentPage) {
iCurrentPage = aCurrentPage;
HDEBUG(iCurrentPage);
if (!iCurrentPage) clearSelection();
Q_EMIT currentPageChanged();
}
}
void BooksPageWidget::setModel(BooksBookModel* aModel) void BooksPageWidget::setModel(BooksBookModel* aModel)
{ {
if (iModel != aModel) { if (iModel != aModel) {
@ -582,7 +738,7 @@ void BooksPageWidget::paint(QPainter* aPainter)
bool BooksPageWidget::loading() const bool BooksPageWidget::loading() const
{ {
return iPage >= 0 && (iResetTask || iRenderTask); return iPage >= 0 && iImage.isNull() && (iResetTask || iRenderTask);
} }
void BooksPageWidget::resetView() void BooksPageWidget::resetView()
@ -680,6 +836,75 @@ void BooksPageWidget::onPressTaskDone()
task->release(this); task->release(this);
} }
void BooksPageWidget::onClearSelectionTaskDone()
{
HASSERT(sender() == iClearSelectionTask);
ClearSelectionTask* task = iClearSelectionTask;
iClearSelectionTask = NULL;
if (!iSelectionEmpty) {
iSelectionEmpty = true;
HDEBUG("selection cleared");
Q_EMIT selectionEmptyChanged();
}
if (task->iImageUpdated) {
iImage = task->iImage;
update();
}
task->release(this);
}
void BooksPageWidget::onStartSelectionTaskDone()
{
HASSERT(sender() == iStartSelectionTask);
StartSelectionTask* task = iStartSelectionTask;
iStartSelectionTask = NULL;
if (iPressed) {
iImage = task->iImage;
// Emit signals when we are in a consistent state
bool emitSelectionEmpty;
if (iSelectionEmpty != task->iSelectionEmpty) {
iSelectionEmpty = task->iSelectionEmpty;
HDEBUG("selection" << iSelectionEmpty);
emitSelectionEmpty = true;
}
if (!iSelecting) {
iSelecting = true;
HDEBUG("entering selection mode");
Q_EMIT selectingChanged();
}
if (emitSelectionEmpty) {
Q_EMIT selectionEmptyChanged();
}
update();
}
task->release(this);
}
void BooksPageWidget::onExtendSelectionTaskDone()
{
ExtendSelectionTask* task = (ExtendSelectionTask*)sender();
HASSERT(iExtendSelectionTasks.contains(task));
iExtendSelectionTasks.removeOne(task);
if (iSelecting && task->iSelectionChanged) {
iImage = task->iImage;
if (iSelectionEmpty != task->iSelectionEmpty) {
iSelectionEmpty = task->iSelectionEmpty;
HDEBUG("selection" << iSelectionEmpty);
Q_EMIT selectionEmptyChanged();
}
update();
}
task->release(this);
}
void BooksPageWidget::onFootnoteTaskDone() void BooksPageWidget::onFootnoteTaskDone()
{ {
HASSERT(sender() == iFootnoteTask); HASSERT(sender() == iFootnoteTask);
@ -769,6 +994,12 @@ void BooksPageWidget::onLongPressTaskDone()
BooksImageProvider::instance()->addImage(iModel, id, task->iImage); BooksImageProvider::instance()->addImage(iModel, id, task->iImage);
Q_EMIT imagePressed(IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id), Q_EMIT imagePressed(IMAGE_URL.arg(BooksImageProvider::PROVIDER_ID, id),
task->iRect); task->iRect);
} else if (!iData.isNull()) {
if (iStartSelectionTask) iStartSelectionTask->release(this);
iStartSelectionTask = new StartSelectionTask(iData,
task->iX, task->iY, width(), height());
iTaskQueue->submit(iStartSelectionTask, this,
SLOT(onStartSelectionTaskDone()));
} }
task->release(this); task->release(this);
@ -813,8 +1044,8 @@ void BooksPageWidget::handleLongPress(int aX, int aY)
HDEBUG(aX << aY); HDEBUG(aX << aY);
if (!iResetTask && !iRenderTask && !iData.isNull()) { if (!iResetTask && !iRenderTask && !iData.isNull()) {
if (iLongPressTask) iLongPressTask->release(this); if (iLongPressTask) iLongPressTask->release(this);
iLongPressTask = new PressTask(iData, aX, aY); iTaskQueue->submit(iLongPressTask = new PressTask(iData, aX, aY),
iTaskQueue->submit(iLongPressTask, this, SLOT(onLongPressTaskDone())); this, SLOT(onLongPressTaskDone()));
} }
} }
@ -823,7 +1054,50 @@ void BooksPageWidget::handlePress(int aX, int aY)
HDEBUG(aX << aY); HDEBUG(aX << aY);
if (!iResetTask && !iRenderTask && !iData.isNull()) { if (!iResetTask && !iRenderTask && !iData.isNull()) {
if (iPressTask) iPressTask->release(this); if (iPressTask) iPressTask->release(this);
iPressTask = new PressTask(iData, aX, aY); iTaskQueue->submit(iPressTask = new PressTask(iData, aX, aY),
iTaskQueue->submit(iPressTask, this, SLOT(onPressTaskDone())); this, SLOT(onPressTaskDone()));
}
}
void BooksPageWidget::handlePositionChanged(int aX, int aY)
{
if (iSelecting && !iData.isNull()) {
HDEBUG(aX << aY);
// Drop the tasks which haven't been started yet
ExtendSelectionTask* task;
for (int i = iExtendSelectionTasks.count()-1; i>=0; i--) {
task = iExtendSelectionTasks.at(i);
if (task->isStarted()) {
break;
} else {
task->release(this);
iExtendSelectionTasks.removeAt(i);
HDEBUG("dropped queued task," << i << "left");
}
}
task = new ExtendSelectionTask(iData, aX, aY, width(), height());
iTaskQueue->submit(task, this, SLOT(onExtendSelectionTaskDone()));
iExtendSelectionTasks.append(task);
} else {
// Finger was moved before we entered selection mode
if (iStartSelectionTask) {
iStartSelectionTask->release(this);
iStartSelectionTask = NULL;
HDEBUG("oops");
}
}
}
void BooksPageWidget::clearSelection()
{
if (!iData.isNull()) {
if (iClearSelectionTask) iClearSelectionTask->release(this);
iTaskQueue->submit(iClearSelectionTask =
new ClearSelectionTask(iData, width(), height()),
this, SLOT(onClearSelectionTaskDone()));
}
if (iSelecting) {
iSelecting = false;
Q_EMIT selectingChanged();
} }
} }

View file

@ -47,11 +47,16 @@
#include <QQuickPaintedItem> #include <QQuickPaintedItem>
#include <QTimer> #include <QTimer>
#include <QList>
class BooksPageWidget: public QQuickPaintedItem, private BooksLoadingProperty class BooksPageWidget: public QQuickPaintedItem, private BooksLoadingProperty
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged) Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
Q_PROPERTY(bool selecting READ selecting NOTIFY selectingChanged)
Q_PROPERTY(bool selectionEmpty READ selectionEmpty NOTIFY selectionEmptyChanged)
Q_PROPERTY(bool pressed READ pressed WRITE setPressed NOTIFY pressedChanged)
Q_PROPERTY(bool currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged) Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged) Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
@ -62,34 +67,48 @@ class BooksPageWidget: public QQuickPaintedItem, private BooksLoadingProperty
public: public:
class Data; class Data;
BooksPageWidget(QQuickItem* aParent = NULL); explicit BooksPageWidget(QQuickItem* aParent = NULL);
~BooksPageWidget(); ~BooksPageWidget();
bool loading() const; bool loading() const;
bool selecting() const;
bool selectionEmpty() const;
int page() const { return iPage; } bool pressed() const;
void setPressed(bool aPressed);
bool currentPage() const;
void setCurrentPage(bool aCurrentPage);
int page() const;
void setPage(int aPage); void setPage(int aPage);
BooksBookModel* model() const { return iModel; } BooksBookModel* model() const;
void setModel(BooksBookModel* aModel); void setModel(BooksBookModel* aModel);
int leftMargin() const { return iMargins.iLeft; } int leftMargin() const;
int rightMargin() const { return iMargins.iRight; } int rightMargin() const;
int topMargin() const { return iMargins.iTop; } int topMargin() const;
int bottomMargin() const { return iMargins.iBottom; } int bottomMargin() const;
void setLeftMargin(int aMargin); void setLeftMargin(int aMargin);
void setRightMargin(int aMargin); void setRightMargin(int aMargin);
void setTopMargin(int aMargin); void setTopMargin(int aMargin);
void setBottomMargin(int aMargin); void setBottomMargin(int aMargin);
BooksMargins margins() const { return iMargins; } BooksMargins margins() const;
Q_INVOKABLE void handleLongPress(int aX, int aY);
Q_INVOKABLE void handlePress(int aX, int aY); Q_INVOKABLE void handlePress(int aX, int aY);
Q_INVOKABLE void handleLongPress(int aX, int aY);
Q_INVOKABLE void handlePositionChanged(int aX, int aY);
Q_INVOKABLE void clearSelection();
Q_SIGNALS: Q_SIGNALS:
void loadingChanged(); void loadingChanged();
void pressedChanged();
void selectingChanged();
void selectionEmptyChanged();
void currentPageChanged();
void pageChanged(); void pageChanged();
void modelChanged(); void modelChanged();
void leftMarginChanged(); void leftMarginChanged();
@ -115,6 +134,9 @@ private Q_SLOTS:
void onInvertColorsChanged(); void onInvertColorsChanged();
void onResetTaskDone(); void onResetTaskDone();
void onRenderTaskDone(); void onRenderTaskDone();
void onClearSelectionTaskDone();
void onStartSelectionTaskDone();
void onExtendSelectionTaskDone();
void onPressTaskDone(); void onPressTaskDone();
void onLongPressTaskDone(); void onLongPressTaskDone();
void onFootnoteTaskDone(); void onFootnoteTaskDone();
@ -123,6 +145,7 @@ private:
void paint(QPainter *painter); void paint(QPainter *painter);
void updateSize(); void updateSize();
void resetView(); void resetView();
void releaseExtendSelectionTasks();
void scheduleRepaint(); void scheduleRepaint();
void cancelRepaint(); void cancelRepaint();
bool invertColors() const; bool invertColors() const;
@ -131,6 +154,9 @@ private:
class ResetTask; class ResetTask;
class RenderTask; class RenderTask;
class PressTask; class PressTask;
class ClearSelectionTask;
class StartSelectionTask;
class ExtendSelectionTask;
class FootnoteTask; class FootnoteTask;
QSharedPointer<BooksSettings> iSettings; QSharedPointer<BooksSettings> iSettings;
@ -144,13 +170,42 @@ private:
QImage iImage; QImage iImage;
ResetTask* iResetTask; ResetTask* iResetTask;
RenderTask* iRenderTask; RenderTask* iRenderTask;
ClearSelectionTask* iClearSelectionTask;
StartSelectionTask* iStartSelectionTask;
QList<ExtendSelectionTask*> iExtendSelectionTasks;
PressTask* iPressTask; PressTask* iPressTask;
PressTask* iLongPressTask; PressTask* iLongPressTask;
FootnoteTask* iFootnoteTask; FootnoteTask* iFootnoteTask;
bool iEmpty; bool iEmpty;
bool iPressed;
bool iSelecting;
bool iSelectionEmpty;
bool iCurrentPage;
int iPage; int iPage;
}; };
inline bool BooksPageWidget::pressed() const
{ return iPressed; }
inline bool BooksPageWidget::selecting() const
{ return iSelecting; }
inline bool BooksPageWidget::selectionEmpty() const
{ return iSelectionEmpty; }
inline bool BooksPageWidget::currentPage() const
{ return iCurrentPage; }
inline int BooksPageWidget::page() const
{ return iPage; }
inline BooksBookModel* BooksPageWidget::model() const
{ return iModel; }
inline int BooksPageWidget::leftMargin() const
{ return iMargins.iLeft; }
inline int BooksPageWidget::rightMargin() const
{ return iMargins.iRight; }
inline int BooksPageWidget::topMargin() const
{ return iMargins.iTop; }
inline int BooksPageWidget::bottomMargin() const
{ return iMargins.iBottom; }
inline BooksMargins BooksPageWidget::margins() const
{ return iMargins; }
inline bool BooksPageWidget::invertColors() const inline bool BooksPageWidget::invertColors() const
{ return iSettings && iSettings->invertColors(); } { return iSettings && iSettings->invertColors(); }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015-2016 Jolla Ltd. * Copyright (C) 2015-2017 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:
@ -14,7 +14,7 @@
* notice, this list of conditions and the following disclaimer in * notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the * the documentation and/or other materials provided with the
* distribution. * 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 * may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* *
@ -34,6 +34,8 @@
#include "BooksTextView.h" #include "BooksTextView.h"
#include "BooksTextStyle.h" #include "BooksTextStyle.h"
#include "ZLTextSelectionModel.h"
#define SUPER ZLTextView #define SUPER ZLTextView
const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255); const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255);
@ -97,12 +99,12 @@ shared_ptr<ZLTextStyle> BooksTextView::baseStyle() const
bool BooksTextView::isSelectionEnabled() const bool BooksTextView::isSelectionEnabled() const
{ {
return false; return true;
} }
int BooksTextView::doubleClickDelay() const int BooksTextView::doubleClickDelay() const
{ {
return isSelectionEnabled() ? 200 : 0; return 0;
} }
shared_ptr<ZLTextPositionIndicatorInfo> BooksTextView::indicatorInfo() const shared_ptr<ZLTextPositionIndicatorInfo> BooksTextView::indicatorInfo() const
@ -140,3 +142,22 @@ void BooksTextView::gotoPosition(const BooksPos& aPos)
SUPER::gotoPosition(aPos.iParagraphIndex, aPos.iElementIndex, SUPER::gotoPosition(aPos.iParagraphIndex, aPos.iElementIndex,
aPos.iCharIndex); aPos.iCharIndex);
} }
void BooksTextView::startSelection(int aX, int aY)
{
if (!selectionModel().selectWord(textArea().realX(aX), aY, true)) {
// There's no text where we have clicked
activateSelection(aX, aY);
}
}
bool BooksTextView::extendSelection(int aX, int aY)
{
return selectionModel().extendTo(textArea().realX(aX), aY, true) ==
ZLTextSelectionModel::BOUND_CHANGED;
}
void BooksTextView::endSelection()
{
selectionModel().deactivate();
}

View file

@ -1,35 +1,35 @@
/* /*
Copyright (C) 2015 Jolla Ltd. * Copyright (C) 2015-2017 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:
*
Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
are met: * are met:
*
* Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in * notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the * the documentation and/or other materials provided with the
distribution. * 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 * may be used to endorse or promote products derived from this
software without specific prior written permission. * software without specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef BOOKS_TEXT_VIEW_H #ifndef BOOKS_TEXT_VIEW_H
#define BOOKS_TEXT_VIEW_H #define BOOKS_TEXT_VIEW_H
@ -57,6 +57,9 @@ public:
public: public:
BooksPos position() const; BooksPos position() const;
const BooksPos rewind(); const BooksPos rewind();
void startSelection(int aX, int aY);
bool extendSelection(int aX, int aY);
void endSelection();
void setInvertColors(bool aInvertColors); void setInvertColors(bool aInvertColors);
void gotoPosition(const BooksPos& aPos); void gotoPosition(const BooksPos& aPos);
bool nextPage(); bool nextPage();