RTS Style Selection Functionality

This is my first post in the unity community. I started using unity a couple of months ago and I think it is incredible. I saw a post containing code that implemented rudimentary RTS Selection Box style functionality, which I used as a base to create a much more fleshed out version for a project I’m working on.

Then I thought, hey, why not share it with everyone.

I’ve extensively commented the code, but being an independently trained programmer, just because the explanation makes sense to me doesn’t mean it will make sense to everyone else. If you find caveats, bugs, redundancies, poor coding practices or areas it could otherwise be improved, let me know!

There are two stages to making this work:
Apply the SelectionBox script to a game object with a canvas set to Screen Space Overlay
Implement the IBoxSelectable interface on your own MonoBehaviours to make them selectable.

Firstly, the SelectionBox class:

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using System.Collections.Generic;

/*
* What the SelectionBox component does is allow the game player to select objects using an RTS style click and drag interface:
*
* We want to be able to select Game Objects of any type,
* We want to be able to drag select a group of game objects to select them,
* We want to be able to hold the shift key and drag select a group of game objects to add them to the current selection,
* We want to be able to single click a game object to select it,
* We want to be able to hold the shift key and single click a game object to add it to the current selection,
* We want to be able to hold the shift key and single click an already selected game object to remove it from the current selection.
*
* Most importantly, we want this behaviour to work with UI, 2D or 3D gameObjects, so it has to be smart about considering their respective screen spaces.
*
* Add this component to a Gameobject with a Canvas with RenderMode.ScreenSpaceOverlay
* And implement the IBoxSelectable interface on any MonoBehaviour to make it selectable.
*
* Improvements that could be made:
*
* Control clicking a game object to select all objects of that type or tag.
* Compatability with Canvas Scaling
* Filtering single click selections of objects occupying the same space. (So that, for example, you're only click selecting the game object found closest to the camera)
*
*/

namespace UnityEngine.UI.Extensions {

  
    [RequireComponent(typeof(Canvas))]
    public class SelectionBox : MonoBehaviour
    {
      
        // The color of the selection box.
        public Color color;
      
        // An optional parameter, but you can add a sprite to the selection box to give it a border or a stylized look.
        // It's suggested you use a monochrome sprite so that the selection
        // Box color is still relevent.
        public Sprite art;
      
        // Will store the location of wherever we first click before dragging.
        private Vector2 origin;
      
        // A rectTransform set by the User that can limit which part of the screen is eligable for drag selection
        public RectTransform selectionMask;
      
        //Stores the rectTransform connected to the generated gameObject being used for the selection box visuals
        private RectTransform boxRect;
      
        // Stores all of the selectable game objects
        private IBoxSelectable[] selectables;
      
        // A secondary storage of objects that the user can manually set.
        private MonoBehaviour[] selectableGroup;
      
        //Stores the selectable that was touched when the mouse button was pressed down
        private IBoxSelectable clickedBeforeDrag;
      
        //Stores the selectable that was touched when the mouse button was released
        private IBoxSelectable clickedAfterDrag;
      
        //Custom UnityEvent so we can add Listeners to this instance when Selections are changed.
        public class SelectionEvent : UnityEvent<IBoxSelectable[]> {}
        public SelectionEvent onSelectionChange = new SelectionEvent();
      
        //Ensures that the canvas that this component is attached to is set to the correct render mode. If not, it will not render the selection box properly.
        void ValidateCanvas(){
            var canvas = gameObject.GetComponent<Canvas>();
          
            if (canvas.renderMode != RenderMode.ScreenSpaceOverlay) {
                throw new System.Exception("SelectionBox component must be placed on a canvas in Screen Space Overlay mode.");
            }
          
            var canvasScaler = gameObject.GetComponent<CanvasScaler>();
          
            if (canvasScaler && canvasScaler.enabled && (!Mathf.Approximately(canvasScaler.scaleFactor, 1f) || canvasScaler.uiScaleMode != CanvasScaler.ScaleMode.ConstantPixelSize)) {
                Destroy(canvasScaler);
                Debug.LogWarning("SelectionBox component is on a gameObject with a Canvas Scaler component. As of now, Canvas Scalers without the default settings throw off the coordinates of the selection box. Canvas Scaler has been removed.");
            }
        }
      
        /*
     * The user can manually set a group of objects with monoBehaviours to be the pool of objects considered to be selectable. The benefits of this are two fold:
     *
     * 1) The default behaviour is to check every game object in the scene, which is much slower.
     * 2) The user can filter which objects should be selectable, for example units versus menu selections
     *
     */
        void SetSelectableGroup(IEnumerable<MonoBehaviour> behaviourCollection) {
          
            // If null, the selectionbox reverts to it's default behaviour
            if (behaviourCollection == null) {
                selectableGroup = null;
              
                return;
            }
          
            //Runs a double check to ensure each of the objects in the collection can be selectable, and doesn't include them if not.
            var behaviourList = new List<MonoBehaviour>();
          
            foreach(var behaviour in behaviourCollection) {
                if (behaviour as IBoxSelectable != null) {
                    behaviourList.Add (behaviour);
                }
            }
          
            selectableGroup = behaviourList.ToArray();
        }
      
        void CreateBoxRect(){
            var selectionBoxGO = new GameObject();
          
            selectionBoxGO.name = "Selection Box";
            selectionBoxGO.transform.parent = transform;
            selectionBoxGO.AddComponent<Image>();
          
            boxRect = selectionBoxGO.transform as RectTransform;
          
        }
      
        //Set all of the relevant rectTransform properties to zero,
        //finally deactivates the boxRect gameobject since it doesn't
        //need to be enabled when not in a selection action.
        void ResetBoxRect(){
          
            //Update the art and color on the off chance they've changed
            Image image = boxRect.GetComponent<Image>();
            image.color = color;
            image.sprite = art;
          
            origin = Vector2.zero;
          
            boxRect.anchoredPosition = Vector2.zero;
            boxRect.sizeDelta = Vector2.zero;
            boxRect.anchorMax = Vector2.zero;
            boxRect.anchorMin = Vector2.zero;
            boxRect.pivot = Vector2.zero;
            boxRect.gameObject.SetActive(false);
        }
      
      
        void BeginSelection(){
            // Click somewhere in the Game View.
            if (!Input.GetMouseButtonDown(0))
                return;
          
            //The boxRect will be inactive up until the point we start selecting
            boxRect.gameObject.SetActive(true);
          
            // Get the initial click position of the mouse.
            origin = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
          
            //If the initial click point is not inside the selection mask, we abort the selection
            if (!PointIsValidAgainstSelectionMask(origin)) {
                ResetBoxRect();
                return;
            }
          
            // The anchor is set to the same place.
            boxRect.anchoredPosition = origin;
          
            MonoBehaviour[] behavioursToGetSelectionsFrom;
          
            // If we do not have a group of selectables already set, we'll just loop through every object that's a monobehaviour, and look for selectable interfaces in them
            if (selectableGroup == null) {
                behavioursToGetSelectionsFrom = GameObject.FindObjectsOfType<MonoBehaviour>();
            } else {
                behavioursToGetSelectionsFrom = selectableGroup;
            }
          
            //Temporary list to store the found selectables before converting to the main selectables array
            List<IBoxSelectable> selectableList = new List<IBoxSelectable>();
          
            foreach (MonoBehaviour behaviour in behavioursToGetSelectionsFrom) {
              
                //If the behaviour implements the selectable interface, we add it to the selectable list
                IBoxSelectable selectable = behaviour as IBoxSelectable;
                if (selectable != null) {
                    selectableList.Add (selectable);
                  
                    //We're using left shift to act as the "Add To Selection" command. So if left shift isn't pressed, we want everything to begin deselected
                    if (!Input.GetKey (KeyCode.LeftShift)) {
                        selectable.selected = false;
                    }
                }
              
            }
            selectables = selectableList.ToArray();
          
            //For single-click actions, we need to get the selectable that was clicked when selection began (if any)
            clickedBeforeDrag = GetSelectableAtMousePosition();
          
        }
      
        bool PointIsValidAgainstSelectionMask(Vector2 screenPoint){
            //If there is no seleciton mask, any point is valid
            if (!selectionMask) {
                return true;
            }
          
            Camera screenPointCamera = GetScreenPointCamera(selectionMask);
          
            return RectTransformUtility.RectangleContainsScreenPoint(selectionMask, screenPoint, screenPointCamera);
        }
      
        IBoxSelectable GetSelectableAtMousePosition() {
            //Firstly, we cannot click on something that is not inside the selection mask (if we have one)
            if (!PointIsValidAgainstSelectionMask(Input.mousePosition)) {
                return null;
            }
          
            //This gets a bit tricky, because we have to make considerations depending on the heirarchy of the selectable's gameObject
            foreach (var selectable in selectables) {
              
                //First we check to see if the selectable has a rectTransform
                var rectTransform = (selectable.transform as RectTransform);
              
                if (rectTransform) {
                    //Because if it does, the camera we use to calulate it's screen point will vary
                    var screenCamera = GetScreenPointCamera(rectTransform);
                  
                    //Once we've found the rendering camera, we check if the selectables rectTransform contains the click. That way we
                    //Can click anywhere on a rectTransform to select it.
                    if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, screenCamera)) {
                      
                        //And if it does, we select it and send it back
                        return selectable;
                    }
                } else {
                    //If it doesn't have a rectTransform, we need to get the radius so we can use it as an area around the center to detect a click.
                    //This works because a 2D or 3D renderer will both return a radius
                    var radius = selectable.transform.renderer.bounds.extents.magnitude;
                  
                    var selectableScreenPoint = GetScreenPointOfSelectable(selectable);
                  
                    //Check that the click fits within the screen-radius of the selectable
                    if (Vector2.Distance(selectableScreenPoint, Input.mousePosition) <= radius) {
                      
                        //And if it does, we select it and send it back
                        return selectable;
                    }
                  
                }
            }
          
            return null;
        }
      
      
        void DragSelection(){
            //Return if we're not dragging or if the selection has been aborted (BoxRect disabled)
            if (!Input.GetMouseButton(0) || !boxRect.gameObject.activeSelf)
                return;
          
            // Store the current mouse position in screen space.
            Vector2 currentMousePosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
          
            // How far have we moved the mouse?
            Vector2 difference = currentMousePosition - origin;
          
            // Copy the initial click position to a new variable. Using the original variable will cause
            // the anchor to move around to wherever the current mouse position is,
            // which isn't desirable.
            Vector2 startPoint = origin;
          
            // The following code accounts for dragging in various directions.
            if (difference.x < 0)
            {
                startPoint.x = currentMousePosition.x;
                difference.x = -difference.x;
            }
            if (difference.y < 0)
            {
                startPoint.y = currentMousePosition.y;
                difference.y = -difference.y;
            }
          
            // Set the anchor, width and height every frame.
            boxRect.anchoredPosition = startPoint;
            boxRect.sizeDelta = difference;
          
            //Then we check our list of Selectables to see if they're being preselected or not.
            foreach(var selectable in selectables) {
              
                Vector3 screenPoint = GetScreenPointOfSelectable(selectable);
              
                //If the box Rect contains the selectabels screen point and that point is inside a valid selection mask, it's being preselected, otherwise it is not.
                selectable.preSelected = RectTransformUtility.RectangleContainsScreenPoint(boxRect, screenPoint, null) && PointIsValidAgainstSelectionMask(screenPoint);
              
            }
          
            //Finally, since it's possible for our first clicked object to not be within the bounds of the selection box
            //If it exists, we always ensure that it is preselected.
            if (clickedBeforeDrag != null) {
                clickedBeforeDrag.preSelected = true;
            }
        }
      
        void ApplySingleClickDeselection(){
          
            //If we didn't touch anything with the original mouse press, we don't need to continue checking
            if (clickedBeforeDrag == null)
                return;
          
            //If we clicked a selectable without dragging, and that selectable was previously selected, we must be trying to deselect it.
            if (clickedAfterDrag != null && clickedBeforeDrag.selected && clickedBeforeDrag.transform == clickedAfterDrag.transform ) {
                clickedBeforeDrag.selected = false;
                clickedBeforeDrag.preSelected = false;
              
            }
          
        }
      
        void ApplyPreSelections(){
          
            foreach(var selectable in selectables) {
              
                //If the selectable was preSelected, we finalize it as selected.
                if (selectable.preSelected) {
                    selectable.selected = true;
                    selectable.preSelected = false;
                }
            }
          
        }
      
        Vector2 GetScreenPointOfSelectable(IBoxSelectable selectable) {
            //Getting the screen point requires it's own function, because we have to take into consideration the selectables heirarchy.
          
            //Cast the transform as a rectTransform
            var rectTransform = selectable.transform as RectTransform;
          
            //If it has a rectTransform component, it must be in the heirarchy of a canvas, somewhere.
            if (rectTransform) {
              
                //And the camera used to calculate it's screen point will vary.
                Camera renderingCamera = GetScreenPointCamera(rectTransform);
              
                return RectTransformUtility.WorldToScreenPoint(renderingCamera, selectable.transform.position);
            }
          
            //If it's no in the heirarchy of a canvas, the regular Camera.main.WorldToScreenPoint will do.
            return Camera.main.WorldToScreenPoint(selectable.transform.position);                                                       
          
        }
      
        /*
     * Finding the camera used to calculate the screenPoint of an object causes a couple of problems:
     *
     * If it has a rectTransform, the root Canvas that the rectTransform is a descendant of will give unusable
     * screen points depending on the Canvas.RenderMode, if we don't do any further calculation.
     *
     * This function solves that problem.
     */
        Camera GetScreenPointCamera(RectTransform rectTransform) {
          
            Canvas rootCanvas = null;
            RectTransform rectCheck = rectTransform;
          
            //We're going to check all the canvases in the heirarchy of this rectTransform until we find the root.
            do {
                rootCanvas = rectCheck.GetComponent<Canvas>();
              
                //If we found a canvas on this Object, and it's not the rootCanvas, then we don't want to keep it
                if (rootCanvas && !rootCanvas.isRootCanvas) {
                    rootCanvas = null;
                }
              
                //Then we promote the rect we're checking to it's parent.
                rectCheck = (RectTransform)rectCheck.parent;
              
            } while (rootCanvas == null);
          
            //Once we've found the root Canvas, we return a camera depending on it's render mode.
            switch (rootCanvas.renderMode) {
            case RenderMode.ScreenSpaceOverlay:
                //If we send back a camera when set to screen space overlay, the coordinates will not be accurate. If we return null, they will be.
                return null;
              
            case RenderMode.ScreenSpaceCamera:
                //If it's set to screen space we use the world Camera that the Canvas is using.
                //If it doesn't have one set, however, we have to send back the current camera. otherwise the coordinates will not be accurate.
                return (rootCanvas.worldCamera) ? rootCanvas.worldCamera : Camera.main;
              
            default:
            case RenderMode.WorldSpace:
                //World space always uses the current camera.
                return Camera.main;
            }
          
        }
      
        public IBoxSelectable[] GetAllSelected(){
            if (selectables == null) {
                return new IBoxSelectable[0];
            }
          
            var selectedList = new List<IBoxSelectable>();
          
            foreach(var selectable in selectables) {
                if (selectable.selected) {
                    selectedList.Add (selectable);
                }
            }
          
            return selectedList.ToArray();
        }
      
        void EndSelection(){
            //Get out if we haven't finished selecting, or if the selection has been aborted (boxRect disabled)
            if (!Input.GetMouseButtonUp(0) || !boxRect.gameObject.activeSelf)
                return;
          
            clickedAfterDrag = GetSelectableAtMousePosition();
          
            ApplySingleClickDeselection();
            ApplyPreSelections();
            ResetBoxRect();
            onSelectionChange.Invoke(GetAllSelected());
        }
      
        void Start(){
            ValidateCanvas();
            CreateBoxRect();
            ResetBoxRect();
        }
      
        void Update() {
            BeginSelection ();
            DragSelection ();
            EndSelection ();
        }
    }
}

Secondly, the IBoxSelectable interface:

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

namespace UnityEngine.UI.Extensions {

    /*
     * Implement this interface on any MonoBehaviour that you'd like to be considered selectable.
     */
    public interface IBoxSelectable {
        bool selected {
            get;
            set;
        }
      
        bool preSelected {
            get;
            set;
        }
      
        //This property doesn't actually need to be implemented, as this interface should already be placed on a MonoBehaviour, which will
        //already have it. Defining it here only allows us access to the transform property by casting through the selectable interface.
        Transform transform {
            get;
        }
    }

}

Thirdly, an example of how to implement this interface in your own Scripts (Remember to use the namespace!)

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UI.Extensions;
using System.Collections;

public class ExampleSelectable : MonoBehaviour, IBoxSelectable {

    #region Implemented members of IBoxSelectable
    bool _selected = false;
    public bool selected {
        get {
            return _selected;
        }

        set {
            _selected = value;
        }
    }

    bool _preSelected = false;
    public bool preSelected {
        get {
            return _preSelected;
        }
       
        set {
            _preSelected = value;
        }
    }
    #endregion

    //We want the test object to be either a UI element, a 2D element or a 3D element, so we'll get the appropriate components
    SpriteRenderer spriteRenderer;
    Image image;
    Text text;

    void Start () {
        spriteRenderer = transform.GetComponent<SpriteRenderer>();
        image = transform.GetComponent<Image>();
        text = transform.GetComponent<Text>();
    }

    void Update () {

        //What the game object does with the knowledge that it is selected is entirely up to it.
        //In this case we're just going to change the color.

        //White if deselected.
        Color color = Color.white;

        if (preSelected) {
            //Yellow if preselected
            color = Color.yellow;
        }
        if (selected) {
            //And green if selected.
            color = Color.green;
        }

        //Set the color depending on what the game object has.
        if (spriteRenderer) {
            spriteRenderer.color = color;
        } else if (text) {
            text.color = color;
        } else if (image) {
            image.color = color;
        } else if (renderer) {
            renderer.material.color = color;
        }


    }
}

And finally, everything has been attached to this file in a unityPackage with an example scene.

Enjoy!

1888812–121540–SelectionBox.unitypackage (15.2 KB)

5 Likes

Hey! Thanks for sharing the script!

Selection box seems to be fine but there’s an issue that bother me. What happens when scrolling the map while drawing a selection box? The anchoredPosition should be updated somehow while map is scrolled in any direction. I hope You know what I mean :).

I’m trying to make it work for about 6 hours and still can’t find any good solution. I tried raycasting, screen-to-world and back, etc…
Do You know any solution?

Thanks in advance.
AmBeam.

Are you saying that you want to begin a drag selection, and have the point that you started from move around with the world?

What is your application for this? For an RTS, I would say that kind of behaviour would be undesirable.

Nonetheless, here’s how you would do it:
In the DragSelection() function, I’d add a line as such:

        void DragSelection(){
            //Return if we're not dragging or if the selection has been aborted (BoxRect disabled)
            if (!Input.GetMouseButton(0) || !boxRect.gameObject.activeSelf)
                return;

            // Store the current mouse position in screen space.
            Vector2 currentMousePosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);

            /*****************************************
            **** Here is where we make the change ****
            *****************************************/

            // Vector2 difference = currentMousePosition - origin; 

            //  ^ This Becomes:

            Vector2 difference = currentMousePosition - (origin + worldPositionalDifference);
         
            // Copy the initial click position to a new variable. Using the original variable will cause
            // the anchor to move around to wherever the current mouse position is,
            // which isn't desirable.
            Vector2 startPoint = origin;
         
            // The following code accounts for dragging in various directions.
            if (difference.x < 0)
            {
                startPoint.x = currentMousePosition.x;
                difference.x = -difference.x;
            }
            if (difference.y < 0)
            {
                startPoint.y = currentMousePosition.y;
                difference.y = -difference.y;
            }
         
            // Set the anchor, width and height every frame.
            boxRect.anchoredPosition = startPoint;
            boxRect.sizeDelta = difference;
         
            //Then we check our list of Selectables to see if they're being preselected or not.
            foreach(var selectable in selectables) {
             
                Vector3 screenPoint = GetScreenPointOfSelectable(selectable);
             
                //If the box Rect contains the selectabels screen point and that point is inside a valid selection mask, it's being preselected, otherwise it is not.
                selectable.preSelected = RectTransformUtility.RectangleContainsScreenPoint(boxRect, screenPoint, null) && PointIsValidAgainstSelectionMask(screenPoint);
             
            }
         
            //Finally, since it's possible for our first clicked object to not be within the bounds of the selection box
            //If it exists, we always ensure that it is preselected.
            if (clickedBeforeDrag != null) {
                clickedBeforeDrag.preSelected = true;
            }
        }

Now how you actually calculate the worldPositionalDifference depends on a number of factors. If your camera is always the same distance from the terrain, and you don’t have any changes in perspective, then you easily figure out the intraFrame delta:

//This would be on a monobehaviour placed on a camera
public Vector3 worldPositionalDifference = Vector3.zero;
private Vector3 lastCameraPosition;
void Update {
      worldPositionalDifference = transform.position - lastCameraPosition;
      lastCameraPosition = transform.position;
}

Otherwise you’d have to do a some raycasting or what have you to figure out where the difference is in screen space against a 3D terrain with perspective.

Hope this helps!

how do you use this from unity java?

If you mean UnityScript, there are several assets in the asset store that convert C# scripts to UnityScript, but they are paid. You can do it manually if you follow the guidelines in the following post (see the green accepted answer):

no ive done a lot of both actually I guess I should have asked how to use implements in unity script

Oops I misunderstood, sorry.

public class DerivedClass extends BaseClass implements ICustomInterface {
  
     //You get the idea

}

probably less pain to rewrite but im just curious how to get it working
public class ship_select extends SelectionBox implements IBoxSelectable {
//You get the idea
}
gives the following error maybe im doing wrong
Duplicate parameter name ‘value’ in ‘selectable.set_selected(boolean, boolean)’.

Hi I’ve imported this into a new project and its come up with 8 errors. This is probably an easy fix but this code is on the edge of my coding knowledge, is it to do with the namespaces?

Thanks,
Steve.

Why are you extending selection box? It functions by itself. All you have to do is implement IBoxSelectable to a MonoBehaviour that goes onto objects you want selectable.

Hey Steve! It looks to me like you havent yet installed unity 4.6. Or you somehow omitted “using UnityEngine.UI;” in the top of SelectionBox.cs

Strange, I have 4.6 and I’m sure it was using UnityEngine.UI;… I’ll double check theres no spelling errors up there tomorrow.

So I have double checked, I am using Unity 4.6.0b20 and definitely have using UnityEngine.UI;

EDIT: Apologies you need to have the latest Unity 4.6.2 for this script to work, in lower versions RenderMode seems to have different API’s. eg. RenderMode.Overlay.

I’ve updated and now working in case anyone else has the same issue.

Hi, thank you for providing the script,

However there is an issue with the simple click selection as I see:

if (Vector2.Distance(selectableScreenPoint, Input.mousePosition) <= radius)

because the above line depends on the distance from the camera to object and when you zoom it makes the single click selection more difficult. Maybe ray-casting would be better?

cheers,
S.

Help ! O.o
I can’t deselect the uint, what i’m doing wrong ?

    void Update () {

        //What the game object does with the knowledge that it is selected is entirely up to it.
        //In this case we're just going to change the color.

        if (preSelected) {
            //Yellow if preselected
            // color = Color.yellow;
        }
        if (selected)
        {
            interactive.Select();
        }
        else
        {
            if (selected)
            {
                selected = false;
                interactive.Deselect();
            }
        }

if(selected)


else if(selected) // you will never get here!

Debug.Log() is your friend

1 Like

Yea… lol I’ve laughed by my self for a cupple of minutes
here is how I try to fixed it… But it didn’t work …
one still always selected

Thank you Sandadiego =)

bool isSelected;
  void Update ()
    {
      if (selected)
        {
            interactive.Select();
            isSelected = true;
        }
        else
        {
            if (isSelected)
            {
                isSelected = false;
                Debug.Log("deselect");
                selected = false;
                interactive.Deselect();
            }
        }
    }

if(selected) do something;
else // since we are not selected // do something else;

you will need to learn the rudimentary basics of programming
there are very many free on-line

Can you just explain what you’re trying to do?
Maybe you’re overworked and need a break. ;D

I just don’t want to push interactive.Deselect(); every single frame…
and, indeed, on the “else” the behavior still the same, will deselect all units but one still selected :\

… yea maybe I need a break ^^

I’ve this class which manage the unit’s interactivity, GUI, the element that show it’s selected etc…ect.
The selection works fine, but looks that I’m not able to deselect 'em for some reason.