diff --git a/CHANGELOG.md b/CHANGELOG.md index 9181d713d..d920392ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Changed message handlers to use prefix handle\_ - Renamed messages to drop the Message suffix - Events now bubble by default +- Refactor of layout ### Added - Added App.measure - Added auto_width to Vertical Layout, WindowView, an ScrollView - Added big_table.py example +- Added easing.py example ## [0.1.10] - 2021-08-25 diff --git a/examples/easing.py b/examples/easing.py new file mode 100644 index 000000000..a53b01412 --- /dev/null +++ b/examples/easing.py @@ -0,0 +1,44 @@ +from textual._easing import EASING +from textual.app import App +from textual.reactive import Reactive + +from textual.views import DockView +from textual.widgets import Placeholder, TreeControl, ScrollView, TreeClick + + +class EasingApp(App): + """An app do demonstrate easing.""" + + side = Reactive(False) + easing = Reactive("linear") + + def watch_side(self, side: bool) -> None: + """Animate when the side changes (False for left, True for right).""" + width = self.easing_view.size.width + animate_x = (width - self.placeholder.size.width) if side else 0 + self.placeholder.animate( + "layout_offset_x", animate_x, easing=self.easing, duration=1 + ) + + async def on_mount(self) -> None: + """Called when application mode is ready.""" + + self.placeholder = Placeholder() + self.easing_view = DockView() + + tree = TreeControl("Easing", {}) + for easing_key in sorted(EASING.keys()): + await tree.add(tree.root.id, easing_key, {"easing": easing_key}) + await tree.root.expand() + + await self.view.dock(ScrollView(tree), edge="left", size=32) + await self.view.dock(self.easing_view) + await self.easing_view.dock(self.placeholder, edge="left", size=32) + + async def handle_tree_click(self, message: TreeClick[dict]) -> None: + """Called in response to a tree click.""" + self.easing = message.node.data.get("easing", "linear") + self.side = not self.side + + +EasingApp().run(log="textual.log") diff --git a/src/textual/geometry.py b/src/textual/geometry.py index 98d25af70..6db5371a9 100644 --- a/src/textual/geometry.py +++ b/src/textual/geometry.py @@ -261,6 +261,19 @@ class Region(NamedTuple): return Region(x - ox, y - oy, width, height) return NotImplemented + def expand(self, size: tuple[int, int]) -> Region: + """Add additional height. + + Args: + size (tuple[int, int]): Additional width and height. + + Returns: + Region: A new region. + """ + add_width, add_height = size + x, y, width, height = self + return Region(x, y, width + add_width, height + add_height) + def overlaps(self, other: Region) -> bool: """Check if another region overlaps this region. diff --git a/src/textual/layouts/vertical.py b/src/textual/layouts/vertical.py index c6e79c7fc..09cd7d282 100644 --- a/src/textual/layouts/vertical.py +++ b/src/textual/layouts/vertical.py @@ -40,7 +40,7 @@ class VerticalLayout(Layout): def arrange(self, size: Size, scroll: Offset) -> Iterable[WidgetPlacement]: index = 0 - width, height = size + width, _height = size gutter_height, gutter_width = self.gutter render_width = ( max(width, self._max_widget_width) + gutter_width * 2 @@ -65,10 +65,4 @@ class VerticalLayout(Layout): yield WidgetPlacement(region, widget, (self.z, index)) total_region = total_region.union(region) - yield WidgetPlacement(total_region) - # x, y, width, height = map.contents_region - # map.contents_region = Region( - # x, y, width + self.gutter[0], height + self.gutter[1] - # ) - - # return map + yield WidgetPlacement(total_region.expand(self.gutter))