Class MultiSelectCallback

3DS Max Plug-In SDK

Class MultiSelectCallback

See Also: Class Animatable.

class MultiSelectCallback

Description:

This class is available in release 3.0 and later only.

This is the callback object used to perform the (de)selection via Animatable:: SvGetMultiSelectCallback().

Schematic view supports multiple selection. When the user selects a set of objects in the schematic view and then "transfers" that selection set to the rest of max (either by having "synchronize selection" on or by manually moving the selection out), there are a number of ambiguities that can arise. For example, some of the objects in the schematic view cannot be selected in the viewports, material editor, or modifier stack. Another example: the material editor only supports one active material/map but many materials and maps can be selected simultaneously in the schematic view. The "MultiSelectCallback" system exists order to handle these cases and to handle selection synchronization between SV and future editors in 3ds max. When the schematic view attempts to synchronize selection by moving the SV selection set to the "outside" world, it follows this procedure:

1. First SV calls SvGetMultiSelectCallback(...) on all the visible SV nodes to "collect" MultiSelectCallback objects. Objects that want to synchronize their selection state with the schematic view (not a common or trivial operation -- this is really more associated with adding a new editor in 3ds max rather than adding new plugin) return a pointer to a static instance of a MultiSelectCallback derived object. There is only one instance of a MultiSelectCallback per editor. Furthermore, if an editor displays objects of many classes, all the classes should override SvGetMultiSelectCallback(...) to return the same MultiSelectCallback instance. This implies that, as far as the schematic view is concerned, there is never more than one primary editor class associated with any particular object class (currently, viewports for nodes, material editor for materials and maps and the modifier panel for modifiers).

For example, here is the code in BaseNode that returns the MultiSelectCallback instance for nodes (this is the MultiSelectCallback used for viewports):

class BaseNodeMSelCB : public MultiSelectCallback

 {

 private:

 bool clear;

 BaseNodeTab selNodeTab;

 BaseNodeTab deselNodeTab;

 

 public:

 int Priority() { return 1000; }

 void Begin(IGraphObjectManager *gom, bool clear);

 void Select(IGraphObjectManager *gom, IGraphNode *gNode, bool isSelected);

 void End(IGraphObjectManager *gom);

 };

static BaseNodeMSelCB baseNodeMSelCB;

MultiSelectCallback* BaseNode::SvGetMultiSelectCallback(IGraphObjectManager *gom, IGraphNode *gNode)

 {

 return &baseNodeMSelCB;

 }

2. For each selection class (unique MultiSelectCallback instance), the schematic views calls "Begin(...)". This is the spot where any "pre-selection" preparation takes place. The order that the MultiSelectCallback instances are called in is determined by their priority. The priority is returned by the "Priority()" method. MultiSelectCallback's with a higher priority (lower value) are called before those with a lower priority (higher value). For example, here is the Begin associated with the viewports:

void BaseNodeMSelCB::Begin(IGraphObjectManager *gom, bool clear)

  {

  this->clear = clear;

//

// If the "clear" bool is true, the current viewport selection set is cleared...

//

  if (clear)

   GetActiveSelSet()->Clear(FALSE);

//

// Some housekeeping in preparation for the select...

//

  selNodeTab.Resize(0);

  deselNodeTab.Resize(0);

  }

3. For each of objects in the schematic view whose selection state is changing, the object's MultiSelectCallback instance is retrieved (again) and the "Select" method is called. Here is where the actual selection/deselection work can take place. I say "can" because, in practice, the select method usually just collects all the objects to be selected and all the objects to be deselected into lists which are then processed in the "End(...)" method. This is simply for performance -- it is often more efficient to set the selection state of a group of objects all at once. Here's the "Select(...)" method from BaseNode:

void Select(IGraphObjectManager *gom, IGraphNode *gNode, bool isSelected)

  {

  BaseNode *baseNode = (BaseNode *) gNode->GetAnim();

 

  if (isSelected)

   {

   if (!baseNode->IsRootNode() && !baseNode->IsFrozen() && !baseNode->IsHidden())

    selNodeTab.AppendNode(baseNode, FALSE);

   }

  else

   {

   if (baseNode->Selected())

    deselNodeTab.AppendNode(baseNode, FALSE);

   }

  }

4. Finally, for each selection class (unique MultiSelectCallback instance), the schematic views calls "End(...)". This is the spot where any "post-selection" operations take place. For example, here is the "End(...)" for the BaseNode (viewports):

void End(IGraphObjectManager *gom)

  {

  if (selNodeTab.Count() > 0 || deselNodeTab.Count() > 0)

   {

   theHold.Begin();

   if (selNodeTab.Count() > 0)

    GetActiveSelSet()->SelectMultiple(selNodeTab, FALSE);

 

   if (deselNodeTab.Count() > 0)

    GetActiveSelSet()->DeselectMultiple(deselNodeTab, FALSE);

 

   theHold.Accept(getResMgr().getString(IDS_SV_SELECT, appInst));

   RedrawViewports(GetCurTime(), VP_DONT_SIMPLIFY);

   }

  else

   {

   if (clear)

    RedrawViewports(GetCurTime(), VP_DONT_SIMPLIFY);

   }

  }

Methods:

public:

Prototype:

virtual int Priority()=0;

Remarks:

Returns the priority of the callback. MultiSelectCallback's with a higher priority (lower value) are called before those with a lower priority (higher value).

Prototype:

virtual void Begin(IGraphObjectManager *gom, bool clear)=0;

Remarks:

Called to begin the multi-selection process. This is the spot where any "pre-selection" operations take place.

Parameters:

IGraphObjectManager *gom

Points to the schematic view window manager.

bool clear

true to clear the previous selection; false to leave intact.

Prototype:

virtual void Select(IGraphObjectManager *gom, IGraphNode *gNode, bool isSelected)=0;

Remarks:

This method selects or deselects the node passed.

Parameters:

IGraphObjectManager *gom

Points to the schematic view window manager.

IGraphNode *gNode

Points to the node in schematic view.

bool isSelected

true if select; false if deselect.

Prototype:

virtual void End(IGraphObjectManager *gom)=0;

Remarks:

Called when done. This is the spot where any "post-selection" operations take place.

Parameters:

IGraphObjectManager *gom

Points to the schematic view window manager.