mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-02-28 17:37:46 +01:00
Tool for text selection (first part)
This commit is contained in:
parent
7ad4c46124
commit
95f6135482
@ -227,3 +227,11 @@ qt_libraries.files = $$[QT_INSTALL_BINS]/Qt?Widgets$${SUFFIX}.dll \
|
||||
$$[QT_INSTALL_BINS]/Qt?Svg$${SUFFIX}.dll
|
||||
qt_libraries.path = $$DESTDIR/install
|
||||
INSTALLS += qt_libraries
|
||||
|
||||
qt_plugin_platform.files = $$[QT_INSTALL_PLUGINS]/platforms/qwindows$${SUFFIX}.dll
|
||||
qt_plugin_platform.path = $$DESTDIR/install/platforms
|
||||
INSTALLS += qt_plugin_platform
|
||||
|
||||
qt_plugin_iconengine.files = $$[QT_INSTALL_PLUGINS]/iconengines/qsvgicon$${SUFFIX}.dll
|
||||
qt_plugin_iconengine.path = $$DESTDIR/install/iconengines
|
||||
INSTALLS += qt_plugin_iconengine
|
||||
|
@ -784,6 +784,31 @@ std::vector<PDFInteger> PDFDrawWidgetProxy::getPagesIntersectingRect(QRect rect)
|
||||
return pages;
|
||||
}
|
||||
|
||||
PDFInteger PDFDrawWidgetProxy::getPageUnderPoint(QPoint point, QPointF* pagePoint) const
|
||||
{
|
||||
// Iterate trough pages, place them and test, if they intersects with rectangle
|
||||
for (const LayoutItem& item : m_layout.items)
|
||||
{
|
||||
// The offsets m_horizontalOffset and m_verticalOffset are offsets to the
|
||||
// topleft point of the block. But block maybe doesn't start at (0, 0),
|
||||
// so we must also use translation from the block beginning.
|
||||
QRect placedRect = item.pageRect.translated(m_horizontalOffset - m_layout.blockRect.left(), m_verticalOffset - m_layout.blockRect.top());
|
||||
if (placedRect.contains(point))
|
||||
{
|
||||
if (pagePoint)
|
||||
{
|
||||
const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex);
|
||||
QMatrix matrix = PDFRenderer::createPagePointToDevicePointMatrix(page, placedRect).inverted();
|
||||
*pagePoint = matrix.map(point);
|
||||
}
|
||||
|
||||
return item.pageIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QRect PDFDrawWidgetProxy::getPagesIntersectingRectBoundingBox(QRect rect) const
|
||||
{
|
||||
QRect resultRect;
|
||||
|
@ -35,7 +35,6 @@ namespace pdf
|
||||
class PDFProgress;
|
||||
class PDFWidget;
|
||||
class IDrawWidget;
|
||||
class PDFWidgetTool;
|
||||
class PDFCMSManager;
|
||||
class PDFTextLayoutGetter;
|
||||
class PDFAsynchronousPageCompiler;
|
||||
@ -269,6 +268,13 @@ public:
|
||||
/// \param rect Rectangle to test
|
||||
std::vector<PDFInteger> getPagesIntersectingRect(QRect rect) const;
|
||||
|
||||
/// Returns page, under which is point. If no page is under the point,
|
||||
/// then -1 is returned. Point is in widget coordinates. If \p pagePoint
|
||||
/// is not nullptr, then point in page coordinate space is set here.
|
||||
/// \param point Point
|
||||
/// \param pagePoint Point in page coordinate system
|
||||
PDFInteger getPageUnderPoint(QPoint point, QPointF* pagePoint) const;
|
||||
|
||||
/// Returns bounding box of pages, which are intersecting rectangle (even partially)
|
||||
/// \param rect Rectangle to test
|
||||
QRect getPagesIntersectingRectBoundingBox(QRect rect) const;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "pdfdrawwidget.h"
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
#include "pdfcompiler.h"
|
||||
#include "pdfwidgettool.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QGridLayout>
|
||||
@ -31,6 +32,7 @@ namespace pdf
|
||||
PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_cmsManager(cmsManager),
|
||||
m_toolManager(nullptr),
|
||||
m_drawWidget(nullptr),
|
||||
m_horizontalScrollBar(nullptr),
|
||||
m_verticalScrollBar(nullptr),
|
||||
@ -177,6 +179,7 @@ PDFDrawWidgetBase<BaseWidget>::PDFDrawWidgetBase(PDFWidget* widget, QWidget* par
|
||||
m_mouseOperation(MouseOperation::None)
|
||||
{
|
||||
this->setFocusPolicy(Qt::StrongFocus);
|
||||
this->setMouseTracking(true);
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
@ -216,10 +219,21 @@ void PDFDrawWidgetBase<BaseWidget>::performMouseOperation(QPoint currentMousePos
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
QScrollBar* verticalScrollbar = m_widget->getVerticalScrollbar();
|
||||
event->ignore();
|
||||
|
||||
// Try to pass event to tool manager
|
||||
if (PDFToolManager* toolManager = getPDFWidget()->getToolManager())
|
||||
{
|
||||
toolManager->keyPressEvent(this, event);
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical navigation
|
||||
QScrollBar* verticalScrollbar = m_widget->getVerticalScrollbar();
|
||||
if (verticalScrollbar->isVisible())
|
||||
{
|
||||
constexpr std::pair<QKeySequence::StandardKey, PDFDrawWidgetProxy::Operation> keyToOperations[] =
|
||||
@ -241,24 +255,52 @@ void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
// Try to pass event to tool manager
|
||||
if (PDFToolManager* toolManager = getPDFWidget()->getToolManager())
|
||||
{
|
||||
toolManager->mousePressEvent(this, event);
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
m_mouseOperation = MouseOperation::Translate;
|
||||
m_lastMousePosition = event->pos();
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
// Try to pass event to tool manager
|
||||
if (PDFToolManager* toolManager = getPDFWidget()->getToolManager())
|
||||
{
|
||||
toolManager->mouseReleaseEvent(this, event);
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
performMouseOperation(event->pos());
|
||||
|
||||
switch (m_mouseOperation)
|
||||
@ -269,7 +311,6 @@ void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
|
||||
case MouseOperation::Translate:
|
||||
{
|
||||
m_mouseOperation = MouseOperation::None;
|
||||
unsetCursor();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -277,19 +318,83 @@ void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
// Try to pass event to tool manager
|
||||
if (PDFToolManager* toolManager = getPDFWidget()->getToolManager())
|
||||
{
|
||||
toolManager->mouseMoveEvent(this, event);
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
performMouseOperation(event->pos());
|
||||
updateCursor();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::updateCursor()
|
||||
{
|
||||
std::optional<QCursor> cursor;
|
||||
if (PDFToolManager* toolManager = m_widget->getToolManager())
|
||||
{
|
||||
cursor = toolManager->getCursor();
|
||||
}
|
||||
|
||||
if (!cursor)
|
||||
{
|
||||
switch (m_mouseOperation)
|
||||
{
|
||||
case MouseOperation::None:
|
||||
cursor = QCursor(Qt::OpenHandCursor);
|
||||
break;
|
||||
|
||||
case MouseOperation::Translate:
|
||||
cursor = QCursor(Qt::ClosedHandCursor);
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor)
|
||||
{
|
||||
this->setCursor(*cursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
// Try to pass event to tool manager
|
||||
if (PDFToolManager* toolManager = getPDFWidget()->getToolManager())
|
||||
{
|
||||
toolManager->wheelEvent(this, event);
|
||||
if (event->isAccepted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
||||
|
||||
PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
|
||||
|
@ -29,6 +29,7 @@ namespace pdf
|
||||
{
|
||||
class PDFDocument;
|
||||
class PDFCMSManager;
|
||||
class PDFToolManager;
|
||||
class PDFDrawWidget;
|
||||
class PDFDrawWidgetProxy;
|
||||
|
||||
@ -77,6 +78,7 @@ public:
|
||||
void updateCacheLimits(int compiledPageCacheLimit, int thumbnailsCacheLimit, int fontCacheLimit, int instancedFontCacheLimit);
|
||||
|
||||
const PDFCMSManager* getCMSManager() const { return m_cmsManager; }
|
||||
PDFToolManager* getToolManager() const { return m_toolManager; }
|
||||
IDrawWidget* getDrawWidget() const { return m_drawWidget; }
|
||||
QScrollBar* getHorizontalScrollbar() const { return m_horizontalScrollBar; }
|
||||
QScrollBar* getVerticalScrollbar() const { return m_verticalScrollBar; }
|
||||
@ -84,6 +86,8 @@ public:
|
||||
const PageRenderingErrors* getPageRenderingErrors() const { return &m_pageRenderingErrors; }
|
||||
int getPageRenderingErrorCount() const;
|
||||
|
||||
void setToolManager(PDFToolManager* toolManager) { m_toolManager = toolManager; }
|
||||
|
||||
signals:
|
||||
void pageRenderingErrorsChanged(PDFInteger pageIndex, int errorsCount);
|
||||
|
||||
@ -95,6 +99,7 @@ private:
|
||||
IDrawWidget* createDrawWidget(RendererEngine rendererEngine, int samplesCount);
|
||||
|
||||
const PDFCMSManager* m_cmsManager;
|
||||
PDFToolManager* m_toolManager;
|
||||
IDrawWidget* m_drawWidget;
|
||||
QScrollBar* m_horizontalScrollBar;
|
||||
QScrollBar* m_verticalScrollBar;
|
||||
@ -125,6 +130,8 @@ protected:
|
||||
PDFWidget* getPDFWidget() const { return m_widget; }
|
||||
|
||||
private:
|
||||
void updateCursor();
|
||||
|
||||
enum class MouseOperation
|
||||
{
|
||||
None,
|
||||
|
@ -349,6 +349,19 @@ qint64 PDFTextLayout::getMemoryConsumptionEstimate() const
|
||||
return estimate;
|
||||
}
|
||||
|
||||
bool PDFTextLayout::isHoveringOverTextBlock(const QPointF& point) const
|
||||
{
|
||||
for (const PDFTextBlock& block : m_blocks)
|
||||
{
|
||||
if (block.getBoundingBox().contains(point))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout)
|
||||
{
|
||||
stream >> layout.m_characters;
|
||||
|
@ -200,6 +200,9 @@ struct PDFTextSelectionColoredItem
|
||||
|
||||
}
|
||||
|
||||
bool operator==(const PDFTextSelectionColoredItem&) const = default;
|
||||
bool operator!=(const PDFTextSelectionColoredItem&) const = default;
|
||||
|
||||
inline bool operator<(const PDFTextSelectionColoredItem& other) const { return std::tie(start, end) < std::tie(other.start, other.end); }
|
||||
|
||||
PDFCharacterPointer start;
|
||||
@ -217,6 +220,9 @@ public:
|
||||
|
||||
using iterator = PDFTextSelectionColoredItems::const_iterator;
|
||||
|
||||
bool operator==(const PDFTextSelection&) const = default;
|
||||
bool operator!=(const PDFTextSelection&) const = default;
|
||||
|
||||
/// Adds text selection items to selection
|
||||
/// \param items Items
|
||||
/// \param color Color for items (must include alpha channel)
|
||||
@ -232,6 +238,9 @@ public:
|
||||
/// Returns iterator to end of page range
|
||||
iterator end(PDFInteger pageIndex) const;
|
||||
|
||||
/// Returns true, if text selection is empty
|
||||
bool isEmpty() const { return m_items.empty(); }
|
||||
|
||||
private:
|
||||
PDFTextSelectionColoredItems m_items;
|
||||
};
|
||||
@ -327,6 +336,9 @@ public:
|
||||
/// Returns recognized text blocks
|
||||
const PDFTextBlocks& getTextBlocks() const { return m_blocks; }
|
||||
|
||||
/// Returns true, if given point is pointing to some text block
|
||||
bool isHoveringOverTextBlock(const QPointF& point) const;
|
||||
|
||||
friend QDataStream& operator<<(QDataStream& stream, const PDFTextLayout& layout);
|
||||
friend QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout);
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include <QLineEdit>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QWheelEvent>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
@ -33,6 +36,17 @@ PDFWidgetTool::PDFWidgetTool(PDFDrawWidgetProxy* proxy, QObject* parent) :
|
||||
BaseClass(parent),
|
||||
m_active(false),
|
||||
m_document(nullptr),
|
||||
m_action(nullptr),
|
||||
m_proxy(proxy)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFWidgetTool::PDFWidgetTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent) :
|
||||
BaseClass(parent),
|
||||
m_active(false),
|
||||
m_document(nullptr),
|
||||
m_action(action),
|
||||
m_proxy(proxy)
|
||||
{
|
||||
|
||||
@ -62,6 +76,7 @@ void PDFWidgetTool::setDocument(const PDFDocument* document)
|
||||
// We must turn off the tool, if we are changing the document
|
||||
setActive(false);
|
||||
m_document = document;
|
||||
updateActions();
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,17 +96,57 @@ void PDFWidgetTool::setActive(bool active)
|
||||
}
|
||||
|
||||
setActiveImpl(active);
|
||||
updateActions();
|
||||
|
||||
m_proxy->repaintNeeded();
|
||||
emit toolActivityChanged(active);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::setActiveImpl(bool active)
|
||||
{
|
||||
Q_UNUSED(active);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::updateActions()
|
||||
{
|
||||
if (m_action)
|
||||
{
|
||||
m_action->setChecked(isActive());
|
||||
m_action->setEnabled(m_document);
|
||||
}
|
||||
}
|
||||
|
||||
PDFFindTextTool::PDFFindTextTool(PDFDrawWidgetProxy* proxy, QAction* prevAction, QAction* nextAction, QObject* parent, QWidget* parentDialog) :
|
||||
BaseClass(proxy, parent),
|
||||
m_prevAction(prevAction),
|
||||
@ -143,7 +198,7 @@ void PDFFindTextTool::setActiveImpl(bool active)
|
||||
getProxy()->getTextLayoutCompiler()->makeTextLayout();
|
||||
|
||||
// Create dialog
|
||||
m_dialog = new QDialog(m_parentDialog, Qt::Tool);
|
||||
m_dialog = new QDialog(m_parentDialog, Qt::Popup | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
|
||||
m_dialog->setWindowTitle(tr("Find"));
|
||||
|
||||
QGridLayout* layout = new QGridLayout(m_dialog);
|
||||
@ -164,6 +219,9 @@ void PDFFindTextTool::setActiveImpl(bool active)
|
||||
m_previousButton->setDefault(false);
|
||||
m_nextButton->setDefault(false);
|
||||
|
||||
m_previousButton->setShortcut(m_prevAction->shortcut());
|
||||
m_nextButton->setShortcut(m_nextAction->shortcut());
|
||||
|
||||
connect(m_previousButton, &QPushButton::clicked, m_prevAction, &QAction::trigger);
|
||||
connect(m_nextButton, &QPushButton::clicked, m_nextAction, &QAction::trigger);
|
||||
connect(m_findTextEdit, &QLineEdit::editingFinished, this, &PDFFindTextTool::onSearchText);
|
||||
@ -184,6 +242,8 @@ void PDFFindTextTool::setActiveImpl(bool active)
|
||||
|
||||
m_dialog->show();
|
||||
m_dialog->move(topRightParent - QPoint(m_dialog->width() * 1.1, 0));
|
||||
m_dialog->setFocus();
|
||||
m_findTextEdit->setFocus();
|
||||
connect(m_dialog, &QDialog::rejected, this, [this] { setActive(false); });
|
||||
}
|
||||
else
|
||||
@ -329,6 +389,8 @@ void PDFFindTextTool::performSearch()
|
||||
|
||||
void PDFFindTextTool::updateActions()
|
||||
{
|
||||
BaseClass::updateActions();
|
||||
|
||||
const bool isActive = this->isActive();
|
||||
const bool hasResults = !m_findResults.empty();
|
||||
const bool enablePrevious = isActive && hasResults;
|
||||
@ -384,15 +446,161 @@ PDFTextSelection PDFFindTextTool::getTextSelectionImpl() const
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFToolManager::PDFToolManager(PDFDrawWidgetProxy* proxy, QAction* findPreviousAction, QAction* findNextAction, QObject* parent, QWidget* parentDialog) :
|
||||
PDFSelectTextTool::PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* selectAllAction, QAction* deselectAction, QObject* parent) :
|
||||
BaseClass(proxy, action, parent),
|
||||
m_selectAllAction(selectAllAction),
|
||||
m_deselectAction(deselectAction),
|
||||
m_isCursorOverText(false)
|
||||
{
|
||||
updateActions();
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
QPointF pagePoint;
|
||||
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
if (pageIndex != -1)
|
||||
{
|
||||
m_selectionInfo.pageIndex = pageIndex;
|
||||
m_selectionInfo.selectionStartPoint = pagePoint;
|
||||
event->accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selectionInfo = SelectionInfo();
|
||||
}
|
||||
|
||||
setSelection(pdf::PDFTextSelection());
|
||||
updateCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
if (m_selectionInfo.pageIndex != -1)
|
||||
{
|
||||
QPointF pagePoint;
|
||||
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
|
||||
if (m_selectionInfo.pageIndex == pageIndex)
|
||||
{
|
||||
// Jakub Melka: handle the selection
|
||||
}
|
||||
else
|
||||
{
|
||||
setSelection(pdf::PDFTextSelection());
|
||||
}
|
||||
|
||||
m_selectionInfo = SelectionInfo();
|
||||
event->accept();
|
||||
updateCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
QPointF pagePoint;
|
||||
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
|
||||
m_isCursorOverText = textLayout.isHoveringOverTextBlock(pagePoint);
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
if (m_selectionInfo.pageIndex != -1)
|
||||
{
|
||||
if (m_selectionInfo.pageIndex == pageIndex)
|
||||
{
|
||||
// Jakub Melka: handle the selection
|
||||
}
|
||||
else
|
||||
{
|
||||
setSelection(pdf::PDFTextSelection());
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::setActiveImpl(bool active)
|
||||
{
|
||||
if (active)
|
||||
{
|
||||
pdf::PDFAsynchronousTextLayoutCompiler* compiler = getProxy()->getTextLayoutCompiler();
|
||||
if (!compiler->isTextLayoutReady())
|
||||
{
|
||||
compiler->makeTextLayout();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just clear the text selection
|
||||
setSelection(PDFTextSelection());
|
||||
}
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::updateActions()
|
||||
{
|
||||
BaseClass::updateActions();
|
||||
|
||||
m_selectAllAction->setEnabled(isActive());
|
||||
m_deselectAction->setEnabled(isActive() && !m_textSelection.isEmpty());
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::updateCursor()
|
||||
{
|
||||
if (isActive())
|
||||
{
|
||||
if (m_isCursorOverText)
|
||||
{
|
||||
setCursor(QCursor(Qt::IBeamCursor));
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursor(QCursor(Qt::ArrowCursor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFSelectTextTool::setSelection(PDFTextSelection&& textSelection)
|
||||
{
|
||||
if (m_textSelection != textSelection)
|
||||
{
|
||||
m_textSelection = qMove(textSelection);
|
||||
getProxy()->repaintNeeded();
|
||||
updateActions();
|
||||
}
|
||||
}
|
||||
|
||||
PDFToolManager::PDFToolManager(PDFDrawWidgetProxy* proxy, Actions actions, QObject* parent, QWidget* parentDialog) :
|
||||
BaseClass(parent),
|
||||
m_predefinedTools()
|
||||
{
|
||||
m_predefinedTools[FindTextTool] = new PDFFindTextTool(proxy, findPreviousAction, findNextAction, this, parentDialog);
|
||||
m_predefinedTools[FindTextTool] = new PDFFindTextTool(proxy, actions.findPrevAction, actions.findNextAction, this, parentDialog);
|
||||
m_predefinedTools[SelectTextTool] = new PDFSelectTextTool(proxy, actions.selectTextToolAction, actions.selectAllAction, actions.deselectAction, this);
|
||||
|
||||
for (PDFWidgetTool* tool : m_predefinedTools)
|
||||
{
|
||||
m_tools.insert(tool);
|
||||
|
||||
if (QAction* action = tool->getAction())
|
||||
{
|
||||
m_actionsToTools[action] = tool;
|
||||
connect(action, &QAction::triggered, this, &PDFToolManager::onToolActionTriggered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,6 +612,22 @@ void PDFToolManager::setDocument(const PDFDocument* document)
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::setActiveTool(PDFWidgetTool* tool)
|
||||
{
|
||||
PDFWidgetTool* activeTool = getActiveTool();
|
||||
if (activeTool && activeTool != tool)
|
||||
{
|
||||
activeTool->setActive(false);
|
||||
}
|
||||
|
||||
Q_ASSERT(!getActiveTool());
|
||||
|
||||
if (tool)
|
||||
{
|
||||
tool->setActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
PDFWidgetTool* PDFToolManager::getActiveTool() const
|
||||
{
|
||||
for (PDFWidgetTool* tool : m_tools)
|
||||
@ -422,4 +646,88 @@ PDFFindTextTool* PDFToolManager::getFindTextTool() const
|
||||
return qobject_cast<PDFFindTextTool*>(m_predefinedTools[FindTextTool]);
|
||||
}
|
||||
|
||||
void PDFToolManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
// Escape key cancels current tool
|
||||
PDFWidgetTool* activeTool = getActiveTool();
|
||||
if (event->key() == Qt::Key_Escape && activeTool)
|
||||
{
|
||||
activeTool->setActive(false);
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTool)
|
||||
{
|
||||
activeTool->keyPressEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||
{
|
||||
activeTool->mousePressEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||
{
|
||||
activeTool->mouseReleaseEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||
{
|
||||
activeTool->mouseMoveEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||
{
|
||||
activeTool->wheelEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
const std::optional<QCursor>& PDFToolManager::getCursor() const
|
||||
{
|
||||
if (PDFWidgetTool* tool = getActiveTool())
|
||||
{
|
||||
return tool->getCursor();
|
||||
}
|
||||
|
||||
static const std::optional<QCursor> dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
void PDFToolManager::onToolActionTriggered(bool checked)
|
||||
{
|
||||
PDFWidgetTool* tool = m_actionsToTools.at(qobject_cast<QAction*>(sender()));
|
||||
if (checked)
|
||||
{
|
||||
setActiveTool(tool);
|
||||
}
|
||||
else
|
||||
{
|
||||
tool->setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "pdftextlayout.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QCursor>
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
@ -40,6 +41,7 @@ private:
|
||||
|
||||
public:
|
||||
explicit PDFWidgetTool(PDFDrawWidgetProxy* proxy, QObject* parent);
|
||||
explicit PDFWidgetTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
virtual ~PDFWidgetTool();
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
@ -61,24 +63,62 @@ public:
|
||||
/// Returns true, if tool is active
|
||||
bool isActive() const { return m_active; }
|
||||
|
||||
/// Returns action for activating/deactivating this tool
|
||||
QAction* getAction() const { return m_action; }
|
||||
|
||||
/// Handles key press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles mouse press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse release event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse move event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse wheel event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event);
|
||||
|
||||
/// Returns actual cursor defined by the tool. Cursor can be undefined,
|
||||
/// in this case, optional will be set to nullopt.
|
||||
const std::optional<QCursor>& getCursor() const { return m_cursor; }
|
||||
|
||||
signals:
|
||||
void toolActivityChanged(bool active);
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active);
|
||||
virtual void updateActions();
|
||||
|
||||
PDFDrawWidgetProxy* getProxy() const { return m_proxy; }
|
||||
|
||||
inline void setCursor(QCursor cursor) { m_cursor = qMove(cursor); }
|
||||
inline void unsetCursor() { m_cursor = std::nullopt; }
|
||||
|
||||
private:
|
||||
bool m_active;
|
||||
const PDFDocument* m_document;
|
||||
QAction* m_action;
|
||||
PDFDrawWidgetProxy* m_proxy;
|
||||
std::vector<PDFWidgetTool*> m_toolStack;
|
||||
std::optional<QCursor> m_cursor;
|
||||
};
|
||||
|
||||
/// Simple tool for find text in PDF document. It is much simpler than advanced
|
||||
/// search and can't search using regular expressions.
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFFindTextTool : public PDFWidgetTool
|
||||
class PDFFindTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -102,6 +142,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void onSearchText();
|
||||
@ -109,7 +150,6 @@ private:
|
||||
void onActionNext();
|
||||
|
||||
void performSearch();
|
||||
void updateActions();
|
||||
void updateResultsUI();
|
||||
void updateTitle();
|
||||
void clearResults();
|
||||
@ -142,6 +182,45 @@ private:
|
||||
mutable pdf::PDFCachedItem<pdf::PDFTextSelection> m_textSelection;
|
||||
};
|
||||
|
||||
/// Tool for selection of text in document
|
||||
class PDFSelectTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Construct new text selection tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param parent Parent object
|
||||
explicit PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* selectAllAction,QAction* deselectAction, QObject* parent);
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void updateCursor();
|
||||
void setSelection(pdf::PDFTextSelection&& textSelection);
|
||||
|
||||
struct SelectionInfo
|
||||
{
|
||||
PDFInteger pageIndex = -1;
|
||||
QPointF selectionStartPoint;
|
||||
};
|
||||
|
||||
QAction* m_selectAllAction;
|
||||
QAction* m_deselectAction;
|
||||
pdf::PDFTextSelection m_textSelection;
|
||||
SelectionInfo m_selectionInfo;
|
||||
bool m_isCursorOverText;
|
||||
};
|
||||
|
||||
/// Manager used for managing tools, their activity, availability
|
||||
/// and other settings. It also defines a predefined set of tools,
|
||||
/// available for various purposes (text searching, magnifier tool etc.)
|
||||
@ -153,13 +232,21 @@ private:
|
||||
using BaseClass = QObject;
|
||||
|
||||
public:
|
||||
struct Actions
|
||||
{
|
||||
QAction* findPrevAction = nullptr; ///< Action for navigating to previous result
|
||||
QAction* findNextAction = nullptr; ///< Action for navigating to next result
|
||||
QAction* selectTextToolAction = nullptr;
|
||||
QAction* selectAllAction = nullptr;
|
||||
QAction* deselectAction = nullptr;
|
||||
};
|
||||
|
||||
/// Construct new text search tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param prevAction Action for navigating to previous result
|
||||
/// \param nextAction Action for navigating to next result
|
||||
/// \param actions Actions
|
||||
/// \param parent Parent object
|
||||
/// \param parentDialog Paret dialog for tool dialog
|
||||
explicit PDFToolManager(PDFDrawWidgetProxy* proxy, QAction* findPreviousAction, QAction* findNextAction, QObject* parent, QWidget* parentDialog);
|
||||
explicit PDFToolManager(PDFDrawWidgetProxy* proxy, Actions actions, QObject* parent, QWidget* parentDialog);
|
||||
|
||||
/// Sets document
|
||||
/// \param document Document
|
||||
@ -168,9 +255,13 @@ public:
|
||||
enum PredefinedTools
|
||||
{
|
||||
FindTextTool,
|
||||
SelectTextTool,
|
||||
ToolEnd
|
||||
};
|
||||
|
||||
/// Sets active tool
|
||||
void setActiveTool(PDFWidgetTool* tool);
|
||||
|
||||
/// Returns first active tool from tool set. If no tool is active,
|
||||
/// then nullptr is returned.
|
||||
PDFWidgetTool* getActiveTool() const;
|
||||
@ -178,9 +269,41 @@ public:
|
||||
/// Returns find text tool
|
||||
PDFFindTextTool* getFindTextTool() const;
|
||||
|
||||
/// Handles key press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles mouse press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse release event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void mouseReleaseEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse move event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void mouseMoveEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse wheel event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void wheelEvent(QWidget* widget, QWheelEvent* event);
|
||||
|
||||
/// Returns actual cursor defined by the tool. Cursor can be undefined,
|
||||
/// in this case, optional will be set to nullopt.
|
||||
const std::optional<QCursor>& getCursor() const;
|
||||
|
||||
private:
|
||||
void onToolActionTriggered(bool checked);
|
||||
|
||||
std::set<PDFWidgetTool*> m_tools;
|
||||
std::array<PDFWidgetTool*, ToolEnd> m_predefinedTools;
|
||||
std::map<QAction*, PDFWidgetTool*> m_actionsToTools;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -31,5 +31,6 @@
|
||||
<file>resources/find-advanced.svg</file>
|
||||
<file>resources/find-next.svg</file>
|
||||
<file>resources/find-previous.svg</file>
|
||||
<file>resources/select-text.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "pdfutils.h"
|
||||
#include "pdfsendmail.h"
|
||||
#include "pdfexecutionpolicy.h"
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QFileDialog>
|
||||
@ -85,6 +86,10 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Initialize toolbar icon size
|
||||
QSize iconSize = PDFWidgetUtils::scaleDPI(this, QSize(24, 24));
|
||||
ui->mainToolBar->setIconSize(iconSize);
|
||||
|
||||
// Initialize task bar progress
|
||||
m_progressTaskbarIndicator = m_taskbarButton->progress();
|
||||
|
||||
@ -97,6 +102,8 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
||||
ui->actionFind->setShortcut(QKeySequence::Find);
|
||||
ui->actionFindPrevious->setShortcut(QKeySequence::FindPrevious);
|
||||
ui->actionFindNext->setShortcut(QKeySequence::FindNext);
|
||||
ui->actionSelectTextAll->setShortcut(QKeySequence::SelectAll);
|
||||
ui->actionDeselectText->setShortcut(QKeySequence::Deselect);
|
||||
|
||||
connect(ui->actionOpen, &QAction::triggered, this, &PDFViewerMainWindow::onActionOpenTriggered);
|
||||
connect(ui->actionClose, &QAction::triggered, this, &PDFViewerMainWindow::onActionCloseTriggered);
|
||||
@ -160,6 +167,10 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
||||
ui->mainToolBar->addAction(ui->actionFitPage);
|
||||
ui->mainToolBar->addAction(ui->actionFitWidth);
|
||||
ui->mainToolBar->addAction(ui->actionFitHeight);
|
||||
ui->mainToolBar->addSeparator();
|
||||
|
||||
// Tools
|
||||
ui->mainToolBar->addAction(ui->actionSelectText);
|
||||
|
||||
connect(ui->actionZoom_In, &QAction::triggered, this, [this] { m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::ZoomIn); });
|
||||
connect(ui->actionZoom_Out, &QAction::triggered, this, [this] { m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::ZoomOut); });
|
||||
@ -212,7 +223,14 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
||||
m_sidebarDockWidget->toggleViewAction()->setObjectName("actionSidebar");
|
||||
|
||||
// Initialize tools
|
||||
m_toolManager = new pdf::PDFToolManager(m_pdfWidget->getDrawWidgetProxy(), ui->actionFindPrevious, ui->actionFindNext, this, this);
|
||||
pdf::PDFToolManager::Actions actions;
|
||||
actions.findPrevAction = ui->actionFindPrevious;
|
||||
actions.findNextAction = ui->actionFindNext;
|
||||
actions.selectTextToolAction = ui->actionSelectText;
|
||||
actions.selectAllAction = ui->actionSelectTextAll;
|
||||
actions.deselectAction = ui->actionDeselectText;
|
||||
m_toolManager = new pdf::PDFToolManager(m_pdfWidget->getDrawWidgetProxy(), actions, this, this);
|
||||
m_pdfWidget->setToolManager(m_toolManager);
|
||||
|
||||
connect(m_pdfWidget->getDrawWidgetProxy(), &pdf::PDFDrawWidgetProxy::drawSpaceChanged, this, &PDFViewerMainWindow::onDrawSpaceChanged);
|
||||
connect(m_pdfWidget->getDrawWidgetProxy(), &pdf::PDFDrawWidgetProxy::pageLayoutChanged, this, &PDFViewerMainWindow::onPageLayoutChanged);
|
||||
@ -223,7 +241,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
||||
connect(m_progress, &pdf::PDFProgress::progressFinished, this, &PDFViewerMainWindow::onProgressFinished);
|
||||
connect(&m_futureWatcher, &QFutureWatcher<AsyncReadingResult>::finished, this, &PDFViewerMainWindow::onDocumentReadingFinished);
|
||||
connect(this, &PDFViewerMainWindow::queryPasswordRequest, this, &PDFViewerMainWindow::onQueryPasswordRequest, Qt::BlockingQueuedConnection);
|
||||
connect(ui->actionFind, &QAction::triggered, this, [this] { m_toolManager->getFindTextTool()->setActive(true); });
|
||||
connect(ui->actionFind, &QAction::triggered, this, [this] { m_toolManager->setActiveTool(m_toolManager->getFindTextTool()); });
|
||||
|
||||
readActionSettings();
|
||||
updatePageLayoutActions();
|
||||
|
@ -103,6 +103,11 @@
|
||||
<addaction name="actionFind"/>
|
||||
<addaction name="actionFindPrevious"/>
|
||||
<addaction name="actionFindNext"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSelectText"/>
|
||||
<addaction name="actionSelectTextAll"/>
|
||||
<addaction name="actionDeselectText"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuEdit"/>
|
||||
@ -376,6 +381,28 @@
|
||||
<string>Find Next</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSelectText">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="pdfforqtviewer.qrc">
|
||||
<normaloff>:/resources/select-text.svg</normaloff>:/resources/select-text.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select text</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSelectTextAll">
|
||||
<property name="text">
|
||||
<string>Select All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeselectText">
|
||||
<property name="text">
|
||||
<string>Deselect</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
|
@ -63,4 +63,17 @@ void PDFWidgetUtils::scaleWidget(QWidget* widget, QSize unscaledSize)
|
||||
widget->resize(width, height);
|
||||
}
|
||||
|
||||
QSize PDFWidgetUtils::scaleDPI(QWidget* widget, QSize unscaledSize)
|
||||
{
|
||||
const double logicalDPI_x = widget->logicalDpiX();
|
||||
const double logicalDPI_y = widget->logicalDpiY();
|
||||
const double defaultDPI_x = qt_default_dpi_x();
|
||||
const double defaultDPI_y = qt_default_dpi_y();
|
||||
|
||||
const int width = (logicalDPI_x / defaultDPI_x) * unscaledSize.width();
|
||||
const int height = (logicalDPI_y / defaultDPI_y) * unscaledSize.height();
|
||||
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
@ -40,6 +40,11 @@ public:
|
||||
/// \param widget Widget to be scaled
|
||||
/// \param unscaledSize Unscaled size of the widget
|
||||
static void scaleWidget(QWidget* widget, QSize unscaledSize);
|
||||
|
||||
/// Scales size based on DPI
|
||||
/// \param widget Widget, from which we get DPI
|
||||
/// \param unscaledSize Unscaled size
|
||||
static QSize scaleDPI(QWidget* widget, QSize unscaledSize);
|
||||
};
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
226
PdfForQtViewer/resources/select-text.svg
Normal file
226
PdfForQtViewer/resources/select-text.svg
Normal file
@ -0,0 +1,226 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="30mm"
|
||||
height="30mm"
|
||||
viewBox="0 0 30 30"
|
||||
version="1.1"
|
||||
id="svg5291"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="select-text.svg">
|
||||
<defs
|
||||
id="defs5285">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker1935"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1933"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
transform="scale(0.8) translate(12.5,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Club"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Club"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1637"
|
||||
d="M -1.5971367,-7.0977635 C -3.4863874,-7.0977635 -5.0235187,-5.5606321 -5.0235187,-3.6713813 C -5.0235187,-3.0147015 -4.7851656,-2.4444556 -4.4641095,-1.9232271 C -4.5028609,-1.8911157 -4.5437814,-1.8647646 -4.5806531,-1.8299921 C -5.2030765,-2.6849849 -6.1700514,-3.2751330 -7.3077730,-3.2751330 C -9.1970245,-3.2751331 -10.734155,-1.7380016 -10.734155,0.15124914 C -10.734155,2.0404999 -9.1970245,3.5776313 -7.3077730,3.5776313 C -6.3143268,3.5776313 -5.4391540,3.1355702 -4.8137404,2.4588126 C -4.9384274,2.8137041 -5.0235187,3.1803000 -5.0235187,3.5776313 C -5.0235187,5.4668819 -3.4863874,7.0040135 -1.5971367,7.0040135 C 0.29211394,7.0040135 1.8292454,5.4668819 1.8292454,3.5776313 C 1.8292454,2.7842354 1.5136868,2.0838028 1.0600576,1.5031550 C 2.4152718,1.7663868 3.7718375,2.2973711 4.7661444,3.8340272 C 4.0279463,3.0958289 3.5540908,1.7534117 3.5540908,-0.058529361 L 2.9247554,-0.10514681 L 3.5074733,-0.12845553 C 3.5074733,-1.9403966 3.9580199,-3.2828138 4.6962183,-4.0210121 C 3.7371277,-2.5387813 2.4390549,-1.9946496 1.1299838,-1.7134486 C 1.5341802,-2.2753578 1.8292454,-2.9268556 1.8292454,-3.6713813 C 1.8292454,-5.5606319 0.29211394,-7.0977635 -1.5971367,-7.0977635 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:0.74587913pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
transform="scale(0.6)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Torso"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Torso"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<g
|
||||
id="g1634"
|
||||
transform="scale(0.7)"
|
||||
style="stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1">
|
||||
<path
|
||||
id="path1620"
|
||||
d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.25;stroke-opacity:1" />
|
||||
<path
|
||||
id="path1622"
|
||||
d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" />
|
||||
<path
|
||||
id="path1624"
|
||||
d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" />
|
||||
<rect
|
||||
id="rect1626"
|
||||
transform="matrix(0.527536,-0.849533,0.887668,0.460484,0,0)"
|
||||
y="-1.7408575"
|
||||
x="-10.391706"
|
||||
height="2.7608147"
|
||||
width="2.6366582"
|
||||
style="fill-rule:evenodd;stroke-width:1pt;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" />
|
||||
<rect
|
||||
id="rect1628"
|
||||
transform="matrix(0.671205,-0.741272,0.790802,0.612072,0,0)"
|
||||
y="-7.9629307"
|
||||
x="4.9587269"
|
||||
height="2.8614161"
|
||||
width="2.7327356"
|
||||
style="fill-rule:evenodd;stroke-width:1pt;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" />
|
||||
<path
|
||||
id="path1630"
|
||||
transform="matrix(0,-1.109517,1.109517,0,25.96648,19.71619)"
|
||||
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" />
|
||||
<path
|
||||
id="path1632"
|
||||
transform="matrix(0,-1.109517,1.109517,0,26.82450,16.99126)"
|
||||
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" />
|
||||
</g>
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Lstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1426"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(1.1) translate(1,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleInL"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="TriangleInL"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1541"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
transform="scale(-0.8)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1408"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
transform="scale(0.8) translate(12.5,0)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.979899"
|
||||
inkscape:cx="-0.15372919"
|
||||
inkscape:cy="4.1302353"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2035"
|
||||
inkscape:window-x="-13"
|
||||
inkscape:window-y="-13"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5288">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Melka</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Vrstva 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-267)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.28888893px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
x="2.0528727"
|
||||
y="290.79916"
|
||||
id="text1404"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1402"
|
||||
x="2.0528727"
|
||||
y="290.79916"
|
||||
style="font-size:11.28888893px;stroke-width:0.26458332">abc</tspan></text>
|
||||
<g
|
||||
id="g2058">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 12.566406,271.99023 -0.533203,0.59571 13.763672,12.29492 0.533203,-0.5957 z"
|
||||
id="path1406"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.64000006pt;stroke-opacity:1"
|
||||
d="m 18.266245,277.61759 4.518301,-0.25488 -10.484776,-5.0744 6.221355,9.84758 z"
|
||||
id="path2064"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
Loading…
x
Reference in New Issue
Block a user