The RTObjectSelection class allows you to register handlers for different events that your application can use to take action when something important happens with the object selection. These events are discussed next.

Selection Changed Event

Your application can be informed whenever the selection changes by registering a handler for the Changed event:

RTObjectSelection.Get.Changed += OnSelectionChanged;

The handler must have the following signature:

void OnSelectionChanged(ObjectSelectionChangedEventArgs args);

The handler function must accept a reference to an ObjectSelectionChangedEventArgs instance that contains information about the way in which the object selection has changed.

This public interface of this class is defined like so:

public class ObjectSelectionChangedEventArgs
{
    public ObjectSelectReason SelectReason { get { return _selectReason; } }
    public List<GameObject> ObjectsWhichWereSelected { get { return new List<GameObject>(_objectsWhichWereSelected); } }
    public ObjectDeselectReason DeselectReason { get { return _deselectReason; } }
    public List<GameObject> ObjectsWhichWereDeselected { get { return new List<GameObject>(_objectsWhichWereDeselected); } }
    public ObjectSelectionSnapshot UndoRedoSnapshot { get { return _undoRedoSnapshot; } }
}
Property Description
SelectReason If the selection changed because an object or group of objects were selected, this will indicate the reason why those objects were selected. If no objects were selected, this will be set to ObjectSelectReason.None.
ObjectsWhichWereSelected If SelectReason is not None, this is a list which contains the newly selected objects. Otherwise, this list is empty.
DeselectReason If the selection changed because an object or group of objects were deselected, this will indicate the reason why those objects were deselected. If no objects were deselected, this will be set to ObjectDeselectReason.None.
ObjectsWhichWereDeselected If DeselectReason is not None, this is a list which contains the objects that have been deselected. Otherwise, this list is empty.
UndoRedoSnapshot Used internally to restore object selection states on Undo/Redo. Do not use.

Enabled/Disabled Events

Whenver the object selection module's enabled state changes, it will fire the following 2 events: Enabled and Disabled.

RTObjectSelection.Get.Enabled += OnObjectSelectionModuleEnabled;
RTObjectSelection.Get.Disabled += OnObjectSelectionModuleDisabled;

The event handler must have the following signature:

void OnObjectSelectionModuleEnabled();
void OnObjectSelectionModuleDisabled();

Manip Session Begin/End Events

If you wish to be informed about when a manip session begins and ends, you can subscribe to the following 2 events:

RTObjectSelection.Get.ManipSessionBegin += OnManipSessionBegin;
RTObjectSelection.Get.ManipSessionEnd += OnManipSessionEnd;

The event handler must have the following signature:

void OnManipSessionBegin(ObjectSelectionManipSession session);
void OnManipSessionEnd(ObjectSelectionManipSession session);

Both handlers must accept the id of the session which has begun/ended. Please see Object Manip Sessions for more info.

Can Select/Deselect Events

Sometimes it may be useful to inform the selection module that under certain conditions it should not allow the selection/deselection of objects via mouse clicks or the multi-select rectangle.

This can be done by registering the following handlers:

RTObjectSelection.Get.CanClickSelectDeselect += OnCanClickSelectDeselect;
RTObjectSelection.Get.CanMultiSelectDeselect += OnCanMultiSelectDeselect;

The handlers must have the following signatures:

void OnCanClickSelectDeselect(YesNoAnswer answer);
void OnCanMultiSelectDeselect(YesNoAnswer answer);

Both handlers must accept a reference to an instance of the YesNoAnswer class.

Here is a simple example:

private void OnCanClickSelectDeselect(YesNoAnswer answer)
{
    canClickSelectDeselect = /*condition to allow click select/deselect*/;
    if (canClickSelectDeselect) answer.yes();
    else answer.No();
}

private void OnCanMultiSelectDeselect(YesNoAnswer answer)
{
    canMultiSelectDeselect = /*condition to allow multi select/deselect*/;
    if (canMultiSelectDeselect) answer.yes();
    else answer.No();
}

As you can see, when the module is allowed to select or deselect objects, you must call answer.Yes(). Otherwise, you must call answer.No().

Note

If multiple handlers are registered, it is enough for one of them to answer No and in that case the module will know that selection/deselection is NOT allowed. You can think of this as a logical AND operation between different subscribers (e.g. if (sub[0].Yes() && sub[1].Yes() && ...) { } ).

Note

RLD will register its own handlers for these events, so if you answer Yes in your own, but RLD answered No, then the final result will be No.

Selection Delete Events

There are 2 events which are fired when the selected objects get deleted (by pressing the DELETE key or by calling RTObjectSelection.Get.Delete()):

RTObjectSelection.Get.WillBeDeleted += OnWillBeDeleted;
RTObjectSelection.Get.Deleted += OnDelete;

The WilBeDeleted event is fired before the selection is about to be deleted and the Deleted handler is called after the objects have been deleted.

The handler signatures must look like this:

void OnWillBeDeleted();
void OnDeleted();

Selection Duplicate Events

There are 2 events which are fired when the selected objects are duplicated (by pressing LCTRL + D or by calling RTObjectSelection.Get.Duplicate()):

RTObjectSelection.Get.WillBeDuplicated+= OnWillBeDuplicated;
RTObjectSelection.Get.Duplicated += OnDuplicate;

The WillBeDuplicated event is fired before the selection is about to be duplicated and the Duplicated handler is called after the objects have been duplicated.

The handler signatures must look like this:

void OnWillBeDuplicated();
void OnDuplicate(ObjectSelectionDuplicationResult result);

As you can see the handler for the Duplicated event accepts a parameter which represents the result of the duplication operation. This is an instance of the ObjectSelectionDuplicationResult class and its public interface is defined like so:

public class ObjectSelectionDuplicationResult
{
    public List<GameObject> DuplicateParents;
    public int NumDuplicateParent;

    public GameObject GetParentByIndex(int index);
}

The DuplicateParents property returns a list of parents that have been created after the duplication process. A parent in this case is an object that has children. So for example, if you have selected an entire object hierarchy and then duplicated it, this will return a list with a single element which is the root of the hierarchy. If you select 2 hierarchies and then duplicate them, this list will contain 2 elements: the roots of both hierarchies.

Note

The hierarchy roots may themseleves be children of another object. But if that object is not selected, it will be ignored by the duplication process.

Selection Rotated Events

Whenever the selection is rotated, the Rotated event is fired.

RTObjectSelection.Get.Rotated += OnSelectionRotated;

The handler signature must look like this:

void OnSelectionRotated();

Selection PreSelect/PreDeselect Customize Events

These 2 events are fired whenever an object or group of objects are about to be selected or deselected via a mouse click or the multi-select rectangle and they can be used to customzie the way in which objects get selected or deselected.

For example, with these events it is possible to customize the selection mechanism such that when you click on an object another group of objects is selected instead. Same for deselection.

Note

By default, RLD implements its own handlers which ensure that entire hierarchies are selected/deselected. For example, when you click on an object, by default, RLD will select the entire hierarchy that the object is part of. You can write the following code to disable this functionality: ObjectSelectEntireHierarchy.Get.SetActive(false);. You need to disable this if you plan on writing your own customize handlers.

Handler registration can be done like so:

RTObjectSelection.Get.PreSelectCustomize += OnPreSelectCustomize;
RTObjectSelection.Get.PreDeselectCustomize += OnPreDeselectCustomize

The handler signatures must look like this:

void OnPreSelectCustomize(ObjectPreSelectCustomizeInfo customizeInfo, List<GameObject> toBeSelected);
void OnPreDeselectCustomize(ObjectPreDeselectCustomizeInfo customizeInfo, List<GameObject> toBeDeselected);

Now let's talk about each of these in more detail.

The PreSelectCustomize Event

When you click on an object to select it or when an object (or group of objects) enter the area of the multi-select rectangle, the selection module will fire a PreSelectCustomize event. This event gives you a chance to specify what objects should actually get selected.

The handler signature for this event is:

void OnPreSelectCustomize(ObjectPreSelectCustomizeInfo customizeInfo, List<GameObject> toBeSelected);

The first parameter is an instance of the ObjectPreSelectCustomizeInfo class. The public interface looks like this:

public class ObjectPreSelectCustomizeInfo
{
    public ObjectSelectReason SelectReason;
    public int ToBeSelectedCount;
    public List<GameObject> ToBeSelected;

    public void SelectThese(IEnumerable<GameObject> toBeSelected);
    public void IgnoreThese(IEnumerable<GameObject> toBeIgnored);
}
Property Description
SelectReason This is the selection module's way of telling you why the objects are going to be selected.
ToBeSelectedCount The number of objects that are going to be selected;
ToBeSelected Returns a copy of the list of objects which are going to be selected. For example, when you left click an object, this will contain the object that was clicked. When you drag the multi-select rectangle, this list contains the objects that have entered the selection rectangle's area.
Function Description
SelectThese This is how you tell the selection module that you want something else to be selected instead. Simply pass a collection of objects that you want to be selected.
IgnoreThese Allows you to specify a collection of objects which should not be selected.

Note

The SelectReason property will always be one of the following: Click, ClickAppend, MultiSelect, MultiSelectAppend.

The second parameter is the list of objects which are about to be selected. This is the same as the ToBeSelected property of the ObjectPreSelectCustomizeInfo class discussed above and you should use this instead since it avoids a copy operation.

Note

It is best to avoid modifying the toBeSelected list. Although nothing wrong will happen if you do so, this might change in future implementations.

Let's take a look at a simple example in which we create a customize select handler that will select all objects in an area of N units around the clicked object. So when the user will click an on object, it will select that object plus all surrounding objects in the given area radius.

// This handeler can be used to customize the object selection so that when an object is clicked,
// all objects within a certain radius around the object are also selected.
void OnPreSelectCustomize(ObjectPreSelectCustomizeInfo customizeInfo, List<GameObject> toBeSelected)
{
    // Let's choose to customize only for click select
    if (customizeInfo.SelectReason == ObjectSelectReason.Click ||
        customizeInfo.SelectReason == ObjectSelectReason.ClickAppend)
    {
        // We will store all the objects that we want selected in a hash set to avoid duplicates
        var selectThese = new HashSet<GameObject>();

        // Store the overlap radius 
        Vector3 overlapRadius = new Vector3(3.0f, 0.0f, 3.0f);

        // Loop through each object in the 'toBeSelected' collection
        foreach(var gameObj in toBeSelected)
        {
            // Build the overlap OOBB around the object and call RTScene.Get.OverlapBox to get a list of objects
            // that are overlapped by the OOBB.
            OOBB overlapOOBB = new OOBB(gameObj.transform.position, overlapRadius, gameObj.transform.rotation);
            List<GameObject> overlapped = RTScene.Get.OverlapBox(overlapOOBB);

            // Was anything overlapped?
            if (overlapped.Count != 0)
            {
                // Yes! Then loop through each overlapped object and add it to the selected list
                foreach(var overlappedObject in overlapped)
                {
                    selectThese.Add(overlappedObject);
                }
            }
        }

        // Finally, tell the selection module that we want these objects to be selected
        // by calling 'SelectThese'. When the handler exists, the selection module will
        // use the customizeInfo instance to decide which objects to select.
        customizeInfo.SelectThese(selectThese);
    }
}

The PreDeselectCustomize Event

When you click on an object to deselect it (by holding down LCTRL) or when an object (or group of objects) exit the area of the multi-select rectangle, the selection module will fire a PreDeselectCustomize event. This event gives you a chance to specify what objects should actually get deselected.

The handler signature for this event is:

void OnPreDeselectCustomize(ObjectPreDeselectCustomizeInfo customizeInfo, List<GameObject> toBeDeselected);

The first parameter is an instance of the ObjectPreDeselectCustomizeInfo class. The public interface looks like this:

public class ObjectPreDeselectCustomizeInfo
{
    public ObjectDeselectReason DeselectReason;
    public int ToBeDeselectedCount;
    public List<GameObject> ToBeDeselected;

    public void DeselectThese(IEnumerable<GameObject> toBeDeselected);
    public void IgnoreThese(IEnumerable<GameObject> toBeIgnored);
}
Property Description
DeselectReason This is the selection module's way of telling you why the objects are going to be deselected.
ToBeDeselectedCount The number of objects that are going to be deselected;
ToBeDeselected Returns a copy of the list of objects which are going to be deselected. For example, when you left click on an already selected object while holding down LCTRL, this will contain the object that was clicked. When you drag the multi-select rectangle, this list contains the objects that have exited the selection rectangle's area.
Function Description
DeselectThese This is how you tell the selection module that you want something else to be deselected instead. Simply pass a collection of objects that you want to be deselected.
IgnoreThese Allows you to specify a collection of objects which should not be deselected.

Note

The DeselectReason property will always be one of the following: ClickAppendAlreadySelected, MultiDeselect, MultiSelectNotOverlapped.

The second parameter is the list of objects which are about to be deselected. This is the same as the ToBeDeselected property of the ObjectPreDeselectCustomizeInfo class discussed above and you should use this instead since it avoids a copy operation.

Note

It is best to avoid modifying the toBeDeselected list. Although nothing wrong will happen if you do so, this might change in future implementations.

The ObjectSelectEntireHierarchy Class

By default RLD registers 2 handlers for the PreSelectCustomize and PreDeselectCustomize events. These handlers make sure that when an object is about to be selected, the entire hierarchy that the object is part of will be selected. Same for deselection.

If you plan on creating your own handlers, then you should first deactivate the ones mentioned above by writing:

ObjectSelectEntireHierarchy.Get.SetActive(false);