#pragma once #include "core.h" #include #include #include class QsciScintilla; class QsciLexerCPP; namespace rcx { class RcxEditor : public QWidget { Q_OBJECT public: explicit RcxEditor(QWidget* parent = nullptr); void applyDocument(const ComposeResult& result); ViewState saveViewState() const; void restoreViewState(const ViewState& vs); QsciScintilla* scintilla() const { return m_sci; } const LineMeta* metaForLine(int line) const; int currentNodeIndex() const; // ── Column span computation ── static ColumnSpan typeSpan(const LineMeta& lm); static ColumnSpan nameSpan(const LineMeta& lm); static ColumnSpan valueSpan(const LineMeta& lm, int lineLength); // ── Multi-selection ── QSet selectedNodeIndices() const; // ── Inline editing ── bool isEditing() const { return m_editState.active; } bool beginInlineEdit(EditTarget target, int line = -1); void cancelInlineEdit(); void applySelectionOverlay(const QSet& selIds); void setEditorFont(const QString& fontName); static void setGlobalFontName(const QString& fontName); signals: void marginClicked(int margin, int line, Qt::KeyboardModifiers mods); void contextMenuRequested(int line, int nodeIdx, int subLine, QPoint globalPos); void nodeClicked(int line, uint64_t nodeId, Qt::KeyboardModifiers mods); void inlineEditCommitted(int nodeIdx, int subLine, EditTarget target, const QString& text); void inlineEditCancelled(); protected: bool eventFilter(QObject* obj, QEvent* event) override; private: QsciScintilla* m_sci = nullptr; QsciLexerCPP* m_lexer = nullptr; QVector m_meta; int m_marginStyleBase = -1; int m_hintLine = -1; // ── Hover cursor + highlight ── QPoint m_lastHoverPos; bool m_hoverInside = false; bool m_cursorOverridden = false; uint64_t m_hoveredNodeId = 0; QSet m_currentSelIds; int m_hoverSpanLine = -1; // Line with hover span indicator // ── Drag selection ── bool m_dragging = false; bool m_dragStarted = false; // true once drag threshold exceeded int m_dragLastLine = -1; QPoint m_dragStartPos; // viewport coords at press Qt::KeyboardModifiers m_dragInitMods = Qt::NoModifier; // ── Deferred click (protects multi-select on double-click) ── uint64_t m_pendingClickNodeId = 0; int m_pendingClickLine = -1; Qt::KeyboardModifiers m_pendingClickMods = Qt::NoModifier; // ── Inline edit state ── struct InlineEditState { bool active = false; int line = -1; int nodeIdx = -1; int subLine = 0; EditTarget target = EditTarget::Name; int spanStart = 0; int linelenAfterReplace = 0; QString original; long posStart = 0; // Scintilla position of edit start long posEnd = 0; // Scintilla position of edit end NodeKind editKind = NodeKind::Int32; int commentCol = -1; // fixed comment column (stored at edit start) bool lastValidationOk = true; // track state to avoid redundant updates }; InlineEditState m_editState; void setupScintilla(); void setupLexer(); void setupMargins(); void setupFolding(); void setupMarkers(); void allocateMarginStyles(); void applyMarginText(const QVector& meta); void applyMarkers(const QVector& meta); void applyFoldLevels(const QVector& meta); void applyHexDimming(const QVector& meta); void applyBaseAddressColoring(const QVector& meta); void commitInlineEdit(); int editEndCol() const; bool handleNormalKey(QKeyEvent* ke); bool handleEditKey(QKeyEvent* ke); void showTypeAutocomplete(); void showTypeListFiltered(const QString& filter); void updateTypeListFilter(); void paintEditableSpans(int line); void updateEditableIndicators(int line); void applyHoverCursor(); void applyHoverHighlight(); void validateEditLive(); void setEditComment(const QString& comment); void clampEditSelection(); // ── Refactored helpers ── struct HitInfo { int line = -1; int col = -1; uint64_t nodeId = 0; bool inFoldCol = false; }; HitInfo hitTest(const QPoint& viewportPos) const; struct EndEditInfo { int nodeIdx; int subLine; EditTarget target; }; EndEditInfo endInlineEdit(); struct NormalizedSpan { int start = 0; int end = 0; bool valid = false; }; NormalizedSpan normalizeSpan(const ColumnSpan& raw, const QString& lineText, EditTarget target, bool skipPrefixes) const; // ── Indicator helpers (dedupe + UTF-8 safe) ── void clearIndicatorLine(int indic, int line); void fillIndicatorCols(int indic, int line, int colA, int colB); bool resolvedSpanFor(int line, EditTarget t, NormalizedSpan& out, QString* lineTextOut = nullptr) const; }; } // namespace rcx