mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-03-10 08:20:09 +01:00
Annotation tooltips
This commit is contained in:
parent
dc7dd8fe74
commit
6c746ba901
@ -24,8 +24,10 @@
|
||||
#include "pdfwidgetutils.h"
|
||||
#include "pdfpagecontentprocessor.h"
|
||||
#include "pdfparser.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
@ -900,6 +902,69 @@ PDFAnnotationManager::~PDFAnnotationManager()
|
||||
|
||||
}
|
||||
|
||||
QMatrix PDFAnnotationManager::prepareTransformations(const QMatrix& pagePointToDevicePointMatrix,
|
||||
QPaintDevice* device,
|
||||
const PDFAnnotation::Flags annotationFlags,
|
||||
const PDFPage* page,
|
||||
QRectF& annotationRectangle) const
|
||||
{
|
||||
// "Unrotate" user coordinate space, if NoRotate flag is set
|
||||
QMatrix userSpaceToDeviceSpace = pagePointToDevicePointMatrix;
|
||||
if (annotationFlags.testFlag(PDFAnnotation::NoRotate))
|
||||
{
|
||||
PDFReal rotationAngle = 0.0;
|
||||
switch (page->getPageRotation())
|
||||
{
|
||||
case PageRotation::None:
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate90:
|
||||
rotationAngle = -90.0;
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate180:
|
||||
rotationAngle = -180.0;
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate270:
|
||||
rotationAngle = -270.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
QMatrix rotationMatrix;
|
||||
rotationMatrix.rotate(-rotationAngle);
|
||||
QPointF topLeft = annotationRectangle.bottomLeft(); // Do not forget, that y is upward instead of Qt
|
||||
QPointF difference = topLeft - rotationMatrix.map(topLeft);
|
||||
|
||||
QMatrix finalMatrix;
|
||||
finalMatrix.translate(difference.x(), difference.y());
|
||||
finalMatrix.rotate(-rotationAngle);
|
||||
userSpaceToDeviceSpace = finalMatrix * userSpaceToDeviceSpace;
|
||||
}
|
||||
|
||||
if (annotationFlags.testFlag(PDFAnnotation::NoZoom))
|
||||
{
|
||||
// Jakub Melka: we must adjust annotation rectangle to disable zoom. We calculate
|
||||
// inverse zoom as square root of absolute value of determinant of scale matrix.
|
||||
// Determinant corresponds approximately to zoom squared, and if we will have
|
||||
// unrotated matrix, and both axes are scaled by same value, then determinant will
|
||||
// be exactly zoom squared. Also, we will adjust to target device logical DPI,
|
||||
// if we, for example are using 4K, or 8K monitors.
|
||||
qreal zoom = 1.0 / qSqrt(qAbs(pagePointToDevicePointMatrix.determinant()));
|
||||
zoom = PDFWidgetUtils::scaleDPI_x(device, zoom);
|
||||
|
||||
QRectF unzoomedRect(annotationRectangle.bottomLeft(), annotationRectangle.size() * zoom);
|
||||
unzoomedRect.translate(0, -unzoomedRect.height());
|
||||
annotationRectangle = unzoomedRect;
|
||||
}
|
||||
|
||||
return userSpaceToDeviceSpace;
|
||||
}
|
||||
|
||||
void PDFAnnotationManager::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
@ -909,7 +974,7 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
|
||||
Q_UNUSED(compiledPage);
|
||||
Q_UNUSED(layoutGetter);
|
||||
|
||||
PageAnnotations& annotations = getPageAnnotations(pageIndex);
|
||||
const PageAnnotations& annotations = getPageAnnotations(pageIndex);
|
||||
if (!annotations.isEmpty())
|
||||
{
|
||||
const PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
|
||||
@ -929,7 +994,7 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
|
||||
const PDFCMSPointer cms = m_cmsManager->getCurrentCMS();
|
||||
m_fontCache->setCacheShrinkEnabled(this, false);
|
||||
|
||||
for (PageAnnotation& annotation : annotations.annotations)
|
||||
for (const PageAnnotation& annotation : annotations.annotations)
|
||||
{
|
||||
const PDFAnnotation::Flags annotationFlags = annotation.annotation->getFlags();
|
||||
if (annotationFlags.testFlag(PDFAnnotation::Hidden) || // Annotation is completely hidden
|
||||
@ -972,58 +1037,10 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
|
||||
continue;
|
||||
}
|
||||
|
||||
// "Unrotate" user coordinate space, if NoRotate flag is set
|
||||
QMatrix userSpaceToDeviceSpace = pagePointToDevicePointMatrix;
|
||||
if (annotationFlags.testFlag(PDFAnnotation::NoRotate))
|
||||
{
|
||||
PDFReal rotationAngle = 0.0;
|
||||
switch (page->getPageRotation())
|
||||
{
|
||||
case PageRotation::None:
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate90:
|
||||
rotationAngle = -90.0;
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate180:
|
||||
rotationAngle = -180.0;
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate270:
|
||||
rotationAngle = -270.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
QMatrix rotationMatrix;
|
||||
rotationMatrix.rotate(-rotationAngle);
|
||||
QPointF topLeft = annotationRectangle.bottomLeft(); // Do not forget, that y is upward instead of Qt
|
||||
QPointF difference = topLeft - rotationMatrix.map(topLeft);
|
||||
|
||||
QMatrix finalMatrix;
|
||||
finalMatrix.translate(difference.x(), difference.y());
|
||||
finalMatrix.rotate(-rotationAngle);
|
||||
userSpaceToDeviceSpace = finalMatrix * userSpaceToDeviceSpace;
|
||||
}
|
||||
QMatrix userSpaceToDeviceSpace = prepareTransformations(pagePointToDevicePointMatrix, painter->device(), annotationFlags, page, annotationRectangle);
|
||||
|
||||
if (annotationFlags.testFlag(PDFAnnotation::NoZoom))
|
||||
{
|
||||
// Jakub Melka: we must adjust annotation rectangle to disable zoom. We calculate
|
||||
// inverse zoom as square root of absolute value of determinant of scale matrix.
|
||||
// Determinant corresponds approximately to zoom squared, and if we will have
|
||||
// unrotated matrix, and both axes are scaled by same value, then determinant will
|
||||
// be exactly zoom squared. Also, we will adjust to target device logical DPI,
|
||||
// if we, for example are using 4K, or 8K monitors.
|
||||
qreal zoom = 1.0 / qSqrt(qAbs(pagePointToDevicePointMatrix.determinant()));
|
||||
zoom = PDFWidgetUtils::scaleDPI_x(painter->device(), zoom);
|
||||
|
||||
QRectF unzoomedRect(annotationRectangle.bottomLeft(), annotationRectangle.size() * zoom);
|
||||
unzoomedRect.translate(0, -unzoomedRect.height());
|
||||
annotationRectangle = unzoomedRect;
|
||||
features.setFlag(PDFRenderer::ClipToCropBox, false);
|
||||
}
|
||||
|
||||
@ -1070,16 +1087,23 @@ void PDFAnnotationManager::setDocument(const PDFDocument* document, const PDFOpt
|
||||
}
|
||||
}
|
||||
|
||||
PDFObject PDFAnnotationManager::getAppearanceStream(PageAnnotation& pageAnnotation) const
|
||||
PDFObject PDFAnnotationManager::getAppearanceStream(const PageAnnotation& pageAnnotation) const
|
||||
{
|
||||
auto getAppearanceStream = [&pageAnnotation] (void) -> PDFObject
|
||||
{
|
||||
return pageAnnotation.annotation->getAppearanceStreams().getAppearance(pageAnnotation.appearance, pageAnnotation.annotation->getAppearanceState());
|
||||
};
|
||||
|
||||
QMutexLocker lock(&m_mutex);
|
||||
return pageAnnotation.appearanceStream.get(getAppearanceStream);
|
||||
}
|
||||
|
||||
PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(PDFInteger pageIndex) const
|
||||
const PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(PDFInteger pageIndex) const
|
||||
{
|
||||
return const_cast<PDFAnnotationManager*>(this)->getPageAnnotations(pageIndex);
|
||||
}
|
||||
|
||||
PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(PDFInteger pageIndex)
|
||||
{
|
||||
Q_ASSERT(m_document);
|
||||
|
||||
@ -1112,6 +1136,16 @@ PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool PDFAnnotationManager::hasAnnotation(PDFInteger pageIndex) const
|
||||
{
|
||||
return !getPageAnnotations(pageIndex).isEmpty();
|
||||
}
|
||||
|
||||
bool PDFAnnotationManager::hasAnyPageAnnotation(const std::vector<PDFInteger>& pageIndices) const
|
||||
{
|
||||
return std::any_of(pageIndices.cbegin(), pageIndices.cend(), std::bind(&PDFAnnotationManager::hasAnnotation, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
PDFRenderer::Features PDFAnnotationManager::getFeatures() const
|
||||
{
|
||||
return m_features;
|
||||
@ -1175,6 +1209,99 @@ PDFWidgetAnnotationManager::~PDFWidgetAnnotationManager()
|
||||
m_proxy->unregisterDrawInterface(this);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
|
||||
updateFromMouseEvent(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
|
||||
updateFromMouseEvent(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
|
||||
updateFromMouseEvent(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::updateFromMouseEvent(QMouseEvent* event)
|
||||
{
|
||||
PDFWidget* widget = m_proxy->getWidget();
|
||||
std::vector<PDFInteger> currentPages = widget->getDrawWidget()->getCurrentPages();
|
||||
|
||||
if (!hasAnyPageAnnotation(currentPages))
|
||||
{
|
||||
// All pages doesn't have annotation
|
||||
return;
|
||||
}
|
||||
|
||||
m_tooltip = QString();
|
||||
|
||||
// We must update appearance states, and update tooltip
|
||||
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
||||
const bool isDown = event->buttons().testFlag(Qt::LeftButton);
|
||||
const PDFAppeareanceStreams::Appearance hoverAppearance = isDown ? PDFAppeareanceStreams::Appearance::Down : PDFAppeareanceStreams::Appearance::Rollover;
|
||||
|
||||
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
||||
{
|
||||
PageAnnotations& pageAnnotations = getPageAnnotations(snapshotItem.pageIndex);
|
||||
for (PageAnnotation& pageAnnotation : pageAnnotations.annotations)
|
||||
{
|
||||
QRectF annotationRect = pageAnnotation.annotation->getRectangle();
|
||||
QMatrix matrix = prepareTransformations(snapshotItem.pageToDeviceMatrix, widget, pageAnnotation.annotation->getFlags(), m_document->getCatalog()->getPage(snapshotItem.pageIndex), annotationRect);
|
||||
QPainterPath path;
|
||||
path.addRect(annotationRect);
|
||||
path = matrix.map(path);
|
||||
|
||||
if (path.contains(event->pos()))
|
||||
{
|
||||
pageAnnotation.appearance = hoverAppearance;
|
||||
|
||||
// Generate tooltip
|
||||
if (m_tooltip.isEmpty())
|
||||
{
|
||||
const PDFMarkupAnnotation* markupAnnotation = dynamic_cast<const PDFMarkupAnnotation*>(pageAnnotation.annotation.data());
|
||||
if (markupAnnotation)
|
||||
{
|
||||
QColor backgroundColor = markupAnnotation->getDrawColorFromAnnotationColor(markupAnnotation->getColor());
|
||||
if (!backgroundColor.isValid())
|
||||
{
|
||||
backgroundColor = Qt::lightGray;
|
||||
}
|
||||
backgroundColor.setHslF(backgroundColor.hslHueF(), backgroundColor.hslSaturationF(), 1.0);
|
||||
m_tooltip = QString("<p><b>%1 (%2)</b></p><p>%3</p>").arg(markupAnnotation->getWindowTitle(), markupAnnotation->getCreationDate().toLocalTime().toString(), markupAnnotation->getContents());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pageAnnotation.appearance = PDFAppeareanceStreams::Appearance::Normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFSimpleGeometryAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
{
|
||||
Q_ASSERT(parameters.painter);
|
||||
|
@ -32,6 +32,10 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
class QKeyEvent;
|
||||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFObjectStorage;
|
||||
@ -1284,12 +1288,13 @@ public:
|
||||
PDFRenderer::Features getFeatures() const;
|
||||
void setFeatures(PDFRenderer::Features features);
|
||||
|
||||
private:
|
||||
protected:
|
||||
struct PageAnnotation
|
||||
{
|
||||
PDFAppeareanceStreams::Appearance appearance = PDFAppeareanceStreams::Appearance::Normal;
|
||||
PDFCachedItem<PDFObject> appearanceStream;
|
||||
PDFAnnotationPtr annotation;
|
||||
|
||||
mutable PDFCachedItem<PDFObject> appearanceStream;
|
||||
};
|
||||
|
||||
struct PageAnnotations
|
||||
@ -1299,14 +1304,37 @@ private:
|
||||
std::vector<PageAnnotation> annotations;
|
||||
};
|
||||
|
||||
/// Prepares annotation transformations for rendering
|
||||
/// \param pagePointToDevicePointMatrix Page point to device point matrix
|
||||
/// \param device Paint device, onto which will be annotation rendered
|
||||
/// \param annotationFlags Annotation flags
|
||||
/// \param page Page
|
||||
/// \param[in,out] annotationRectangle Input/output annotation rectangle
|
||||
QMatrix prepareTransformations(const QMatrix& pagePointToDevicePointMatrix,
|
||||
QPaintDevice* device,
|
||||
const PDFAnnotation::Flags annotationFlags,
|
||||
const PDFPage* page,
|
||||
QRectF& annotationRectangle) const;
|
||||
|
||||
/// Returns current appearance stream for given page annotation
|
||||
/// \param pageAnnotation Page annotation
|
||||
PDFObject getAppearanceStream(PageAnnotation& pageAnnotation) const;
|
||||
PDFObject getAppearanceStream(const PageAnnotation& pageAnnotation) const;
|
||||
|
||||
/// Returns constant reference to page annotation for given page index.
|
||||
/// This function requires, that pointer to m_document is valid.
|
||||
/// \param pageIndex Page index (must point to valid page)
|
||||
const PageAnnotations& getPageAnnotations(PDFInteger pageIndex) const;
|
||||
|
||||
/// Returns reference to page annotation for given page index.
|
||||
/// This function requires, that pointer to m_document is valid.
|
||||
/// \param pageIndex Page index (must point to valid page)
|
||||
PageAnnotations& getPageAnnotations(PDFInteger pageIndex) const;
|
||||
PageAnnotations& getPageAnnotations(PDFInteger pageIndex);
|
||||
|
||||
/// Returns true, if given page has any annotation
|
||||
bool hasAnnotation(PDFInteger pageIndex) const;
|
||||
|
||||
/// Returns true, if any page in the given indices has annotation
|
||||
bool hasAnyPageAnnotation(const std::vector<PDFInteger>& pageIndices) const;
|
||||
|
||||
const PDFDocument* m_document;
|
||||
|
||||
@ -1334,8 +1362,39 @@ public:
|
||||
explicit PDFWidgetAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent);
|
||||
virtual ~PDFWidgetAnnotationManager() override;
|
||||
|
||||
/// Handles key press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles mouse press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse release event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void mouseReleaseEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse move event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void mouseMoveEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse wheel event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
void wheelEvent(QWidget* widget, QWheelEvent* event);
|
||||
|
||||
/// Returns tooltip generated from annotation
|
||||
const QString& getTooltip() const { return m_tooltip; }
|
||||
|
||||
private:
|
||||
void updateFromMouseEvent(QMouseEvent* event);
|
||||
|
||||
PDFDrawWidgetProxy* m_proxy;
|
||||
QString m_tooltip;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -35,7 +35,6 @@ namespace pdf
|
||||
{
|
||||
class PDFProgress;
|
||||
class PDFWidget;
|
||||
class IDrawWidget;
|
||||
class PDFCMSManager;
|
||||
class PDFTextLayoutGetter;
|
||||
class PDFWidgetAnnotationManager;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
#include "pdfcompiler.h"
|
||||
#include "pdfwidgettool.h"
|
||||
#include "pdfannotation.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QGridLayout>
|
||||
@ -232,6 +233,17 @@ void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (PDFWidgetAnnotationManager* annotationManager = getPDFWidget()->getDrawWidgetProxy()->getAnnotationManager())
|
||||
{
|
||||
annotationManager->keyPressEvent(this, event);
|
||||
setToolTip(annotationManager->getTooltip());
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical navigation
|
||||
QScrollBar* verticalScrollbar = m_widget->getVerticalScrollbar();
|
||||
if (verticalScrollbar->isVisible())
|
||||
@ -275,6 +287,17 @@ void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (PDFWidgetAnnotationManager* annotationManager = getPDFWidget()->getDrawWidgetProxy()->getAnnotationManager())
|
||||
{
|
||||
annotationManager->mousePressEvent(this, event);
|
||||
setToolTip(annotationManager->getTooltip());
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
m_mouseOperation = MouseOperation::Translate;
|
||||
@ -301,6 +324,17 @@ void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (PDFWidgetAnnotationManager* annotationManager = getPDFWidget()->getDrawWidgetProxy()->getAnnotationManager())
|
||||
{
|
||||
annotationManager->mouseReleaseEvent(this, event);
|
||||
setToolTip(annotationManager->getTooltip());
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
performMouseOperation(event->pos());
|
||||
|
||||
switch (m_mouseOperation)
|
||||
@ -338,6 +372,17 @@ void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (PDFWidgetAnnotationManager* annotationManager = getPDFWidget()->getDrawWidgetProxy()->getAnnotationManager())
|
||||
{
|
||||
annotationManager->mouseMoveEvent(this, event);
|
||||
setToolTip(annotationManager->getTooltip());
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
performMouseOperation(event->pos());
|
||||
updateCursor();
|
||||
event->accept();
|
||||
@ -395,6 +440,17 @@ void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (PDFWidgetAnnotationManager* annotationManager = getPDFWidget()->getDrawWidgetProxy()->getAnnotationManager())
|
||||
{
|
||||
annotationManager->wheelEvent(this, event);
|
||||
setToolTip(annotationManager->getTooltip());
|
||||
if (event->isAccepted())
|
||||
{
|
||||
updateCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
||||
|
||||
PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
|
||||
|
Loading…
x
Reference in New Issue
Block a user