Dev:Action System

From Synfig Studio :: Documentation
Jump to: navigation, search

The action system provides a good entry-point into Synfig because it functions as a stand-alone component that only interacts with Synfig's core data structure. This page is intended to provide a quick overview of the structure of the action system.

Data Structures

The action system interacts with the underlying data structure of a Synfig document. An action is most likely to affect the parameters of a given layer or object, which are described by the following classes.

Value (ValueBase)

The ValueBase class can store values of any of the 13 Value Types, such as numbers, points, and colors. Before reading or setting any values, it is important to check the type of value being used (by calling value.get_type()). Getting the contents of the value as a C++ type also requires knowing what type is expected (e.g. value.get(Real())).


A ValueNode is a value can change with time. A "converted" or "animated" parameter is always a ValueNode.

Calling "value_node(time)" retrieves the value at that given time.


Instances of this class describe a location where a ValueNode may be rather than that ValueNode itself. For example, they can refer to "the 'amount' parameter of layer x" or "the 5th point in the spline (bline)". That way, the ValueDesc continues to function even if the underlying value has been changed, exported, converted, etc.

Actions typically receive ValueDescs to operate on, only retrieving their values when they are necessary for computations.

Properties of an Action

The majority of actions are accessible by right-clicking on certain handle (ducks), parameters, or layers. At that point, Synfig Studio automatically determines which actions can be called based on the data that is currently selected.

The first step is for the action to provide a "Parameter Vocabulary" object that describes what types of parameters it needs in order to function.


Typical implementation:

  • Get the param vocab from the parent action. In most cases, it will be "ParamVocab ret(Action::CanvasSpecific::get_param_vocab());"
  • Create a parameter description for each of the parameters your action needs(see ParamDesc)
    • ParamDesc("new_value",Param::TYPE_VALUE)
    • Set the parameter options e.g. "ParamDesc(...).set_local_name(_("ValueBase"))"
    • The set actions all return the object, so you should chain them: ParamDesc(...).set_local_name(...).set_supports_multiple(...)
  • Once the parameters are set, add them to the Parameter Vocabulary e.g. "ret.push_back(ParamDesc("new_value",Param::TYPE_VALUE).set_local_name(_("ValueBase")));"

However, the parameter types alone are not always sufficient to determine whether the action should be called. As such, checking a given parameter set is done by the action:

is_candidate(const ParamList &x)

Typical implementation:

  • The first step of any candidate check is to test whether the requirements of the ParamDesc are met. "if (!candidate_check(get_param_vocab(), x)) return false;"
  • At this point, you know that all of your parameters are present and can begin testing for specific cases. (For example, the "activepointsetoff" action is only applicable when the activepoint is currently on)
  • If there are no tests to perform, return "true".

Once the parameter list is checked, Synfig Studio will pass the actual parameters to the action. The action must then retrieve their values and store them internally. This internal storage allows for the action to be un-done and re-done multiple times.

set_param(const synfig::String& name, const Action::Param &param)

Typical implementation:

  • Retrieve value of the parameter and store it in an internal variable

The action needs to be able to check whether all of its parameters are set. While the parameter list is checked when the action is called as a result of a right-click menu, any actions called from other places (e.g. by other actions) manually set parameters and must check that the proper parameters are present.


Typical implementation:

  • Return false if your custom parameters are unset
  • Check that the required parameters for CanvasSpecific actions are met "return Action::CanvasSpecific::is_ready();"

get_param(const synfig::String& name, Action::Param &param)

Typical implementation:

  • Set the value of the parameter from the action point of vue

The action is used in action like renameValueNode / renameLayer ... all case when a previous value was present. To use get_param you will need Action::set_value_provided() property during the parameter description in get_param_vocab() implemenation.

Types of actions

There are two major types of actions.

Undoable actions

The first are standard undoable actions


The second are Super-actions which can only call other actions. Since undoing a Super-action is simply undoing all of its sub-actions, these do not require an undo method.

  • Inherit from Super
  • perform() and undo() are inherited from Super and should not be overridden.
  • Instead, one should implement the prepare() method, which creates sub-actions

To add sub-actions:

  • First create the action of the needed type e.g. "Action::Handle action(Action::create("ValueDescSet"));" or "ValueDescConnect::create()" (TODO: Style review here)
  • Set its parameters:
    • The canvas, canvas interface, and current time of the current action are usually passed on to children
      • action->set_param("canvas",get_canvas());
      • action->set_param("canvas_interface",get_canvas_interface());
      • action->set_param("time",time);
    • Other parameters will vary from action to action. For ValueDescSet they might be:
      • action->set_param("value_desc",reference_value_desc);
      • action->set_param("new_value",value);
  • Add it to the action stack
    • "add_action(action)"