mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
selection and hover use full-row bg markers instead of indicators
- replace IND_SELECTED/IND_HOVER indicators with M_HOVER(6) M_SELECTED(7) bg markers - disable caret line highlight and native selection rendering - re-enable sel rendering only during inline edit - add drag-select support via nodeClicked shift signals - use lineRangeNoEol helper to exclude EOL from indicator ranges - add drag tracking state to editor
This commit is contained in:
@@ -109,6 +109,8 @@ enum Marker : int {
|
|||||||
M_CYCLE = 3,
|
M_CYCLE = 3,
|
||||||
M_ERR = 4,
|
M_ERR = 4,
|
||||||
M_STRUCT_BG = 5,
|
M_STRUCT_BG = 5,
|
||||||
|
M_HOVER = 6,
|
||||||
|
M_SELECTED = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Provider interface ──
|
// ── Provider interface ──
|
||||||
|
|||||||
136
src/editor.cpp
136
src/editor.cpp
@@ -23,8 +23,6 @@ static const QColor kFgMarginDim("#505050");
|
|||||||
|
|
||||||
static constexpr int IND_EDITABLE = 8;
|
static constexpr int IND_EDITABLE = 8;
|
||||||
static constexpr int IND_HEX_DIM = 9;
|
static constexpr int IND_HEX_DIM = 9;
|
||||||
static constexpr int IND_SELECTED = 10;
|
|
||||||
static constexpr int IND_HOVER = 11;
|
|
||||||
|
|
||||||
static QFont editorFont() {
|
static QFont editorFont() {
|
||||||
QFont f("Consolas", 12);
|
QFont f("Consolas", 12);
|
||||||
@@ -87,8 +85,7 @@ void RcxEditor::setupScintilla() {
|
|||||||
|
|
||||||
m_sci->setReadOnly(true);
|
m_sci->setReadOnly(true);
|
||||||
m_sci->setWrapMode(QsciScintilla::WrapNone);
|
m_sci->setWrapMode(QsciScintilla::WrapNone);
|
||||||
m_sci->setCaretLineVisible(true);
|
m_sci->setCaretLineVisible(false);
|
||||||
m_sci->setCaretLineBackgroundColor(QColor("#2c3338"));
|
|
||||||
|
|
||||||
m_sci->setPaper(kBgText);
|
m_sci->setPaper(kBgText);
|
||||||
m_sci->setColor(QColor("#d4d4d4"));
|
m_sci->setColor(QColor("#d4d4d4"));
|
||||||
@@ -103,9 +100,9 @@ void RcxEditor::setupScintilla() {
|
|||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRAASCENT, (long)2);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRAASCENT, (long)2);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRADESCENT, (long)2);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRADESCENT, (long)2);
|
||||||
|
|
||||||
// Selection colors
|
// Disable native selection rendering — we use markers for selection
|
||||||
m_sci->setSelectionBackgroundColor(QColor("#264f78"));
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELFORE, (long)0, (long)0);
|
||||||
m_sci->setSelectionForegroundColor(QColor("#d4d4d4"));
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELBACK, (long)0, (long)0);
|
||||||
|
|
||||||
// Editable-field link-style indicator (colored text + underline)
|
// Editable-field link-style indicator (colored text + underline)
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
|
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
|
||||||
@@ -118,30 +115,6 @@ void RcxEditor::setupScintilla() {
|
|||||||
IND_HEX_DIM, 17 /*INDIC_TEXTFORE*/);
|
IND_HEX_DIM, 17 /*INDIC_TEXTFORE*/);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
|
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
|
||||||
IND_HEX_DIM, QColor("#505050"));
|
IND_HEX_DIM, QColor("#505050"));
|
||||||
|
|
||||||
// Selection overlay — translucent blue box
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
|
|
||||||
IND_SELECTED, 8 /*INDIC_STRAIGHTBOX*/);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
|
|
||||||
IND_SELECTED, QColor("#264f78"));
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETALPHA,
|
|
||||||
IND_SELECTED, (long)50);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETOUTLINEALPHA,
|
|
||||||
IND_SELECTED, (long)100);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETUNDER,
|
|
||||||
IND_SELECTED, (long)1);
|
|
||||||
|
|
||||||
// Hover row highlight — very subtle fill
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
|
|
||||||
IND_HOVER, 16 /*INDIC_FULLBOX*/);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
|
|
||||||
IND_HOVER, QColor("#264f78"));
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETALPHA,
|
|
||||||
IND_HOVER, (long)25);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETOUTLINEALPHA,
|
|
||||||
IND_HOVER, (long)0);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETUNDER,
|
|
||||||
IND_HOVER, (long)1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RcxEditor::setupLexer() {
|
void RcxEditor::setupLexer() {
|
||||||
@@ -238,6 +211,14 @@ void RcxEditor::setupMarkers() {
|
|||||||
m_sci->markerDefine(QsciScintilla::Background, M_STRUCT_BG);
|
m_sci->markerDefine(QsciScintilla::Background, M_STRUCT_BG);
|
||||||
m_sci->setMarkerBackgroundColor(QColor("#1a2332"), M_STRUCT_BG);
|
m_sci->setMarkerBackgroundColor(QColor("#1a2332"), M_STRUCT_BG);
|
||||||
m_sci->setMarkerForegroundColor(QColor("#d4d4d4"), M_STRUCT_BG);
|
m_sci->setMarkerForegroundColor(QColor("#d4d4d4"), M_STRUCT_BG);
|
||||||
|
|
||||||
|
// M_HOVER (6): full-row hover highlight
|
||||||
|
m_sci->markerDefine(QsciScintilla::Background, M_HOVER);
|
||||||
|
m_sci->setMarkerBackgroundColor(QColor(43, 43, 43), M_HOVER);
|
||||||
|
|
||||||
|
// M_SELECTED (7): full-row selection highlight (higher = wins over hover)
|
||||||
|
m_sci->markerDefine(QsciScintilla::Background, M_SELECTED);
|
||||||
|
m_sci->setMarkerBackgroundColor(QColor(53, 53, 53), M_SELECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RcxEditor::allocateMarginStyles() {
|
void RcxEditor::allocateMarginStyles() {
|
||||||
@@ -324,6 +305,12 @@ void RcxEditor::applyFoldLevels(const QVector<LineMeta>& meta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void lineRangeNoEol(QsciScintilla* sci, int line, long& start, long& len) {
|
||||||
|
start = sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)line);
|
||||||
|
long end = sci->SendScintilla(QsciScintillaBase::SCI_GETLINEENDPOSITION, (unsigned long)line);
|
||||||
|
len = (end > start) ? (end - start) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
void RcxEditor::applyHexDimming(const QVector<LineMeta>& meta) {
|
void RcxEditor::applyHexDimming(const QVector<LineMeta>& meta) {
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_HEX_DIM);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_HEX_DIM);
|
||||||
for (int i = 0; i < meta.size(); i++) {
|
for (int i = 0; i < meta.size(); i++) {
|
||||||
@@ -331,10 +318,7 @@ void RcxEditor::applyHexDimming(const QVector<LineMeta>& meta) {
|
|||||||
case NodeKind::Hex8: case NodeKind::Hex16:
|
case NodeKind::Hex8: case NodeKind::Hex16:
|
||||||
case NodeKind::Hex32: case NodeKind::Hex64:
|
case NodeKind::Hex32: case NodeKind::Hex64:
|
||||||
case NodeKind::Padding: {
|
case NodeKind::Padding: {
|
||||||
long pos = m_sci->SendScintilla(
|
long pos, len; lineRangeNoEol(m_sci, i, pos, len);
|
||||||
QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)i);
|
|
||||||
long len = m_sci->SendScintilla(
|
|
||||||
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)i);
|
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
|
||||||
break;
|
break;
|
||||||
@@ -346,49 +330,23 @@ void RcxEditor::applyHexDimming(const QVector<LineMeta>& meta) {
|
|||||||
|
|
||||||
void RcxEditor::applySelectionOverlay(const QSet<uint64_t>& selIds) {
|
void RcxEditor::applySelectionOverlay(const QSet<uint64_t>& selIds) {
|
||||||
m_currentSelIds = selIds;
|
m_currentSelIds = selIds;
|
||||||
|
m_sci->markerDeleteAll(M_SELECTED);
|
||||||
// Clear all selection indicators
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_SELECTED);
|
|
||||||
long docLen = m_sci->SendScintilla(QsciScintillaBase::SCI_GETLENGTH);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, (uintptr_t)0, docLen);
|
|
||||||
|
|
||||||
if (selIds.isEmpty()) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < m_meta.size(); i++) {
|
for (int i = 0; i < m_meta.size(); i++) {
|
||||||
if (selIds.contains(m_meta[i].nodeId)) {
|
if (selIds.contains(m_meta[i].nodeId))
|
||||||
long pos = m_sci->SendScintilla(
|
m_sci->markerAdd(i, M_SELECTED);
|
||||||
QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)i);
|
|
||||||
long len = m_sci->SendScintilla(
|
|
||||||
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)i);
|
|
||||||
if (len > 0)
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh hover since selection may suppress it
|
|
||||||
applyHoverHighlight();
|
applyHoverHighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RcxEditor::applyHoverHighlight() {
|
void RcxEditor::applyHoverHighlight() {
|
||||||
// Clear previous hover indicator
|
m_sci->markerDeleteAll(M_HOVER);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_HOVER);
|
|
||||||
long docLen = m_sci->SendScintilla(QsciScintillaBase::SCI_GETLENGTH);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, (uintptr_t)0, docLen);
|
|
||||||
|
|
||||||
if (m_editState.active) return;
|
if (m_editState.active) return;
|
||||||
if (!m_hoverInside) return;
|
if (!m_hoverInside) return;
|
||||||
if (m_hoveredNodeId == 0) return;
|
if (m_hoveredNodeId == 0) return;
|
||||||
if (m_currentSelIds.contains(m_hoveredNodeId)) return;
|
if (m_currentSelIds.contains(m_hoveredNodeId)) return;
|
||||||
|
|
||||||
for (int i = 0; i < m_meta.size(); i++) {
|
for (int i = 0; i < m_meta.size(); i++) {
|
||||||
if (m_meta[i].nodeId == m_hoveredNodeId) {
|
if (m_meta[i].nodeId == m_hoveredNodeId)
|
||||||
long pos = m_sci->SendScintilla(
|
m_sci->markerAdd(i, M_HOVER);
|
||||||
QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)i);
|
|
||||||
long len = m_sci->SendScintilla(
|
|
||||||
QsciScintillaBase::SCI_LINELENGTH, (unsigned long)i);
|
|
||||||
if (len > 0)
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,6 +423,9 @@ RcxEditor::EndEditInfo RcxEditor::endInlineEdit() {
|
|||||||
EndEditInfo info{m_editState.nodeIdx, m_editState.subLine, m_editState.target};
|
EndEditInfo info{m_editState.nodeIdx, m_editState.subLine, m_editState.target};
|
||||||
m_editState.active = false;
|
m_editState.active = false;
|
||||||
m_sci->setReadOnly(true);
|
m_sci->setReadOnly(true);
|
||||||
|
// Disable selection rendering again
|
||||||
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELFORE, (long)0, (long)0);
|
||||||
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELBACK, (long)0, (long)0);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)1);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)1);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_EMPTYUNDOBUFFER);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_EMPTYUNDOBUFFER);
|
||||||
return info;
|
return info;
|
||||||
@@ -613,12 +574,40 @@ bool RcxEditor::eventFilter(QObject* obj, QEvent* event) {
|
|||||||
// Selection click — emit for controller to manage
|
// Selection click — emit for controller to manage
|
||||||
if (line >= 0 && line < m_meta.size()) {
|
if (line >= 0 && line < m_meta.size()) {
|
||||||
uint64_t nid = m_meta[line].nodeId;
|
uint64_t nid = m_meta[line].nodeId;
|
||||||
if (nid != 0)
|
if (nid != 0) {
|
||||||
emit nodeClicked(line, nid, me->modifiers());
|
emit nodeClicked(line, nid, me->modifiers());
|
||||||
|
m_dragging = true;
|
||||||
|
m_dragLastLine = line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Drag-select: extend selection as mouse moves with button held
|
||||||
|
if (obj == m_sci->viewport() && !m_editState.active
|
||||||
|
&& event->type() == QEvent::MouseMove && m_dragging) {
|
||||||
|
auto* me = static_cast<QMouseEvent*>(event);
|
||||||
|
if (me->buttons() & Qt::LeftButton) {
|
||||||
|
long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE,
|
||||||
|
(unsigned long)me->pos().x(), (long)me->pos().y());
|
||||||
|
if (pos >= 0) {
|
||||||
|
int line = (int)m_sci->SendScintilla(
|
||||||
|
QsciScintillaBase::SCI_LINEFROMPOSITION, (unsigned long)pos);
|
||||||
|
if (line >= 0 && line < m_meta.size() && line != m_dragLastLine) {
|
||||||
|
uint64_t nid = m_meta[line].nodeId;
|
||||||
|
if (nid != 0) {
|
||||||
|
emit nodeClicked(line, nid, Qt::ShiftModifier);
|
||||||
|
m_dragLastLine = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_dragging = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj == m_sci->viewport() && event->type() == QEvent::MouseButtonRelease) {
|
||||||
|
m_dragging = false;
|
||||||
|
}
|
||||||
if (obj == m_sci->viewport() && !m_editState.active
|
if (obj == m_sci->viewport() && !m_editState.active
|
||||||
&& event->type() == QEvent::MouseButtonDblClick) {
|
&& event->type() == QEvent::MouseButtonDblClick) {
|
||||||
auto* me = static_cast<QMouseEvent*>(event);
|
auto* me = static_cast<QMouseEvent*>(event);
|
||||||
@@ -639,8 +628,7 @@ bool RcxEditor::eventFilter(QObject* obj, QEvent* event) {
|
|||||||
}
|
}
|
||||||
// Clear underlines when editor loses focus
|
// Clear underlines when editor loses focus
|
||||||
if (m_hintLine >= 0) {
|
if (m_hintLine >= 0) {
|
||||||
long start = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)m_hintLine);
|
long start, len; lineRangeNoEol(m_sci, m_hintLine, start, len);
|
||||||
long len = m_sci->SendScintilla(QsciScintillaBase::SCI_LINELENGTH, (unsigned long)m_hintLine);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, start, len);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, start, len);
|
||||||
m_hintLine = -1;
|
m_hintLine = -1;
|
||||||
@@ -815,6 +803,11 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
|
|||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)0);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)0);
|
||||||
m_sci->setReadOnly(false);
|
m_sci->setReadOnly(false);
|
||||||
|
|
||||||
|
// Re-enable selection rendering for inline edit
|
||||||
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELFORE, (long)0, (long)0);
|
||||||
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELBACK, (long)1,
|
||||||
|
QColor("#264f78"));
|
||||||
|
|
||||||
// Select just the trimmed text (keeps columns aligned)
|
// Select just the trimmed text (keeps columns aligned)
|
||||||
long lineStart = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,
|
long lineStart = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,
|
||||||
(unsigned long)line);
|
(unsigned long)line);
|
||||||
@@ -902,8 +895,7 @@ void RcxEditor::updateEditableUnderline(int line) {
|
|||||||
|
|
||||||
auto clearLine = [&](int l) {
|
auto clearLine = [&](int l) {
|
||||||
if (l < 0) return;
|
if (l < 0) return;
|
||||||
long start = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, (unsigned long)l);
|
long start, len; lineRangeNoEol(m_sci, l, start, len);
|
||||||
long len = m_sci->SendScintilla(QsciScintillaBase::SCI_LINELENGTH, (unsigned long)l);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_SETINDICATORCURRENT, IND_EDITABLE);
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, start, len);
|
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORCLEARRANGE, start, len);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ private:
|
|||||||
uint64_t m_hoveredNodeId = 0;
|
uint64_t m_hoveredNodeId = 0;
|
||||||
QSet<uint64_t> m_currentSelIds;
|
QSet<uint64_t> m_currentSelIds;
|
||||||
|
|
||||||
|
// ── Drag selection ──
|
||||||
|
bool m_dragging = false;
|
||||||
|
int m_dragLastLine = -1;
|
||||||
|
|
||||||
// ── Inline edit state ──
|
// ── Inline edit state ──
|
||||||
struct InlineEditState {
|
struct InlineEditState {
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user