Implement rendering display lines
This commit is contained in:
parent
01a97c4147
commit
9df8338b0e
3 changed files with 88 additions and 11 deletions
|
|
@ -40,9 +40,10 @@ class Element(abc.ABC):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def render(self,
|
def render(self,
|
||||||
|
width: int,
|
||||||
depth: int,
|
depth: int,
|
||||||
highlighted: bool,
|
highlighted: bool = False,
|
||||||
folded: bool,
|
folded: bool = False,
|
||||||
) -> RenderedElement:
|
) -> RenderedElement:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -153,6 +154,10 @@ class RenderedElement:
|
||||||
def element(self) -> Element:
|
def element(self) -> Element:
|
||||||
return self._element
|
return self._element
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lines(self) -> List[AttributedText]:
|
||||||
|
return self._lines
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def height(self) -> int:
|
def height(self) -> int:
|
||||||
return len(self._lines)
|
return len(self._lines)
|
||||||
|
|
|
||||||
|
|
@ -274,8 +274,27 @@ class TreeDisplay:
|
||||||
It should be called just before drawing the display lines to the curses
|
It should be called just before drawing the display lines to the curses
|
||||||
window.
|
window.
|
||||||
"""
|
"""
|
||||||
|
filler_line = AttributedText(" " * self.width)
|
||||||
|
|
||||||
pass # TODO
|
if self._rendered is None:
|
||||||
|
self._display_lines = [filler_line] * self.height
|
||||||
|
return
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
if self._rendered.upper_offset > 0:
|
||||||
|
# Fill the screen with empty lines until we hit the actual messages
|
||||||
|
lines.extend([filler_line] * self._rendered.upper_offset)
|
||||||
|
|
||||||
|
rendered_lines = self._rendered.to_lines(start=0, stop=self.height-1)
|
||||||
|
lines.extend(line for line, rendered in rendered_lines)
|
||||||
|
|
||||||
|
if self._rendered.lower_offset < self.height - 1:
|
||||||
|
# Fill the rest of the screen with empty lines
|
||||||
|
lines_left = self.height - 1 - self._rendered.lower_offset
|
||||||
|
lines.extend([filler_line] * lines_left)
|
||||||
|
|
||||||
|
self._display_lines = lines
|
||||||
|
|
||||||
# SCROLLING
|
# SCROLLING
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,36 @@
|
||||||
import collections
|
import collections
|
||||||
from typing import Deque, List
|
from typing import Deque, List, Optional, Tuple
|
||||||
|
|
||||||
from .element import Id, RenderedElement
|
from .element import Id, RenderedElement
|
||||||
|
from .markup import AttributedText
|
||||||
|
|
||||||
__all__ = ["TreeList"]
|
__all__ = ["TreeList"]
|
||||||
|
|
||||||
class TreeList:
|
class TreeList:
|
||||||
|
"""
|
||||||
|
This class is the stage between tree-like Element structures and lines of
|
||||||
|
text like the TreeDisplay's DisplayLines.
|
||||||
|
|
||||||
|
It keeps track of the results of rendering Element trees, and also the top
|
||||||
|
and bottom tree's ids, so the TreeList can be expanded easily by appending
|
||||||
|
trees to the top and bottom.
|
||||||
|
|
||||||
|
Despite its name, the "trees" it stores are just flat lists, and they're
|
||||||
|
stored in a flat deque one message at a time. Its name comes from how i is
|
||||||
|
used with rendered Element trees.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
tree: List[RenderedElement],
|
tree: List[RenderedElement],
|
||||||
anchor_id: Id,
|
anchor_id: Id,
|
||||||
) -> None:
|
) -> None:
|
||||||
self._deque: Deque = collections.deque()
|
self._deque: Deque[RenderedElement] = collections.deque()
|
||||||
|
|
||||||
# The offsets can be thought of as the index of a line relative to the
|
# The offsets can be thought of as the index of a line relative to the
|
||||||
# anchor's first line.
|
# anchor's first line.
|
||||||
#
|
#
|
||||||
# The upper offset is the index of the uppermost message's first line.
|
# The upper offset is the index of the uppermost message's first line.
|
||||||
# upper_offset <= 0.
|
|
||||||
#
|
|
||||||
# The lower offset is the index of the lowermost message's LAST line.
|
# The lower offset is the index of the lowermost message's LAST line.
|
||||||
# lower_offset >= 0.
|
|
||||||
self._upper_offset: int
|
self._upper_offset: int
|
||||||
self._lower_offset: int
|
self._lower_offset: int
|
||||||
|
|
||||||
|
|
@ -47,9 +58,14 @@ class TreeList:
|
||||||
def lower_tree_id(self) -> Id:
|
def lower_tree_id(self) -> Id:
|
||||||
return self._lower_tree_id
|
return self._lower_tree_id
|
||||||
|
|
||||||
def offset_by(self, offset: int) -> None:
|
def offset_by(self, delta: int) -> None:
|
||||||
self._upper_offset += offset
|
"""
|
||||||
self._lower_offset += offset
|
Change all the TreeList's offsets by a delta (which is added to each
|
||||||
|
offset).
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._upper_offset += delta
|
||||||
|
self._lower_offset += delta
|
||||||
|
|
||||||
def _add_first_tree(self,
|
def _add_first_tree(self,
|
||||||
tree: List[RenderedElement],
|
tree: List[RenderedElement],
|
||||||
|
|
@ -81,6 +97,10 @@ class TreeList:
|
||||||
self._lower_offset = offset - 1
|
self._lower_offset = offset - 1
|
||||||
|
|
||||||
def add_above(self, tree: List[RenderedElement]) -> None:
|
def add_above(self, tree: List[RenderedElement]) -> None:
|
||||||
|
"""
|
||||||
|
Add a rendered tree above all current trees.
|
||||||
|
"""
|
||||||
|
|
||||||
if len(tree) == 0:
|
if len(tree) == 0:
|
||||||
raise ValueError("The tree must contain at least one element")
|
raise ValueError("The tree must contain at least one element")
|
||||||
|
|
||||||
|
|
@ -96,6 +116,10 @@ class TreeList:
|
||||||
#self._deque.extendLeft(reversed(tree))
|
#self._deque.extendLeft(reversed(tree))
|
||||||
|
|
||||||
def add_below(self, tree: List[RenderedElement]) -> None:
|
def add_below(self, tree: List[RenderedElement]) -> None:
|
||||||
|
"""
|
||||||
|
Add a rendered tree below all current trees.
|
||||||
|
"""
|
||||||
|
|
||||||
if len(tree) == 0:
|
if len(tree) == 0:
|
||||||
raise ValueError("The tree must contain at least one element")
|
raise ValueError("The tree must contain at least one element")
|
||||||
|
|
||||||
|
|
@ -109,3 +133,32 @@ class TreeList:
|
||||||
#delta = sum(map(lambda r: r.height, tree))
|
#delta = sum(map(lambda r: r.height, tree))
|
||||||
#self._lower_offset += delta
|
#self._lower_offset += delta
|
||||||
#self._deque.extend(tree)
|
#self._deque.extend(tree)
|
||||||
|
|
||||||
|
def to_lines(self,
|
||||||
|
start: Optional[int] = None,
|
||||||
|
stop: Optional[int] = None,
|
||||||
|
) -> List[Tuple[AttributedText, RenderedElement]]:
|
||||||
|
|
||||||
|
offset = self.upper_offset
|
||||||
|
lines: List[Tuple[AttributedText, RenderedElement]] = []
|
||||||
|
|
||||||
|
# I'm creating this generator instead of using two nested for loops
|
||||||
|
# below, because I want to be able to break out of the for loop without
|
||||||
|
# the code getting too ugly, and because it's fun :)
|
||||||
|
all_lines = ((line, rendered)
|
||||||
|
for rendered in self._deque
|
||||||
|
for line in rendered.lines)
|
||||||
|
|
||||||
|
for line, rendered in all_lines:
|
||||||
|
after_start = start is not None and offset >= start
|
||||||
|
before_stop = stop is not None and offset <= stop
|
||||||
|
|
||||||
|
if after_start and before_stop:
|
||||||
|
lines.append((line, rendered))
|
||||||
|
|
||||||
|
if not before_stop:
|
||||||
|
break
|
||||||
|
|
||||||
|
offset += 1
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue