mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Signature plugin: Element manipulation
This commit is contained in:
@ -19,6 +19,7 @@
|
|||||||
#include "pdfpainterutils.h"
|
#include "pdfpainterutils.h"
|
||||||
#include "pdfdrawwidget.h"
|
#include "pdfdrawwidget.h"
|
||||||
#include "pdfdrawspacecontroller.h"
|
#include "pdfdrawspacecontroller.h"
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
@ -49,6 +50,121 @@ void PDFPageContentElement::setElementId(PDFInteger newElementId)
|
|||||||
m_elementId = newElementId;
|
m_elementId = newElementId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint PDFPageContentElement::getRectangleManipulationMode(const QRectF& rectangle,
|
||||||
|
const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const
|
||||||
|
{
|
||||||
|
if ((rectangle.topLeft() - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return TopLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rectangle.topRight() - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return TopRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rectangle.bottomLeft() - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return BottomLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rectangle.bottomRight() - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return BottomRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rectangle.left() <= point.x() &&
|
||||||
|
point.x() <= rectangle.right() &&
|
||||||
|
(qAbs(rectangle.top() - point.y()) < snapPointDistanceThreshold))
|
||||||
|
{
|
||||||
|
return Top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rectangle.left() <= point.x() &&
|
||||||
|
point.x() <= rectangle.right() &&
|
||||||
|
(qAbs(rectangle.bottom() - point.y()) < snapPointDistanceThreshold))
|
||||||
|
{
|
||||||
|
return Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rectangle.top() <= point.y() &&
|
||||||
|
point.y() <= rectangle.bottom() &&
|
||||||
|
(qAbs(rectangle.left() - point.y()) < snapPointDistanceThreshold))
|
||||||
|
{
|
||||||
|
return Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rectangle.top() <= point.y() &&
|
||||||
|
point.y() <= rectangle.bottom() &&
|
||||||
|
(qAbs(rectangle.right() - point.y()) < snapPointDistanceThreshold))
|
||||||
|
{
|
||||||
|
return Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rectangle.contains(point))
|
||||||
|
{
|
||||||
|
return Translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElement::performRectangleManipulation(QRectF& rectangle,
|
||||||
|
uint mode,
|
||||||
|
const QPointF& offset)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case None:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Translate:
|
||||||
|
rectangle.translate(offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Top:
|
||||||
|
rectangle.setTop(qMin(rectangle.bottom(), rectangle.top() + offset.y()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Left:
|
||||||
|
rectangle.setLeft(qMin(rectangle.right(), rectangle.left() + offset.x()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Right:
|
||||||
|
rectangle.setRight(qMax(rectangle.left(), rectangle.right() + offset.x()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bottom:
|
||||||
|
rectangle.setBottom(qMax(rectangle.top(), rectangle.bottom() + offset.y()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TopLeft:
|
||||||
|
rectangle.setTop(qMin(rectangle.bottom(), rectangle.top() + offset.y()));
|
||||||
|
rectangle.setLeft(qMin(rectangle.right(), rectangle.left() + offset.x()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TopRight:
|
||||||
|
rectangle.setTop(qMin(rectangle.bottom(), rectangle.top() + offset.y()));
|
||||||
|
rectangle.setRight(qMax(rectangle.left(), rectangle.right() + offset.x()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BottomLeft:
|
||||||
|
rectangle.setBottom(qMax(rectangle.top(), rectangle.bottom() + offset.y()));
|
||||||
|
rectangle.setLeft(qMin(rectangle.right(), rectangle.left() + offset.x()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BottomRight:
|
||||||
|
rectangle.setBottom(qMax(rectangle.top(), rectangle.bottom() + offset.y()));
|
||||||
|
rectangle.setRight(qMax(rectangle.left(), rectangle.right() + offset.x()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QPen& PDFPageContentStyledElement::getPen() const
|
const QPen& PDFPageContentStyledElement::getPen() const
|
||||||
{
|
{
|
||||||
return m_pen;
|
return m_pen;
|
||||||
@ -135,10 +251,22 @@ void PDFPageContentElementRectangle::drawPage(QPainter* painter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint PDFPageContentElementRectangle::getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const
|
||||||
|
{
|
||||||
|
return getRectangleManipulationMode(getRectangle(), point, snapPointDistanceThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementRectangle::performManipulation(uint mode, const QPointF& offset)
|
||||||
|
{
|
||||||
|
performRectangleManipulation(m_rectangle, mode, offset);
|
||||||
|
}
|
||||||
|
|
||||||
PDFPageContentScene::PDFPageContentScene(QObject* parent) :
|
PDFPageContentScene::PDFPageContentScene(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_firstFreeId(1),
|
m_firstFreeId(1),
|
||||||
m_isActive(false),
|
m_isActive(false),
|
||||||
|
m_widget(nullptr),
|
||||||
m_manipulator(this, nullptr)
|
m_manipulator(this, nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -156,6 +284,22 @@ void PDFPageContentScene::addElement(PDFPageContentElement* element)
|
|||||||
emit sceneChanged();
|
emit sceneChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFPageContentScene::replaceElement(PDFPageContentElement* element)
|
||||||
|
{
|
||||||
|
std::unique_ptr<PDFPageContentElement> elementPtr(element);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_elements.size(); ++i)
|
||||||
|
{
|
||||||
|
if (m_elements[i]->getElementId() == element->getElementId())
|
||||||
|
{
|
||||||
|
m_elements[i] = std::move(elementPtr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit sceneChanged();
|
||||||
|
}
|
||||||
|
|
||||||
PDFPageContentElement* PDFPageContentScene::getElementById(PDFInteger id) const
|
PDFPageContentElement* PDFPageContentScene::getElementById(PDFInteger id) const
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_elements.cbegin(), m_elements.cend(), [id](const auto& element) { return element->getElementId() == id; });
|
auto it = std::find_if(m_elements.cbegin(), m_elements.cend(), [id](const auto& element) { return element->getElementId() == id; });
|
||||||
@ -214,8 +358,8 @@ void PDFPageContentScene::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
if (!m_manipulator.isManipulationInProgress())
|
if (!m_manipulator.isManipulationInProgress())
|
||||||
{
|
{
|
||||||
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
||||||
const bool isCtrl = keyboardModifiers.testFlag(Qt::CTRL);
|
const bool isCtrl = keyboardModifiers.testFlag(Qt::ControlModifier);
|
||||||
const bool isShift = keyboardModifiers.testFlag(Qt::SHIFT);
|
const bool isShift = keyboardModifiers.testFlag(Qt::ShiftModifier);
|
||||||
|
|
||||||
if (isCtrl && !isShift)
|
if (isCtrl && !isShift)
|
||||||
{
|
{
|
||||||
@ -236,6 +380,10 @@ void PDFPageContentScene::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
|
|
||||||
grabMouse(info, event);
|
grabMouse(info, event);
|
||||||
}
|
}
|
||||||
|
else if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
m_manipulator.deselectAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
void PDFPageContentScene::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||||
@ -271,25 +419,55 @@ void PDFPageContentScene::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
if (event->button() == Qt::LeftButton)
|
if (event->button() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
m_manipulator.finishManipulation();
|
|
||||||
|
if (m_manipulator.isManipulationInProgress())
|
||||||
|
{
|
||||||
|
QPointF pagePoint;
|
||||||
|
const PDFInteger pageIndex = m_widget->getDrawWidgetProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
|
m_mouseGrabInfo.info.widgetMouseCurrentPos = event->pos();
|
||||||
|
bool isCopyCreated = QApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
|
||||||
|
m_manipulator.finishManipulation(pageIndex, m_mouseGrabInfo.info.pagePos, pagePoint, isCopyCreated);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ungrabMouse(info, event);
|
ungrabMouse(getMouseEventInfo(widget, event->pos()), event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
void PDFPageContentScene::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
|
||||||
if (!isActive())
|
if (!isActive())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
const PDFReal threshold = getSnapPointDistanceThreshold();
|
||||||
if (info.isValid())
|
|
||||||
|
QPointF pagePoint;
|
||||||
|
const PDFInteger pageIndex = m_widget->getDrawWidgetProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
|
if (m_mouseGrabInfo.info.isValid() &&
|
||||||
|
event->buttons().testFlag(Qt::LeftButton) &&
|
||||||
|
m_mouseGrabInfo.info.pageIndex == pageIndex &&
|
||||||
|
m_manipulator.isManipulationAllowed(pageIndex))
|
||||||
{
|
{
|
||||||
|
// Jakub Melka: Start grab?
|
||||||
|
m_mouseGrabInfo.info.widgetMouseCurrentPos = event->pos();
|
||||||
|
|
||||||
|
if (!m_manipulator.isManipulationInProgress())
|
||||||
|
{
|
||||||
|
QPoint vector = m_mouseGrabInfo.info.widgetMouseCurrentPos - m_mouseGrabInfo.info.widgetMouseStartPos;
|
||||||
|
if (vector.manhattanLength() > QApplication::startDragDistance() ||
|
||||||
|
m_mouseGrabInfo.info.timer.hasExpired(QApplication::startDragTime()))
|
||||||
|
{
|
||||||
|
m_manipulator.startManipulation(pageIndex, m_mouseGrabInfo.info.pagePos, pagePoint, threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_manipulator.updateManipulation(pageIndex, m_mouseGrabInfo.info.pagePos, pagePoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If mouse is grabbed, then event is accepted always (because
|
// If mouse is grabbed, then event is accepted always (because
|
||||||
@ -361,6 +539,7 @@ PDFPageContentScene::MouseEventInfo PDFPageContentScene::getMouseEventInfo(QWidg
|
|||||||
{
|
{
|
||||||
MouseEventInfo result;
|
MouseEventInfo result;
|
||||||
|
|
||||||
|
Q_UNUSED(widget);
|
||||||
Q_ASSERT(isActive());
|
Q_ASSERT(isActive());
|
||||||
|
|
||||||
if (isMouseGrabbed())
|
if (isMouseGrabbed())
|
||||||
@ -370,15 +549,38 @@ PDFPageContentScene::MouseEventInfo PDFPageContentScene::getMouseEventInfo(QWidg
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
result.widgetMouseStartPos = point;
|
||||||
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
result.widgetMouseCurrentPos = point;
|
||||||
{
|
result.timer = m_mouseGrabInfo.info.timer;
|
||||||
|
result.pageIndex = m_widget->getDrawWidgetProxy()->getPageUnderPoint(point, &result.pagePos);
|
||||||
|
|
||||||
|
const PDFReal threshold = getSnapPointDistanceThreshold();
|
||||||
|
for (const auto& elementItem : m_elements)
|
||||||
|
{
|
||||||
|
PDFPageContentElement* element = elementItem.get();
|
||||||
|
|
||||||
|
if (element->getPageIndex() != result.pageIndex)
|
||||||
|
{
|
||||||
|
// Different page
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element->getManipulationMode(result.pagePos, threshold) != 0)
|
||||||
|
{
|
||||||
|
result.hoveredElementIds.insert(element->getElementId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFReal PDFPageContentScene::getSnapPointDistanceThreshold() const
|
||||||
|
{
|
||||||
|
const PDFReal snapPointDistanceThresholdPixels = PDFWidgetUtils::scaleDPI_x(m_widget, 6.0);
|
||||||
|
const PDFReal snapPointDistanceThreshold = m_widget->getDrawWidgetProxy()->transformPixelToDeviceSpace(snapPointDistanceThresholdPixels);
|
||||||
|
return snapPointDistanceThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::grabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
void PDFPageContentScene::grabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_ASSERT(isActive());
|
Q_ASSERT(isActive());
|
||||||
@ -431,6 +633,16 @@ void PDFPageContentScene::ungrabMouse(const MouseEventInfo& info, QMouseEvent* e
|
|||||||
Q_ASSERT(m_mouseGrabInfo.mouseGrabNesting >= 0);
|
Q_ASSERT(m_mouseGrabInfo.mouseGrabNesting >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFWidget* PDFPageContentScene::widget() const
|
||||||
|
{
|
||||||
|
return m_widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentScene::setWidget(PDFWidget* newWidget)
|
||||||
|
{
|
||||||
|
m_widget = newWidget;
|
||||||
|
}
|
||||||
|
|
||||||
bool PDFPageContentScene::isActive() const
|
bool PDFPageContentScene::isActive() const
|
||||||
{
|
{
|
||||||
return m_isActive;
|
return m_isActive;
|
||||||
@ -501,6 +713,67 @@ void PDFPageContentElementLine::drawPage(QPainter* painter,
|
|||||||
painter->drawLine(getLine());
|
painter->drawLine(getLine());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint PDFPageContentElementLine::getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const
|
||||||
|
{
|
||||||
|
if ((m_line.p1() - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return Pt1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_line.p2() - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return Pt2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF vl = m_line.p2() - m_line.p1();
|
||||||
|
QPointF vp = point - m_line.p1();
|
||||||
|
|
||||||
|
const qreal lengthSquared = QPointF::dotProduct(vp, vp);
|
||||||
|
|
||||||
|
if (qFuzzyIsNull(lengthSquared))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
const qreal t = QPointF::dotProduct(vl, vp) / lengthSquared;
|
||||||
|
if (t >= 0.0 && t <= 1.0)
|
||||||
|
{
|
||||||
|
QPointF projectedPoint = m_line.p1() + t * vl;
|
||||||
|
if ((point - projectedPoint).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return Translate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementLine::performManipulation(uint mode, const QPointF& offset)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case None:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pt1:
|
||||||
|
m_line.setP1(m_line.p1() + offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pt2:
|
||||||
|
m_line.setP2(m_line.p2() + offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Translate:
|
||||||
|
m_line.translate(offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PDFPageContentElementLine::LineGeometry PDFPageContentElementLine::getGeometry() const
|
PDFPageContentElementLine::LineGeometry PDFPageContentElementLine::getGeometry() const
|
||||||
{
|
{
|
||||||
return m_geometry;
|
return m_geometry;
|
||||||
@ -591,6 +864,16 @@ void PDFPageContentSvgElement::drawPage(QPainter* painter,
|
|||||||
m_renderer->render(painter, targetRenderBox);
|
m_renderer->render(painter, targetRenderBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint PDFPageContentSvgElement::getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const
|
||||||
|
{
|
||||||
|
return getRectangleManipulationMode(getRectangle(), point, snapPointDistanceThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentSvgElement::performManipulation(uint mode, const QPointF& offset)
|
||||||
|
{
|
||||||
|
performRectangleManipulation(m_rectangle, mode, offset);
|
||||||
|
}
|
||||||
|
|
||||||
const QByteArray& PDFPageContentSvgElement::getContent() const
|
const QByteArray& PDFPageContentSvgElement::getContent() const
|
||||||
{
|
{
|
||||||
return m_content;
|
return m_content;
|
||||||
@ -650,6 +933,34 @@ void PDFPageContentElementDot::drawPage(QPainter* painter,
|
|||||||
painter->drawPoint(m_point);
|
painter->drawPoint(m_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint PDFPageContentElementDot::getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const
|
||||||
|
{
|
||||||
|
if ((m_point - point).manhattanLength() < snapPointDistanceThreshold)
|
||||||
|
{
|
||||||
|
return Translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementDot::performManipulation(uint mode, const QPointF& offset)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case None:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Translate:
|
||||||
|
m_point += offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QPointF PDFPageContentElementDot::getPoint() const
|
QPointF PDFPageContentElementDot::getPoint() const
|
||||||
{
|
{
|
||||||
return m_point;
|
return m_point;
|
||||||
@ -696,6 +1007,40 @@ void PDFPageContentElementFreehandCurve::drawPage(QPainter* painter,
|
|||||||
painter->drawPath(getCurve());
|
painter->drawPath(getCurve());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint PDFPageContentElementFreehandCurve::getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(snapPointDistanceThreshold);
|
||||||
|
|
||||||
|
if (m_curve.isEmpty())
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_curve.controlPointRect().contains(point))
|
||||||
|
{
|
||||||
|
return Translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementFreehandCurve::performManipulation(uint mode, const QPointF& offset)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case None:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Translate:
|
||||||
|
m_curve.translate(offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QPainterPath PDFPageContentElementFreehandCurve::getCurve() const
|
QPainterPath PDFPageContentElementFreehandCurve::getCurve() const
|
||||||
{
|
{
|
||||||
return m_curve;
|
return m_curve;
|
||||||
@ -732,7 +1077,7 @@ PDFPageContentElementManipulator::PDFPageContentElementManipulator(PDFPageConten
|
|||||||
|
|
||||||
void PDFPageContentElementManipulator::reset()
|
void PDFPageContentElementManipulator::reset()
|
||||||
{
|
{
|
||||||
stopManipulation();
|
cancelManipulation();
|
||||||
deselectAll();
|
deselectAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -863,12 +1208,12 @@ void PDFPageContentElementManipulator::select(const std::set<PDFInteger>& ids)
|
|||||||
|
|
||||||
void PDFPageContentElementManipulator::selectNew(PDFInteger id)
|
void PDFPageContentElementManipulator::selectNew(PDFInteger id)
|
||||||
{
|
{
|
||||||
update(id, Select | Clear);
|
update(id, SelectionModes(Select | Clear));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentElementManipulator::selectNew(const std::set<PDFInteger>& ids)
|
void PDFPageContentElementManipulator::selectNew(const std::set<PDFInteger>& ids)
|
||||||
{
|
{
|
||||||
update(ids, Select | Clear);
|
update(ids, SelectionModes(Select | Clear));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentElementManipulator::deselect(PDFInteger id)
|
void PDFPageContentElementManipulator::deselect(PDFInteger id)
|
||||||
@ -886,22 +1231,118 @@ void PDFPageContentElementManipulator::deselectAll()
|
|||||||
update(-1, Clear);
|
update(-1, Clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDFPageContentElementManipulator::isManipulationAllowed(PDFInteger pageIndex) const
|
||||||
|
{
|
||||||
|
for (const PDFInteger id : m_selection)
|
||||||
|
{
|
||||||
|
if (const PDFPageContentElement* element = m_scene->getElementById(id))
|
||||||
|
{
|
||||||
|
if (element->getPageIndex() == pageIndex)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPageContentElementManipulator::manipulateDeleteSelection()
|
void PDFPageContentElementManipulator::manipulateDeleteSelection()
|
||||||
{
|
{
|
||||||
stopManipulation();
|
cancelManipulation();
|
||||||
m_scene->removeElementsById(m_selection);
|
m_scene->removeElementsById(m_selection);
|
||||||
deselectAll();
|
deselectAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentElementManipulator::stopManipulation()
|
void PDFPageContentElementManipulator::startManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint,
|
||||||
|
PDFReal snapPointDistanceThreshold)
|
||||||
{
|
{
|
||||||
if (m_isManipulationInProgress)
|
Q_ASSERT(!isManipulationInProgress());
|
||||||
|
|
||||||
|
// Collect elements to be manipulated
|
||||||
|
for (const PDFInteger id : m_selection)
|
||||||
|
{
|
||||||
|
const PDFPageContentElement* element = m_scene->getElementById(id);
|
||||||
|
|
||||||
|
if (!element || element->getPageIndex() != pageIndex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint manipulationMode = element->getManipulationMode(startPoint, snapPointDistanceThreshold);
|
||||||
|
if (manipulationMode)
|
||||||
|
{
|
||||||
|
// Jakub Melka: yes, we can manipulate this element
|
||||||
|
m_manipulatedElements.emplace_back(element->clone());
|
||||||
|
m_manipulationModes[id] = manipulationMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lastUpdatedPoint = startPoint;
|
||||||
|
updateManipulation(pageIndex, startPoint, currentPoint);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::updateManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint)
|
||||||
|
{
|
||||||
|
Q_UNUSED(startPoint);
|
||||||
|
|
||||||
|
QPointF offset = currentPoint - m_lastUpdatedPoint;
|
||||||
|
|
||||||
|
for (const auto& element : m_manipulatedElements)
|
||||||
|
{
|
||||||
|
if (element->getElementId() == pageIndex)
|
||||||
|
{
|
||||||
|
element->performManipulation(m_manipulationModes[element->getElementId()], offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::finishManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint,
|
||||||
|
bool createCopy)
|
||||||
|
{
|
||||||
|
Q_ASSERT(isManipulationInProgress());
|
||||||
|
updateManipulation(pageIndex, startPoint, currentPoint);
|
||||||
|
|
||||||
|
if (createCopy)
|
||||||
|
{
|
||||||
|
for (const auto& element : m_manipulatedElements)
|
||||||
|
{
|
||||||
|
m_scene->addElement(element->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto& element : m_manipulatedElements)
|
||||||
|
{
|
||||||
|
m_scene->replaceElement(element->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelManipulation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::cancelManipulation()
|
||||||
|
{
|
||||||
|
if (isManipulationInProgress())
|
||||||
{
|
{
|
||||||
m_isManipulationInProgress = false;
|
m_isManipulationInProgress = false;
|
||||||
m_manipulatedElements.clear();
|
m_manipulatedElements.clear();
|
||||||
m_manipulationModes.clear();
|
m_manipulationModes.clear();
|
||||||
emit stateChanged();
|
emit stateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!m_isManipulationInProgress);
|
||||||
|
Q_ASSERT(m_manipulatedElements.empty());
|
||||||
|
Q_ASSERT(m_manipulationModes.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -31,6 +31,7 @@ class QSvgRenderer;
|
|||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
class PDFWidget;
|
||||||
class PDFPageContentScene;
|
class PDFPageContentScene;
|
||||||
|
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentElement
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElement
|
||||||
@ -48,6 +49,19 @@ public:
|
|||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const = 0;
|
QList<PDFRenderError>& errors) const = 0;
|
||||||
|
|
||||||
|
/// Returns manipulation mode. If manipulation mode is zero, then element
|
||||||
|
/// cannot be manipulated. If it is nonzero, then element can be manipulated
|
||||||
|
/// in some way.
|
||||||
|
/// \param point Point on page
|
||||||
|
/// \param snapPointDistanceTreshold Snap point threshold
|
||||||
|
virtual uint getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const = 0;
|
||||||
|
|
||||||
|
/// Performs manipulation of given mode. Mode must be the one returned
|
||||||
|
/// from function getManipulationMode. \sa getManipulationMode
|
||||||
|
/// \param mode Mode
|
||||||
|
/// \param offset Offset
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) = 0;
|
||||||
|
|
||||||
PDFInteger getPageIndex() const;
|
PDFInteger getPageIndex() const;
|
||||||
void setPageIndex(PDFInteger newPageIndex);
|
void setPageIndex(PDFInteger newPageIndex);
|
||||||
|
|
||||||
@ -55,6 +69,31 @@ public:
|
|||||||
void setElementId(PDFInteger newElementId);
|
void setElementId(PDFInteger newElementId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
enum ManipulationModes : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Translate,
|
||||||
|
Top,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
TopLeft,
|
||||||
|
TopRight,
|
||||||
|
BottomLeft,
|
||||||
|
BottomRight,
|
||||||
|
Pt1,
|
||||||
|
Pt2
|
||||||
|
};
|
||||||
|
|
||||||
|
uint getRectangleManipulationMode(const QRectF& rectangle,
|
||||||
|
const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const;
|
||||||
|
|
||||||
|
void performRectangleManipulation(QRectF& rectangle,
|
||||||
|
uint mode,
|
||||||
|
const QPointF& offset);
|
||||||
|
|
||||||
PDFInteger m_elementId = -1;
|
PDFInteger m_elementId = -1;
|
||||||
PDFInteger m_pageIndex = -1;
|
PDFInteger m_pageIndex = -1;
|
||||||
};
|
};
|
||||||
@ -96,6 +135,11 @@ public:
|
|||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_rounded = false;
|
bool m_rounded = false;
|
||||||
QRectF m_rectangle;
|
QRectF m_rectangle;
|
||||||
@ -122,6 +166,11 @@ public:
|
|||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
|
||||||
LineGeometry getGeometry() const;
|
LineGeometry getGeometry() const;
|
||||||
void setGeometry(LineGeometry newGeometry);
|
void setGeometry(LineGeometry newGeometry);
|
||||||
|
|
||||||
@ -147,6 +196,11 @@ public:
|
|||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
|
||||||
|
|
||||||
QPointF getPoint() const;
|
QPointF getPoint() const;
|
||||||
void setPoint(QPointF newPoint);
|
void setPoint(QPointF newPoint);
|
||||||
@ -169,6 +223,11 @@ public:
|
|||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
|
||||||
QPainterPath getCurve() const;
|
QPainterPath getCurve() const;
|
||||||
void setCurve(QPainterPath newCurve);
|
void setCurve(QPainterPath newCurve);
|
||||||
|
|
||||||
@ -196,6 +255,11 @@ public:
|
|||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
|
||||||
const QByteArray& getContent() const;
|
const QByteArray& getContent() const;
|
||||||
void setContent(const QByteArray& newContent);
|
void setContent(const QByteArray& newContent);
|
||||||
|
|
||||||
@ -245,22 +309,38 @@ public:
|
|||||||
void deselect(const std::set<PDFInteger>& ids);
|
void deselect(const std::set<PDFInteger>& ids);
|
||||||
void deselectAll();
|
void deselectAll();
|
||||||
|
|
||||||
|
bool isManipulationAllowed(PDFInteger pageIndex) const;
|
||||||
bool isManipulationInProgress() const { return m_isManipulationInProgress; }
|
bool isManipulationInProgress() const { return m_isManipulationInProgress; }
|
||||||
|
|
||||||
void manipulateDeleteSelection();
|
void manipulateDeleteSelection();
|
||||||
|
|
||||||
|
void startManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint,
|
||||||
|
PDFReal snapPointDistanceThreshold);
|
||||||
|
|
||||||
|
void updateManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint);
|
||||||
|
|
||||||
|
void finishManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint,
|
||||||
|
bool createCopy);
|
||||||
|
|
||||||
|
void cancelManipulation();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void selectionChanged();
|
void selectionChanged();
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void stopManipulation();
|
|
||||||
|
|
||||||
PDFPageContentScene* m_scene;
|
PDFPageContentScene* m_scene;
|
||||||
std::set<PDFInteger> m_selection;
|
std::set<PDFInteger> m_selection;
|
||||||
bool m_isManipulationInProgress;
|
bool m_isManipulationInProgress;
|
||||||
std::vector<std::unique_ptr<PDFPageContentElement>> m_manipulatedElements;
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_manipulatedElements;
|
||||||
std::map<PDFInteger, uint> m_manipulationModes;
|
std::map<PDFInteger, uint> m_manipulationModes;
|
||||||
|
QPointF m_lastUpdatedPoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentScene : public QObject,
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentScene : public QObject,
|
||||||
@ -278,6 +358,11 @@ public:
|
|||||||
/// \param element Element
|
/// \param element Element
|
||||||
void addElement(PDFPageContentElement* element);
|
void addElement(PDFPageContentElement* element);
|
||||||
|
|
||||||
|
/// Replaces element in the page content scene, scene
|
||||||
|
/// takes ownership over the element.
|
||||||
|
/// \param element Element
|
||||||
|
void replaceElement(PDFPageContentElement* element);
|
||||||
|
|
||||||
/// Returns element by its id (identifier number)
|
/// Returns element by its id (identifier number)
|
||||||
/// \param id Element id
|
/// \param id Element id
|
||||||
PDFPageContentElement* getElementById(PDFInteger id) const;
|
PDFPageContentElement* getElementById(PDFInteger id) const;
|
||||||
@ -317,6 +402,9 @@ public:
|
|||||||
PDFTextLayoutGetter& layoutGetter,
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
PDFWidget* widget() const;
|
||||||
|
void setWidget(PDFWidget* newWidget);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/// This signal is emitted when scene has changed (including graphics)
|
/// This signal is emitted when scene has changed (including graphics)
|
||||||
void sceneChanged();
|
void sceneChanged();
|
||||||
@ -329,6 +417,8 @@ private:
|
|||||||
QPoint widgetMouseStartPos;
|
QPoint widgetMouseStartPos;
|
||||||
QPoint widgetMouseCurrentPos;
|
QPoint widgetMouseCurrentPos;
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
|
PDFInteger pageIndex = -1;
|
||||||
|
QPointF pagePos;
|
||||||
|
|
||||||
bool isValid() const { return !hoveredElementIds.empty(); }
|
bool isValid() const { return !hoveredElementIds.empty(); }
|
||||||
};
|
};
|
||||||
@ -343,6 +433,8 @@ private:
|
|||||||
bool isMouseGrabbed() const { return mouseGrabNesting > 0; }
|
bool isMouseGrabbed() const { return mouseGrabNesting > 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PDFReal getSnapPointDistanceThreshold() const;
|
||||||
|
|
||||||
bool isMouseGrabbed() const { return m_mouseGrabInfo.isMouseGrabbed(); }
|
bool isMouseGrabbed() const { return m_mouseGrabInfo.isMouseGrabbed(); }
|
||||||
|
|
||||||
/// Grabs mouse input, if mouse is already grabbed, or if event
|
/// Grabs mouse input, if mouse is already grabbed, or if event
|
||||||
@ -358,6 +450,7 @@ private:
|
|||||||
|
|
||||||
PDFInteger m_firstFreeId;
|
PDFInteger m_firstFreeId;
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
|
PDFWidget* m_widget;
|
||||||
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
||||||
std::optional<QCursor> m_cursor;
|
std::optional<QCursor> m_cursor;
|
||||||
PDFPageContentElementManipulator m_manipulator;
|
PDFPageContentElementManipulator m_manipulator;
|
||||||
|
@ -137,7 +137,9 @@ void SignaturePlugin::setWidget(pdf::PDFWidget* widget)
|
|||||||
toolManager->addTool(tool);
|
toolManager->addTool(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_widget->addInputInterface(&m_scene);
|
||||||
m_widget->getDrawWidgetProxy()->registerDrawInterface(&m_scene);
|
m_widget->getDrawWidgetProxy()->registerDrawInterface(&m_scene);
|
||||||
|
m_scene.setWidget(m_widget);
|
||||||
connect(&m_scene, &pdf::PDFPageContentScene::sceneChanged, this, &SignaturePlugin::onSceneChanged);
|
connect(&m_scene, &pdf::PDFPageContentScene::sceneChanged, this, &SignaturePlugin::onSceneChanged);
|
||||||
connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear);
|
connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear);
|
||||||
connect(activateAction, &QAction::triggered, this, &SignaturePlugin::setActive);
|
connect(activateAction, &QAction::triggered, this, &SignaturePlugin::setActive);
|
||||||
|
Reference in New Issue
Block a user