diff --git a/src/controller.cpp b/src/controller.cpp index 5dfed50..f5f5334 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -256,13 +256,23 @@ void RcxController::connectEditor(RcxEditor* editor) { bool typeOk; NodeKind elemKind = kindFromTypeName(elemTypeName, &typeOk); if (typeOk && nodeIdx < m_doc->tree.nodes.size()) { - const Node& node = m_doc->tree.nodes[nodeIdx]; - if (node.kind == NodeKind::Array) { - m_doc->undoStack.push(new RcxCommand(this, - cmd::ChangeArrayMeta{node.id, - node.elementKind, elemKind, - node.arrayLen, newCount})); + const uint64_t nodeId = m_doc->tree.nodes[nodeIdx].id; + bool wasSuppressed = m_suppressRefresh; + m_suppressRefresh = true; + m_doc->undoStack.beginMacro(QStringLiteral("Change to array")); + if (m_doc->tree.nodes[nodeIdx].kind != NodeKind::Array) + changeNodeKind(nodeIdx, NodeKind::Array); + int idx = m_doc->tree.indexOfId(nodeId); + if (idx >= 0) { + auto& n = m_doc->tree.nodes[idx]; + if (n.elementKind != elemKind || n.arrayLen != newCount) + m_doc->undoStack.push(new RcxCommand(this, + cmd::ChangeArrayMeta{nodeId, n.elementKind, elemKind, + n.arrayLen, newCount})); } + m_doc->undoStack.endMacro(); + m_suppressRefresh = wasSuppressed; + if (!m_suppressRefresh) refresh(); } } } else { @@ -2051,8 +2061,28 @@ void RcxController::applyTypePopupResult(TypePopupMode mode, int nodeIdx, if (mode == TypePopupMode::FieldType) { if (entry.entryKind == TypeEntry::Primitive) { - if (entry.primitiveKind != nodeKind) - changeNodeKind(nodeIdx, entry.primitiveKind); + if (spec.arrayCount > 0) { + // Primitive array: e.g. "int32_t[10]" + bool wasSuppressed = m_suppressRefresh; + m_suppressRefresh = true; + m_doc->undoStack.beginMacro(QStringLiteral("Change to primitive array")); + if (nodeKind != NodeKind::Array) + changeNodeKind(nodeIdx, NodeKind::Array); + int idx = m_doc->tree.indexOfId(nodeId); + if (idx >= 0) { + auto& n = m_doc->tree.nodes[idx]; + if (n.elementKind != entry.primitiveKind || n.arrayLen != spec.arrayCount) + m_doc->undoStack.push(new RcxCommand(this, + cmd::ChangeArrayMeta{nodeId, n.elementKind, entry.primitiveKind, + n.arrayLen, spec.arrayCount})); + } + m_doc->undoStack.endMacro(); + m_suppressRefresh = wasSuppressed; + if (!m_suppressRefresh) refresh(); + } else { + if (entry.primitiveKind != nodeKind) + changeNodeKind(nodeIdx, entry.primitiveKind); + } } else if (entry.entryKind == TypeEntry::Composite) { bool wasSuppressed = m_suppressRefresh; m_suppressRefresh = true; diff --git a/src/typeselectorpopup.cpp b/src/typeselectorpopup.cpp index 7017adc..0ed3d90 100644 --- a/src/typeselectorpopup.cpp +++ b/src/typeselectorpopup.cpp @@ -334,7 +334,12 @@ TypeSelectorPopup::TypeSelectorPopup(QWidget* parent) this, [this](int id, bool checked) { if (!checked) return; m_arrayCountEdit->setVisible(id == 3); - if (id == 3) m_arrayCountEdit->setFocus(); + if (id == 3) { + if (m_arrayCountEdit->text().trimmed().isEmpty()) + m_arrayCountEdit->setText(QStringLiteral("1")); + m_arrayCountEdit->setFocus(); + m_arrayCountEdit->selectAll(); + } updateModifierPreview(); applyFilter(m_filterEdit->text()); }); diff --git a/tests/test_controller.cpp b/tests/test_controller.cpp index b0bac73..5eb1aef 100644 --- a/tests/test_controller.cpp +++ b/tests/test_controller.cpp @@ -643,6 +643,36 @@ private slots: QCOMPARE(vals.size(), ValueHistory::kCapacity); QCOMPARE(vals.last(), vh.last()); } + // ── Test: inline edit "int32_t[4]" on primitive converts to array ── + void testInlineEditPrimitiveArray() { + // Find a primitive field to convert + int idx = -1; + for (int i = 0; i < m_doc->tree.nodes.size(); i++) { + if (m_doc->tree.nodes[i].name == "field_u32") { idx = i; break; } + } + QVERIFY(idx >= 0); + QCOMPARE(m_doc->tree.nodes[idx].kind, NodeKind::UInt32); + uint64_t nodeId = m_doc->tree.nodes[idx].id; + + // Emit inlineEditCommitted with array syntax + emit m_editor->inlineEditCommitted(idx, 0, EditTarget::Type, + QStringLiteral("int32_t[4]")); + QApplication::processEvents(); + + // Node should now be an Array with elementKind=Int32, arrayLen=4 + int newIdx = m_doc->tree.indexOfId(nodeId); + QVERIFY(newIdx >= 0); + QCOMPARE(m_doc->tree.nodes[newIdx].kind, NodeKind::Array); + QCOMPARE(m_doc->tree.nodes[newIdx].elementKind, NodeKind::Int32); + QCOMPARE(m_doc->tree.nodes[newIdx].arrayLen, 4); + + // Undo should restore to UInt32 + m_doc->undoStack.undo(); + QApplication::processEvents(); + newIdx = m_doc->tree.indexOfId(nodeId); + QVERIFY(newIdx >= 0); + QCOMPARE(m_doc->tree.nodes[newIdx].kind, NodeKind::UInt32); + } }; QTEST_MAIN(TestController) diff --git a/tests/test_type_selector.cpp b/tests/test_type_selector.cpp index a0f7c8d..f303bb8 100644 --- a/tests/test_type_selector.cpp +++ b/tests/test_type_selector.cpp @@ -736,6 +736,63 @@ private slots: QVERIFY(listView); QVERIFY(listView->model()->rowCount() > 2); } + // ── FieldType popup: primitive with [n] creates an array ── + + void testFieldTypePrimitiveArrayCreation() { + auto* doc = new RcxDocument(); + buildTwoRootTree(doc->tree); + doc->provider = std::make_unique(makeBuffer()); + + auto* splitter = new QSplitter(); + auto* ctrl = new RcxController(doc, nullptr); + ctrl->addSplitEditor(splitter); + + splitter->resize(800, 600); + splitter->show(); + QVERIFY(QTest::qWaitForWindowExposed(splitter)); + ctrl->refresh(); + QApplication::processEvents(); + + // Find the "x" field (Int32) + int xIdx = -1; + for (int i = 0; i < doc->tree.nodes.size(); i++) { + if (doc->tree.nodes[i].name == "x") { xIdx = i; break; } + } + QVERIFY(xIdx >= 0); + QCOMPARE(doc->tree.nodes[xIdx].kind, NodeKind::Int32); + uint64_t xNodeId = doc->tree.nodes[xIdx].id; + + // Simulate the primitive-array path of applyTypePopupResult: + // beginMacro → changeNodeKind(Array) → ChangeArrayMeta → endMacro + doc->undoStack.beginMacro(QStringLiteral("Change to primitive array")); + ctrl->changeNodeKind(xIdx, NodeKind::Array); + xIdx = doc->tree.indexOfId(xNodeId); + QVERIFY(xIdx >= 0); + doc->undoStack.push(new RcxCommand(ctrl, + cmd::ChangeArrayMeta{xNodeId, doc->tree.nodes[xIdx].elementKind, + NodeKind::Int32, + doc->tree.nodes[xIdx].arrayLen, 4})); + doc->undoStack.endMacro(); + QApplication::processEvents(); + + // Node should now be an Array + xIdx = doc->tree.indexOfId(xNodeId); + QVERIFY(xIdx >= 0); + QCOMPARE(doc->tree.nodes[xIdx].kind, NodeKind::Array); + QCOMPARE(doc->tree.nodes[xIdx].elementKind, NodeKind::Int32); + QCOMPARE(doc->tree.nodes[xIdx].arrayLen, 4); + + // Single undo reverses the entire macro + doc->undoStack.undo(); + QApplication::processEvents(); + xIdx = doc->tree.indexOfId(xNodeId); + QVERIFY(xIdx >= 0); + QCOMPARE(doc->tree.nodes[xIdx].kind, NodeKind::Int32); + + delete ctrl; + delete splitter; + delete doc; + } }; QTEST_MAIN(TestTypeSelector)