Programmatically create a palette?
-
Is it possible to programmatically create a palette with commands that I specify? I would like to be able to create palettes on demand with certain commands so that a user can dock them.
-
Hello @kbar,
Thank you for reaching out to us. I am sure you are aware that this has been discussed before and nothing has changed here. It is not possible to programmatically instantiate, open, or populate palettes from the public C++ API. While we technically have the possibility to do it internally, our internal code does not really make use of this either. Which is why such a function does not exist although frequently requested.
There are two options you have:
- Cinema 4D relies primarily on layouts these days. If you want to provide a specific working environment for users, you can simply provide layout files just as Cinema 4D does. Layout files can be provided for a full layout just as for single palette. Layout files for palettes can be saved from the context menu of a palette.
A layout file can then be loaded back into Cinema 4D with the general-purpose file loading functionLoadFile
. Find a brief example in Python at the end of this posting. - You can provide and structure your product menu with
CommandData
plugins in such way that they form easy to separate palettes for the user.
Cheers,
FerdinandThe result:
The script:
"""Loads a palette file into Cinema 4D. Showcases the ability of LoadFile() to handle almost all file formats Cinema 4D can deal with, including layout files for palettes or the whole window. """ import c4d import os def main() -> None: """Loads a palette into Cinema 4D. """ # Determine and assert the palette file path, the palette file in this # example is meant to be located in the same directory as this script. directory = os.path.dirname(__file__) paletteFile = os.path.join(directory, "myPalette.l4d") if not os.path.exists(paletteFile ): raise OSError(f"The path {paletteFile } does not exist.") # Open the palette with LoadFile(). c4d.documents.LoadFile(paletteFile) if __name__ == '__main__': main()
- Cinema 4D relies primarily on layouts these days. If you want to provide a specific working environment for users, you can simply provide layout files just as Cinema 4D does. Layout files can be provided for a full layout just as for single palette. Layout files for palettes can be saved from the context menu of a palette.
-
F ferdinand referenced this topic on
-
C chuanzhen referenced this topic on
-
@ferdinand
Is this still the best way to create a palette 3 years later? Preferably I would like there to be an option for our plugin to insert its objects into the standard palette.
Switching to Reshift changes the default palette, I was hoping i could do something similar. -
Hello @ECHekman,
It is very unlikely that this will ever change unless we do a fundamental rewrite of our UI core (which itself is not that unlikely but there are no current concrete plans or an ETA, Cinema 4D could keep using its current UI core for another decade).
What Redshift, or more concretely things like the foreground object, are doing, is not loading or modifying palettes. They are modifying the state of the command via CMD_HIDDEN. For things where you usually do not have control over the command implementation, you can register a CommandGetStateDelegate for a specific command ID. This delegate will be called whenever the state of the command is queried, and you can then modify the state as you see fit.
Cheers,
FerdinandCode
// Demonstrates how to register a CommandGetStateDelegate for a specific command ID, allowing us to // override the CommandData::GetState behavior of the command, i.e., how its enabled/checked/ // hidden (and more) behavior is. // // Doing this is usually only necessary if the command implementation is not under our control, as // for example, for scene elements (NodeData, ObjectData, etc.) where we usually do not implement the // command ourselves but let Cinema 4D handle it. // // NEVER IMPLEMENT ANY STATE DELEGATES FOR COMMANDS THAT YOU DO NOT OWN. // This is the state handler for the foreground object command. It will hide the command if the active // renderer is Redshift. namespace maxon { MAXON_DECLARATION_REGISTER(CommandGetStateDelegates, NumToString<Oforeground>::value) { CommandGetStateDelegate delegate = [](cinema::BaseDocument* doc) -> Int32 { Int32 state = cinema::CMD_ENABLED; if (doc) { cinema::RenderData* rd = doc->GetActiveRenderData(); if (rd) { const Bool isRedshiftActiveRenderer = rd->GetDataInstance()->GetInt32(RDATA_RENDERENGINE) == VPrsrenderer; if (isRedshiftActiveRenderer) state |= cinema::CMD_HIDDEN; } } return state; }; return delegate; } } // namespace maxon