guiIconButtonCtrl.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //-------------------------------------
  23. //
  24. // Icon Button Control
  25. // Draws the bitmap within a special button control. Only a single bitmap is used and the
  26. // button will be drawn in a highlighted mode when the mouse hovers over it or when it
  27. // has been clicked.
  28. //
  29. // Use mTextLocation to choose where within the button the text will be drawn, if at all.
  30. // Use mTextMargin to set the text away from the button sides or from the bitmap.
  31. // Use mButtonMargin to set everything away from the button sides.
  32. // Use mErrorBitmapName to set the name of a bitmap to draw if the main bitmap cannot be found.
  33. // Use mFitBitmapToButton to force the bitmap to fill the entire button extent. Usually used
  34. // with no button text defined.
  35. //
  36. // if the extent is set to (0,0) in the gui editor and appy hit, this control will
  37. // set it's extent to be exactly the size of the normal bitmap (if present)
  38. //
  39. #include "console/console.h"
  40. #include "graphics/dgl.h"
  41. #include "console/consoleTypes.h"
  42. #include "platform/platformAudio.h"
  43. #include "gui/guiCanvas.h"
  44. #include "gui/guiDefaultControlRender.h"
  45. #include "gui/buttons/guiIconButtonCtrl.h"
  46. static ColorI colorWhite(255,255,255);
  47. static ColorI colorBlack(0,0,0);
  48. IMPLEMENT_CONOBJECT(GuiIconButtonCtrl);
  49. //-------------------------------------
  50. GuiIconButtonCtrl::GuiIconButtonCtrl()
  51. {
  52. mBitmapName = StringTable->EmptyString;
  53. mTextLocation = TextLocLeft;
  54. mIconLocation = IconLocLeft;
  55. mTextMargin = 4;
  56. mButtonMargin.set(4,4);
  57. mFitBitmapToButton = false;
  58. mErrorBitmapName = StringTable->EmptyString;
  59. mErrorTextureHandle = NULL;
  60. mBounds.extent.set(140, 30);
  61. }
  62. static EnumTable::Enums textLocEnums[] =
  63. {
  64. { GuiIconButtonCtrl::TextLocNone, "None" },
  65. { GuiIconButtonCtrl::TextLocBottom, "Bottom" },
  66. { GuiIconButtonCtrl::TextLocRight, "Right" },
  67. { GuiIconButtonCtrl::TextLocTop, "Top" },
  68. { GuiIconButtonCtrl::TextLocLeft, "Left" },
  69. { GuiIconButtonCtrl::TextLocCenter, "Center" },
  70. };
  71. static EnumTable gTextLocTable(6, &textLocEnums[0]);
  72. static EnumTable::Enums iconLocEnums[] =
  73. {
  74. { GuiIconButtonCtrl::IconLocLeft, "Left" },
  75. { GuiIconButtonCtrl::IconLocRight, "Right" },
  76. { GuiIconButtonCtrl::IconLocNone, "None" },
  77. };
  78. static EnumTable gIconLocTable(3, &iconLocEnums[0]);
  79. //-------------------------------------
  80. void GuiIconButtonCtrl::initPersistFields()
  81. {
  82. Parent::initPersistFields();
  83. addField("buttonMargin", TypePoint2I, Offset(mButtonMargin, GuiIconButtonCtrl));
  84. addField("iconBitmap", TypeFilename, Offset(mBitmapName, GuiIconButtonCtrl));
  85. addField("iconLocation", TypeEnum, Offset(mIconLocation, GuiIconButtonCtrl), 1, &gIconLocTable);
  86. addField("sizeIconToButton", TypeBool, Offset(mFitBitmapToButton, GuiIconButtonCtrl));
  87. addField("textLocation", TypeEnum, Offset(mTextLocation, GuiIconButtonCtrl), 1, &gTextLocTable);
  88. addField("textMargin", TypeS32, Offset(mTextMargin, GuiIconButtonCtrl));
  89. }
  90. //-------------------------------------
  91. bool GuiIconButtonCtrl::onWake()
  92. {
  93. if (! Parent::onWake())
  94. return false;
  95. setActive(true);
  96. setBitmap(mBitmapName);
  97. if( mProfile )
  98. mProfile->constructBitmapArray();
  99. return true;
  100. }
  101. //-------------------------------------
  102. void GuiIconButtonCtrl::onSleep()
  103. {
  104. mTextureNormal = NULL;
  105. Parent::onSleep();
  106. }
  107. //-------------------------------------
  108. ConsoleMethod( GuiIconButtonCtrl, setBitmap, void, 3, 3, "(filepath name) Loads bitmap from file\n"
  109. "@param name The path of the desired bitmap file\n"
  110. "@return No Return Value.")
  111. {
  112. char* argBuffer = Con::getArgBuffer( 512 );
  113. Platform::makeFullPathName( argv[2], argBuffer, 512 );
  114. object->setBitmap( argBuffer );
  115. }
  116. //-------------------------------------
  117. void GuiIconButtonCtrl::inspectPostApply()
  118. {
  119. // if the extent is set to (0,0) in the gui editor and appy hit, this control will
  120. // set it's extent to be exactly the size of the normal bitmap (if present)
  121. Parent::inspectPostApply();
  122. if ((mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureNormal)
  123. {
  124. TextureObject *texture = (TextureObject *) mTextureNormal;
  125. mBounds.extent.x = texture->getBitmapWidth() + 4;
  126. mBounds.extent.y = texture->getBitmapHeight() + 4;
  127. }
  128. }
  129. //-------------------------------------
  130. void GuiIconButtonCtrl::setBitmap(const char *name)
  131. {
  132. mBitmapName = StringTable->insert(name);
  133. if(!isAwake())
  134. return;
  135. if (*mBitmapName)
  136. {
  137. mTextureNormal = TextureHandle(name, TextureHandle::BitmapTexture, true);
  138. }
  139. else
  140. {
  141. mTextureNormal = NULL;
  142. }
  143. setUpdate();
  144. }
  145. //-------------------------------------
  146. void GuiIconButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
  147. {
  148. renderButton( offset, updateRect);
  149. }
  150. //------------------------------------------------------------------------------
  151. void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
  152. {
  153. bool highlight = mMouseOver;
  154. bool depressed = mDepressed;
  155. ColorI fontColor;
  156. if (!mActive)
  157. fontColor = mProfile->mFontColorNA;
  158. else
  159. {
  160. if (highlight)
  161. fontColor = mProfile->mFontColorHL;
  162. else if (mStateOn)
  163. fontColor = mProfile->mFontColorSEL;
  164. else
  165. fontColor = mProfile->mFontColor;
  166. }
  167. ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
  168. ColorI borderColor = mActive ? mProfile->mBorderColor : mProfile->mBorderColorNA;
  169. RectI boundsRect(offset, mBounds.extent);
  170. if (mDepressed || mStateOn)
  171. {
  172. // If there is a bitmap array then render using it. Otherwise use a standard
  173. // fill.
  174. if( mProfile->mBitmapArrayRects.size() )
  175. renderBitmapArray(boundsRect, statePressed);
  176. else
  177. renderLoweredBox(boundsRect, mProfile);
  178. }
  179. else if(mMouseOver && mActive)
  180. {
  181. // If there is a bitmap array then render using it. Otherwise use a standard
  182. // fill.
  183. if(mProfile->mBitmapArrayRects.size())
  184. renderBitmapArray(boundsRect, stateMouseOver);
  185. else
  186. renderRaisedBox(boundsRect, mProfile);
  187. }
  188. else
  189. {
  190. // If there is a bitmap array then render using it. Otherwise use a standard
  191. // fill.
  192. if(mProfile->mBitmapArrayRects.size())
  193. {
  194. if(mActive)
  195. renderBitmapArray(boundsRect, stateNormal);
  196. else
  197. renderBitmapArray(boundsRect, stateDisabled);
  198. }
  199. else
  200. {
  201. dglDrawRectFill(boundsRect, mProfile->mFillColorNA);
  202. dglDrawRect(boundsRect, mProfile->mBorderColorNA);
  203. }
  204. }
  205. Point2I textPos = offset;
  206. if(depressed)
  207. textPos += Point2I(1,1);
  208. // Render the icon
  209. if ( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone )
  210. {
  211. // Render the normal bitmap
  212. dglClearBitmapModulation();
  213. TextureObject *texture = (TextureObject *) mTextureNormal;
  214. // Maintain the bitmap size or fill the button?
  215. if(!mFitBitmapToButton)
  216. {
  217. RectI iconRect(offset + mButtonMargin, Point2I(texture->getBitmapWidth(),texture->getBitmapHeight()));
  218. Point2I textureSize( texture->getBitmapWidth(), texture->getBitmapHeight() );
  219. if( mIconLocation == IconLocRight )
  220. iconRect.set( offset + mBounds.extent - ( mButtonMargin + textureSize ), textureSize );
  221. else if( mIconLocation == IconLocLeft )
  222. iconRect.set(offset + mButtonMargin, textureSize );
  223. dglDrawBitmapStretch(texture, iconRect);
  224. }
  225. else
  226. {
  227. RectI rect(offset + mButtonMargin, mBounds.extent - (mButtonMargin * 2) );
  228. dglDrawBitmapStretch(texture, rect);
  229. }
  230. }
  231. // Render text
  232. if(mTextLocation != TextLocNone)
  233. {
  234. dglSetBitmapModulation( fontColor );
  235. S32 textWidth = mProfile->mFont->getStrWidth(mButtonText);
  236. if(mTextLocation == TextLocRight)
  237. {
  238. Point2I start( mTextMargin, (mBounds.extent.y-mProfile->mFont->getHeight())/2 );
  239. if( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone )
  240. {
  241. TextureObject *texture = (TextureObject *) mTextureNormal;
  242. start.x = texture->getBitmapWidth() + mButtonMargin.x + mTextMargin;
  243. }
  244. dglDrawText( mProfile->mFont, start + offset, mButtonText, mProfile->mFontColors );
  245. }
  246. if(mTextLocation == TextLocCenter)
  247. {
  248. Point2I start;
  249. if( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone )
  250. {
  251. TextureObject *texObject = (TextureObject *) mTextureNormal;
  252. start.set( ( (mBounds.extent.x - textWidth - texObject->getBitmapWidth())/2) + texObject->getBitmapWidth(), (mBounds.extent.y-mProfile->mFont->getHeight())/2 );
  253. }
  254. else
  255. start.set( (mBounds.extent.x - textWidth)/2, (mBounds.extent.y-mProfile->mFont->getHeight())/2 );
  256. dglSetBitmapModulation( fontColor );
  257. dglDrawText( mProfile->mFont, start + offset, mButtonText, mProfile->mFontColors );
  258. }
  259. }
  260. renderChildControls( offset, updateRect);
  261. }
  262. // Draw the bitmap array's borders according to the button's state.
  263. void GuiIconButtonCtrl::renderBitmapArray(RectI &bounds, S32 state)
  264. {
  265. switch(state)
  266. {
  267. case stateNormal:
  268. if(mProfile->mBorder == -2)
  269. renderSizableBitmapBordersFilled(bounds, 1, mProfile);
  270. else
  271. renderFixedBitmapBordersFilled(bounds, 1, mProfile);
  272. break;
  273. case stateMouseOver:
  274. if(mProfile->mBorder == -2)
  275. renderSizableBitmapBordersFilled(bounds, 2, mProfile);
  276. else
  277. renderFixedBitmapBordersFilled(bounds, 2, mProfile);
  278. break;
  279. case statePressed:
  280. if(mProfile->mBorder == -2)
  281. renderSizableBitmapBordersFilled(bounds, 3, mProfile);
  282. else
  283. renderFixedBitmapBordersFilled(bounds, 3, mProfile);
  284. break;
  285. case stateDisabled:
  286. if(mProfile->mBorder == -2)
  287. renderSizableBitmapBordersFilled(bounds, 4, mProfile);
  288. else
  289. renderFixedBitmapBordersFilled(bounds, 4, mProfile);
  290. break;
  291. }
  292. }