[Widget] Slider, float value

Crystal Hammer

03-05-2012 20:26:04

Hi, I've made a simple widget, similar to horizontal ScrollBar (for us it's a replacement for it).
It has a float value, not int, and always between 0.f and 1.f. So it's easier for most of our controls, no need for any weird transforms from/to int in code, only multiply by range.
It's only move to click, no knob dragging needed. Knob size is fixed. Looks almost exactly like ScrollBar, knob is image not button.
It doesn't have this issue that click didn't work after resizing (to a bigger screen resolution, in upper area).
Feel free to use or modify.

Slider.h

#ifndef __MYGUI_SLIDER_H__
#define __MYGUI_SLIDER_H__

#include "MyGUI_Prerequest.h"
#include "MyGUI_Widget.h"

namespace MyGUI
{
class Slider;
typedef delegates::CMultiDelegate2<Slider*, float> EventHandle_ValueChanged;

class Slider :
public Widget,
public MemberObsolete<Slider>
{
MYGUI_RTTI_DERIVED( Slider )

public:
Slider();

// Slider value 0.f .. 1.f
void setValue(float val);
float getValue() const;

/*events:*/
/** Event : Slider position changed.\n
signature : void method(MyGUI::Slider* sender, float value)\n
@param sender - widget that called this event
@param value - new slider value
*/
EventHandle_ValueChanged eventValueChanged;

virtual void setSize(const IntSize& _value);
virtual void setCoord(const IntCoord& _value);
void setSize(int _width, int _height);
void setCoord(int _left, int _top, int _width, int _height);

protected:
virtual void initialiseOverride();
virtual void shutdownOverride();
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);

void notifyMouse(Widget* _sender, int _left, int _top, MouseButton _id);
void notifyMouseWheel(Widget* _sender, int _rel);
void onMouseWheel(int _rel);

void updateTrack();

protected:
// <--[]----->
Button* mWidgetStart; // <
Button* mWidgetEnd; // >
ImageBox* mWidgetTrack; // [] knob

float mfValue;
};

}

#endif


Slider.cpp

#include "MyGUI_Precompiled.h"
#include "Slider.h"
#include "MyGUI_InputManager.h"
#include "MyGUI_Button.h"
#include "MyGUI_ResourceSkin.h"
#include "MyGUI_ImageBox.h"

namespace MyGUI
{

Slider::Slider() :
mWidgetStart(nullptr),
mWidgetEnd(nullptr),
mWidgetTrack(nullptr),
mfValue(0.f)
{
}

// Init
//-----------------------------------------------------------------------------------------------
void Slider::initialiseOverride()
{
Base::initialiseOverride();

eventMouseButtonPressed += newDelegate(this, &Slider::notifyMouse);
eventMouseDrag += newDelegate(this, &Slider::notifyMouse);
eventMouseWheel += newDelegate(this, &Slider::notifyMouseWheel);

assignWidget(mWidgetTrack, "Track");
if (mWidgetTrack != nullptr)
{
mWidgetTrack->eventMouseDrag += newDelegate(this, &Slider::notifyMouse);
mWidgetTrack->eventMouseButtonPressed += newDelegate(this, &Slider::notifyMouse);
mWidgetTrack->eventMouseWheel += newDelegate(this, &Slider::notifyMouseWheel);
mWidgetTrack->setVisible(false);
}

assignWidget(mWidgetStart, "Start");
if (mWidgetStart != nullptr)
{
mWidgetStart->eventMouseButtonPressed += newDelegate(this, &Slider::notifyMouse);
mWidgetStart->eventMouseWheel += newDelegate(this, &Slider::notifyMouseWheel);
}
assignWidget(mWidgetEnd, "End");
if (mWidgetEnd != nullptr)
{
mWidgetEnd->eventMouseButtonPressed += newDelegate(this, &Slider::notifyMouse);
mWidgetEnd->eventMouseWheel += newDelegate(this, &Slider::notifyMouseWheel);
}
}

void Slider::shutdownOverride()
{
mWidgetStart = nullptr;
mWidgetEnd = nullptr;
mWidgetTrack = nullptr;

Base::shutdownOverride();
}

void Slider::updateTrack()
{
if (mWidgetTrack == nullptr)
return;

_forcePick(mWidgetTrack);

if (!mWidgetTrack->getVisible())
mWidgetTrack->setVisible(true);

int iTrack = mWidgetTrack->getSize().width;
int iSize = mWidgetTrack->getParent()->getSize().width - iTrack;

int pos = mfValue * iSize;

mWidgetTrack->setPosition(pos, mWidgetTrack->getTop());
}

/// mouse button
//-----------------------------------------------------------------------------------------------
void Slider::notifyMouse(Widget* _sender, int _left, int _top, MouseButton _id)
{
//eventMouseButtonPressed(this, _left, _top, _id);
//if (MouseButton::Left != _id)
// return;

const IntPoint& p = mWidgetTrack->getParent()->getAbsolutePosition();
const IntSize& s = mWidgetTrack->getParent()->getSize();
int iTrack = mWidgetTrack->getSize().width;

float fx = (_left-iTrack/2 - p.left) / float(s.width - iTrack);
//float fy = (_top - p.top) / float(s.height);
fx = std::max(0.f, std::min(1.f, fx));

mfValue = fx;
eventValueChanged(this, mfValue);
updateTrack();
}


float Slider::getValue() const
{
return mfValue;
}

void Slider::setValue(float val)
{
//if (mValue == val)
// return;

mfValue = val; //std::max(0.f, std::min(1.f, val));
updateTrack();
}


// mouse wheel
//--------------------------------------------------------------------------------
void Slider::onMouseWheel(int _rel)
{
notifyMouseWheel(nullptr, _rel);

Base::onMouseWheel(_rel);
}

void Slider::notifyMouseWheel(Widget* _sender, int _rel)
{
mfValue = std::max(0.f, std::min(1.f, mfValue - _rel/120.f*0.5f * 0.125f ));
eventValueChanged(this, mfValue);
updateTrack();
}

void Slider::setPropertyOverride(const std::string& _key, const std::string& _value)
{
if (_key == "Value")
setValue(utility::parseValue<float>(_value));
else
{
Base::setPropertyOverride(_key, _value);
return;
}
eventChangeProperty(this, _key, _value);
}


// update track on resize
void Slider::setSize(int _width, int _height)
{
setSize(IntSize(_width, _height));
}

void Slider::setCoord(int _left, int _top, int _width, int _height)
{
setCoord(IntCoord(_left, _top, _width, _height));
}

void Slider::setSize(const IntSize& _size)
{
Base::setSize(_size);
updateTrack();
}

void Slider::setCoord(const IntCoord& _coord)
{
Base::setCoord(_coord);
updateTrack();
}

}


and add to your core_blackbluetemplates.xml or other file this layout definition:

<Resource type="ResourceLayout" name="Slider" version="3.2.0">
<Widget type="Widget" skin="ScrollPanelHSkin" position="25 50 125 15" name="Root">
<Property key="VerticalAlignment" value="false"/>
<UserString key="LE_TargetWidgetType" value="ScrollBar"/>
<Widget type="Widget" skin="PanelEmpty" position="14 0 98 15" align="Stretch" name="TrackPlace">
<Property key="NeedKey" value="false"/>
<Property key="InheritsPick" value="true"/>
<Widget type="ImageBox" skin="ScrollTrackHSkin" position="35 1 21 14" align="Left VStretch" name="Track"/>
</Widget>
<Widget type="Button" skin="ButtonLeftSkin" position="2 1 12 14" align="Left VCenter" name="Start"/>
<Widget type="Button" skin="ButtonRightSkin" position="112 1 12 14" align="Right VCenter" name="End"/>
</Widget>
</Resource>