mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Improvement of snappper
This commit is contained in:
@ -884,6 +884,36 @@ PDFInteger PDFDrawWidgetProxy::getPageUnderPoint(QPoint point, QPointF* pagePoin
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFWidgetSnapshot PDFDrawWidgetProxy::getSnapshot() const
|
||||||
|
{
|
||||||
|
PDFWidgetSnapshot snapshot;
|
||||||
|
|
||||||
|
// Get the viewport
|
||||||
|
QRect viewport = getWidget()->rect();
|
||||||
|
|
||||||
|
// 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.intersects(viewport))
|
||||||
|
{
|
||||||
|
const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex);
|
||||||
|
|
||||||
|
PDFWidgetSnapshot::SnapshotItem snapshotItem;
|
||||||
|
snapshotItem.rect = placedRect;
|
||||||
|
snapshotItem.pageIndex = item.pageIndex;
|
||||||
|
snapshotItem.compiledPage = m_compiler->getCompiledPage(item.pageIndex, false);
|
||||||
|
snapshotItem.pageToDeviceMatrix = createPagePointToDevicePointMatrix(page, placedRect);
|
||||||
|
snapshot.items.emplace_back(qMove(snapshotItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
QRect PDFDrawWidgetProxy::getPagesIntersectingRectBoundingBox(QRect rect) const
|
QRect PDFDrawWidgetProxy::getPagesIntersectingRectBoundingBox(QRect rect) const
|
||||||
{
|
{
|
||||||
QRect resultRect;
|
QRect resultRect;
|
||||||
|
@ -185,6 +185,21 @@ private:
|
|||||||
PDFFontCache m_fontCache;
|
PDFFontCache m_fontCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Snapshot for current widget viewable items.
|
||||||
|
struct PDFWidgetSnapshot
|
||||||
|
{
|
||||||
|
struct SnapshotItem
|
||||||
|
{
|
||||||
|
PDFInteger pageIndex = -1; ///< Index of page
|
||||||
|
QRectF rect; ///< Page rectangle on viewport
|
||||||
|
QMatrix pageToDeviceMatrix; ///< Transforms page coordinates to widget coordinates
|
||||||
|
const PDFPrecompiledPage* compiledPage = nullptr; ///< Compiled page (can be nullptr)
|
||||||
|
};
|
||||||
|
|
||||||
|
using SnapshotItems = std::vector<SnapshotItem>;
|
||||||
|
SnapshotItems items;
|
||||||
|
};
|
||||||
|
|
||||||
/// This is a proxy class to draw space controller using widget. We have two spaces, pixel space
|
/// This is a proxy class to draw space controller using widget. We have two spaces, pixel space
|
||||||
/// (on the controlled widget) and device space (device is draw space controller).
|
/// (on the controlled widget) and device space (device is draw space controller).
|
||||||
class PDFFORQTLIBSHARED_EXPORT PDFDrawWidgetProxy : public QObject
|
class PDFFORQTLIBSHARED_EXPORT PDFDrawWidgetProxy : public QObject
|
||||||
@ -350,6 +365,17 @@ public:
|
|||||||
|
|
||||||
/// Returns current paper color
|
/// Returns current paper color
|
||||||
QColor getPaperColor();
|
QColor getPaperColor();
|
||||||
|
|
||||||
|
/// Transforms pixels to device space
|
||||||
|
/// \param pixel Value in pixels
|
||||||
|
PDFReal transformPixelToDeviceSpace(PDFReal pixel) const { return pixel * m_pixelToDeviceSpaceUnit; }
|
||||||
|
|
||||||
|
/// Transforms value in device space to pixel value
|
||||||
|
/// \param deviceSpaceValue Value in device space
|
||||||
|
PDFReal transformDeviceSpaceToPixel(PDFReal deviceSpaceValue) const { return deviceSpaceValue * m_deviceSpaceUnitToPixel; }
|
||||||
|
|
||||||
|
/// Returns snapshot of current view area
|
||||||
|
PDFWidgetSnapshot getSnapshot() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void drawSpaceChanged();
|
void drawSpaceChanged();
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "pdfsnapper.h"
|
#include "pdfsnapper.h"
|
||||||
#include "pdfcompiler.h"
|
#include "pdfcompiler.h"
|
||||||
#include "pdfwidgetutils.h"
|
#include "pdfwidgetutils.h"
|
||||||
|
#include "pdfdrawspacecontroller.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
@ -74,28 +75,25 @@ PDFSnapper::PDFSnapper()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFSnapper::drawSnapPoints(QPainter* painter, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, const QMatrix& pagePointToDevicePointMatrix) const
|
void PDFSnapper::drawSnapPoints(QPainter* painter) const
|
||||||
{
|
{
|
||||||
if (m_currentPage != -1 && m_currentPage != pageIndex)
|
|
||||||
{
|
|
||||||
// We are drawing only snap points, which are on current page
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_ASSERT(painter);
|
Q_ASSERT(painter);
|
||||||
Q_ASSERT(compiledPage);
|
|
||||||
|
|
||||||
const PDFSnapInfo* snapInfo = (m_currentPage != pageIndex) ? compiledPage->getSnapInfo() : &m_currentPageSnapInfo;
|
|
||||||
|
|
||||||
painter->save();
|
painter->save();
|
||||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
|
||||||
QPen pen = painter->pen();
|
QPen pen = painter->pen();
|
||||||
pen.setCapStyle(Qt::RoundCap);
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
pen.setWidth(PDFWidgetUtils::scaleDPI_x(painter->device(), 10));
|
pen.setWidth(m_snapPointPixelSize);
|
||||||
|
|
||||||
for (const PDFSnapInfo::SnapPoint& snapPoint : snapInfo->getSnapPoints())
|
for (const ViewportSnapPoint& snapPoint : m_snapPoints)
|
||||||
{
|
{
|
||||||
|
if (!isSnappingAllowed(snapPoint.pageIndex))
|
||||||
|
{
|
||||||
|
// We are drawing only snap points, which are on current page
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QColor color = pen.color();
|
QColor color = pen.color();
|
||||||
QColor newColor = color;
|
QColor newColor = color;
|
||||||
switch (snapPoint.type)
|
switch (snapPoint.type)
|
||||||
@ -119,11 +117,92 @@ void PDFSnapper::drawSnapPoints(QPainter* painter, PDFInteger pageIndex, const P
|
|||||||
painter->setPen(pen);
|
painter->setPen(pen);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint point = pagePointToDevicePointMatrix.map(snapPoint.point).toPoint();
|
QPoint point = snapPoint.viewportPoint.toPoint();
|
||||||
|
painter->drawPoint(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSnapped())
|
||||||
|
{
|
||||||
|
pen.setColor(Qt::yellow);
|
||||||
|
painter->setPen(pen);
|
||||||
|
QPoint point = m_snappedPoint->viewportPoint.toPoint();
|
||||||
painter->drawPoint(point);
|
painter->drawPoint(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDFSnapper::isSnappingAllowed(PDFInteger pageIndex) const
|
||||||
|
{
|
||||||
|
return (m_currentPage == -1) || (m_currentPage == pageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSnapper::updateSnappedPoint(const QPointF& mousePoint)
|
||||||
|
{
|
||||||
|
m_snappedPoint = std::nullopt;
|
||||||
|
m_mousePoint = mousePoint;
|
||||||
|
|
||||||
|
// Iterate trough all points, check, if some satisfies condition
|
||||||
|
const PDFReal toleranceSquared = m_snapPointTolerance * m_snapPointTolerance;
|
||||||
|
for (const ViewportSnapPoint& snapPoint : m_snapPoints)
|
||||||
|
{
|
||||||
|
QPointF difference = mousePoint - snapPoint.viewportPoint;
|
||||||
|
PDFReal distanceSquared = QPointF::dotProduct(difference, difference);
|
||||||
|
if (distanceSquared < toleranceSquared && isSnappingAllowed(snapPoint.pageIndex))
|
||||||
|
{
|
||||||
|
m_snappedPoint = snapPoint;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSnapper::buildSnapPoints(const PDFWidgetSnapshot& snapshot)
|
||||||
|
{
|
||||||
|
// First, clear all snap points
|
||||||
|
m_snapPoints.clear();
|
||||||
|
|
||||||
|
// Second, create snapping points from snapshot
|
||||||
|
for (const PDFWidgetSnapshot::SnapshotItem& item : snapshot.items)
|
||||||
|
{
|
||||||
|
if (!item.compiledPage)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFSnapInfo* info = item.compiledPage->getSnapInfo();
|
||||||
|
for (const PDFSnapInfo::SnapPoint& snapPoint : info->getSnapPoints())
|
||||||
|
{
|
||||||
|
ViewportSnapPoint viewportSnapPoint;
|
||||||
|
viewportSnapPoint.type = snapPoint.type;
|
||||||
|
viewportSnapPoint.point = snapPoint.point;
|
||||||
|
viewportSnapPoint.pageIndex = item.pageIndex;
|
||||||
|
viewportSnapPoint.viewportPoint = item.pageToDeviceMatrix.map(snapPoint.point);
|
||||||
|
m_snapPoints.push_back(qMove(viewportSnapPoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third, update snap shot position
|
||||||
|
updateSnappedPoint(m_mousePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFSnapper::getSnapPointTolerance() const
|
||||||
|
{
|
||||||
|
return m_snapPointTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSnapper::setSnapPointTolerance(int snapPointTolerance)
|
||||||
|
{
|
||||||
|
m_snapPointTolerance = snapPointTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF PDFSnapper::getSnappedPoint() const
|
||||||
|
{
|
||||||
|
if (isSnapped())
|
||||||
|
{
|
||||||
|
return m_snappedPoint->viewportPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_mousePoint;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -21,12 +21,14 @@
|
|||||||
#include "pdfglobal.h"
|
#include "pdfglobal.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
class QPainter;
|
class QPainter;
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
class PDFPrecompiledPage;
|
class PDFPrecompiledPage;
|
||||||
|
struct PDFWidgetSnapshot;
|
||||||
|
|
||||||
enum class SnapType
|
enum class SnapType
|
||||||
{
|
{
|
||||||
@ -90,19 +92,69 @@ class PDFSnapper
|
|||||||
public:
|
public:
|
||||||
PDFSnapper();
|
PDFSnapper();
|
||||||
|
|
||||||
/// Draws snapping points onto the page
|
/// Sets snap point pixel size
|
||||||
|
/// \param snapPointPixelSize Snap point diameter in pixels
|
||||||
|
void setSnapPointPixelSize(int snapPointPixelSize) { m_snapPointPixelSize = snapPointPixelSize; }
|
||||||
|
|
||||||
|
/// Returns snap point pixel size
|
||||||
|
int getSnapPointPixelSize() const { return m_snapPointPixelSize; }
|
||||||
|
|
||||||
|
/// Draws snapping points onto the painter. This function needs valid snap points,
|
||||||
|
/// so \p m_snapPoints must be valid before this function is called.
|
||||||
/// \param painter Painter
|
/// \param painter Painter
|
||||||
/// \param pageIndex Page index
|
void drawSnapPoints(QPainter* painter) const;
|
||||||
/// \param compiledPage Compiled page
|
|
||||||
/// \param pagePointToDevicePointMatrix Matrix mapping page space to device point space
|
/// Returns true, if snapping is allowed at current page
|
||||||
void drawSnapPoints(QPainter* painter,
|
/// \param pageIndex Page index to be tested for allowing snapping
|
||||||
pdf::PDFInteger pageIndex,
|
bool isSnappingAllowed(PDFInteger pageIndex) const;
|
||||||
const PDFPrecompiledPage* compiledPage,
|
|
||||||
const QMatrix& pagePointToDevicePointMatrix) const;
|
/// Updates snapped point using given information. If current page is set, it means, we are
|
||||||
|
/// using snapping info from current page, and if we are hovering at different page,
|
||||||
|
/// then nothing happens. Otherwise, other page snap info is used to update snapped point.
|
||||||
|
/// If mouse point distance from some snap point is lesser than tolerance, then new snap is set.
|
||||||
|
/// \param mousePoint Mouse point in widget coordinates
|
||||||
|
void updateSnappedPoint(const QPointF& mousePoint);
|
||||||
|
|
||||||
|
/// Returns true, if some point of interest is snapped
|
||||||
|
bool isSnapped() const { return m_snappedPoint.has_value(); }
|
||||||
|
|
||||||
|
/// Builds snap points from the widget snapshot. Updates current value
|
||||||
|
/// of snapped point (from mouse position).
|
||||||
|
/// \param snapshot Widget snapshot
|
||||||
|
void buildSnapPoints(const PDFWidgetSnapshot& snapshot);
|
||||||
|
|
||||||
|
/// Returns current snap point tolerance (while aiming with the mouse cursor,
|
||||||
|
/// when mouse cursor is at most tolerance distance from some snap point,
|
||||||
|
/// it is snapped.
|
||||||
|
int getSnapPointTolerance() const;
|
||||||
|
|
||||||
|
/// Sets snap point tolerance
|
||||||
|
void setSnapPointTolerance(int snapPointTolerance);
|
||||||
|
|
||||||
|
/// Returns snapped position. If point at mouse cursor is not snapped, then
|
||||||
|
/// mouse cursor position is returned.
|
||||||
|
QPointF getSnappedPoint() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PDFSnapInfo m_currentPageSnapInfo;
|
|
||||||
|
struct ViewportSnapPoint : public PDFSnapInfo::SnapPoint
|
||||||
|
{
|
||||||
|
QPointF viewportPoint;
|
||||||
|
PDFInteger pageIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SnappedPoint
|
||||||
|
{
|
||||||
|
PDFInteger pageIndex = -1;
|
||||||
|
QPointF snappedPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ViewportSnapPoint> m_snapPoints;
|
||||||
|
std::optional<ViewportSnapPoint> m_snappedPoint;
|
||||||
|
QPointF m_mousePoint;
|
||||||
PDFInteger m_currentPage = -1;
|
PDFInteger m_currentPage = -1;
|
||||||
|
int m_snapPointPixelSize = 0;
|
||||||
|
int m_snapPointTolerance = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "pdfwidgettool.h"
|
#include "pdfwidgettool.h"
|
||||||
#include "pdfdrawwidget.h"
|
#include "pdfdrawwidget.h"
|
||||||
#include "pdfcompiler.h"
|
#include "pdfcompiler.h"
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@ -951,25 +952,22 @@ PDFPickTool::PDFPickTool(PDFDrawWidgetProxy* proxy, PDFPickTool::Mode mode, QObj
|
|||||||
m_mode(mode)
|
m_mode(mode)
|
||||||
{
|
{
|
||||||
setCursor(Qt::BlankCursor);
|
setCursor(Qt::BlankCursor);
|
||||||
}
|
m_snapper.setSnapPointPixelSize(PDFWidgetUtils::scaleDPI_x(proxy->getWidget(), 10));
|
||||||
|
m_snapper.setSnapPointTolerance(m_snapper.getSnapPointPixelSize());
|
||||||
|
|
||||||
void PDFPickTool::drawPage(QPainter* painter,
|
connect(proxy, &PDFDrawWidgetProxy::drawSpaceChanged, this, &PDFPickTool::buildSnapPoints);
|
||||||
PDFInteger pageIndex,
|
connect(proxy, &PDFDrawWidgetProxy::pageImageChanged, this, &PDFPickTool::buildSnapPoints);
|
||||||
const PDFPrecompiledPage* compiledPage,
|
|
||||||
PDFTextLayoutGetter& layoutGetter,
|
|
||||||
const QMatrix& pagePointToDevicePointMatrix) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(layoutGetter);
|
|
||||||
|
|
||||||
m_snapper.drawSnapPoints(painter, pageIndex, compiledPage, pagePointToDevicePointMatrix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPickTool::drawPostRendering(QPainter* painter, QRect rect) const
|
void PDFPickTool::drawPostRendering(QPainter* painter, QRect rect) const
|
||||||
{
|
{
|
||||||
QPoint hleft = m_mousePosition;
|
m_snapper.drawSnapPoints(painter);
|
||||||
QPoint hright = m_mousePosition;
|
|
||||||
QPoint vtop = m_mousePosition;
|
QPoint snappedPoint = m_snapper.getSnappedPoint().toPoint();
|
||||||
QPoint vbottom = m_mousePosition;
|
QPoint hleft = snappedPoint;
|
||||||
|
QPoint hright = snappedPoint;
|
||||||
|
QPoint vtop = snappedPoint;
|
||||||
|
QPoint vbottom = snappedPoint;
|
||||||
|
|
||||||
hleft.setX(0);
|
hleft.setX(0);
|
||||||
hright.setX(rect.width());
|
hright.setX(rect.width());
|
||||||
@ -1001,10 +999,31 @@ void PDFPickTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
if (m_mousePosition != mousePos)
|
if (m_mousePosition != mousePos)
|
||||||
{
|
{
|
||||||
m_mousePosition = mousePos;
|
m_mousePosition = mousePos;
|
||||||
|
m_snapper.updateSnappedPoint(m_mousePosition);
|
||||||
getProxy()->repaintNeeded();
|
getProxy()->repaintNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFPickTool::setActiveImpl(bool active)
|
||||||
|
{
|
||||||
|
BaseClass::setActiveImpl(active);
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
buildSnapPoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPickTool::buildSnapPoints()
|
||||||
|
{
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_snapper.buildSnapPoints(getProxy()->getSnapshot());
|
||||||
|
}
|
||||||
|
|
||||||
PDFScreenshotTool::PDFScreenshotTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent) :
|
PDFScreenshotTool::PDFScreenshotTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent) :
|
||||||
BaseClass(proxy, action, parent),
|
BaseClass(proxy, action, parent),
|
||||||
m_pickTool(nullptr)
|
m_pickTool(nullptr)
|
||||||
|
@ -296,16 +296,21 @@ public:
|
|||||||
/// \param parent Parent object
|
/// \param parent Parent object
|
||||||
explicit PDFPickTool(PDFDrawWidgetProxy* proxy, Mode mode, QObject* parent);
|
explicit PDFPickTool(PDFDrawWidgetProxy* proxy, Mode mode, QObject* parent);
|
||||||
|
|
||||||
virtual void drawPage(QPainter* painter, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, PDFTextLayoutGetter& layoutGetter, const QMatrix& pagePointToDevicePointMatrix) const override;
|
|
||||||
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
|
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
|
||||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setActiveImpl(bool active) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void buildSnapPoints();
|
||||||
|
|
||||||
Mode m_mode;
|
Mode m_mode;
|
||||||
PDFSnapper m_snapper;
|
PDFSnapper m_snapper;
|
||||||
QPoint m_mousePosition;
|
QPoint m_mousePosition;
|
||||||
|
std::vector<QPointF> m_pickedPoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Tool that makes screenshot of page area and copies it to the clipboard
|
/// Tool that makes screenshot of page area and copies it to the clipboard
|
||||||
|
Reference in New Issue
Block a user