mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-30 00:55:12 +01:00
Improvement of snappper
This commit is contained in:
parent
a27216e752
commit
46c267e537
@ -884,6 +884,36 @@ PDFInteger PDFDrawWidgetProxy::getPageUnderPoint(QPoint point, QPointF* pagePoin
|
||||
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 resultRect;
|
||||
|
@ -185,6 +185,21 @@ private:
|
||||
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
|
||||
/// (on the controlled widget) and device space (device is draw space controller).
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFDrawWidgetProxy : public QObject
|
||||
@ -350,6 +365,17 @@ public:
|
||||
|
||||
/// Returns current paper color
|
||||
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:
|
||||
void drawSpaceChanged();
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "pdfsnapper.h"
|
||||
#include "pdfcompiler.h"
|
||||
#include "pdfwidgetutils.h"
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
|
||||
#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(compiledPage);
|
||||
|
||||
const PDFSnapInfo* snapInfo = (m_currentPage != pageIndex) ? compiledPage->getSnapInfo() : &m_currentPageSnapInfo;
|
||||
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
QPen pen = painter->pen();
|
||||
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 newColor = color;
|
||||
switch (snapPoint.type)
|
||||
@ -119,11 +117,92 @@ void PDFSnapper::drawSnapPoints(QPainter* painter, PDFInteger pageIndex, const P
|
||||
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->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
|
||||
|
@ -21,12 +21,14 @@
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
class QPainter;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFPrecompiledPage;
|
||||
struct PDFWidgetSnapshot;
|
||||
|
||||
enum class SnapType
|
||||
{
|
||||
@ -90,19 +92,69 @@ class PDFSnapper
|
||||
public:
|
||||
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 pageIndex Page index
|
||||
/// \param compiledPage Compiled page
|
||||
/// \param pagePointToDevicePointMatrix Matrix mapping page space to device point space
|
||||
void drawSnapPoints(QPainter* painter,
|
||||
pdf::PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
const QMatrix& pagePointToDevicePointMatrix) const;
|
||||
void drawSnapPoints(QPainter* painter) const;
|
||||
|
||||
/// Returns true, if snapping is allowed at current page
|
||||
/// \param pageIndex Page index to be tested for allowing snapping
|
||||
bool isSnappingAllowed(PDFInteger pageIndex) 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:
|
||||
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;
|
||||
int m_snapPointPixelSize = 0;
|
||||
int m_snapPointTolerance = 0;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "pdfwidgettool.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
#include "pdfcompiler.h"
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QAction>
|
||||
@ -951,25 +952,22 @@ PDFPickTool::PDFPickTool(PDFDrawWidgetProxy* proxy, PDFPickTool::Mode mode, QObj
|
||||
m_mode(mode)
|
||||
{
|
||||
setCursor(Qt::BlankCursor);
|
||||
}
|
||||
m_snapper.setSnapPointPixelSize(PDFWidgetUtils::scaleDPI_x(proxy->getWidget(), 10));
|
||||
m_snapper.setSnapPointTolerance(m_snapper.getSnapPointPixelSize());
|
||||
|
||||
void PDFPickTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QMatrix& pagePointToDevicePointMatrix) const
|
||||
{
|
||||
Q_UNUSED(layoutGetter);
|
||||
|
||||
m_snapper.drawSnapPoints(painter, pageIndex, compiledPage, pagePointToDevicePointMatrix);
|
||||
connect(proxy, &PDFDrawWidgetProxy::drawSpaceChanged, this, &PDFPickTool::buildSnapPoints);
|
||||
connect(proxy, &PDFDrawWidgetProxy::pageImageChanged, this, &PDFPickTool::buildSnapPoints);
|
||||
}
|
||||
|
||||
void PDFPickTool::drawPostRendering(QPainter* painter, QRect rect) const
|
||||
{
|
||||
QPoint hleft = m_mousePosition;
|
||||
QPoint hright = m_mousePosition;
|
||||
QPoint vtop = m_mousePosition;
|
||||
QPoint vbottom = m_mousePosition;
|
||||
m_snapper.drawSnapPoints(painter);
|
||||
|
||||
QPoint snappedPoint = m_snapper.getSnappedPoint().toPoint();
|
||||
QPoint hleft = snappedPoint;
|
||||
QPoint hright = snappedPoint;
|
||||
QPoint vtop = snappedPoint;
|
||||
QPoint vbottom = snappedPoint;
|
||||
|
||||
hleft.setX(0);
|
||||
hright.setX(rect.width());
|
||||
@ -1001,10 +999,31 @@ void PDFPickTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
if (m_mousePosition != mousePos)
|
||||
{
|
||||
m_mousePosition = mousePos;
|
||||
m_snapper.updateSnappedPoint(m_mousePosition);
|
||||
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) :
|
||||
BaseClass(proxy, action, parent),
|
||||
m_pickTool(nullptr)
|
||||
|
@ -296,16 +296,21 @@ public:
|
||||
/// \param parent Parent object
|
||||
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 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;
|
||||
|
||||
private:
|
||||
void buildSnapPoints();
|
||||
|
||||
Mode m_mode;
|
||||
PDFSnapper m_snapper;
|
||||
QPoint m_mousePosition;
|
||||
std::vector<QPointF> m_pickedPoints;
|
||||
};
|
||||
|
||||
/// Tool that makes screenshot of page area and copies it to the clipboard
|
||||
|
Loading…
x
Reference in New Issue
Block a user