From e8fa74e4c40cf6b2c18e89f38e61eaa35ffc256e Mon Sep 17 00:00:00 2001 From: Alfredo Monclus Date: Tue, 3 Jun 2025 13:05:30 -0600 Subject: [PATCH] Gui: Property editor use a checkbox instead of a combobox for booleans (#21555) * Gui: property-editor add property copy context menu * Gui: Property editor checkbox brighter border * Gui: Property editor refactor optimize * Gui: Property editor checkbox react to first click and add label * Gui: Property editor remove auto-inserted include * Gui: property-checkbox fix not painting the grid --- src/Gui/propertyeditor/PropertyItem.cpp | 22 +++---- .../propertyeditor/PropertyItemDelegate.cpp | 58 ++++++++++++++++++- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index 7ebe9db4bd..981bea9857 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1376,26 +1377,25 @@ void PropertyBoolItem::setValue(const QVariant& value) QWidget* PropertyBoolItem::createEditor(QWidget* parent, const std::function& method, - FrameOption frameOption) const + FrameOption /*frameOption*/) const { - auto cb = new QComboBox(parent); - cb->setFrame(static_cast(frameOption)); - cb->addItem(QLatin1String("false")); - cb->addItem(QLatin1String("true")); - QObject::connect(cb, qOverload(&QComboBox::activated), method); - return cb; + auto checkbox = new QCheckBox(parent); + return checkbox; } void PropertyBoolItem::setEditorData(QWidget* editor, const QVariant& data) const { - auto cb = qobject_cast(editor); - cb->setCurrentIndex(cb->findText(data.toString())); + if (auto checkbox = qobject_cast(editor)) { + checkbox->setChecked(data.toBool()); + } } QVariant PropertyBoolItem::editorData(QWidget* editor) const { - auto cb = qobject_cast(editor); - return {cb->currentText()}; + if (auto checkbox = qobject_cast(editor)) { + return checkbox->isChecked(); + } + return false; } // --------------------------------------------------------------- diff --git a/src/Gui/propertyeditor/PropertyItemDelegate.cpp b/src/Gui/propertyeditor/PropertyItemDelegate.cpp index 0f74bc6ad7..5d7261b88a 100644 --- a/src/Gui/propertyeditor/PropertyItemDelegate.cpp +++ b/src/Gui/propertyeditor/PropertyItemDelegate.cpp @@ -25,9 +25,11 @@ #ifndef _PreComp_ # include +# include # include # include # include +# include #endif #include @@ -103,7 +105,44 @@ void PropertyItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QPen savedPen = painter->pen(); - QItemDelegate::paint(painter, option, index); + if (index.column() == 1 && property && dynamic_cast(property)) { + bool checked = index.data(Qt::EditRole).toBool(); + QStyleOptionButton checkboxOption; + if (property->isReadOnly()) { + checkboxOption.state |= QStyle::State_ReadOnly; + } else { + checkboxOption.state |= QStyle::State_Enabled; + } + checkboxOption.state |= checked ? QStyle::State_On : QStyle::State_Off; + // Draw the checkbox + checkboxOption.rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkboxOption); + int leftSpacing = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr); + QRect checkboxRect = QStyle::alignedRect( + option.direction, Qt::AlignVCenter, + checkboxOption.rect.size(), + option.rect.adjusted(leftSpacing, 0, -leftSpacing, 0) + ); + checkboxOption.rect = checkboxRect; + QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkboxOption, painter); + // Draw a bright border on the checkbox to stand out + QColor borderColor = QApplication::palette().color(QPalette::BrightText); + painter->setPen(borderColor); + painter->drawRect(checkboxOption.rect.adjusted(0, 0, -1, -1)); + // Draw the label of the checkbox + QString labelText = checked ? tr("Yes") : tr("No"); + int spacing = QApplication::style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, nullptr); + QRect textRect( + checkboxOption.rect.right() + spacing, + checkboxOption.rect.top(), + option.rect.right() - (checkboxOption.rect.right() + spacing), + checkboxOption.rect.height() + ); + painter->setPen(option.palette.color(QPalette::Text)); + painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, labelText); + } + else { + QItemDelegate::paint(painter, option, index); + } QColor color = static_cast(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt, qobject_cast(parent()))); painter->setPen(QPen(color)); @@ -136,6 +175,17 @@ bool PropertyItemDelegate::eventFilter(QObject *o, QEvent *ev) comboBox->showPopup(); } } + auto *checkBox = qobject_cast(o); + if (checkBox) { + auto parentEditor = qobject_cast(this->parent()); + if (parentEditor && parentEditor->activeEditor == checkBox) { + checkBox->toggle(); + // Delay valueChanged to ensure proper recomputation + QTimer::singleShot(0, this, [this]() { + valueChanged(); + }); + } + } } else if (ev->type() == QEvent::FocusOut) { auto parentEditor = qobject_cast(this->parent()); @@ -233,9 +283,11 @@ void PropertyItemDelegate::valueChanged() if (propertyEditor) { Base::FlagToggler<> flag(changed); Q_EMIT commitData(propertyEditor); - auto *comboBox = qobject_cast(propertyEditor); - if (comboBox) { + if (qobject_cast(propertyEditor) + || qobject_cast(propertyEditor)) + { Q_EMIT closeEditor(propertyEditor); + return; } } }