Skip to content

Commit d64d858

Browse files
committed
Make mouse handling to the terminal by default; use --mouse for letting b2view capture it instead.
1 parent d3b2c1b commit d64d858

3 files changed

Lines changed: 50 additions & 21 deletions

File tree

doc/getting_started/b2view.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ left, and **meta**, **vlmeta** and **data** panels for the node selected
4242
in the tree. Move between panels with ``tab`` / ``shift+tab``, maximize
4343
the focused one with ``m`` (``r`` restores it), and quit with ``q``.
4444

45+
By default the mouse is left to the terminal, so selecting and copying text
46+
works as in any other command line program. Pass ``--mouse`` to let b2view
47+
capture it instead: panels become clickable and the wheel scrolls the data
48+
grid (paging at the boundaries), at the cost of native text selection.
49+
4550
You can also jump straight to a node and panel:
4651

4752
.. code-block:: console

src/blosc2/b2view/app.py

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, ClassVar
5+
from typing import TYPE_CHECKING, Any, ClassVar
66

77
from textual.app import App, ComposeResult
88
from textual.binding import Binding
@@ -18,6 +18,9 @@
1818
make_preview_renderables,
1919
)
2020

21+
if TYPE_CHECKING:
22+
from textual import events
23+
2124
_KIND_ICONS = {
2225
"group": "📁",
2326
"ndarray": "▦",
@@ -105,6 +108,26 @@ def action_select_cursor(self) -> None:
105108
return
106109
super().action_select_cursor()
107110

111+
def _wheel_step(self) -> int:
112+
# Half the visible rows per tick; arrow keys remain the
113+
# single-step path (also for dim-mode index changes).
114+
return max(1, self.row_count // 2)
115+
116+
def on_mouse_scroll_down(self, event: events.MouseScrollDown) -> None:
117+
# The grid holds exactly one viewport-sized page, so the default
118+
# scroll handler has nothing to scroll; move the cursor instead,
119+
# which pages at the edges just like the arrow keys.
120+
event.stop()
121+
event.prevent_default()
122+
for _ in range(self._wheel_step()):
123+
self.action_cursor_down()
124+
125+
def on_mouse_scroll_up(self, event: events.MouseScrollUp) -> None:
126+
event.stop()
127+
event.prevent_default()
128+
for _ in range(self._wheel_step()):
129+
self.action_cursor_up()
130+
108131
def on_resize(self, event) -> None:
109132
# The column/row windows are fitted to this table's size; re-check
110133
# whenever it changes (terminal resize, panel maximize, ...).
@@ -1231,7 +1254,7 @@ def action_refresh(self) -> None:
12311254
def _adjust_fixed_value(self, direction: int) -> None:
12321255
"""Adjust the fixed value of the active dimension (if it is fixed).
12331256
1234-
In DIM mode the value wraps around at boundaries (0 ↔ max).
1257+
The value clamps at the boundaries (no wrap-around).
12351258
"""
12361259
layout = self._data_layout
12371260
if layout is None or self.table_page is None:
@@ -1243,19 +1266,9 @@ def _adjust_fixed_value(self, direction: int) -> None:
12431266
if total <= 0:
12441267
return
12451268
current = layout.fixed_values[dim]
1246-
if self._dim_mode and total > 1:
1247-
# Cycle: up at max → 0, down at 0 → max-1
1248-
new_val = (current + direction) % total
1249-
else:
1250-
# Clamp at boundaries (normal mode)
1251-
if direction > 0:
1252-
if current >= total - 1:
1253-
return
1254-
new_val = current + 1
1255-
else:
1256-
if current <= 0:
1257-
return
1258-
new_val = current - 1
1269+
new_val = min(max(current + direction, 0), total - 1)
1270+
if new_val == current:
1271+
return
12591272
new_fixed = dict(layout.fixed_values)
12601273
new_fixed[dim] = new_val
12611274
self._data_layout = layout.copy_with(fixed_values=new_fixed)
@@ -1335,7 +1348,7 @@ def _dim_adjust(self, direction: int) -> None:
13351348
self._scroll_navigable_viewport(direction)
13361349

13371350
def _scroll_navigable_viewport(self, direction: int) -> None:
1338-
"""Shift the viewport of a navigable dimension by one step (wraps)."""
1351+
"""Shift the viewport of a navigable dimension by one step (clamps)."""
13391352
layout = self._data_layout
13401353
if layout is None or self.table_page is None:
13411354
return
@@ -1348,13 +1361,19 @@ def _scroll_navigable_viewport(self, direction: int) -> None:
13481361
total = layout.shape[dim]
13491362

13501363
if pos == 0:
1351-
# Row navigable dim — shift start by one row (wraps)
1352-
new_start = (page["start"] + direction) % total
1364+
# Row navigable dim — shift start by one row, keeping a full page
1365+
max_start = max(0, total - self._table_page_size())
1366+
new_start = min(max(page["start"] + direction, 0), max_start)
1367+
if new_start == page["start"]:
1368+
return
13531369
self.table_buffer = None
13541370
data = self._load_table_page(self.selected_path, new_start)
13551371
else:
1356-
# Column navigable dim — shift col_start by one column (wraps)
1357-
new_col = (page["col_start"] + direction) % total
1372+
# Column navigable dim — shift col_start by one whole column
1373+
max_col = self._fit_col_start_backward(total)
1374+
new_col = min(max(page["col_start"] + direction, 0), max_col)
1375+
if new_col == page["col_start"]:
1376+
return
13581377
self.grid_col_start = new_col
13591378
self.table_buffer = None
13601379
data = self._load_table_page(self.selected_path, page["start"])

src/blosc2/b2view/cli.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ def build_parser() -> argparse.ArgumentParser:
1818
default="tree",
1919
help="Panel to focus on startup",
2020
)
21+
parser.add_argument(
22+
"--mouse",
23+
action="store_true",
24+
help="Capture the mouse for clicking and scrolling (disables the terminal's native text selection)",
25+
)
2126
return parser
2227

2328

@@ -40,7 +45,7 @@ def main(argv: list[str] | None = None) -> int:
4045
preview_rows=args.preview_rows,
4146
preview_cols=args.preview_cols,
4247
)
43-
app.run()
48+
app.run(mouse=args.mouse)
4449
return 0
4550

4651

0 commit comments

Comments
 (0)