aboutsummaryrefslogtreecommitdiffstats
path: root/idatui
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 14:17:20 +0200
committerblasty <blasty@local>2026-07-09 14:17:20 +0200
commit29326c9c88a62532fd5aeb76302075ab138c5887 (patch)
treecab35eee55256dd4565f18f878b9a97aabe79081 /idatui
parentcolumn cursor: real left/right movement + follow the ref UNDER the cursor (diff)
downloadida-tui-29326c9c88a62532fd5aeb76302075ab138c5887.tar.gz
ida-tui-29326c9c88a62532fd5aeb76302075ab138c5887.tar.xz
ida-tui-29326c9c88a62532fd5aeb76302075ab138c5887.zip
mouse: click to place cursor, double-click to follow
- ColumnCursor.on_click maps the click to a virtual (line, column) via event.get_content_offset (handles padding/border) + scroll_offset, then places the line+column cursor (disasm posts CursorMoved for the status line). - double-click (event.chain>=2) = place cursor + follow the symbol under it, identical to selecting it and pressing Enter. - works in both views (verified: disasm click on 'call sub_XXXX' lands on the exact token; pseudocode click maps columns with no padding). - pilot suite 36/36.
Diffstat (limited to 'idatui')
-rw-r--r--idatui/app.py32
1 files changed, 32 insertions, 0 deletions
diff --git a/idatui/app.py b/idatui/app.py
index d8900c0..49156e6 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -253,6 +253,35 @@ class ColumnCursor:
s, e = _word_bounds(plain, min(self.cursor_x, len(plain) - 1))
return plain[s:e] or None
+ # -- mouse ------------------------------------------------------------- #
+ def _after_cursor_move(self) -> None:
+ pass
+
+ def _set_cursor_at(self, line: int, col: int) -> None:
+ total = self.total
+ if total <= 0:
+ return
+ self.cursor = max(0, min(total - 1, line))
+ plain = self._line_plain(self.cursor)
+ maxx = max(len(plain) - 1, 0) if plain is not None else col
+ self.cursor_x = max(0, min(maxx, col))
+ self._scroll_cursor_into_view()
+ self._hscroll()
+ self.refresh()
+ self._after_cursor_move()
+
+ def on_click(self, event) -> None: # type: ignore[no-untyped-def]
+ off = event.get_content_offset(self)
+ if off is None:
+ return
+ line = round(self.scroll_offset.y) + off.y
+ if line >= self.total:
+ return
+ self.focus()
+ self._set_cursor_at(line, round(self.scroll_offset.x) + off.x)
+ if event.chain >= 2: # double-click == place cursor + follow
+ self.post_message(FollowRequested(self))
+
class SearchMixin:
"""Vim-style in-view search shared by the disasm and pseudocode views.
@@ -617,6 +646,9 @@ class DisasmView(SearchMixin, NavMixin, ColumnCursor, ScrollView, can_focus=True
_refresh_lines(self, old, self.cursor) # only the two changed rows
self.post_message(DisasmView.CursorMoved(self.cursor, self._cursor_ea()))
+ def _after_cursor_move(self) -> None:
+ self.post_message(DisasmView.CursorMoved(self.cursor, self._cursor_ea()))
+
def _cursor_ea(self) -> int | None:
if self.model is None:
return None