1 /***********************************************************************
2 	created:	13/4/2004
3 	author:		Paul D Turner
4 
5 	purpose:	Implementation of Slider widget base class
6 *************************************************************************/
7 /***************************************************************************
8  *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
9  *
10  *   Permission is hereby granted, free of charge, to any person obtaining
11  *   a copy of this software and associated documentation files (the
12  *   "Software"), to deal in the Software without restriction, including
13  *   without limitation the rights to use, copy, modify, merge, publish,
14  *   distribute, sublicense, and/or sell copies of the Software, and to
15  *   permit persons to whom the Software is furnished to do so, subject to
16  *   the following conditions:
17  *
18  *   The above copyright notice and this permission notice shall be
19  *   included in all copies or substantial portions of the Software.
20  *
21  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24  *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25  *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26  *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  *   OTHER DEALINGS IN THE SOFTWARE.
28  ***************************************************************************/
29 #include "CEGUI/widgets/Slider.h"
30 #include "CEGUI/widgets/Thumb.h"
31 #include "CEGUI/WindowManager.h"
32 #include "CEGUI/Exceptions.h"
33 
34 // Start of CEGUI namespace section
35 namespace CEGUI
36 {
37 const String Slider::EventNamespace("Slider");
38 const String Slider::WidgetTypeName("CEGUI/Slider");
39 
40 /*************************************************************************
41     SliderWindowRenderer
42 *************************************************************************/
SliderWindowRenderer(const String & name)43 SliderWindowRenderer::SliderWindowRenderer(const String& name) :
44     WindowRenderer(name, Slider::EventNamespace)
45 {
46 }
47 
48 /*************************************************************************
49 	Event name constants
50 *************************************************************************/
51 const String Slider::EventValueChanged( "ValueChanged" );
52 const String Slider::EventThumbTrackStarted( "ThumbTrackStarted" );
53 const String Slider::EventThumbTrackEnded( "ThumbTrackEnded" );
54 
55 /*************************************************************************
56     Child Widget name constants
57 *************************************************************************/
58 const String Slider::ThumbName( "__auto_thumb__" );
59 
60 /*************************************************************************
61 	Slider base class constructor
62 *************************************************************************/
Slider(const String & type,const String & name)63 Slider::Slider(const String& type, const String& name) :
64 	Window(type, name),
65 	d_value(0.0f),
66 	d_maxValue(1.0f),
67 	d_step(0.01f)
68 {
69 	addSliderProperties();
70 }
71 
72 
73 /*************************************************************************
74 	Slider base class destructor
75 *************************************************************************/
~Slider(void)76 Slider::~Slider(void)
77 {
78 }
79 
80 
81 /*************************************************************************
82 	Initialises the Window based object ready for use.
83 *************************************************************************/
initialiseComponents(void)84 void Slider::initialiseComponents(void)
85 {
86 	// get thumb
87 	Thumb* thumb = getThumb();
88 
89 	// bind handler to thumb events
90 	thumb->subscribeEvent(Thumb::EventThumbPositionChanged, Event::Subscriber(&CEGUI::Slider::handleThumbMoved, this));
91 	thumb->subscribeEvent(Thumb::EventThumbTrackStarted, Event::Subscriber(&CEGUI::Slider::handleThumbTrackStarted, this));
92 	thumb->subscribeEvent(Thumb::EventThumbTrackEnded, Event::Subscriber(&CEGUI::Slider::handleThumbTrackEnded, this));
93 
94 	performChildWindowLayout();
95 }
96 
97 
98 /*************************************************************************
99 	set the maximum value for the slider.
100 	Note that the minimum value is fixed at 0.
101 *************************************************************************/
setMaxValue(float maxVal)102 void Slider::setMaxValue(float maxVal)
103 {
104 	d_maxValue = maxVal;
105 
106 	float oldval = d_value;
107 
108 	// limit current value to be within new max
109 	if (d_value > d_maxValue) {
110 		d_value = d_maxValue;
111 	}
112 
113 	updateThumb();
114 
115 	// send notification if slider value changed.
116 	if (d_value != oldval)
117 	{
118 		WindowEventArgs args(this);
119 		onValueChanged(args);
120 	}
121 
122 }
123 
124 
125 /*************************************************************************
126 	set the current slider value.
127 *************************************************************************/
setCurrentValue(float value)128 void Slider::setCurrentValue(float value)
129 {
130 	float oldval = d_value;
131 
132 	// range for value: 0 <= value <= maxValue
133 	d_value = (value >= 0.0f) ? ((value <= d_maxValue) ? value : d_maxValue) : 0.0f;
134 
135 	updateThumb();
136 
137 	// send notification if slider value changed.
138 	if (d_value != oldval)
139 	{
140 		WindowEventArgs args(this);
141 		onValueChanged(args);
142 	}
143 
144 }
145 
validateWindowRenderer(const WindowRenderer * renderer) const146 bool Slider::validateWindowRenderer(const WindowRenderer* renderer) const
147 {
148 	return dynamic_cast<const SliderWindowRenderer*>(renderer) != 0;
149 }
150 
151 /*************************************************************************
152 	Handler triggered when the slider value changes
153 *************************************************************************/
onValueChanged(WindowEventArgs & e)154 void Slider::onValueChanged(WindowEventArgs& e)
155 {
156 	fireEvent(EventValueChanged, e, EventNamespace);
157 }
158 
159 
160 /*************************************************************************
161 	Handler triggered when the user begins to drag the slider thumb.
162 *************************************************************************/
onThumbTrackStarted(WindowEventArgs & e)163 void Slider::onThumbTrackStarted(WindowEventArgs& e)
164 {
165 	fireEvent(EventThumbTrackStarted, e, EventNamespace);
166 }
167 
168 
169 /*************************************************************************
170 	Handler triggered when the slider thumb is released
171 *************************************************************************/
onThumbTrackEnded(WindowEventArgs & e)172 void Slider::onThumbTrackEnded(WindowEventArgs& e)
173 {
174 	fireEvent(EventThumbTrackEnded, e, EventNamespace);
175 }
176 
177 
178 /*************************************************************************
179 	Handler for when a mouse button is pressed
180 *************************************************************************/
onMouseButtonDown(MouseEventArgs & e)181 void Slider::onMouseButtonDown(MouseEventArgs& e)
182 {
183 	// base class processing
184 	Window::onMouseButtonDown(e);
185 
186 	if (e.button == LeftButton)
187 	{
188 		float adj = getAdjustDirectionFromPoint(e.position);
189 
190 		// adjust slider position in whichever direction as required.
191 		if (adj != 0)
192 		{
193 			setCurrentValue(d_value + (adj * d_step));
194 		}
195 
196 		++e.handled;
197 	}
198 
199 }
200 
201 
202 /*************************************************************************
203 	Handler for scroll wheel changes
204 *************************************************************************/
onMouseWheel(MouseEventArgs & e)205 void Slider::onMouseWheel(MouseEventArgs& e)
206 {
207 	// base class processing
208 	Window::onMouseWheel(e);
209 
210 	// scroll by e.wheelChange * stepSize
211 	setCurrentValue(d_value + d_step * e.wheelChange);
212 
213 	// ensure the message does not go to our parent.
214 	++e.handled;
215 }
216 
217 
218 /*************************************************************************
219 	handler function for when thumb moves.
220 *************************************************************************/
handleThumbMoved(const EventArgs &)221 bool Slider::handleThumbMoved(const EventArgs&)
222 {
223 	setCurrentValue(getValueFromThumb());
224 
225 	return true;
226 }
227 
228 
229 /*************************************************************************
230 	handler function for when thumb tracking begins
231 *************************************************************************/
handleThumbTrackStarted(const EventArgs &)232 bool Slider::handleThumbTrackStarted(const EventArgs&)
233 {
234 	// simply trigger our own version of this event
235 	WindowEventArgs args(this);
236 	onThumbTrackStarted(args);
237 
238 	return true;
239 }
240 
241 
242 /*************************************************************************
243 	handler function for when thumb tracking begins
244 *************************************************************************/
handleThumbTrackEnded(const EventArgs &)245 bool Slider::handleThumbTrackEnded(const EventArgs&)
246 {
247 	// simply trigger our own version of this event
248 	WindowEventArgs args(this);
249 	onThumbTrackEnded(args);
250 
251 	return true;
252 }
253 
254 
255 /*************************************************************************
256 	Add properties for the slider
257 *************************************************************************/
addSliderProperties(void)258 void Slider::addSliderProperties(void)
259 {
260     const String& propertyOrigin = WidgetTypeName;
261 
262     CEGUI_DEFINE_PROPERTY(Slider, float,
263         "CurrentValue", "Property to get/set the current value of the slider.  Value is a float.",
264         &Slider::setCurrentValue, &Slider::getCurrentValue, 0.0f
265     );
266 
267     CEGUI_DEFINE_PROPERTY(Slider, float,
268         "MaximumValue", "Property to get/set the maximum value of the slider.  Value is a float.",
269         &Slider::setMaxValue, &Slider::getMaxValue, 1.0f /* TODO: Inconsistency */
270     );
271 
272     CEGUI_DEFINE_PROPERTY(Slider, float,
273         "ClickStepSize", "Property to get/set the click-step size for the slider.  Value is a float.",
274         &Slider::setClickStep, &Slider::getClickStep, 0.01f /* TODO: Inconsistency */
275     );
276 }
277 
278 /*************************************************************************
279     Return a pointer to the Thumb component widget..
280 *************************************************************************/
getThumb() const281 Thumb* Slider::getThumb() const
282 {
283     return static_cast<Thumb*>(getChild(ThumbName));
284 }
285 
286 /*************************************************************************
287     update the size and location of the thumb to properly represent the
288     current state of the scroll bar
289 *************************************************************************/
updateThumb(void)290 void Slider::updateThumb(void)
291 {
292     if (d_windowRenderer != 0)
293     {
294         SliderWindowRenderer* wr = (SliderWindowRenderer*)d_windowRenderer;
295         wr->updateThumb();
296     }
297     else
298     {
299         //updateThumb_impl();
300         CEGUI_THROW(InvalidRequestException(
301             "This function must be implemented by the window renderer module"));
302     }
303 }
304 
305 /*************************************************************************
306     return value that best represents current scroll bar position given
307     the current location of the thumb.
308 *************************************************************************/
getValueFromThumb(void) const309 float Slider::getValueFromThumb(void) const
310 {
311     if (d_windowRenderer != 0)
312     {
313         SliderWindowRenderer* wr = (SliderWindowRenderer*)d_windowRenderer;
314         return wr->getValueFromThumb();
315     }
316     else
317     {
318         //return getValueFromThumb_impl();
319         CEGUI_THROW(InvalidRequestException(
320             "This function must be implemented by the window renderer module"));
321     }
322 }
323 
324 /*************************************************************************
325     Given window location 'pt', return a value indicating what change
326     should be made to the scroll bar.
327 *************************************************************************/
getAdjustDirectionFromPoint(const Vector2f & pt) const328 float Slider::getAdjustDirectionFromPoint(const Vector2f& pt) const
329 {
330     if (d_windowRenderer != 0)
331     {
332         SliderWindowRenderer* wr = (SliderWindowRenderer*)d_windowRenderer;
333         return wr->getAdjustDirectionFromPoint(pt);
334     }
335     else
336     {
337         //return getAdjustDirectionFromPoint_impl(pt);
338         CEGUI_THROW(InvalidRequestException(
339             "This function must be implemented by the window renderer module"));
340     }
341 }
342 
343 } // End of  CEGUI namespace section
344