[app] Implemented text selection (whole words)
The selected text is getting copied to clipboard.
This commit is contained in:
parent
a48fe1d0e4
commit
89775f269e
6 changed files with 432 additions and 54 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue