mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Inline edit UX improvements: selection clamping, auto-select, validation fixes
- Constrain selection/cursor to edit span boundaries during inline edit - Auto-select entire text when entering edit mode (Name, Value, Type) - Double-click during edit selects entire editable text - Fix vector component validation (subLine >= 0 for x component) - Accept EU decimal separator (comma) for float parsing - Darker selection highlight (35,35,35) vs hover (43,43,43) - Remove blue text indicator, use hidden style - Fix validation error message display Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -86,6 +86,9 @@ RcxEditor::RcxEditor(QWidget* parent) : QWidget(parent) {
|
||||
if (m_editState.target == EditTarget::Value)
|
||||
QTimer::singleShot(0, this, &RcxEditor::validateEditLive);
|
||||
});
|
||||
|
||||
connect(m_sci, &QsciScintilla::selectionChanged,
|
||||
this, &RcxEditor::clampEditSelection);
|
||||
}
|
||||
|
||||
void RcxEditor::setupScintilla() {
|
||||
@@ -116,11 +119,9 @@ void RcxEditor::setupScintilla() {
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELFORE, (long)0, (long)0);
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELBACK, (long)0, (long)0);
|
||||
|
||||
// Editable-field link-style indicator (colored text)
|
||||
// Editable-field indicator - set to HIDDEN (no visual, avoids INDIC_PLAIN underline)
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
|
||||
IND_EDITABLE, 17 /*INDIC_TEXTFORE*/);
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,
|
||||
IND_EDITABLE, QColor("#569cd6"));
|
||||
IND_EDITABLE, 5 /*INDIC_HIDDEN*/);
|
||||
|
||||
// Hex/Padding node dim indicator — overrides text color to gray
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
|
||||
@@ -232,7 +233,7 @@ void RcxEditor::setupMarkers() {
|
||||
|
||||
// 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);
|
||||
m_sci->setMarkerBackgroundColor(QColor(35, 35, 35), M_SELECTED);
|
||||
}
|
||||
|
||||
void RcxEditor::allocateMarginStyles() {
|
||||
@@ -753,9 +754,11 @@ bool RcxEditor::eventFilter(QObject* obj, QEvent* event) {
|
||||
m_pendingClickNodeId = 0;
|
||||
}
|
||||
}
|
||||
// Block double/triple-click during edit mode (prevents word/line selection)
|
||||
// Double-click during edit mode: select entire editable text
|
||||
if (obj == m_sci->viewport() && m_editState.active
|
||||
&& event->type() == QEvent::MouseButtonDblClick) {
|
||||
m_sci->setSelection(m_editState.line, m_editState.spanStart,
|
||||
m_editState.line, editEndCol());
|
||||
return true;
|
||||
}
|
||||
if (obj == m_sci->viewport() && !m_editState.active
|
||||
@@ -931,7 +934,7 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
|
||||
m_editState.linelenAfterReplace = lineText.size();
|
||||
m_editState.editKind = lm->nodeKind;
|
||||
if ((lm->nodeKind == NodeKind::Vec2 || lm->nodeKind == NodeKind::Vec3 ||
|
||||
lm->nodeKind == NodeKind::Vec4) && lm->subLine > 0)
|
||||
lm->nodeKind == NodeKind::Vec4) && lm->subLine >= 0)
|
||||
m_editState.editKind = NodeKind::Float;
|
||||
|
||||
// Store fixed comment column position for value editing
|
||||
@@ -964,7 +967,7 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
|
||||
(unsigned long)line);
|
||||
long posStart = lineStart + m_editState.spanStart;
|
||||
long posEnd = posStart + trimmed.toUtf8().size();
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSEL, posEnd, posEnd);
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSEL, posStart, posEnd);
|
||||
|
||||
// Show initial edit hint in comment column
|
||||
if (target == EditTarget::Value)
|
||||
@@ -982,6 +985,50 @@ int RcxEditor::editEndCol() const {
|
||||
return m_editState.spanStart + m_editState.original.size() + delta;
|
||||
}
|
||||
|
||||
void RcxEditor::clampEditSelection() {
|
||||
if (!m_editState.active) return;
|
||||
|
||||
static bool s_clamping = false;
|
||||
if (s_clamping) return;
|
||||
s_clamping = true;
|
||||
|
||||
int selStartLine, selStartCol, selEndLine, selEndCol;
|
||||
m_sci->getSelection(&selStartLine, &selStartCol, &selEndLine, &selEndCol);
|
||||
|
||||
int editEnd = editEndCol();
|
||||
bool isCursor = (selStartLine == selEndLine && selStartCol == selEndCol);
|
||||
|
||||
if (isCursor) {
|
||||
// Cursor positioning (no selection) - only clamp if outside bounds
|
||||
if (selStartLine != m_editState.line ||
|
||||
selStartCol < m_editState.spanStart || selStartCol > editEnd) {
|
||||
int clampedCol = qBound(m_editState.spanStart, selStartCol, editEnd);
|
||||
m_sci->setCursorPosition(m_editState.line, clampedCol);
|
||||
}
|
||||
} else {
|
||||
// Actual selection - clamp both ends to edit span
|
||||
bool clamped = false;
|
||||
|
||||
// Force to edit line
|
||||
if (selStartLine != m_editState.line || selEndLine != m_editState.line) {
|
||||
m_sci->setSelection(m_editState.line, m_editState.spanStart,
|
||||
m_editState.line, editEnd);
|
||||
s_clamping = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (selStartCol < m_editState.spanStart) { selStartCol = m_editState.spanStart; clamped = true; }
|
||||
if (selEndCol < m_editState.spanStart) { selEndCol = m_editState.spanStart; clamped = true; }
|
||||
if (selStartCol > editEnd) { selStartCol = editEnd; clamped = true; }
|
||||
if (selEndCol > editEnd) { selEndCol = editEnd; clamped = true; }
|
||||
|
||||
if (clamped)
|
||||
m_sci->setSelection(selStartLine, selStartCol, selEndLine, selEndCol);
|
||||
}
|
||||
|
||||
s_clamping = false;
|
||||
}
|
||||
|
||||
// ── Commit inline edit ──
|
||||
|
||||
void RcxEditor::commitInlineEdit() {
|
||||
@@ -1015,11 +1062,7 @@ void RcxEditor::showTypeAutocomplete() {
|
||||
if (!m_editState.active || m_editState.target != EditTarget::Type)
|
||||
return;
|
||||
|
||||
// Collapse selection to start — old type text stays visible
|
||||
long lineStart = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,
|
||||
(unsigned long)m_editState.line);
|
||||
long posStart = lineStart + m_editState.spanStart;
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_GOTOPOS, posStart);
|
||||
// Selection stays intact - typing/autocomplete will replace selected text
|
||||
|
||||
// Build list from typeName (matches what the editor displays)
|
||||
QByteArray list = allTypeNamesForUI().join(' ').toUtf8();
|
||||
@@ -1179,7 +1222,7 @@ void RcxEditor::validateEditLive() {
|
||||
} else {
|
||||
if (isSelected) m_sci->markerDelete(m_editState.line, M_SELECTED);
|
||||
m_sci->markerAdd(m_editState.line, M_ERR);
|
||||
if (stateChanged) setEditComment("! " + text);
|
||||
if (stateChanged) setEditComment("! " + errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user