Fix resize when modals are visible

Use a callback function to allow items farther up in the stack
to have their own resize logic. This also requires a slight
change to the main TimelineApp to stay DRY
pull/101/head
Derek Schmidt 2019-04-24 16:42:28 -07:00
rodzic aff0c2281f
commit 24421fcb53
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 0F5D491793B4035A
1 zmienionych plików z 61 dodań i 30 usunięć

Wyświetl plik

@ -254,11 +254,12 @@ class StatusDetailWindow:
class Modal: class Modal:
def __init__(self, stdscr): def __init__(self, stdscr, resize_callback=None):
height, width, y, x = self.get_size_pos(stdscr) self.stdscr = stdscr
self.resize_callback = resize_callback
self.window = curses.newwin(height, width, y, x) self.setup_windows()
self.draw() self.full_redraw()
self.panel = curses.panel.new_panel(self.window) self.panel = curses.panel.new_panel(self.window)
self.panel.hide() self.panel.hide()
@ -277,8 +278,12 @@ class Modal:
return height, width, y, x return height, width, y, x
def draw(self): def setup_windows(self):
self.window.erase() height, width, y, x = self.get_size_pos(self.stdscr)
self.window = curses.newwin(height, width, y, x)
def full_redraw(self):
self.setup_windows()
self.window.box() self.window.box()
draw_lines(self.window, self.get_content(), 1, 2, Color.WHITE) draw_lines(self.window, self.get_content(), 1, 2, Color.WHITE)
@ -295,9 +300,16 @@ class Modal:
def loop(self): def loop(self):
self.show() self.show()
key = None while True:
while key != 'q': ch = self.window.getch()
key = self.window.getkey() key = chr(ch).lower() if curses.ascii.isprint(ch) else None
if key == 'q':
break
elif ch == curses.KEY_RESIZE:
if self.resize_callback:
self.resize_callback()
self.full_redraw()
self.hide() self.hide()
@ -327,7 +339,9 @@ class HelpModal(Modal):
class EntryModal(Modal): class EntryModal(Modal):
def __init__(self, stdscr, title, footer=None, size=(None, None), default=None): def __init__(self, stdscr, title, footer=None, size=(None, None), default=None, resize_callback=None):
self.stdscr = stdscr
self.resize_callback = resize_callback
self.content = [] if default is None else default.split() self.content = [] if default is None else default.split()
self.cursor_pos = 0 self.cursor_pos = 0
self.pad_y, self.pad_x = 2, 2 self.pad_y, self.pad_x = 2, 2
@ -338,13 +352,8 @@ class EntryModal(Modal):
if self.footer: if self.footer:
self.pad_y += 1 self.pad_y += 1
height, width, y, x = self.get_size_pos(stdscr) self.setup_windows()
self.full_redraw()
self.window = curses.newwin(height, width, y, x)
self.text_window = self.window.derwin(height - (self.pad_y * 2), width - (self.pad_x * 2), self.pad_y, self.pad_x)
self.text_window.keypad(True)
self.draw()
self.panel = curses.panel.new_panel(self.window) self.panel = curses.panel.new_panel(self.window)
self.panel.hide() self.panel.hide()
@ -364,7 +373,14 @@ class EntryModal(Modal):
return height, width, y, x return height, width, y, x
def draw(self): def setup_windows(self):
height, width, y, x = self.get_size_pos(self.stdscr)
self.window = curses.newwin(height, width, y, x)
self.text_window = self.window.derwin(height - (self.pad_y * 2), width - (self.pad_x * 2), self.pad_y, self.pad_x)
self.text_window.keypad(True)
def full_redraw(self):
self.window.erase() self.window.erase()
self.window.box() self.window.box()
@ -373,9 +389,10 @@ class EntryModal(Modal):
window_height, window_width = self.window.getmaxyx() window_height, window_width = self.window.getmaxyx()
draw_lines(self.window, [self.footer], window_height - self.pad_y + 1, 2, Color.WHITE) draw_lines(self.window, [self.footer], window_height - self.pad_y + 1, 2, Color.WHITE)
self.refresh() self.window.refresh()
self.refresh_text()
def refresh(self): def refresh_text(self):
text = self.get_content() text = self.get_content()
lines = text.split('\n') lines = text.split('\n')
draw_lines(self.text_window, lines, 0, 0, Color.WHITE) draw_lines(self.text_window, lines, 0, 0, Color.WHITE)
@ -393,6 +410,12 @@ class EntryModal(Modal):
self.content = [] self.content = []
self.cursor_pos = 0 self.cursor_pos = 0
def on_resize(self):
if self.resize_callback:
self.resize_callback()
self.setup_windows()
self.full_redraw()
def do_command(self, ch): def do_command(self, ch):
if curses.ascii.isprint(ch) or ch == curses.ascii.LF: if curses.ascii.isprint(ch) or ch == curses.ascii.LF:
text_window_height, text_window_width = self.text_window.getmaxyx() text_window_height, text_window_width = self.text_window.getmaxyx()
@ -435,7 +458,11 @@ class EntryModal(Modal):
self.clear() self.clear()
return False, True return False, True
self.refresh() elif ch == curses.KEY_RESIZE:
self.on_resize()
return True, False
self.refresh_text()
return True, False return True, False
def get_content(self): def get_content(self):
@ -458,15 +485,16 @@ class EntryModal(Modal):
class ComposeModal(EntryModal): class ComposeModal(EntryModal):
def __init__(self, stdscr, default_cw=None): def __init__(self, stdscr, default_cw=None, **kwargs):
super().__init__(stdscr, title="Compose a toot", footer="^D to submit, ESC to quit, ^W to mark sensitive (cw)") super().__init__(stdscr, title="Compose a toot", footer="^D to submit, ESC to quit, ^W to mark sensitive (cw)", **kwargs)
self.cw = default_cw self.cw = default_cw
self.cwmodal = EntryModal(stdscr, title="Content warning", size=(1, 60), default=self.cw) self.cwmodal = EntryModal(stdscr, title="Content warning", size=(1, 60), default=self.cw, resize_callback=self.on_resize)
def do_command(self, ch): def do_command(self, ch):
if ch == curses.ascii.ctrl(ord('w')): if ch == curses.ascii.ctrl(ord('w')):
self.cwmodal.on_resize()
self.cw = self.cwmodal.loop() or None self.cw = self.cwmodal.loop() or None
self.draw() self.full_redraw()
return True, False return True, False
else: else:
return super().do_command(ch) return super().do_command(ch)
@ -520,7 +548,7 @@ class TimelineApp:
self.left = StatusListWindow(self.stdscr, main_height, left_width, header_height, 0) self.left = StatusListWindow(self.stdscr, main_height, left_width, header_height, 0)
self.right = StatusDetailWindow(self.stdscr, main_height, main_width, header_height, left_width) self.right = StatusDetailWindow(self.stdscr, main_height, main_width, header_height, left_width)
self.help_modal = HelpModal(self.stdscr) self.help_modal = HelpModal(self.stdscr, resize_callback=self.on_resize)
def loop(self): def loop(self):
while True: while True:
@ -561,8 +589,7 @@ class TimelineApp:
self.reply() self.reply()
elif ch == curses.KEY_RESIZE: elif ch == curses.KEY_RESIZE:
self.setup_windows() self.on_resize()
self.full_redraw()
def show_sensitive(self): def show_sensitive(self):
status = self.get_selected_status() status = self.get_selected_status()
@ -577,7 +604,7 @@ class TimelineApp:
self.footer.draw_message("You must be logged in to post", Color.RED) self.footer.draw_message("You must be logged in to post", Color.RED)
return return
compose_modal = ComposeModal(self.stdscr) compose_modal = ComposeModal(self.stdscr, resize_callback=self.on_resize)
content, cw = compose_modal.loop() content, cw = compose_modal.loop()
self.full_redraw() self.full_redraw()
if content is None: if content is None:
@ -602,7 +629,7 @@ class TimelineApp:
self.footer.draw_message("You must be logged in to reply", Color.RED) self.footer.draw_message("You must be logged in to reply", Color.RED)
return return
compose_modal = ComposeModal(self.stdscr, default_cw='\n'.join(status['spoiler_text']) or None) compose_modal = ComposeModal(self.stdscr, default_cw='\n'.join(status['spoiler_text']) or None, resize_callback=self.on_resize)
content, cw = compose_modal.loop() content, cw = compose_modal.loop()
self.full_redraw() self.full_redraw()
if content is None: if content is None:
@ -706,6 +733,10 @@ class TimelineApp:
return len(statuses) return len(statuses)
def on_resize(self):
self.setup_windows()
self.full_redraw()
def full_redraw(self): def full_redraw(self):
"""Perform a full redraw of the UI.""" """Perform a full redraw of the UI."""
self.header.draw(self.user) self.header.draw(self.user)