//----------------------------------------------------------------------------- // 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. //----------------------------------------------------------------------------- //------------------------------------- // // Icon Button Control // Draws the bitmap within a special button control. Only a single bitmap is used and the // button will be drawn in a highlighted mode when the mouse hovers over it or when it // has been clicked. // // Use mTextLocation to choose where within the button the text will be drawn, if at all. // Use mTextMargin to set the text away from the button sides or from the bitmap. // Use mButtonMargin to set everything away from the button sides. // Use mErrorBitmapName to set the name of a bitmap to draw if the main bitmap cannot be found. // Use mFitBitmapToButton to force the bitmap to fill the entire button extent. Usually used // with no button text defined. // // if the extent is set to (0,0) in the gui editor and appy hit, this control will // set it's extent to be exactly the size of the normal bitmap (if present) // #include "console/console.h" #include "graphics/dgl.h" #include "console/consoleTypes.h" #include "platform/platformAudio.h" #include "gui/guiCanvas.h" #include "gui/guiDefaultControlRender.h" #include "gui/buttons/guiIconButtonCtrl.h" static ColorI colorWhite(255,255,255); static ColorI colorBlack(0,0,0); IMPLEMENT_CONOBJECT(GuiIconButtonCtrl); //------------------------------------- GuiIconButtonCtrl::GuiIconButtonCtrl() { mBitmapName = StringTable->EmptyString; mTextLocation = TextLocLeft; mIconLocation = IconLocLeft; mTextMargin = 4; mButtonMargin.set(4,4); mFitBitmapToButton = false; mErrorBitmapName = StringTable->EmptyString; mErrorTextureHandle = NULL; mBounds.extent.set(140, 30); } static EnumTable::Enums textLocEnums[] = { { GuiIconButtonCtrl::TextLocNone, "None" }, { GuiIconButtonCtrl::TextLocBottom, "Bottom" }, { GuiIconButtonCtrl::TextLocRight, "Right" }, { GuiIconButtonCtrl::TextLocTop, "Top" }, { GuiIconButtonCtrl::TextLocLeft, "Left" }, { GuiIconButtonCtrl::TextLocCenter, "Center" }, }; static EnumTable gTextLocTable(6, &textLocEnums[0]); static EnumTable::Enums iconLocEnums[] = { { GuiIconButtonCtrl::IconLocLeft, "Left" }, { GuiIconButtonCtrl::IconLocRight, "Right" }, { GuiIconButtonCtrl::IconLocNone, "None" }, }; static EnumTable gIconLocTable(3, &iconLocEnums[0]); //------------------------------------- void GuiIconButtonCtrl::initPersistFields() { Parent::initPersistFields(); addField("buttonMargin", TypePoint2I, Offset(mButtonMargin, GuiIconButtonCtrl)); addField("iconBitmap", TypeFilename, Offset(mBitmapName, GuiIconButtonCtrl)); addField("iconLocation", TypeEnum, Offset(mIconLocation, GuiIconButtonCtrl), 1, &gIconLocTable); addField("sizeIconToButton", TypeBool, Offset(mFitBitmapToButton, GuiIconButtonCtrl)); addField("textLocation", TypeEnum, Offset(mTextLocation, GuiIconButtonCtrl), 1, &gTextLocTable); addField("textMargin", TypeS32, Offset(mTextMargin, GuiIconButtonCtrl)); } //------------------------------------- bool GuiIconButtonCtrl::onWake() { if (! Parent::onWake()) return false; setActive(true); setBitmap(mBitmapName); if( mProfile ) mProfile->constructBitmapArray(); return true; } //------------------------------------- void GuiIconButtonCtrl::onSleep() { mTextureNormal = NULL; Parent::onSleep(); } //------------------------------------- ConsoleMethod( GuiIconButtonCtrl, setBitmap, void, 3, 3, "(filepath name) Loads bitmap from file\n" "@param name The path of the desired bitmap file\n" "@return No Return Value.") { char* argBuffer = Con::getArgBuffer( 512 ); Platform::makeFullPathName( argv[2], argBuffer, 512 ); object->setBitmap( argBuffer ); } //------------------------------------- void GuiIconButtonCtrl::inspectPostApply() { // if the extent is set to (0,0) in the gui editor and appy hit, this control will // set it's extent to be exactly the size of the normal bitmap (if present) Parent::inspectPostApply(); if ((mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureNormal) { TextureObject *texture = (TextureObject *) mTextureNormal; mBounds.extent.x = texture->getBitmapWidth() + 4; mBounds.extent.y = texture->getBitmapHeight() + 4; } } //------------------------------------- void GuiIconButtonCtrl::setBitmap(const char *name) { mBitmapName = StringTable->insert(name); if(!isAwake()) return; if (*mBitmapName) { mTextureNormal = TextureHandle(name, TextureHandle::BitmapTexture, true); } else { mTextureNormal = NULL; } setUpdate(); } //------------------------------------- void GuiIconButtonCtrl::onRender(Point2I offset, const RectI& updateRect) { renderButton( offset, updateRect); } //------------------------------------------------------------------------------ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) { bool highlight = mMouseOver; bool depressed = mDepressed; ColorI fontColor; if (!mActive) fontColor = mProfile->mFontColorNA; else { if (highlight) fontColor = mProfile->mFontColorHL; else if (mStateOn) fontColor = mProfile->mFontColorSEL; else fontColor = mProfile->mFontColor; } ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA; ColorI borderColor = mActive ? mProfile->mBorderColor : mProfile->mBorderColorNA; RectI boundsRect(offset, mBounds.extent); if (mDepressed || mStateOn) { // If there is a bitmap array then render using it. Otherwise use a standard // fill. if( mProfile->mBitmapArrayRects.size() ) renderBitmapArray(boundsRect, statePressed); else renderLoweredBox(boundsRect, mProfile); } else if(mMouseOver && mActive) { // If there is a bitmap array then render using it. Otherwise use a standard // fill. if(mProfile->mBitmapArrayRects.size()) renderBitmapArray(boundsRect, stateMouseOver); else renderRaisedBox(boundsRect, mProfile); } else { // If there is a bitmap array then render using it. Otherwise use a standard // fill. if(mProfile->mBitmapArrayRects.size()) { if(mActive) renderBitmapArray(boundsRect, stateNormal); else renderBitmapArray(boundsRect, stateDisabled); } else { dglDrawRectFill(boundsRect, mProfile->mFillColorNA); dglDrawRect(boundsRect, mProfile->mBorderColorNA); } } Point2I textPos = offset; if(depressed) textPos += Point2I(1,1); // Render the icon if ( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone ) { // Render the normal bitmap dglClearBitmapModulation(); TextureObject *texture = (TextureObject *) mTextureNormal; // Maintain the bitmap size or fill the button? if(!mFitBitmapToButton) { RectI iconRect(offset + mButtonMargin, Point2I(texture->getBitmapWidth(),texture->getBitmapHeight())); Point2I textureSize( texture->getBitmapWidth(), texture->getBitmapHeight() ); if( mIconLocation == IconLocRight ) iconRect.set( offset + mBounds.extent - ( mButtonMargin + textureSize ), textureSize ); else if( mIconLocation == IconLocLeft ) iconRect.set(offset + mButtonMargin, textureSize ); dglDrawBitmapStretch(texture, iconRect); } else { RectI rect(offset + mButtonMargin, mBounds.extent - (mButtonMargin * 2) ); dglDrawBitmapStretch(texture, rect); } } // Render text if(mTextLocation != TextLocNone) { dglSetBitmapModulation( fontColor ); S32 textWidth = mProfile->mFont->getStrWidth(mButtonText); if(mTextLocation == TextLocRight) { Point2I start( mTextMargin, (mBounds.extent.y-mProfile->mFont->getHeight())/2 ); if( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone ) { TextureObject *texture = (TextureObject *) mTextureNormal; start.x = texture->getBitmapWidth() + mButtonMargin.x + mTextMargin; } dglDrawText( mProfile->mFont, start + offset, mButtonText, mProfile->mFontColors ); } if(mTextLocation == TextLocCenter) { Point2I start; if( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone ) { TextureObject *texObject = (TextureObject *) mTextureNormal; start.set( ( (mBounds.extent.x - textWidth - texObject->getBitmapWidth())/2) + texObject->getBitmapWidth(), (mBounds.extent.y-mProfile->mFont->getHeight())/2 ); } else start.set( (mBounds.extent.x - textWidth)/2, (mBounds.extent.y-mProfile->mFont->getHeight())/2 ); dglSetBitmapModulation( fontColor ); dglDrawText( mProfile->mFont, start + offset, mButtonText, mProfile->mFontColors ); } } renderChildControls( offset, updateRect); } // Draw the bitmap array's borders according to the button's state. void GuiIconButtonCtrl::renderBitmapArray(RectI &bounds, S32 state) { switch(state) { case stateNormal: if(mProfile->mBorder == -2) renderSizableBitmapBordersFilled(bounds, 1, mProfile); else renderFixedBitmapBordersFilled(bounds, 1, mProfile); break; case stateMouseOver: if(mProfile->mBorder == -2) renderSizableBitmapBordersFilled(bounds, 2, mProfile); else renderFixedBitmapBordersFilled(bounds, 2, mProfile); break; case statePressed: if(mProfile->mBorder == -2) renderSizableBitmapBordersFilled(bounds, 3, mProfile); else renderFixedBitmapBordersFilled(bounds, 3, mProfile); break; case stateDisabled: if(mProfile->mBorder == -2) renderSizableBitmapBordersFilled(bounds, 4, mProfile); else renderFixedBitmapBordersFilled(bounds, 4, mProfile); break; } }