| 1091 | // ── Point → line/col/nodeId resolution ── |
| 1092 | |
| 1093 | RcxEditor::HitInfo RcxEditor::hitTest(const QPoint& vp) const { |
| 1094 | HitInfo h; |
| 1095 | |
| 1096 | // Try precise position first (works when cursor is over actual text) |
| 1097 | long pos = m_sci->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINTCLOSE, |
| 1098 | (unsigned long)vp.x(), (long)vp.y()); |
| 1099 | if (pos >= 0) { |
| 1100 | h.line = (int)m_sci->SendScintilla( |
| 1101 | QsciScintillaBase::SCI_LINEFROMPOSITION, (unsigned long)pos); |
| 1102 | h.col = (int)m_sci->SendScintilla( |
| 1103 | QsciScintillaBase::SCI_GETCOLUMN, (unsigned long)pos); |
| 1104 | } else { |
| 1105 | // Fallback: calculate line from Y coordinate (for empty space past text) |
| 1106 | int firstVisible = (int)m_sci->SendScintilla( |
| 1107 | QsciScintillaBase::SCI_GETFIRSTVISIBLELINE); |
| 1108 | int lineHeight = (int)m_sci->SendScintilla( |
| 1109 | QsciScintillaBase::SCI_TEXTHEIGHT, 0); |
| 1110 | if (lineHeight > 0) |
| 1111 | h.line = firstVisible + vp.y() / lineHeight; |
| 1112 | } |
| 1113 | |
| 1114 | if (h.line >= 0 && h.line < m_meta.size()) { |
| 1115 | h.nodeId = m_meta[h.line].nodeId; |
| 1116 | h.inFoldCol = (h.col >= 0 && h.col < kFoldCol + 1 && m_meta[h.line].foldHead); |
| 1117 | } |
| 1118 | return h; |
| 1119 | } |
| 1120 | |
| 1121 | // ── Double-click hit test ── |
| 1122 | |