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 plug-in) 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; 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/de-selection 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(GetCOREInterface()->GetTime(), VP_DONT_SIMPLIFY); } else { if (clear) RedrawViewports(GetCOREInterface()->GetTime(), VP_DONT_SIMPLIFY); } }
#include <svcore.h>
Public Member Functions |
|
virtual | ~MultiSelectCallback () |
virtual int | Priority ()=0 |
Returns the priority of the callback.
|
|
virtual void | Begin (IGraphObjectManager *gom, bool clear)=0 |
Called to begin the multi-selection process.
|
|
virtual void | Select (IGraphObjectManager *gom, IGraphNode *gNode, bool isSelected)=0 |
Selects or de-selects the node passed.
|
|
virtual void | End (IGraphObjectManager *gom)=0 |
Called when done. |
virtual ~MultiSelectCallback | ( | ) | [inline, virtual] |
{}
virtual int Priority | ( | ) | [pure virtual] |
Returns the priority of the callback.
MultiSelectCallback's with a higher priority (lower value) are called before those with a lower with a higher priority (lower value) are called before those with a lower priority (higher value).
virtual void Begin | ( | IGraphObjectManager * | gom, |
bool | clear | ||
) | [pure virtual] |
Called to begin the multi-selection process.
This is the spot where any "pre-selection" operations take place.
gom | - Points to the schematic view window manager. |
clear | - true to clear the previous selection; false to leave intact. |
virtual void Select | ( | IGraphObjectManager * | gom, |
IGraphNode * | gNode, | ||
bool | isSelected | ||
) | [pure virtual] |
Selects or de-selects the node passed.
gom | Points to the schematic view window manager. |
gNode | Points to the node in schematic view. |
isSelected | true if select; false if deselect. |
virtual void End | ( | IGraphObjectManager * | gom | ) | [pure virtual] |
Called when done.
! This is the spot where any "post-selection" operations take place.
gom | Points to the schematic view window manager. |