mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Widget painting
This commit is contained in:
@ -36,6 +36,7 @@
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QStyleOptionButton>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
@ -165,7 +166,7 @@ PDFObject PDFAppeareanceStreams::getAppearance(Appearance appearance, const QByt
|
||||
return PDFObject();
|
||||
}
|
||||
|
||||
QByteArrayList PDFAppeareanceStreams::getAppearanceStates(Appearance appearance)
|
||||
QByteArrayList PDFAppeareanceStreams::getAppearanceStates(Appearance appearance) const
|
||||
{
|
||||
QByteArrayList result;
|
||||
|
||||
@ -182,6 +183,13 @@ QByteArrayList PDFAppeareanceStreams::getAppearanceStates(Appearance appearance)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFAppeareanceStreams::getAppearanceKeys() const
|
||||
{
|
||||
std::vector<Key> result;
|
||||
std::transform(m_appearanceStreams.cbegin(), m_appearanceStreams.cend(), std::back_inserter(result), [](const auto& item) { return item.first; });
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFAnnotation::PDFAnnotation() :
|
||||
m_flags(),
|
||||
m_structParent(0)
|
||||
@ -194,8 +202,10 @@ void PDFAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
Q_UNUSED(parameters);
|
||||
}
|
||||
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFAnnotation::getDrawKeys() const
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFAnnotation::getDrawKeys(const PDFFormManager* formManager) const
|
||||
{
|
||||
Q_UNUSED(formManager);
|
||||
|
||||
return { PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Normal, QByteArray() } };
|
||||
}
|
||||
|
||||
@ -1749,8 +1759,10 @@ QColor PDFMarkupAnnotation::getFillColor() const
|
||||
return color;
|
||||
}
|
||||
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFTextAnnotation::getDrawKeys() const
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFTextAnnotation::getDrawKeys(const PDFFormManager* formManager) const
|
||||
{
|
||||
Q_UNUSED(formManager);
|
||||
|
||||
return { PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Normal, QByteArray() },
|
||||
PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Rollover, QByteArray() },
|
||||
PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Down, QByteArray() } };
|
||||
@ -2328,8 +2340,10 @@ void PDFHighlightAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
parameters.boundingRectangle.adjust(-penWidth, -penWidth, penWidth, penWidth);
|
||||
}
|
||||
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFLinkAnnotation::getDrawKeys() const
|
||||
std::vector<PDFAppeareanceStreams::Key> PDFLinkAnnotation::getDrawKeys(const PDFFormManager* formManager) const
|
||||
{
|
||||
Q_UNUSED(formManager);
|
||||
|
||||
return { PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Down, QByteArray() } };
|
||||
}
|
||||
|
||||
@ -2899,6 +2913,8 @@ void PDFWidgetAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
return;
|
||||
}
|
||||
|
||||
PDFPainterStateGuard guard(parameters.painter);
|
||||
|
||||
const PDFFormFieldWidgetEditor* editor = parameters.formManager->getEditor(formField);
|
||||
if (editor && editor->isEditorDrawEnabled())
|
||||
{
|
||||
@ -2921,8 +2937,112 @@ void PDFWidgetAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
}
|
||||
|
||||
case PDFFormField::FieldType::Button:
|
||||
case PDFFormField::FieldType::Invalid:
|
||||
{
|
||||
const PDFFormFieldButton* button = dynamic_cast<const PDFFormFieldButton*>(formField);
|
||||
switch (button->getButtonType())
|
||||
{
|
||||
case PDFFormFieldButton::ButtonType::PushButton:
|
||||
{
|
||||
QRectF rectangle = getRectangle();
|
||||
|
||||
QByteArray defaultAppearance = parameters.formManager->getForm()->getDefaultAppearance().value_or(QByteArray());
|
||||
PDFAnnotationDefaultAppearance appearance = PDFAnnotationDefaultAppearance::parse(defaultAppearance);
|
||||
|
||||
qreal fontSize = appearance.getFontSize();
|
||||
if (qFuzzyIsNull(fontSize))
|
||||
{
|
||||
fontSize = rectangle.height() * 0.6;
|
||||
}
|
||||
|
||||
QFont font(appearance.getFontName());
|
||||
font.setHintingPreference(QFont::PreferNoHinting);
|
||||
font.setPixelSize(qCeil(fontSize));
|
||||
font.setStyleStrategy(QFont::ForceOutline);
|
||||
|
||||
QFontMetrics fontMetrics(font);
|
||||
|
||||
QPainter* painter = parameters.painter;
|
||||
painter->translate(rectangle.bottomLeft());
|
||||
painter->scale(1.0, -1.0);
|
||||
painter->setFont(font);
|
||||
|
||||
QStyleOptionButton option;
|
||||
option.state = QStyle::State_Enabled;
|
||||
option.rect = QRect(0, 0, qFloor(rectangle.width()), qFloor(rectangle.height()));
|
||||
option.palette = QApplication::palette();
|
||||
|
||||
if (parameters.key.first == PDFAppeareanceStreams::Appearance::Rollover)
|
||||
{
|
||||
option.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
|
||||
if (parameters.key.first == PDFAppeareanceStreams::Appearance::Down)
|
||||
{
|
||||
option.state |= QStyle::State_Sunken;
|
||||
}
|
||||
|
||||
option.features = QStyleOptionButton::None;
|
||||
option.text = getContents();
|
||||
option.fontMetrics = fontMetrics;
|
||||
|
||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &option, painter, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case PDFFormFieldButton::ButtonType::RadioButton:
|
||||
case PDFFormFieldButton::ButtonType::CheckBox:
|
||||
{
|
||||
QRectF rectangle = getRectangle();
|
||||
QPainter* painter = parameters.painter;
|
||||
painter->translate(rectangle.bottomLeft());
|
||||
painter->scale(1.0, -1.0);
|
||||
|
||||
QStyleOptionButton option;
|
||||
option.state = QStyle::State_Enabled;
|
||||
option.rect = QRect(0, 0, qFloor(rectangle.width()), qFloor(rectangle.height()));
|
||||
option.palette = QApplication::palette();
|
||||
|
||||
if (parameters.key.first == PDFAppeareanceStreams::Appearance::Rollover)
|
||||
{
|
||||
option.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
|
||||
if (parameters.key.first == PDFAppeareanceStreams::Appearance::Down)
|
||||
{
|
||||
option.state |= QStyle::State_Sunken;
|
||||
}
|
||||
|
||||
if (parameters.key.second != "Off")
|
||||
{
|
||||
option.state |= QStyle::State_On;
|
||||
}
|
||||
else
|
||||
{
|
||||
option.state |= QStyle::State_Off;
|
||||
}
|
||||
|
||||
option.features = QStyleOptionButton::None;
|
||||
option.text = QString();
|
||||
|
||||
QStyle::PrimitiveElement element = (button->getButtonType() == PDFFormFieldButton::ButtonType::CheckBox) ? QStyle::PE_IndicatorCheckBox : QStyle::PE_IndicatorRadioButton;
|
||||
QApplication::style()->drawPrimitive(element, &option, painter, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PDFFormField::FieldType::Choice:
|
||||
// TODO: Draw choice field
|
||||
|
||||
case PDFFormField::FieldType::Invalid:
|
||||
case PDFFormField::FieldType::Signature:
|
||||
break;
|
||||
|
||||
@ -2935,4 +3055,82 @@ void PDFWidgetAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<pdf::PDFAppeareanceStreams::Key> PDFWidgetAnnotation::getDrawKeys(const PDFFormManager* formManager) const
|
||||
{
|
||||
if (!formManager)
|
||||
{
|
||||
return PDFAnnotation::getDrawKeys(formManager);
|
||||
}
|
||||
|
||||
std::vector<pdf::PDFAppeareanceStreams::Key> result;
|
||||
|
||||
// Try get the form field, if we find it, then determine from form field type
|
||||
// the list of appearance states.
|
||||
const PDFFormField* formField = formManager->getFormFieldForWidget(getSelfReference());
|
||||
if (!formField)
|
||||
{
|
||||
return PDFAnnotation::getDrawKeys(formManager);
|
||||
}
|
||||
|
||||
switch (formField->getFieldType())
|
||||
{
|
||||
case PDFFormField::FieldType::Invalid:
|
||||
break;
|
||||
|
||||
case PDFFormField::FieldType::Button:
|
||||
{
|
||||
const PDFFormFieldButton* button = dynamic_cast<const PDFFormFieldButton*>(formField);
|
||||
switch (button->getButtonType())
|
||||
{
|
||||
case PDFFormFieldButton::ButtonType::PushButton:
|
||||
{
|
||||
result = { PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Normal, QByteArray() },
|
||||
PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Rollover, QByteArray() },
|
||||
PDFAppeareanceStreams::Key{ PDFAppeareanceStreams::Appearance::Down, QByteArray() } };
|
||||
break;
|
||||
}
|
||||
|
||||
case PDFFormFieldButton::ButtonType::RadioButton:
|
||||
case PDFFormFieldButton::ButtonType::CheckBox:
|
||||
{
|
||||
result = getAppearanceStreams().getAppearanceKeys();
|
||||
PDFAppeareanceStreams::Key offKey{ PDFAppeareanceStreams::Appearance::Normal, QByteArray() };
|
||||
if (std::find(result.cbegin(), result.cend(), offKey) == result.cend())
|
||||
{
|
||||
result.push_back(qMove(offKey));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PDFFormField::FieldType::Text:
|
||||
// Text has only default appearance
|
||||
break;
|
||||
|
||||
case PDFFormField::FieldType::Choice:
|
||||
// TODO: Implement choice appearance
|
||||
break;
|
||||
|
||||
case PDFFormField::FieldType::Signature:
|
||||
// Signatures have always default appearance
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.empty())
|
||||
{
|
||||
result = PDFAnnotation::getDrawKeys(formManager);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -212,7 +212,10 @@ public:
|
||||
|
||||
/// Returns list of appearance states for given appearance
|
||||
/// \param appearance Appearance
|
||||
QByteArrayList getAppearanceStates(Appearance appearance);
|
||||
QByteArrayList getAppearanceStates(Appearance appearance) const;
|
||||
|
||||
/// Returns list of appearance keys
|
||||
std::vector<Key> getAppearanceKeys() const;
|
||||
|
||||
private:
|
||||
std::map<Key, PDFObject> m_appearanceStreams;
|
||||
@ -504,7 +507,7 @@ public:
|
||||
virtual void draw(AnnotationDrawParameters& parameters) const;
|
||||
|
||||
/// Returns a list of appearance states, which must be created for this annotation
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys() const;
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys(const PDFFormManager* formManager) const;
|
||||
|
||||
/// Returns effective flags (some annotations can behave as they have always
|
||||
/// set some flags, such as NoZoom and NoRotate)
|
||||
@ -695,7 +698,7 @@ public:
|
||||
inline explicit PDFTextAnnotation() = default;
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::Text; }
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys() const override;
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys(const PDFFormManager* formManager) const override;
|
||||
virtual void draw(AnnotationDrawParameters& parameters) const override;
|
||||
virtual Flags getEffectiveFlags() const override;
|
||||
|
||||
@ -729,7 +732,7 @@ public:
|
||||
inline explicit PDFLinkAnnotation() = default;
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::Link; }
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys() const;
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys(const PDFFormManager* formManager) const override;
|
||||
virtual void draw(AnnotationDrawParameters& parameters) const override;
|
||||
|
||||
const PDFAction* getAction() const { return m_action.data(); }
|
||||
@ -1168,6 +1171,7 @@ public:
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::Widget; }
|
||||
virtual void draw(AnnotationDrawParameters& parameters) const override;
|
||||
virtual std::vector<PDFAppeareanceStreams::Key> getDrawKeys(const PDFFormManager* formManager) const override;
|
||||
|
||||
HighlightMode getHighlightMode() const { return m_highlightMode; }
|
||||
const PDFAnnotationAppearanceCharacteristics& getAppearanceCharacteristics() const { return m_appearanceCharacteristics; }
|
||||
|
@ -755,7 +755,7 @@ void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference an
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<PDFAppeareanceStreams::Key> keys = annotation->getDrawKeys();
|
||||
std::vector<PDFAppeareanceStreams::Key> keys = annotation->getDrawKeys(m_formManager);
|
||||
std::map<PDFAppeareanceStreams::Key, PDFObjectReference> appearanceStreams;
|
||||
|
||||
QRectF boundingRectangle;
|
||||
@ -1080,6 +1080,16 @@ std::vector<PDFObject> PDFDocumentBuilder::copyFrom(const std::vector<PDFObject>
|
||||
return result;
|
||||
}
|
||||
|
||||
const PDFFormManager* PDFDocumentBuilder::getFormManager() const
|
||||
{
|
||||
return m_formManager;
|
||||
}
|
||||
|
||||
void PDFDocumentBuilder::setFormManager(const PDFFormManager* formManager)
|
||||
{
|
||||
m_formManager = formManager;
|
||||
}
|
||||
|
||||
PDFContentStreamBuilder::PDFContentStreamBuilder(QSizeF size, CoordinateSystem coordinateSystem) :
|
||||
m_size(size),
|
||||
m_coordinateSystem(coordinateSystem),
|
||||
|
@ -279,6 +279,9 @@ public:
|
||||
/// \param annotationReference Reference to the annotation
|
||||
void updateAnnotationAppearanceStreams(PDFObjectReference annotationReference);
|
||||
|
||||
const PDFFormManager* getFormManager() const;
|
||||
void setFormManager(const PDFFormManager* formManager);
|
||||
|
||||
/* START GENERATED CODE */
|
||||
|
||||
/// Appends a new page after last page.
|
||||
@ -973,6 +976,7 @@ private:
|
||||
|
||||
PDFObjectStorage m_storage;
|
||||
PDFVersion m_version;
|
||||
const PDFFormManager* m_formManager = nullptr;
|
||||
};
|
||||
|
||||
/// This class serves for document modification. While document is modified,
|
||||
|
@ -780,6 +780,7 @@ void PDFFormManager::setFormFieldValue(PDFFormField::SetValueParameters paramete
|
||||
parameters.scope = PDFFormField::SetValueParameters::Scope::User;
|
||||
|
||||
PDFDocumentModifier modifier(m_document);
|
||||
modifier.getBuilder()->setFormManager(this);
|
||||
parameters.modifier = &modifier;
|
||||
|
||||
if (parameters.invokingFormField->setValue(parameters))
|
||||
@ -2102,6 +2103,23 @@ QMatrix PDFTextEditPseudowidget::createTextBoxTransformMatrix(bool edit) const
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2228,7 +2246,7 @@ void PDFTextEditPseudowidget::draw(AnnotationDrawParameters& parameters, bool ed
|
||||
m_textLayout.draw(painter, QPointF(0.0, 0.0), selections, QRectF());
|
||||
|
||||
// If we are editing, also draw text
|
||||
if (edit)
|
||||
if (edit && !isReadonly())
|
||||
{
|
||||
m_textLayout.drawCursor(painter, QPointF(0.0, 0.0), m_positionCursor);
|
||||
}
|
||||
|
Reference in New Issue
Block a user