guiSliderCtrl.cpp
Engine/source/gui/controls/guiSliderCtrl.cpp
Public Functions
ConsoleDocClass(GuiSliderCtrl , "@brief A <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> that displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> between its minimal and maximal bounds using <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider placed on <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vertical " "or horizontal <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">axis.\n\n</a>" "A slider displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> and allows that <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be changed by dragging <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> thumb <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> along the axis of the " "slider. In this way, the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> is changed between its allowed minimum and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">maximum.\n\n</a>" "To hook up script code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> changes of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider, use the #command and #altCommand properties. #command is " "executed once the thumb is released by the user whereas #altCommand is called any time the slider <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> changes. " "When changing the slider <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> from script, however , trigger of #altCommand is suppressed by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">default.\n\n</a>" "The orientation of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider is automatically determined from the ratio of its width <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> its height. If <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider is " "taller than it is wide, it will be rendered with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vertical orientation. If it is wider than it is tall)
DefineEngineMethod(GuiSliderCtrl , getValue , F32 , () , "Get the current <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of the slider based on the position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">thumb.\n</a>" "@return Slider position (from range.x <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> range.y)." )
DefineEngineMethod(GuiSliderCtrl , isThumbBeingDragged , bool , () , "Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the thumb is currently being dragged by the user. This method is mainly useful " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scrubbing type sliders where the slider position is sync'd <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> changing value. When the " "user is dragging the thumb, however , the sync 'ing should pause and not get in the way of the user." )
DefineEngineMethod(GuiSliderCtrl , setValue , void , (F32 pos, bool doCallback) , (false) , "Set position of the thumb on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slider.\n</a>" "@param pos New slider position (from range.x <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> range.y)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param doCallback If true, the altCommand callback will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">invoked\n</a>" )
IMPLEMENT_CALLBACK(GuiSliderCtrl , onMouseDragged , void , () , () , "Called when the left mouse button is dragged across the slider." )
Detailed Description
Public Functions
ConsoleDocClass(GuiSliderCtrl , "@brief A <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> that displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> between its minimal and maximal bounds using <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider placed on <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vertical " "or horizontal <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">axis.\n\n</a>" "A slider displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> and allows that <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be changed by dragging <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> thumb <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> along the axis of the " "slider. In this way, the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> is changed between its allowed minimum and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">maximum.\n\n</a>" "To hook up script code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> changes of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider, use the #command and #altCommand properties. #command is " "executed once the thumb is released by the user whereas #altCommand is called any time the slider <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> changes. " "When changing the slider <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> from script, however , trigger of #altCommand is suppressed by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">default.\n\n</a>" "The orientation of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider is automatically determined from the ratio of its width <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> its height. If <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> slider is " "taller than it is wide, it will be rendered with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vertical orientation. If it is wider than it is tall)
DefineEngineMethod(GuiSliderCtrl , getValue , F32 , () , "Get the current <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of the slider based on the position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">thumb.\n</a>" "@return Slider position (from range.x <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> range.y)." )
DefineEngineMethod(GuiSliderCtrl , isThumbBeingDragged , bool , () , "Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the thumb is currently being dragged by the user. This method is mainly useful " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scrubbing type sliders where the slider position is sync'd <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> changing value. When the " "user is dragging the thumb, however , the sync 'ing should pause and not get in the way of the user." )
DefineEngineMethod(GuiSliderCtrl , setValue , void , (F32 pos, bool doCallback) , (false) , "Set position of the thumb on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slider.\n</a>" "@param pos New slider position (from range.x <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> range.y)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param doCallback If true, the altCommand callback will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">invoked\n</a>" )
IMPLEMENT_CALLBACK(GuiSliderCtrl , onMouseDragged , void , () , () , "Called when the left mouse button is dragged across the slider." )
IMPLEMENT_CONOBJECT(GuiSliderCtrl )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "console/console.h" 25#include "console/consoleTypes.h" 26#include "console/engineAPI.h" 27#include "gfx/gfxTextureManager.h" 28#include "gui/controls/guiSliderCtrl.h" 29#include "gui/core/guiDefaultControlRender.h" 30#include "gfx/primBuilder.h" 31#include "gfx/gfxDrawUtil.h" 32#include "sfx/sfxSystem.h" 33#include "sfx/sfxTrack.h" 34 35 36IMPLEMENT_CONOBJECT( GuiSliderCtrl ); 37 38ConsoleDocClass( GuiSliderCtrl, 39 "@brief A control that displays a value between its minimal and maximal bounds using a slider placed on a vertical " 40 "or horizontal axis.\n\n" 41 42 "A slider displays a value and allows that value to be changed by dragging a thumb control along the axis of the " 43 "slider. In this way, the value is changed between its allowed minimum and maximum.\n\n" 44 45 "To hook up script code to the value changes of a slider, use the #command and #altCommand properties. #command is " 46 "executed once the thumb is released by the user whereas #altCommand is called any time the slider value changes. " 47 "When changing the slider value from script, however, trigger of #altCommand is suppressed by default.\n\n" 48 49 "The orientation of a slider is automatically determined from the ratio of its width to its height. If a slider is " 50 "taller than it is wide, it will be rendered with a vertical orientation. If it is wider than it is tall, it will be " 51 "rendered with a horizontal orientation.\n\n" 52 53 "The rendering of a slider depends on the bitmap in the slider's profile. This bitmap must be a bitmap array comprised " 54 "of at least five bitmap rectangles. The rectangles are used such that:\n\n" 55 56 "- Rectangle #1: Left edge of slider\n" 57 "- Rectangle #2: Center piece of slider; this is stretched between the left and right edge\n" 58 "- Rectangle #3: Right edge of slider\n" 59 "- Rectangle #4: Thumb button in normal state\n" 60 "- Rectangle #5: Thumb button in highlighted (mouse-over) state\n\n" 61 62 "@tsexample\n" 63 "// Create a sound source and a slider that changes the volume of the source.\n" 64 "\n" 65 "%source = sfxPlayOnce( \"art/sound/testing\", AudioLoop2D );\n" 66 "\n" 67 "new GuiSlider()\n" 68 "{\n" 69 " // Update the sound source volume when the slider is being dragged and released.\n" 70 " command = %source @ \".setVolume( $ThisControl.value );\";\n" 71 "\n" 72 " // Limit the range to 0..1 since that is the allowable range for sound volumes.\n" 73 " range = \"0 1\";\n" 74 "};\n" 75 "@endtsexample\n\n" 76 77 "@see GuiTextEditSliderCtrl\n" 78 "@see GuiTextEditSliderBitmapCtrl\n\n" 79 80 "@ingroup GuiValues" 81); 82 83 84IMPLEMENT_CALLBACK( GuiSliderCtrl, onMouseDragged, void, (), (), 85 "Called when the left mouse button is dragged across the slider." ); 86 87 88//---------------------------------------------------------------------------- 89 90GuiSliderCtrl::GuiSliderCtrl() 91 : mRange( 0., 1.f ), 92 mTicks( 10 ), 93 mRenderTicks(true), 94 mSnap( false ), 95 mValue( 0.5f ), 96 mThumbSize( 8, 20 ), 97 mShiftPoint( 5 ), 98 mShiftExtent( 10 ), 99 mIncAmount( 0.f ), 100 mDisplayValue( false ), 101 mMouseOver( false ), 102 mDepressed( false ), 103 mMouseDragged( false ), 104 mHasTexture(false), 105 mUseFillBar(false), 106 mFillBarColor(ColorI(255,255,255)), 107 mBitmapBounds(NULL) 108{ 109} 110 111//---------------------------------------------------------------------------- 112 113void GuiSliderCtrl::initPersistFields() 114{ 115 addGroup( "Slider" ); 116 117 addField( "range", TypePoint2F, Offset( mRange, GuiSliderCtrl ), 118 "Min and max values corresponding to left and right slider position." ); 119 addField( "ticks", TypeS32, Offset( mTicks, GuiSliderCtrl ), 120 "Spacing between tick marks in pixels. 0=off." ); 121 addField( "snap", TypeBool, Offset( mSnap, GuiSliderCtrl ), 122 "Whether to snap the slider to tick marks." ); 123 addProtectedField( "value", TypeF32, Offset( mValue, GuiSliderCtrl ), 124 _setValue, defaultProtectedGetFn, 125 "The value corresponding to the current slider position." ); 126 addField("useFillBar", TypeBool, Offset(mUseFillBar, GuiSliderCtrl), 127 "Whether to render the tick marks."); 128 addField("fillBarColor", TypeColorI, Offset(mFillBarColor, GuiSliderCtrl), 129 "Whether to render the tick marks."); 130 addField("renderTicks", TypeBool, Offset(mRenderTicks, GuiSliderCtrl), 131 "Whether to render the tick marks."); 132 133 endGroup( "Slider" ); 134 135 Parent::initPersistFields(); 136} 137 138//---------------------------------------------------------------------------- 139 140void GuiSliderCtrl::setValue(F32 val, bool doCallback) 141{ 142 _updateThumb( val, mSnap, false, doCallback ); 143} 144 145//---------------------------------------------------------------------------- 146 147void GuiSliderCtrl::setActive( bool value ) 148{ 149 if( !value && mDepressed ) 150 { 151 // We're in the middle of a drag. Finish it here as once we've 152 // been deactivated, we are not going to see a mouse-up event. 153 154 mDepressed = false; 155 mouseUnlock(); 156 execConsoleCallback(); 157 } 158 159 Parent::setActive( value ); 160} 161 162//---------------------------------------------------------------------------- 163 164bool GuiSliderCtrl::onWake() 165{ 166 if( !Parent::onWake() ) 167 return false; 168 169 mHasTexture = mProfile->constructBitmapArray() >= NumBitmaps; 170 if( mHasTexture ) 171 { 172 mBitmapBounds = mProfile->mBitmapArrayRects.address(); 173 mThumbSize = Point2I( mBitmapBounds[ SliderButtonNormal ].extent.x, mBitmapBounds[ SliderButtonNormal ].extent.y ); 174 } 175 176 F32 value; 177 if( mConsoleVariable[ 0 ] ) 178 value = getFloatVariable(); 179 else 180 value = mValue; 181 182 mValue = mClampF( value, mRange.x, mRange.y ); 183 184 // mouse scroll increment percentage is 5% of the range 185 mIncAmount = ( ( mRange.y - mRange.x ) * 0.05 ); 186 187 if( ( mThumbSize.y + mProfile->mFont->getHeight() - 4 ) <= getExtent().y ) 188 mDisplayValue = true; 189 else 190 mDisplayValue = false; 191 192 _updateThumb( mValue, mSnap, true ); 193 194 return true; 195} 196 197//---------------------------------------------------------------------------- 198 199void GuiSliderCtrl::onMouseDown(const GuiEvent &event) 200{ 201 if ( !mActive || !mAwake || !mVisible ) 202 return; 203 204 mouseLock(); 205 setFirstResponder(); 206 mDepressed = true; 207 208 Point2I curMousePos = globalToLocalCoord( event.mousePoint ); 209 F32 value; 210 if (getWidth() >= getHeight()) 211 value = F32(curMousePos.x-mShiftPoint) / F32(getWidth()-mShiftExtent)*(mRange.y-mRange.x) + mRange.x; 212 else 213 value = F32(curMousePos.y) / F32(getHeight())*(mRange.y-mRange.x) + mRange.x; 214 215 _updateThumb( value, mSnap || ( event.modifier & SI_SHIFT ) ); 216} 217 218//---------------------------------------------------------------------------- 219 220void GuiSliderCtrl::onMouseDragged( const GuiEvent &event ) 221{ 222 if ( !mActive || !mAwake || !mVisible ) 223 return; 224 225 mMouseDragged = true; 226 227 F32 value = _getThumbValue( event ); 228 _updateThumb( value, mSnap || ( event.modifier & SI_SHIFT ) ); 229 230 onMouseDragged_callback(); 231} 232 233//---------------------------------------------------------------------------- 234 235void GuiSliderCtrl::onMouseUp( const GuiEvent& event ) 236{ 237 if ( !mActive || !mAwake || !mVisible ) 238 return; 239 240 mouseUnlock(); 241 242 mDepressed = false; 243 mMouseDragged = false; 244 245 _updateThumb( _getThumbValue( event ), event.modifier & SI_SHIFT ); 246 247 execConsoleCallback(); 248} 249 250//---------------------------------------------------------------------------- 251 252void GuiSliderCtrl::onMouseEnter(const GuiEvent &event) 253{ 254 setUpdate(); 255 if( isMouseLocked() ) 256 { 257 mDepressed = true; 258 mMouseOver = true; 259 } 260 else 261 { 262 if( mActive && mProfile->mSoundButtonOver ) 263 { 264 //F32 pan = (F32(event.mousePoint.x)/F32(getRoot()->getWidth())*2.0f-1.0f)*0.8f; 265 SFX->playOnce( mProfile->mSoundButtonOver ); 266 } 267 268 mMouseOver = true; 269 } 270} 271 272//---------------------------------------------------------------------------- 273 274void GuiSliderCtrl::onMouseLeave(const GuiEvent &) 275{ 276 setUpdate(); 277 if( isMouseLocked() ) 278 mDepressed = false; 279 mMouseOver = false; 280} 281//---------------------------------------------------------------------------- 282 283bool GuiSliderCtrl::onMouseWheelUp(const GuiEvent &event) 284{ 285 if ( !mActive || !mAwake || !mVisible ) 286 return Parent::onMouseWheelUp(event); 287 288 _updateThumb( mValue + mIncAmount, ( event.modifier & SI_SHIFT ) ); 289 execConsoleCallback(); 290 291 return true; 292} 293 294//---------------------------------------------------------------------------- 295 296bool GuiSliderCtrl::onMouseWheelDown(const GuiEvent &event) 297{ 298 if ( !mActive || !mAwake || !mVisible ) 299 return Parent::onMouseWheelUp(event); 300 301 _updateThumb( mValue - mIncAmount, ( event.modifier & SI_SHIFT ) ); 302 execConsoleCallback(); 303 304 return true; 305} 306 307//---------------------------------------------------------------------------- 308 309void GuiSliderCtrl::_updateThumb( F32 _value, bool snap, bool onWake, bool doCallback ) 310{ 311 if( snap && mTicks > 0 ) 312 { 313 // If the shift key is held, snap to the nearest tick, if any are being drawn 314 315 F32 tickStep = (mRange.y - mRange.x) / F32(mTicks + 1); 316 317 F32 tickSteps = (_value - mRange.x) / tickStep; 318 S32 actualTick = S32(tickSteps + 0.5); 319 320 _value = actualTick * tickStep + mRange.x; 321 } 322 323 // Clamp the thumb to legal values. 324 325 if( _value < mRange.x ) 326 _value = mRange.x; 327 if( _value > mRange.y ) 328 _value = mRange.y; 329 330 // If value hasn't changed and this isn't the initial update on 331 // waking, do nothing. 332 333 if( mValue == _value && !onWake ) 334 return; 335 336 mValue = _value; 337 338 Point2I ext = getExtent(); 339 ext.x -= ( mShiftExtent + mThumbSize.x ) / 2; 340 // update the bounding thumb rect 341 if (getWidth() >= getHeight()) 342 { // HORZ thumb 343 S32 mx = (S32)((F32(ext.x) * (mValue-mRange.x) / (mRange.y-mRange.x))); 344 S32 my = ext.y/2; 345 if(mDisplayValue) 346 my = mThumbSize.y/2; 347 348 mThumb.point.x = mx - (mThumbSize.x/2); 349 mThumb.point.y = my - (mThumbSize.y/2); 350 mThumb.extent = mThumbSize; 351 } 352 else 353 { // VERT thumb 354 S32 mx = ext.x/2; 355 S32 my = (S32)((F32(ext.y) * (mValue-mRange.x) / (mRange.y-mRange.x))); 356 mThumb.point.x = mx - (mThumbSize.y/2); 357 mThumb.point.y = my - (mThumbSize.x/2); 358 mThumb.extent.x = mThumbSize.y; 359 mThumb.extent.y = mThumbSize.x; 360 } 361 362 setFloatVariable(mValue); 363 setUpdate(); 364 365 // Use the alt console command if you want to continually update: 366 if ( !onWake && doCallback ) 367 execAltConsoleCallback(); 368} 369 370//---------------------------------------------------------------------------- 371 372void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect) 373{ 374 Point2I pos(offset.x+mShiftPoint, offset.y); 375 Point2I ext(getWidth() - mShiftExtent, getHeight()); 376 RectI thumb = mThumb; 377 378 GFXDrawUtil* drawUtil = GFX->getDrawUtil(); 379 380 if (mUseFillBar) 381 { 382 383 drawUtil->drawRectFill(RectI(offset.x, offset.y, getWidth() * mValue, getHeight()), mFillBarColor); 384 385 renderChildControls(offset, updateRect); 386 return; 387 } 388 389 if( mHasTexture ) 390 { 391 if(mTicks > 0 && mRenderTicks) 392 { 393 // TODO: tick marks should be positioned based on the bitmap dimensions. 394 Point2I mid(ext.x, ext.y/2); 395 Point2I oldpos = pos; 396 pos += Point2I(1, 0); 397 398 PrimBuild::color4f( 0.f, 0.f, 0.f, 1.f ); 399 PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 ); 400 // tick marks 401 for (U32 t = 0; t <= (mTicks+1); t++) 402 { 403 S32 x = (S32)(F32(mid.x+1)/<a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a>(mTicks+1)*F32(t)) + pos.x; 404 S32 y = pos.y + mid.y; 405 PrimBuild::vertex2i(x, y + mShiftPoint); 406 PrimBuild::vertex2i(x, y + mShiftPoint*2 + 2); 407 } 408 PrimBuild::end(); 409 // TODO: it would be nice, if the primitive builder were a little smarter, 410 // so that we could change colors midstream. 411 PrimBuild::color4f(0.9f, 0.9f, 0.9f, 1.0f); 412 PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 ); 413 // tick marks 414 for (U32 t = 0; t <= (mTicks+1); t++) 415 { 416 S32 x = (S32)(F32(mid.x+1)/<a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a>(mTicks+1)*F32(t)) + pos.x + 1; 417 S32 y = pos.y + mid.y + 1; 418 PrimBuild::vertex2i(x, y + mShiftPoint ); 419 PrimBuild::vertex2i(x, y + mShiftPoint * 2 + 3); 420 } 421 PrimBuild::end(); 422 pos = oldpos; 423 } 424 425 S32 index = SliderButtonNormal; 426 if(mMouseOver) 427 index = SliderButtonHighlight; 428 drawUtil->clearBitmapModulation(); 429 430 //left border 431 drawUtil->drawBitmapSR(mProfile->mTextureObject, Point2I(offset.x,offset.y), mBitmapBounds[SliderLineLeft]); 432 //right border 433 drawUtil->drawBitmapSR(mProfile->mTextureObject, Point2I(offset.x + getWidth() - mBitmapBounds[SliderLineRight].extent.x, offset.y), mBitmapBounds[SliderLineRight]); 434 435 436 //draw our center piece to our slider control's border and stretch it 437 RectI destRect; 438 destRect.point.x = offset.x + mBitmapBounds[SliderLineLeft].extent.x; 439 destRect.extent.x = getWidth() - mBitmapBounds[SliderLineLeft].extent.x - mBitmapBounds[SliderLineRight].extent.x; 440 destRect.point.y = offset.y; 441 destRect.extent.y = mBitmapBounds[SliderLineCenter].extent.y; 442 443 RectI stretchRect; 444 stretchRect = mBitmapBounds[SliderLineCenter]; 445 stretchRect.inset(1,0); 446 447 drawUtil->drawBitmapStretchSR(mProfile->mTextureObject, destRect, stretchRect); 448 449 //draw our control slider button 450 thumb.point += pos; 451 drawUtil->drawBitmapSR(mProfile->mTextureObject,Point2I(thumb.point.x,offset.y ),mBitmapBounds[index]); 452 453 } 454 else if (getWidth() >= getHeight()) 455 { 456 Point2I mid(ext.x, ext.y/2); 457 if(mDisplayValue) 458 mid.set(ext.x, mThumbSize.y/2); 459 460 PrimBuild::color4f( 0.f, 0.f, 0.f, 1.f ); 461 PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 + 2); 462 // horz rule 463 PrimBuild::vertex2i( pos.x, pos.y + mid.y ); 464 PrimBuild::vertex2i( pos.x + mid.x, pos.y + mid.y ); 465 466 // tick marks 467 if (mRenderTicks) 468 { 469 for (U32 t = 0; t <= (mTicks + 1); t++) 470 { 471 S32 x = (S32)(F32(mid.x - 1) / F32(mTicks + 1) * F32(t)); 472 PrimBuild::vertex2i(pos.x + x, pos.y + mid.y - mShiftPoint); 473 PrimBuild::vertex2i(pos.x + x, pos.y + mid.y + mShiftPoint); 474 } 475 } 476 PrimBuild::end(); 477 } 478 else 479 { 480 Point2I mid(ext.x/2, ext.y); 481 482 PrimBuild::color4f( 0.f, 0.f, 0.f, 1.f ); 483 PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 + 2); 484 // horz rule 485 PrimBuild::vertex2i( pos.x + mid.x, pos.y ); 486 PrimBuild::vertex2i( pos.x + mid.x, pos.y + mid.y ); 487 488 // tick marks 489 if (mRenderTicks) 490 { 491 for (U32 t = 0; t <= (mTicks + 1); t++) 492 { 493 S32 y = (S32)(F32(mid.y - 1) / F32(mTicks + 1) * F32(t)); 494 PrimBuild::vertex2i(pos.x + mid.x - mShiftPoint, pos.y + y); 495 PrimBuild::vertex2i(pos.x + mid.x + mShiftPoint, pos.y + y); 496 } 497 } 498 PrimBuild::end(); 499 mDisplayValue = false; 500 } 501 // draw the thumb 502 thumb.point += pos; 503 renderRaisedBox(thumb, mProfile); 504 505 if(mDisplayValue) 506 { 507 char buf[20]; 508 dSprintf(buf,sizeof(buf),"%0.3f",mValue); 509 510 Point2I textStart = thumb.point; 511 512 S32 txt_w = mProfile->mFont->getStrWidth((const UTF8 *)buf); 513 514 textStart.x += (S32)((thumb.extent.x/2.0f)); 515 textStart.y += thumb.extent.y - 2; //19 516 textStart.x -= (txt_w/2); 517 if(textStart.x < offset.x) 518 textStart.x = offset.x; 519 else if(textStart.x + txt_w > offset.x+getWidth()) 520 textStart.x -=((textStart.x + txt_w) - (offset.x+getWidth())); 521 522 drawUtil->setBitmapModulation(mProfile->mFontColor); 523 drawUtil->drawText(mProfile->mFont, textStart, buf, mProfile->mFontColors); 524 } 525 renderChildControls(offset, updateRect); 526} 527 528//---------------------------------------------------------------------------- 529 530bool GuiSliderCtrl::resize( const Point2I& newPosition, const Point2I& newSize ) 531{ 532 if( !Parent::resize( newPosition, newSize ) ) 533 return false; 534 535 _updateThumb( mValue, false, true, false ); 536 return true; 537} 538 539//---------------------------------------------------------------------------- 540 541void GuiSliderCtrl::parentResized( const RectI& oldParentRect, const RectI& newParentRect ) 542{ 543 Parent::parentResized( oldParentRect, newParentRect ); 544 545 _updateThumb( mValue, false, true, false ); 546} 547 548//---------------------------------------------------------------------------- 549 550F32 GuiSliderCtrl::_getThumbValue( const GuiEvent& event ) 551{ 552 Point2I curMousePos = globalToLocalCoord( event.mousePoint ); 553 554 F32 value; 555 if( getWidth() >= getHeight() ) 556 value = F32( curMousePos.x - mShiftPoint ) / F32( getWidth() - mShiftExtent ) * ( mRange.y - mRange.x ) + mRange.x; 557 else 558 value = F32( curMousePos.y ) / F32( getHeight() ) * ( mRange.y - mRange.x ) + mRange.x; 559 560 if(value > mRange.y ) 561 value = mRange.y; 562 else if( value < mRange.x ) 563 value = mRange.x; 564 565 if( mSnap || ( event.modifier & SI_SHIFT && mTicks >= 1 ) ) 566 { 567 // If the shift key is held, snap to the nearest tick, if any are being drawn 568 569 F32 tickStep = ( mRange.y - mRange.x ) / F32( mTicks + 1 ); 570 571 F32 tickSteps = (value - mRange.x ) / tickStep; 572 S32 actualTick = S32( tickSteps + 0.5 ); 573 574 value = actualTick * tickStep + mRange.x; 575 AssertFatal( value <= mRange.y && value>= mRange.x, "Error, out of bounds value generated from shift-snap of slider" ); 576 } 577 578 return value; 579} 580 581//============================================================================= 582// Console Methods. 583//============================================================================= 584 585//----------------------------------------------------------------------------- 586 587DefineEngineMethod( GuiSliderCtrl, getValue, F32, (),, 588 "Get the current value of the slider based on the position of the thumb.\n" 589 "@return Slider position (from range.x to range.y)." ) 590{ 591 return object->getValue(); 592} 593 594//---------------------------------------------------------------------------- 595 596DefineEngineMethod( GuiSliderCtrl, setValue, void, ( F32 pos, bool doCallback ), ( false ), 597 "Set position of the thumb on the slider.\n" 598 "@param pos New slider position (from range.x to range.y)\n" 599 "@param doCallback If true, the altCommand callback will be invoked\n" ) 600{ 601 object->setValue( pos, doCallback ); 602} 603 604//---------------------------------------------------------------------------- 605 606DefineEngineMethod( GuiSliderCtrl, isThumbBeingDragged, bool, (),, 607 "Returns true if the thumb is currently being dragged by the user. This method is mainly useful " 608 "for scrubbing type sliders where the slider position is sync'd to a changing value. When the " 609 "user is dragging the thumb, however, the sync'ing should pause and not get in the way of the user." ) 610{ 611 return object->isThumbBeingDragged(); 612} 613