Skip to content

Draft: RFC: qml use state machines for tracking complex widget states

Pierre Lamot requested to merge chub/vlc:qml/dsm-dev into master

This proposal is for the inclusion of the QtQml.MachineState to manage the state of items that have a complex state.

The idea is to rely on state machines to handle the different states of a given component, and to manage how the component will transition from one state to the other. This aim to move the state logic outside the visual part, the visual will react to the active states (how it should look in a given state) and will emit signal on user actions that will affect or not the current state.

For the experiment I tried to refactor some component that I found were good candidate:

  • volume widget/seek bar: edit and reactive state, when the user modifies the slider, the widget should ignore the values from the player, in reactive state it should update with the player, in paintOnly mode, it should neither read values from the player not update the player

  • player.qml: lots of state and interaction (audio, pined controls, control autohiding, autohiding locking mechanism) + the playlist visibility

note that this is still an RFC, the goal is to open the discussion in the first place

@jagannatharjun @fuzun @bunjee

Pros and Cons

pros:

  • Better decoupling of behavior and presentation, less logic in the visual part of the widgets, they usually send events to the FSM, and react to the states from the FSM they're interested into.

  • States machines are usually easy to understand, especialy once visualized with their UML counterpart

  • It usually a good way of modeling designs from our graphists as they usually gives us views of the application in various states.

  • This ease the use of timer, for instance all the interactions with the timer in Player.qml can be reduced to a timeout transition from the AutoHideVisible state.

  • This is a local approach, compared to design pattern like Flux or Redux, no need to change everything. Only the component that need to manage complex state can benefit from it.

  • Good extensibility, adding a new state or a substate is a matter of adding the entry and connecting the signals

  • We already do state management, this aim to be a better representation of it.

cons:

  • This use the package QtQml.MachineState, so this adds yet another Qml dependency. This is a part of QtDeclarative, already in the contribs, so it's not really that exotic. This shouldn't be an issue for windows and snap version, but linux folks probably need to install it.

  • This tend to be a bit verbose in terms of line of code, but the code is usually simple.

  • As with every system, there is a bit of a learning curve, especially when designing components.

  • YAGNI: well, it already works without this.

FAQ

  • Don't QML already provides states and transition?

    QML states are a good tool to represent the visual properties and how they shoud animate between the states

    It does not provide, hierarchical states, transitions on event (this needs to be done manually),

    I know its possible to translate hierarchical FSM to a flat one, though this often leads to a combinatory explosion of the number of states.

    I think we should continue to use QML State/Transition for the use case we alreay use them for, managing the visual properties and animations of a component

  • Do we need the QtQml.StateMachine package:

    Qt provides different tool to work with state machines:

    • We can achieve the same using Qt StateMachine C++ API, integration with Qml should be made manually on top of it.

    • SCXML to C++ code conversion tool, the advantage is that this use a standard format that can be visually edited (or at least represented) using various tools. but this seems a bit overkill and would complexify the build process (more over it not available in meson yet), plus you have the same drawbacks as with the native C++ implementation regarding QML integration.

    • QQuickItem state & transitions: see previous question

    • QtQml.StateMachine: provides the "best" integration within QML

  • Should we use state machine for everything:

    Hell no! QML property binding does a very good job at exposing orthogonal states. This is good tool for representing complex state, probably overkill and over-verbose for simple state.

Use case

As "a picture is worth a thousand words", here is a visualisation of the state machine used for the player controller (sorry for the overlapping arrows, plantuml limitations).

player_fsm

We have 3 main mode the the controllers: audio, video pined and video with auto-hide. AutoHide is either visible or hidden, visible will automatically switch to hidden after a timeout. Visible can be "locked" in some case (user is interacting with a menu or with the playlist)

The playlist should be only visible when not floating and visible, having a video embed will automatically hide the playlist in the view, but without affecting the global setting, switching back to an audio media or to the medialibrary view will restore the playlist visibility. asking for the playlist to be shown when video is embed, will show the playlist.

Further documentation on FSM for GUI

TODO

  • add dependency for windows package

  • add dependency for snap package

Merge request reports