<< Multiple Values>> in Attribute Manager
-
Hello! I understand that TriState is used to display <<Multiple Values>> for GeDialogs, but is there a way to simulate that functionality in the Attribute Manager when a single object is selected?
I'm looking to have different parameters displayed depending on which object is selected in an InExclude, and if multiple objects are selected I wanted to mimic the Multiple Values behavior. Is this possible?
Dan
-
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 codemaxon::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 -
Thanks! That's exactly what I needed!