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:
@ -17,11 +17,14 @@
|
||||
|
||||
#include "pdfpagecontentelements.h"
|
||||
#include "pdfpainterutils.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QSvgRenderer>
|
||||
#include <QApplication>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
@ -36,6 +39,16 @@ void PDFPageContentElement::setPageIndex(PDFInteger newPageIndex)
|
||||
m_pageIndex = newPageIndex;
|
||||
}
|
||||
|
||||
PDFInteger PDFPageContentElement::getElementId() const
|
||||
{
|
||||
return m_elementId;
|
||||
}
|
||||
|
||||
void PDFPageContentElement::setElementId(PDFInteger newElementId)
|
||||
{
|
||||
m_elementId = newElementId;
|
||||
}
|
||||
|
||||
const QPen& PDFPageContentStyledElement::getPen() const
|
||||
{
|
||||
return m_pen;
|
||||
@ -59,6 +72,7 @@ void PDFPageContentStyledElement::setBrush(const QBrush& newBrush)
|
||||
PDFPageContentElementRectangle* PDFPageContentElementRectangle::clone() const
|
||||
{
|
||||
PDFPageContentElementRectangle* copy = new PDFPageContentElementRectangle();
|
||||
copy->setElementId(getElementId());
|
||||
copy->setPageIndex(getPageIndex());
|
||||
copy->setPen(getPen());
|
||||
copy->setBrush(getBrush());
|
||||
@ -123,7 +137,9 @@ void PDFPageContentElementRectangle::drawPage(QPainter* painter,
|
||||
|
||||
PDFPageContentScene::PDFPageContentScene(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_isActive(false)
|
||||
m_firstFreeId(1),
|
||||
m_isActive(false),
|
||||
m_manipulator(this, nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
@ -135,10 +151,22 @@ PDFPageContentScene::~PDFPageContentScene()
|
||||
|
||||
void PDFPageContentScene::addElement(PDFPageContentElement* element)
|
||||
{
|
||||
element->setElementId(m_firstFreeId++);
|
||||
m_elements.emplace_back(element);
|
||||
emit sceneChanged();
|
||||
}
|
||||
|
||||
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; });
|
||||
if (it != m_elements.cend())
|
||||
{
|
||||
return it->get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PDFPageContentScene::clear()
|
||||
{
|
||||
if (!m_elements.empty())
|
||||
@ -168,32 +196,127 @@ void PDFPageContentScene::keyReleaseEvent(QWidget* widget, QKeyEvent* event)
|
||||
|
||||
void PDFPageContentScene::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->ignore();
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||
if (info.isValid() || isMouseGrabbed())
|
||||
{
|
||||
// We to handle selecting/deselecting the active
|
||||
// item. After that, accept the item.
|
||||
if (info.isValid() && event->button() == Qt::LeftButton)
|
||||
{
|
||||
info.widgetMouseStartPos = event->pos();
|
||||
info.timer.start();
|
||||
|
||||
if (!m_manipulator.isManipulationInProgress())
|
||||
{
|
||||
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
||||
const bool isCtrl = keyboardModifiers.testFlag(Qt::CTRL);
|
||||
const bool isShift = keyboardModifiers.testFlag(Qt::SHIFT);
|
||||
|
||||
if (isCtrl && !isShift)
|
||||
{
|
||||
m_manipulator.select(info.hoveredElementIds);
|
||||
}
|
||||
else if (!isCtrl && isShift)
|
||||
{
|
||||
m_manipulator.deselect(info.hoveredElementIds);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_manipulator.selectNew(info.hoveredElementIds);
|
||||
}
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
grabMouse(info, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentScene::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->ignore();
|
||||
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If mouse is grabbed, then event is accepted always (because
|
||||
// we get Press event, when we grabbed the mouse, then we will
|
||||
// wait for corresponding release event while all mouse move events
|
||||
// will be accepted, even if editor doesn't accept them.
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentScene::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->ignore();
|
||||
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
event->accept();
|
||||
m_manipulator.finishManipulation();
|
||||
}
|
||||
|
||||
ungrabMouse(info, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentScene::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->ignore();
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||
if (info.isValid())
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
// If mouse is grabbed, then event is accepted always (because
|
||||
// we get Press event, when we grabbed the mouse, then we will
|
||||
// wait for corresponding release event while all mouse move events
|
||||
// will be accepted, even if editor doesn't accept them.
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentScene::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->ignore();
|
||||
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We will accept mouse wheel events, if we are grabbing the mouse.
|
||||
// We do not want to zoom in/zoom out while grabbing.
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
QString PDFPageContentScene::getTooltip() const
|
||||
@ -234,6 +357,80 @@ void PDFPageContentScene::drawPage(QPainter* painter,
|
||||
}
|
||||
}
|
||||
|
||||
PDFPageContentScene::MouseEventInfo PDFPageContentScene::getMouseEventInfo(QWidget* widget, QPoint point)
|
||||
{
|
||||
MouseEventInfo result;
|
||||
|
||||
Q_ASSERT(isActive());
|
||||
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
result = m_mouseGrabInfo.info;
|
||||
result.widgetMouseCurrentPos = point;
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
||||
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFPageContentScene::grabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||
{
|
||||
Q_ASSERT(isActive());
|
||||
|
||||
if (event->type() == QEvent::MouseButtonDblClick)
|
||||
{
|
||||
// Double clicks doesn't grab the mouse
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(event->type() == QEvent::MouseButtonPress);
|
||||
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
// If mouse is already grabbed, then when new mouse button is pressed,
|
||||
// we just increase nesting level and accept the mouse event. We are
|
||||
// accepting all mouse events, if mouse is grabbed.
|
||||
++m_mouseGrabInfo.mouseGrabNesting;
|
||||
event->accept();
|
||||
}
|
||||
else if (event->isAccepted())
|
||||
{
|
||||
// Event is accepted and we are not grabbing the mouse. We must start
|
||||
// grabbing the mouse.
|
||||
Q_ASSERT(m_mouseGrabInfo.mouseGrabNesting == 0);
|
||||
++m_mouseGrabInfo.mouseGrabNesting;
|
||||
m_mouseGrabInfo.info = info;
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentScene::ungrabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(info);
|
||||
Q_ASSERT(isActive());
|
||||
Q_ASSERT(event->type() == QEvent::MouseButtonRelease);
|
||||
|
||||
if (isMouseGrabbed())
|
||||
{
|
||||
// Mouse is being grabbed, decrease nesting level. We must also accept
|
||||
// mouse release event, because mouse is being grabbed.
|
||||
--m_mouseGrabInfo.mouseGrabNesting;
|
||||
event->accept();
|
||||
|
||||
if (!isMouseGrabbed())
|
||||
{
|
||||
m_mouseGrabInfo.info = MouseEventInfo();
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT(m_mouseGrabInfo.mouseGrabNesting >= 0);
|
||||
}
|
||||
|
||||
bool PDFPageContentScene::isActive() const
|
||||
{
|
||||
return m_isActive;
|
||||
@ -244,6 +441,25 @@ void PDFPageContentScene::setActive(bool newIsActive)
|
||||
if (m_isActive != newIsActive)
|
||||
{
|
||||
m_isActive = newIsActive;
|
||||
|
||||
if (!newIsActive)
|
||||
{
|
||||
m_mouseGrabInfo = MouseGrabInfo();
|
||||
m_manipulator.reset();
|
||||
}
|
||||
|
||||
emit sceneChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentScene::removeElementsById(const std::set<PDFInteger>& selection)
|
||||
{
|
||||
const size_t oldSize = m_elements.size();
|
||||
m_elements.erase(std::remove_if(m_elements.begin(), m_elements.end(), [&selection](const auto& element){ return selection.count(element->getElementId()); }), m_elements.end());
|
||||
const size_t newSize = m_elements.size();
|
||||
|
||||
if (newSize < oldSize)
|
||||
{
|
||||
emit sceneChanged();
|
||||
}
|
||||
}
|
||||
@ -251,6 +467,7 @@ void PDFPageContentScene::setActive(bool newIsActive)
|
||||
PDFPageContentElementLine* PDFPageContentElementLine::clone() const
|
||||
{
|
||||
PDFPageContentElementLine* copy = new PDFPageContentElementLine();
|
||||
copy->setElementId(getElementId());
|
||||
copy->setPageIndex(getPageIndex());
|
||||
copy->setPen(getPen());
|
||||
copy->setBrush(getBrush());
|
||||
@ -328,6 +545,7 @@ PDFPageContentSvgElement::~PDFPageContentSvgElement()
|
||||
PDFPageContentSvgElement* PDFPageContentSvgElement::clone() const
|
||||
{
|
||||
PDFPageContentSvgElement* copy = new PDFPageContentSvgElement();
|
||||
copy->setElementId(getElementId());
|
||||
copy->setPageIndex(getPageIndex());
|
||||
copy->setRectangle(getRectangle());
|
||||
copy->setContent(getContent());
|
||||
@ -400,6 +618,7 @@ void PDFPageContentSvgElement::setRectangle(const QRectF& newRectangle)
|
||||
PDFPageContentElementDot* PDFPageContentElementDot::clone() const
|
||||
{
|
||||
PDFPageContentElementDot* copy = new PDFPageContentElementDot();
|
||||
copy->setElementId(getElementId());
|
||||
copy->setPageIndex(getPageIndex());
|
||||
copy->setPen(getPen());
|
||||
copy->setBrush(getBrush());
|
||||
@ -444,6 +663,7 @@ void PDFPageContentElementDot::setPoint(QPointF newPoint)
|
||||
PDFPageContentElementFreehandCurve* PDFPageContentElementFreehandCurve::clone() const
|
||||
{
|
||||
PDFPageContentElementFreehandCurve* copy = new PDFPageContentElementFreehandCurve();
|
||||
copy->setElementId(getElementId());
|
||||
copy->setPageIndex(getPageIndex());
|
||||
copy->setPen(getPen());
|
||||
copy->setBrush(getBrush());
|
||||
@ -502,4 +722,186 @@ void PDFPageContentElementFreehandCurve::clear()
|
||||
m_curve = QPainterPath();
|
||||
}
|
||||
|
||||
PDFPageContentElementManipulator::PDFPageContentElementManipulator(PDFPageContentScene* scene, QObject* parent) :
|
||||
QObject(parent),
|
||||
m_scene(scene),
|
||||
m_isManipulationInProgress(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::reset()
|
||||
{
|
||||
stopManipulation();
|
||||
deselectAll();
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::update(PDFInteger id, SelectionModes modes)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
if (modes.testFlag(Clear))
|
||||
{
|
||||
modified = !m_selection.empty();
|
||||
m_selection.clear();
|
||||
}
|
||||
|
||||
// Is id valid?
|
||||
if (id > 0)
|
||||
{
|
||||
if (modes.testFlag(Select))
|
||||
{
|
||||
if (!isSelected(id))
|
||||
{
|
||||
modified = true;
|
||||
m_selection.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (modes.testFlag(Deselect))
|
||||
{
|
||||
if (isSelected(id))
|
||||
{
|
||||
modified = true;
|
||||
m_selection.erase(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (modes.testFlag(Toggle))
|
||||
{
|
||||
if (isSelected(id))
|
||||
{
|
||||
m_selection.erase(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selection.insert(id);
|
||||
}
|
||||
|
||||
// When toggle is performed, selection is always changed
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (modified)
|
||||
{
|
||||
emit selectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::update(const std::set<PDFInteger>& ids, SelectionModes modes)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
if (modes.testFlag(Clear))
|
||||
{
|
||||
modified = !m_selection.empty();
|
||||
m_selection.clear();
|
||||
}
|
||||
|
||||
// Is id valid?
|
||||
if (!ids.empty())
|
||||
{
|
||||
if (modes.testFlag(Select))
|
||||
{
|
||||
for (auto id : ids)
|
||||
{
|
||||
if (!isSelected(id))
|
||||
{
|
||||
modified = true;
|
||||
m_selection.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modes.testFlag(Deselect))
|
||||
{
|
||||
for (auto id : ids)
|
||||
{
|
||||
if (isSelected(id))
|
||||
{
|
||||
modified = true;
|
||||
m_selection.erase(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modes.testFlag(Toggle))
|
||||
{
|
||||
for (auto id : ids)
|
||||
{
|
||||
if (isSelected(id))
|
||||
{
|
||||
m_selection.erase(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selection.insert(id);
|
||||
}
|
||||
|
||||
// When toggle is performed, selection is always changed
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modified)
|
||||
{
|
||||
emit selectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::select(PDFInteger id)
|
||||
{
|
||||
update(id, Select);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::select(const std::set<PDFInteger>& ids)
|
||||
{
|
||||
update(ids, Select);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::selectNew(PDFInteger id)
|
||||
{
|
||||
update(id, Select | Clear);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::selectNew(const std::set<PDFInteger>& ids)
|
||||
{
|
||||
update(ids, Select | Clear);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::deselect(PDFInteger id)
|
||||
{
|
||||
update(id, Deselect);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::deselect(const std::set<PDFInteger>& ids)
|
||||
{
|
||||
update(ids, Deselect);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::deselectAll()
|
||||
{
|
||||
update(-1, Clear);
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::manipulateDeleteSelection()
|
||||
{
|
||||
stopManipulation();
|
||||
m_scene->removeElementsById(m_selection);
|
||||
deselectAll();
|
||||
}
|
||||
|
||||
void PDFPageContentElementManipulator::stopManipulation()
|
||||
{
|
||||
if (m_isManipulationInProgress)
|
||||
{
|
||||
m_isManipulationInProgress = false;
|
||||
m_manipulatedElements.clear();
|
||||
m_manipulationModes.clear();
|
||||
emit stateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
Reference in New Issue
Block a user