From 68d84af411fb438b46454a9729290225545259b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Wed, 18 Sep 2024 17:38:54 +0200 Subject: [PATCH] Allow expanding the child properties for any GroupProperty Also when it isn't displayed as a header. Also introduced a "level" member of VariantEditor which is passed on to the PropertyLabel, which is used to indent expanded child properties. --- src/tiled/propertieswidget.cpp | 14 ++--- src/tiled/propertyeditorwidgets.cpp | 65 +++++++++++++++++------ src/tiled/propertyeditorwidgets.h | 41 ++++++++------- src/tiled/varianteditor.cpp | 82 +++++++++++++---------------- src/tiled/varianteditor.h | 7 ++- 5 files changed, 120 insertions(+), 89 deletions(-) diff --git a/src/tiled/propertieswidget.cpp b/src/tiled/propertieswidget.cpp index ef004baf99..cbf5661643 100644 --- a/src/tiled/propertieswidget.cpp +++ b/src/tiled/propertieswidget.cpp @@ -1275,7 +1275,7 @@ class TilesetProperties : public ObjectProperties push(new ChangeTilesetTransformationFlags(tilesetDocument(), value)); }); - // todo: sub-properties are not displayed yet and image file name doesn't update in the TilesetParametersEdit + // todo: image file name doesn't update in the TilesetParametersEdit mTilesetImageProperty = new TilesetImageProperty(document, this); mImageProperty = new UrlProperty( @@ -1302,6 +1302,12 @@ class TilesetProperties : public ObjectProperties mMarginProperty->setSuffix(tr(" px")); mTileSpacingProperty->setSuffix(tr(" px")); + mImageProperty->setEnabled(false); + mTransparentColorProperty->setEnabled(false); + mTileSizeProperty->setEnabled(false); + mMarginProperty->setEnabled(false); + mTileSpacingProperty->setEnabled(false); + mTilesetImageProperty->addProperty(mImageProperty); mTilesetImageProperty->addProperty(mTransparentColorProperty); mTilesetImageProperty->addProperty(mTileSizeProperty); @@ -1379,12 +1385,6 @@ class TilesetProperties : public ObjectProperties void updateEnabledState() { const bool collection = tileset()->isCollection(); - mTilesetImageProperty->setEnabled(!collection); - mImageProperty->setEnabled(!collection); - mTransparentColorProperty->setEnabled(!collection); - mTileSizeProperty->setEnabled(!collection); - mMarginProperty->setEnabled(!collection); - mTileSpacingProperty->setEnabled(!collection); mColumnCountProperty->setEnabled(collection); } diff --git a/src/tiled/propertyeditorwidgets.cpp b/src/tiled/propertyeditorwidgets.cpp index 0d6af44cc2..24d2437486 100644 --- a/src/tiled/propertyeditorwidgets.cpp +++ b/src/tiled/propertyeditorwidgets.cpp @@ -491,38 +491,73 @@ void ElidingLabel::paintEvent(QPaintEvent *) } -HeaderWidget::HeaderWidget(const QString &text, QWidget *parent) - : ElidingLabel(text, parent) +PropertyLabel::PropertyLabel(int level, QWidget *parent) + : ElidingLabel(parent) { - setBackgroundRole(QPalette::Dark); - setForegroundRole(QPalette::BrightText); - setAutoFillBackground(true); + setMinimumWidth(Utils::dpiScaled(50)); + setLevel(level); +} + +void PropertyLabel::setLevel(int level) +{ + m_level = level; - const int spacing = Utils::dpiScaled(4); + const int spacing = Utils::dpiScaled(3); const int branchIndicatorWidth = Utils::dpiScaled(14); - setContentsMargins(spacing + branchIndicatorWidth, + setContentsMargins(spacing + branchIndicatorWidth * std::max(m_level, 1), spacing, spacing, spacing); } -void HeaderWidget::mousePressEvent(QMouseEvent *event) +void PropertyLabel::setHeader(bool header) +{ + if (m_header == header) + return; + + m_header = header; + setBackgroundRole(header ? QPalette::Dark : QPalette::NoRole); + setForegroundRole(header ? QPalette::BrightText : QPalette::NoRole); + setAutoFillBackground(header); +} + +void PropertyLabel::setExpandable(bool expandable) +{ + if (m_expandable == expandable) + return; + + m_expandable = expandable; + update(); +} + +void PropertyLabel::setExpanded(bool expanded) +{ + if (m_expanded == expanded) + return; + + m_expanded = expanded; + update(); + emit toggled(m_expanded); +} + +void PropertyLabel::mousePressEvent(QMouseEvent *event) { - if (event->button() == Qt::LeftButton) { - m_checked = !m_checked; - emit toggled(m_checked); + if (m_expandable && event->button() == Qt::LeftButton) { + setExpanded(!m_expanded); + return; } ElidingLabel::mousePressEvent(event); } -void HeaderWidget::paintEvent(QPaintEvent *event) +void PropertyLabel::paintEvent(QPaintEvent *event) { ElidingLabel::paintEvent(event); QStyleOption branchOption; branchOption.initFrom(this); branchOption.rect = QRect(0, 0, contentsMargins().left(), height()); - branchOption.state = QStyle::State_Children; - if (m_checked) + if (m_expandable) + branchOption.state |= QStyle::State_Children; + if (m_expanded) branchOption.state |= QStyle::State_Open; QStylePainter p(this); @@ -530,7 +565,7 @@ void HeaderWidget::paintEvent(QPaintEvent *event) } -QSize LineEditLabel::sizeHint() const +QSize PropertyLabel::sizeHint() const { auto hint = ElidingLabel::sizeHint(); hint.setHeight(m_lineEdit.sizeHint().height()); diff --git a/src/tiled/propertyeditorwidgets.h b/src/tiled/propertyeditorwidgets.h index 493a95a02c..e5355c0f9e 100644 --- a/src/tiled/propertyeditorwidgets.h +++ b/src/tiled/propertyeditorwidgets.h @@ -274,40 +274,41 @@ class ElidingLabel : public QLabel }; /** - * A header widget that can be toggled. + * A property label widget, which can be a header or just be expandable. */ -class HeaderWidget : public ElidingLabel +class PropertyLabel : public ElidingLabel { Q_OBJECT public: - HeaderWidget(const QString &text, QWidget *parent = nullptr); + PropertyLabel(int level, QWidget *parent = nullptr); -signals: - void toggled(bool checked); + void setLevel(int level); -protected: - void mousePressEvent(QMouseEvent *event) override; - void paintEvent(QPaintEvent *) override; + void setHeader(bool header); + bool isHeader() const { return m_header; } -private: - bool m_checked = true; -}; - -/** - * A label that matches its preferred height with that of a line edit. - */ -class LineEditLabel : public ElidingLabel -{ - Q_OBJECT + void setExpandable(bool expandable); + bool isExpandable() const { return m_expandable; } -public: - using ElidingLabel::ElidingLabel; + void setExpanded(bool expanded); + bool isExpanded() const { return m_expanded; } QSize sizeHint() const override; +signals: + void toggled(bool expanded); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void paintEvent(QPaintEvent *) override; + private: QLineEdit m_lineEdit; + int m_level = 0; + bool m_header = false; + bool m_expandable = false; + bool m_expanded = false; }; } // namespace Tiled diff --git a/src/tiled/varianteditor.cpp b/src/tiled/varianteditor.cpp index d4225fc4e7..aed7f6f81c 100644 --- a/src/tiled/varianteditor.cpp +++ b/src/tiled/varianteditor.cpp @@ -502,31 +502,30 @@ void VariantEditor::addSeparator() void VariantEditor::addProperty(Property *property) { - const int spacing = m_layout->spacing(); - const int branchIndicatorWidth = Utils::dpiScaled(14); + const auto displayMode = property->displayMode(); - switch (property->displayMode()) { - case Property::DisplayMode::Default: - case Property::DisplayMode::NoLabel: { + if (displayMode == Property::DisplayMode::Separator) { + addSeparator(); + return; + } + + auto label = new PropertyLabel(m_level, this); + + if (displayMode != Property::DisplayMode::NoLabel) { + label->setText(property->name()); + label->setToolTip(property->toolTip()); + label->setEnabled(property->isEnabled()); + connect(property, &Property::toolTipChanged, label, &QWidget::setToolTip); + connect(property, &Property::enabledChanged, label, &QWidget::setEnabled); + } + + if (displayMode == Property::DisplayMode::Header) { + label->setHeader(true); + m_layout->addWidget(label); + } else { auto propertyLayout = new QHBoxLayout; - propertyLayout->setContentsMargins(0, 0, spacing, 0); - - // Property label indentation, which shrinks when there is very little space - propertyLayout->addSpacerItem(new QSpacerItem(spacing + branchIndicatorWidth, 0, - QSizePolicy::Maximum)); - propertyLayout->setStretch(0, 1); - - if (property->displayMode() == Property::DisplayMode::Default) { - auto label = new LineEditLabel(property->name(), this); - label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - label->setToolTip(property->toolTip()); - label->setEnabled(property->isEnabled()); - connect(property, &Property::toolTipChanged, label, &QWidget::setToolTip); - connect(property, &Property::enabledChanged, label, &QWidget::setEnabled); - propertyLayout->addWidget(label, LabelStretch, Qt::AlignTop); - } else { - propertyLayout->addStretch(LabelStretch); - } + propertyLayout->setContentsMargins(0, 0, m_layout->spacing(), 0); + propertyLayout->addWidget(label, LabelStretch, Qt::AlignTop); if (auto editor = createEditor(property)) { editor->setToolTip(property->toolTip()); @@ -537,34 +536,26 @@ void VariantEditor::addProperty(Property *property) } m_layout->addLayout(propertyLayout); - - break; } - case Property::DisplayMode::Header: { - auto headerWidget = new HeaderWidget(property->name(), this); - m_layout->addWidget(headerWidget); - if (auto groupProperty = dynamic_cast(property)) { - auto editor = new VariantEditor(this); - for (auto property : groupProperty->subProperties()) - editor->addProperty(property); + if (auto groupProperty = dynamic_cast(property)) { + label->setExpandable(true); + label->setExpanded(label->isHeader()); - connect(headerWidget, &HeaderWidget::toggled, - editor, [this, editor](bool checked) { - editor->setVisible(checked); + auto editor = new VariantEditor(this); + editor->setLevel(m_level + 1); + editor->setVisible(label->isExpanded()); + for (auto property : groupProperty->subProperties()) + editor->addProperty(property); - // needed to avoid flickering when hiding the editor - layout()->activate(); - }); + connect(label, &PropertyLabel::toggled, editor, [=](bool expanded) { + editor->setVisible(expanded); - m_layout->addWidget(editor); - } + // needed to avoid flickering when hiding the editor + layout()->activate(); + }); - break; - } - case Property::DisplayMode::Separator: - addSeparator(); - break; + m_layout->addWidget(editor); } } @@ -600,6 +591,7 @@ void VariantEditor::addValue(const QVariant &value) QWidget *VariantEditor::createEditor(Property *property) { if (const auto editor = property->createEditor(this)) { + editor->setMinimumWidth(Utils::dpiScaled(70)); editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); return editor; } else { diff --git a/src/tiled/varianteditor.h b/src/tiled/varianteditor.h index 90ebab10c8..43b0235b3f 100644 --- a/src/tiled/varianteditor.h +++ b/src/tiled/varianteditor.h @@ -32,7 +32,7 @@ class QVBoxLayout; namespace Tiled { -class HeaderWidget; +class PropertyLabel; /** * A property represents a named value that can create its own edit widget. @@ -133,7 +133,7 @@ class PropertyTemplate : public Property {} Type value() const { return m_get(); } - void setValue(const Type &value) { m_set(value); } + void setValue(const Type &value) { if (m_set) m_set(value); } private: std::function m_get; @@ -409,6 +409,8 @@ class VariantEditor : public QWidget void addProperty(Property *property); // void addValue(const QVariant &value); + void setLevel(int level) { m_level = level; } + private: QWidget *createEditor(Property *property); @@ -418,6 +420,7 @@ class VariantEditor : public QWidget }; QVBoxLayout *m_layout; + int m_level = 0; }; } // namespace Tiled