From 52545651db4c5dfb0cae3678ea0968c37cdb00b8 Mon Sep 17 00:00:00 2001 From: Daniel Edgecumbe Date: Wed, 27 Sep 2017 17:18:09 +0100 Subject: [PATCH] Fix various screen resizing issues; should no longer attempt to draw out of bounds --- footer.py | 23 +++++++++++++++++++++-- header.py | 19 +++++++++++++++++-- interface.py | 10 ++++++++++ macros.py | 2 ++ main.py | 23 +++++++++++++++++++++-- monitor.py | 19 ++++++++++++++++++- peers.py | 18 +++++++++++++++++- 7 files changed, 106 insertions(+), 8 deletions(-) diff --git a/footer.py b/footer.py index 5cdc816..89191a2 100644 --- a/footer.py +++ b/footer.py @@ -4,7 +4,7 @@ import curses -from macros import MODES +from macros import MODES, MIN_WINDOW_SIZE class FooterView(object): @@ -16,6 +16,8 @@ class FooterView(object): self._callbacks = set() + self._window_size = MIN_WINDOW_SIZE + def add_callback(self, callback): self._callbacks.add(callback) @@ -43,7 +45,15 @@ class FooterView(object): if self._dt: self._pad.addstr(0, 81, self._dt.isoformat(timespec="seconds")[:19]) - self._pad.refresh(0, 0, 25, 0, 27, 100) + self._draw_pad_to_screen() + + def _draw_pad_to_screen(self): + maxy, maxx = self._window_size + if maxy < 5 or maxx < 3: + # Can't do it + return + + self._pad.refresh(0, 0, maxy-2, 0, maxy, min(maxx-1, 100)) async def on_mode_change(self, newmode, seek=None): if seek is not None: @@ -63,3 +73,12 @@ class FooterView(object): async def on_tick(self, dt): self._dt = dt self.draw() + + async def on_window_resize(self, y, x): + # At the moment we ignore the x size and limit to 100. + if y > self._window_size[0] and self._pad: + self._pad.clear() + self._draw_pad_to_screen() + + self._window_size = (y, x) + self.draw() diff --git a/header.py b/header.py index 84ffa1c..db87a89 100644 --- a/header.py +++ b/header.py @@ -5,7 +5,7 @@ import curses import platform -from macros import VERSION_STRING +from macros import VERSION_STRING, MIN_WINDOW_SIZE class HeaderView(object): @@ -26,6 +26,8 @@ class HeaderView(object): self._nettotals = None self._balance = None + self._window_size = MIN_WINDOW_SIZE + def draw(self): # TODO: figure out window width etc. @@ -103,7 +105,15 @@ class HeaderView(object): else: self._pad.addstr(0, 74, "wallet disabled") - self._pad.refresh(0, 0, 1, 0, 2, 100) + self._draw_pad_to_screen() + + def _draw_pad_to_screen(self): + maxy, maxx = self._window_size + if maxy < 3 or maxx < 3: + # can't do it + return + + self._pad.refresh(0, 0, 1, 0, min(maxy, 2), min(maxx-1, 100)) async def on_networkinfo(self, key, obj): try: @@ -149,3 +159,8 @@ class HeaderView(object): pass self.draw() + + async def on_window_resize(self, y, x): + # At the moment we ignore the x size and limit to 100. + self._window_size = (y, x) + self.draw() diff --git a/interface.py b/interface.py index 428849f..32406de 100644 --- a/interface.py +++ b/interface.py @@ -4,6 +4,8 @@ import curses +from macros import MIN_WINDOW_SIZE + def init_curses(): window = curses.initscr() @@ -26,3 +28,11 @@ def init_curses(): def end_curses(): curses.nocbreak() curses.endwin() + + +def check_min_window_size(y, x): + if (y < MIN_WINDOW_SIZE[0]): + raise Exception("Window is too small, {} < {}".format(y, MIN_WINDOW_SIZE[0])) + + if (x < MIN_WINDOW_SIZE[1]): + raise Exception("Window is too small, {} < {}".format(x, MIN_WINDOW_SIZE[1])) diff --git a/macros.py b/macros.py index 0fdf0a8..94e1a62 100644 --- a/macros.py +++ b/macros.py @@ -10,3 +10,5 @@ VERSION_STRING = "bitcoind-ncurses v0.2.0-dev" # ] MODES = ["monitor", "peers"] DEFAULT_MODE = "monitor" + +MIN_WINDOW_SIZE = (10, 20) diff --git a/main.py b/main.py index 219919b..6e0d62b 100644 --- a/main.py +++ b/main.py @@ -17,9 +17,14 @@ import peers from macros import MODES, DEFAULT_MODE -async def handle_hotkeys(window, callback): +async def handle_hotkeys(window, callback, resize_callback): async def handle_key(key): + if key == "KEY_RESIZE": + y, x = window.getmaxyx() + await resize_callback(y, x) + return + if key == "KEY_LEFT": await callback(None, seek=-1) return @@ -123,6 +128,20 @@ def create_tasks(client, window): await footerview.on_tick(dt) await monitorview.on_tick(dt) + async def on_window_resize(y, x): + interface.check_min_window_size(y, x) + + await headerview.on_window_resize(y, x) + await footerview.on_window_resize(y, x) + await monitorview.on_window_resize(y, x) + await peerview.on_window_resize(y, x) + + # Set the initial window sizes + ty, tx = window.getmaxyx() + loop2 = asyncio.new_event_loop() + loop2.run_until_complete(on_window_resize(ty, tx)) + loop2.close() + tasks = [ poll_client(client, "getbestblockhash", monitorview.on_bestblockhash, 1.0), @@ -135,7 +154,7 @@ def create_tasks(client, window): poll_client(client, "getpeerinfo", on_peerinfo, 5.0), tick(on_tick, 1.0), - handle_hotkeys(window, footerview.on_mode_change) + handle_hotkeys(window, footerview.on_mode_change, on_window_resize) ] if not check_disablewallet(client): diff --git a/monitor.py b/monitor.py index f46d6ca..20d0fb5 100644 --- a/monitor.py +++ b/monitor.py @@ -8,6 +8,8 @@ import curses import asyncio from decimal import Decimal +from macros import MIN_WINDOW_SIZE + class MonitorView(object): def __init__(self, client): @@ -24,6 +26,8 @@ class MonitorView(object): self._bestcoinbase = None # raw json tx self._dt = None + self._window_size = MIN_WINDOW_SIZE + def _draw(self): # TODO: figure out window width etc. @@ -109,7 +113,14 @@ class MonitorView(object): math.log(int(bb["chainwork"], 16), 2), )) - self._pad.refresh(0, 0, 4, 0, 24, 100) + self._draw_pad_to_screen() + + def _draw_pad_to_screen(self): + maxy, maxx = self._window_size + if maxy < 8 or maxx < 3: + return # Can't do it + + self._pad.refresh(0, 0, 4, 0, min(maxy-3, 24), min(maxx-1, 100)) async def draw(self): with await self._lock: @@ -153,3 +164,9 @@ class MonitorView(object): self._visible = True await self.draw() + + async def on_window_resize(self, y, x): + # At the moment we ignore the x size and limit to 100. + self._window_size = (y, x) + if self._visible: + await self.draw() diff --git a/peers.py b/peers.py index 2cee7e9..50911f5 100644 --- a/peers.py +++ b/peers.py @@ -8,6 +8,7 @@ import math import curses import asyncio +from macros import MIN_WINDOW_SIZE class PeersView(object): def __init__(self): @@ -15,6 +16,8 @@ class PeersView(object): self._visible = False self._peerinfo = None # raw data from getpeerinfo + self._window_size = MIN_WINDOW_SIZE + def draw(self): # TODO: figure out window width etc. @@ -85,7 +88,14 @@ class PeersView(object): if 'synced_headers' in peer: self._pad.addstr(1+index-offset, 93, str(peer['synced_headers']).rjust(7) ) - self._pad.refresh(0, 0, 4, 0, 24, 100) + self._draw_pad_to_screen() + + def _draw_pad_to_screen(self): + maxy, maxx = self._window_size + if maxy < 8 or maxx < 3: + return # Can't do it + + self._pad.refresh(0, 0, 4, 0, min(maxy-3, 24), min(maxx-1, 100)) async def on_peerinfo(self, key, obj): try: @@ -103,3 +113,9 @@ class PeersView(object): self._visible = True self.draw() + + async def on_window_resize(self, y, x): + # At the moment we ignore the x size and limit to 100. + self._window_size = (y, x) + if self._visible: + await self.draw()