| 726 | } |
| 727 | |
| 728 | void RcxController::insertNode(uint64_t parentId, int offset, NodeKind kind, const QString& name) { |
| 729 | Node n; |
| 730 | n.kind = kind; |
| 731 | n.name = name; |
| 732 | n.parentId = parentId; |
| 733 | |
| 734 | if (offset < 0) { |
| 735 | // Auto-place after last sibling with alignment |
| 736 | int maxEnd = 0; |
| 737 | auto siblings = m_doc->tree.childrenOf(parentId); |
| 738 | for (int si : siblings) { |
| 739 | auto& sn = m_doc->tree.nodes[si]; |
| 740 | int sz = (sn.kind == NodeKind::Struct || sn.kind == NodeKind::Array) |
| 741 | ? m_doc->tree.structSpan(sn.id) : sn.byteSize(); |
| 742 | int end = sn.offset + sz; |
| 743 | if (end > maxEnd) maxEnd = end; |
| 744 | } |
| 745 | int align = alignmentFor(kind); |
| 746 | n.offset = (maxEnd + align - 1) / align * align; |
| 747 | } else { |
| 748 | n.offset = offset; |
| 749 | } |
| 750 | |
| 751 | // Reserve unique ID atomically before pushing command |
| 752 | n.id = m_doc->tree.reserveId(); |
| 753 | |
| 754 | m_doc->undoStack.push(new RcxCommand(this, cmd::Insert{n})); |
| 755 | } |
| 756 | |
| 757 | void RcxController::removeNode(int nodeIdx) { |
| 758 | if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return; |