mirror of
https://github.com/rr-/pq-cli.git
synced 2026-11-12 22:40:36 -07:00
ui: import and export .pqw files from the menus
The basic interface gets two main menu entries that ask for a path. The curses roster gets [I] Import and [E] Export, with a new text input view for the path, prefilled with NAME.pqw on export, and a message view for the outcome and any warnings. The README explains how to move characters to and from the web version. Resolves #21
This commit is contained in:
7 files changed
+266
-3
No files matched your search
@@ -0,0 +1,73 @@
|
||||
import curses
|
||||
import curses.ascii
|
||||
|
||||
from pqcli.ui.curses.event_handler import EventHandler
|
||||
from pqcli.ui.curses.views.base_view import BaseView
|
||||
|
||||
|
||||
class TextInputView(BaseView):
|
||||
"""Ask for one line of text, such as a file name."""
|
||||
|
||||
def __init__(self, screen: curses.window, title: str, text: str) -> None:
|
||||
super().__init__(screen)
|
||||
|
||||
self.on_cancel = EventHandler[[]]()
|
||||
self.on_confirm = EventHandler[[str]]()
|
||||
|
||||
self._title = title
|
||||
self._text = text
|
||||
self._win: curses.window | None = None
|
||||
self._text_win: curses.window | None = None
|
||||
|
||||
def start(self) -> None:
|
||||
self.screen.erase()
|
||||
self.screen.noutrefresh()
|
||||
|
||||
scr_height, scr_width = self.screen.getmaxyx()
|
||||
h = 6
|
||||
w = min(60, scr_width - 4)
|
||||
y = (scr_height - h - 2) // 2
|
||||
x = (scr_width - w - 2) // 2
|
||||
self._win = curses.newwin(h + 2, w + 2, y, x)
|
||||
self._text_win = curses.newwin(3, w + 2, y + 2, x - 1)
|
||||
self._render()
|
||||
|
||||
def stop(self) -> None:
|
||||
self._win = None
|
||||
self._text_win = None
|
||||
|
||||
def keypress(self, key: int) -> None:
|
||||
if key == curses.ascii.ESC:
|
||||
self.on_cancel()
|
||||
return
|
||||
if key == curses.ascii.NL:
|
||||
text = self._text.strip()
|
||||
if text:
|
||||
self.on_confirm(text)
|
||||
else:
|
||||
self.on_cancel()
|
||||
return
|
||||
if key in {curses.KEY_BACKSPACE, curses.ascii.DEL}:
|
||||
self._text = self._text[:-1]
|
||||
elif key == curses.ascii.ETB: # ^w
|
||||
self._text = ""
|
||||
elif curses.ascii.isprint(key):
|
||||
self._text += chr(key)
|
||||
self._render()
|
||||
|
||||
def _render(self) -> None:
|
||||
if not self._win or not self._text_win:
|
||||
return
|
||||
|
||||
self._win.erase()
|
||||
self._win.addstr(0, 0, self._title)
|
||||
self._win.addstr(5, 0, "[Enter] Continue")
|
||||
self._win.addstr(6, 0, "[Esc ] Cancel")
|
||||
self._win.refresh()
|
||||
|
||||
width = self._text_win.getmaxyx()[1] - 2
|
||||
self._text_win.erase()
|
||||
self._text_win.box()
|
||||
# keep the end of long paths in view
|
||||
self._text_win.addnstr(1, 1, self._text[-width + 1 :], width)
|
||||
self._text_win.refresh()
|
||||
Reference in new issue
Block a user