Skip to content

Commit 24e54db

Browse files
authored
feat: tabbed left panel (#200)
* chore: use yield for content switcher Signed-off-by: Henry Schreiner <[email protected]> * fix: esc will also quit Signed-off-by: Henry Schreiner <[email protected]> * feat: add tabs for the left panel Signed-off-by: Henry Schreiner <[email protected]> * fix: pylint broken Signed-off-by: Henry Schreiner <[email protected]> --------- Signed-off-by: Henry Schreiner <[email protected]>
1 parent 65061ee commit 24e54db

File tree

8 files changed

+77
-48
lines changed

8 files changed

+77
-48
lines changed

noxfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def pylint(session: nox.Session) -> None:
2626
"""
2727

2828
session.install("-e.", "pylint", "matplotlib")
29-
session.run("pylint", "src", *session.posargs)
29+
session.run("pylint", "uproot_browser", *session.posargs)
3030

3131

3232
@nox.session

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ ignore_missing_imports = true
104104

105105

106106
[tool.pylint]
107-
master.py-version = "3.9"
108-
master.jobs = "0"
107+
py-version = "3.9"
108+
jobs = "1"
109109
reports.output-format = "colorized"
110110
similarities.ignore-imports = "yes"
111111
messages_control.enable = [

src/uproot_browser/tui/README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,28 @@ something to plot. Press `spacebar` to open/close a directory or tree. You can
99
also use the VIM keys: `j` to move down, `k` to move up, `l` to open a folder,
1010
and `h` to close a folder.
1111

12+
You can also open the command palette with `ctrl-p`, which gives you some
13+
options like changing the theme, writing out an SVG, or quitting the program.
14+
1215
## Plotting
1316

1417
Histograms, rectangular simple data (e.g. TTree's), and jagged arrays can
1518
be plotted. Click on an item or press `enter` to plot. If something can't
1619
be plotted, you'll see a scrollable error traceback. If you think it should
1720
be plottable, feel free to open an issue. 2D plots are not yet supported.
1821

19-
## Themes
22+
## Tools
23+
24+
The panel on the left (which can be hidden/shown with `b` has tabs; the `Tree`
25+
tab is the default, but you can also select `Tools`, which has a theme
26+
selector, and an Info tab, which gives the versions of installed packages.
2027

21-
You can press `t` to toggle light and dark mode.
2228

2329
## Leaving
2430

25-
You can press `q` to quit. You can also press `d` to quit with a dump of the
26-
current plot and how to get the object being plotted in Python uproot code.
31+
You can press `q` or `esc` to quit. You can also press `d` to quit with a dump
32+
of the current plot and how to get the object being plotted in Python uproot
33+
code.
2734

2835
## Exiting the help.
2936

src/uproot_browser/tui/browser.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Browser Widget {
88
scrollbar-size: 1 1;
99
}
1010

11-
#tree-view {
11+
#left-view {
1212
display: none;
1313
overflow: auto;
1414
width: 25%;
@@ -21,7 +21,7 @@ Tree > .tree--cursor {
2121
text-style: bold;
2222
}
2323

24-
Browser.-show-tree #tree-view {
24+
Browser.-show-panel #left-view {
2525
display: block;
2626
max-width: 50%;
2727
}
@@ -50,6 +50,14 @@ ContentSwitcher#main-view {
5050
content-align: center middle;
5151
}
5252

53+
Info {
54+
overflow: scroll;
55+
}
56+
57+
Tools {
58+
overflow: scroll;
59+
}
60+
5361
Footer > .footer--highlight {
5462
background: $secondary-darken-2;
5563
}

src/uproot_browser/tui/browser.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
PlotWidget,
4747
make_plot,
4848
)
49+
from .tools import Info, Tools
4950

5051

5152
class Browser(textual.app.App[object]):
@@ -58,12 +59,13 @@ class Browser(textual.app.App[object]):
5859
textual.binding.Binding("b", "toggle_files", "Navbar"),
5960
textual.binding.Binding("q", "quit", "Quit"),
6061
textual.binding.Binding("d", "quit_with_dump", "Dump & Quit"),
61-
textual.binding.Binding("t", "toggle_theme", "Theme"),
6262
textual.binding.Binding("f1", "help", "Help"),
6363
textual.binding.Binding("?", "help", "Help", show=False),
64+
textual.binding.Binding("escape", "quit", "Quit", show=False),
6465
]
6566

6667
show_tree = var(True)
68+
show_tools = var(False)
6769

6870
def __init__(self, path: str, **kwargs: Any) -> None:
6971
self.path = path
@@ -77,24 +79,27 @@ def compose(self) -> textual.app.ComposeResult:
7779
yield Header("uproot-browser")
7880
with textual.containers.Container():
7981
# left_panel
80-
yield UprootTree(self.path, id="tree-view")
81-
# right_panel
82-
yield textual.widgets.ContentSwitcher(
83-
LogoWidget(id="logo"),
84-
self.plot_widget,
85-
self.error_widget,
86-
EmptyWidget(id="empty"),
87-
id="main-view",
88-
initial="logo",
89-
)
82+
with textual.widgets.TabbedContent(id="left-view"):
83+
with textual.widgets.TabPane("Tree"):
84+
yield UprootTree(self.path, id="tree-view")
85+
with textual.widgets.TabPane("Tools"):
86+
yield Tools()
87+
with textual.widgets.TabPane("Info"):
88+
yield Info()
89+
# main_panel
90+
with textual.widgets.ContentSwitcher(id="main-view", initial="logo"):
91+
yield LogoWidget(id="logo")
92+
yield self.plot_widget
93+
yield self.error_widget
94+
yield EmptyWidget(id="empty")
9095
yield textual.widgets.Footer()
9196

9297
def on_mount(self, _event: textual.events.Mount) -> None:
93-
self.query_one("#tree-view", UprootTree).focus()
98+
self.query_one("#tree-view").focus()
9499

95100
def watch_show_tree(self, show_tree: bool) -> None:
96101
"""Called when show_tree is modified."""
97-
self.set_class(show_tree, "-show-tree")
102+
self.set_class(show_tree, "-show-panel")
98103

99104
def action_help(self) -> None:
100105
self.push_screen(HelpScreen())
@@ -133,14 +138,10 @@ def action_quit_with_dump(self) -> None:
133138

134139
self.exit(message=results)
135140

136-
def action_toggle_theme(self) -> None:
137-
"""An action to toggle dark mode."""
138-
dark = self.theme != "textual-light"
139-
theme = "textual-light" if dark else "textual-dark"
140-
141+
def watch_theme(self, _old: str, new: str) -> None:
142+
dark = not new.endswith("-light")
141143
if self.plot_widget.item:
142-
self.plot_widget.item.theme = "default" if dark else "dark"
143-
self.theme = theme
144+
self.plot_widget.item.theme = "dark" if dark else "default"
144145

145146
def on_uproot_selected(self, message: UprootSelected) -> None:
146147
"""A message sent by the tree when a file is clicked."""

src/uproot_browser/tui/help.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ class HelpScreen(textual.screen.ModalScreen[None]):
2222
textual.binding.Binding("b", "", "Nothing", show=False),
2323
textual.binding.Binding("f1", "", "Nothing", show=False),
2424
textual.binding.Binding("q", "done", "Done", show=True),
25-
textual.binding.Binding("esc", "done", "Done", show=True),
26-
textual.binding.Binding("t", "toggle_theme", "Theme", show=True),
25+
textual.binding.Binding("escape", "done", "Done", show=True),
2726
]
2827

2928
app: Browser
@@ -43,6 +42,3 @@ def on_button_pressed(self, _event: textual.widgets.Button.Pressed) -> None:
4342

4443
def action_done(self) -> None:
4544
self.app.pop_screen()
46-
47-
def action_toggle_theme(self) -> None:
48-
self.app.action_toggle_theme()

src/uproot_browser/tui/tools.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import importlib.metadata
2+
3+
import textual.containers
4+
import textual.widgets
5+
6+
from .. import __version__
7+
8+
9+
class Tools(textual.containers.Container):
10+
def compose(self) -> textual.app.ComposeResult:
11+
yield textual.widgets.Label("Tools")
12+
with textual.widgets.Collapsible(title="Theme", collapsed=False):
13+
themes = self.app.available_themes
14+
yield textual.widgets.Select([(t, t) for t in themes])
15+
16+
@textual.on(textual.widgets.Select.Changed)
17+
def select_changed(self, event: textual.widgets.Select.Changed) -> None:
18+
# pylint: disable-next=attribute-defined-outside-init
19+
self.app.theme = str(event.value)
20+
21+
22+
class Info(textual.containers.Container):
23+
def compose(self) -> textual.app.ComposeResult:
24+
yield textual.widgets.Label("Info")
25+
with textual.widgets.Collapsible(title="uproot-browser", collapsed=False):
26+
yield textual.widgets.Label(f"Version: [green]{__version__}[/green]")
27+
with textual.widgets.Collapsible(title="Packages", collapsed=False):
28+
for dist in importlib.metadata.distributions():
29+
yield textual.widgets.Label(
30+
f"{dist.metadata['Name']} == [green]{dist.version}[/green]"
31+
)

tests/test_tui.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,6 @@ async def test_browse_plot() -> None:
1818
assert pilot.app.query_one("#main-view").current == "plot"
1919

2020

21-
async def test_theme_switch() -> None:
22-
async with Browser(
23-
skhep_testdata.data_path("uproot-Event.root")
24-
).run_test() as pilot:
25-
await pilot.press("down", "down", "down", "enter")
26-
browser_theme = pilot.app.theme
27-
plot_theme = pilot.app.theme
28-
await pilot.press("t")
29-
new_browser_theme = pilot.app.theme
30-
new_plot_theme = pilot.app.theme
31-
assert browser_theme != new_browser_theme
32-
assert plot_theme != new_plot_theme
33-
34-
3521
async def test_browse_empty() -> None:
3622
async with Browser(
3723
skhep_testdata.data_path("uproot-empty.root")

0 commit comments

Comments
 (0)