Unnecessary slider controls

Nov 30, 2010 at 9:53 PM

The complexities of this framework can overwhelm me at some points and I'd just like to check that how I'm going about something is the preferred method for extending it and that I'm not missing an easy trick somewhere.

I've noted that when I create list boxes it will create the slider control even if the current list items fits within the list control completely. This leaves a slider control at the side which is just one big thumb.

Whilst from a usage point of view its fine it just looks a bit messy to me so I've had a quick go at try to make a slider only render and update if its needed. Now because you don't know if a slider is needed until you start rendering the parent control to get the IListRowLocator to determine row height the way I went about it was the following.

I created a new class SliderControlToggable with a new property SliderActive. I then set this bool value inside the updateSlider of the parent list control. Its later used by the slider renderer to see if it needs to draw the slider, it is also used as a check against all the OnMouse inherited SliderControl methods and it only calls the base method if the SliderActive is true, see below example. Is this the right way to go about it?

public abstract class SliderControlToggable : SliderControl
    {
        public bool SliderActive
        {
            get;
            set;
        }

        /// Moves the thumb to the specified location
        /// Location the thumb will be moved to
        protected override abstract void MoveThumb(float x, float y);

        /// Obtains the region covered by the slider's thumb
        /// The region covered by the slider's thumb
        protected override abstract RectangleF GetThumbRegion();

        public override bool ThumbDepressed
        {
            get
            {
                return false;
            }
        }

        protected override void OnMousePressed(Nuclex.Input.MouseButtons button)
        {
            if(SliderActive)
                base.OnMousePressed(button);
        }

        protected override void OnMouseReleased(Nuclex.Input.MouseButtons button)
        {
            if(SliderActive)
                base.OnMouseReleased(button);
        }

        protected override void OnMouseMoved(float x, float y)
        {
            if (SliderActive)
                base.OnMouseMoved(x, y);
        }

        protected override void OnMouseLeft()
        {
            if (SliderActive)
                base.OnMouseLeft();
        }

        protected override void OnMoved()
        {
            if (SliderActive)
                base.OnMoved();
        }
    }

Coordinator
Dec 12, 2010 at 6:49 PM

That is one way you can do it, though it might not play perfectly nice with the automated notification routing - unless you also move the slider outside of the list's bounding rectangle if it is disabled.

You could also dynamically add/remove the slider from the control tree (the entire control tree of the GUI follows the Composite pattern - any control is also a container for other controls, so the slider is simply a child control in the list control).

I thought implementing a permanent slider control was cool because, to me, it seemed to be the most consistent solution: the visible area of the list is always the same and doesn't depend on the number of items in it. But maybe it's a strange decision from a usability point of view :)

Dec 13, 2010 at 7:10 PM

Actually that's exactly what I tried to do the first time.

I suppose the issue was that this is really something I would be trying to handle in the update calls, but you don't know if its something you need to do till the draw call. At that point the request to draw is already in the GUIManager and my attempts to remove it never seemed to work (just null reference errors). If you know the safe way to remove a GUI element from the control tree after rendering has already started then that would be perfect.

Coordinator
Dec 19, 2010 at 2:00 PM

There shouldn't be any exceptions from that - will be fixed in the next release ;)

I'm planning a little redesign for the GUI soon that should get rid of the not-so-great reference assignment during rendering. Currently, when the GUI is rendered, the "visualizer" determines which "renderer" to use and then gives it the control to draw it. My planned change is to associate each control with its own renderer. That way, there's a cleanly defined association phase during which the renderer can provide the control with data such as text height and letter finding callbacks. It also allows the renderers to animate things because they're no longer required to be stateless.

Dec 19, 2010 at 9:41 PM

Sounds perfect, I'll put my extra controls on the backburner until the next release and work on something else, sounds as if these changes would be breaking.

If your going to be digging around in the GUI sections can I recommend adding in some extra placement definitions in the skin XML files? I've just finished adding them into my own project for some situations I came across. When you specify the placement of an element, left, right or stretch, this gets converted into the % section of your uniscalar. The ability to also add in an offset for these placements for the pixel section of the uniscalar gives you complete control over the skin. For example I would specify the placement of an element as stretch and then a leftOffset and rightOffset, useful for when you want something to cover the entire inside of a GUI control minus some borders.