mirror of https://github.com/JakubMelka/PDF4QT.git
Mouse grabbing
This commit is contained in:
parent
c9d2c3dd8b
commit
bfb26c4807
|
@ -1172,6 +1172,8 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
|
||||||
// printing to the printer.
|
// printing to the printer.
|
||||||
if (isContentVisible && m_target == Target::View)
|
if (isContentVisible && m_target == Target::View)
|
||||||
{
|
{
|
||||||
|
PDFPainterStateGuard guard(painter);
|
||||||
|
painter->resetMatrix();
|
||||||
drawWidgetAnnotationHighlight(annotationRectangle, annotation.annotation.get(), painter, userSpaceToDeviceSpace);
|
drawWidgetAnnotationHighlight(annotationRectangle, annotation.annotation.get(), painter, userSpaceToDeviceSpace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1312,7 +1312,6 @@ public:
|
||||||
PDFFormManager* getFormManager() const;
|
PDFFormManager* getFormManager() const;
|
||||||
void setFormManager(PDFFormManager* formManager);
|
void setFormManager(PDFFormManager* formManager);
|
||||||
|
|
||||||
protected:
|
|
||||||
struct PageAnnotation
|
struct PageAnnotation
|
||||||
{
|
{
|
||||||
PDFAppeareanceStreams::Appearance appearance = PDFAppeareanceStreams::Appearance::Normal;
|
PDFAppeareanceStreams::Appearance appearance = PDFAppeareanceStreams::Appearance::Normal;
|
||||||
|
@ -1374,6 +1373,7 @@ protected:
|
||||||
/// Returns true, if any page in the given indices has annotation
|
/// Returns true, if any page in the given indices has annotation
|
||||||
bool hasAnyPageAnnotation(const std::vector<PDFInteger>& pageIndices) const;
|
bool hasAnyPageAnnotation(const std::vector<PDFInteger>& pageIndices) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
void drawWidgetAnnotationHighlight(QRectF annotationRectangle,
|
void drawWidgetAnnotationHighlight(QRectF annotationRectangle,
|
||||||
const PDFAnnotation* annotation,
|
const PDFAnnotation* annotation,
|
||||||
QPainter* painter,
|
QPainter* painter,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "pdfform.h"
|
#include "pdfform.h"
|
||||||
#include "pdfdocument.h"
|
#include "pdfdocument.h"
|
||||||
#include "pdfdrawspacecontroller.h"
|
#include "pdfdrawspacecontroller.h"
|
||||||
|
#include "pdfdrawwidget.h"
|
||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
@ -123,6 +124,17 @@ const PDFFormField* PDFForm::getFormFieldForWidget(PDFObjectReference widget) co
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFFormField* PDFForm::getFormFieldForWidget(PDFObjectReference widget)
|
||||||
|
{
|
||||||
|
auto it = m_widgetToFormField.find(widget);
|
||||||
|
if (it != m_widgetToFormField.cend())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFFormField::fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping)
|
void PDFFormField::fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping)
|
||||||
{
|
{
|
||||||
for (const auto& childField : m_childFields)
|
for (const auto& childField : m_childFields)
|
||||||
|
@ -609,26 +621,193 @@ void PDFFormManager::keyReleaseEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
|
||||||
void PDFFormManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
void PDFFormManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
if (!hasForm())
|
||||||
Q_UNUSED(event);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||||
|
if (info.isValid())
|
||||||
|
{
|
||||||
|
Q_ASSERT(info.editor);
|
||||||
|
|
||||||
|
// We try to set focus on editor
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
setFocusToEditor(info.editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
info.editor->mousePressEvent(widget, event);
|
||||||
|
grabMouse(info, event);
|
||||||
|
}
|
||||||
|
else if (!isMouseGrabbed())
|
||||||
|
{
|
||||||
|
// Mouse is not grabbed, user clicked elsewhere, unfocus editor
|
||||||
|
setFocusToEditor(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFFormManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
void PDFFormManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
if (!hasForm())
|
||||||
Q_UNUSED(event);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||||
|
if (info.isValid())
|
||||||
|
{
|
||||||
|
Q_ASSERT(info.editor);
|
||||||
|
info.editor->mouseReleaseEvent(widget, event);
|
||||||
|
ungrabMouse(info, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFFormManager::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
void PDFFormManager::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
if (!hasForm())
|
||||||
Q_UNUSED(event);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||||
|
if (info.isValid())
|
||||||
|
{
|
||||||
|
Q_ASSERT(info.editor);
|
||||||
|
info.editor->mouseMoveEvent(widget, event);
|
||||||
|
|
||||||
|
// 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 PDFFormManager::wheelEvent(QWidget* widget, QWheelEvent* event)
|
void PDFFormManager::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFFormManager::grabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
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 PDFFormManager::ungrabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(info);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFFormManager::MouseEventInfo PDFFormManager::getMouseEventInfo(QWidget* widget, QPoint point)
|
||||||
|
{
|
||||||
|
MouseEventInfo result;
|
||||||
|
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
result = m_mouseGrabInfo.info;
|
||||||
|
result.mousePosition = result.deviceToWidget.map(point);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PDFInteger> currentPages = m_proxy->getWidget()->getDrawWidget()->getCurrentPages();
|
||||||
|
|
||||||
|
if (!m_annotationManager->hasAnyPageAnnotation(currentPages))
|
||||||
|
{
|
||||||
|
// All pages doesn't have annotation
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
||||||
|
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
||||||
|
{
|
||||||
|
const PDFAnnotationManager::PageAnnotations& pageAnnotations = m_annotationManager->getPageAnnotations(snapshotItem.pageIndex);
|
||||||
|
for (const PDFAnnotationManager::PageAnnotation& pageAnnotation : pageAnnotations.annotations)
|
||||||
|
{
|
||||||
|
if (pageAnnotation.annotation->isReplyTo())
|
||||||
|
{
|
||||||
|
// Annotation is reply to another annotation, do not interact with it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageAnnotation.annotation->getType() != AnnotationType::Widget)
|
||||||
|
{
|
||||||
|
// Annotation is not widget annotation (form field), do not interact with it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF annotationRect = pageAnnotation.annotation->getRectangle();
|
||||||
|
QMatrix widgetToDevice = m_annotationManager->prepareTransformations(snapshotItem.pageToDeviceMatrix, widget, pageAnnotation.annotation->getEffectiveFlags(), m_document->getCatalog()->getPage(snapshotItem.pageIndex), annotationRect);
|
||||||
|
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRect(annotationRect);
|
||||||
|
path = widgetToDevice.map(path);
|
||||||
|
|
||||||
|
if (path.contains(point))
|
||||||
|
{
|
||||||
|
if (PDFFormField* formField = getFormFieldForWidget(pageAnnotation.annotation->getSelfReference()))
|
||||||
|
{
|
||||||
|
result.formField = formField;
|
||||||
|
result.deviceToWidget = widgetToDevice.inverted();
|
||||||
|
result.mousePosition = result.deviceToWidget.map(point);
|
||||||
|
result.editor = getEditor(formField);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<QCursor>& PDFFormManager::getCursor() const
|
const std::optional<QCursor>& PDFFormManager::getCursor() const
|
||||||
|
@ -724,6 +903,19 @@ void PDFFormManager::updateFieldValues()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFFormFieldWidgetEditor* PDFFormManager::getEditor(const PDFFormField* formField) const
|
||||||
|
{
|
||||||
|
for (PDFFormFieldWidgetEditor* editor : m_widgetEditors)
|
||||||
|
{
|
||||||
|
if (editor->getFormField() == formField)
|
||||||
|
{
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
PDFFormFieldWidgetEditor::PDFFormFieldWidgetEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent) :
|
PDFFormFieldWidgetEditor::PDFFormFieldWidgetEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent) :
|
||||||
BaseClass(parent),
|
BaseClass(parent),
|
||||||
m_formManager(formManager),
|
m_formManager(formManager),
|
||||||
|
@ -885,6 +1077,17 @@ void PDFFormFieldPushButtonEditor::keyReleaseEvent(QWidget* widget, QKeyEvent* e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFFormFieldPushButtonEditor::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
click();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDFFormFieldPushButtonEditor::click()
|
void PDFFormFieldPushButtonEditor::click()
|
||||||
{
|
{
|
||||||
if (const PDFAction* action = m_formManager->getAction(PDFAnnotationAdditionalActions::MousePressed, getFormWidget()))
|
if (const PDFAction* action = m_formManager->getAction(PDFAnnotationAdditionalActions::MousePressed, getFormWidget()))
|
||||||
|
|
|
@ -351,6 +351,11 @@ public:
|
||||||
/// \param widget Widget annotation
|
/// \param widget Widget annotation
|
||||||
const PDFFormField* getFormFieldForWidget(PDFObjectReference widget) const;
|
const PDFFormField* getFormFieldForWidget(PDFObjectReference widget) const;
|
||||||
|
|
||||||
|
/// Returns form field for widget. If widget doesn't have attached form field,
|
||||||
|
/// then nullptr is returned.
|
||||||
|
/// \param widget Widget annotation
|
||||||
|
PDFFormField* getFormFieldForWidget(PDFObjectReference widget);
|
||||||
|
|
||||||
/// Parses form from the object. If some error occurs
|
/// Parses form from the object. If some error occurs
|
||||||
/// then empty form is returned, no exception is thrown.
|
/// then empty form is returned, no exception is thrown.
|
||||||
/// \param document Document
|
/// \param document Document
|
||||||
|
@ -417,8 +422,9 @@ public:
|
||||||
explicit PDFFormFieldPushButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent);
|
explicit PDFFormFieldPushButtonEditor(PDFFormManager* formManager, PDFFormWidget formWidget, QObject* parent);
|
||||||
virtual ~PDFFormFieldPushButtonEditor() = default;
|
virtual ~PDFFormFieldPushButtonEditor() = default;
|
||||||
|
|
||||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event);
|
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void click();
|
void click();
|
||||||
|
@ -498,6 +504,7 @@ public:
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(FormAppearanceFlags, FormAppearanceFlag)
|
Q_DECLARE_FLAGS(FormAppearanceFlags, FormAppearanceFlag)
|
||||||
|
|
||||||
|
bool hasForm() const { return hasAcroForm() || hasXFAForm(); }
|
||||||
bool hasAcroForm() const { return m_form.getFormType() == PDFForm::FormType::AcroForm; }
|
bool hasAcroForm() const { return m_form.getFormType() == PDFForm::FormType::AcroForm; }
|
||||||
bool hasXFAForm() const { return m_form.getFormType() == PDFForm::FormType::XFAForm; }
|
bool hasXFAForm() const { return m_form.getFormType() == PDFForm::FormType::XFAForm; }
|
||||||
|
|
||||||
|
@ -506,6 +513,11 @@ public:
|
||||||
/// \param widget Widget annotation
|
/// \param widget Widget annotation
|
||||||
const PDFFormField* getFormFieldForWidget(PDFObjectReference widget) const { return m_form.getFormFieldForWidget(widget); }
|
const PDFFormField* getFormFieldForWidget(PDFObjectReference widget) const { return m_form.getFormFieldForWidget(widget); }
|
||||||
|
|
||||||
|
/// Returns form field for widget. If widget doesn't have attached form field,
|
||||||
|
/// then nullptr is returned.
|
||||||
|
/// \param widget Widget annotation
|
||||||
|
PDFFormField* getFormFieldForWidget(PDFObjectReference widget) { return m_form.getFormFieldForWidget(widget); }
|
||||||
|
|
||||||
PDFAnnotationManager* getAnnotationManager() const;
|
PDFAnnotationManager* getAnnotationManager() const;
|
||||||
void setAnnotationManager(PDFAnnotationManager* annotationManager);
|
void setAnnotationManager(PDFAnnotationManager* annotationManager);
|
||||||
|
|
||||||
|
@ -553,6 +565,27 @@ public:
|
||||||
/// Returns default form apperance flags
|
/// Returns default form apperance flags
|
||||||
static constexpr FormAppearanceFlags getDefaultApperanceFlags() { return HighlightFields | HighlightRequiredFields; }
|
static constexpr FormAppearanceFlags getDefaultApperanceFlags() { return HighlightFields | HighlightRequiredFields; }
|
||||||
|
|
||||||
|
struct MouseEventInfo
|
||||||
|
{
|
||||||
|
/// Form field under mouse event, nullptr, if
|
||||||
|
/// no form field is under mouse button.
|
||||||
|
PDFFormField* formField = nullptr;
|
||||||
|
|
||||||
|
/// Form field widget editor, which is associated
|
||||||
|
/// with given form field.
|
||||||
|
PDFFormFieldWidgetEditor* editor = nullptr;
|
||||||
|
|
||||||
|
/// Mouse position in form field coordinate space
|
||||||
|
QPointF mousePosition;
|
||||||
|
|
||||||
|
/// Matrix, which maps from device space to widget space
|
||||||
|
QMatrix deviceToWidget;
|
||||||
|
|
||||||
|
/// Returns true, if mouse event info is valid, i.e.
|
||||||
|
/// mouse event occurs above some form field.
|
||||||
|
bool isValid() const { return editor != nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
// interface IDrawWidgetInputInterface
|
// interface IDrawWidgetInputInterface
|
||||||
|
|
||||||
/// Handles key press event from widget
|
/// Handles key press event from widget
|
||||||
|
@ -600,6 +633,31 @@ private:
|
||||||
void updateFormWidgetEditors();
|
void updateFormWidgetEditors();
|
||||||
void updateFieldValues();
|
void updateFieldValues();
|
||||||
|
|
||||||
|
PDFFormFieldWidgetEditor* getEditor(const PDFFormField* formField) const;
|
||||||
|
MouseEventInfo getMouseEventInfo(QWidget* widget, QPoint point);
|
||||||
|
|
||||||
|
struct MouseGrabInfo
|
||||||
|
{
|
||||||
|
MouseEventInfo info;
|
||||||
|
int mouseGrabNesting = 0;
|
||||||
|
|
||||||
|
bool isMouseGrabbed() const { return mouseGrabNesting > 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isMouseGrabbed() const { return m_mouseGrabInfo.isMouseGrabbed(); }
|
||||||
|
|
||||||
|
/// Grabs mouse input, if mouse is already grabbed, or if event
|
||||||
|
/// is accepted. When mouse is grabbed, then mouse input events
|
||||||
|
/// are sent to active editor and are automatically accepted.
|
||||||
|
/// \param info Mouse event info
|
||||||
|
/// \param event Mouse event
|
||||||
|
void grabMouse(const MouseEventInfo& info, QMouseEvent* event);
|
||||||
|
|
||||||
|
/// Release mouse input
|
||||||
|
/// \param info Mouse event info
|
||||||
|
/// \param event Mouse event
|
||||||
|
void ungrabMouse(const MouseEventInfo& info, QMouseEvent* event);
|
||||||
|
|
||||||
PDFDrawWidgetProxy* m_proxy;
|
PDFDrawWidgetProxy* m_proxy;
|
||||||
PDFAnnotationManager* m_annotationManager;
|
PDFAnnotationManager* m_annotationManager;
|
||||||
const PDFDocument* m_document;
|
const PDFDocument* m_document;
|
||||||
|
@ -608,6 +666,7 @@ private:
|
||||||
|
|
||||||
std::vector<PDFFormFieldWidgetEditor*> m_widgetEditors;
|
std::vector<PDFFormFieldWidgetEditor*> m_widgetEditors;
|
||||||
PDFFormFieldWidgetEditor* m_focusedEditor;
|
PDFFormFieldWidgetEditor* m_focusedEditor;
|
||||||
|
MouseGrabInfo m_mouseGrabInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
Loading…
Reference in New Issue