Skip to content

Commit

Permalink
Enable animating offset with tuple of int/float. Textualize#3028
Browse files Browse the repository at this point in the history
Added unit tests as well.
  • Loading branch information
yuvalmo committed Aug 7, 2023
1 parent 5a662e6 commit c8af27a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/textual/css/styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,13 @@ def __textual_animation__(
# If destination is a number, we can convert that to a scalar
if isinstance(value, (int, float)):
value = Scalar(value, Unit.CELLS, Unit.CELLS)
# If destination is a pair of numbers, we can convert it to a
# scalar offset
elif isinstance(value, tuple) and (
list(map(type, value)) == [int, int]
or list(map(type, value)) == [float, float]
):
value = ScalarOffset.from_offset(value)

# We can only animate to Scalar
if not isinstance(value, (Scalar, ScalarOffset)):
Expand Down
42 changes: 42 additions & 0 deletions tests/test_animation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from time import perf_counter

import pytest

from textual.app import App, ComposeResult
from textual.css.scalar import NULL_SCALAR, Scalar, ScalarOffset, Unit
from textual.geometry import Offset
from textual.reactive import var
from textual.widgets import Static

Expand Down Expand Up @@ -39,6 +43,44 @@ async def test_animate_height() -> None:
assert static.styles.height.value == 100


destinations = [
ScalarOffset.from_offset((10, 5)),
Offset(10, 5),
(10, 5),
(10.0, 5.0),
]


@pytest.mark.parametrize("destination", destinations)
async def test_animate_offset(destination) -> None:
"""Test animating styles.offset works."""
# Styles.offset is a ScalarOffset, which makes it more complicated to animate

app = AnimApp()

async with app.run_test() as pilot:
static = app.query_one(Static)
assert static.offset == Offset(0, 0)
assert static.styles.offset == NULL_SCALAR

static.styles.animate("offset", destination, duration=0.5, easing="linear")
start = perf_counter()

# Wait for the animation to finished
await pilot.wait_for_animation()
elapsed = perf_counter() - start
# Check that the full time has elapsed
assert elapsed >= 0.5

# Check the offset reached the destination
# fmt: off
assert static.styles.offset == ScalarOffset(
Scalar(10, Unit.CELLS, Unit.WIDTH),
Scalar(5, Unit.CELLS, Unit.HEIGHT)
)
# fmt: on


async def test_scheduling_animation() -> None:
"""Test that scheduling an animation works."""

Expand Down

0 comments on commit c8af27a

Please sign in to comment.