From e9c8640159838e5196e9a72ffb82706538e412f1 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 9 Nov 2020 00:44:08 +0100 Subject: [PATCH] Width and height are managed dynamically: we can almost freely resize the window --- dungeonbattle/display/display.py | 30 +++++++++++++++++++++++++-- dungeonbattle/display/mapdisplay.py | 3 +-- dungeonbattle/display/menudisplay.py | 19 ++++++++++------- dungeonbattle/display/statsdisplay.py | 7 +++---- dungeonbattle/tests/game_test.py | 2 +- dungeonbattle/tests/screen.py | 3 +++ 6 files changed, 48 insertions(+), 16 deletions(-) diff --git a/dungeonbattle/display/display.py b/dungeonbattle/display/display.py index d569d9b..7604812 100644 --- a/dungeonbattle/display/display.py +++ b/dungeonbattle/display/display.py @@ -7,11 +7,37 @@ from dungeonbattle.tests.screen import FakePad class Display: def __init__(self, screen: Any): self.screen = screen - self.rows = curses.LINES if screen else 42 - self.cols = curses.COLS * 4 // 5 if screen else 42 def refresh(self) -> None: raise NotImplementedError def newpad(self, height: int, width: int) -> Union[FakePad, Any]: return curses.newpad(height, width) if self.screen else FakePad() + + def ensure_resized(self, *pads) -> bool: + """ + If the window got resized, ensure that the pads are also resized. + """ + y, x = self.screen.getmaxyx() if self.screen else (0, 0) + for pad in pads: + pad.resize(y, x) + if self.screen and curses.is_term_resized(self.rows, self.cols): + curses.resizeterm(y, x) + return True + return False + + @property + def rows(self) -> int: + return curses.LINES if self.screen else 42 + + @property + def height(self) -> int: + return self.rows + + @property + def cols(self) -> int: + return curses.COLS if self.screen else 42 + + @property + def width(self) -> int: + return self.cols diff --git a/dungeonbattle/display/mapdisplay.py b/dungeonbattle/display/mapdisplay.py index 38a27a2..c9fc91b 100644 --- a/dungeonbattle/display/mapdisplay.py +++ b/dungeonbattle/display/mapdisplay.py @@ -10,8 +10,6 @@ from dungeonbattle.interfaces import Map class MapDisplay(Display): def __init__(self, screen: Any, m: Map, player: Player, pack: TexturePack): super().__init__(screen) - self.height = self.rows - self.width = self.cols self.pack = pack self.map = m self.player = player @@ -38,4 +36,5 @@ class MapDisplay(Display): self.pad.refresh(pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol) def refresh(self) -> None: + self.ensure_resized(self.pad) return self.display(self.player.y, self.player.x) diff --git a/dungeonbattle/display/menudisplay.py b/dungeonbattle/display/menudisplay.py index a619199..cc7a1f8 100644 --- a/dungeonbattle/display/menudisplay.py +++ b/dungeonbattle/display/menudisplay.py @@ -9,8 +9,6 @@ class MenuDisplay(Display): super().__init__(screen) self.values = menu.values self.menu = menu - self.width = self.cols - self.height = self.rows self.trueheight = len(menu.values) self.truewidth = max(len(item.value) for item in menu.values) self.topleftx = topleftx @@ -18,33 +16,40 @@ class MenuDisplay(Display): # Menu values are printed in pad self.pad = self.newpad(self.trueheight, self.truewidth + 1) - for i in range(self.trueheight): - self.pad.addstr(i, 0, " " + self.values[i].value) # Menu box self.menubox = self.newpad(self.height, self.width) + + def update_pad(self, position: int) -> None: self.menubox.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓") for i in range(1, self.height - 2): self.menubox.addstr(i, 0, "┃" + " " * (self.width - 2) + "┃") self.menubox.addstr(self.height - 2, 0, "┗" + "━" * (self.width - 2) + "┛") - def update_pad(self, position: int) -> None: + for i in range(self.trueheight): + self.pad.addstr(i, 0, " " + self.values[i].value) + for i in range(self.trueheight): self.pad.addstr(i, 0, " ") # set a marker in front of the selected line self.pad.addstr(position, 0, ">") def refresh(self) -> None: + with open("/tmp/log", "a") as f: + f.write(f"{self.width}x{self.height}\n") + + self.ensure_resized(self.menubox, self.pad) + if self.height - 2 >= self.menu.position - 1: cornery = 0 elif self.height - 2 >= self.trueheight - self.menu.position: cornery = self.trueheight - self.height + 2 + self.update_pad(self.menu.position) self.menubox.refresh(0, 0, self.toplefty, self.topleftx, self.height + self.toplefty, self.width + self.topleftx) - self.update_pad(self.menu.position) self.pad.refresh(cornery, 0, self.toplefty + 1, self.topleftx + 1, - self.height - 2 + self.toplefty, + self.height - 3 + self.toplefty, self.width - 2 + self.topleftx) diff --git a/dungeonbattle/display/statsdisplay.py b/dungeonbattle/display/statsdisplay.py index cc5bc74..9867181 100644 --- a/dungeonbattle/display/statsdisplay.py +++ b/dungeonbattle/display/statsdisplay.py @@ -5,15 +5,13 @@ from dungeonbattle.entities.player import Player class StatsDisplay(Display): - def __init__(self, screen: Any, player: Player, height: int, width: int, + def __init__(self, screen: Any, player: Player, topleftx: int, toplefty: int): super().__init__(screen) - self.width = width - self.height = height self.topleftx = topleftx self.toplefty = toplefty self.player = player - self.pad = self.newpad(height, width) + self.pad = self.newpad(self.height, self.width) def update_pad(self) -> None: string = "" @@ -37,6 +35,7 @@ class StatsDisplay(Display): self.pad.addstr(2, 0, string3) def refresh(self) -> None: + self.ensure_resized(self.pad) self.pad.clear() self.update_pad() self.pad.refresh(0, 0, self.toplefty, self.topleftx, diff --git a/dungeonbattle/tests/game_test.py b/dungeonbattle/tests/game_test.py index b591a68..fea99a0 100644 --- a/dungeonbattle/tests/game_test.py +++ b/dungeonbattle/tests/game_test.py @@ -106,5 +106,5 @@ class TestGame(unittest.TestCase): def test_stats_display(self) -> None: self.game.current_display = StatsDisplay(None, self.game.player, - 42, 42, 0, 0) + 42, 42) self.game.current_display.refresh() diff --git a/dungeonbattle/tests/screen.py b/dungeonbattle/tests/screen.py index c1aad8c..b9ec851 100644 --- a/dungeonbattle/tests/screen.py +++ b/dungeonbattle/tests/screen.py @@ -12,3 +12,6 @@ class FakePad: def clear(self) -> None: pass + + def resize(self, height: int, width: int) -> None: + pass