mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
- WinDbg provider no longer picks arbitrary module[0] as name/base (was showing "WS2_32" for kernel dumps). Name is now generic "WinDbg (Live)" / "WinDbg (Dump)", base stays 0 so controller doesn't override user's address. - Added throttled read failure logging to WinDbg provider. - New tabs (File→New Class, workspace right-click) inherit the current tab's source/provider so users don't have to re-attach. - Updated WinDbg provider tests for new behavior.
213 lines
8.3 KiB
C++
213 lines
8.3 KiB
C++
#pragma once
|
|
#include "core.h"
|
|
#include "themes/theme.h"
|
|
#include <QWidget>
|
|
#include <QSet>
|
|
#include <QPoint>
|
|
#include <QHash>
|
|
|
|
class QsciScintilla;
|
|
class QsciLexerCPP;
|
|
|
|
namespace rcx {
|
|
|
|
struct SavedSourceDisplay {
|
|
QString text;
|
|
bool active = false;
|
|
};
|
|
|
|
class RcxEditor : public QWidget {
|
|
Q_OBJECT
|
|
public:
|
|
explicit RcxEditor(QWidget* parent = nullptr);
|
|
~RcxEditor() override;
|
|
|
|
void applyDocument(const ComposeResult& result);
|
|
|
|
ViewState saveViewState() const;
|
|
void restoreViewState(const ViewState& vs);
|
|
|
|
QsciScintilla* scintilla() const { return m_sci; }
|
|
QWidget* structPreviewPopup() const { return m_structPreviewPopup; }
|
|
const LineMeta* metaForLine(int line) const;
|
|
int currentNodeIndex() const;
|
|
void scrollToNodeId(uint64_t nodeId);
|
|
|
|
// ── Column span computation ──
|
|
static ColumnSpan typeSpan(const LineMeta& lm, int typeW = kColType);
|
|
static ColumnSpan nameSpan(const LineMeta& lm, int typeW = kColType, int nameW = kColName);
|
|
static ColumnSpan valueSpan(const LineMeta& lm, int lineLength, int typeW = kColType, int nameW = kColName);
|
|
|
|
// ── Multi-selection ──
|
|
QSet<int> selectedNodeIndices() const;
|
|
|
|
// ── Inline editing ──
|
|
bool isEditing() const { return m_editState.active; }
|
|
bool beginInlineEdit(EditTarget target, int line = -1, int col = -1);
|
|
void cancelInlineEdit();
|
|
|
|
void applySelectionOverlay(const QSet<uint64_t>& selIds);
|
|
void setCommandRowText(const QString& line);
|
|
void setEditorFont(const QString& fontName);
|
|
static void setGlobalFontName(const QString& fontName);
|
|
static QString globalFontName();
|
|
void applyTheme(const Theme& theme);
|
|
|
|
// Custom type names (struct types from the tree) shown in type picker + lexer GlobalClass coloring
|
|
QString textWithMargins() const;
|
|
void setCustomTypeNames(const QStringList& names);
|
|
void setValueHistoryRef(const QHash<uint64_t, ValueHistory>* ref) { m_valueHistory = ref; }
|
|
void setProviderRef(const Provider* prov, const Provider* realProv, const NodeTree* tree) {
|
|
m_disasmProvider = prov; m_disasmRealProv = realProv; m_disasmTree = tree;
|
|
}
|
|
|
|
// Saved sources for quick-switch in source picker
|
|
void setSavedSources(const QVector<SavedSourceDisplay>& sources) { m_savedSourceDisplay = sources; }
|
|
|
|
signals:
|
|
void marginClicked(int margin, int line, Qt::KeyboardModifiers mods);
|
|
void contextMenuRequested(int line, int nodeIdx, int subLine, QPoint globalPos);
|
|
void keywordConvertRequested(const QString& newKeyword);
|
|
void nodeClicked(int line, uint64_t nodeId, Qt::KeyboardModifiers mods);
|
|
void inlineEditCommitted(int nodeIdx, int subLine,
|
|
EditTarget target, const QString& text,
|
|
uint64_t resolvedAddr = 0);
|
|
void inlineEditCancelled();
|
|
void typeSelectorRequested();
|
|
void typePickerRequested(EditTarget target, int nodeIdx, QPoint globalPos);
|
|
|
|
protected:
|
|
bool eventFilter(QObject* obj, QEvent* event) override;
|
|
|
|
private:
|
|
QsciScintilla* m_sci = nullptr;
|
|
QsciLexerCPP* m_lexer = nullptr;
|
|
QVector<LineMeta> m_meta;
|
|
LayoutInfo m_layout; // cached from ComposeResult
|
|
|
|
// ── Toggle: absolute vs relative offset margin
|
|
bool m_relativeOffsets = true;
|
|
|
|
int m_marginStyleBase = -1;
|
|
int m_hintLine = -1;
|
|
|
|
// ── Hover cursor + highlight ──
|
|
QPoint m_lastHoverPos;
|
|
bool m_hoverInside = false;
|
|
uint64_t m_hoveredNodeId = 0;
|
|
int m_hoveredLine = -1;
|
|
uint64_t m_prevHoveredNodeId = 0; // for incremental marker update
|
|
int m_prevHoveredLine = -1; // for incremental marker update
|
|
QSet<uint64_t> m_currentSelIds;
|
|
QVector<int> m_hoverSpanLines; // Lines with hover span indicators
|
|
// ── nodeId → display-line index (built in applyDocument) ──
|
|
QHash<uint64_t, QVector<int>> m_nodeLineIndex;
|
|
// ── 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;
|
|
|
|
// ── Tab cycling state ──
|
|
EditTarget m_lastTabTarget = EditTarget::Value;
|
|
|
|
// ── Custom type names for type picker ──
|
|
QStringList m_customTypeNames;
|
|
|
|
// ── Saved sources for quick-switch ──
|
|
QVector<SavedSourceDisplay> m_savedSourceDisplay;
|
|
|
|
// ── Value history ref (owned by controller) ──
|
|
const QHash<uint64_t, ValueHistory>* m_valueHistory = nullptr;
|
|
QWidget* m_historyPopup = nullptr; // ValueHistoryPopup (file-local class in editor.cpp)
|
|
QWidget* m_disasmPopup = nullptr; // DisasmPopup (file-local class in editor.cpp)
|
|
QWidget* m_structPreviewPopup = nullptr; // StructPreviewPopup (file-local class in editor.cpp)
|
|
const Provider* m_disasmProvider = nullptr; // snapshot or real — for reading tree data
|
|
const Provider* m_disasmRealProv = nullptr; // real process provider — for reading code at arbitrary addresses
|
|
const NodeTree* m_disasmTree = nullptr;
|
|
|
|
// ── Reentrancy guards ──
|
|
bool m_applyingDocument = false;
|
|
bool m_clampingSelection = false;
|
|
bool m_updatingComment = false;
|
|
|
|
void setupScintilla();
|
|
void setupLexer();
|
|
void setupMargins();
|
|
void setupFolding();
|
|
void setupMarkers();
|
|
void allocateMarginStyles();
|
|
|
|
void applyMarginText(const QVector<LineMeta>& meta);
|
|
void reformatMargins();
|
|
void applyMarkers(const QVector<LineMeta>& meta);
|
|
void applyFoldLevels(const QVector<LineMeta>& meta);
|
|
void applyHexDimming(const QVector<LineMeta>& meta);
|
|
void applyHeatmapHighlight(const QVector<LineMeta>& meta);
|
|
void applySymbolColoring(const QVector<LineMeta>& meta);
|
|
void applyBaseAddressColoring(const QVector<LineMeta>& meta);
|
|
void applyCommandRowPills();
|
|
|
|
void commitInlineEdit();
|
|
int editEndCol() const;
|
|
bool handleNormalKey(QKeyEvent* ke);
|
|
bool handleEditKey(QKeyEvent* ke);
|
|
void showTypeAutocomplete();
|
|
void showSourcePicker();
|
|
void showTypeListFiltered(const QString& filter);
|
|
void updateTypeListFilter();
|
|
void showPointerTargetPicker();
|
|
void showPointerTargetListFiltered(const QString& filter);
|
|
void updatePointerTargetFilter();
|
|
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
|