Skip to content

Commands API#375

Open
FelipeDefensor wants to merge 41 commits intodevfrom
refactor-timeline-requests
Open

Commands API#375
FelipeDefensor wants to merge 41 commits intodevfrom
refactor-timeline-requests

Conversation

@FelipeDefensor
Copy link
Collaborator

Introduces the commands API, a much simpler way to handle user interactions. Commands make all the following obsolete:

  • All timeline and timeline component RequestHandlers
  • TimelineComponentSelector
  • Several TimelineSelectors
  • TiliaActions
  • user_action fixture
  • TimelineUi.on_timeline_request, TimelineUI.on_timeline_component_request (substituted by TimelineUIs.on_timeline_command)
  • TimelineUIs.pre_process_timeline_request()
  • tilia\ui\timelines\collection\requests\args.py
  • Several Post and Get members
  • Some TimelineSelector members

The core functionality is given by command.py, along with fuller documentation.

Usage of commands:

    # Register a new command
    commands.register(
        'example.command',
        callback_function,
        text='Menu Text',  # Optional: for display in Qt interface
        shortcut='Ctrl+E',  # Optional: keyboard shortcut
        icon='example_icon'   # Optional: icon name in IMG_DIR (without extension)
    )

    # Execute a command
    commands.execute('example.command', arg1, arg2, kwarg1=value1)

Examples of commands:

  • File commands: 'file.open', 'file.save', 'file.export.img'
  • Timeline commands: 'timeline.delete', 'timeline.component.copy'
  • View commands: 'view.zoom.in', 'view.zoom.out'

Note that we can pass arguments to commands directly, so we don't need (horrible) things like TimelineSelector.FROM_MANAGE_TIMELINES_TO_PERMUTE.

Commands also set the stage for plugins, as they provide a simpler interface to modify application state programatically.

This PR also contains small changes that were covenient preliminaries for or complements to the implementation:
- Bug fixes (3be8cee, 24576bd, 6964fdd)
- Additional testing (467cb5e, f07fd4d)
- Convenient refactors (b8d15ef, 914a0bd, 974e715, 769e30b, f13fa08)
- Documentation (45dd1da)

This is a hacky, temporary solution. This state can be achieved by:
- Creating a score timeline and then deleting the beat timeline used to create it
- Restoring the app state (e.g. after an exception during a timeline command), if the svg viewer happens to be loaded before the beat timeline is restored
"" is a valid value for the color property, it means "use the default color", just as None.
…eline kinds

We should leverage classes as first-class citizens to use them instead of relying on an additional TimelineKind abstraction (TimelineKind). This is a first step towards that.
This commits introduces the commands API, a much simpler way to handle user interactions. Commands make all the following obsolete:

- All timeline and timeline component `RequestHandlers`
- `TimelineComponentSelector`
-  Several `TimelineSelectors`
- `TiliaActions`
- `user_action` fixture
- `TimelineUi.on_timeline_request`, `TimelineUI.on_timeline_component_request` (substituted by `TimelineUIs.on_timeline_command`)
- `TimelineUIs.pre_process_timeline_request()`
- `tilia\ui\timelines\collection\requests\args.py`
- Several `Post` and `Get` members
- Some `TimelineSelector` members

The core functionality is given by `command.py`, along with fuller documentation.

Usage of commands:
```
    # Register a new command
    commands.register(
        'example.command',
        callback_function,
        text='Menu Text',  # Optional: for display in Qt interface
        shortcut='Ctrl+E',  # Optional: keyboard shortcut
        icon='example_icon'   # Optional: icon name in IMG_DIR (without extension)
    )

    # Execute a command
    commands.execute('example.command', arg1, arg2, kwarg1=value1)
```

Examples of commands:
- File commands:        'file.open', 'file.save', 'file.export.img'
- Timeline commands:    'timeline.delete', 'timeline.component.copy'
- View commands:        'view.zoom.in', 'view.zoom.out'

Note that we can pass arguments to commands directly, so we don't need (horrible) things like `TimelineSelector.FROM_MANAGE_TIMELINES_TO_PERMUTE`.

Commands also set the stage for plugins, as they provide a simpler interface to modify application state programatically.
Also add tests for clear commands
Also improve message wording.
@FelipeDefensor
Copy link
Collaborator Author

This shaves of 600 lines, while still adding functionality and fixing a bunch of bugs. Feels good :)
grafik

@FelipeDefensor
Copy link
Collaborator Author

FelipeDefensor commented Nov 26, 2025

@azfoo, let me know if you want to review this (partly or fully).

@FelipeDefensor FelipeDefensor force-pushed the refactor-timeline-requests branch 2 times, most recently from 7749286 to 4749d00 Compare January 16, 2026 11:07
…created

We should find a more robust solution for this. For instance, we should warn the user that the score won't scroll automatically if the beat timeline is deleted; and we shouldn't rely on dictionaries if we care about order.
@FelipeDefensor FelipeDefensor force-pushed the refactor-timeline-requests branch from 78b077a to b90e4a0 Compare February 5, 2026 09:09
@FelipeDefensor
Copy link
Collaborator Author

@azfoo, have you run into similar CI failures? Would they be fixed by the new build system?

@azfoo
Copy link
Collaborator

azfoo commented Feb 18, 2026

A locally run Linux pytest fails on the same test. We might have to look into why.

This crash was particularly annoying when we are working on a new timeline in a separate branch, because the timeline folder wont't get deleted by git when switching branches.
Takeaway: we should use `QTest` to simulate interaction with the ui instead of calling widget methods attributes ourselves.
Takeaway: we should use `QTest` to simulate interaction with the ui instead of calling widget methods attributes ourselves.
@FelipeDefensor FelipeDefensor requested a review from azfoo February 27, 2026 10:41
@azfoo
Copy link
Collaborator

azfoo commented Mar 4, 2026

Just to clarify, why refactor some requests into commands but not the others?

azfoo added 2 commits March 4, 2026 16:08
`on_side_arrow_press` and `on_horizontal_arrow_press` are duplicates, with the latter being defined in the parent tlui.
Redefined in audiowave because elements don't have "time" attr.
@FelipeDefensor
Copy link
Collaborator Author

Just to clarify, why refactor some requests into commands but not the others?

The main goal here was to get rid of the convoluted logic around TimelineUI.on_timeline_request and TimelineUI.on_timeline_component_request. In the long term, the idea is to use the commands API for any action that might be performed by an user, and that could in later be used by plugin developers. Our "internal" requests should still use the post\get API, although at this point there still might be some things that are user actions that still use it.

@azfoo
Copy link
Collaborator

azfoo commented Mar 6, 2026

In that case, I am wondering whether it would be easier to document if all of these "external" actions were centralised in one place, like in a JSON file (see: https://github.com/ArjanCodes/examples/tree/main/2026/spec for example). The current naming system of timeline.kind.action also lends itself very nicely to become some kind of dict structure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants