feat: enum editing UI, protect enums from struct ops, New Class opens two tabs

- New Class creates two Unnamed tabs, selects the first
- New Enum creates 5 placeholder members (Member0-4)
- Right-click enum member: Add Member Above/Below, Remove Member
- Right-click enum header: Add Member, Rename, Delete only
- Enum nodes fully protected from struct operations (no Add Child, Insert, Convert)
This commit is contained in:
IChooseYou
2026-03-06 11:00:06 -07:00
committed by IChooseYou
parent e5938f7e82
commit 35b3cd9ac1
2 changed files with 79 additions and 0 deletions

View File

@@ -1777,7 +1777,41 @@ void RcxController::showContextMenu(RcxEditor* editor, int line, int nodeIdx,
&& !node.bitfieldMembers.isEmpty()
&& subLine >= 0 && subLine < node.bitfieldMembers.size();
bool isEnumNode = node.resolvedClassKeyword() == QStringLiteral("enum");
if (isEnumMember || isBitfieldMember) {
if (isEnumMember) {
menu.addAction(icon("diff-added.svg"), "Add Member Above", [this, nodeId, subLine]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni < 0) return;
auto members = m_doc->tree.nodes[ni].enumMembers;
int64_t val = (subLine > 0) ? members[subLine - 1].second + 1 : 0;
auto oldMembers = members;
members.insert(subLine, {QStringLiteral("NewMember"), val});
m_doc->undoStack.push(new RcxCommand(this,
cmd::ChangeEnumMembers{nodeId, oldMembers, members}));
});
menu.addAction(icon("diff-added.svg"), "Add Member Below", [this, nodeId, subLine]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni < 0) return;
auto members = m_doc->tree.nodes[ni].enumMembers;
int64_t val = members[subLine].second + 1;
auto oldMembers = members;
members.insert(subLine + 1, {QStringLiteral("NewMember"), val});
m_doc->undoStack.push(new RcxCommand(this,
cmd::ChangeEnumMembers{nodeId, oldMembers, members}));
});
menu.addAction(icon("trash.svg"), "Remove Member", [this, nodeId, subLine]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni < 0) return;
auto members = m_doc->tree.nodes[ni].enumMembers;
auto oldMembers = members;
members.remove(subLine);
m_doc->undoStack.push(new RcxCommand(this,
cmd::ChangeEnumMembers{nodeId, oldMembers, members}));
});
menu.addSeparator();
}
if (isBitfieldMember) {
const auto& bm = node.bitfieldMembers[subLine];
if (bm.bitWidth == 1) {
@@ -1792,6 +1826,28 @@ void RcxController::showContextMenu(RcxEditor* editor, int line, int nodeIdx,
menu.addSeparator();
}
// Fall through to always-available actions
} else if (isEnumNode) {
// Enum header line — enum-specific actions only (no struct ops)
menu.addAction(icon("diff-added.svg"), "Add Member", [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni < 0) return;
auto members = m_doc->tree.nodes[ni].enumMembers;
int64_t nextVal = members.isEmpty() ? 0 : members.last().second + 1;
auto oldMembers = members;
members.append({QStringLiteral("NewMember"), nextVal});
m_doc->undoStack.push(new RcxCommand(this,
cmd::ChangeEnumMembers{nodeId, oldMembers, members}));
});
menu.addAction(icon("edit.svg"), "&Rename...", [this, editor, line]() {
editor->beginInlineEdit(EditTarget::Name, line);
});
menu.addSeparator();
menu.addAction(icon("trash.svg"), "&Delete", [this, nodeId]() {
int ni = m_doc->tree.indexOfId(nodeId);
if (ni >= 0) removeNode(ni);
});
menu.addSeparator();
// Fall through to always-available actions
} else {
// ── Quick-convert suggestions (top-level for fast access) ──

View File

@@ -1920,6 +1920,26 @@ void MainWindow::setupDockTabBars() {
// Build a minimal empty struct for new documents
static void buildEmptyStruct(NodeTree& tree, const QString& classKeyword = QString()) {
// ── Enum: bare node with empty enumMembers, no hex children ──
if (classKeyword == QStringLiteral("enum")) {
Node root;
root.kind = NodeKind::Struct;
root.name = "Unnamed";
root.structTypeName = "Unnamed";
root.classKeyword = classKeyword;
root.parentId = 0;
root.offset = 0;
root.enumMembers = {
{QStringLiteral("Member0"), 0},
{QStringLiteral("Member1"), 1},
{QStringLiteral("Member2"), 2},
{QStringLiteral("Member3"), 3},
{QStringLiteral("Member4"), 4},
};
tree.addNode(root);
return;
}
Node root;
root.kind = NodeKind::Struct;
root.name = "instance";
@@ -1988,7 +2008,10 @@ MainWindow::~MainWindow() {
}
void MainWindow::newClass() {
auto* first = project_new(QStringLiteral("class"));
project_new(QStringLiteral("class"));
// Select the first tab
if (first) first->raise();
}
void MainWindow::newStruct() {