From 3330a85c2c4d87f73f88b4ac461f6be18f5c165f Mon Sep 17 00:00:00 2001 From: Mia Herkt Date: Sat, 30 Mar 2024 17:30:33 +0100 Subject: [PATCH] ModUI: Update for Textual 0.54.0 --- mod.css | 16 +++------------ mod.py | 49 +++++++++++++++++++++++----------------------- modui/filetable.py | 44 +++++++++++++++++++++++++++-------------- 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/mod.css b/mod.css index c001ef1..5563832 100644 --- a/mod.css +++ b/mod.css @@ -1,5 +1,6 @@ #ftable { width: 1fr; + height: 100%; } #infopane { @@ -10,7 +11,7 @@ #finfo { background: $boost; - height: 12; + height: 14; width: 1fr; box-sizing: content-box; } @@ -27,20 +28,9 @@ width: 1fr; } -#filter_container { - height: auto; - display: none; -} - -#filter_label { - content-align: right middle; - height: 1fr; - width: 20%; - margin: 0 1 0 2; -} - #filter_input { width: 1fr; + display: none; } Notification { diff --git a/mod.py b/mod.py index 0748a42..df011fe 100755 --- a/mod.py +++ b/mod.py @@ -5,7 +5,7 @@ from sys import stdout import time from textual.app import App, ComposeResult -from textual.widgets import DataTable, Header, Footer, TextLog, Static, Input +from textual.widgets import DataTable, Header, Footer, RichLog, Static, Input from textual.containers import Horizontal, Vertical from textual.screen import Screen from textual import log @@ -20,13 +20,13 @@ fhost_app.app_context().push() class NullptrMod(Screen): BINDINGS = [ ("q", "quit_app", "Quit"), - ("f1", "filter(1, 'Lookup name:')", "Lookup name"), - ("f2", "filter(2, 'Filter IP address:')", "Filter IP"), - ("f3", "filter(3, 'Filter MIME Type:')", "Filter MIME"), - ("f4", "filter(4, 'Filter extension:')", "Filter Ext."), + ("f1", "filter(1, 'Name')", "Lookup name"), + ("f2", "filter(2, 'IP address')", "Filter IP"), + ("f3", "filter(3, 'MIME Type')", "Filter MIME"), + ("f4", "filter(4, 'Extension')", "Filter Ext."), ("f5", "refresh", "Refresh"), ("f6", "filter_clear", "Clear filter"), - ("f7", "filter(5, 'Filter user agent:')", "Filter UA"), + ("f7", "filter(5, 'User agent')", "Filter UA"), ("r", "remove_file(False)", "Remove file"), ("ctrl+r", "remove_file(True)", "Ban file"), ("p", "ban_ip(False)", "Ban IP"), @@ -42,29 +42,28 @@ class NullptrMod(Screen): ftable.watch_query(None, None) def action_filter_clear(self): - self.query_one("#filter_container").display = False + self.finput.display = False ftable = self.query_one("#ftable") ftable.focus() ftable.query = ftable.base_query def action_filter(self, fcol: int, label: str): - self.query_one("#filter_label").update(label) - finput = self.query_one("#filter_input") + self.finput.placeholder = label + self.finput.display = True + self.finput.focus() self.filter_col = fcol - self.query_one("#filter_container").display = True - finput.focus() self._refresh_layout() if self.current_file: match fcol: - case 1: finput.value = "" - case 2: finput.value = self.current_file.addr - case 3: finput.value = self.current_file.mime - case 4: finput.value = self.current_file.ext - case 5: finput.value = self.current_file.ua or "" + case 1: self.finput.value = "" + case 2: self.finput.value = self.current_file.addr + case 3: self.finput.value = self.current_file.mime + case 4: self.finput.value = self.current_file.ext + case 5: self.finput.value = self.current_file.ua or "" def on_input_submitted(self, message: Input.Submitted) -> None: - self.query_one("#filter_container").display = False + self.finput.display = False ftable = self.query_one("#ftable") ftable.focus() @@ -122,13 +121,13 @@ class NullptrMod(Screen): def compose(self) -> ComposeResult: yield Header() yield Horizontal( - FileTable(id="ftable", zebra_stripes=True), + FileTable(id="ftable", zebra_stripes=True, cursor_type="row"), Vertical( - DataTable(id="finfo", show_header=False), + DataTable(id="finfo", show_header=False, cursor_type="none"), MpvWidget(id="mpv"), - TextLog(id="ftextlog"), + RichLog(id="ftextlog", auto_scroll=False), id="infopane")) - yield Horizontal(Static("Filter:", id="filter_label"), Input(id="filter_input"), id="filter_container") + yield Input(id="filter_input") yield Footer() def on_mount(self) -> None: @@ -143,6 +142,8 @@ class NullptrMod(Screen): self.mpvw = self.query_one("#mpv") self.ftlog = self.query_one("#ftextlog") + self.finput = self.query_one("#filter_input") + self.mimehandler = mime.MIMEHandler() self.mimehandler.register(mime.MIMECategory.Archive, self.handle_libarchive) self.mimehandler.register(mime.MIMECategory.Text, self.handle_text) @@ -261,13 +262,11 @@ class NullptrMod(Screen): ]) self.mpvw.stop_mpv(True) - self.ftlog.remove() - self.query_one("#infopane").mount(TextLog(id="ftextlog")) - self.ftlog = self.query_one("#ftextlog") + self.ftlog.clear() if f.getpath().is_file(): self.mimehandler.handle(f.mime, f.ext) - self.ftlog.scroll_home(animate=False) + self.ftlog.scroll_to(x=0, y=0, animate=False) class NullptrModApp(App): CSS_PATH = "mod.css" diff --git a/modui/filetable.py b/modui/filetable.py index 7be0f1b..879eed0 100644 --- a/modui/filetable.py +++ b/modui/filetable.py @@ -1,6 +1,6 @@ from textual.widgets import DataTable, Static from textual.reactive import Reactive -from textual.message import Message, MessageTarget +from textual.message import Message from textual import events, log from jinja2.filters import do_filesizeformat @@ -21,9 +21,9 @@ class FileTable(DataTable): self.query = self.base_query class Selected(Message): - def __init__(self, sender: MessageTarget, f: File) -> None: + def __init__(self, f: File) -> None: self.file = f - super().__init__(sender) + super().__init__() def watch_order_col(self, old, value) -> None: self.watch_query(None, None) @@ -44,25 +44,39 @@ class FileTable(DataTable): ) if (self.query): - self.clear() + order = FileTable.colmap[self.order_col] q = self.query if order: q = q.order_by(order.desc() if self.order_desc else order, File.id) - self.add_rows(map(fmt_file, q.limit(self.limit))) + qres = list(map(fmt_file, q.limit(self.limit))) - def _scroll_cursor_in_to_view(self, animate: bool = False) -> None: - region = self._get_cell_region(self.cursor_row, 0) - spacing = self._get_cell_border() - self.scroll_to_region(region, animate=animate, spacing=spacing) + ri = 0 + row = self.cursor_coordinate.row + if row < self.row_count and row >= 0: + ri = int(self.get_row_at(row)[0]) - async def watch_cursor_cell(self, old, value) -> None: - super().watch_cursor_cell(old, value) - if value[0] < len(self.data) and value[0] >= 0: - f = File.query.get(int(self.data[value[0]][0])) - await self.emit(self.Selected(self, f)) + self.clear() + self.add_rows(qres) + + for i, v in enumerate(qres): + if int(v[0]) == ri: + self.move_cursor(row=i) + break + + self.on_selected() + + def on_selected(self) -> Selected: + row = self.cursor_coordinate.row + if row < self.row_count and row >= 0: + f = File.query.get(int(self.get_row_at(row)[0])) + self.post_message(self.Selected(f)) + + def watch_cursor_coordinate(self, old, value) -> None: + super().watch_cursor_coordinate(old, value) + if old != value: + self.on_selected() def on_click(self, event: events.Click) -> None: - super().on_click(event) meta = self.get_style_at(event.x, event.y).meta if meta: if meta["row"] == -1: