mirror of https://github.com/JakubMelka/PDF4QT.git
Combo box (basics)
This commit is contained in:
parent
0a05c33c3b
commit
7e02bdde1e
|
@ -124,6 +124,8 @@ public:
|
|||
inline int getCursorNextLine() const { return getCurrentLineTextEnd(); }
|
||||
inline int getCursorPreviousLine() const { return getNextPrevCursorPosition(getCurrentLineTextStart(), -1, QTextLayout::SkipCharacters); }
|
||||
|
||||
const QRectF& getWidgetRect() const { return m_widgetRect; }
|
||||
|
||||
private:
|
||||
/// This function does following things:
|
||||
/// 1) Clamps edit text to fit maximum length
|
||||
|
@ -274,17 +276,6 @@ private:
|
|||
PDFTextEditPseudowidget m_textEdit;
|
||||
};
|
||||
|
||||
/// Editor for combo boxes
|
||||
class PDFFormFieldComboBoxEditor : public PDFFormFieldWidgetEditor
|
||||
{
|
||||
private:
|
||||
using BaseClass = PDFFormFieldWidgetEditor;
|
||||
|
||||
public:
|
||||
explicit PDFFormFieldComboBoxEditor(PDFFormManager* formManager, PDFFormWidget formWidget);
|
||||
virtual ~PDFFormFieldComboBoxEditor() = default;
|
||||
};
|
||||
|
||||
/// "Pseudo" widget, which is emulating list box. It can contain scrollbar.
|
||||
class PDFListBoxPseudowidget
|
||||
{
|
||||
|
@ -393,6 +384,50 @@ private:
|
|||
QColor m_textColor;
|
||||
};
|
||||
|
||||
/// Editor for combo boxes
|
||||
class PDFFormFieldComboBoxEditor : public PDFFormFieldWidgetEditor
|
||||
{
|
||||
private:
|
||||
using BaseClass = PDFFormFieldWidgetEditor;
|
||||
|
||||
public:
|
||||
explicit PDFFormFieldComboBoxEditor(PDFFormManager* formManager, PDFFormWidget formWidget);
|
||||
virtual ~PDFFormFieldComboBoxEditor() = default;
|
||||
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition) override;
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition) override;
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event, const QPointF& mousePagePosition) override;
|
||||
virtual void reloadValue() override;
|
||||
virtual bool isEditorDrawEnabled() const override { return m_hasFocus; }
|
||||
virtual void draw(AnnotationDrawParameters& parameters, bool edit) const override;
|
||||
virtual QRectF getActiveEditorRectangle() const override;
|
||||
|
||||
/// Initializes text edit using actual form field value,
|
||||
/// font, color for text edit appearance.
|
||||
/// \param textEdit Text editor
|
||||
void initializeTextEdit(PDFTextEditPseudowidget* textEdit) const;
|
||||
|
||||
/// Initializes list box using actual form field font, color for text edit appearance.
|
||||
/// This listbox is used when combo box is in "down" mode, displaying options.
|
||||
/// \param listBox List box
|
||||
void initializeListBox(PDFListBoxPseudowidget* listBox) const;
|
||||
|
||||
protected:
|
||||
virtual void setFocusImpl(bool focused);
|
||||
|
||||
private:
|
||||
static PDFFormField::FieldFlags getTextEditFlags(PDFFormField::FieldFlags flags);
|
||||
|
||||
PDFTextEditPseudowidget m_textEdit;
|
||||
PDFListBoxPseudowidget m_listBox;
|
||||
QRectF m_listBoxPopupRectangle;
|
||||
QRectF m_dropDownButtonRectangle;
|
||||
bool m_listBoxVisible;
|
||||
};
|
||||
|
||||
/// Editor for list boxes
|
||||
class PDFFormFieldListBoxEditor : public PDFFormFieldWidgetEditor
|
||||
{
|
||||
|
@ -1485,16 +1520,21 @@ PDFFormManager::MouseEventInfo PDFFormManager::getMouseEventInfo(QWidget* widget
|
|||
continue;
|
||||
}
|
||||
|
||||
QRectF annotationRect = pageAnnotation.annotation->getRectangle();
|
||||
QMatrix widgetToDevice = m_annotationManager->prepareTransformations(snapshotItem.pageToDeviceMatrix, widget, pageAnnotation.annotation->getEffectiveFlags(), m_document->getCatalog()->getPage(snapshotItem.pageIndex), annotationRect);
|
||||
|
||||
QPainterPath path;
|
||||
path.addRect(annotationRect);
|
||||
path = widgetToDevice.map(path);
|
||||
|
||||
if (path.contains(point))
|
||||
if (PDFFormField* formField = getFormFieldForWidget(pageAnnotation.annotation->getSelfReference()))
|
||||
{
|
||||
if (PDFFormField* formField = getFormFieldForWidget(pageAnnotation.annotation->getSelfReference()))
|
||||
const PDFFormFieldWidgetEditor* editor = getEditor(formField);
|
||||
QRectF annotationRect = editor->getActiveEditorRectangle();
|
||||
if (!annotationRect.isValid())
|
||||
{
|
||||
annotationRect = pageAnnotation.annotation->getRectangle();
|
||||
}
|
||||
QMatrix widgetToDevice = m_annotationManager->prepareTransformations(snapshotItem.pageToDeviceMatrix, widget, pageAnnotation.annotation->getEffectiveFlags(), m_document->getCatalog()->getPage(snapshotItem.pageIndex), annotationRect);
|
||||
|
||||
QPainterPath path;
|
||||
path.addRect(annotationRect);
|
||||
path = widgetToDevice.map(path);
|
||||
|
||||
if (path.contains(point))
|
||||
{
|
||||
result.formField = formField;
|
||||
result.deviceToWidget = widgetToDevice.inverted();
|
||||
|
@ -1903,11 +1943,284 @@ void PDFFormFieldCheckableButtonEditor::click()
|
|||
}
|
||||
|
||||
PDFFormFieldComboBoxEditor::PDFFormFieldComboBoxEditor(PDFFormManager* formManager, PDFFormWidget formWidget) :
|
||||
BaseClass(formManager, formWidget)
|
||||
BaseClass(formManager, formWidget),
|
||||
m_textEdit(getTextEditFlags(formWidget.getParent()->getFlags())),
|
||||
m_listBox(formWidget.getParent()->getFlags()),
|
||||
m_listBoxVisible(false)
|
||||
{
|
||||
const int listBoxItems = 7;
|
||||
QRectF comboBoxRectangle = m_formManager->getWidgetRectangle(m_formWidget);
|
||||
QRectF listBoxPopupRectangle = comboBoxRectangle;
|
||||
listBoxPopupRectangle.translate(0, -comboBoxRectangle.height() * (listBoxItems));
|
||||
listBoxPopupRectangle.setHeight(comboBoxRectangle.height() * listBoxItems);
|
||||
m_listBoxPopupRectangle = listBoxPopupRectangle;
|
||||
m_dropDownButtonRectangle = comboBoxRectangle;
|
||||
m_dropDownButtonRectangle.setLeft(m_dropDownButtonRectangle.right() - m_dropDownButtonRectangle.height());
|
||||
|
||||
initializeTextEdit(&m_textEdit);
|
||||
initializeListBox(&m_listBox);
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
if (!m_hasFocus || !m_listBoxVisible)
|
||||
{
|
||||
m_textEdit.shortcutOverrideEvent(widget, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_listBox.shortcutOverrideEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_ASSERT(!m_textEdit.isMultiline());
|
||||
|
||||
if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
||||
{
|
||||
// Commit the editor
|
||||
m_formManager->setFocusToEditor(nullptr);
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Escape)
|
||||
{
|
||||
// Cancel the editor
|
||||
reloadValue();
|
||||
m_formManager->setFocusToEditor(nullptr);
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_hasFocus || !m_listBoxVisible)
|
||||
{
|
||||
m_textEdit.keyPressEvent(widget, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_listBox.keyPressEvent(widget, event);
|
||||
}
|
||||
|
||||
if (event->isAccepted())
|
||||
{
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::mousePressEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton && m_hasFocus)
|
||||
{
|
||||
// If popup list box is visible, delegate mouse click to
|
||||
// this list box only.
|
||||
if (m_listBoxVisible)
|
||||
{
|
||||
const int index = m_listBox.getIndexFromWidgetPosition(mousePagePosition);
|
||||
|
||||
if (event->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
std::set<int> selection = m_listBox.getSelection();
|
||||
if (selection.count(index))
|
||||
{
|
||||
selection.erase(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
selection.insert(index);
|
||||
}
|
||||
m_listBox.setSelection(qMove(selection), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_listBox.setCurrentItem(index, event->modifiers());
|
||||
}
|
||||
|
||||
m_listBoxVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do we click popup button?
|
||||
if (m_dropDownButtonRectangle.contains(mousePagePosition))
|
||||
{
|
||||
m_listBoxVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int cursorPosition = m_textEdit.getCursorPositionFromWidgetPosition(mousePagePosition, m_hasFocus);
|
||||
m_textEdit.setCursorPosition(cursorPosition, event->modifiers() & Qt::ShiftModifier);
|
||||
}
|
||||
}
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::mouseMoveEvent(QWidget* widget, QMouseEvent* event, const QPointF& mousePagePosition)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::wheelEvent(QWidget* widget, QWheelEvent* event, const QPointF& mousePagePosition)
|
||||
{
|
||||
Q_UNUSED(mousePagePosition);
|
||||
|
||||
if (m_hasFocus && m_listBoxVisible)
|
||||
{
|
||||
if (event->angleDelta().y() < 0)
|
||||
{
|
||||
m_listBox.scrollTo(m_listBox.getValidIndex(m_listBox.getTopItemIndex() + m_listBox.getViewportRowCount()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_listBox.scrollTo(m_listBox.getValidIndex(m_listBox.getTopItemIndex() - 1));
|
||||
}
|
||||
|
||||
widget->update();
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::reloadValue()
|
||||
{
|
||||
const PDFFormFieldChoice* parentField = dynamic_cast<const PDFFormFieldChoice*>(m_formWidget.getParent());
|
||||
Q_ASSERT(parentField);
|
||||
|
||||
PDFDocumentDataLoaderDecorator loader(m_formManager->getDocument());
|
||||
m_textEdit.setText(loader.readTextString(m_formWidget.getParent()->getValue(), QString()));
|
||||
|
||||
m_listBoxVisible = false;
|
||||
|
||||
m_listBox.setTopItemIndex(0);
|
||||
m_listBox.setSelection({ }, true);
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::draw(AnnotationDrawParameters& parameters, bool edit) const
|
||||
{
|
||||
if (edit)
|
||||
{
|
||||
// Draw text edit always
|
||||
{
|
||||
PDFPainterStateGuard guard(parameters.painter);
|
||||
m_textEdit.draw(parameters, true);
|
||||
}
|
||||
|
||||
// Draw down button
|
||||
{
|
||||
PDFPainterStateGuard guard(parameters.painter);
|
||||
|
||||
parameters.painter->translate(m_dropDownButtonRectangle.bottomLeft());
|
||||
parameters.painter->scale(1.0, -1.0);
|
||||
|
||||
QStyleOption option;
|
||||
option.state = QStyle::State_Enabled;
|
||||
option.rect = QRect(0, 0, qFloor(m_dropDownButtonRectangle.width()), qFloor(m_dropDownButtonRectangle.height()));
|
||||
QApplication::style()->drawPrimitive(QStyle::PE_IndicatorButtonDropDown, &option, parameters.painter, nullptr);
|
||||
}
|
||||
|
||||
if (m_listBoxVisible)
|
||||
{
|
||||
PDFPainterStateGuard guard(parameters.painter);
|
||||
|
||||
AnnotationDrawParameters listBoxParameters = parameters;
|
||||
listBoxParameters.boundingRectangle = m_listBoxPopupRectangle;
|
||||
|
||||
QColor color = parameters.invertColors ? Qt::black : Qt::white;
|
||||
listBoxParameters.painter->fillRect(listBoxParameters.boundingRectangle, color);
|
||||
|
||||
m_listBox.draw(listBoxParameters, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw static contents
|
||||
PDFTextEditPseudowidget pseudowidget(m_formWidget.getParent()->getFlags());
|
||||
initializeTextEdit(&pseudowidget);
|
||||
pseudowidget.draw(parameters, false);
|
||||
}
|
||||
}
|
||||
|
||||
QRectF PDFFormFieldComboBoxEditor::getActiveEditorRectangle() const
|
||||
{
|
||||
if (m_hasFocus && m_listBoxVisible)
|
||||
{
|
||||
return m_textEdit.getWidgetRect().united(m_listBoxPopupRectangle);
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::initializeTextEdit(PDFTextEditPseudowidget* textEdit) const
|
||||
{
|
||||
const PDFFormFieldChoice* parentField = dynamic_cast<const PDFFormFieldChoice*>(m_formWidget.getParent());
|
||||
Q_ASSERT(parentField);
|
||||
|
||||
PDFDocumentDataLoaderDecorator loader(m_formManager->getDocument());
|
||||
|
||||
QByteArray defaultAppearance = m_formManager->getForm()->getDefaultAppearance().value_or(QByteArray());
|
||||
Qt::Alignment alignment = m_formManager->getForm()->getDefaultAlignment();
|
||||
|
||||
// Initialize text edit
|
||||
textEdit->setAppearance(PDFAnnotationDefaultAppearance::parse(defaultAppearance), alignment, m_formManager->getWidgetRectangle(m_formWidget), 0);
|
||||
textEdit->setText(loader.readTextString(parentField->getValue(), QString()));
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::initializeListBox(PDFListBoxPseudowidget* listBox) const
|
||||
{
|
||||
const PDFFormFieldChoice* parentField = dynamic_cast<const PDFFormFieldChoice*>(m_formWidget.getParent());
|
||||
Q_ASSERT(parentField);
|
||||
|
||||
// Initialize popup list box
|
||||
listBox->setAppearance(PDFAnnotationDefaultAppearance::parse(m_formManager->getForm()->getDefaultAppearance().value_or(QByteArray())),
|
||||
m_formManager->getForm()->getDefaultAlignment(),
|
||||
m_listBoxPopupRectangle,
|
||||
parentField->getOptions(),
|
||||
0,
|
||||
{ });
|
||||
}
|
||||
|
||||
void PDFFormFieldComboBoxEditor::setFocusImpl(bool focused)
|
||||
{
|
||||
if (focused)
|
||||
{
|
||||
m_textEdit.setCursorPosition(m_textEdit.getPositionEnd(), false);
|
||||
m_textEdit.performSelectAll();
|
||||
}
|
||||
else if (!m_formManager->isCommitDisabled())
|
||||
{
|
||||
// If text has been changed, then commit it
|
||||
PDFObject object = PDFObjectFactory::createTextString(m_textEdit.getText());
|
||||
|
||||
if (object != m_formWidget.getParent()->getValue())
|
||||
{
|
||||
PDFFormField::SetValueParameters parameters;
|
||||
parameters.formManager = m_formManager;
|
||||
parameters.invokingWidget = m_formWidget.getWidget();
|
||||
parameters.invokingFormField = m_formWidget.getParent();
|
||||
parameters.scope = PDFFormField::SetValueParameters::Scope::User;
|
||||
parameters.value = qMove(object);
|
||||
m_formManager->setFormFieldValue(parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PDFFormField::FieldFlags PDFFormFieldComboBoxEditor::getTextEditFlags(PDFFormField::FieldFlags flags)
|
||||
{
|
||||
if (flags.testFlag(PDFFormField::ReadOnly) || !flags.testFlag(PDFFormField::Edit))
|
||||
{
|
||||
return PDFFormField::ReadOnly;
|
||||
}
|
||||
|
||||
return PDFFormField::None;
|
||||
}
|
||||
|
||||
void PDFFormFieldTextBoxEditor::initializeTextEdit(PDFTextEditPseudowidget* textEdit) const
|
||||
{
|
||||
const PDFFormFieldText* parentField = dynamic_cast<const PDFFormFieldText*>(m_formWidget.getParent());
|
||||
|
@ -2652,6 +2965,15 @@ void PDFTextEditPseudowidget::draw(AnnotationDrawParameters& parameters, bool ed
|
|||
};
|
||||
|
||||
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));
|
||||
|
@ -3121,7 +3443,11 @@ QMatrix PDFListBoxPseudowidget::createListBoxTransformMatrix() const
|
|||
void PDFListBoxPseudowidget::draw(AnnotationDrawParameters& parameters, bool edit) const
|
||||
{
|
||||
pdf::PDFPainterStateGuard guard(parameters.painter);
|
||||
parameters.boundingRectangle = parameters.annotation->getRectangle();
|
||||
|
||||
if (!parameters.boundingRectangle.isValid())
|
||||
{
|
||||
parameters.boundingRectangle = parameters.annotation->getRectangle();
|
||||
}
|
||||
|
||||
QPalette palette = QApplication::palette();
|
||||
|
||||
|
@ -3138,6 +3464,15 @@ void PDFListBoxPseudowidget::draw(AnnotationDrawParameters& parameters, bool edi
|
|||
QMatrix matrix = createListBoxTransformMatrix();
|
||||
|
||||
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(matrix, true);
|
||||
painter->setPen(getAdjustedColor(m_textColor));
|
||||
|
@ -3164,7 +3499,7 @@ void PDFListBoxPseudowidget::draw(AnnotationDrawParameters& parameters, bool edi
|
|||
|
||||
if (edit && m_currentIndex == i)
|
||||
{
|
||||
pdf::PDFPainterStateGuard guard(parameters.painter);
|
||||
pdf::PDFPainterStateGuard guard(painter);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->setPen(Qt::DotLine);
|
||||
painter->drawRect(rect);
|
||||
|
|
|
@ -475,6 +475,7 @@ public:
|
|||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event, const QPointF& mousePagePosition);
|
||||
virtual void reloadValue() { }
|
||||
virtual bool isEditorDrawEnabled() const { return false; }
|
||||
virtual QRectF getActiveEditorRectangle() const { return QRectF(); }
|
||||
|
||||
const PDFFormWidget* getFormWidget() const { return &m_formWidget; }
|
||||
PDFFormField* getFormField() const { return m_formWidget.getParent(); }
|
||||
|
|
|
@ -798,9 +798,12 @@ PDFAttachmentsTreeItem::PDFAttachmentsTreeItem(PDFAttachmentsTreeItem* parent, Q
|
|||
m_icon(qMove(icon)),
|
||||
m_title(qMove(title)),
|
||||
m_description(qMove(description)),
|
||||
m_fileSpecification(std::make_unique<PDFFileSpecification>(*fileSpecification))
|
||||
m_fileSpecification(nullptr)
|
||||
{
|
||||
|
||||
if (fileSpecification)
|
||||
{
|
||||
m_fileSpecification = std::make_unique<PDFFileSpecification>(*fileSpecification);
|
||||
}
|
||||
}
|
||||
|
||||
PDFAttachmentsTreeItem::~PDFAttachmentsTreeItem()
|
||||
|
|
Loading…
Reference in New Issue