123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 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 "console/console.h"
- #include "console/consoleTypes.h"
- #include "graphics/dgl.h"
- #include "graphics/TextureManager.h"
- #include "gui/guiSliderCtrl.h"
- #include "gui/guiDefaultControlRender.h"
- #include "platform/event.h"
- IMPLEMENT_CONOBJECT(GuiSliderCtrl);
- //----------------------------------------------------------------------------
- GuiSliderCtrl::GuiSliderCtrl(void)
- {
- mActive = true;
- mRange.set(0.0f, 1.0f);
- mTicks = 10;
- mValue = 0.5f;
- mThumbSize.set(8, 20);
- mShiftPoint = 5;
- mShiftExtent = 10;
- mDisplayValue = false;
- mMouseOver = false;
- mDepressed = false;
- mRendersChildren = false;
- mIsContainer = false;
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::initPersistFields()
- {
- Parent::initPersistFields();
- addGroup("Slider");
- addField("range", TypePoint2F, Offset(mRange, GuiSliderCtrl));
- addField("ticks", TypeS32, Offset(mTicks, GuiSliderCtrl));
- addField("value", TypeF32, Offset(mValue, GuiSliderCtrl));
- endGroup("Slider");
- }
- //----------------------------------------------------------------------------
- ConsoleMethod( GuiSliderCtrl, getValue, F32, 2, 2, "() Use the getValue method to get the current value of the slider.\n"
- "@return Returns current value of control (position of slider)"){
- return object->getValue();
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::setScriptValue(const char *val)
- {
- mValue = dAtof(val);
- updateThumb(mValue, false);
- }
- //----------------------------------------------------------------------------
- bool GuiSliderCtrl::onWake()
- {
- if (!Parent::onWake())
- return false;
- if (mThumbSize.y + mProfile->getFont(mFontSizeAdjust)->getHeight() - 4 <= (U32) mBounds.extent.y)
- mDisplayValue = true;
- else
- mDisplayValue = false;
- updateThumb(mValue, false, true);
- mHasTexture = mProfile->constructBitmapArray() >= NumBitmaps;
- if (mHasTexture)
- mBitmapBounds = mProfile->mBitmapArrayRects.address();
- return true;
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::onTouchDown(const GuiEvent &event)
- {
- if (!mActive || !mAwake || !mVisible)
- return;
- mouseLock();
- setFirstResponder();
- mDepressed = true;
- Point2I curMousePos = globalToLocalCoord(event.mousePoint);
- F32 value;
- if (mBounds.extent.x >= mBounds.extent.y)
- value = F32(curMousePos.x - mShiftPoint) / F32(mBounds.extent.x - mShiftExtent) * (mRange.y - mRange.x) + mRange.x;
- else
- value = F32(curMousePos.y) / F32(mBounds.extent.y) * (mRange.y - mRange.x) + mRange.x;
- updateThumb(value, !(event.modifier & SI_SHIFT));
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::onTouchDragged(const GuiEvent &event)
- {
- if (!mActive || !mAwake || !mVisible)
- return;
- Point2I curMousePos = globalToLocalCoord(event.mousePoint);
- F32 value;
- if (mBounds.extent.x >= mBounds.extent.y)
- value = F32(curMousePos.x - mShiftPoint) / F32(mBounds.extent.x - mShiftExtent) * (mRange.y - mRange.x) + mRange.x;
- else
- value = F32(curMousePos.y) / F32(mBounds.extent.y) * (mRange.y - mRange.x) + mRange.x;
- if (value > mRange.y)
- value = mRange.y;
- else if (value < mRange.x)
- value = mRange.x;
- if (!(event.modifier & SI_SHIFT) && mTicks > 2)
- {
- // If the shift key is held, snap to the nearest tick, if any are being drawn
- F32 tickStep = (mRange.y - mRange.x) / F32(mTicks + 1);
- F32 tickSteps = (value - mRange.x) / tickStep;
- S32 actualTick = S32(tickSteps + 0.5);
- value = actualTick * tickStep + mRange.x;
- AssertFatal(value <= mRange.y && value >= mRange.x, "Error, out of bounds value generated from shift-snap of slider");
- }
- Con::executef(this, 1, "onMouseDragged");
- updateThumb(value, !(event.modifier & SI_SHIFT));
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::onTouchUp(const GuiEvent &)
- {
- if (!mActive || !mAwake || !mVisible)
- return;
- mDepressed = false;
- mouseUnlock();
- execConsoleCallback();
- }
- void GuiSliderCtrl::onTouchEnter(const GuiEvent &event)
- {
- setUpdate();
- if (isMouseLocked())
- {
- mDepressed = true;
- mMouseOver = true;
- }
- else
- {
- mMouseOver = true;
- }
- }
- void GuiSliderCtrl::onTouchLeave(const GuiEvent &)
- {
- setUpdate();
- if (isMouseLocked())
- mDepressed = false;
- mMouseOver = false;
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::updateThumb(F32 _value, bool snap, bool onWake)
- {
- if (snap && mTicks > 1)
- {
- // If the shift key is held, snap to the nearest tick, if any are being drawn
- F32 tickStep = (mRange.y - mRange.x) / F32(mTicks + 1);
- F32 tickSteps = (_value - mRange.x) / tickStep;
- S32 actualTick = S32(tickSteps + 0.5);
- _value = actualTick * tickStep + mRange.x;
- AssertFatal(_value <= mRange.y && _value >= mRange.x, "Error, out of bounds value generated from shift-snap of slider");
- }
- mValue = _value;
- // clamp the thumb to legal values
- if (mValue < mRange.x) mValue = mRange.x;
- if (mValue > mRange.y) mValue = mRange.y;
- Point2I ext = mBounds.extent;
- ext.x -= (mShiftExtent + mThumbSize.x) / 2;
- // update the bounding thumb rect
- if (mBounds.extent.x >= mBounds.extent.y)
- { // HORZ thumb
- S32 mx = (S32) ((F32(ext.x) * (mValue - mRange.x) / (mRange.y - mRange.x)));
- S32 my = ext.y / 2;
- if (mDisplayValue)
- my = mThumbSize.y / 2;
- mThumb.point.x = mx - (mThumbSize.x / 2);
- mThumb.point.y = my - (mThumbSize.y / 2);
- mThumb.extent = mThumbSize;
- }
- else
- { // VERT thumb
- S32 mx = ext.x / 2;
- S32 my = (S32) ((F32(ext.y) * (mValue - mRange.x) / (mRange.y - mRange.x)));
- mThumb.point.x = mx - (mThumbSize.y / 2);
- mThumb.point.y = my - (mThumbSize.x / 2);
- mThumb.extent.x = mThumbSize.y;
- mThumb.extent.y = mThumbSize.x;
- }
- setFloatVariable(mValue);
- setUpdate();
- // Use the alt console command if you want to continually update:
- if (!onWake)
- execAltConsoleCallback();
- }
- //----------------------------------------------------------------------------
- void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
- {
- Point2I pos(offset.x + mShiftPoint, offset.y);
- Point2I ext(mBounds.extent.x - mShiftExtent, mBounds.extent.y);
- RectI thumb = mThumb;
- if (mHasTexture)
- {
- if (mTicks > 0)
- {
- // TODO: tick marks should be positioned based on the bitmap dimentions.
- Point2I mid(ext.x, ext.y / 2);
- Point2I oldpos = pos;
- pos += Point2I(1, 0);
- glColor4f(0, 0, 0, 1);
- #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
- // tick marks
- for (U32 t = 0; t <= (mTicks + 1); t++)
- {
- S32 x = (S32) (F32(mid.x + 1) / F32(mTicks + 1) * F32(t)) + pos.x;
- S32 y = pos.y + mid.y;
- GLfloat shiftVert[] = {
- (GLfloat) (x),
- (GLfloat) (y + mShiftPoint),
- (GLfloat) (x),
- (GLfloat) (y + mShiftPoint * 2.0f + 2.0f),
- };
- glVertexPointer(2, GL_FLOAT, 0, shiftVert);
- glDrawArrays(GL_LINES, 0, 2);
- }
- glColor4f(0.9f, 0.9f, 0.9f, 1.0f);
- // tick marks
- for (U32 t = 0; t <= (mTicks + 1); t++)
- {
- S32 x = (S32) (F32(mid.x + 1) / F32(mTicks + 1) * F32(t)) + pos.x + 1;
- S32 y = pos.y + mid.y + 1;
- GLfloat shiftVert[] = {
- (GLfloat) (x),
- (GLfloat) (y + mShiftPoint),
- (GLfloat) (x),
- (GLfloat) (y + mShiftPoint * 2 + 3),
- };
- glVertexPointer(2, GL_FLOAT, 0, shiftVert);
- glDrawArrays(GL_LINES, 0, 2);
- }
- #else
- glBegin(GL_LINES);
- // tick marks
- for (U32 t = 0; t <= (mTicks+1); t++)
- {
- S32 x = (S32)(F32(mid.x+1)/F32(mTicks+1)*F32(t)) + pos.x;
- S32 y = pos.y + mid.y;
- glVertex2i(x, y + mShiftPoint);
- glVertex2i(x, y + mShiftPoint*2 + 2);
- }
- glEnd();
- glColor4f(0.9f, 0.9f, 0.9f, 1.0f);
- glBegin(GL_LINES);
- // tick marks
- for (U32 t = 0; t <= (mTicks+1); t++)
- {
- S32 x = (S32)(F32(mid.x+1)/F32(mTicks+1)*F32(t)) + pos.x + 1;
- S32 y = pos.y + mid.y + 1;
- glVertex2i(x, y + mShiftPoint );
- glVertex2i(x, y + mShiftPoint*2 + 3);
- }
- glEnd();
- #endif
- pos = oldpos;
- }
- S32 index = SliderButtonNormal;
- if (mMouseOver)
- index = SliderButtonHighlight;
- dglClearBitmapModulation();
- //left border
- dglDrawBitmapSR(mProfile->mTextureHandle, Point2I(offset.x, offset.y + (mBounds.extent.y / 4)), mBitmapBounds[SliderLineLeft]);
- //right border
- dglDrawBitmapSR(mProfile->mTextureHandle, Point2I(offset.x + mBounds.extent.x - mBitmapBounds[SliderLineRight].extent.x, offset.y + (mBounds.extent.y / 4)), mBitmapBounds[SliderLineRight]);
- //draw our center piece to our slider control's border and stretch it
- RectI destRect;
- destRect.point.x = offset.x + mBitmapBounds[SliderLineLeft].extent.x;
- destRect.extent.x = mBounds.extent.x - mBitmapBounds[SliderLineLeft].extent.x - mBitmapBounds[SliderLineRight].extent.x;
- destRect.point.y = offset.y + (mBounds.extent.y / 4);
- destRect.extent.y = mBitmapBounds[SliderLineCenter].extent.y;
- RectI stretchRect;
- stretchRect = mBitmapBounds[SliderLineCenter];
- stretchRect.inset(1, 0);
- dglDrawBitmapStretchSR(mProfile->mTextureHandle, destRect, stretchRect);
- //draw our control slider button
- thumb.point += pos;
- dglDrawBitmapSR(mProfile->mTextureHandle, Point2I(thumb.point.x, offset.y), mBitmapBounds[index]);
- }
- else
- {
- // we're not usina a bitmap, draw procedurally.
- if (mBounds.extent.x >= mBounds.extent.y)
- {
- Point2I mid(ext.x, ext.y / 2);
- if (mDisplayValue)
- mid.set(ext.x, mThumbSize.y / 2);
- glColor4f(0, 0, 0, 1);
- #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
- // tick marks
- for (U32 t = 0; t <= (mTicks + 1); t++)
- {
- S32 x = (S32) (F32(mid.x - 1) / F32(mTicks + 1) * F32(t));
- GLfloat verts[] = {
- static_cast<GLfloat>(pos.x + x), static_cast<GLfloat>(pos.y + mid.y - mShiftPoint),
- static_cast<GLfloat>(pos.x + x), static_cast<GLfloat>(pos.y + mid.y + mShiftPoint)
- };
- glVertexPointer(2, GL_FLOAT, 0, verts);
- glDrawArrays(GL_LINES, 0, 2);
- }
- GLfloat verts[] = {
- static_cast<GLfloat>(pos.x), static_cast<GLfloat>(pos.y + mid.y),
- static_cast<GLfloat>(pos.x + mid.x), static_cast<GLfloat>(pos.y + mid.y)
- };
- glVertexPointer(2, GL_FLOAT, 0, verts);
- glDrawArrays(GL_LINES, 0, 2);
- }
- else
- {
- Point2I mid(ext.x / 2, ext.y);
- glColor4f(0, 0, 0, 1);
- // tick marks
- for (U32 t = 0; t <= (mTicks + 1); t++)
- {
- S32 y = (S32) (F32(mid.y - 1) / F32(mTicks + 1) * F32(t));
- GLfloat verts[] = {
- static_cast<GLfloat>(pos.x + mid.x - mShiftPoint), static_cast<GLfloat>(pos.y + y),
- static_cast<GLfloat>(pos.x + mid.x + mShiftPoint), static_cast<GLfloat>(pos.y + y)
- };
- glVertexPointer(2, GL_FLOAT, 0, verts);
- glDrawArrays(GL_LINES, 0, 2);
- }
- GLfloat verts[] = {
- static_cast<GLfloat>(pos.x + mid.x), static_cast<GLfloat>(pos.y),
- static_cast<GLfloat>(pos.x + mid.x), static_cast<GLfloat>(pos.y + mid.y)
- };
- //for the horizontal line
- glVertexPointer(2, GL_FLOAT, 0, verts);
- glDrawArrays(GL_LINES, 0, 2);
- #else
- glBegin(GL_LINES);
- // horz rule
- glVertex2i(pos.x, pos.y+mid.y);
- glVertex2i(pos.x+mid.x, pos.y+mid.y);
- // tick marks
- for (U32 t = 0; t <= (mTicks+1); t++)
- {
- S32 x = (S32)(F32(mid.x-1)/F32(mTicks+1)*F32(t));
- glVertex2i(pos.x+x, pos.y+mid.y-mShiftPoint);
- glVertex2i(pos.x+x, pos.y+mid.y+mShiftPoint);
- }
- glEnd();
- }
- else
- {
- Point2I mid(ext.x/2, ext.y);
- glColor4f(0, 0, 0, 1);
- glBegin(GL_LINES);
- // horz rule
- glVertex2i(pos.x+mid.x, pos.y);
- glVertex2i(pos.x+mid.x, pos.y+mid.y);
- // tick marks
- for (U32 t = 0; t <= (mTicks+1); t++)
- {
- S32 y = (S32)(F32(mid.y-1)/F32(mTicks+1)*F32(t));
- glVertex2i(pos.x+mid.x-mShiftPoint, pos.y+y);
- glVertex2i(pos.x+mid.x+mShiftPoint, pos.y+y);
- }
- glEnd();
- #endif
- mDisplayValue = false;
- }
- // draw the thumb
- thumb.point += pos;
- renderUniversalRect(thumb, mProfile, NormalState);
- }
- if (mDisplayValue)
- {
- char buf[20];
- dSprintf(buf, sizeof(buf), "%0.3g", mValue);
- Point2I textStart = thumb.point;
- S32 txt_w = mProfile->getFont(mFontSizeAdjust)->getStrWidth((const UTF8 *) buf);
- textStart.x += (S32) ((thumb.extent.x / 2.0f));
- textStart.y += thumb.extent.y - 2; //19
- textStart.x -= (txt_w / 2);
- if (textStart.x < offset.x)
- textStart.x = offset.x;
- else if (textStart.x + txt_w > offset.x + mBounds.extent.x)
- textStart.x -= ((textStart.x + txt_w) - (offset.x + mBounds.extent.x));
- dglSetBitmapModulation(getFontColor(mProfile));
- dglDrawText(mProfile->getFont(mFontSizeAdjust), textStart, buf, mProfile->mFontColors);
- }
- renderChildControls(offset, mBounds, updateRect);
- }
|