kopia lustrzana https://github.com/ihabunek/toot
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 DRYpull/101/head
rodzic
aff0c2281f
commit
24421fcb53
|
@ -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)
|
||||||
|
|
Ładowanie…
Reference in New Issue