commit 7020a60bfedc3fb426314840abd33f6e65e2542e
parent 28417c7dcea0c5613c25e2d1075055e038403779
Author: Paco Esteban <paco@e1e0.net>
Date: Sun, 27 Jun 2021 17:37:33 +0200
betterer and clearerer scroll method
Diffstat:
1 file changed, 94 insertions(+), 55 deletions(-)
diff --git a/subclient/subclient.py b/subclient/subclient.py
@@ -20,80 +20,119 @@ def get_config_file():
class SubClient:
+ UP = -1
+ DOWN = 1
+
def __init__(self):
self.config = configparser.ConfigParser()
self.config.read(get_config_file())
+
self.subsonic = subsonic.Subsonic(self.config['subclient'])
+
+ self.window = None
+ self.hight = 0
+ self.width = 0
+ self.init_curses()
+
self.nav_list = self.subsonic.get_artists()
- self.nav_y = 0
self.nav_selected = 0
- self.nav_list_selected = 0
+ self.nav_top = 0
+ self.nav_bottom = len(self.nav_list)
+ self.nav_max_lines = curses.LINES
+ self.nav_page = self.nav_bottom // self.nav_max_lines
- def load_artists(self):
- for i, artist in enumerate(self.nav_list):
- if i == self.nav_list_selected:
- self.nav_win.addstr(i, 0, artist.name, curses.A_REVERSE)
- else:
- self.nav_win.addstr(i, 0, artist.name)
-
- def nav_down(self):
- self.nav_selected += 1
- self.nav_list_selected += 1
- if self.nav_list_selected > len(self.nav_list):
- self.nav_list_selected = len(self.nav_list)
- if self.nav_selected >= (curses.LINES - 5):
- self.nav_y += 1
- self.nav_selected = curses.LINES - 5
- self.nav_win.clear()
- self.load_artists()
- self.nav_win.refresh(self.nav_y, 0, 1, 0,
- curses.LINES - 2, curses.COLS - 1)
-
- def nav_up(self):
- self.nav_selected -= 1
- self.nav_list_selected -= 1
- if self.nav_list_selected < 0:
- self.nav_list_selected = 0
- if self.nav_selected <= 3:
- self.nav_y -= 1
- if self.nav_selected < 0:
- self.nav_selected = 0
- if self.nav_y < 0:
- self.nav_y = 0
- self.nav_win.clear()
- self.load_artists()
- self.nav_win.refresh(self.nav_y, 0, 1, 0,
- curses.LINES - 2, curses.COLS - 1)
+ def init_curses(self):
+ self.window = curses.initscr()
+ self.window.keypad(True)
- def refresh(self):
- self.stdscr.noutrefresh()
- self.nav_win.noutrefresh(self.nav_y, 0, 1, 0,
- curses.LINES - 2, curses.COLS - 1)
- curses.doupdate()
+ curses.curs_set(0) # disable cursor
+ curses.noecho()
+ curses.cbreak()
+
+ self.height, self.width = self.window.getmaxyx()
- def main_loop(self):
+ def run(self):
+ # read chars until we exit, then clean
+ try:
+ self.input_loop()
+ except KeyboardInterrupt:
+ pass
+ finally:
+ curses.endwin()
+
+ def input_loop(self):
while True:
- c = self.stdscr.getkey()
+ self.window.erase()
+ self.load_list()
+ self.refresh()
+
+ c = self.window.getkey()
if c == 'q': # quit
break
elif c == 'j':
- self.nav_down()
+ self.nav_scroll(self.DOWN)
elif c == 'k':
- self.nav_up()
+ self.nav_scroll(self.UP)
+ elif c in [curses.KEY_ENTER, '\r', '\n']:
+ with open('foo.txt', 'w') as f:
+ print(f"top: {self.nav_top}", file=f)
+ print(f"bottom: {self.nav_bottom}", file=f)
+ print(f"selected: {self.nav_selected}", file=f)
+ break
- def start(self, stdscr):
- self.stdscr = stdscr
- self.nav_win = curses.newpad(len(self.nav_list) + 1, curses.COLS - 1)
- self.stdscr.clear()
- curses.curs_set(0) # disable cursor
- self.load_artists()
- self.refresh()
- self.main_loop()
+ def load_list(self):
+ for i, t in enumerate(
+ self.nav_list[self.nav_top:self.nav_top + self.nav_max_lines]):
+ if i == self.nav_selected:
+ self.window.addstr(i, 0, t.name, curses.A_REVERSE)
+ else:
+ self.window.addstr(i, 0, t.name)
+
+ def nav_scroll(self, direction):
+ # next cursor position
+ next_line = self.nav_selected + direction
+
+ # scroll up direction
+ if direction == self.UP:
+ # with overflow
+ # current cursor position is 0 so we are at the first line,
+ # but top position is greater than 0, so we can scroll up.
+ # so we substract 1 from nav_top
+ if self.nav_top > 0 and self.nav_selected == 0:
+ self.nav_top += direction
+ return
+ # without overflow
+ # current cursor position is greater than 0
+ # so we just adjust the selected line.
+ if self.nav_selected > 0:
+ self.nav_selected = next_line
+ return
+
+ # Scroll in down direction
+ if direction == self.DOWN:
+ # With overflow
+ # next cursor position reaches max lines, so we increment the top
+ # but we take care to not increase if we reach end of list (top
+ # + one page < than len(list) aka bottom)
+ if (next_line == self.nav_max_lines
+ and self.nav_top + self.nav_max_lines < self.nav_bottom):
+ self.nav_top += direction
+ return
+ # Without overflow
+ # next cursor position is above max lines, so we increment the
+ # selected line
+ if next_line < self.nav_max_lines:
+ self.nav_selected = next_line
+ return
+
+ def refresh(self):
+ self.window.noutrefresh()
+ curses.doupdate()
def main():
subclient = SubClient()
- curses.wrapper(subclient.start)
+ subclient.run()
if __name__ == "__main__":