Coding style.
- Increase maximum line length from 80 to 100.
This commit is contained in:
parent
75a028272d
commit
71b9da128b
15 changed files with 404 additions and 696 deletions
|
|
@ -14,15 +14,13 @@ import termstr
|
|||
|
||||
|
||||
def appearance_is_valid(appearance):
|
||||
return (all(isinstance(line, (str, termstr.TermStr)) and len(line) > 0
|
||||
for line in appearance) and
|
||||
len(set(len(line) for line in appearance)) < 2)
|
||||
return (all(isinstance(line, (str, termstr.TermStr)) and len(line) > 0 for line in appearance)
|
||||
and len(set(len(line) for line in appearance)) < 2)
|
||||
|
||||
|
||||
def appearance_resize(appearance, dimensions, pad_char=" "):
|
||||
width, height = dimensions
|
||||
result = [line[:width].ljust(width, pad_char)
|
||||
for line in appearance[:height]]
|
||||
result = [line[:width].ljust(width, pad_char) for line in appearance[:height]]
|
||||
if len(result) < height:
|
||||
result.extend([pad_char * width] * (height - len(result)))
|
||||
return result
|
||||
|
|
@ -82,18 +80,14 @@ class Row:
|
|||
widths = self.widths_func(self.widgets, width)
|
||||
assert sum(widths) == width, (sum(widths), width)
|
||||
return join_horizontal([column_widget.appearance((item_width, height))
|
||||
for column_widget, item_width
|
||||
in zip(self.widgets, widths)])
|
||||
for column_widget, item_width in zip(self.widgets, widths)])
|
||||
|
||||
def appearance_min(self):
|
||||
appearances = [column_widget.appearance_min()
|
||||
for column_widget in self.widgets]
|
||||
dimensions = [appearance_dimensions(appearance)
|
||||
for appearance in appearances]
|
||||
appearances = [column_widget.appearance_min() for column_widget in self.widgets]
|
||||
dimensions = [appearance_dimensions(appearance) for appearance in appearances]
|
||||
max_height = max(height for width, height in dimensions)
|
||||
return join_horizontal([
|
||||
appearance_resize(appearance, (width, max_height))
|
||||
for appearance, (width, height) in zip(appearances, dimensions)])
|
||||
return join_horizontal([appearance_resize(appearance, (width, max_height))
|
||||
for appearance, (width, height) in zip(appearances, dimensions)])
|
||||
|
||||
|
||||
def even_partition(row_widgets, height):
|
||||
|
|
@ -115,8 +109,7 @@ def join_vertical(appearances):
|
|||
|
||||
class Column:
|
||||
|
||||
def __init__(self, widgets, partition_func=even_partition,
|
||||
background_char=" "):
|
||||
def __init__(self, widgets, partition_func=even_partition, background_char=" "):
|
||||
self.widgets = widgets
|
||||
self.partition_func = partition_func
|
||||
self.background_char = background_char
|
||||
|
|
@ -128,19 +121,16 @@ class Column:
|
|||
heights = self.partition_func(self.widgets, height)
|
||||
assert sum(heights) == height, (sum(heights), height)
|
||||
return join_vertical([row_widget.appearance((width, item_height))
|
||||
for row_widget, item_height
|
||||
in zip(self.widgets, heights)])
|
||||
for row_widget, item_height in zip(self.widgets, heights)])
|
||||
|
||||
def _appearance_list(self, widgets):
|
||||
if widgets == []:
|
||||
return []
|
||||
appearances = [row_widget.appearance_min() for row_widget in widgets]
|
||||
dimensions = [appearance_dimensions(appearance)
|
||||
for appearance in appearances]
|
||||
dimensions = [appearance_dimensions(appearance) for appearance in appearances]
|
||||
max_width = max(width for width, height in dimensions)
|
||||
padded_appearances = [
|
||||
appearance_resize(appearance, (max_width, height))
|
||||
for appearance, (width, height) in zip(appearances, dimensions)]
|
||||
padded_appearances = [appearance_resize(appearance, (max_width, height))
|
||||
for appearance, (width, height) in zip(appearances, dimensions)]
|
||||
result = []
|
||||
for appearance in padded_appearances:
|
||||
result.extend(appearance)
|
||||
|
|
@ -170,44 +160,37 @@ class ScrollBar:
|
|||
DEFAULT_BAR_COLOR = termstr.Color.grey_100
|
||||
DEFAULT_BACKGROUND_COLOR = termstr.Color.grey_30
|
||||
|
||||
def __init__(self, is_horizontal, interval=(0, 0), bar_color=None,
|
||||
background_color=None):
|
||||
def __init__(self, is_horizontal, interval=(0, 0), bar_color=None, background_color=None):
|
||||
self._is_horizontal = is_horizontal
|
||||
self.interval = interval
|
||||
bar_color = bar_color or ScrollBar.DEFAULT_BAR_COLOR
|
||||
background_color = (background_color or
|
||||
ScrollBar.DEFAULT_BACKGROUND_COLOR)
|
||||
background_color = background_color or ScrollBar.DEFAULT_BACKGROUND_COLOR
|
||||
self._bar_char = termstr.TermStr("█").fg_color(bar_color)
|
||||
self._background_char = termstr.TermStr(" ").bg_color(background_color)
|
||||
if self._is_horizontal:
|
||||
bar_color, background_color = background_color, bar_color
|
||||
self._partial_chars = [(termstr.TermStr(char).fg_color(
|
||||
bar_color).bg_color(background_color),
|
||||
termstr.TermStr(char).fg_color(
|
||||
background_color).bg_color(bar_color))
|
||||
for char in self._PARTIAL_CHARS[self._is_horizontal]]
|
||||
self._partial_chars = [
|
||||
(termstr.TermStr(char).fg_color(bar_color).bg_color(background_color),
|
||||
termstr.TermStr(char).fg_color(background_color).bg_color(bar_color))
|
||||
for char in self._PARTIAL_CHARS[self._is_horizontal]]
|
||||
|
||||
def appearance(self, dimensions):
|
||||
width, height = dimensions
|
||||
assert width == 1 or height == 1, (width, height)
|
||||
length = width if self._is_horizontal else height
|
||||
assert all(0 <= fraction <= 1 for fraction in self.interval), \
|
||||
self.interval
|
||||
assert all(0 <= fraction <= 1 for fraction in self.interval), self.interval
|
||||
(start_index, start_remainder), (end_index, end_remainder) = \
|
||||
[divmod(fraction * length * 8, 8) for fraction in self.interval]
|
||||
start_index, end_index = int(start_index), int(end_index)
|
||||
start_remainder, end_remainder = \
|
||||
int(start_remainder), int(end_remainder)
|
||||
start_remainder, end_remainder = int(start_remainder), int(end_remainder)
|
||||
if start_index == end_index:
|
||||
end_index, end_remainder = start_index + 1, start_remainder
|
||||
elif end_index == start_index + 1:
|
||||
end_remainder = max(start_remainder, end_remainder)
|
||||
bar = (self._background_char * start_index +
|
||||
self._partial_chars[start_remainder][0] +
|
||||
bar = (self._background_char * start_index + self._partial_chars[start_remainder][0] +
|
||||
self._bar_char * (end_index - start_index - 1) +
|
||||
self._partial_chars[end_remainder][1] +
|
||||
self._background_char * (length - end_index - 1))
|
||||
bar = bar[:length]
|
||||
self._background_char * (length - end_index - 1))[:length]
|
||||
return [bar] if self._is_horizontal else [char for char in bar]
|
||||
|
||||
|
||||
|
|
@ -222,8 +205,7 @@ class Portal:
|
|||
def _scroll_half_pages(self, dx, dy):
|
||||
x, y = self.position
|
||||
width, height = self.last_dimensions
|
||||
self.position = (max(x + dx * (width // 2), 0),
|
||||
max(y + dy * (height // 2), 0))
|
||||
self.position = (max(x + dx * (width // 2), 0), max(y + dy * (height // 2), 0))
|
||||
|
||||
def scroll_up(self):
|
||||
self._scroll_half_pages(0, -1)
|
||||
|
|
@ -251,8 +233,7 @@ class Portal:
|
|||
|
||||
class View:
|
||||
|
||||
def __init__(self, portal, horizontal_scrollbar, vertical_scrollbar,
|
||||
hide_scrollbars=True):
|
||||
def __init__(self, portal, horizontal_scrollbar, vertical_scrollbar, hide_scrollbars=True):
|
||||
self.portal = portal
|
||||
self.horizontal_scrollbar = horizontal_scrollbar
|
||||
self.vertical_scrollbar = vertical_scrollbar
|
||||
|
|
@ -260,8 +241,7 @@ class View:
|
|||
|
||||
@classmethod
|
||||
def from_widget(cls, widget):
|
||||
return cls(Portal(widget), ScrollBar(is_horizontal=True),
|
||||
ScrollBar(is_horizontal=False))
|
||||
return cls(Portal(widget), ScrollBar(is_horizontal=True), ScrollBar(is_horizontal=False))
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
|
|
@ -282,41 +262,32 @@ class View:
|
|||
def appearance(self, dimensions):
|
||||
width, height = dimensions
|
||||
try:
|
||||
full_width, full_height = (self.portal.widget.
|
||||
appearance_dimensions())
|
||||
full_width, full_height = self.portal.widget.appearance_dimensions()
|
||||
except AttributeError:
|
||||
full_appearance = self.portal.widget.appearance_min()
|
||||
full_width, full_height = appearance_dimensions(full_appearance)
|
||||
if full_width == 0 or full_height == 0:
|
||||
return self.portal.appearance(dimensions)
|
||||
x, y = self.portal.position
|
||||
hide_scrollbar_vertical = (self.hide_scrollbars and
|
||||
full_height <= height and y == 0)
|
||||
hide_scrollbar_horizontal = (self.hide_scrollbars and
|
||||
full_width <= width and x == 0)
|
||||
hide_scrollbar_vertical = self.hide_scrollbars and full_height <= height and y == 0
|
||||
hide_scrollbar_horizontal = self.hide_scrollbars and full_width <= width and x == 0
|
||||
if not hide_scrollbar_horizontal:
|
||||
full_width = max(full_width, x + width)
|
||||
self.horizontal_scrollbar.interval = (x / full_width,
|
||||
(x + width) / full_width)
|
||||
self.horizontal_scrollbar.interval = (x / full_width, (x + width) / full_width)
|
||||
height -= 1
|
||||
if not hide_scrollbar_vertical:
|
||||
full_height = max(full_height, y + height)
|
||||
self.vertical_scrollbar.interval = (y / full_height,
|
||||
(y + height) / full_height)
|
||||
self.vertical_scrollbar.interval = (y / full_height, (y + height) / full_height)
|
||||
width -= 1
|
||||
portal_appearance = self.portal.appearance((width, height))
|
||||
if hide_scrollbar_vertical:
|
||||
result = portal_appearance
|
||||
else:
|
||||
scrollbar_v_appearance = self.vertical_scrollbar.appearance(
|
||||
(1, height))
|
||||
result = join_horizontal([portal_appearance,
|
||||
scrollbar_v_appearance])
|
||||
scrollbar_v_appearance = self.vertical_scrollbar.appearance((1, height))
|
||||
result = join_horizontal([portal_appearance, scrollbar_v_appearance])
|
||||
if not hide_scrollbar_horizontal:
|
||||
scrollbar_h_appearance = self.horizontal_scrollbar.appearance(
|
||||
(width, 1))
|
||||
result.append(scrollbar_h_appearance[0] +
|
||||
("" if hide_scrollbar_vertical else " "))
|
||||
scrollbar_h_appearance = self.horizontal_scrollbar.appearance((width, 1))
|
||||
result.append(scrollbar_h_appearance[0] + ("" if hide_scrollbar_vertical else " "))
|
||||
return result
|
||||
|
||||
|
||||
|
|
@ -350,8 +321,7 @@ class Table:
|
|||
def appearance_min(self):
|
||||
if self._widgets == []:
|
||||
return []
|
||||
appearances = [[cell.appearance_min() for cell in row]
|
||||
for row in self._widgets]
|
||||
appearances = [[cell.appearance_min() for cell in row] for row in self._widgets]
|
||||
row_heights = [0] * len(self._widgets)
|
||||
column_widths = [0] * len(self._widgets[0])
|
||||
for y, row in enumerate(appearances):
|
||||
|
|
@ -397,8 +367,7 @@ class Border:
|
|||
title_bar = padded_title.center(content_width, self.top)
|
||||
result = [self.top_left + title_bar + self.top_right]
|
||||
result.extend(self.left + line + self.right for line in body_content)
|
||||
result.append(self.bottom_left + self.bottom * content_width +
|
||||
self.bottom_right)
|
||||
result.append(self.bottom_left + self.bottom * content_width + self.bottom_right)
|
||||
return result
|
||||
|
||||
def appearance_min(self):
|
||||
|
|
@ -450,12 +419,9 @@ def draw_screen(widget):
|
|||
def patch_screen(widget):
|
||||
global _last_appearance
|
||||
appearance = widget.appearance(os.get_terminal_size())
|
||||
zip_func = (itertools.zip_longest
|
||||
if len(appearance) > len(_last_appearance) else zip)
|
||||
changed_lines = (str(terminal.move(0, row_index)) + line
|
||||
for row_index, (line, old_line)
|
||||
in enumerate(zip_func(appearance, _last_appearance))
|
||||
if line != old_line)
|
||||
zip_func = (itertools.zip_longest if len(appearance) > len(_last_appearance) else zip)
|
||||
changed_lines = (str(terminal.move(0, row_index)) + line for row_index, (line, old_line)
|
||||
in enumerate(zip_func(appearance, _last_appearance)) if line != old_line)
|
||||
print(*changed_lines, sep="", end="", flush=True)
|
||||
_last_appearance = appearance
|
||||
|
||||
|
|
@ -491,12 +457,10 @@ def context(loop, appearance_changed_event, screen_widget, exit_loop=None):
|
|||
appearance_changed_event.set()
|
||||
if exit_loop is None:
|
||||
exit_loop = loop.stop
|
||||
with signal_handler(loop, signal.SIGWINCH,
|
||||
lambda: draw_screen(screen_widget)), \
|
||||
signal_handler(loop, signal.SIGINT, exit_loop), \
|
||||
signal_handler(loop, signal.SIGTERM, exit_loop), \
|
||||
terminal.alternate_buffer(), terminal.interactive(), \
|
||||
terminal.mouse_tracking():
|
||||
with (signal_handler(loop, signal.SIGWINCH, lambda: draw_screen(screen_widget)),
|
||||
signal_handler(loop, signal.SIGINT, exit_loop),
|
||||
signal_handler(loop, signal.SIGTERM, exit_loop), terminal.alternate_buffer(),
|
||||
terminal.interactive(), terminal.mouse_tracking()):
|
||||
update_task = loop.create_task(
|
||||
update_screen(screen_widget, appearance_changed_event))
|
||||
try:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue