Animation

Detailed Description

Classes

class  Animation
 Animation is a helper class for setting up UI animations. More...
 
class  AnimationHelper
 Provides simple static functions wrapping common transformations applied to Qt Widgets. More...
 
class  Scene
 This is an internal object used for tracking Scene information. More...
 
class  ContentAlignmentAnimatingWidget
 Helper widget that animates the alignment of a given child widget. More...
 
class  SceneManager
 Moving between different UI states can be very tedious and end up producing incredibly complex and often indecipherable code. More...
 
class  SceneManager::SceneBuilder
 The SceneBuilder class is a helper for the buildup/teardown process of a Scene. More...
 

Class Documentation

◆ Animation

class Animation

Animation is a helper class for setting up UI animations.

Animations can be created as standalone objects (for simpler single-item animations), and can also be used within the Scene Manager for transitions between scenes.

By default, Animation upon being started will interpolate between 0.0 and 1.0.

Accessibility General motion can be enabled/disabled via the binaryninja.ui.motion setting. Whenever motion is disabled, instead of interpolating between values, animations will only fire the start and end value.

Your options regarding this are:

It is worth keeping in mind that this is an accessibility feature, and overriding reduced motion should only be done where it is explicitly appropriate. (e.g. Loading spinners and other simple critical animations.)

Signals

void ended ()
 Signal fired after the animation ends and all callbacks have fired. More...
 

Public Member Functions

Animationnamed (std::string name)
 Set the name of the animation. More...
 
AnimationwithDuration (int msecs)
 Set the duration of the animation; that is, "how long should it take to interpolate between 0.0 and 1.0?". More...
 
AnimationwithEasingCurve (QEasingCurve curve)
 Allows setting the QEasingCurve for this animation. More...
 
AnimationthenOnStart (std::function< void(QAbstractAnimation::Direction)> startCallback)
 Callback to fire at the start of the animation. More...
 
AnimationthenOnValueChanged (std::function< void(double)> callback)
 Callback to fire when this animation's progress is updated. More...
 
AnimationthenUpdatePropertyOnValueChanged (QObject *obj, QString property)
 By passing this an object and associated property name, a Q_PROPERTY of a given object can be updated with the animation's state. More...
 
AnimationthenOnEnd (std::function< void(QAbstractAnimation::Direction)> endCallback)
 Callback to fire at the end of the animation. More...
 
AnimationoverridingReducedAnimationsForAVeryGoodReason ()
 ONLY use this if you are doing something like a loading spinner. AVOID IT. More...
 
void start ()
 Fire the animation. More...
 

Static Public Member Functions

static Animationcreate (QObject *owner=nullptr)
 Create a new animation object. More...
 
static AnimationcreateCopy (Animation *animation)
 Creates a copy of the target animation. More...
 
static bool reducedMotionEnabled ()
 Whether reduced motion is enabled for the BinaryNinja Application. More...
 

Protected Member Functions

bool event (QEvent *event) override
 
void updateCurrentValue (const QVariant &value) override
 
void updateState (QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override
 

Member Function Documentation

◆ create()

static Animation * Animation::create ( QObject *  owner = nullptr)
static

Create a new animation object.

A note on lifetimes: if a given Animation is passed to a SceneManager , the SceneManager will take ownership of the Animation , and it will not be deleted until the SceneManager itself is.

Parameters
owner
Returns
Pointer to the new Animation object

◆ createCopy()

static Animation * Animation::createCopy ( Animation animation)
static

Creates a copy of the target animation.

This will duplicate all configurable values, callbacks, etc.

Lifetime note: The parent of the new animation will be set to the target's.

Parameters
animationAnimation to be copied.
Returns
Pointer to the new Animation object

◆ reducedMotionEnabled()

static bool Animation::reducedMotionEnabled ( )
inlinestatic

Whether reduced motion is enabled for the BinaryNinja Application.

This will return true if the `binaryninja.ui.motion` setting is enabled.

The `binaryninja.ui.motion` setting will be enabled automatically if the Operating System's reduce motion setting is turned on.

Returns
Whether reduced motion is enabled.

◆ named()

Animation * Animation::named ( std::string  name)
inline

Set the name of the animation.

This is only useful for debugging purposes, however if you are working with several animations in a SceneManager, it's highly recommended you give it something, as error messages regarding this animation will report it.

Parameters
nameName of the animation.
Returns
Pointer to this Animation object

◆ withDuration()

Animation * Animation::withDuration ( int  msecs)
inline

Set the duration of the animation; that is, "how long should it take to interpolate between 0.0 and 1.0?".

Parameters
msecsDuration of the animation in msecs;
Returns
Pointer to this Animation object

◆ withEasingCurve()

Animation * Animation::withEasingCurve ( QEasingCurve  curve)
inline

Allows setting the QEasingCurve for this animation.

It's recommended you read the official Qt documentation here: https://doc.qt.io/qt-6/qeasingcurve.html

Parameters
curveEasing curve
Returns
Pointer to this Animation object

◆ thenOnStart()

Animation * Animation::thenOnStart ( std::function< void(QAbstractAnimation::Direction)>  startCallback)

Callback to fire at the start of the animation.

It will be passed an AnimationDirection value, which is relevant when using animations for linear scene transitions.

See also
SceneManager::SceneBuilder::onSetup
Note
This will fire at the start even if the animation is running backwards, i.e. in a linear scene transition.
Parameters
startCallbackFunction to be called
Returns
Pointer to this Animation object

◆ thenOnValueChanged()

Animation * Animation::thenOnValueChanged ( std::function< void(double)>  callback)

Callback to fire when this animation's progress is updated.

This is where the bulk of your animation logic will go.

Will be passed a double value between 0.0 and 1.0.

Parameters
callbackCallback to be fired
Returns
Pointer to this Animation object

◆ thenUpdatePropertyOnValueChanged()

Animation * Animation::thenUpdatePropertyOnValueChanged ( QObject *  obj,
QString  property 
)

By passing this an object and associated property name, a Q_PROPERTY of a given object can be updated with the animation's state.

It will be passed a double , containing a value between 0.0 and 1.0.

(This is functionally equivalent to thenOnValueChanged, with the primary difference being where you decide to implement your animation logic.)

This can be particularly useful if you have an opacity property you want to fade in or out, or you prefer to implement some animation related logic in a QProperty setter. It can also be useful for debugging via the UI debugger.

An example usage of this involves manipulating the properties of ContentAlignmentAnimatingWidget to move a widget for your animation.

Parameters
objQObject target
propertyQ_PROPERTY target name
Returns
Pointer to this Animation object

◆ thenOnEnd()

Animation * Animation::thenOnEnd ( std::function< void(QAbstractAnimation::Direction)>  endCallback)

Callback to fire at the end of the animation.

It will be passed an AnimationDirection value, which is relevant when using animations for linear scene transitions.

See also
SceneManager::SceneBuilder::onTeardown
Note
This will fire at the end even if the animation is running backwards, i.e. in a linear scene transition.
Parameters
endCallbackFunction to be called
Returns
Pointer to this Animation object

◆ overridingReducedAnimationsForAVeryGoodReason()

Animation * Animation::overridingReducedAnimationsForAVeryGoodReason ( )
inline

ONLY use this if you are doing something like a loading spinner. AVOID IT.

◆ start()

void Animation::start ( )

Fire the animation.

These events will occur, in order:

  1. Start callbacks will be fired.
  2. The internal state will begin iterating through 0.0 to 1.0, or 1.0 to 0.0 if backwards. Callbacks passed by thenOnValueChanged will fire now. If reduced motion is enabled, this will only fire the start and end value.
  3. After reaching its destination value, End callbacks will be fired.

◆ ended

void Animation::ended ( )
signal

Signal fired after the animation ends and all callbacks have fired.

Warning
Do NOT use this. Do NOT expect this to work the way you intend. Your connection WILL be disconnected unless you explicitly reconnect it every time the animation is about to fire. There are callbacks that do what you want.

◆ event()

bool Animation::event ( QEvent *  event)
overrideprotected

◆ updateCurrentValue()

void Animation::updateCurrentValue ( const QVariant &  value)
overrideprotected

◆ updateState()

void Animation::updateState ( QAbstractAnimation::State  newState,
QAbstractAnimation::State  oldState 
)
overrideprotected

◆ AnimationHelper

class AnimationHelper

Provides simple static functions wrapping common transformations applied to Qt Widgets.

Static Public Member Functions

static void SetLabelOpacity (QLabel *label, double opacity)
 Set the opacity of a given QLabel. More...
 

Member Function Documentation

◆ SetLabelOpacity()

static void AnimationHelper::SetLabelOpacity ( QLabel *  label,
double  opacity 
)
static

Set the opacity of a given QLabel.

Specifically, this will set the text opacity.

Parameters
labelTarget label.
opacityTarget opacity. Value between 0.0 and 1.0.

◆ Scene

class Scene

This is an internal object used for tracking Scene information.

Create an instance of a scene via AnimationStateMachine->createScene();

Signals

void setupScene (std::string transitioningFrom)
 
void teardownScene (std::string transitionedTo)
 

Member Function Documentation

◆ setupScene

void Scene::setupScene ( std::string  transitioningFrom)
signal

◆ teardownScene

void Scene::teardownScene ( std::string  transitionedTo)
signal

◆ ContentAlignmentAnimatingWidget

class ContentAlignmentAnimatingWidget

Helper widget that animates the alignment of a given child widget.

Public Slots

void updateWithTransitionState (double transitionState)
 

Public Member Functions

 ContentAlignmentAnimatingWidget (QWidget *parent=nullptr)
 
Qt::Alignment stopOneAlignment () const
 
void setStopOneAlignment (Qt::Alignment align)
 
Qt::Alignment stopTwoAlignment () const
 
void setStopTwoAlignment (Qt::Alignment align)
 
QMargins padding () const
 
void setPadding (QMargins padding)
 
QWidget * widget () const
 
void setWidget (QWidget *widget)
 

Protected Member Functions

void resizeEvent (QResizeEvent *event) override
 

Properties

Qt::Alignment stopOneAlignment
 
Qt::Alignment stopTwoAlignment
 
QMargins padding
 
QWidget * widget
 

Constructor & Destructor Documentation

◆ ContentAlignmentAnimatingWidget()

ContentAlignmentAnimatingWidget::ContentAlignmentAnimatingWidget ( QWidget *  parent = nullptr)

Member Function Documentation

◆ stopOneAlignment()

Qt::Alignment ContentAlignmentAnimatingWidget::stopOneAlignment ( ) const
inline

◆ setStopOneAlignment()

void ContentAlignmentAnimatingWidget::setStopOneAlignment ( Qt::Alignment  align)
inline

◆ stopTwoAlignment()

Qt::Alignment ContentAlignmentAnimatingWidget::stopTwoAlignment ( ) const
inline

◆ setStopTwoAlignment()

void ContentAlignmentAnimatingWidget::setStopTwoAlignment ( Qt::Alignment  align)
inline

◆ padding()

QMargins ContentAlignmentAnimatingWidget::padding ( ) const
inline

◆ setPadding()

void ContentAlignmentAnimatingWidget::setPadding ( QMargins  padding)
inline

◆ widget()

QWidget * ContentAlignmentAnimatingWidget::widget ( ) const
inline

◆ setWidget()

void ContentAlignmentAnimatingWidget::setWidget ( QWidget *  widget)

◆ resizeEvent()

void ContentAlignmentAnimatingWidget::resizeEvent ( QResizeEvent *  event)
inlineoverrideprotected

◆ updateWithTransitionState

void ContentAlignmentAnimatingWidget::updateWithTransitionState ( double  transitionState)
slot

Property Documentation

◆ stopOneAlignment

Qt::Alignment ContentAlignmentAnimatingWidget::stopOneAlignment
readwrite

◆ stopTwoAlignment

Qt::Alignment ContentAlignmentAnimatingWidget::stopTwoAlignment
readwrite

◆ padding

QMargins ContentAlignmentAnimatingWidget::padding
readwrite

◆ widget

QWidget* ContentAlignmentAnimatingWidget::widget
readwrite

◆ SceneManager

class SceneManager

Moving between different UI states can be very tedious and end up producing incredibly complex and often indecipherable code.

Adding animations into the mix does not help.

The SceneManager class, along with the rest of the utilities provided for Animation, aim to help with writing more maintainable and parseable code for UI state transitions.

This documentation block goes over the general concepts of this class, while the implementation details are documented on the functions themselves.

Note
While this manager has several features to make things nicer, you should always have a clear idea of which state you are in, which state you want to get to, how those two are connected, and the exact behavior that will result from firing a given scene transition.
Multi-scene UI can easily become very complex, and while this class can help organize and facilitate that, care should always be taken to ensure it is being used properly and clearly.
Tools such as https://asciiflow.com/ and other drawing utilities are often useful to create a clearer overview of the "State Machine" that you are building.
When the SceneManager encounters errors related to transitions, programmer error is presumed, and the application will halt and output debug information via stderr.

A general note on multi-stage animations in Binary Ninja:

These should ideally not be used in locations in the application where interactions should feel instant. Login screens, the new tab page, update UI, etc. are valid applications for this; however, animations within your analysis plugin providing UI may feel clunky and out of place.

This manager can, however, be used for managing multiple scenes regardless, with the Animations' simply lacking a valueUpdated callback and duration set to 0ms, relying on setup and teardown callbacks instead.

Linear connections

Linear connections are useful for setting up multi-stage UIs. They can "pathfind" between connected scenes, move in both directions, and be swapped via transitionToScene .

connectScenesLinear will create a bidirectional link between two Scenes, firing the animation in reverse if a backwards transition is requested. See the Animation class documentation for more info on reversed animations.

     ┌─────────────┐           ┌─────────────┐           ┌─────────────┐
     │             ├──────────►│             ├──────────►│             │
     │   Scene 1   │ Animat. 1 │   Scene 2   │ Animat. 2 │   Scene 3   │
     │             │◄──────────┤             │◄──────────┤             │
     └─────────────┘           └─────────────┘           └─────────────┘
 

In the above described chain, if one were currently in Scene 1, transitionToScene("scene3") could be called, which would walk the chain of required scenes to transition to Scene 3. In this case, Animation 1 would be fired, and then immediately after it finished, Animation 2 would be fired, ending in Scene 3.

Note
It is worth noting that, in the case of Scene 1 having a "Direct Connection" to Scene 3, that the direct connection would be prioritized. The Direct Connections section goes over this in more detail.

One could also call mySceneManager->transitionToScene(mySceneManager->nextScene()) , which would transition from Scene 1 to Scene 2.

Linear connection loops

These aren't recommended, as they can cause minor confusion related to linear pathfinding

See SceneManager::transitionToScene .

Linear connections can loop back around. This can be useful for setting up simple on-off transitions, carousels, etc. However, in almost all cases, it can be more clear to utilize direct connections for loopbacks, to more explicitly define the behavior required, and to avoid confusion regarding the linear pathfinding.

                ┌─────────────┐           ┌─────────────┐           ┌─────────────┐
     ──────────►│             ├──────────►│             ├──────────►│             ├───────────
      Animat. 3 │   Scene 1   │ Animat. 1 │   Scene 2   │ Animat. 2 │   Scene 3   │ Animat. 3
     ───────────┤             │◄──────────┤             │◄──────────┤             │◄──────────
                └─────────────┘           └─────────────┘           └─────────────┘
 

Direct connections

Direct connections are the alternative to linear ones. They allow building out much more complex graphs, more explicit handling of loopbacks, etc, at the cost of not being able to "pathfind" to other animations.

Instead, a scene with only direct connections MUST transition to one it is directly connected to.

Direct connections will also override Linear ones. When doing pathfinding, the Scene Manager will look for any direct links between the current and target scenes before checking for ones Linearly connected.

For more information on pathfinding, see SceneManager::transitionToScene

Scene setup/teardown

Scenes also have setup and teardown callbacks. See also SceneBuilder .

These differ from Animation start and end callbacks in that, a Scene can have multiple animations between different scenes, but may have some shared code that always needs to be ran when transitioning to/away from this scene.

Overview The following is an exhaustive list of what will happen when transitioning between two example scenes, "scene1" and "scene2"

  1. A suitable path is found between the two. In this case we assume they are connected linearly to one another.
  2. "scene2" 's onSetup callback will be fired.
  3. Animation begins.
  4. Animation onStart callbacks fired.
  5. Animation value interpolation loop. onValueChanged callbacks fired.
  6. Animation onEnd callbacks fired.
  7. "scene1" 's onTeardown callbacks are fired.

To transition back, we call, transitionToScene("scene1").

  1. We find the bidirectional path back to the first animation.
  2. "scene1" 's onSetup callback is fired.
  3. Animation begins.
  4. Animation onStart callbacks fired, this time with the direction argument set to AnimationDirection::Backwards
  5. Animation value interpolation loop runs backwards, going from 1.0 to 0.0
  6. Animation onEnd callbacks fired, this time with the direction argument set to AnimationDirection::Backwards
  7. "scene2" 's onTeardown callbacks are fired.

Public Member Functions

 ~SceneManager ()
 
 SceneManager (QObject *owner=nullptr)
 Create a new Scene Manager. More...
 
SceneBuilder createScene (const std::string &name)
 Create a scene with a given name. More...
 
void setupInitialScene (const std::string &initial)
 Set the initial scene and perform the required setup to load it. More...
 
void connectScenes (const std::string &firstScene, const std::string &secondScene, Animation *animation)
 Create a connection between firstScene and secondScene with a given animation. More...
 
void connectScenesLinear (const std::string &firstScene, const std::string &secondScene, Animation *animation)
 Creates a linear connection between two scenes with a given animation. More...
 
const std::string currentScene ()
 Get the currently active scene. More...
 
void transitionToScene (const std::string targetScene)
 Transition to a given scene. More...
 
std::string prevScene ()
 Returns the name of the current scene's "Previous Scene", if this scene is part of a linear chain. More...
 
std::string nextScene ()
 Returns the name of the current scene's "Next Scene", if this scene is part of a linear chain. More...
 
bool transitionRunning () const
 Check whether a transition is currently running. More...
 

Constructor & Destructor Documentation

◆ ~SceneManager()

SceneManager::~SceneManager ( )

◆ SceneManager()

SceneManager::SceneManager ( QObject *  owner = nullptr)

Create a new Scene Manager.

Note
Object lifetime: If an owner is not passed, YOU are responsible for deleting this.
Parameters
ownerParent QObject. When the parent is deallocated, this SceneManager will be as well.

Member Function Documentation

◆ createScene()

SceneBuilder SceneManager::createScene ( const std::string &  name)

Create a scene with a given name.

This name will be used as the scene's "identifier", and is what should be passed to all functions of this class that request a scene name.

Parameters
nameName of the Scene
Returns
a SceneBuilder object, for you to add setup/teardown callbacks to.

◆ setupInitialScene()

void SceneManager::setupInitialScene ( const std::string &  initial)

Set the initial scene and perform the required setup to load it.

Warning
This MUST be called for the SceneManager to operate and perform transitions.

onSetup will be called for the target scene, with the argument ""

Parameters
initialtarget scene

◆ connectScenes()

void SceneManager::connectScenes ( const std::string &  firstScene,
const std::string &  secondScene,
Animation animation 
)

Create a connection between firstScene and secondScene with a given animation.

This will create a direct link, instead of a linear one. If there's a linear path between these two scenes, this connection will overrule that and use the provided animation to transition directly instead.

This can also be used for transitions that do not need to be bidirectional.

Parameters
firstSceneInitial scene
secondSceneTarget scene
animationAnimation to be used when transitioning from firstScene to secondScene.

◆ connectScenesLinear()

void SceneManager::connectScenesLinear ( const std::string &  firstScene,
const std::string &  secondScene,
Animation animation 
)

Creates a linear connection between two scenes with a given animation.

In terms of direction, the two scenes will be treated (and connected) as follows:

                      ◄─── Previous
                    ┌────────────────────┐
    ┌───────────────▼───┐             ┌──┴────────────────┐
    │                   │             │                   │
    │ "firstScene"      │ "animation" │ "secondScene"     │
    │                   │             │                   │
    └───────────────┬───┘             └──▲────────────────┘
                    └────────────────────┘
                             Next ──►

By connecting a third scene with "secondScene" here as the first scene, you can create a chain.

Parameters
firstSceneFirst scene to connect
secondSceneSecond scene to connect
animationAnimation linking the two scenes together, which will be used whenever transitioning between the two.

◆ currentScene()

const std::string SceneManager::currentScene ( )

Get the currently active scene.

Returns
The name of the currently active scene.

◆ transitionToScene()

void SceneManager::transitionToScene ( const std::string  targetScene)

Transition to a given scene.

This will look for, in this order:

  1. A direct link between the current Scene and provided targetScene
  2. Whether the target scene is directly before or after this scene
  3. Whether the target scene can be located by walking the scene chain forwards
  4. Whether the target scene can be located by walking the scene chain in reverse.

It will then kick off the transition to that scene, if it was found. If it was not, serious programmer error is presumed and the application will halt and output debug information via stderr.

Parameters
targetSceneScene to transition to.

◆ prevScene()

std::string SceneManager::prevScene ( )

Returns the name of the current scene's "Previous Scene", if this scene is part of a linear chain.

If this scene was never passed to connectScenesLinear as the second scene, this will be empty.

Returns
Name of previous scene, empty if current is not linearly connected.

◆ nextScene()

std::string SceneManager::nextScene ( )

Returns the name of the current scene's "Next Scene", if this scene is part of a linear chain.

If this scene was never passed to connectScenesLinear as the first scene, this will be empty.

Returns
Name of next scene, empty if current is not linearly connected.

◆ transitionRunning()

bool SceneManager::transitionRunning ( ) const
inline

Check whether a transition is currently running.

Returns
Whether a transition is currently running.

◆ SceneManager::SceneBuilder

class SceneManager::SceneBuilder

The SceneBuilder class is a helper for the buildup/teardown process of a Scene.

Warning
DO NOT create an instance of this class directly! You will be given an instance of it via SceneManger::createScene!

This is primarily useful for putting up UI prep code, via callbacks to be fired before the Animation is hit. It also allows separating code that should be preserved even if the animations and links between scenes are modified.

As an example, in a multi-scene dialog, one would "place" the objects for the next scene in a setup callback, and would remove or hide them in a teardown callback.

onSetup will be passed the name of the scene being transitioned away from.

onTeardown will be passed the name of the scene that was transitioned to.

Example

An example Scene setup pattern might look like this.

auto selecting = m_sceneManager->createScene("selecting");
// Called BEFORE the transition to this scene starts.
selecting.onSetup([this](std::string) {
m_someLabel->setVisible(true);
m_actionButton->setText("Update");
m_cancelButton->setText("Cancel");
// We want to reconnect our buttons to different signals, now.
m_actionButton->disconnect();
m_cancelButton->disconnect();
connect(m_actionButton, &QPushButton::clicked, this, &MyDialog::ADifferentCallback);
// Maybe in the past this sent us back a scene, but now we want it to close the dialog entirely.
connect(m_cancelButton, &QPushButton::clicked, this, &QWidget::close);
});
// Called AFTER the animation transitioning away from this scene has ended.
selecting.onTeardown([this](std::string) {
m_someLabel->setVisible(false);
m_actionButton->disconnect();
m_cancelButton->disconnect();
});

onSetup and onTeardown also return references to the given SceneBuilder, so, if it were preferred, one could instead use the following pattern.

m_sceneManager->createScene("modifying")
.onSetup([this](std::string){
m_someLabel->setVisible(true);
})
.onTeardown([this](std::string){
m_someLabel->setVisible(false);
});
SceneBuilder & onTeardown(std::function< void(std::string toScene)> func)

Public Member Functions

 SceneBuilder (SceneManager *mgr, const std::string &name)
 
SceneBuilderonSetup (std::function< void(std::string fromScene)> func)
 
SceneBuilderonTeardown (std::function< void(std::string toScene)> func)
 

Constructor & Destructor Documentation

◆ SceneBuilder()

SceneManager::SceneBuilder::SceneBuilder ( SceneManager mgr,
const std::string &  name 
)

Member Function Documentation

◆ onSetup()

SceneBuilder & SceneManager::SceneBuilder::onSetup ( std::function< void(std::string fromScene)>  func)

◆ onTeardown()

SceneBuilder & SceneManager::SceneBuilder::onTeardown ( std::function< void(std::string toScene)>  func)