Command management

Command record

A command is represented in memory by a record of variable size, starting with an encoded data field and followed by zero, one or more 32-bit tokens.

VP::Cmd::Record is the base class which implements access helper methods (vp/CmdManager.h).

The encoded data field stores the following information :

Command category

Command flags

Command undoability

Command class ID

Command class

The command classes all derive from class VP::Cmd::Base and implement the interface VP::Cmd::ProcessOp. Thus, every command class implements the following members :

Methods ProcessUndo and ProcessRedo

Methods ProcessUndo and ProcessRedo are very similar. They must operate on the provided command record. The operation being performed is specified by the parameter op and is one of the VP::Result::ACTION_xxx values.

 
VP::Result::Code
ProcessUndo (VP::Result::Code op,
             VP::Cmd::RecordPtr record)
 

The parameter op must be interpreted as following :

 

 
VP::Result::Code
ProcessRedo (VP::Result::Code op,
             VP::Cmd::RecordPtr record)
 

The parameter op must be interpreted as following :

Method Purge

 
void
Purge (VP::Result::Code, VP::Cmd::RecordPtr)
 

Purge may be called either to purge the undo or the redo history, depending on the value of the code parameter :

Method Optimise

 
void
Optimise (VP::Cmd::RecordPtr)
 

Optimise may be called to collapse the current command with the previous one. Usually, this method :

Operator ()

 
void
operator () (T1 const & arg1, T2 const & arg2)
 

The command class' operator () implements the do behaviour and has zero, one or more arguments (const passed by reference). The types of the arguments can be one of the following :

Other types can be used, but an implementation for the templatized function VP::Cmd::Parse<T> must be provided (see method Execute).

Method Execute

 
void
Execute (VP::CharCPtr script)
 

This method decodes the script arguments and forwards them to the command's operator (), based on the templatized decoding function VP::Cmd::Parse<T>.

Command base class

 
class VPCoreDLL Base : public VP::Cmd::ProcessOp
{

protected:
    ...

    Base (VP::Cmd::ClassID cid, const char* name);
    Base (VP::DocumentPtr document);
};
 

Command definition

A command is best defined by using the CMD_DEFINITION macro :

 
CMD_DEFINITION (Name, (T1 arg1, T2 arg2));
 

which defines a command class named Cmd_Name, tagged with the CID_Name unique class ID. The command 'do' operation (in this case) takes two arguments of type T1 and T2.

The implementation of the command is simplified by the following macros :

Here is a partial example of an implementation for command Cmd_Name defined previously :

 
CMD_IMPLEMENT_EXECUTE_2 (Name, T1, arg1, T2, arg2)
{
    VP::Cmd::RecordPtr record = 0;
    
    record = cmd_manager->Insert (VP::Cmd::CAT_REGULAR,
                                  VP::Cmd::CID_Name,
                                  VP::Cmd::UNDO_REGULAR, 3);
    ...
}

CMD_IMPLEMENT_UNDO (Name)
{
    ...
    return VP::Result::STATUS_OK;
}

CMD_IMPLEMENT_REDO (Name)
{
    ...
    return VP::Result::STATUS_OK;
}

CMD_IMPLEMENT_PURGE (Name)
{
    ...
}

CMD_IMPLEMENT_OPTIMISE (Name)
{
    ...
}
 

There are default "no-op" macros for the undo, redo, purge and optimise methods. There are also default "not implemented" macros for the undo and the redo. And finally, there is a macro to specify that undo and redo are symmetric and need only one implementation. Pick the one you need :

 
CMD_NOP_UNDO (Name);
CMD_NOP_REDO (Name);
CMD_NOP_PURGE (Name);
CMD_NOP_OPTIMISE (Name);

CMD_UNIMPLEMENTED_UNDO (Name);
CMD_UNIMPLEMENTED_REDO (Name);

CMD_SYMMETRIC_REDO (Name);
 

To avoid having to modify/extend every command source file the day a new command method is added, it is highly recommended to use one of the following default macros :

Defining a parsable enum

It is possible to define enums and make them parsable automatically by the command manager :

 
ENUM_PARSER_BEGIN (EnumTypeName)
 { "label 1", ENUM_LABEL_1 },
 { "label 2", ENUM_LABEL_2 },
 { 0, INVALID_ENUM_LABEL }
ENUM_PARSER_END ()
 

This defines an implementation for the Parse<EnumTypeName> template which converts a textual argument into an enumeration value.

It is also possible to define the parsing table programmatically, using the following macro :

const char*
RetEnumLabelName (EnumTypeName value)
{
    ...
}
 
ENUM_PARSER (EnumTypeName, RetEnumLabelName,
             INVALID_ENUM_LABEL, ENUM_LABEL_END)
 

This defines an implementation for the Parse<EnumTypeName> template which converts a textual argument into an enumeration value. The textual representations of the enum values are provided by a function; INVALID_ENUM_LABEL should define an invalid label and ENUM_LABEL_END the last valid label. Label values should not start below 0 (but for the invalid value).

Command implementation

...

Exec command

The generic command Exec takes the contents of either the named variable or the !action variable and executes it as if it were a command itself.

If the variable begins with 'Dialog.', then this substring will be stripped and replaced by the name of the dialog; this allows the reuse of the same GUI description in different dialogs, with different command bindings.

The elements embedded within {} are substituted by the values of their corresponding variables. If the variables are, for example :

 
!action = Dialog.Test {a1} {a2}
a1 = foo
a2 = bar 
 

and the dialog is named 'Settings', then the following command will get executed :

 
Settings_Test foo bar
 

Adding a {*} in the !action variable will force an additional substitution pass, which allows the use of meta variables (if a variable contains another variable reference, the final variable value will be used, in the end).

List of available commands

The following commands are currently implemented by VP :