diff --git a/libs/piqt_widgets/pivaluetree_edit.cpp b/libs/piqt_widgets/pivaluetree_edit.cpp index d1be70a..9ffe2e1 100644 --- a/libs/piqt_widgets/pivaluetree_edit.cpp +++ b/libs/piqt_widgets/pivaluetree_edit.cpp @@ -1,28 +1,27 @@ #include "pivaluetree_edit.h" #include "piqt.h" +#include "pivaluetree_edit_parameters.h" #include "pivariant_edit.h" #include "qinputdialog.h" #include "qmessagebox.h" #include "qtoolbutton.h" #include "ui_pivaluetree_edit_array.h" -#include "ui_pivaluetree_edit_parameters.h" #include #include #include +using Attribute = PIValueTree::Attribute; + const char property_name[] = "__name__"; PIValueTreeEdit::PIValueTreeEdit(QWidget * parent): QWidget(parent) { - widget_params = new QDialog(); + widget_params = new PIValueTreeEditParameters(); ui_array = new Ui::PIValueTreeEditArray(); - ui_params = new Ui::PIValueTreeEditParameters(); - ui_params->setupUi(widget_params); - grid = new GridWidgets(ui_params); - grid->parent = this; - auto * lay = new QBoxLayout(QBoxLayout::TopToBottom); + grid = new GridWidgets(this); + auto * lay = new QBoxLayout(QBoxLayout::TopToBottom); lay->setContentsMargins(0, 0, 0, 0); setLayout(lay); } @@ -30,7 +29,6 @@ PIValueTreeEdit::PIValueTreeEdit(QWidget * parent): QWidget(parent) { PIValueTreeEdit::~PIValueTreeEdit() { delete grid; - delete ui_params; delete ui_array; delete widget_params; } @@ -84,7 +82,9 @@ void PIValueTreeEdit::removeAll() { value_edits.clear(); tree_edits.clear(); if (widget_array) { - ui_array->layoutArray->takeAt(0); + ui_array->layoutArray->removeWidget(grid); + grid->hide(); + grid->setParent(this); delete widget_array; widget_array = nullptr; } @@ -97,18 +97,17 @@ void PIValueTreeEdit::removeAll() { void PIValueTreeEdit::build() { + grid->create_edit_buttons = false; removeAll(); - // piCout << source.attributes().value(PIValueTree::attributeArrayType) << array_type; + // piCout << source.attributes().value(Attribute::arrayType) << array_type; if (source.isArray()) { - grid->create_edit_buttons = false; - widget_array = new QWidget(); + widget_array = new QWidget(); ui_array->setupUi(widget_array); - ui_array->spinCount->setRange(source.attribute(PIValueTree::attributeArrayMinCount, 0).toInt(), - source.attribute(PIValueTree::attributeArrayMaxCount, 65536).toInt()); - ui_array->spinCount->setValue(source.children().size_s()); - ui_array->widgetEdit->setVisible(source.attribute(PIValueTree::attributeArrayResize, false).toBool()); + applyArrayAttributes(); ui_array->layoutArray->addWidget(grid); - uint array_type = PIVariant::typeIDFromName(source.attribute(PIValueTree::attributeArrayType).toString()); + grid->button_add->hide(); + grid->show(); + uint array_type = PIVariant::typeIDFromName(source.attribute(Attribute::arrayType).toString()); int index = 0; for (const auto & i: source.children()) { auto * ve = new PIVariantEdit(); @@ -117,7 +116,7 @@ void PIValueTreeEdit::build() { grid->add(PIValueTree(), QString::number(++index), ve, PI2QString(i.comment())); array_edits << ve; } - connect(ui_array->spinCount, QOverload::of(&QSpinBox::valueChanged), this, [this, array_type](int value) { + connect(ui_array->spinCount, QOverload::of(&QSpinBox::valueChanged), widget_array, [this, array_type](int value) { value = piMaxi(value, 0); for (int i = grid->rowCount() - 1; i >= value; --i) grid->removeRow(i); @@ -134,9 +133,10 @@ void PIValueTreeEdit::build() { } else { grid->create_edit_buttons = is_full_edit; layout()->addWidget(grid); + if (!source.hasChildren()) grid->clear(); for (const auto & i: source.children()) { - if (i.attribute(PIValueTree::attributeHidden, false).toBool()) continue; - if (i.attribute(PIValueTree::attributeIsLabel, false).toBool()) { + if (i.attribute(Attribute::hidden, false).toBool()) continue; + if (i.attribute(Attribute::isLabel, false).toBool()) { if (i.name().isEmpty()) continue; auto * l = new QLabel(PI2QString(i.name())); l->setAlignment(Qt::AlignCenter); @@ -144,34 +144,9 @@ void PIValueTreeEdit::build() { continue; } if (i.hasChildren() || i.isArray()) { - auto * ve = new PIValueTreeEdit(); - PIStringList rp = root_path; - rp << i.name(); - ve->root_path = rp; - ve->setGroupingEnabled(is_grouping); - ve->setFullEditMode(is_full_edit); - ve->setValue(i); - if (is_grouping) { - auto * gb = new QGroupBox(); - gb->setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); - gb->layout()->addWidget(ve); - gb->setTitle(PI2QString(i.name())); - gb->setToolTip(PI2QString(i.comment())); - gb->setCheckable(true); - gb->setChecked(true); - gb->setAlignment(Qt::AlignCenter); - connect(gb, &QGroupBox::toggled, ve, &QWidget::setVisible); - grid->add(i, gb); - } else { - grid->add(i, PI2QString(i.name()), ve, PI2QString(i.comment())); - } - tree_edits[i.name()] = ve; + addTreeEdit(i); } else { - auto * ve = new PIVariantEdit(); - ve->setAttributes(i.attributes()); - ve->setValue(i.value()); - grid->add(i, PI2QString(i.name()), ve, PI2QString(i.comment())); - value_edits[i.name()] = ve; + addValueEdit(i); } } } @@ -180,7 +155,7 @@ void PIValueTreeEdit::build() { void PIValueTreeEdit::applyValues() const { if (source.isArray()) { - if (array_edits.isNotEmpty()) source.mergeAttributes(array_edits[0]->defaultAttributes()); + if (array_edits.isNotEmpty()) source.mergeAttributes(array_edits[0]->attributes()); source.clearChildren(); for (int i = 0; i < array_edits.size_s(); ++i) source.addChild({PIString::fromNumber(i), array_edits[i]->value()}); @@ -188,7 +163,7 @@ void PIValueTreeEdit::applyValues() const { auto vit = value_edits.makeIterator(); while (vit.next()) { auto & c(source.child(vit.key())); - c.mergeAttributes(vit.value()->defaultAttributes()); + c.mergeAttributes(vit.value()->attributes()); c.setValue(vit.value()->value()); } auto tit = tree_edits.makeIterator(); @@ -201,7 +176,7 @@ void PIValueTreeEdit::applyValues() const { void PIValueTreeEdit::actionTriggered(QToolButton * button, const PIString & vn, QAction * a) { - if (a == ui_params->actionRename) { + if (a == widget_params->actionRename) { PIString nn = Q2PIString(QInputDialog::getText(nullptr, tr("Rename"), tr("Input new name:"), QLineEdit::Normal, PI2QString(vn))); if (nn.isEmpty() || (nn == vn)) return; for (const auto & c: source.children()) { @@ -213,51 +188,140 @@ void PIValueTreeEdit::actionTriggered(QToolButton * button, const PIString & vn, source[vn].setName(nn); button->setProperty(property_name, PI2QString(nn)); grid->rename(PI2QString(vn), PI2QString(nn)); + if (value_edits.contains(vn)) { + value_edits[nn] = value_edits[vn]; + value_edits.remove(vn); + } + if (tree_edits.contains(vn)) { + tree_edits[nn] = tree_edits[vn]; + tree_edits.remove(vn); + } } - if (a == ui_params->actionRemove) { + if (a == widget_params->actionRemove) { source.remove(vn); grid->removeRow(grid->getRow(button)); + value_edits.remove(vn); + tree_edits.remove(vn); } - if (a == ui_params->actionChange) { - if (last_IDs_count != PIVariant::knownTypeIDsCount()) { - last_IDs_count = PIVariant::knownTypeIDsCount(); - ui_params->comboType->clear(); - auto ids = PIVariant::knownTypeIDs(); - PIVector> types; - for (auto id: ids) { - if (!PIVariantEditorBase::editorExists(id)) continue; - PIString tn = PIVariant::typeNameFromID(id); - if (tn.startsWith("PI")) tn.remove(0, 2); - if (tn.startsWith("VariantTypes::")) tn.remove(0, 14); - types.append({id, PI2QString(tn)}); - } - types.sort([](const PIPair & a, const PIPair & b) { - return QString::localeAwareCompare(a.second, b.second) < 0; - }); - for (const auto & t: types) - ui_params->comboType->addItem(t.second, t.first); + if (a == widget_params->actionChange) { + auto & vt(source[vn]); + if (vt.isArray()) { + auto * ve = tree_edits.value(vn, nullptr); + if (!ve) return; + vt = ve->value(); + if (!widget_params->showFor(vt)) return; + ve->setValue(vt); + // ve->applyArrayAttributes(); + } else { + auto * ve = value_edits.value(vn, nullptr); + if (!ve) return; + vt.setValue(ve->value()); + if (!widget_params->showFor(vt)) return; + ve->setAttributes(vt.attributes()); + ve->setValue(vt.value()); } - auto old_vt = source.child(vn); - ui_params->comboType->setCurrentIndex(ui_params->comboType->findData(old_vt.value().typeID())); - ui_params->checkArray->setChecked(old_vt.isArray()); - if (widget_params->exec() != QDialog::Accepted) return; - auto & el(source[vn]); - uint nid = ui_params->comboType->currentData().toUInt(); - PIString vs = el.value().toString(); - PIVariant var = PIVariant::fromType(nid); - var.setValueFromString(vs); - source[vn].setValue(var); - build(); + } +} + + +PIValueTreeEdit * PIValueTreeEdit::addTreeEdit(const PIValueTree & vt) { + auto * ve = new PIValueTreeEdit(); + PIStringList rp = root_path; + rp << vt.name(); + ve->root_path = rp; + ve->setGroupingEnabled(is_grouping); + ve->setFullEditMode(is_full_edit); + ve->setValue(vt); + if (is_grouping) { + auto * gb = new QGroupBox(); + gb->setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); + gb->layout()->addWidget(ve); + gb->setTitle(PI2QString(vt.name())); + gb->setToolTip(PI2QString(vt.comment())); + gb->setCheckable(true); + gb->setChecked(true); + gb->setAlignment(Qt::AlignCenter); + connect(gb, &QGroupBox::toggled, ve, &QWidget::setVisible); + grid->add(vt, gb, true); + } else { + grid->add(vt, PI2QString(vt.name()), ve, PI2QString(vt.comment()), true); + } + tree_edits[vt.name()] = ve; + return ve; +} + + +void PIValueTreeEdit::addValueEdit(const PIValueTree & vt) { + auto * ve = new PIVariantEdit(); + ve->setAttributes(vt.attributes()); + ve->setValue(vt.value()); + grid->add(vt, PI2QString(vt.name()), ve, PI2QString(vt.comment())); + value_edits[vt.name()] = ve; +} + + +void PIValueTreeEdit::applyArrayAttributes() { + ui_array->spinCount->setRange(source.attribute(Attribute::arrayMinCount, 0).toInt(), + source.attribute(Attribute::arrayMaxCount, 65536).toInt()); + ui_array->spinCount->setValue(source.children().size_s()); + ui_array->widgetEdit->setVisible(source.attribute(Attribute::arrayResize, false).toBool()); + uint array_type = PIVariant::typeIDFromName(source.attribute(Attribute::arrayType).toString()); + for (int i = 0; i < array_edits.size_s(); ++i) { + auto * w = array_edits[i]; + w->setAttributes(source.attributes()); + w->setValue(i < source.children().size_s() ? source.children()[i].value() : PIVariant(), array_type); + } +} + + +void PIValueTreeEdit::newRequest(NewType type) { + PIString nn = Q2PIString(QInputDialog::getText(nullptr, tr("New item"), tr("Input new name:"))); + if (nn.isEmpty()) return; + for (const auto & c: source.children()) { + if (c.name() == nn) { + QMessageBox::critical(nullptr, tr("New item"), tr("This name already exists!")); + return; + } + } + PIValueTree vt; + vt.setName(nn); + if (type == NewType::Value) { + if (!widget_params->showFor(vt)) return; + } + if (type == NewType::Array) { + vt.setAttribute(Attribute::arrayType, PIVariant::typeName()); + if (!widget_params->showFor(vt)) return; + } + source.addChild(vt); + switch (type) { + case NewType::Value: addValueEdit(vt); break; + case NewType::Group: addTreeEdit(vt); break; + case NewType::Array: addTreeEdit(vt); break; } } // PIValueTreeEdit::GridWidgets -PIValueTreeEdit::GridWidgets::GridWidgets(Ui::PIValueTreeEditParameters * ui_) { - ui_params = ui_; +PIValueTreeEdit::GridWidgets::GridWidgets(PIValueTreeEdit * p) { + parent = p; icon_conf = QIcon(":/icons/configure.png"); - conf_menu.addActions({ui_params->actionRename, ui_params->actionChange, ui_params->actionRemove}); + menu_group.addActions({p->widget_params->actionRename, p->widget_params->actionRemove}); + menu_conf.addActions({p->widget_params->actionRename, p->widget_params->actionChange, p->widget_params->actionRemove}); + menu_new.addActions({p->widget_params->actionValue, p->widget_params->actionGroup, p->widget_params->actionArray}); + button_add = new QToolButton(); + button_add->setIcon(QIcon(":/icons/list-add.png")); + button_add->setPopupMode(QToolButton::InstantPopup); + button_add->setMenu(&menu_new); + p->widget_params->actionValue->setData((int)NewType::Value); + p->widget_params->actionGroup->setData((int)NewType::Group); + p->widget_params->actionArray->setData((int)NewType::Array); + connect(button_add, &QToolButton::triggered, this, [this](QAction * a) { parent->newRequest((NewType)a->data().toInt()); }); +} + + +PIValueTreeEdit::GridWidgets::~GridWidgets() { + delete button_add; } @@ -266,19 +330,16 @@ int PIValueTreeEdit::GridWidgets::getRow(QWidget * w) const { for (int r = 0; r < lay->rowCount(); ++r) { for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(r, c); - if (li) { - if (li->widget()) { - if (li->widget() == w) return r; - } - } + if (!li) continue; + if (li->widget() && (li->widget() == w)) return r; } } return -1; } -void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QString label, QWidget * w, const QString & comment) { - int col = beginRow(vt); +void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QString label, QWidget * w, const QString & comment, bool is_group) { + int col = beginRow(vt, is_group); if (!label.isEmpty()) label += ':'; auto * l = new QLabel(label); auto * c = new QLabel(comment); @@ -291,24 +352,27 @@ void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QString label, QW widgets << l << w << c; labels << l; ++row_count; + changed(); } -void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QWidget * w) { - int col = beginRow(vt); +void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QWidget * w, bool is_group) { + int col = beginRow(vt, is_group); lay->addWidget(w, row_count, col, 1, -1); widgets << w; ++row_count; + changed(); } -int PIValueTreeEdit::GridWidgets::beginRow(const PIValueTree & vt) { +int PIValueTreeEdit::GridWidgets::beginRow(const PIValueTree & vt, bool is_group) { if (!create_edit_buttons) return 0; auto * b = new QToolButton(); b->setIcon(icon_conf); b->setPopupMode(QToolButton::InstantPopup); - b->setMenu(&conf_menu); + b->setMenu((is_group && !vt.isArray()) ? &menu_group : &menu_conf); b->setProperty(property_name, PI2QString(vt.name())); + b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); lay->addWidget(b, row_count, 0); connect(b, &QToolButton::triggered, this, [this, b](QAction * a) { parent->actionTriggered(b, Q2PIString(b->property(property_name).toString()), a); @@ -319,13 +383,24 @@ int PIValueTreeEdit::GridWidgets::beginRow(const PIValueTree & vt) { void PIValueTreeEdit::GridWidgets::rename(QString prev_name, QString new_name) { - if (!prev_name.isEmpty()) prev_name += ':'; - if (!new_name.isEmpty()) new_name += ':'; - for (auto * l: labels) - if (l->text() == prev_name) { - l->setText(new_name); - break; + if (parent->is_grouping) { + for (auto * w: widgets) { + auto * gb = qobject_cast(w); + if (!gb) continue; + if (gb->title() == prev_name) { + gb->setTitle(new_name); + break; + } } + } else { + if (!prev_name.isEmpty()) prev_name += ':'; + if (!new_name.isEmpty()) new_name += ':'; + for (auto * l: labels) + if (l->text() == prev_name) { + l->setText(new_name); + break; + } + } } @@ -337,25 +412,35 @@ void PIValueTreeEdit::GridWidgets::clear() { lay->setContentsMargins(0, 0, 0, 0); setLayout(lay); row_count = 0; + changed(); +} + + +void PIValueTreeEdit::GridWidgets::changed() { + if (!create_edit_buttons || !lay) return; + lay->addWidget(button_add, row_count, 0); + button_add->show(); } void PIValueTreeEdit::GridWidgets::removeRow(int index) { - if (!lay || index < 0 || row_count <= index) return; + if (!lay) return; + if ((index < 0) || (index >= row_count) || (index >= lay->rowCount())) return; for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(index, c); if (li) { - if (li->widget()) { - widgets.removeOne(li->widget()); - QLabel * lbl = qobject_cast(li->widget()); + QWidget * w = li->widget(); + if (w) { + widgets.removeOne(w); + QLabel * lbl = qobject_cast(w); if (lbl) labels.removeOne(lbl); - delete li->widget(); + delete w; } - delete li; } } --row_count; simplify(); + changed(); } diff --git a/libs/piqt_widgets/pivaluetree_edit.h b/libs/piqt_widgets/pivaluetree_edit.h index ec38c57..5b81bdd 100644 --- a/libs/piqt_widgets/pivaluetree_edit.h +++ b/libs/piqt_widgets/pivaluetree_edit.h @@ -22,19 +22,19 @@ #include "pivaluetree.h" #include "qad_piqt_utils_export.h" -#include "qicon.h" -#include "qmenu.h" +#include #include +#include #include class QGridLayout; class QToolButton; class PIVariantEdit; +class PIValueTreeEditParameters; namespace Ui { class PIValueTreeEditArray; -class PIValueTreeEditParameters; -} // namespace Ui +} class QAD_PIQT_UTILS_EXPORT PIValueTreeEdit: public QWidget { Q_OBJECT @@ -59,51 +59,61 @@ public: void clear(); private: + enum class NewType { + Value, + Group, + Array + }; + void changeEvent(QEvent * e) override; void removeAll(); void build(); void applyValues() const; void actionTriggered(QToolButton * button, const PIString & vn, QAction * a); + void newRequest(NewType type); + PIValueTreeEdit * addTreeEdit(const PIValueTree & vt); + void addValueEdit(const PIValueTree & vt); + void applyArrayAttributes(); class GridWidgets: public QWidget { public: - GridWidgets(Ui::PIValueTreeEditParameters * ui_); + GridWidgets(PIValueTreeEdit * p); + ~GridWidgets(); int rowCount() const { return row_count; } int getRow(QWidget * w) const; void removeRow(int index); - void add(const PIValueTree & vt, QString label, QWidget * w, const QString & comment); - void add(const PIValueTree & vt, QWidget * w); - int beginRow(const PIValueTree & vt); + void add(const PIValueTree & vt, QString label, QWidget * w, const QString & comment, bool is_group = false); + void add(const PIValueTree & vt, QWidget * w, bool is_group = false); + int beginRow(const PIValueTree & vt, bool is_group); void rename(QString prev_name, QString new_name); void clear(); + void changed(); bool create_edit_buttons = false; - PIValueTreeEdit * parent; + QToolButton * button_add; private: void simplify(); int row_count = 0; QGridLayout * lay = nullptr; - QMenu conf_menu; + PIValueTreeEdit * parent; + QMenu menu_group, menu_conf, menu_new; QWidgetList widgets; QList labels; QIcon icon_conf; - Ui::PIValueTreeEditParameters * ui_params; }; QWidget * widget_array = nullptr; - QDialog * widget_params; + PIValueTreeEditParameters * widget_params; PIStringList root_path; PIVector array_edits; PIMap value_edits; PIMap tree_edits; Ui::PIValueTreeEditArray * ui_array; - Ui::PIValueTreeEditParameters * ui_params; GridWidgets * grid = nullptr; mutable PIValueTree source; - int last_IDs_count = -1; bool is_grouping = true, is_full_edit = false; }; diff --git a/libs/piqt_widgets/pivaluetree_edit_parameters.cpp b/libs/piqt_widgets/pivaluetree_edit_parameters.cpp new file mode 100644 index 0000000..ab354d9 --- /dev/null +++ b/libs/piqt_widgets/pivaluetree_edit_parameters.cpp @@ -0,0 +1,142 @@ +#include "pivaluetree_edit_parameters.h" + +#include "piqt.h" +#include "pivariant_edit.h" + +#include +#include + +using Attribute = PIValueTree::Attribute; + +const char property_name[] = "__name__"; + + +PIValueTreeEditParameters::PIValueTreeEditParameters(QWidget * parent): QDialog(parent) { + setupUi(this); +} + + +PIValueTreeEditParameters::~PIValueTreeEditParameters() {} + + +bool PIValueTreeEditParameters::showFor(PIValueTree & vt) { + setWindowTitle(tr("Change of \"%1\"").arg(PI2QString(vt.name()))); + ve_attr.clear(); + ve_array.clear(); + while (layoutAttributes->rowCount() > 0) + layoutAttributes->removeRow(0); + while (layoutArray->rowCount() > 0) + layoutArray->removeRow(0); + + if (last_IDs_count != PIVariant::knownTypeIDsCount()) { + last_IDs_count = PIVariant::knownTypeIDsCount(); + comboType->clear(); + auto ids = PIVariant::knownTypeIDs(); + PIVector> types; + for (auto id: ids) { + if (!PIVariantEditorBase::editorExists(id)) continue; + PIString tn = PIVariant::typeNameFromID(id); + if (tn.startsWith("PI")) tn.remove(0, 2); + if (tn.startsWith("VariantTypes::")) tn.remove(0, 14); + types.append({id, PI2QString(tn)}); + } + types.sort([](const PIPair & a, const PIPair & b) { + return QString::localeAwareCompare(a.second, b.second) < 0; + }); + for (const auto & t: types) + comboType->addItem(t.second, t.first); + } + + comboType->blockSignals(true); + if (vt.isArray()) { + uint array_type = PIVariant::typeIDFromName(vt.attribute(Attribute::arrayType).toString()); + comboType->setCurrentIndex(comboType->findData(array_type)); + checkAttribute(vt, Attribute::arrayMinCount, 0); + checkAttribute(vt, Attribute::arrayMaxCount, 65536); + checkAttribute(vt, Attribute::arrayReorder, true); + checkAttribute(vt, Attribute::arrayResize, true); + createAttributes(ve_array, layoutArray, vt.attributes(), true); + groupArray->show(); + } else { + comboType->setCurrentIndex(comboType->findData(vt.value().typeID())); + groupArray->hide(); + } + comboType->blockSignals(false); + checkHidden->setChecked(vt.attribute(Attribute::hidden, false).toBool()); + checkReadOnly->setChecked(vt.attribute(Attribute::readOnly, false).toBool()); + checkLabel->setChecked(vt.attribute(Attribute::isLabel, false).toBool()); + createAttributes(ve_attr, layoutAttributes, vt.attributes()); + + if (exec() != QDialog::Accepted) return false; + + if (!vt.isArray()) { + PIString vs = vt.value().toString(); + PIVariant var = PIVariant::fromType(comboType->currentData().toUInt()); + var.setValueFromString(vs); + vt.setValue(var); + } + applyAttributes(vt); + + return true; +} + + +void PIValueTreeEditParameters::createAttributes(QList & list, + QFormLayout * lay, + const PIVariantMap & attr, + bool inv_filter) { + static PIStringList hidden({"type", Attribute::hidden, Attribute::readOnly, Attribute::isLabel, Attribute::arrayType}); + static PIStringList filter({Attribute::arrayMinCount, Attribute::arrayMaxCount, Attribute::arrayReorder, Attribute::arrayResize}); + list.clear(); + while (lay->rowCount() > 0) + lay->removeRow(0); + PIVariantMap dal; + if (!inv_filter) dal = PIVariantEditorBase::editorDefaultAttributes(comboType->currentData().toUInt()); + auto vit = attr.makeIterator(); + while (vit.next()) { + if (hidden.contains(vit.key())) continue; + bool cf = filter.contains(vit.key()); + if (cf && !inv_filter) continue; + if (!cf && inv_filter) continue; + dal[vit.key()] = vit.value(); + } + auto dit = dal.makeIterator(); + while (dit.next()) { + auto * ve = new PIVariantEdit(); + ve->setValue(dit.value()); + ve->setProperty(property_name, PI2QString(dit.key())); + list << ve; + lay->addRow(PI2QString(dit.key() + ":"), ve); + } +} + + +void PIValueTreeEditParameters::applyAttributes(PIValueTree & vt) { + bool is_array = vt.isArray(); + vt.attributes().clear(); + for (auto * w: ve_attr) { + PIString an = Q2PIString(w->property(property_name).toString()); + vt.setAttribute(an, w->value()); + } + if (is_array) { + vt.setAttribute(Attribute::arrayType, PIVariant::typeNameFromID(comboType->currentData().toUInt())); + for (auto * w: ve_array) { + PIString an = Q2PIString(w->property(property_name).toString()); + vt.setAttribute(an, w->value()); + } + } + vt.setAttribute(Attribute::hidden, checkHidden->isChecked()); + vt.setAttribute(Attribute::readOnly, checkReadOnly->isChecked()); + vt.setAttribute(Attribute::isLabel, checkLabel->isChecked()); +} + + +void PIValueTreeEditParameters::checkAttribute(PIValueTree & vt, PIString an, PIVariant def) { + if (vt.attributes().contains(an)) def.setValueFromString(vt.attributes().value(an).toString()); + vt.setAttribute(an, def); +} + + +void PIValueTreeEditParameters::on_comboType_currentIndexChanged(int) { + createAttributes(ve_attr, layoutAttributes); +} diff --git a/libs/piqt_widgets/pivaluetree_edit_parameters.h b/libs/piqt_widgets/pivaluetree_edit_parameters.h new file mode 100644 index 0000000..b119b9b --- /dev/null +++ b/libs/piqt_widgets/pivaluetree_edit_parameters.h @@ -0,0 +1,57 @@ +/* + PIQt Utils - Qt utilites for PIP + + Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef pivaluetree_edit_parameters_H +#define pivaluetree_edit_parameters_H + +#include "pivaluetree.h" +#include "qformlayout.h" +#include "ui_pivaluetree_edit_parameters.h" + +#include +#include + +class PIVariantEdit; + +class PIValueTreeEditParameters + : public QDialog + , public Ui::PIValueTreeEditParameters { + Q_OBJECT + +public: + PIValueTreeEditParameters(QWidget * parent = nullptr); + ~PIValueTreeEditParameters(); + + bool showFor(PIValueTree & vt); + +private: + void + createAttributes(QList & list, QFormLayout * lay, const PIVariantMap & attr = PIVariantMap(), bool inv_filter = false); + void applyAttributes(PIValueTree & vt); + void checkAttribute(PIValueTree & vt, PIString an, PIVariant def); + + int last_IDs_count = -1; + QList ve_attr, ve_array; + +private slots: + void on_comboType_currentIndexChanged(int); +}; + + +#endif diff --git a/libs/piqt_widgets/pivaluetree_edit_parameters.ui b/libs/piqt_widgets/pivaluetree_edit_parameters.ui index fce97f4..3d3d10f 100644 --- a/libs/piqt_widgets/pivaluetree_edit_parameters.ui +++ b/libs/piqt_widgets/pivaluetree_edit_parameters.ui @@ -6,8 +6,8 @@ 0 0 - 395 - 172 + 457 + 347 @@ -17,24 +17,75 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - Array + Read-only - + + + + Hidden + + + + + + + Label + + + + Type: - + + + + + Array + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + Attributes + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + @@ -70,6 +121,33 @@ Rename ... + + + + :/icons/code-variable.png:/icons/code-variable.png + + + Value + + + + + + :/icons/code-struct.png:/icons/code-struct.png + + + Group + + + + + + :/icons/code-union.png:/icons/code-union.png + + + Array + + @@ -82,6 +160,7 @@ + diff --git a/libs/piqt_widgets/pivariant_edit.cpp b/libs/piqt_widgets/pivariant_edit.cpp index 62c248b..0a35dc7 100644 --- a/libs/piqt_widgets/pivariant_edit.cpp +++ b/libs/piqt_widgets/pivariant_edit.cpp @@ -19,6 +19,11 @@ bool PIVariantEditorBase::editorExists(uint type_id) { } +PIVariantMap PIVariantEditorBase::editorDefaultAttributes(uint type_id) { + return default_attributes().value(type_id); +} + + void PIVariantEditorBase::createBoxLayout(QBoxLayout::Direction d) { auto * l = new QBoxLayout(d); l->setContentsMargins(0, 0, 0, 0); @@ -38,6 +43,12 @@ PIMap & PIVariantEditorBase::factories() { } +PIMap & PIVariantEditorBase::default_attributes() { + static PIMap ret; + return ret; +} + + PIVariantEdit::PIVariantEdit(QWidget * parent): QWidget(parent) { label = new QLabel(); label->setAlignment(Qt::AlignCenter); @@ -88,9 +99,9 @@ void PIVariantEdit::setAttributes(const PIVariantMap & a) { } -PIVariantMap PIVariantEdit::defaultAttributes() const { +PIVariantMap PIVariantEdit::attributes() const { if (!editor) return PIVariantMap(); - return editor->defaultAttributes(); + return editor->attributes(); } diff --git a/libs/piqt_widgets/pivariant_edit.h b/libs/piqt_widgets/pivariant_edit.h index 3787014..f1e7dde 100644 --- a/libs/piqt_widgets/pivariant_edit.h +++ b/libs/piqt_widgets/pivariant_edit.h @@ -45,7 +45,8 @@ public: virtual void setValue(const PIVariant & v) = 0; virtual PIVariant value() const = 0; - virtual PIVariantMap defaultAttributes() const { return PIVariantMap(); } + virtual PIVariantMap attributes() const { return PIVariantMap(); } + static PIVariantMap defaultAttributes() { return PIVariantMap(); } template static void registerEditor(uint type_id) { @@ -53,10 +54,13 @@ public: piCout << "[PIVariantEditorBase::registerEditor] Editor with typeID" << type_id << "already registered, ignore"; return; } - factories()[type_id] = []() -> PIVariantEditorBase * { return new T(); }; + factories()[type_id] = []() -> PIVariantEditorBase * { return new T(); }; + default_attributes()[type_id] = T::defaultAttributes(); } + static PIVariantEditorBase * createEditor(uint type_id); static bool editorExists(uint type_id); + static PIVariantMap editorDefaultAttributes(uint type_id); protected: void createBoxLayout(QBoxLayout::Direction d = QBoxLayout::LeftToRight); @@ -69,6 +73,7 @@ private: void changeEvent(QEvent * e) override; static PIMap & factories(); + static PIMap & default_attributes(); }; @@ -81,7 +86,7 @@ public: PIVariant value() const; void setAttributes(const PIVariantMap & a); - PIVariantMap defaultAttributes() const; + PIVariantMap attributes() const; void setFullEditMode(bool on); diff --git a/libs/piqt_widgets/pivariant_edit_widgets.cpp b/libs/piqt_widgets/pivariant_edit_widgets.cpp index a4c3c03..26d393d 100644 --- a/libs/piqt_widgets/pivariant_edit_widgets.cpp +++ b/libs/piqt_widgets/pivariant_edit_widgets.cpp @@ -20,100 +20,134 @@ REGISTER_PIVARIANTEDITOR(PIDateTime, PIVariantEditors::DateTime); REGISTER_PIVARIANTEDITOR(PIVariantTypes::Color, PIVariantEditors::Color); REGISTER_PIVARIANTEDITOR(PIVariantTypes::Enum, PIVariantEditors::Enum); +using Attribute = PIValueTree::Attribute; // PIVariantEditors::Int -PIVariantMap PIVariantEditors::Int::defaultAttributes() const { +PIVariantMap PIVariantEditors::Int::attributes() const { return { - {PIValueTree::attributeMinimum, widget->minimum() }, - {PIValueTree::attributeMaximum, widget->maximum() }, - {PIValueTree::attributeSingleStep, widget->singleStep() }, - {PIValueTree::attributePrefix, Q2PIString(widget->prefix())}, - {PIValueTree::attributeSuffix, Q2PIString(widget->suffix())}, + {Attribute::minimum, widget->minimum() }, + {Attribute::maximum, widget->maximum() }, + {Attribute::singleStep, widget->singleStep() }, + {Attribute::prefix, Q2PIString(widget->prefix())}, + {Attribute::suffix, Q2PIString(widget->suffix())}, + }; +} + + +PIVariantMap PIVariantEditors::Int::defaultAttributes() { + return { + {Attribute::minimum, -std::numeric_limits::max()}, + {Attribute::maximum, std::numeric_limits::max() }, + {Attribute::singleStep, 1. }, + {Attribute::prefix, "" }, + {Attribute::suffix, "" }, }; } void PIVariantEditors::Int::applyAttributes(const PIVariantMap & a) { - widget->setRange(a.value(PIValueTree::attributeMinimum, widget->minimum()).toInt(), - a.value(PIValueTree::attributeMaximum, widget->maximum()).toInt()); - widget->setSingleStep(a.value(PIValueTree::attributeSingleStep, widget->singleStep()).toInt()); - widget->setPrefix(PI2QString(a.value(PIValueTree::attributePrefix, Q2PIString(widget->prefix())).toString())); - widget->setSuffix(PI2QString(a.value(PIValueTree::attributeSuffix, Q2PIString(widget->suffix())).toString())); - widget->setReadOnly(a.value(PIValueTree::attributeReadOnly, widget->isReadOnly()).toBool()); + widget->setRange(a.value(Attribute::minimum, widget->minimum()).toInt(), a.value(Attribute::maximum, widget->maximum()).toInt()); + widget->setSingleStep(a.value(Attribute::singleStep, widget->singleStep()).toInt()); + widget->setPrefix(PI2QString(a.value(Attribute::prefix, Q2PIString(widget->prefix())).toString())); + widget->setSuffix(PI2QString(a.value(Attribute::suffix, Q2PIString(widget->suffix())).toString())); + widget->setReadOnly(a.value(Attribute::readOnly, widget->isReadOnly()).toBool()); } // PIVariantEditors::Double -PIVariantMap PIVariantEditors::Double::defaultAttributes() const { +PIVariantMap PIVariantEditors::Double::attributes() const { return { - {PIValueTree::attributeMinimum, widget->minimum() }, - {PIValueTree::attributeMaximum, widget->maximum() }, - {PIValueTree::attributeSingleStep, widget->singleStep() }, - {PIValueTree::attributeDecimals, widget->decimals() }, - {PIValueTree::attributePrefix, Q2PIString(widget->prefix())}, - {PIValueTree::attributeSuffix, Q2PIString(widget->suffix())}, + {Attribute::minimum, widget->minimum() }, + {Attribute::maximum, widget->maximum() }, + {Attribute::singleStep, widget->singleStep() }, + {Attribute::decimals, widget->decimals() }, + {Attribute::prefix, Q2PIString(widget->prefix())}, + {Attribute::suffix, Q2PIString(widget->suffix())}, + }; +} + + +PIVariantMap PIVariantEditors::Double::defaultAttributes() { + return { + {Attribute::minimum, -std::numeric_limits::max()}, + {Attribute::maximum, std::numeric_limits::max() }, + {Attribute::singleStep, 1. }, + {Attribute::decimals, 3 }, + {Attribute::prefix, "" }, + {Attribute::suffix, "" }, }; } void PIVariantEditors::Double::applyAttributes(const PIVariantMap & a) { - widget->setRange(a.value(PIValueTree::attributeMinimum, widget->minimum()).toDouble(), - a.value(PIValueTree::attributeMaximum, widget->maximum()).toDouble()); - widget->setSingleStep(a.value(PIValueTree::attributeSingleStep, widget->singleStep()).toDouble()); - widget->setDecimals(a.value(PIValueTree::attributeDecimals, widget->decimals()).toInt()); - widget->setPrefix(PI2QString(a.value(PIValueTree::attributePrefix, Q2PIString(widget->prefix())).toString())); - widget->setSuffix(PI2QString(a.value(PIValueTree::attributeSuffix, Q2PIString(widget->suffix())).toString())); - widget->setReadOnly(a.value(PIValueTree::attributeReadOnly, widget->isReadOnly()).toBool()); + widget->setRange(a.value(Attribute::minimum, widget->minimum()).toDouble(), a.value(Attribute::maximum, widget->maximum()).toDouble()); + widget->setSingleStep(a.value(Attribute::singleStep, widget->singleStep()).toDouble()); + widget->setDecimals(a.value(Attribute::decimals, widget->decimals()).toInt()); + widget->setPrefix(PI2QString(a.value(Attribute::prefix, Q2PIString(widget->prefix())).toString())); + widget->setSuffix(PI2QString(a.value(Attribute::suffix, Q2PIString(widget->suffix())).toString())); + widget->setReadOnly(a.value(Attribute::readOnly, widget->isReadOnly()).toBool()); } // PIVariantEditors::String -PIVariantMap PIVariantEditors::String::defaultAttributes() const { +PIVariantMap PIVariantEditors::String::attributes() const { + return {}; +} + + +PIVariantMap PIVariantEditors::String::defaultAttributes() { return {}; } void PIVariantEditors::String::applyAttributes(const PIVariantMap & a) { - widget->setReadOnly(a.value(PIValueTree::attributeReadOnly, widget->isReadOnly()).toBool()); + widget->setReadOnly(a.value(Attribute::readOnly, widget->isReadOnly()).toBool()); } // PIVariantEditors::Color -PIVariantMap PIVariantEditors::Color::defaultAttributes() const { +PIVariantMap PIVariantEditors::Color::attributes() const { return { {"useAlpha", widget->useAlphaChannel()}, }; } +PIVariantMap PIVariantEditors::Color::defaultAttributes() { + return { + {"useAlpha", true}, + }; +} + + void PIVariantEditors::Color::applyAttributes(const PIVariantMap & a) { widget->setUseAlphaChannel(a.value("useAlpha", widget->useAlphaChannel()).toBool()); - widget->setEnabled(!a.value(PIValueTree::attributeReadOnly, !widget->isEnabled()).toBool()); + widget->setEnabled(!a.value(Attribute::readOnly, !widget->isEnabled()).toBool()); } // PIVariantEditors::Time void PIVariantEditors::Time::applyAttributes(const PIVariantMap & a) { - widget->setReadOnly(a.value(PIValueTree::attributeReadOnly, widget->isReadOnly()).toBool()); + widget->setReadOnly(a.value(Attribute::readOnly, widget->isReadOnly()).toBool()); } // PIVariantEditors::Date void PIVariantEditors::Date::applyAttributes(const PIVariantMap & a) { - widget->setReadOnly(a.value(PIValueTree::attributeReadOnly, widget->isReadOnly()).toBool()); + widget->setReadOnly(a.value(Attribute::readOnly, widget->isReadOnly()).toBool()); } // PIVariantEditors::DateTime void PIVariantEditors::DateTime::applyAttributes(const PIVariantMap & a) { - widget->setReadOnly(a.value(PIValueTree::attributeReadOnly, widget->isReadOnly()).toBool()); + widget->setReadOnly(a.value(Attribute::readOnly, widget->isReadOnly()).toBool()); } @@ -137,5 +171,5 @@ PIVariant PIVariantEditors::Enum::value() const { void PIVariantEditors::Enum::applyAttributes(const PIVariantMap & a) { - widget->setEnabled(!a.value(PIValueTree::attributeReadOnly, !widget->isEnabled()).toBool()); + widget->setEnabled(!a.value(Attribute::readOnly, !widget->isEnabled()).toBool()); } diff --git a/libs/piqt_widgets/pivariant_edit_widgets.h b/libs/piqt_widgets/pivariant_edit_widgets.h index e4adff3..f36c8b6 100644 --- a/libs/piqt_widgets/pivariant_edit_widgets.h +++ b/libs/piqt_widgets/pivariant_edit_widgets.h @@ -36,6 +36,8 @@ namespace PIVariantEditors { class QAD_PIQT_UTILS_EXPORT Bool: public PIVariantEditorBase { + Q_OBJECT + public: Bool() { widget = new QCheckBox(); @@ -50,6 +52,8 @@ private: class QAD_PIQT_UTILS_EXPORT Int: public PIVariantEditorBase { + Q_OBJECT + public: Int() { widget = new QSpinBox(); @@ -58,7 +62,8 @@ public: } void setValue(const PIVariant & v) override { widget->setValue(v.toInt()); } PIVariant value() const override { return widget->value(); } - PIVariantMap defaultAttributes() const override; + PIVariantMap attributes() const override; + static PIVariantMap defaultAttributes(); private: void applyAttributes(const PIVariantMap & a) override; @@ -67,6 +72,8 @@ private: class QAD_PIQT_UTILS_EXPORT Double: public PIVariantEditorBase { + Q_OBJECT + public: Double() { widget = new QDoubleSpinBox(); @@ -75,7 +82,8 @@ public: } void setValue(const PIVariant & v) override { widget->setValue(v.toDouble()); } PIVariant value() const override { return widget->value(); } - PIVariantMap defaultAttributes() const override; + PIVariantMap attributes() const override; + static PIVariantMap defaultAttributes(); private: void applyAttributes(const PIVariantMap & a) override; @@ -84,6 +92,8 @@ private: class QAD_PIQT_UTILS_EXPORT String: public PIVariantEditorBase { + Q_OBJECT + public: String() { widget = new CLineEdit(); @@ -91,7 +101,8 @@ public: } void setValue(const PIVariant & v) override { widget->setText(PI2QString(v.toString())); } PIVariant value() const override { return Q2PIString(widget->text()); } - PIVariantMap defaultAttributes() const override; + PIVariantMap attributes() const override; + static PIVariantMap defaultAttributes(); private: void applyAttributes(const PIVariantMap & a) override; @@ -100,6 +111,8 @@ private: class QAD_PIQT_UTILS_EXPORT Color: public PIVariantEditorBase { + Q_OBJECT + public: Color() { widget = new ColorButton(); @@ -107,7 +120,8 @@ public: } void setValue(const PIVariant & v) override { widget->setColor(PI2QColor(v.toColor())); } PIVariant value() const override { return Q2PIColor(widget->color()); } - PIVariantMap defaultAttributes() const override; + PIVariantMap attributes() const override; + static PIVariantMap defaultAttributes(); private: void applyAttributes(const PIVariantMap & a) override; @@ -116,6 +130,8 @@ private: class QAD_PIQT_UTILS_EXPORT Time: public PIVariantEditorBase { + Q_OBJECT + public: Time() { widget = new QTimeEdit(); @@ -124,7 +140,7 @@ public: } void setValue(const PIVariant & v) override { widget->setTime(PI2QTime(v.toTime())); } PIVariant value() const override { return Q2PITime(widget->time()); } - PIVariantMap defaultAttributes() const override { return {}; } + PIVariantMap attributes() const override { return {}; } private: void applyAttributes(const PIVariantMap & a) override; @@ -133,6 +149,8 @@ private: class QAD_PIQT_UTILS_EXPORT Date: public PIVariantEditorBase { + Q_OBJECT + public: Date() { widget = new QDateEdit(); @@ -141,7 +159,7 @@ public: } void setValue(const PIVariant & v) override { widget->setDate(PI2QDate(v.toDate())); } PIVariant value() const override { return Q2PIDate(widget->date()); } - PIVariantMap defaultAttributes() const override { return {}; } + PIVariantMap attributes() const override { return {}; } private: void applyAttributes(const PIVariantMap & a) override; @@ -150,6 +168,8 @@ private: class QAD_PIQT_UTILS_EXPORT DateTime: public PIVariantEditorBase { + Q_OBJECT + public: DateTime() { widget = new QDateTimeEdit(); @@ -158,7 +178,7 @@ public: } void setValue(const PIVariant & v) override { widget->setDateTime(PI2QDateTime(v.toDateTime())); } PIVariant value() const override { return Q2PIDateTime(widget->dateTime()); } - PIVariantMap defaultAttributes() const override { return {}; } + PIVariantMap attributes() const override { return {}; } private: void applyAttributes(const PIVariantMap & a) override; @@ -167,6 +187,8 @@ private: class QAD_PIQT_UTILS_EXPORT Enum: public PIVariantEditorBase { + Q_OBJECT + public: Enum() { widget = new QComboBox(); @@ -174,7 +196,7 @@ public: } void setValue(const PIVariant & v) override; PIVariant value() const override; - PIVariantMap defaultAttributes() const override { return {}; } + PIVariantMap attributes() const override { return {}; } private: void applyAttributes(const PIVariantMap & a) override; diff --git a/libs/piqt_widgets/qad_piqt_widgets.qrc b/libs/piqt_widgets/qad_piqt_widgets.qrc index 562be5d..53f119a 100644 --- a/libs/piqt_widgets/qad_piqt_widgets.qrc +++ b/libs/piqt_widgets/qad_piqt_widgets.qrc @@ -2,5 +2,9 @@ ../../icons/configure.png ../../icons/border-line.png + ../../icons/list-add.png + ../../icons/code-variable.png + ../../icons/code-struct.png + ../../icons/code-union.png