| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 | //-----------------------------------------------------------------------------// Copyright (c) 2012 GarageGames, LLC//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS// IN THE SOFTWARE.//-----------------------------------------------------------------------------#include "platform/platform.h"#include "gui/controls/guiTextEditSliderBitmapCtrl.h"#include "console/consoleTypes.h"#include "console/console.h"#include "gui/core/guiCanvas.h"#include "gfx/gfxDevice.h"#include "gfx/gfxDrawUtil.h"IMPLEMENT_CONOBJECT(GuiTextEditSliderBitmapCtrl);ConsoleDocClass( GuiTextEditSliderBitmapCtrl,   "@brief GUI Control which displays a numerical value which can be increased "   "or decreased using a pair of bitmap up/down buttons. \n\n"   "This control uses the bitmap specified in it's profile "   "(GuiControlProfile::bitmapName). It takes this image and breaks up aspects "   "of it to render the up and down arrows. It is also important to set "   "GuiControlProfile::hasBitmapArray to true on the profile as well.\n\n"   "The bitmap referenced should be broken up into a 1 x 4 grid (using the top "   "left color pixel as a border color between each of the images) in which it "   "will map to the following places:\n"   "<ol>\n"   "<li>Up arrow active</li>\n"   "<li>Up arrow inactive</li>\n"   "<li>Down arrow active</li>\n"   "<li>Down arrow inactive</li>\n"   "</ol>\n\n"   "<pre>\n"   "1\n"   "2\n"   "3\n"   "4</pre>\n\n"   "@tsexample\n"   "singleton GuiControlProfile (SliderBitmapGUIProfile)\n"   "{\n"   "   bitmap = \"core/art/gui/images/sliderArray\";\n"   "   hasBitmapArray = true;\n"   "   opaque = false;\n"   "};\n\n"   "new GuiTextEditSliderBitmapCtrl()\n"   "{\n"   "   profile = \"SliderBitmapGUIProfile\";\n"   "   format = \"%3.2f\";\n"   "   range = \"-1e+03 1e+03\";\n"   "   increment = \"0.1\";\n"   "   focusOnMouseWheel = \"0\";\n"   "   bitmap = \"\";\n"   "   //Properties not specific to this control have been omitted from this example.\n"   "};\n"   "@endtsexample\n\n"   "@see GuiTextEditSliderCtrl\n\n"   "@see GuiTextEditCtrl\n\n"   "@ingroup GuiCore\n");GuiTextEditSliderBitmapCtrl::GuiTextEditSliderBitmapCtrl(){   mRange.set(0.0f, 1.0f);   mIncAmount = 1.0f;   mValue = 0.0f;   mMulInc = 0;   mIncCounter = 0.0f;   mFormat = StringTable->insert("%3.2f");   mTextAreaHit = None;   mFocusOnMouseWheel = false;   mBitmapName = StringTable->insert( "" );}GuiTextEditSliderBitmapCtrl::~GuiTextEditSliderBitmapCtrl(){}void GuiTextEditSliderBitmapCtrl::initPersistFields(){   addField("format",    TypeString,  Offset(mFormat, GuiTextEditSliderBitmapCtrl), "Character format type to place in the control.\n");   addField("range",     TypePoint2F, Offset(mRange, GuiTextEditSliderBitmapCtrl), "Maximum vertical and horizontal range to allow in the control.\n");   addField("increment", TypeF32,     Offset(mIncAmount,     GuiTextEditSliderBitmapCtrl), "How far to increment the slider on each step.\n");   addField("focusOnMouseWheel", TypeBool, Offset(mFocusOnMouseWheel, GuiTextEditSliderBitmapCtrl), "If true, the control will accept giving focus to the user when the mouse wheel is used.\n");   addField("bitmap",    TypeFilename,Offset(mBitmapName, GuiTextEditSliderBitmapCtrl), "Unused" );   Parent::initPersistFields();}void GuiTextEditSliderBitmapCtrl::getText(char *dest){   Parent::getText(dest);}void GuiTextEditSliderBitmapCtrl::setText(const char *txt){   mValue = dAtof(txt);   checkRange();   setValue();}bool GuiTextEditSliderBitmapCtrl::onKeyDown(const GuiEvent &event){   return Parent::onKeyDown(event);}void GuiTextEditSliderBitmapCtrl::checkRange(){   if(mValue < mRange.x)      mValue = mRange.x;   else if(mValue > mRange.y)      mValue = mRange.y;}void GuiTextEditSliderBitmapCtrl::setValue(){   char buf[20];   // For some reason this sprintf is failing to convert   // a floating point number to anything with %d, so cast it.   if( dStricmp( mFormat, "%d" ) == 0 )      dSprintf(buf,sizeof(buf),mFormat, (S32)mValue);   else      dSprintf(buf,sizeof(buf),mFormat, mValue);   Parent::setText(buf);}void GuiTextEditSliderBitmapCtrl::onMouseDown(const GuiEvent &event){   // If we're not active then skip out.   if ( !mActive || !mAwake || !mVisible )   {      Parent::onMouseDown(event);      return;   }   char txt[20];   Parent::getText(txt);   mValue = dAtof(txt);   mMouseDownTime = Sim::getCurrentTime();   GuiControl *parent = getParent();   if(!parent)      return;   Point2I camPos  = event.mousePoint;   Point2I point = parent->localToGlobalCoord(getPosition());   if(camPos.x > point.x + getExtent().x - 14)   {      if(camPos.y > point.y + (getExtent().y/2))      {         mValue -=mIncAmount;         mTextAreaHit = ArrowDown;         mMulInc = -0.15f;      }      else      {         mValue +=mIncAmount;         mTextAreaHit = ArrowUp;         mMulInc = 0.15f;      }      checkRange();      setValue();      mouseLock();      // We should get the focus and set the       // cursor to the start of the text to       // mimic the standard Windows behavior.      setFirstResponder();      mCursorPos = mBlockStart = mBlockEnd = 0;      setUpdate();      return;   }   Parent::onMouseDown(event);}void GuiTextEditSliderBitmapCtrl::onMouseDragged(const GuiEvent &event){   // If we're not active then skip out.   if ( !mActive || !mAwake || !mVisible )   {      Parent::onMouseDragged(event);      return;   }   if(mTextAreaHit == None || mTextAreaHit == Slider)   {      mTextAreaHit = Slider;      GuiControl *parent = getParent();      if(!parent)         return;      Point2I camPos = event.mousePoint;      Point2I point = parent->localToGlobalCoord(getPosition());      F32 maxDis = 100;      F32 val;      if(camPos.y < point.y)      {         if((F32)point.y < maxDis)            maxDis = (F32)point.y;         val = point.y - maxDis;                  if(point.y > 0)            mMulInc= 1.0f-(((float)camPos.y - val) / maxDis);         else            mMulInc = 1.0f;                  checkIncValue();                  return;      }      else if(camPos.y > point.y + getExtent().y)      {         GuiCanvas *root = getRoot();         val = (F32)(root->getHeight() - (point.y + getHeight()));         if(val < maxDis)            maxDis = val;         if( val > 0)            mMulInc= -(F32)(camPos.y - (point.y + getHeight()))/maxDis;         else            mMulInc = -1.0f;         checkIncValue();         return;      }      mTextAreaHit = None;      Parent::onMouseDragged(event);   }}void GuiTextEditSliderBitmapCtrl::onMouseUp(const GuiEvent &event){   // If we're not active then skip out.   if ( !mActive || !mAwake || !mVisible )   {      Parent::onMouseUp(event);      return;   }   mMulInc = 0.0f;   mouseUnlock();   if ( mTextAreaHit != None )  //if we released the mouse within this control, then the parent will call  //the mConsoleCommand other wise we have to call it.   Parent::onMouseUp(event);   //if we didn't release the mouse within this control, then perform the action   // if (!cursorInControl())   execConsoleCallback();      execAltConsoleCallback();   mTextAreaHit = None;}bool GuiTextEditSliderBitmapCtrl::onMouseWheelUp(const GuiEvent &event){   if ( !mActive || !mAwake || !mVisible )      return Parent::onMouseWheelUp(event);   if ( !isFirstResponder() && !mFocusOnMouseWheel )      return false;   mValue += mIncAmount;   checkRange();   setValue();      setFirstResponder();   mCursorPos = mBlockStart = mBlockEnd = 0;   setUpdate();   return true;}bool GuiTextEditSliderBitmapCtrl::onMouseWheelDown(const GuiEvent &event){   if ( !mActive || !mAwake || !mVisible )      return Parent::onMouseWheelDown(event);   if ( !isFirstResponder() && !mFocusOnMouseWheel )      return false;   mValue -= mIncAmount;   checkRange();   setValue();   setFirstResponder();   mCursorPos = mBlockStart = mBlockEnd = 0;   setUpdate();   return true;}void GuiTextEditSliderBitmapCtrl::checkIncValue(){   if(mMulInc > 1.0f)      mMulInc = 1.0f;   else if(mMulInc < -1.0f)      mMulInc = -1.0f;}void GuiTextEditSliderBitmapCtrl::timeInc(U32 elapseTime){   S32 numTimes = elapseTime / 750;   if(mTextAreaHit != Slider && numTimes > 0)   {      if(mTextAreaHit == ArrowUp)         mMulInc = 0.15f * numTimes;      else         mMulInc = -0.15f * numTimes;      checkIncValue();   }}bool GuiTextEditSliderBitmapCtrl::onWake(){   if(!Parent::onWake())      return false;	mNumberOfBitmaps = mProfile->constructBitmapArray();   return true;}void GuiTextEditSliderBitmapCtrl::onPreRender(){   if (isFirstResponder())   {      U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastCursorFlipped;      mNumFramesElapsed++;      if ((timeElapsed > 500) && (mNumFramesElapsed > 3))      {         mCursorOn = !mCursorOn;         mTimeLastCursorFlipped = Sim::getCurrentTime();         mNumFramesElapsed = 0;         setUpdate();      }      //update the cursor if the text is scrolling      if (mDragHit)      {         if ((mScrollDir < 0) && (mCursorPos > 0))         {            mCursorPos--;         }         else if ((mScrollDir > 0) && (mCursorPos < (S32)dStrlen(mText)))         {            mCursorPos++;         }      }   }}void GuiTextEditSliderBitmapCtrl::onRender(Point2I offset, const RectI &updateRect){   if(mTextAreaHit != None)   {      U32 elapseTime = Sim::getCurrentTime() - mMouseDownTime;      if(elapseTime > 750 || mTextAreaHit == Slider)      {         timeInc(elapseTime);         mIncCounter += mMulInc;         if(mIncCounter >= 1.0f || mIncCounter <= -1.0f)         {            mValue = (mMulInc > 0.0f) ? mValue+mIncAmount : mValue-mIncAmount;            mIncCounter = (mIncCounter > 0.0f) ? mIncCounter-1 : mIncCounter+1;            checkRange();            setValue();            mCursorPos = 0;         }      }   }	Parent::onRender(offset, updateRect);	// Arrow placement coordinates   Point2I arrowUpStart(offset.x + getWidth() - 14, offset.y + 1 );   Point2I arrowUpEnd(13, getExtent().y/2);	Point2I arrowDownStart(offset.x + getWidth() - 14, offset.y + 1 + getExtent().y/2);	Point2I arrowDownEnd(13, getExtent().y/2);		// Draw the line that splits the number and bitmaps	GFX->getDrawUtil()->drawLine(Point2I(offset.x + getWidth() - 14 -2, offset.y + 1 ),		Point2I(arrowUpStart.x -2, arrowUpStart.y + getExtent().y),		mProfile->mBorderColor);	GFX->getDrawUtil()->clearBitmapModulation();		if(mNumberOfBitmaps == 0)		Con::warnf("No image provided for GuiTextEditSliderBitmapCtrl; do not render");	else	{		// This control needs 4 images in order to render correctly		if(mTextAreaHit == ArrowUp)			GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowUpStart,arrowUpEnd), mProfile->mBitmapArrayRects[0] );		else			GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowUpStart,arrowUpEnd), mProfile->mBitmapArrayRects[1] );		if(mTextAreaHit == ArrowDown)			GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowDownStart,arrowDownEnd), mProfile->mBitmapArrayRects[2] );		else			GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowDownStart,arrowDownEnd), mProfile->mBitmapArrayRects[3] );	}}void GuiTextEditSliderBitmapCtrl::setBitmap(const char *name){   bool awake = mAwake;   if(awake)      onSleep();   mBitmapName = StringTable->insert(name);   if(awake)      onWake();   setUpdate();}
 |