THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/02/2007 at 12:07, xxxxxxxx wrote:
GetDDescription() is called *fairly* often (sarcasm). If you add GePrint("GetDDescription"); to the top of your GetDDescription() function call and open C4D's Console, you'll see just how frequently is it indeed called.
That said, you should never have to call this function directly. A good way to 'kick' your plugin to call GetDDescription() is to send a Message(MSG_CHANGE) for the plugin - node->Message(MSG_CHANGE);. You may also try node->GetDescription(desc,0);. Description* desc will need to be allocated/freed each time.
For example, you add your dynamic description elements using GetD(ynamic)Description(). These are description elements not stored statically in the description .res file for the plugin. They need their own IDs that don't conflict with the static ones.
MSG_DESCRIPTION_COMMAND is sent when a description button is clicked. If you are wanting to add dynamic elements on a button click, then you are heading in the correct direction. But instead of trying to call GetDDescription from there, get the node and do node->Message(MSG_CHANGE). In the GetDDescription() function is where you are going to assemble the dynamic elements - that is its purpose.
// NodeData.GetDDescription - Descriptions and Parameters
//*---------------------------------------------------------------------------*
Bool IPPBase::GetDDescription(GeListNode* node, Description* description, LONG& flags)
//*---------------------------------------------------------------------------*
{
if (!(node && description)) return FALSE;
if (!description->LoadDescription(node->GetType())) return FALSE;
// Get Object containing Dials
BaseDocument* baseDoc = node->GetDocument();
if (!baseDoc) return FALSE;
BaseObject* obj = static_cast<BaseObject*>(node);
if (!obj) return FALSE;
BaseContainer* opBC = obj->GetDataInstance();
if (!opBC) return FALSE;
// Add dial tags
BaseContainer* pbc;
DescID descID;
String dname;
ULONG type;
ULONG tsf;
LONG index;
BOOL hideZero = opBC->GetBool(IPP_HIDE_ZERODIALS);
BOOL hide;
Real value;
// Initialize BaseContainer static values
BaseContainer sliderBC = GetCustomDataTypeDefault(DTYPE_REAL);
sliderBC.SetLong(DESC_ANIMATE, DESC_ANIMATE_ON);
sliderBC.SetBool(DESC_REMOVEABLE, FALSE);
sliderBC.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_REALSLIDER); // _REAL, _REALSLIDERONLY
sliderBC.SetReal(DESC_MIN, MINREAL);
sliderBC.SetReal(DESC_MAX, MAXREAL);
#ifdef C4D_R85
sliderBC.SetBool(DESC_SCALEH, TRUE);
#endif
BaseContainer editBC = GetCustomDataTypeDefault(DTYPE_BUTTON);
editBC.SetString(DESC_SHORT_NAME, "Edit");
editBC.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON);
editBC.SetLong(DESC_ANIMATE, DESC_ANIMATE_OFF);
editBC.SetBool(DESC_REMOVEABLE, FALSE);
// Filter visible body part dial groups
for (BaseTag* pt = obj->GetFirstTag(); pt; pt = pt->GetNext())
{
if (!pt->IsInstanceOf(ID_IPPDIALTAG)) continue;
pbc = pt->GetDataInstance();
if (!pbc) continue;
// Dial Index
index = pbc->GetLong(IPPDIAL_INDEX);
// Dial Slider
dname = pbc->GetString(IPPDIAL_DIALNAME);
sliderBC.SetString(DESC_NAME, dname);
value = pbc->GetReal(IPPDIAL_CURRENTVALUE);
tsf = (ULONG)pbc->GetLong(IPPDIAL_TYPESUBFLAGS);
type = tsf & 0x000000FFL;
hide = tsf & DIAL_FLAGS_HIDDEN;
// Transforms
if (tsf & DIAL_FLAGS_TRANSFORM) descID = DescID(DescLevel(GROUP_TRANSFORM));
// Morphs
else if (type == CHAN_TYPE_TARGETGEOM)
{
if (hideZero && (value == 0.0f)) hide = TRUE;
descID = DescID(DescLevel(GROUP_MORPH));
}
// Other
else
{
if ((type == CHAN_TYPE_VALUEPARM) && hideZero && (value == 0.0f)) hide = TRUE;
descID = DescID(DescLevel(GROUP_OTHER));
}
if (hide)
{
// - Set display state to hide
sliderBC.SetBool(DESC_HIDE, TRUE);
editBC.SetBool(DESC_HIDE, TRUE);
}
else
{
sliderBC.SetString(DESC_SHORT_NAME, pt->GetName());
sliderBC.SetLong(DESC_UNIT, chanTypeParams[type].unit);
// - Set Min/Max/Step for Slider
sliderBC.SetReal(DESC_MINSLIDER, pbc->GetReal(IPPDIAL_MIN));
sliderBC.SetReal(DESC_MAXSLIDER, pbc->GetReal(IPPDIAL_MAX));
sliderBC.SetReal(DESC_STEP, pbc->GetReal(IPPDIAL_STEP));
// - Set display state to show
sliderBC.SetBool(DESC_HIDE, FALSE);
editBC.SetBool(DESC_HIDE, FALSE);
editBC.SetString(DESC_NAME, dname);
// -- Set Master-Slave button to show whether dial is Master and/or Slave
if (tsf & DIAL_FLAGS_SLAVES)
{
if (tsf & DIAL_FLAGS_VALUEOP) editBC.SetString(DESC_SHORT_NAME, "Edit M/S");
else editBC.SetString(DESC_SHORT_NAME, "Edit M/_");
}
else
{
if (tsf & DIAL_FLAGS_VALUEOP) editBC.SetString(DESC_SHORT_NAME, "Edit _/S");
else editBC.SetString(DESC_SHORT_NAME, "Edit _/_");
}
}
// Dial Slider
if (!description->SetParameter(DescLevel(index,DTYPE_REAL,0), sliderBC, descID)) return FALSE;
// Edit Button
if (!description->SetParameter(DescLevel(index+1,DTYPE_BUTTON,0), editBC, descID)) return FALSE;
opBC->SetReal(index, value);
}
flags |= DESCFLAGS_DESC_LOADED|DESCFLAGS_DESC_RECURSIONLOCK;
return SUPER::GetDDescription(node,description,flags);
}
Note that a set of tags is being used to set up a set of dynamic sliders and buttons on this plugin object.
Your message would be something like:
// NodeData.Message
//*---------------------------------------------------------------------------*
Bool IPPBase::Message(GeListNode* node, LONG type, void* data)
//*---------------------------------------------------------------------------*
{
if (!node) return FALSE;
switch (type)
{
// One of the Buttons
case MSG_DESCRIPTION_COMMAND:
{
if (!data) return TRUE;
LONG id = ((DescriptionCommand* )data)->id[0].id;
switch (id)
{
// Force update of Attributes Manager descriptions
// This will also force a call to GetDDescription()
case DIALGROUP_KICK:
AutoAlloc<Description> desc;
if (desc) node->GetDescription(desc,0);
break;
...
}
break;
}
}
return TRUE;
}
If the AutoAlloc<> doesn't work with Description, you'll need to do it this way:
Description* desc = Description::Alloc();
if (desc)
{
node->GetDescription(desc,0);
Description::Free(desc);
}