Guest User

propertyeditordialog.cpp

a guest
Apr 1st, 2020
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include "propertyeditordialog.h"
  2. #include "./ui_propertyeditordialog.h"
  3.  
  4. #include "colorpicker.h"
  5.  
  6. #include <QWindow>
  7. #include <QMetaProperty>
  8. #include <QSpinBox>
  9. #include <QDoubleSpinBox>
  10. #include <QCheckBox>
  11. #include <QColorDialog>
  12. #include <QLineEdit>
  13. #include <QSize>
  14. #include <QTextStream>
  15. #include <QLocale>
  16. #include <QLineEdit>
  17. #include <QFileDialog>
  18.  
  19. #include <limits>
  20.  
  21. PropertyEditorDialog::PropertyEditorDialog(QObject * object, QWidget * parent)
  22.     : QDialog(parent)
  23.     , ui(new Ui::PropertyEditorDialog)
  24. {
  25.     ui->setupUi(this);
  26.  
  27.     auto t = ui->tableWidget;
  28.     t->setColumnCount(2);
  29.     t->setHorizontalHeaderLabels({"Property name", "Property value"});
  30.     t->resizeColumnToContents(0);
  31.     t->horizontalHeader()->setStretchLastSection(true);
  32.     t->verticalHeader()->setVisible(false);
  33.  
  34.     int propertyOffset = object->metaObject()->propertyOffset();
  35.     int propertyCount = object->metaObject()->propertyCount();
  36.     t->setRowCount(propertyCount - propertyOffset);
  37.     for (int i = propertyOffset; i < propertyCount; ++i) {
  38.         const auto & property = object->metaObject()->property(i);
  39.         Q_ASSERT(property.hasNotifySignal());
  40.         auto propertyName = property.name();
  41.  
  42.         // name
  43.         auto nameItem = new QTableWidgetItem(propertyName);
  44.         nameItem->setFlags(nameItem->flags() & ~Qt::ItemIsEditable);
  45.         t->setItem(i - propertyOffset, 0, nameItem);
  46.  
  47.         // value
  48.         auto value = object->property(property.name());
  49.         switch (int(property.type())) {
  50.         case QMetaType::QString : {
  51.             auto valueItem = new QLineEdit{t};
  52.             valueItem->setText(value.toString());
  53.             t->setCellWidget(i - propertyOffset, 1, valueItem);
  54.             QObject::connect(valueItem, &QLineEdit::textChanged, object, [object, propertyName] (QString value) { object->setProperty(propertyName, value); });
  55.             break;
  56.         }
  57.         case QMetaType::Bool : {
  58.             auto valueItem = new QCheckBox{t};
  59.             valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked);
  60.             t->setCellWidget(i - propertyOffset, 1, valueItem);
  61.             QObject::connect(valueItem, &QCheckBox::stateChanged, object, [object, propertyName] (int state) { object->setProperty(propertyName, (Qt::CheckState(state) == Qt::Checked)); });
  62.             break;
  63.         }
  64.         case QMetaType::Float : {
  65.             auto valueItem = new QDoubleSpinBox{t};
  66.             valueItem->setRange(qreal(std::numeric_limits<float>::min()), qreal(std::numeric_limits<float>::max()));
  67.             valueItem->setStepType(QDoubleSpinBox::AdaptiveDecimalStepType);
  68.             valueItem->setValue(value.toDouble());
  69.             t->setCellWidget(i - propertyOffset, 1, valueItem);
  70.             QObject::connect(valueItem, qOverload<double>(&QDoubleSpinBox::valueChanged), object, [object, propertyName] (double value) { object->setProperty(propertyName, value); });
  71.             break;
  72.         }
  73.         case QMetaType::Int : {
  74.             auto valueItem = new QSpinBox{t};
  75.             valueItem->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
  76.             valueItem->setStepType(QSpinBox::AdaptiveDecimalStepType);
  77.             valueItem->setValue(value.toInt());
  78.             t->setCellWidget(i - propertyOffset, 1, valueItem);
  79.             QObject::connect(valueItem, qOverload<int>(&QSpinBox::valueChanged), object, [object, propertyName] (int value) { object->setProperty(propertyName, value); });
  80.             break;
  81.         }
  82.         case QVariant::Type::Color : {
  83.             auto color = value.value<QColor>();
  84.             auto valueItem = new ColorPicker{color, t};
  85.             t->setCellWidget(i - propertyOffset, 1, valueItem);
  86.             QObject::connect(valueItem, &ColorPicker::colorChanged, object, [object, propertyName] (QColor color) { object->setProperty(propertyName, color); });
  87.             break;
  88.         }
  89.         case QMetaType::QSize : {
  90.             auto valueItem = new QLineEdit{t};
  91.             auto v = new SizeValidator;
  92.             Q_CHECK_PTR(v);
  93.             valueItem->setValidator(v);
  94.             valueItem->setInputMask(QStringLiteral("00009x00009"));
  95.             auto oldSize = value.toSize();
  96.             valueItem->setText(QStringLiteral("%1x%2").arg(oldSize.width()).arg(oldSize.height()));
  97.             t->setCellWidget(i - propertyOffset, 1, valueItem);
  98.             auto onTextChanged = [object, propertyName, valueItem, oldSize]
  99.             {
  100.                 auto size = SizeValidator::toSize(valueItem->text(), oldSize);
  101.                 object->setProperty(propertyName, size);
  102.             };
  103.             QObject::connect(valueItem, &QLineEdit::textChanged, object, onTextChanged);
  104.             break;
  105.         }
  106.         }
  107.     }
  108.  
  109.     auto onDoubleClicked = [t, this] (QModelIndex index)
  110.     {
  111.         if (index.column() != 0) {
  112.             return;
  113.         }
  114.         auto valueIndex = index.siblingAtColumn(1);
  115.         auto cellWidget = t->indexWidget(valueIndex);
  116.         if (!cellWidget) {
  117.             return;
  118.         }
  119.         if (auto colorPicker = qobject_cast<ColorPicker*>(cellWidget)) {
  120.             auto oldColor = colorPicker->color();
  121.             for (int i = 0; i < QColorDialog::customCount(); ++i) {
  122.                 QColorDialog::setCustomColor(i, oldColor);
  123.             }
  124.             auto color = QColorDialog::getColor(oldColor, this, t->model()->data(index, Qt::DisplayRole).toString(), QColorDialog::DontUseNativeDialog);
  125.             if (!color.isValid() || (color == oldColor)) {
  126.                 return;
  127.             }
  128.             colorPicker->setColor(color);
  129.         } else if (auto lineEdit = qobject_cast<QLineEdit*>(cellWidget)) {
  130.             QFileInfo fileInfo{lineEdit->text()};
  131.             auto filePath = QFileDialog::getOpenFileName(nullptr, QStringLiteral("Open filepath"), fileInfo.dir().path(), "All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog);
  132.             if (!filePath.isEmpty()) {
  133.                 lineEdit->setText(filePath);
  134.             }
  135.         }
  136.     };
  137.     QObject::connect(t, &QTableWidget::doubleClicked, this, onDoubleClicked);
  138.  
  139.  
  140.     QObject::connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
  141.     QObject::connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
  142. }
  143.  
  144. PropertyEditorDialog::~PropertyEditorDialog()
  145. {
  146.     delete ui;
  147. }
  148.  
  149. int PropertyEditorDialog::exec(QString title, QWindow * window)
  150. {
  151.     winId();
  152.     windowHandle()->setTransientParent(window);
  153.     setModal(false);
  154.     setWindowTitle(title);
  155.     return exec();
  156. }
  157.  
  158. SizeValidator::SizeValidator()
  159. {
  160.     setLocale(QLocale::c());
  161. }
  162.  
  163. auto SizeValidator::validate(QString & input, int & pos) const -> State
  164. {
  165.     Q_UNUSED(pos)
  166.     QSize size;
  167.     return toSize(input, &size);
  168. }
  169.  
  170. auto SizeValidator::toSize(QString s, QSize * size) -> State
  171. {
  172.     QTextStream ts{&s, QIODevice::ReadOnly};
  173.     int width = -1, height = -1;
  174.     auto x = QChar::fromLatin1('x');
  175.     if ((ts >> width).status() != QTextStream::Ok) {
  176.         return Intermediate;
  177.     }
  178.     ts.skipWhiteSpace();
  179.     if ((ts >> x).status() != QTextStream::Ok) {
  180.         return Intermediate;
  181.     }
  182.     if (x != 'x') {
  183.         return Invalid;
  184.     }
  185.     if ((ts >> height).status() != QTextStream::Ok) {
  186.         return Intermediate;
  187.     }
  188.     if ((width < (1 << 6)) || (height < (1 << 6))) {
  189.         return Intermediate;
  190.     }
  191.     if ((width > (1 << 14)) || (height > (1 << 14))) {
  192.         return Invalid;
  193.     }
  194.     size->setWidth(width);
  195.     size->setHeight(height);
  196.     if (!size->isValid()) {
  197.         return Invalid;
  198.     }
  199.     return Acceptable;
  200. }
  201.  
  202. QSize SizeValidator::toSize(QString s, const QSize oldSize)
  203. {
  204.     QSize size;
  205.     if (toSize(s, &size) != Acceptable) {
  206.         return oldSize;
  207.     }
  208.     return size;
  209. }
Advertisement
Add Comment
Please, Sign In to add comment