From 01a97c4147c3da160b3a4c42cc9fa4e9fa2e2f6c Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 11 May 2019 20:39:57 +0000 Subject: [PATCH] Implement rendering to TreeView --- cheuph/render/tree_display.py | 194 ++++++++++++++-------------------- 1 file changed, 81 insertions(+), 113 deletions(-) diff --git a/cheuph/render/tree_display.py b/cheuph/render/tree_display.py index 508e0a6..4cce15b 100644 --- a/cheuph/render/tree_display.py +++ b/cheuph/render/tree_display.py @@ -3,6 +3,7 @@ from typing import Any, List, Optional, Set from .element import Element, ElementSupply, Id, RenderedElement from .exceptions import TreeException +from .markup import AttributedText from .tree_list import TreeList __all__ = ["TreeDisplay"] @@ -148,8 +149,8 @@ class TreeDisplay: - make sure the anchor is visible """ - self._width = width - self._height = height + self.width = width + self.height = height #self._root_id: Optional[Id] = None # TODO add root stuff @@ -187,7 +188,84 @@ class TreeDisplay: anchor offset, cursor, width or height are manually changed. """ - pass # TODO + if self.anchor_id is None: + # As described in the class docstring, we have no starting point + # for rendering, so we don't even attempt it. + self._rendered = None + return + + anchor_tree = self._render_tree(self.anchor_id) + + self._rendered = TreeList(anchor_tree, self.anchor_id) + self._rendered.offset_by(self.anchor_offset) + + self._fill_screen_upwards() + self._fill_screen_downwards() + + def _render_tree(self, + tree_id: Id, + depth: int = 0 + ) -> List[RenderedElement]: + + elements: List[RenderedElement] = [] + + highlighted = tree_id == self.cursor_id + folded = tree_id in self._folded + + tree = self._supply.get(tree_id) + rendered = tree.render(width=self.width, depth=depth, + highlighted=highlighted, folded=folded) + + elements.append(rendered) + + if not folded: + for child_id in self._supply.get_children_ids(tree_id): + subelements = self._render_tree(child_id, depth=depth+1) + elements.extend(subelements) + + return elements + + def _fill_screen_upwards(self) -> None: + if self._rendered is None: + raise TreeException(( + "Can't fill screen upwards without a TreeList. This exception" + " should never occur." + )) + + while True: + if self._rendered.upper_offset <= 0: + break + + above_tree_id = self._supply.get_previous_id( + self._rendered.upper_tree_id) + + if above_tree_id is None: + break # We've hit the top of the supply + + self._rendered.add_above(self._render_tree(above_tree_id)) + + def _fill_screen_downwards(self) -> None: + """ + Eerily similar to _fill_screen_upwards()... + """ + + if self._rendered is None: + raise TreeException(( + "Can't fill screen downwards without a TreeList. This exception" + " should never occur." + )) + + while True: + if self._rendered.lower_offset <= 0: + break + + below_tree_id = self._supply.get_previous_id( + self._rendered.upper_tree_id) + + if below_tree_id is None: + break # We've hit the bottom of the supply + + self._rendered.add_below(self._render_tree(below_tree_id)) def render_display_lines(self) -> None: """ @@ -278,116 +356,6 @@ class TreeDisplay: self.fold(element_id) return True - # OTHER STUFF - - def resize(self, width: int, height: int) -> None: - # TODO maybe empty _rendered/invalidate caches etc.? - self._width = width - self._height = height - - def render(self) -> None: - # Steps: - # - # 1. Find and render anchor's branch to TreeList - # 2. Render above and below the branch until the screen is full (with - # the specified anchor offset) - # 2.1. Keep the TreeList for later things like scrolling - # 3. Cut out the visible lines and messages - # 4. Cut out the visible parts horizontally (self._horizontal_offset) - # 4.1. Keep the result for later reference (mouse clicks) - # 5. Convert the result to plain text and draw it in the curses window - # - # Not happy with these steps yet. Scrolling, checking if the cursor is - # in view, switching anchors etc. still feel weird. - # - # TODO Add the above into the TreeDisplay model. - - if self._anchor_id is None: - self._rendered = None - return - - if self._root_id is None: - ancestor_id = self._supply.get_furthest_ancestor_id( - self._anchor_id) - else: - ancestor_id = self._root_id - - ancestor_tree = self._render_tree(self._supply.get_tree(ancestor_id)) - - self._rendered = TreeList(ancestor_tree, self._anchor_id) - self._rendered.offset_by(self._anchor_offset) - - if self._root_id is None: - self._fill_screen_upwards() - self._fill_screen_downwards() - - self._pad.set_lines(self._rendered.to_lines()) - # The vertical offset (anchor offset) is already being dealt with in - # the TreeView, since it is more useful to apply it there (each line's - # offset/index is also the anchor offset it would have if it was the - # anchor. - self._pad.stamp(self._horizontal_offset, 0, self._width, self._height) - - def _render_tree(self, - tree: Element, - depth: int = 0 - ) -> List[RenderedElement]: - elements: List[RenderedElement] = [] - - highlighted = tree.id == self._cursor_id - folded = tree.id in self._folded - - elements.append(tree.render(depth=depth, highlighted=highlighted, - folded=folded)) - - if not folded: - for child in tree.children: - elements.extend(self._render_tree(child, depth=depth+1)) - - return elements - - def _fill_screen_upwards(self) -> None: - if self._rendered is None: - return # TODO think of sensible thing to do here - - while True: - if self._rendered.upper_offset <= 0: - break - - above_tree_id = self._supply.get_previous_id( - self._rendered.upper_tree_id) - - if above_tree_id is None: - break - - above_tree = self._supply.get_tree(above_tree_id) - self._rendered.add_above(self._render_tree(above_tree)) - - def _fill_screen_downwards(self) -> None: - """ - Eerily similar to _fill_screen_upwards()... - """ - - if self._rendered is None: - return # TODO think of sensible thing to do here - - while True: - if self._rendered.lower_offset >= self._height - 1: - break - - below_tree_id = self._supply.get_next_id( - self._rendered.lower_tree_id) - - if below_tree_id is None: - break - - below_tree = self._supply.get_tree(below_tree_id) - self._rendered.add_below(self._render_tree(below_tree)) - - def draw_to(self, window: Any) -> None: - # TODO color styles of the text itself - pass - # Terminology: # # root