From e0d28cbf4697f9e1ac53499f3b1db187bb82778a Mon Sep 17 00:00:00 2001 From: Jakob Pinterits Date: Tue, 18 Jun 2024 23:29:10 +0200 Subject: [PATCH] layouter progress --- rio/data_models.py | 2 +- rio/debug/layouter.py | 127 +++++++++++++++++++++++++++++++----------- 2 files changed, 96 insertions(+), 33 deletions(-) diff --git a/rio/data_models.py b/rio/data_models.py index c5c03b56..0dac8048 100644 --- a/rio/data_models.py +++ b/rio/data_models.py @@ -175,7 +175,7 @@ class UnittestComponentLayout: allocated_height: float # Additional, component-specific information - aux: uniserde.JsonDoc + aux: dict[str, Any] @dataclass diff --git a/rio/debug/layouter.py b/rio/debug/layouter.py index 688fb0dc..6577b624 100644 --- a/rio/debug/layouter.py +++ b/rio/debug/layouter.py @@ -1,10 +1,12 @@ from __future__ import annotations +import json from typing import * # type: ignore from typing import Iterable import PIL.Image import PIL.ImageDraw +import uniserde import rio import rio.components.fundamental_component @@ -35,6 +37,29 @@ def specialized(func: Callable[P, R]) -> Callable[P, R]: return result # type: ignore +def iter_direct_tree_children( + session: rio.Session, + component: rio.Component, +) -> Iterable[rio.Component]: + """ + Iterates over the children of a component. In particular, the children which + are part of the component tree, rather than those stored in the components + attributes. + """ + + # Fundamental components can have any number of children + if isinstance( + component, + rio.components.fundamental_component.FundamentalComponent, + ): + yield from component._iter_direct_children() + + # High level components have a single child: their build result + else: + build_data = session._weak_component_data_by_component[component] + yield build_data.build_result + + class Layouter: session: rio.Session @@ -88,6 +113,7 @@ class Layouter: assert not superfluous_component_ids, superfluous_component_ids # Compute server-side layouts + self._layouts_should = {} self._compute_layouts_should( ordered_components=ordered_components, ) @@ -160,6 +186,7 @@ class Layouter: # 2. Update allocated width root_layout = self._layouts_should[self.session._root_component._id] + root_layout.left_in_viewport = 0 root_layout.allocated_width = max( self.window_width, root_layout.requested_width ) @@ -186,6 +213,7 @@ class Layouter: ) # 4. Update allocated height + root_layout.top_in_viewport = 0 root_layout.allocated_height = max( self.window_height, root_layout.requested_height ) @@ -209,18 +237,18 @@ class Layouter: layout_should.natural_width = layout_is.natural_width - def _update_natural_width_Row( - self, - component: rio.Row, - ) -> None: - # Spacing - layout = self._layouts_should[component._id] - layout.natural_width = component.spacing * (len(component.children) - 1) + # def _update_natural_width_Row( + # self, + # component: rio.Row, + # ) -> None: + # # Spacing + # layout = self._layouts_should[component._id] + # layout.natural_width = component.spacing * (len(component.children) - 1) - # Children - for child in component._iter_direct_children(): - child_layout = self._layouts_should[child._id] - layout.natural_width += child_layout.requested_width + # # Children + # for child in component._iter_direct_children(): + # child_layout = self._layouts_should[child._id] + # layout.natural_width += child_layout.requested_width @specialized def _update_allocated_width( @@ -255,20 +283,20 @@ class Layouter: layout_should.natural_height = layout_is.natural_height - def _update_natural_height_Row( - self, - component: rio.Row, - ) -> None: - # Spacing - layout = self._layouts_should[component._id] - layout.natural_height = 0 + # def _update_natural_height_Row( + # self, + # component: rio.Row, + # ) -> None: + # # Spacing + # layout = self._layouts_should[component._id] + # layout.natural_height = 0 - # Children - for child in component._iter_direct_children(): - child_layout = self._layouts_should[child._id] - layout.natural_height = max( - layout.natural_height, child_layout.requested_height - ) + # # Children + # for child in component._iter_direct_children(): + # child_layout = self._layouts_should[child._id] + # layout.natural_height = max( + # layout.natural_height, child_layout.requested_height + # ) @specialized def _update_allocated_height( @@ -297,6 +325,44 @@ class Layouter: child_layout_is.top_in_viewport ) + def debug_dump_json( + self, + which: Literal["should", "are"], + out: IO[str], + ) -> None: + """ + Dumps the layouts to a JSON file. + """ + # Export the layouts to a JSON file + layouts = ( + self._layouts_should if which == "should" else self._layouts_are + ) + + # Convert the class instances to JSON + result = {} + + layouts = list(layouts.items()) + layouts.sort(key=lambda x: x[0]) + + for key, value_class in layouts: + component = self.session._weak_components_by_id[key] + value_json = { + "type": type(component).__name__, + **uniserde.as_json(value_class), + } + + for key2, value in value_json.items(): + if isinstance(key2, float): + value_json[key2] = round(value, 1) + + result[key] = value_json + + json.dump( + result, + out, + indent=4, + ) + def debug_draw( self, which: Literal["should", "are"], @@ -327,7 +393,7 @@ class Layouter: def get_nesting(component: rio.Component, level: int) -> int: result = level - for child in component._iter_direct_children(): + for child in iter_direct_tree_children(self.session, component): result = max(result, get_nesting(child, level + 1)) return result @@ -340,12 +406,9 @@ class Layouter: level: int, ) -> None: # Determine the color. The deeper the darker - nesting_fraction = level / n_layers - color = ( - round(255 * (1 - nesting_fraction)), - round(255 * nesting_fraction), - 0, - ) + nesting_fraction = level / (n_layers + 1) + color_8bit = round(255 * nesting_fraction) + color = (color_8bit, color_8bit, color_8bit) # Draw the component layout = layouts[component._id] @@ -362,7 +425,7 @@ class Layouter: ) # Chain to children - for child in component._iter_direct_children(): + for child in iter_direct_tree_children(self.session, component): draw_component(child, level + 1) draw_component(self.session._root_component, 1)