| 2130 | } |
| 2131 | |
| 2132 | void RcxEditor::updateEditableIndicators(int line) { |
| 2133 | if (m_editState.active) return; |
| 2134 | if (line == m_hintLine) return; |
| 2135 | |
| 2136 | // No cursor hints when selection is empty (prevents desync during batch ops) |
| 2137 | if (m_currentSelIds.isEmpty()) { |
| 2138 | if (m_hintLine >= 0) { |
| 2139 | clearIndicatorLine(IND_EDITABLE, m_hintLine); |
| 2140 | m_hintLine = -1; |
| 2141 | } |
| 2142 | return; |
| 2143 | } |
| 2144 | |
| 2145 | // Helper to check if a line's node is selected (handles footer IDs) |
| 2146 | auto isLineSelected = [this](const LineMeta* lm) -> bool { |
| 2147 | if (!lm) return false; |
| 2148 | bool isFooter = (lm->lineKind == LineKind::Footer); |
| 2149 | uint64_t checkId = isFooter ? (lm->nodeId | kFooterIdBit) : lm->nodeId; |
| 2150 | return m_currentSelIds.contains(checkId); |
| 2151 | }; |
| 2152 | |
| 2153 | // If new line is selected, its indicators are managed by applySelectionOverlay |
| 2154 | // But we still need to clear the old non-selected hint line |
| 2155 | const LineMeta* newLm = metaForLine(line); |
| 2156 | if (isLineSelected(newLm)) { |
| 2157 | if (m_hintLine >= 0) { |
| 2158 | const LineMeta* oldLm = metaForLine(m_hintLine); |
| 2159 | if (!isLineSelected(oldLm)) |
| 2160 | clearIndicatorLine(IND_EDITABLE, m_hintLine); |
| 2161 | } |
| 2162 | m_hintLine = line; |
| 2163 | return; |
| 2164 | } |
| 2165 | |
| 2166 | // Clear old cursor line (only if not a selected node) |
| 2167 | if (m_hintLine >= 0) { |
| 2168 | const LineMeta* oldLm = metaForLine(m_hintLine); |
| 2169 | if (!isLineSelected(oldLm)) |
| 2170 | clearIndicatorLine(IND_EDITABLE, m_hintLine); |
| 2171 | } |
| 2172 | |
| 2173 | m_hintLine = line; |
| 2174 | paintEditableSpans(line); |
| 2175 | } |
| 2176 | |
| 2177 | // ── Hover cursor ── |
| 2178 |
nothing calls this directly
no outgoing calls
no test coverage detected