mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-27 07:46:08 +01:00
Signature plugin: text edit box
This commit is contained in:
parent
5a8b1ca670
commit
22e8fd4522
@ -89,6 +89,7 @@ SOURCES += \
|
||||
sources/pdfsignaturehandler.cpp \
|
||||
sources/pdfsnapper.cpp \
|
||||
sources/pdfstructuretree.cpp \
|
||||
sources/pdftexteditpseudowidget.cpp \
|
||||
sources/pdftextlayout.cpp \
|
||||
sources/pdftransparencyrenderer.cpp \
|
||||
sources/pdfutils.cpp \
|
||||
@ -170,6 +171,7 @@ HEADERS += \
|
||||
sources/pdfsignaturehandler_impl.h \
|
||||
sources/pdfsnapper.h \
|
||||
sources/pdfstructuretree.h \
|
||||
sources/pdftexteditpseudowidget.h \
|
||||
sources/pdftextlayout.h \
|
||||
sources/pdftransparencyrenderer.h \
|
||||
sources/pdfwidgettool.h \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2020-2021 Jakub Melka
|
||||
// Copyright (C) 2020-2022 Jakub Melka
|
||||
//
|
||||
// This file is part of PDF4QT.
|
||||
//
|
||||
|
@ -18,10 +18,12 @@
|
||||
#include "pdfpagecontenteditortools.h"
|
||||
#include "pdfpagecontentelements.h"
|
||||
#include "pdfpainterutils.h"
|
||||
#include "pdftexteditpseudowidget.h"
|
||||
|
||||
#include <QPen>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QGuiApplication>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
@ -494,4 +496,261 @@ void PDFCreatePCElementFreehandCurveTool::resetTool()
|
||||
m_element->clear();
|
||||
}
|
||||
|
||||
PDFCreatePCElementTextTool::PDFCreatePCElementTextTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_pickTool(nullptr),
|
||||
m_element(nullptr),
|
||||
m_textEditWidget(nullptr)
|
||||
{
|
||||
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||
m_pickTool->setDrawSelectionRectangle(true);
|
||||
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementTextTool::onRectanglePicked);
|
||||
|
||||
QFont font = QGuiApplication::font();
|
||||
font.setPixelSize(16.0);
|
||||
|
||||
m_element = new PDFPageContentElementTextBox();
|
||||
m_element->setBrush(Qt::NoBrush);
|
||||
m_element->setPen(QPen(Qt::SolidLine));
|
||||
m_element->setFont(font);
|
||||
|
||||
m_textEditWidget = new PDFTextEditPseudowidget(PDFFormField::FieldFlags());
|
||||
}
|
||||
|
||||
PDFCreatePCElementTextTool::~PDFCreatePCElementTextTool()
|
||||
{
|
||||
delete m_textEditWidget;
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QMatrix& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
if (pageIndex != m_element->getPageIndex())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEditing())
|
||||
{
|
||||
PDFPainterStateGuard guard(painter);
|
||||
AnnotationDrawParameters parameters;
|
||||
parameters.painter = painter;
|
||||
parameters.boundingRectangle = m_element->getRectangle();
|
||||
parameters.key.first = PDFAppeareanceStreams::Appearance::Normal;
|
||||
parameters.invertColors = getProxy()->getFeatures().testFlag(PDFRenderer::InvertColors);
|
||||
|
||||
painter->setWorldMatrix(pagePointToDevicePointMatrix, true);
|
||||
m_textEditWidget->draw(parameters, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::setActiveImpl(bool active)
|
||||
{
|
||||
BaseClass::setActiveImpl(active);
|
||||
|
||||
if (active)
|
||||
{
|
||||
Q_ASSERT(!getTopToolstackTool());
|
||||
addTool(m_pickTool);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_textEditWidget->setText(QString());
|
||||
m_element->setText(QString());
|
||||
|
||||
if (getTopToolstackTool())
|
||||
{
|
||||
removeTool();
|
||||
}
|
||||
}
|
||||
|
||||
m_pickTool->setActive(active);
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||
{
|
||||
if (pageRectangle.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setRectangle(pageRectangle);
|
||||
|
||||
m_textEditWidget->setAppearance(m_element->getFont(),
|
||||
m_element->getAlignment(),
|
||||
m_element->getRectangle(),
|
||||
std::numeric_limits<int>::max(),
|
||||
m_element->getPen().color());
|
||||
|
||||
removeTool();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::finishEditing()
|
||||
{
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
std::optional<QPointF> PDFCreatePCElementTextTool::getPagePointUnderMouse(QMouseEvent* event) const
|
||||
{
|
||||
QPointF pagePoint;
|
||||
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
if (pageIndex == m_element->getPageIndex() &&
|
||||
m_element->getRectangle().contains(pagePoint))
|
||||
{
|
||||
return pagePoint;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool PDFCreatePCElementTextTool::isEditing() const
|
||||
{
|
||||
return isActive() && !getTopToolstackTool();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
if (isEditing())
|
||||
{
|
||||
m_textEditWidget->shortcutOverrideEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (!isEditing())
|
||||
{
|
||||
BaseClass::keyPressEvent(widget, event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Escape)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_textEditWidget->isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
||||
{
|
||||
// Commit the editor and create element
|
||||
finishEditing();
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
m_textEditWidget->keyPressEvent(widget, event);
|
||||
|
||||
if (event->isAccepted())
|
||||
{
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||
if (pagePoint)
|
||||
{
|
||||
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||
m_textEditWidget->setCursorPosition(cursorPosition, event->modifiers() & Qt::ShiftModifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
finishEditing();
|
||||
}
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::mousePressEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||
if (pagePoint)
|
||||
{
|
||||
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||
m_textEditWidget->setCursorPosition(cursorPosition, false);
|
||||
m_textEditWidget->setCursorPosition(m_textEditWidget->getCursorWordBackward(), false);
|
||||
m_textEditWidget->setCursorPosition(m_textEditWidget->getCursorWordForward(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
finishEditing();
|
||||
}
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::mousePressEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||
if (pagePoint)
|
||||
{
|
||||
// We must test, if left mouse button is pressed while
|
||||
// we are moving the mouse - if yes, then select the text.
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||
m_textEditWidget->setCursorPosition(cursorPosition, true);
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::mouseMoveEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::wheelEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -27,8 +27,10 @@ class PDFPageContentScene;
|
||||
class PDFPageContentSvgElement;
|
||||
class PDFPageContentElementDot;
|
||||
class PDFPageContentElementLine;
|
||||
class PDFPageContentElementTextBox;
|
||||
class PDFPageContentElementRectangle;
|
||||
class PDFPageContentElementFreehandCurve;
|
||||
class PDFTextEditPseudowidget;
|
||||
|
||||
class PDFCreatePCElementTool : public PDFWidgetTool
|
||||
{
|
||||
@ -201,6 +203,49 @@ private:
|
||||
PDFPageContentElementFreehandCurve* m_element;
|
||||
};
|
||||
|
||||
/// Tool that displays SVG image
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTextTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementTextTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementTextTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QMatrix& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
void finishEditing();
|
||||
std::optional<QPointF> getPagePointUnderMouse(QMouseEvent* event) const;
|
||||
|
||||
bool isEditing() const;
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFPageContentElementTextBox* m_element;
|
||||
PDFTextEditPseudowidget* m_textEditWidget;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFPAGECONTENTEDITORTOOLS_H
|
||||
|
@ -2233,4 +2233,114 @@ void PDFPageContentElementManipulator::eraseSelectedElementById(PDFInteger id)
|
||||
}
|
||||
}
|
||||
|
||||
PDFPageContentElementTextBox* PDFPageContentElementTextBox::clone() const
|
||||
{
|
||||
PDFPageContentElementTextBox* copy = new PDFPageContentElementTextBox();
|
||||
copy->setElementId(getElementId());
|
||||
copy->setPageIndex(getPageIndex());
|
||||
copy->setPen(getPen());
|
||||
copy->setBrush(getBrush());
|
||||
copy->setRectangle(getRectangle());
|
||||
copy->setText(getText());
|
||||
copy->setFont(getFont());
|
||||
copy->setAngle(getAngle());
|
||||
copy->setAlignment(getAlignment());
|
||||
return copy;
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QMatrix& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
Q_UNUSED(compiledPage);
|
||||
Q_UNUSED(layoutGetter);
|
||||
Q_UNUSED(errors);
|
||||
|
||||
if (pageIndex != getPageIndex())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF rect = getRectangle();
|
||||
|
||||
PDFPainterStateGuard guard(painter);
|
||||
painter->setWorldMatrix(pagePointToDevicePointMatrix, true);
|
||||
painter->setPen(getPen());
|
||||
painter->setBrush(getBrush());
|
||||
painter->setFont(getFont());
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->setClipRect(rect, Qt::IntersectClip);
|
||||
painter->translate(rect.center());
|
||||
painter->rotate(getAngle());
|
||||
|
||||
QTextOption option;
|
||||
option.setAlignment(getAlignment());
|
||||
QRectF textRect(-rect.width() * 0.5, -rect.height() * 0.5, rect.width(), rect.height());
|
||||
painter->drawText(textRect, getText(), option);
|
||||
}
|
||||
|
||||
uint PDFPageContentElementTextBox::getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const
|
||||
{
|
||||
return getRectangleManipulationMode(getRectangle(), point, snapPointDistanceThreshold);
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::performManipulation(uint mode, const QPointF& offset)
|
||||
{
|
||||
performRectangleManipulation(m_rectangle, mode, offset);
|
||||
}
|
||||
|
||||
QRectF PDFPageContentElementTextBox::getBoundingBox() const
|
||||
{
|
||||
return m_rectangle;
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::setSize(QSizeF size)
|
||||
{
|
||||
performRectangleSetSize(m_rectangle, size);
|
||||
}
|
||||
|
||||
const QString& PDFPageContentElementTextBox::getText() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::setText(const QString& newText)
|
||||
{
|
||||
m_text = newText;
|
||||
}
|
||||
|
||||
const QFont& PDFPageContentElementTextBox::getFont() const
|
||||
{
|
||||
return m_font;
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::setFont(const QFont& newFont)
|
||||
{
|
||||
m_font = newFont;
|
||||
}
|
||||
|
||||
PDFReal PDFPageContentElementTextBox::getAngle() const
|
||||
{
|
||||
return m_angle;
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::setAngle(PDFReal newAngle)
|
||||
{
|
||||
m_angle = newAngle;
|
||||
}
|
||||
|
||||
const Qt::Alignment& PDFPageContentElementTextBox::getAlignment() const
|
||||
{
|
||||
return m_alignment;
|
||||
}
|
||||
|
||||
void PDFPageContentElementTextBox::setAlignment(const Qt::Alignment& newAlignment)
|
||||
{
|
||||
m_alignment = newAlignment;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "pdfdocumentdrawinterface.h"
|
||||
|
||||
#include <QPen>
|
||||
#include <QFont>
|
||||
#include <QBrush>
|
||||
#include <QCursor>
|
||||
#include <QPainterPath>
|
||||
@ -294,6 +295,50 @@ private:
|
||||
std::unique_ptr<QSvgRenderer> m_renderer;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementTextBox : public PDFPageContentStyledElement
|
||||
{
|
||||
public:
|
||||
virtual ~PDFPageContentElementTextBox() = default;
|
||||
|
||||
virtual PDFPageContentElementTextBox* clone() const override;
|
||||
|
||||
const QRectF& getRectangle() const { return m_rectangle; }
|
||||
void setRectangle(const QRectF& newRectangle) { m_rectangle = newRectangle; }
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QMatrix& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size);
|
||||
|
||||
const QString& getText() const;
|
||||
void setText(const QString& newText);
|
||||
|
||||
const QFont& getFont() const;
|
||||
void setFont(const QFont& newFont);
|
||||
|
||||
PDFReal getAngle() const;
|
||||
void setAngle(PDFReal newAngle);
|
||||
|
||||
const Qt::Alignment& getAlignment() const;
|
||||
void setAlignment(const Qt::Alignment& newAlignment);
|
||||
|
||||
private:
|
||||
QString m_text;
|
||||
QRectF m_rectangle;
|
||||
QFont m_font;
|
||||
PDFReal m_angle = 0.0;
|
||||
Qt::Alignment m_alignment = Qt::AlignCenter;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementManipulator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
947
Pdf4QtLib/sources/pdftexteditpseudowidget.cpp
Normal file
947
Pdf4QtLib/sources/pdftexteditpseudowidget.cpp
Normal file
@ -0,0 +1,947 @@
|
||||
// Copyright (C) 2022 Jakub Melka
|
||||
//
|
||||
// This file is part of PDF4QT.
|
||||
//
|
||||
// PDF4QT is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// with the written consent of the copyright owner, any later version.
|
||||
//
|
||||
// PDF4QT is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdftexteditpseudowidget.h"
|
||||
#include "pdfpainterutils.h"
|
||||
|
||||
#include <QStyle>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFTextEditPseudowidget::PDFTextEditPseudowidget(PDFFormField::FieldFlags flags) :
|
||||
m_flags(flags),
|
||||
m_selectionStart(0),
|
||||
m_selectionEnd(0),
|
||||
m_positionCursor(0),
|
||||
m_maxTextLength(0)
|
||||
{
|
||||
m_textLayout.setCacheEnabled(true);
|
||||
m_passwordReplacementCharacter = QApplication::style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter);
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
constexpr QKeySequence::StandardKey acceptedKeys[] = { QKeySequence::Delete, QKeySequence::Cut, QKeySequence::Copy, QKeySequence::Paste,
|
||||
QKeySequence::SelectAll, QKeySequence::MoveToNextChar, QKeySequence::MoveToPreviousChar,
|
||||
QKeySequence::MoveToNextWord, QKeySequence::MoveToPreviousWord, QKeySequence::MoveToNextLine,
|
||||
QKeySequence::MoveToPreviousLine, QKeySequence::MoveToStartOfLine, QKeySequence::MoveToEndOfLine,
|
||||
QKeySequence::MoveToStartOfBlock, QKeySequence::MoveToEndOfBlock, QKeySequence::MoveToStartOfDocument,
|
||||
QKeySequence::MoveToEndOfDocument, QKeySequence::SelectNextChar, QKeySequence::SelectPreviousChar,
|
||||
QKeySequence::SelectNextWord, QKeySequence::SelectPreviousWord, QKeySequence::SelectNextLine,
|
||||
QKeySequence::SelectPreviousLine, QKeySequence::SelectStartOfLine, QKeySequence::SelectEndOfLine,
|
||||
QKeySequence::SelectStartOfBlock, QKeySequence::SelectEndOfBlock, QKeySequence::SelectStartOfDocument,
|
||||
QKeySequence::SelectEndOfDocument, QKeySequence::DeleteStartOfWord, QKeySequence::DeleteEndOfWord,
|
||||
QKeySequence::DeleteEndOfLine, QKeySequence::Deselect, QKeySequence::DeleteCompleteLine, QKeySequence::Backspace };
|
||||
|
||||
if (std::any_of(std::begin(acceptedKeys), std::end(acceptedKeys), [event](QKeySequence::StandardKey standardKey) { return event == standardKey; }))
|
||||
{
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_Direction_L:
|
||||
case Qt::Key_Direction_R:
|
||||
case Qt::Key_Up:
|
||||
case Qt::Key_Down:
|
||||
case Qt::Key_Left:
|
||||
case Qt::Key_Right:
|
||||
event->accept();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!event->text().isEmpty())
|
||||
{
|
||||
event->accept();
|
||||
for (const QChar& character : event->text())
|
||||
{
|
||||
if (!character.isPrint())
|
||||
{
|
||||
event->ignore();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
/*
|
||||
We will support following key sequences:
|
||||
Delete
|
||||
Cut,
|
||||
Copy,
|
||||
Paste,
|
||||
SelectAll,
|
||||
MoveToNextChar,
|
||||
MoveToPreviousChar,
|
||||
MoveToNextWord,
|
||||
MoveToPreviousWord,
|
||||
MoveToNextLine,
|
||||
MoveToPreviousLine,
|
||||
MoveToStartOfLine,
|
||||
MoveToEndOfLine,
|
||||
MoveToStartOfBlock,
|
||||
MoveToEndOfBlock,
|
||||
MoveToStartOfDocument,
|
||||
MoveToEndOfDocument,
|
||||
SelectNextChar,
|
||||
SelectPreviousChar,
|
||||
SelectNextWord,
|
||||
SelectPreviousWord,
|
||||
SelectNextLine,
|
||||
SelectPreviousLine,
|
||||
SelectStartOfLine,
|
||||
SelectEndOfLine,
|
||||
SelectStartOfBlock,
|
||||
SelectEndOfBlock,
|
||||
SelectStartOfDocument,
|
||||
SelectEndOfDocument,
|
||||
DeleteStartOfWord,
|
||||
DeleteEndOfWord,
|
||||
DeleteEndOfLine,
|
||||
Deselect,
|
||||
DeleteCompleteLine,
|
||||
Backspace,
|
||||
* */
|
||||
|
||||
event->accept();
|
||||
|
||||
if (event == QKeySequence::Delete)
|
||||
{
|
||||
performDelete();
|
||||
}
|
||||
else if (event == QKeySequence::Cut)
|
||||
{
|
||||
performCut();
|
||||
}
|
||||
else if (event == QKeySequence::Copy)
|
||||
{
|
||||
performCopy();
|
||||
}
|
||||
else if (event == QKeySequence::Paste)
|
||||
{
|
||||
performPaste();
|
||||
}
|
||||
else if (event == QKeySequence::SelectAll)
|
||||
{
|
||||
setSelection(0, getTextLength());
|
||||
}
|
||||
else if (event == QKeySequence::MoveToNextChar)
|
||||
{
|
||||
setCursorPosition(getCursorCharacterForward(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToPreviousChar)
|
||||
{
|
||||
setCursorPosition(getCursorCharacterBackward(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToNextWord)
|
||||
{
|
||||
setCursorPosition(getCursorWordForward(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToPreviousWord)
|
||||
{
|
||||
setCursorPosition(getCursorWordBackward(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToNextLine)
|
||||
{
|
||||
setCursorPosition(getCursorLineDown(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToPreviousLine)
|
||||
{
|
||||
setCursorPosition(getCursorLineUp(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock)
|
||||
{
|
||||
setCursorPosition(getCursorLineStart(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock)
|
||||
{
|
||||
setCursorPosition(getCursorLineEnd(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToStartOfDocument)
|
||||
{
|
||||
setCursorPosition(getCursorDocumentStart(), false);
|
||||
}
|
||||
else if (event == QKeySequence::MoveToEndOfDocument)
|
||||
{
|
||||
setCursorPosition(getCursorDocumentEnd(), false);
|
||||
}
|
||||
else if (event == QKeySequence::SelectNextChar)
|
||||
{
|
||||
setCursorPosition(getCursorCharacterForward(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectPreviousChar)
|
||||
{
|
||||
setCursorPosition(getCursorCharacterBackward(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectNextWord)
|
||||
{
|
||||
setCursorPosition(getCursorWordForward(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectPreviousWord)
|
||||
{
|
||||
setCursorPosition(getCursorWordBackward(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectNextLine)
|
||||
{
|
||||
setCursorPosition(getCursorLineDown(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectPreviousLine)
|
||||
{
|
||||
setCursorPosition(getCursorLineUp(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock)
|
||||
{
|
||||
setCursorPosition(getCursorLineStart(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock)
|
||||
{
|
||||
setCursorPosition(getCursorLineEnd(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectStartOfDocument)
|
||||
{
|
||||
setCursorPosition(getCursorDocumentStart(), true);
|
||||
}
|
||||
else if (event == QKeySequence::SelectEndOfDocument)
|
||||
{
|
||||
setCursorPosition(getCursorDocumentEnd(), true);
|
||||
}
|
||||
else if (event == QKeySequence::DeleteStartOfWord)
|
||||
{
|
||||
if (!isReadonly())
|
||||
{
|
||||
setCursorPosition(getCursorWordBackward(), true);
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
}
|
||||
else if (event == QKeySequence::DeleteEndOfWord)
|
||||
{
|
||||
if (!isReadonly())
|
||||
{
|
||||
setCursorPosition(getCursorWordForward(), true);
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
}
|
||||
else if (event == QKeySequence::DeleteEndOfLine)
|
||||
{
|
||||
if (!isReadonly())
|
||||
{
|
||||
setCursorPosition(getCursorLineEnd(), true);
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
}
|
||||
else if (event == QKeySequence::Deselect)
|
||||
{
|
||||
clearSelection();
|
||||
}
|
||||
else if (event == QKeySequence::DeleteCompleteLine)
|
||||
{
|
||||
if (!isReadonly())
|
||||
{
|
||||
m_selectionStart = getCurrentLineTextStart();
|
||||
m_selectionEnd = getCurrentLineTextEnd();
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
}
|
||||
else if (event == QKeySequence::Backspace || event->key() == Qt::Key_Backspace)
|
||||
{
|
||||
performBackspace();
|
||||
}
|
||||
else if (event->key() == Qt::Key_Direction_L)
|
||||
{
|
||||
QTextOption option = m_textLayout.textOption();
|
||||
option.setTextDirection(Qt::LeftToRight);
|
||||
m_textLayout.setTextOption(qMove(option));
|
||||
updateTextLayout();
|
||||
}
|
||||
else if (event->key() == Qt::Key_Direction_R)
|
||||
{
|
||||
QTextOption option = m_textLayout.textOption();
|
||||
option.setTextDirection(Qt::LeftToRight);
|
||||
m_textLayout.setTextOption(qMove(option));
|
||||
updateTextLayout();
|
||||
}
|
||||
else if (event->key() == Qt::Key_Up)
|
||||
{
|
||||
setCursorPosition(getCursorLineUp(), event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
}
|
||||
else if (event->key() == Qt::Key_Down)
|
||||
{
|
||||
setCursorPosition(getCursorLineDown(), event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
}
|
||||
else if (event->key() == Qt::Key_Left)
|
||||
{
|
||||
const int position = (event->modifiers().testFlag(Qt::ControlModifier)) ? getCursorWordBackward() : getCursorCharacterBackward();
|
||||
setCursorPosition(position, event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
}
|
||||
else if (event->key() == Qt::Key_Right)
|
||||
{
|
||||
const int position = (event->modifiers().testFlag(Qt::ControlModifier)) ? getCursorWordForward() : getCursorCharacterForward();
|
||||
setCursorPosition(position, event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
}
|
||||
else if (isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
||||
{
|
||||
performInsertText(QString::fromUtf16(u"\u2028"));
|
||||
}
|
||||
else
|
||||
{
|
||||
QString text = event->text();
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
performInsertText(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::setSelection(int startPosition, int selectionLength)
|
||||
{
|
||||
if (selectionLength > 0)
|
||||
{
|
||||
// We are selecting to the right
|
||||
m_selectionStart = startPosition;
|
||||
m_selectionEnd = qMin(startPosition + selectionLength, getTextLength());
|
||||
m_positionCursor = m_selectionEnd;
|
||||
}
|
||||
else if (selectionLength < 0)
|
||||
{
|
||||
// We are selecting to the left
|
||||
m_selectionStart = qMax(startPosition + selectionLength, 0);
|
||||
m_selectionEnd = startPosition;
|
||||
m_positionCursor = m_selectionStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear the selection
|
||||
m_selectionStart = 0;
|
||||
m_selectionEnd = 0;
|
||||
m_positionCursor = startPosition;
|
||||
}
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::setCursorPosition(int position, bool select)
|
||||
{
|
||||
if (select)
|
||||
{
|
||||
const bool isTextSelected = this->isTextSelected();
|
||||
const bool isCursorAtStartOfSelection = isTextSelected && m_selectionStart == m_positionCursor;
|
||||
const bool isCursorAtEndOfSelection = isTextSelected && m_selectionEnd == m_positionCursor;
|
||||
|
||||
// Do we have selected text, and cursor is at the end of selected text?
|
||||
// In this case, we must preserve start of the selection (we are manipulating
|
||||
// with the end of selection.
|
||||
if (isCursorAtEndOfSelection)
|
||||
{
|
||||
m_selectionStart = qMin(m_selectionStart, position);
|
||||
m_selectionEnd = qMax(m_selectionStart, position);
|
||||
}
|
||||
else if (isCursorAtStartOfSelection)
|
||||
{
|
||||
// We must preserve end of the text selection, because we are manipulating
|
||||
// with start of text selection.
|
||||
m_selectionStart = qMin(m_selectionEnd, position);
|
||||
m_selectionEnd = qMax(m_selectionEnd, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise we are manipulating with cursor
|
||||
m_selectionStart = qMin(m_positionCursor, position);
|
||||
m_selectionEnd = qMax(m_positionCursor, position);
|
||||
}
|
||||
}
|
||||
|
||||
// Why we are clearing text selection, even if we doesn't have it?
|
||||
// We can have, for example m_selectionStart == m_selectionEnd == 3,
|
||||
// and we want to have it both zero.
|
||||
if (!select || !isTextSelected())
|
||||
{
|
||||
clearSelection();
|
||||
}
|
||||
|
||||
m_positionCursor = position;
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::setText(const QString& text)
|
||||
{
|
||||
clearSelection();
|
||||
m_editText = text;
|
||||
setCursorPosition(getPositionEnd(), false);
|
||||
updateTextLayout();
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::setAppearance(const PDFAnnotationDefaultAppearance& appearance, Qt::Alignment textAlignment, QRectF rect, int maxTextLength)
|
||||
{
|
||||
// Set appearance
|
||||
qreal fontSize = appearance.getFontSize();
|
||||
if (qFuzzyIsNull(fontSize))
|
||||
{
|
||||
fontSize = rect.height();
|
||||
}
|
||||
|
||||
QFont font(appearance.getFontName());
|
||||
font.setHintingPreference(QFont::PreferNoHinting);
|
||||
font.setPixelSize(qCeil(fontSize));
|
||||
font.setStyleStrategy(QFont::ForceOutline);
|
||||
m_textLayout.setFont(font);
|
||||
|
||||
QTextOption option = m_textLayout.textOption();
|
||||
option.setWrapMode(isMultiline() ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
|
||||
option.setAlignment(textAlignment);
|
||||
option.setUseDesignMetrics(true);
|
||||
m_textLayout.setTextOption(option);
|
||||
|
||||
m_textColor = appearance.getFontColor();
|
||||
if (!m_textColor.isValid())
|
||||
{
|
||||
m_textColor = Qt::black;
|
||||
}
|
||||
|
||||
m_maxTextLength = maxTextLength;
|
||||
m_widgetRect = rect;
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::setAppearance(const QFont& font,
|
||||
Qt::Alignment textAlignment,
|
||||
QRectF rect,
|
||||
int maxTextLength,
|
||||
QColor textColor)
|
||||
{
|
||||
// Set appearance
|
||||
m_textLayout.setFont(font);
|
||||
|
||||
QTextOption option = m_textLayout.textOption();
|
||||
option.setWrapMode(isMultiline() ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
|
||||
option.setAlignment(textAlignment);
|
||||
option.setUseDesignMetrics(true);
|
||||
m_textLayout.setTextOption(option);
|
||||
|
||||
m_textColor = textColor;
|
||||
if (!m_textColor.isValid())
|
||||
{
|
||||
m_textColor = Qt::black;
|
||||
}
|
||||
|
||||
m_maxTextLength = maxTextLength;
|
||||
m_widgetRect = rect;
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performCut()
|
||||
{
|
||||
if (isReadonly())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
performCopy();
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performCopy()
|
||||
{
|
||||
if (isTextSelected() && !isPassword())
|
||||
{
|
||||
QApplication::clipboard()->setText(getSelectedText(), QClipboard::Clipboard);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performPaste()
|
||||
{
|
||||
// We always insert text, even if it is empty. Because we want
|
||||
// to erase selected text.
|
||||
performInsertText(QApplication::clipboard()->text(QClipboard::Clipboard));
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performClear()
|
||||
{
|
||||
if (isReadonly())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
performSelectAll();
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performSelectAll()
|
||||
{
|
||||
m_selectionStart = getPositionStart();
|
||||
m_selectionEnd = getPositionEnd();
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performBackspace()
|
||||
{
|
||||
if (isReadonly())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have selection, then delete selected text. If we do not have
|
||||
// selection, then we delete previous character.
|
||||
if (!isTextSelected())
|
||||
{
|
||||
setCursorPosition(m_textLayout.previousCursorPosition(m_positionCursor, QTextLayout::SkipCharacters), true);
|
||||
}
|
||||
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performDelete()
|
||||
{
|
||||
if (isReadonly())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have selection, then delete selected text. If we do not have
|
||||
// selection, then we delete previous character.
|
||||
if (!isTextSelected())
|
||||
{
|
||||
setCursorPosition(m_textLayout.nextCursorPosition(m_positionCursor, QTextLayout::SkipCharacters), true);
|
||||
}
|
||||
|
||||
performRemoveSelectedText();
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performRemoveSelectedText()
|
||||
{
|
||||
if (isTextSelected())
|
||||
{
|
||||
m_editText.remove(m_selectionStart, getSelectionLength());
|
||||
setCursorPosition(m_selectionStart, false);
|
||||
clearSelection();
|
||||
updateTextLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::performInsertText(const QString& text)
|
||||
{
|
||||
if (isReadonly())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert text at the cursor
|
||||
performRemoveSelectedText();
|
||||
m_editText.insert(m_positionCursor, text);
|
||||
setCursorPosition(m_positionCursor + text.length(), false);
|
||||
updateTextLayout();
|
||||
}
|
||||
|
||||
QMatrix PDFTextEditPseudowidget::createTextBoxTransformMatrix(bool edit) const
|
||||
{
|
||||
QMatrix matrix;
|
||||
|
||||
matrix.translate(m_widgetRect.left(), m_widgetRect.bottom());
|
||||
matrix.scale(1.0, -1.0);
|
||||
|
||||
if (edit && !isComb() && m_textLayout.isValidCursorPosition(m_positionCursor))
|
||||
{
|
||||
// Jakub Melka: we must scroll the control, so cursor is always
|
||||
// visible in the widget area. If we are not editing, this not the
|
||||
// case, because we always show the text from the beginning.
|
||||
|
||||
const QTextLine line = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||
if (line.isValid())
|
||||
{
|
||||
const qreal xCursorPosition = line.cursorToX(m_positionCursor);
|
||||
if (xCursorPosition >= m_widgetRect.width())
|
||||
{
|
||||
const qreal delta = xCursorPosition - m_widgetRect.width();
|
||||
matrix.translate(-delta, 0.0);
|
||||
}
|
||||
|
||||
// Check, if we aren't outside of y position
|
||||
const qreal lineSpacing = line.leadingIncluded() ? line.height() : line.leading() + line.height();
|
||||
const qreal lineBottom = lineSpacing * (line.lineNumber() + 1);
|
||||
|
||||
if (lineBottom >= m_widgetRect.height())
|
||||
{
|
||||
const qreal delta = lineBottom - m_widgetRect.height();
|
||||
matrix.translate(0.0, -delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMultiline() && !isComb())
|
||||
{
|
||||
// If text is single line, then adjust text position to the vertical center
|
||||
QTextLine textLine = m_textLayout.lineAt(0);
|
||||
if (textLine.isValid())
|
||||
{
|
||||
const qreal lineSpacing = textLine.leadingIncluded() ? textLine.height() : textLine.leading() + textLine.height();
|
||||
const qreal textBoxHeight = m_widgetRect.height();
|
||||
|
||||
if (lineSpacing < textBoxHeight)
|
||||
{
|
||||
const qreal delta = (textBoxHeight - lineSpacing) * 0.5;
|
||||
matrix.translate(0.0, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
std::vector<int> PDFTextEditPseudowidget::getCursorPositions() const
|
||||
{
|
||||
std::vector<int> result;
|
||||
result.reserve(m_editText.length());
|
||||
result.push_back(0);
|
||||
|
||||
int currentPos = 0;
|
||||
while (currentPos < m_editText.length())
|
||||
{
|
||||
currentPos = m_textLayout.nextCursorPosition(currentPos, QTextLayout::SkipCharacters);
|
||||
result.push_back(currentPos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::draw(AnnotationDrawParameters& parameters, bool edit) const
|
||||
{
|
||||
pdf::PDFPainterStateGuard guard(parameters.painter);
|
||||
|
||||
if (parameters.annotation)
|
||||
{
|
||||
parameters.boundingRectangle = parameters.annotation->getRectangle();
|
||||
}
|
||||
|
||||
QPalette palette = QApplication::palette();
|
||||
|
||||
auto getAdjustedColor = [¶meters](QColor color)
|
||||
{
|
||||
if (parameters.invertColors)
|
||||
{
|
||||
return invertColor(color);
|
||||
}
|
||||
|
||||
return color;
|
||||
};
|
||||
|
||||
QPainter* painter = parameters.painter;
|
||||
|
||||
if (edit)
|
||||
{
|
||||
pdf::PDFPainterStateGuard guard(painter);
|
||||
painter->setPen(getAdjustedColor(Qt::black));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(parameters.boundingRectangle);
|
||||
}
|
||||
|
||||
painter->setClipRect(parameters.boundingRectangle, Qt::IntersectClip);
|
||||
painter->setWorldMatrix(createTextBoxTransformMatrix(edit), true);
|
||||
painter->setPen(getAdjustedColor(Qt::black));
|
||||
|
||||
if (isComb())
|
||||
{
|
||||
const qreal combCount = qMax(m_maxTextLength, 1);
|
||||
qreal combWidth = m_widgetRect.width() / combCount;
|
||||
QRectF combRect(0.0, 0.0, combWidth, m_widgetRect.height());
|
||||
painter->setFont(m_textLayout.font());
|
||||
|
||||
QColor textColor = getAdjustedColor(m_textColor);
|
||||
QColor highlightTextColor = getAdjustedColor(palette.color(QPalette::HighlightedText));
|
||||
QColor highlightColor = getAdjustedColor(palette.color(QPalette::Highlight));
|
||||
|
||||
std::vector<int> positions = getCursorPositions();
|
||||
for (size_t i = 1; i < positions.size(); ++i)
|
||||
{
|
||||
if (positions[i - 1] >= m_selectionStart && positions[i] - 1 < m_selectionEnd)
|
||||
{
|
||||
// We are in text selection
|
||||
painter->fillRect(combRect, highlightColor);
|
||||
painter->setPen(highlightTextColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are not in text selection
|
||||
painter->setPen(textColor);
|
||||
}
|
||||
|
||||
int length = positions[i] - positions[i - 1];
|
||||
QString text = m_displayText.mid(positions[i - 1], length);
|
||||
painter->drawText(combRect, Qt::AlignCenter, text);
|
||||
|
||||
// Draw the cursor?
|
||||
if (edit && m_positionCursor >= positions[i - 1] && m_positionCursor < positions[i])
|
||||
{
|
||||
QRectF cursorRect(combRect.left(), combRect.bottom() - 1, combRect.width(), 1);
|
||||
painter->fillRect(cursorRect, textColor);
|
||||
}
|
||||
|
||||
combRect.translate(combWidth, 0.0);
|
||||
}
|
||||
|
||||
// Draw the cursor onto next unfilled cell?
|
||||
if (edit && m_positionCursor == getPositionEnd())
|
||||
{
|
||||
QRectF cursorRect(combRect.left(), combRect.bottom() - 1, combRect.width(), 1);
|
||||
painter->fillRect(cursorRect, textColor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QVector<QTextLayout::FormatRange> selections;
|
||||
|
||||
QTextLayout::FormatRange defaultFormat;
|
||||
defaultFormat.start = getPositionStart();
|
||||
defaultFormat.length = getTextLength();
|
||||
defaultFormat.format.clearBackground();
|
||||
defaultFormat.format.setForeground(QBrush(getAdjustedColor(m_textColor), Qt::SolidPattern));
|
||||
|
||||
// If we are editing, draw selections
|
||||
if (edit && isTextSelected())
|
||||
{
|
||||
QTextLayout::FormatRange before = defaultFormat;
|
||||
QTextLayout::FormatRange after = defaultFormat;
|
||||
|
||||
before.start = getPositionStart();
|
||||
before.length = m_selectionStart;
|
||||
after.start = m_selectionEnd;
|
||||
after.length = getTextLength() - m_selectionEnd;
|
||||
|
||||
QTextLayout::FormatRange selectedFormat = defaultFormat;
|
||||
selectedFormat.start = m_selectionStart;
|
||||
selectedFormat.length = getSelectionLength();
|
||||
selectedFormat.format.setForeground(QBrush(getAdjustedColor(palette.color(QPalette::HighlightedText)), Qt::SolidPattern));
|
||||
selectedFormat.format.setBackground(QBrush(getAdjustedColor(palette.color(QPalette::Highlight)), Qt::SolidPattern));
|
||||
|
||||
selections = { before, selectedFormat, after};
|
||||
}
|
||||
else
|
||||
{
|
||||
selections.push_back(defaultFormat);
|
||||
}
|
||||
|
||||
// Draw text
|
||||
m_textLayout.draw(painter, QPointF(0.0, 0.0), selections, QRectF());
|
||||
|
||||
// If we are editing, also draw text
|
||||
if (edit && !isReadonly())
|
||||
{
|
||||
m_textLayout.drawCursor(painter, QPointF(0.0, 0.0), m_positionCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getCursorPositionFromWidgetPosition(const QPointF& point, bool edit) const
|
||||
{
|
||||
QMatrix textBoxSpaceToPageSpace = createTextBoxTransformMatrix(edit);
|
||||
QMatrix pageSpaceToTextBoxSpace = textBoxSpaceToPageSpace.inverted();
|
||||
|
||||
QPointF textBoxPoint = pageSpaceToTextBoxSpace.map(point);
|
||||
|
||||
if (isComb())
|
||||
{
|
||||
// If it is comb, then characters are spaced equidistantly
|
||||
const qreal x = qBound(0.0, textBoxPoint.x(), m_widgetRect.width());
|
||||
const size_t position = qFloor(x * qreal(m_maxTextLength) / qreal(m_widgetRect.width()));
|
||||
std::vector<int> positions = getCursorPositions();
|
||||
if (position < positions.size())
|
||||
{
|
||||
return positions[position];
|
||||
}
|
||||
|
||||
return positions.back();
|
||||
}
|
||||
else if (m_textLayout.lineCount() > 0)
|
||||
{
|
||||
QTextLine line;
|
||||
qreal yPos = 0.0;
|
||||
|
||||
// Find line under cursor
|
||||
for (int i = 0; i < m_textLayout.lineCount(); ++i)
|
||||
{
|
||||
QTextLine currentLine = m_textLayout.lineAt(i);
|
||||
const qreal lineSpacing = currentLine.leadingIncluded() ? currentLine.height() : currentLine.leading() + currentLine.height();
|
||||
const qreal yNextPos = yPos + lineSpacing;
|
||||
|
||||
if (textBoxPoint.y() >= yPos && textBoxPoint.y() < yNextPos)
|
||||
{
|
||||
line = currentLine;
|
||||
break;
|
||||
}
|
||||
|
||||
yPos = yNextPos;
|
||||
}
|
||||
|
||||
// If no line is found, select last line
|
||||
if (!line.isValid())
|
||||
{
|
||||
if (textBoxPoint.y() < 0.0)
|
||||
{
|
||||
line = m_textLayout.lineAt(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
line = m_textLayout.lineAt(m_textLayout.lineCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return line.xToCursor(textBoxPoint.x(), QTextLine::CursorBetweenCharacters);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PDFTextEditPseudowidget::updateTextLayout()
|
||||
{
|
||||
// Prepare display text
|
||||
if (isPassword())
|
||||
{
|
||||
m_displayText.resize(m_editText.length(), m_passwordReplacementCharacter);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_displayText = m_editText;
|
||||
}
|
||||
|
||||
// Perform text layout
|
||||
m_textLayout.clearLayout();
|
||||
m_textLayout.setText(m_displayText);
|
||||
m_textLayout.beginLayout();
|
||||
|
||||
QPointF textLinePosition(0.0, 0.0);
|
||||
|
||||
while (true)
|
||||
{
|
||||
QTextLine textLine = m_textLayout.createLine();
|
||||
if (!textLine.isValid())
|
||||
{
|
||||
// We are finished with layout
|
||||
break;
|
||||
}
|
||||
|
||||
textLinePosition.ry() += textLine.leading();
|
||||
textLine.setLineWidth(m_widgetRect.width());
|
||||
textLine.setPosition(textLinePosition);
|
||||
textLinePosition.ry() += textLine.height();
|
||||
}
|
||||
m_textLayout.endLayout();
|
||||
|
||||
// Check length
|
||||
if (m_maxTextLength > 0)
|
||||
{
|
||||
int length = 0;
|
||||
int currentPos = 0;
|
||||
|
||||
while (currentPos < m_editText.length())
|
||||
{
|
||||
currentPos = m_textLayout.nextCursorPosition(currentPos, QTextLayout::SkipCharacters);
|
||||
++length;
|
||||
|
||||
if (length == m_maxTextLength)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPos < m_editText.length())
|
||||
{
|
||||
m_editText = m_editText.left(currentPos);
|
||||
m_positionCursor = qBound(getPositionStart(), m_positionCursor, getPositionEnd());
|
||||
updateTextLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getSingleStepForward() const
|
||||
{
|
||||
// If direction is right-to-left, then move backward (because
|
||||
// text is painted from right to left.
|
||||
return (m_textLayout.textOption().textDirection() == Qt::RightToLeft) ? -1 : 1;
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getNextPrevCursorPosition(int referencePosition, int steps, QTextLayout::CursorMode mode) const
|
||||
{
|
||||
int cursor = referencePosition;
|
||||
|
||||
if (steps > 0)
|
||||
{
|
||||
for (int i = 0; i < steps; ++i)
|
||||
{
|
||||
cursor = m_textLayout.nextCursorPosition(cursor, mode);
|
||||
}
|
||||
}
|
||||
else if (steps < 0)
|
||||
{
|
||||
for (int i = 0; i < -steps; ++i)
|
||||
{
|
||||
cursor = m_textLayout.previousCursorPosition(cursor, mode);
|
||||
}
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getCurrentLineTextStart() const
|
||||
{
|
||||
return m_textLayout.lineForTextPosition(m_positionCursor).textStart();
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getCurrentLineTextEnd() const
|
||||
{
|
||||
QTextLine textLine = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||
return textLine.textStart() + textLine.textLength();
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getCursorLineUp() const
|
||||
{
|
||||
QTextLine line = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||
const int lineIndex = line.lineNumber() - 1;
|
||||
|
||||
if (lineIndex >= 0)
|
||||
{
|
||||
QTextLine upLine = m_textLayout.lineAt(lineIndex);
|
||||
return upLine.xToCursor(line.cursorToX(m_positionCursor), QTextLine::CursorBetweenCharacters);
|
||||
}
|
||||
|
||||
return m_positionCursor;
|
||||
}
|
||||
|
||||
int PDFTextEditPseudowidget::getCursorLineDown() const
|
||||
{
|
||||
QTextLine line = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||
const int lineIndex = line.lineNumber() + 1;
|
||||
|
||||
if (lineIndex < m_textLayout.lineCount())
|
||||
{
|
||||
QTextLine downLine = m_textLayout.lineAt(lineIndex);
|
||||
return downLine.xToCursor(line.cursorToX(m_positionCursor), QTextLine::CursorBetweenCharacters);
|
||||
}
|
||||
|
||||
return m_positionCursor;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
217
Pdf4QtLib/sources/pdftexteditpseudowidget.h
Normal file
217
Pdf4QtLib/sources/pdftexteditpseudowidget.h
Normal file
@ -0,0 +1,217 @@
|
||||
// Copyright (C) 2022 Jakub Melka
|
||||
//
|
||||
// This file is part of PDF4QT.
|
||||
//
|
||||
// PDF4QT is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// with the written consent of the copyright owner, any later version.
|
||||
//
|
||||
// PDF4QT is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFTEXTEDITPSEUDOWIDGET_H
|
||||
#define PDFTEXTEDITPSEUDOWIDGET_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
#include "pdfform.h"
|
||||
|
||||
#include <QRectF>
|
||||
#include <QColor>
|
||||
|
||||
class QWidget;
|
||||
class QKeyEvent;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
/// "Pseudo" widget, which is emulating text editor, which can be single line, or multiline.
|
||||
/// Passwords can also be edited and editor can be read only.
|
||||
class PDFTextEditPseudowidget
|
||||
{
|
||||
public:
|
||||
explicit PDFTextEditPseudowidget(PDFFormField::FieldFlags flags);
|
||||
|
||||
void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event);
|
||||
void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
inline bool isReadonly() const { return m_flags.testFlag(PDFFormField::ReadOnly); }
|
||||
inline bool isMultiline() const { return m_flags.testFlag(PDFFormField::Multiline); }
|
||||
inline bool isPassword() const { return m_flags.testFlag(PDFFormField::Password); }
|
||||
inline bool isFileSelect() const { return m_flags.testFlag(PDFFormField::FileSelect); }
|
||||
inline bool isComb() const { return m_flags.testFlag(PDFFormField::Comb); }
|
||||
|
||||
inline bool isEmpty() const { return m_editText.isEmpty(); }
|
||||
inline bool isTextSelected() const { return !isEmpty() && getSelectionLength() > 0; }
|
||||
inline bool isWholeTextSelected() const { return !isEmpty() && getSelectionLength() == m_editText.length(); }
|
||||
|
||||
inline int getTextLength() const { return m_editText.length(); }
|
||||
inline int getSelectionLength() const { return m_selectionEnd - m_selectionStart; }
|
||||
|
||||
inline int getPositionCursor() const { return m_positionCursor; }
|
||||
inline int getPositionStart() const { return 0; }
|
||||
inline int getPositionEnd() const { return getTextLength(); }
|
||||
|
||||
inline void clearSelection() { m_selectionStart = m_selectionEnd = 0; }
|
||||
|
||||
inline const QString& getText() const { return m_editText; }
|
||||
inline QString getSelectedText() const { return m_editText.mid(m_selectionStart, getSelectionLength()); }
|
||||
|
||||
/// Sets (updates) text selection
|
||||
/// \param startPosition From where we are selecting text
|
||||
/// \param selectionLength Selection length (positive - to the right, negative - to the left)
|
||||
void setSelection(int startPosition, int selectionLength);
|
||||
|
||||
/// Moves cursor position. It behaves as usual in text boxes,
|
||||
/// when user moves the cursor. If \p select is true, then
|
||||
/// selection is updated.
|
||||
/// \param position New position of the cursor
|
||||
/// \param select Select text when moving the cursor?
|
||||
void setCursorPosition(int position, bool select);
|
||||
|
||||
/// Sets text content of the widget. This functions sets the text,
|
||||
/// even if widget is readonly.
|
||||
/// \param text Text to be set
|
||||
void setText(const QString& text);
|
||||
|
||||
/// Sets widget appearance, such as font, font size, color, text alignment,
|
||||
/// and rectangle, in which widget resides on page (in page coordinates)
|
||||
/// \param appearance Appearance
|
||||
/// \param textAlignment Text alignment
|
||||
/// \param rect Widget rectangle in page coordinates
|
||||
/// \param maxTextLength Maximal text length
|
||||
void setAppearance(const PDFAnnotationDefaultAppearance& appearance,
|
||||
Qt::Alignment textAlignment,
|
||||
QRectF rect,
|
||||
int maxTextLength);
|
||||
|
||||
/// Sets widget appearance, such as font, font size, color, text alignment,
|
||||
/// and rectangle, in which widget resides on page (in page coordinates)
|
||||
/// \param font Font
|
||||
/// \param textAlignment Text alignment
|
||||
/// \param rect Widget rectangle in page coordinates
|
||||
/// \param maxTextLength Maximal text length
|
||||
/// \param textColor Color
|
||||
void setAppearance(const QFont& font,
|
||||
Qt::Alignment textAlignment,
|
||||
QRectF rect,
|
||||
int maxTextLength,
|
||||
QColor textColor);
|
||||
|
||||
void performCut();
|
||||
void performCopy();
|
||||
void performPaste();
|
||||
void performClear();
|
||||
void performSelectAll();
|
||||
void performBackspace();
|
||||
void performDelete();
|
||||
void performRemoveSelectedText();
|
||||
void performInsertText(const QString& text);
|
||||
|
||||
/// Draw text edit using given parameters
|
||||
/// \param parameters Parameters
|
||||
void draw(AnnotationDrawParameters& parameters, bool edit) const;
|
||||
|
||||
/// Returns valid cursor position retrieved from position in the widget.
|
||||
/// \param point Point in page coordinate space
|
||||
/// \param edit Are we using edit transformations?
|
||||
/// \returns Cursor position
|
||||
int getCursorPositionFromWidgetPosition(const QPointF& point, bool edit) const;
|
||||
|
||||
inline int getCursorForward(QTextLayout::CursorMode mode) const { return getNextPrevCursorPosition(getSingleStepForward(), mode); }
|
||||
inline int getCursorBackward(QTextLayout::CursorMode mode) const { return getNextPrevCursorPosition(getSingleStepBackward(), mode); }
|
||||
inline int getCursorCharacterForward() const { return getCursorForward(QTextLayout::SkipCharacters); }
|
||||
inline int getCursorCharacterBackward() const { return getCursorBackward(QTextLayout::SkipCharacters); }
|
||||
inline int getCursorWordForward() const { return getCursorForward(QTextLayout::SkipWords); }
|
||||
inline int getCursorWordBackward() const { return getCursorBackward(QTextLayout::SkipWords); }
|
||||
inline int getCursorDocumentStart() const { return (getSingleStepForward() > 0) ? getPositionStart() : getPositionEnd(); }
|
||||
inline int getCursorDocumentEnd() const { return (getSingleStepForward() > 0) ? getPositionEnd() : getPositionStart(); }
|
||||
inline int getCursorLineStart() const { return (getSingleStepForward() > 0) ? getCurrentLineTextStart() : getCurrentLineTextEnd(); }
|
||||
inline int getCursorLineEnd() const { return (getSingleStepForward() > 0) ? getCurrentLineTextEnd() : getCurrentLineTextStart(); }
|
||||
inline int getCursorNextLine() const { return getCurrentLineTextEnd(); }
|
||||
inline int getCursorPreviousLine() const { return getNextPrevCursorPosition(getCurrentLineTextStart(), -1, QTextLayout::SkipCharacters); }
|
||||
|
||||
const QRectF& getWidgetRect() const { return m_widgetRect; }
|
||||
QFont getFont() const { return m_textLayout.font(); }
|
||||
QColor getFontColor() const { return m_textColor; }
|
||||
|
||||
private:
|
||||
/// This function does following things:
|
||||
/// 1) Clamps edit text to fit maximum length
|
||||
/// 2) Creates display string from edit string
|
||||
/// 3) Updates text layout
|
||||
void updateTextLayout();
|
||||
|
||||
/// Returns single step forward, which is determined
|
||||
/// by cursor move style and layout direction.
|
||||
int getSingleStepForward() const;
|
||||
|
||||
/// Returns single step backward, which is determined
|
||||
/// by cursor move style and layout direction.
|
||||
int getSingleStepBackward() const { return -getSingleStepForward(); }
|
||||
|
||||
/// Returns next/previous position, by number of steps,
|
||||
/// using given cursor mode (skipping characters or whole words).
|
||||
/// \param steps Number of steps to proceed (can be negative number)
|
||||
/// \param mode Skip mode - letters or words?
|
||||
int getNextPrevCursorPosition(int steps, QTextLayout::CursorMode mode) const { return getNextPrevCursorPosition(m_positionCursor, steps, mode); }
|
||||
|
||||
/// Returns next/previous position from reference cursor position, by number of steps,
|
||||
/// using given cursor mode (skipping characters or whole words).
|
||||
/// \param referencePosition Reference cursor position
|
||||
/// \param steps Number of steps to proceed (can be negative number)
|
||||
/// \param mode Skip mode - letters or words?
|
||||
int getNextPrevCursorPosition(int referencePosition, int steps, QTextLayout::CursorMode mode) const;
|
||||
|
||||
/// Returns current line text start position
|
||||
int getCurrentLineTextStart() const;
|
||||
|
||||
/// Returns current line text end position
|
||||
int getCurrentLineTextEnd() const;
|
||||
|
||||
/// Creates text box transform matrix, which transforms from
|
||||
/// widget space to page space.
|
||||
/// \param edit Create matrix for text editing?
|
||||
QMatrix createTextBoxTransformMatrix(bool edit) const;
|
||||
|
||||
/// Returns vector of cursor positions (which may be not equal
|
||||
/// to edit string length, because edit string can contain surrogates,
|
||||
/// or graphemes, which are single glyphs, but represented by more
|
||||
/// 16-bit unicode codes).
|
||||
std::vector<int> getCursorPositions() const;
|
||||
|
||||
int getCursorLineUp() const;
|
||||
int getCursorLineDown() const;
|
||||
|
||||
PDFFormField::FieldFlags m_flags;
|
||||
|
||||
/// Text edited by the user
|
||||
QString m_editText;
|
||||
|
||||
/// Text, which is displayed. It can differ from text
|
||||
/// edited by user, in case password is being entered.
|
||||
QString m_displayText;
|
||||
|
||||
/// Text layout
|
||||
QTextLayout m_textLayout;
|
||||
|
||||
/// Character for displaying passwords
|
||||
QChar m_passwordReplacementCharacter;
|
||||
|
||||
int m_selectionStart;
|
||||
int m_selectionEnd;
|
||||
int m_positionCursor;
|
||||
int m_maxTextLength;
|
||||
|
||||
QRectF m_widgetRect;
|
||||
QColor m_textColor;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFTEXTEDITPSEUDOWIDGET_H
|
@ -106,6 +106,14 @@ void PDFWidgetTool::setActive(bool active)
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetTool::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||
{
|
||||
tool->shortcutOverrideEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||
@ -130,6 +138,14 @@ void PDFWidgetTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetTool::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||
{
|
||||
tool->mouseDoubleClickEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||
@ -194,11 +210,13 @@ PDFWidgetTool* PDFWidgetTool::getTopToolstackTool() const
|
||||
|
||||
void PDFWidgetTool::addTool(PDFWidgetTool* tool)
|
||||
{
|
||||
tool->setActive(isActive());
|
||||
m_toolStack.push_back(tool);
|
||||
}
|
||||
|
||||
void PDFWidgetTool::removeTool()
|
||||
{
|
||||
m_toolStack.back()->setActive(false);
|
||||
m_toolStack.pop_back();
|
||||
}
|
||||
|
||||
@ -809,8 +827,12 @@ PDFMagnifierTool* PDFToolManager::getMagnifierTool() const
|
||||
|
||||
void PDFToolManager::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
event->ignore();
|
||||
|
||||
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||
{
|
||||
activeTool->shortcutOverrideEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
@ -854,8 +876,12 @@ void PDFToolManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
|
||||
void PDFToolManager::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
event->ignore();
|
||||
|
||||
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||
{
|
||||
activeTool->mouseDoubleClickEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFToolManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
@ -1070,6 +1096,11 @@ void PDFPickTool::drawPage(QPainter* painter,
|
||||
Q_UNUSED(layoutGetter);
|
||||
Q_UNUSED(errors);
|
||||
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are picking rectangles, then draw current selection rectangle
|
||||
if (m_mode == Mode::Rectangles && m_drawSelectionRectangle && m_pageIndex == pageIndex && !m_pickedPoints.empty())
|
||||
{
|
||||
@ -1097,6 +1128,11 @@ void PDFPickTool::drawPage(QPainter* painter,
|
||||
|
||||
void PDFPickTool::drawPostRendering(QPainter* painter, QRect rect) const
|
||||
{
|
||||
if (!isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_mode != Mode::Images)
|
||||
{
|
||||
m_snapper.drawSnapPoints(painter);
|
||||
|
@ -62,6 +62,11 @@ public:
|
||||
/// Returns action for activating/deactivating this tool
|
||||
QAction* getAction() const { return m_action; }
|
||||
|
||||
/// Handles shortcut override event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles key press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
@ -77,6 +82,11 @@ public:
|
||||
/// \param event Event
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse double click event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse release event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
|
@ -122,6 +122,7 @@ void SignaturePlugin::setWidget(pdf::PDFWidget* widget)
|
||||
rejectMarkFile.close();
|
||||
}
|
||||
|
||||
m_tools[TextTool] = new pdf::PDFCreatePCElementTextTool(widget->getDrawWidgetProxy(), &m_scene, createTextAction, this);
|
||||
m_tools[FreehandCurveTool] = new pdf::PDFCreatePCElementFreehandCurveTool(widget->getDrawWidgetProxy(), &m_scene, createFreehandCurveAction, this);
|
||||
m_tools[AcceptMarkTool] = new pdf::PDFCreatePCElementSvgTool(widget->getDrawWidgetProxy(), &m_scene, createAcceptMarkAction, acceptMarkContent, this);
|
||||
m_tools[RejectMarkTool] = new pdf::PDFCreatePCElementSvgTool(widget->getDrawWidgetProxy(), &m_scene, createRejectMarkAction, rejectMarkContent, this);
|
||||
|
@ -79,6 +79,7 @@ private:
|
||||
|
||||
enum Tools
|
||||
{
|
||||
TextTool,
|
||||
FreehandCurveTool,
|
||||
AcceptMarkTool,
|
||||
RejectMarkTool,
|
||||
|
Loading…
x
Reference in New Issue
Block a user