#include "pivaluetree_edit.h" #include "ui_pivaluetree_edit_array.h" #include "pivariant_edit.h" #include "piqt.h" #include #include #include PIValueTreeEdit::PIValueTreeEdit(QWidget * parent): QWidget(parent) { ui = new Ui::PIValueTreeEditArray(); grid = new GridWidgets(); auto * lay = new QBoxLayout(QBoxLayout::TopToBottom); lay->setContentsMargins(0, 0, 0, 0); setLayout(lay); } PIValueTreeEdit::~PIValueTreeEdit() { delete ui; delete grid; } void PIValueTreeEdit::setValue(const PIValueTree & v) { source = v; build(); } PIValueTree PIValueTreeEdit::value() const { applyValues(); return source; } void PIValueTreeEdit::setGroupingEnabled(bool yes) { is_grouping = yes; build(); } void PIValueTreeEdit::rollback() { build(); } void PIValueTreeEdit::clear() { source = PIValueTree(); removeAll(); } void PIValueTreeEdit::removeAll() { array_edits.clear(); value_edits.clear(); tree_edits.clear(); if (ui_array) { ui->layoutArray->takeAt(0); delete ui_array; ui_array = nullptr; } QLayoutItem * child = nullptr; while ((child = layout()->takeAt(0)) != nullptr) { delete child; } grid->clear(); } void PIValueTreeEdit::build() { removeAll(); //piCout << source.attributes().value(PIValueTree::attributeArrayType) << array_type; if (source.isArray()) { ui_array = new QWidget(); ui->setupUi(ui_array); ui->spinCount->setRange(source.attribute(PIValueTree::attributeArrayMinCount, 0).toInt(), source.attribute(PIValueTree::attributeArrayMaxCount, 65536).toInt()); ui->spinCount->setValue(source.children().size_s()); ui->widgetEdit->setVisible(source.attribute(PIValueTree::attributeArrayResize, false).toBool()); ui->layoutArray->addWidget(grid); uint array_type = PIVariant::typeIDFromName(source.attribute(PIValueTree::attributeArrayType).toString()); int index = 0; for (const auto & i: source.children()) { auto * ve = new PIVariantEdit(); ve->setAttributes(source.attributes()); ve->setValue(i.value(), array_type); grid->add(QString::number(++index), ve, PI2QString(i.comment())); array_edits << ve; } connect(ui->spinCount, QOverload::of(&QSpinBox::valueChanged), this, [this,array_type](int value){ value = piMaxi(value, 0); for (int i = grid->rowCount() - 1; i >= value; --i) grid->removeRow(i); array_edits.resize(grid->rowCount()); for (int i = grid->rowCount(); i < value; ++i) { auto * ve = new PIVariantEdit(); ve->setAttributes(source.attributes()); ve->setValue(PIVariant::fromType(array_type), array_type); grid->add(QString::number(i + 1), ve, ""); array_edits << ve; } }); layout()->addWidget(ui_array); } else { layout()->addWidget(grid); for (const auto & i: source.children()) { if (i.attribute(PIValueTree::attributeHidden, false).toBool()) continue; if (i.attribute(PIValueTree::attributeIsLabel, false).toBool()) { if (i.name().isEmpty()) continue; auto * l = new QLabel(PI2QString(i.name())); l->setAlignment(Qt::AlignCenter); grid->add(l); continue; } if (i.hasChildren() || i.isArray()) { auto * ve = new PIValueTreeEdit(); ve->setGroupingEnabled(is_grouping); 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(gb); } else { grid->add(PI2QString(i.name()), ve, PI2QString(i.comment())); } tree_edits[i.name()] = ve; } else { auto * ve = new PIVariantEdit(); ve->setAttributes(i.attributes()); ve->setValue(i.value()); grid->add(PI2QString(i.name()), ve, PI2QString(i.comment())); value_edits[i.name()] = ve; } } } } void PIValueTreeEdit::applyValues() const { if (source.isArray()) { if (array_edits.isNotEmpty()) source.mergeAttributes(array_edits[0]->defaultAttributes()); source.clearChildren(); for (int i = 0; i < array_edits.size_s(); ++i) source.addChild({PIString::fromNumber(i), array_edits[i]->value()}); } else { auto vit = value_edits.makeIterator(); while (vit.next()) { auto & c(source.child(vit.key())); c.mergeAttributes(vit.value()->defaultAttributes()); c.setValue(vit.value()->value()); } auto tit = tree_edits.makeIterator(); while (tit.next()) { auto & c(source.child(tit.key())); if (!c.isNull()) c = tit.value()->value(); } } } void PIValueTreeEdit::GridWidgets::add(QString label, QWidget * w, const QString & comment) { if (!label.isEmpty()) label += ':'; auto * l = new QLabel(label); auto * c = new QLabel(comment); l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); c->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); lay->addWidget(l, row_count, 0, Qt::AlignVCenter | Qt::AlignRight); lay->addWidget(w, row_count, 1); lay->addWidget(c, row_count, 2, Qt::AlignVCenter | Qt::AlignLeft); widgets << l << w << c; ++row_count; } void PIValueTreeEdit::GridWidgets::add(QWidget * w) { lay->addWidget(w, row_count, 0, 1, -1); widgets << w; ++row_count; } void PIValueTreeEdit::GridWidgets::clear() { piDeleteAllAndClear(widgets); if (lay) delete lay; lay = new QGridLayout(); lay->setContentsMargins(0, 0, 0, 0); setLayout(lay); row_count = 0; } void PIValueTreeEdit::GridWidgets::removeRow(int index) { if (!lay) return; if (row_count <= index) return; for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(index, c); if (li) { if (li->widget()) { widgets.removeOne(li->widget()); delete li->widget(); } delete li; } } --row_count; simplify(); } void PIValueTreeEdit::GridWidgets::simplify() { if (!lay) return; QVector> wg; QMap wa; for (int r = 0; r < lay->rowCount(); ++r) { QMap row; for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(r, c); if (!li) continue; if (li->widget()) { row[c] = li->widget(); wa[li->widget()] = li->alignment(); } } if (!row.isEmpty()) wg << row; } delete lay; lay = new QGridLayout(); lay->setContentsMargins(0, 0, 0, 0); int rindex = 0; for (const auto & row: wg) { QMapIterator it(row); while (it.hasNext()) { it.next(); lay->addWidget(it.value(), rindex, it.key(), wa.value(it.value())); } ++rindex; } setLayout(lay); }