hi,
you have to use SetTristate in the function GetDParameter.
Of course you have to be careful that TriState is allowed.
Here's an example that will create a generator, if you add two cube as child, it will be able to change the SEGMENT_X
. if both cube have different parameter, the generator will display <<Multiple Values>>
Sorry for the un-commented code
maxon::Int32 g_pc11644 = -1;
#define SEGMENT_X 2000
class PC11644 : public ObjectData
{
INSTANCEOF(PC11644, ObjectData)
public:
static NodeData* Alloc() { return NewObjClear(PC11644); }
virtual Bool Init(GeListNode* node)
{
node->SetParameter(DescID(SEGMENT_X), GeData(1), DESCFLAGS_SET::NONE);
return true;
}
virtual Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags)
{
// Add a Segment Parameter that will drive children parameters.
// we have no description but we can load the basic one.
if (!description->LoadDescription(Obase))
return false;
const DescID* singleid = description->GetSingleDescID();
DescID cid = DescLevel(SEGMENT_X, DTYPE_LONG, 0);
// check if this parameter ID is requested (NOTE: this check is important for speed)
if (!singleid || cid.IsPartOf(*singleid, nullptr))
{
// define the new parameter description
BaseContainer settings = GetCustomDataTypeDefault(DTYPE_LONG);
settings.SetString(DESC_NAME, "Segments X"_s);
// set the new parameter
if (!description->SetParameter(cid, settings, ID_OBJECTPROPERTIES))
return false;
}
flags |= DESCFLAGS_DESC::LOADED;
return SUPER::GetDDescription(node, description, flags);
}
virtual Bool GetDParameter(GeListNode* node, const DescID& id, GeData& t_data, DESCFLAGS_GET& flags) override
{
iferr_scope_handler
{
err.DbgStop();
return err;
};
// check if tristate is allowed for this gadget
const Bool tristateReturnAllowed = (flags & DESCFLAGS_GET::ALLOW_TRISTATE) ? true : false;
if (id[0].id == SEGMENT_X)
{
Bool isTristate = false;
GeData childData;
// Check if all children have the same value
iferr (isTristate = CheckChildValue(node, childData))
{
err.DiagOutput();
}
if (tristateReturnAllowed && isTristate)
{
// if tristate is allowed and value are different we use SetTristate to set the GeData type to DA_TRISTATE
// the gadget will show 'multiple value'
t_data.SetTristate();
}
else if (isTristate)
{
// show default value
t_data.SetInt32(1);
}
else if (childData.GetType() == DA_LONG)
{
t_data = childData;
}
else
{
// retrieves the value in the BaseContainer
BaseContainer *bc = static_cast<BaseObject*>(node)->GetDataInstance();
if (bc == nullptr)
return false;
t_data = bc->GetData(SEGMENT_X);
}
flags |= DESCFLAGS_GET::PARAM_GET;
}
return SUPER::GetDParameter(node, id, t_data, flags);
}
virtual Bool SetDParameter(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_SET& flags) override
{
iferr_scope_handler
{
err.DbgStop();
return false;
};
if (id[0].id == SEGMENT_X)
{
iferr (SetChildValues(node, t_data))
{
err.DiagOutput();
}
BaseContainer *bc = static_cast<BaseObject*>(node)->GetDataInstance();
if (bc == nullptr)
return false;
bc->SetData(SEGMENT_X, t_data);
flags |= DESCFLAGS_SET::PARAM_SET;
}
return SUPER::SetDParameter(node, id, t_data, flags);
}
virtual BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) override
{
GeData data;
if (op->GetParameter(DescID(SEGMENT_X), data, DESCFLAGS_GET::NONE))
{
if (data.GetType() == DA_LONG)
DiagnosticOutput("Type is still DA_LONG with value @", data.GetInt32());
else
DiagnosticOutput("Type is not DA_LONG anymore");
}
BaseObject* parent = BaseObject::Alloc(Onull);
return parent;
}
private:
/// Retrieve the direct child if they are cubes
/// @param[in] in_node the parent of children
maxon::Result<maxon::BaseArray<BaseObject*>> GetChildren(GeListNode* in_node) const
{
iferr_scope;
// Cast the node to a BaseObject
BaseObject* op = static_cast<BaseObject*>(in_node);
if (in_node == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
// Create an array to add the children
maxon::BaseArray<BaseObject*> nodeList;
// return an error if there's no child
BaseObject* child = op->GetDown();
if (child == nullptr)
{
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
}
// Add the children to the array
while (child)
{
if (child->IsInstanceOf(Ocube))
{
nodeList.Append(child) iferr_return;
}
child = child->GetNext();
}
// return the array
return nodeList;
}
///
/// Return if the children's value are all the same (for PRIM_CUBE_SUBX)
/// @param[in] in_node the parent of children
/// @param[out] the value stored for the first children
///
maxon::Result<Bool> CheckChildValue(GeListNode* in_node, GeData& out_childData) const
{
iferr_scope;
// Retrieves the children of the node
iferr (const maxon::BaseArray<BaseObject*> nodeList = GetChildren(in_node))
{
return err;
}
// Retrieve the parameter of the first child
if (!nodeList[0]->GetParameter(PRIM_CUBE_SUBX, out_childData, DESCFLAGS_GET::NONE))
{
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
}
Bool isTristate = false;
// Check for each children if the value is different
for (const auto& child : nodeList)
{
GeData childData;
child->GetParameter(PRIM_CUBE_SUBX, childData, DESCFLAGS_GET::NONE);
if (childData != out_childData)
{
isTristate = true;
}
}
return isTristate;
}
/// Set the value of node's children
/// @param[in] in_node the parent of children
/// @param[in] in_value will set the children with this value
maxon::Result<void> SetChildValues(GeListNode* in_node, const GeData &in_value)
{
iferr_scope;
iferr (maxon::BaseArray<BaseObject*> nodeList = GetChildren(in_node))
{
return err;
}
for (auto& child : nodeList)
{
child->SetParameter(DescID(PRIM_CUBE_SUBX), in_value, DESCFLAGS_SET::NONE);
}
return maxon::OK;
}
};
Cheers,
Manuel