Metadata-Version: 2.4
Name: qt-animation-timeline
Version: 0.1.4
Summary: Package description.
Project-URL: homepage, https://github.com/brisvag/qt-animation-timeline
Project-URL: repository, https://github.com/brisvag/qt-animation-timeline
Author-email: Lorenzo Gaifas <brisvag@gmail.com>
License: BSD-3-Clause
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: numpy
Requires-Dist: psygnal
Requires-Dist: pydantic-extra-types
Requires-Dist: pydantic>2
Requires-Dist: qtpy
Requires-Dist: superqt
Description-Content-Type: text/markdown

# qt-animation-timeline

[![License](https://img.shields.io/pypi/l/qt-animation-timeline.svg?color=green)](https://github.com/brisvag/qt-animation-timeline/qt-animation-timeline/raw/main/LICENSE)
[![PyPI](https://img.shields.io/pypi/v/qt-animation-timeline.svg?color=green)](https://pypi.org/project/qt-animation-timeline)
[![Python Version](https://img.shields.io/pypi/pyversions/qt-animation-timeline.svg?color=green)](https://python.org)
[![CI](https://github.com/brisvag/qt-animation-timeline/qt-animation-timeline/actions/workflows/ci.yml/badge.svg)](https://github.com/brisvag/qt-animation-timeline/qt-animation-timeline/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/brisvag/qt-animation-timeline/qt-animation-timeline/branch/main/graph/badge.svg)](https://codecov.io/gh/brisvag/qt-animation-timeline/qt-animation-timeline)

A blender-style timeline widget for qt to edit animations.

<img width="966" height="188" alt="image" src="https://github.com/user-attachments/assets/5628a987-f299-493e-8c26-5049d6d27cfc" />

## Controls

| Action | Mouse/Key binding | Region |
| -- | -- | -- |
| New Keyframe | Double click | Track |
| Select Keyframe | Click | Keyframe |
| Select multiple | Ctrl + Click | Keyframe |
| Select with box | Shift + Click | Tracks |
| Delete selected | Del | - |
| Move Selected Keyframes | Drag | Keyframe |
| Move whole track | Drag | Track Line |
| Change easing function | Right Click | Track Line or Keyframe |
| Scrub playhead | Drag | Header |
| Select play range | Shift + Drag | Header |
| Play/Pause animation | Space | - |


## Usage

The widget takes a mapping of track names to python objects and attribute names, allowing automatic
setting of the interpolated values of such object given the current state of the animation model.

The widget is designed to work with nested dataclass/pydantic style models, but will work just fine with anything else non-nested.

```py
from pydantic import BaseModel
from qt_animation_timeline import AnimationTimelineWidget

class Circle(BaseModel):
    color: tuple[int, int, int] = (255, 0, 0)
    size: float = 10
    filled: bool = True
    other_stuff: str = "thing"

circle = Circle()

# mapping of names of tracks to a tuple of object/attribute
# any time a change in the animation occur, the object's attribute
# will be updated with the new interpolated value.
track_options = {
    'color': (circle, 'color'),
    'size': (circle, 'size')
}

timeline = AnimationTimelineWidget(track_options=track_options)
timeline.show()
```

This will allow to animate the color and size, updating the model accordingly when the playhead scrubs along the animation.

When a keyframe is created manually, it will inherit the current model value for the given attribute.

Note that this also works for nested models whenever possible:

```py
class CircleSet(BaseModel):
    circle1: Circle = Circle()
    circle2: Circle = Circle()

circleset = CircleSet()

track_options = {
    'circle 1': (circleset, 'circle1'),
    'circle 2 size': (circleset, 'circle2.size')  # or (circleset.circle2, size)
}
timeline = AnimationTimelineWidget(track_options=track_options)
timeline.show()
```

In this case, the whole model is considered the keyframe value, and all its elements will be interpolated.

## Development

The easiest way to get started is to use the [github cli](https://cli.github.com)
and [uv](https://docs.astral.sh/uv/getting-started/installation/):

```sh
gh repo fork brisvag/qt-animation-timeline --clone
# or just
# gh repo clone brisvag/qt-animation-timeline
cd qt-animation-timeline
uv sync
```

Run tests:

```sh
uv run pytest
```

Lint files:

```sh
uv run pre-commit run --all-files
```
