Open Search
    Commands Manual

    About

    maxon::CommandClassInterface is a base interface for standardized commands. Such a command operates solely on the given input data and can be used in various situations.

    CommandClassInterface

    A custom command must implement these two methods:

    An implementation for such a data object must be based on maxon::CommandDataInterface which in return in based on maxon::DataDictionaryObjectInterface.

    Note
    All data related to the execution of the command must be stored in the maxon::CommandDataRef object.

    Interactive commands (e.g. tools) can also implement maxon::CommandInteractionClassInterface:

    // This example implements both a command data and a simple command.
    //------------------------------------------------------------------------------
    // Simple data
    //------------------------------------------------------------------------------
    class ExampleDataImpl : public Component<ExampleDataImpl, CommandDataInterface>
    {
    MAXON_COMPONENT(NORMAL, DataDictionaryObjectClass);
    public:
    MAXON_METHOD Result<void> SetData(ForwardingDataPtr&& key, Data&& data)
    {
    return super.SetData(std::move(key), std::move(data));
    }
    MAXON_METHOD Result<Data> GetData(const ConstDataPtr& key) const
    {
    return super.GetData(std::move(key));
    }
    };
    // register data
    MAXON_COMPONENT_CLASS_REGISTER(ExampleDataImpl, CommandDataClasses, "net.maxonexample.commanddata.exampledata");
    //------------------------------------------------------------------------------
    // Simple command
    //------------------------------------------------------------------------------
    class ExampleCommandImpl : public Component<ExampleCommandImpl, CommandClassInterface>
    {
    public:
    MAXON_METHOD Result<COMMANDSTATE> GetState(CommandDataRef& data) const
    {
    }
    MAXON_METHOD Result<COMMANDRESULT> Execute(CommandDataRef& data) const
    {
    const COMMANDSTATE commandState = self.GetState(data) iferr_return;
    if (commandState != COMMANDSTATE::ENABLED)
    // get data from context
    const maxon::Int32 valueA = data.Get<maxon::Int32>(0) iferr_return;
    const maxon::Int32 valueB = data.Get<maxon::Int32>(1) iferr_return;
    // perform command
    const maxon::Int32 res = valueA + valueB;
    // store result in the context
    data.Set(2, res) iferr_return;
    }
    };
    // register command
    MAXON_COMPONENT_OBJECT_REGISTER(ExampleCommandImpl, CommandClasses, "net.maxonexample.command.addition");
    PyObject * key
    Definition: abstract.h:289
    SKIP
    Definition: asset_browser.h:0
    ENABLED
    The command asset is enabled.
    Definition: asset_command.h:1
    Py_UCS4 * res
    Definition: unicodeobject.h:1113
    @ NORMAL
    Normal Tag morphing.
    int32_t Int32
    32 bit signed integer datatype.
    Definition: apibase.h:190
    ComponentWithBase< C, ComponentRoot, INTERFACES... > Component
    Definition: objectbase.h:2798
    #define MAXON_COMPONENT(KIND,...)
    Definition: objectbase.h:2212
    #define MAXON_COMPONENT_CLASS_REGISTER(C,...)
    Definition: objectbase.h:2410
    #define MAXON_METHOD
    Definition: interfacebase.h:1012
    #define MAXON_COMPONENT_OBJECT_REGISTER(C,...)
    Definition: objectbase.h:2473
    @ OK
    The command was executed properly.
    COMMANDSTATE
    Defines if a command can be executed or not.
    Definition: commandbase.h:28
    @ ENABLED
    The command can be executed.
    #define iferr_scope
    Definition: resultbase.h:1389
    #define iferr_return
    Definition: resultbase.h:1524

    LegacyCommandClassInterface

    Some classic data types like BaseContainer cannot be stored in a maxon::DataDictionary. Therefore a custom data class is needed to store specific custom data. Such a data class can be implemented based on maxon::LegacyCommandDataInterface:

    maxon::LegacyCommandClassInterface is based on maxon::CommandClassInterface. It can be implemented if custom data should be handled.

    // This example shows a simple data structure to store some pointers.
    struct MoGraphSetupData
    {
    maxon::Result<void> CopyFrom(const MoGraphSetupData& other)
    {
    _doc = other._doc;
    _cloner = other._cloner;
    _object = other._object;
    return maxon::OK;
    }
    BaseDocument* _doc = nullptr;
    BaseObject* _cloner = nullptr;
    BaseObject* _object = nullptr;
    };
    Definition: c4d_basedocument.h:497
    Definition: c4d_baseobject.h:248
    PyObject * other
    Definition: dictobject.h:70
    return OK
    Definition: apibase.h:2735
    Definition: object.h:105
    // This example shows the implementation of a simple command that handles "legacy" data.
    //------------------------------------------------------------------------------
    // MoGraph setup data
    //------------------------------------------------------------------------------
    class MoGraphSetupDataImpl : public Component<MoGraphSetupDataImpl, LegacyCommandDataInterface>
    {
    MAXON_COMPONENT(NORMAL, DataDictionaryObjectClass);
    public:
    MAXON_METHOD Int GetLegacyDataCount() const
    {
    return 1;
    }
    MAXON_METHOD Result<Generic*> GetLegacyData(Int index)
    {
    Generic* const dtaPtr = reinterpret_cast<Generic*>(&_data);
    return dtaPtr;
    }
    MAXON_METHOD Result<void> SetLegacyData(const Generic* data, Int index)
    {
    if (data == nullptr)
    return maxon::NullptrError(MAXON_SOURCE_LOCATION);
    const MoGraphSetupData* const moGraphData = reinterpret_cast<const MoGraphSetupData*>(data);
    _data.CopyFrom(*moGraphData) iferr_return;
    return OK;
    }
    MAXON_METHOD Result<void> SetData(ForwardingDataPtr&& key, Data&& data)
    {
    return super.SetData(std::move(key), std::move(data));
    }
    MAXON_METHOD Result<Data> GetData(const ConstDataPtr& key) const
    {
    return super.GetData(std::move(key));
    }
    private:
    MoGraphSetupData _data;
    };
    //------------------------------------------------------------------------------
    // register data
    //------------------------------------------------------------------------------
    MAXON_COMPONENT_CLASS_REGISTER(MoGraphSetupDataImpl, LegacyCommandDataClasses, "net.maxonexample.legacycommanddata.mographsetup");
    //------------------------------------------------------------------------------
    // MoGraph setup command. Creates a cloner and uses the given object as input.
    //------------------------------------------------------------------------------
    class MoGraphSetupCommandImpl : public Component<MoGraphSetupCommandImpl, CommandClassInterface>
    {
    public:
    MAXON_METHOD Result<COMMANDSTATE> GetState(CommandDataRef& data) const
    {
    }
    MAXON_METHOD Result<COMMANDRESULT> Execute(CommandDataRef& data) const
    {
    const COMMANDSTATE commandState = self.GetState(data) iferr_return;
    if (commandState != COMMANDSTATE::ENABLED)
    // get and check input data
    LegacyCommandDataRef legacyData = Cast<LegacyCommandDataRef>(data);
    const maxon::Int dataIndex = 0;
    MoGraphSetupData& moData = legacyData.GetLegacyData<MoGraphSetupData>(dataIndex) iferr_return;
    if (moData._doc == nullptr)
    return maxon::NullptrError(MAXON_SOURCE_LOCATION);
    // check for object
    if (moData._object == nullptr)
    {
    // if no object is given, use the active object
    BaseObject* const activeObject = moData._doc->GetActiveObject();
    // if no object is active, there is nothing to do
    if (activeObject == nullptr)
    moData._object = activeObject;
    }
    // create cloner
    BaseObject* const cloner = BaseObject::Alloc(1018544);
    if (cloner == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    moData._doc->InsertObject(cloner, nullptr, nullptr);
    // place the object under the cloner
    moData._object->Remove();
    moData._doc->InsertObject(moData._object, cloner, nullptr);
    // store result
    moData._cloner = cloner;
    }
    };
    //------------------------------------------------------------------------------
    // register command
    //------------------------------------------------------------------------------
    MAXON_COMPONENT_OBJECT_REGISTER(MoGraphSetupCommandImpl, CommandClasses, "net.maxonexample.command.mographsetup");
    static BaseObject * Alloc(Int32 type)
    Py_ssize_t * index
    Definition: abstract.h:374
    @ OK
    User has selected a font.
    maxon::Int Int
    Definition: ge_sys_math.h:60
    Int64 Int
    signed 32/64 bit int, size depends on the platform
    Definition: apibase.h:202
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:67

    Data

    The data a command operates on is stored in a data object. A default data implementation is stored at maxon::CommandDataClasses::BASE. A custom data class can be implemented based on:

    Calling Commands

    A given command can be executed by calling the "Invoke" of the data object.

    // This example shows the declarations of published objects
    // giving access to the data and command implementations
    namespace CommandDataClasses
    {
    // example data
    MAXON_DECLARATION(CommandDataClasses::EntryType, EXAMPLEDATA, "net.maxonexample.commanddata.exampledata");
    }
    namespace CommandClasses
    {
    // example command
    MAXON_DECLARATION(CommandClasses::EntryType, EXAMPLE, "net.maxonexample.command.addition");
    // MoGraph setup command. Must be used with MOGRAPHSETUPDATA.
    MAXON_DECLARATION(CommandClasses::EntryType, MOGRAPHSETUP, "net.maxonexample.command.mographsetup");
    }
    namespace LegacyCommandDataClasses
    {
    // MoGraph setup data for MOGRAPHSETUP command
    MAXON_DECLARATION(LegacyCommandDataClasses::EntryType, MOGRAPHSETUPDATA, "net.maxonexample.legacycommanddata.mographsetup");
    }
    #define MAXON_DECLARATION(T, Name, id,...)
    Definition: module.h:937
    // This example creates an example data and calls the example command.
    // create data
    maxon::CommandDataRef data = maxon::CommandDataClasses::EXAMPLEDATA().Create() iferr_return;
    data.Set(0, maxon::Int32(100)) iferr_return;
    data.Set(1, maxon::Int32(200)) iferr_return;
    // invoke command
    const auto command = maxon::CommandClasses::EXAMPLE();
    const maxon::COMMANDRESULT res = data.Invoke(command, false) iferr_return;
    return maxon::OK;
    // get result
    const maxon::Int32 resultValue = data.Get<maxon::Int32>(2) iferr_return;
    DiagnosticOutput("Result: @", resultValue);
    #define DiagnosticOutput(formatString,...)
    Definition: debugdiagnostics.h:170
    COMMANDRESULT
    Defines the result of the command after execution.
    Definition: commandbase.h:37
    // This example creates a specific data for the given command,
    // calls that command and receives the resulting object.
    // prepare mograph data
    // no object is set; the active object of the given document should be used
    MoGraphSetupData data;
    data._doc = doc;
    data._object = nullptr;
    const maxon::Int dataIndex = 0;
    // create data
    maxon::LegacyCommandDataRef legacyData = maxon::LegacyCommandDataClasses::MOGRAPHSETUPDATA().Create() iferr_return;
    legacyData.SetLegacyData<MoGraphSetupData>(data, dataIndex) iferr_return;
    // invoke command
    const auto command = maxon::CommandClasses::MOGRAPHSETUP();
    const maxon::COMMANDRESULT res = legacyData.Invoke(command, false) iferr_return;
    return maxon::OK;
    // get result
    const MoGraphSetupData result = legacyData.GetLegacyData<MoGraphSetupData>(dataIndex) iferr_return;
    result._cloner->SetName("The New Cloner"_s);
    PyObject PyObject * result
    Definition: abstract.h:43
    const char * doc
    Definition: pyerrors.h:226

    Further Reading