diff options
| -rw-r--r-- | idatui/app.py | 20 | ||||
| -rw-r--r-- | tests/test_scenarios.py | 9 |
2 files changed, 25 insertions, 4 deletions
diff --git a/idatui/app.py b/idatui/app.py index 5314f66..3b84217 100644 --- a/idatui/app.py +++ b/idatui/app.py @@ -1680,6 +1680,26 @@ class HexView(ScrollView, can_focus=True): top = max(0, min(top, max(self.total - 1, 0))) self._apply_scroll(top) + def watch_scroll_y(self, old_value: float, new_value: float) -> None: + super().watch_scroll_y(old_value, new_value) + # Follow the scroll: a wheel-scroll / scrollbar drag drags the byte cursor + # along so it stays visible (pinned to the nearest edge row, same column). + if round(old_value) != round(new_value): + self._follow_scroll(round(new_value)) + + def _follow_scroll(self, top: int) -> None: + if self.model is None or self.model.size == 0: + return + height = self._visible_height() + row, col = self.cursor // 16, self.cursor % 16 + new_row = min(max(row, top), top + max(height - 1, 0)) + new_row = max(0, min(new_row, max(self.total - 1, 0))) + new_cursor = max(0, min(new_row * 16 + col, self.model.size - 1)) + if new_cursor != self.cursor: + self.cursor = new_cursor + self.refresh() # cursor is reactive(repaint=False) + self.post_message(HexView.Moved(self.cursor_va())) + # -- navigation -------------------------------------------------------- # def _move(self, delta: int) -> None: if self.model is None or self.model.size == 0: diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py index 92c6315..4731a16 100644 --- a/tests/test_scenarios.py +++ b/tests/test_scenarios.py @@ -511,12 +511,13 @@ async def s_hex(c: Ctx): await c.type(hex(rng[0])) await c.press("enter") await c.wait(lambda: hx.cursor_va() == rng[0], 10) - hx.scroll_to(y=40, animate=False) # wheel-style scroll: viewport only + hx.scroll_to(y=40, animate=False) # wheel-style scroll await c.pause(0.15) top = round(hx.scroll_offset.y) - c.check("hex viewport scrolls without dragging the cursor along", - top >= 20 and (hx.cursor // 16) < top, - f"top={top} cursor_row={hx.cursor // 16}") + height = hx._visible_height() + c.check("hex cursor follows the scroll (stays visible)", + top >= 20 and top <= (hx.cursor // 16) < top + height, + f"top={top} cursor_row={hx.cursor // 16} height={height}") PAD = 1 # HexView { padding: 0 1 } -> content is inset one col await c.pilot.click(HexView, offset=(PAD + 19 + 3 * 3, 5)) # hex byte 3, row 5 await c.pause(0.1) |
