Difference between revisions of "Dev:Action System"

From Synfig Studio :: Documentation
Jump to: navigation, search
(Some infor on value/valuenode/valuedesc)
(Make page more coherent)
Line 2: Line 2:
 
At the moment there are only some brief notes.
 
At the moment there are only some brief notes.
  
 +
==Data Structure==
  
Types of actions
+
The action system, for the most part, interacts only with document data structure. As such, it is important to understand what this structure is consists of.
  
*Inherit from [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1Super.html Super]
+
Value (ValueBase): The ValueBase class can store values of any of the 13 {{l|Dev:Types|Types}}. As such, using Values requires one to check the type of the given object (by calling value.get_type()) and to know the value type before fetching its contents (e.g. value.get(Real())).
**can only call other actions
+
**implement a prepare() method to create sub-actions
+
  
 +
ValueNode: A {{l|ValueNode}} is a value that changes with time. Calling value_node(time) retrieves the value at that given time.
  
*Inherit from [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1Undoable.html Undoable] and [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1CanvasSpecific.html CanvasSpecific]
+
ValueDesc: Instances of this class describe a ''location'' where a ValueNode may be rather than that ValueNode itself. (For example "the 'amount' parameter of layer x" or "the 5th point in the bline"). That way, the ValueDesc consistently refers to the same location even if the underlying value has been changed, exported, converted, etc.
**implement perform() and undo()
+
  
  
  
get_param_vocab()
+
Actions typically receive ValueDescs to operate on and will only retrieve the actual value at that point if necessary
  
Each action must be able to supply a "Parameter Vocabulary" object. This object specifies what parameters the action requires and what type they need to be.
+
==Properties of an Action==
 +
 
 +
The majority of actions are accessible by right-clicking on certain 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.
 +
 
 +
get_param_vocab()
  
 +
Typical implementation:
 
* Get the param vocab from the parent action. In most cases, it will be "ParamVocab ret(Action::CanvasSpecific::get_param_vocab());"
 
* 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(see [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1ParamDesc.html ParamDesc])
+
* Create a parameter description for each of the parameters your action needs(see [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1ParamDesc.html ParamDesc])
 
** ParamDesc("new_value",Param::TYPE_VALUE)
 
** ParamDesc("new_value",Param::TYPE_VALUE)
 
** Set the parameter options e.g. "ParamDesc(...).set_local_name(_("ValueBase"))"
 
** 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(...)
 
** The set actions all return the object, so you should chain them: ParamDesc(...).set_local_name(...).set_supports_multiple(...)
* Once the parameters are set, they should be added to the Parameter Vocabulary e.g. "ret.push_back(ParamDesc("new_value",Param::TYPE_VALUE).set_local_name(_("ValueBase")));"
+
* 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")));"
  
  
is_candidate(const ParamList &x)
+
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:
  
Any time the user selects some object (be it a duck, parameter, layer, etc) and right-clicks, she is offered a context menu containing all applicable actions. Synfig checks for candidates by passing them a list of parameters and asking if they are acceptable.
+
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;"
 
* 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)
 
* 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, simply return true.
 
* If there are no tests to perform, simply 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)
 
set_param(const synfig::String& name, const Action::Param &param)
  
When passed a parameter, the action must be able to determine if it is the right type and, if so, set an internal variable that stores the value of the parameter. All action parameters are stored in variables so that they can be accessed again if the action is undone or has been undone and now should be performed again.
+
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.
  
 
is_ready()
 
is_ready()
  
This method should check that all internal variables needed have been properly initialized. This test is performed before any action is called to ensure that it has all of its variables set and can be executed safely.
+
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();"
  
  
prepare()
 
  
(Only applies to actions inheriting from Super). The prepare function should create sub-actions that need to be performed and call "add_action" or "add_action_front" on them. There is no need to manually implement perform() and undo(), as these will be done automatically by either performing all of the sub-actions or undoing them.
+
==Types of actions==
  
Actions are added by:
+
There are two major types of actions.
 +
 
 +
The first are standard undoable actions
 +
*These inherit from [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1Undoable.html Undoable] and [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1CanvasSpecific.html CanvasSpecific]
 +
*It is necessary to implement perform() and undo()
 +
 
 +
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 [http://download.tuxfamily.org/synfig/api/synfig-studio/classsynfigapp_1_1Action_1_1Super.html Super]
 +
*The prepare() method creates sub-actions and adds them to the stack by calling "add_action(action)"
 +
*perform() and undo() are inherited from Super and should not be overridden.
 +
 
 +
Sub-actions are added by:
  
 
* First create the action of the needed type "Action::Handle action(Action::create("ValueDescSet"));" or "ValueDescConnect::create()" (TODO: Style review here)
 
* First create the action of the needed type "Action::Handle action(Action::create("ValueDescSet"));" or "ValueDescConnect::create()" (TODO: Style review here)
Line 61: Line 82:
 
***action->set_param("value_desc",reference_value_desc);
 
***action->set_param("value_desc",reference_value_desc);
 
***action->set_param("new_value",value);
 
***action->set_param("new_value",value);
 
Terminology:
 
 
Value (ValueBase): The ValueBase class can store values of any of the 13 {{l|Dev:Types|Types}}. Actions involved in setting a value typically require an object of this type for a parameter. Since a given instance of ValueBase may in fact store objects of different types, it is important to check the type (by calling value.get_type()) and then get the value in the proper type (e.g. value.get(Real()))
 
 
ValueNode: A {{l|ValueNode}} is a value that changes with time.
 
 
ValueDesc: Instances of this class describe a ''location'' where a ValueNode may be rather than that ValueNode itself. (For example "the 'amount' parameter of layer x" or "the 5th point in the bline"). That way, the ValueDesc consistently refers to the same location even if the underlying value has been changed, exported, converted, etc.
 

Revision as of 20:39, 11 October 2010

This page is a work-in-progress documentation of the action system. At the moment there are only some brief notes.

Data Structure

The action system, for the most part, interacts only with document data structure. As such, it is important to understand what this structure is consists of.

Value (ValueBase): The ValueBase class can store values of any of the 13 Types. As such, using Values requires one to check the type of the given object (by calling value.get_type()) and to know the value type before fetching its contents (e.g. value.get(Real())).

ValueNode: A ValueNode is a value that changes with time. Calling value_node(time) retrieves the value at that given time.

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


Actions typically receive ValueDescs to operate on and will only retrieve the actual value at that point if necessary

Properties of an Action

The majority of actions are accessible by right-clicking on certain 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.

get_param_vocab()

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, simply 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.

is_ready()

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();"


Types of actions

There are two major types of 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
  • The prepare() method creates sub-actions and adds them to the stack by calling "add_action(action)"
  • perform() and undo() are inherited from Super and should not be overridden.

Sub-actions are added by:

  • First create the action of the needed type "Action::Handle action(Action::create("ValueDescSet"));" or "ValueDescConnect::create()" (TODO: Style review here)
  • Set it's parameters:
    • The canvas, canvas interface, and current time are usually simply 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);