BsGUIButton.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #include "BsGUIButton.h"
  2. #include "BsImageSprite.h"
  3. #include "BsGUIWidget.h"
  4. #include "BsGUISkin.h"
  5. #include "BsSpriteTexture.h"
  6. #include "BsTextSprite.h"
  7. #include "BsGUILayoutOptions.h"
  8. #include "BsGUIMouseEvent.h"
  9. #include "BsGUIHelper.h"
  10. #include "CmTexture.h"
  11. using namespace CamelotFramework;
  12. namespace BansheeEngine
  13. {
  14. const String& GUIButton::getGUITypeName()
  15. {
  16. static String name = "Button";
  17. return name;
  18. }
  19. GUIButton::GUIButton(GUIWidget& parent, const GUIElementStyle* style, const GUIContent& content, const GUILayoutOptions& layoutOptions)
  20. :GUIElement(parent, style, layoutOptions), mContent(content), mContentImageSprite(nullptr)
  21. {
  22. mImageSprite = cm_new<ImageSprite, PoolAlloc>();
  23. mTextSprite = cm_new<TextSprite, PoolAlloc>();
  24. SpriteTexturePtr contentTex = content.getImage();
  25. if(contentTex != nullptr)
  26. mContentImageSprite = cm_new<ImageSprite, PoolAlloc>();
  27. mImageDesc.texture = mStyle->normal.texture;
  28. if(mImageDesc.texture != nullptr)
  29. {
  30. mImageDesc.width = mImageDesc.texture->getTexture()->getWidth();
  31. mImageDesc.height = mImageDesc.texture->getTexture()->getHeight();
  32. }
  33. mImageDesc.borderLeft = mStyle->border.left;
  34. mImageDesc.borderRight = mStyle->border.right;
  35. mImageDesc.borderTop = mStyle->border.top;
  36. mImageDesc.borderBottom = mStyle->border.bottom;
  37. }
  38. GUIButton::~GUIButton()
  39. {
  40. cm_delete<PoolAlloc>(mTextSprite);
  41. cm_delete<PoolAlloc>(mImageSprite);
  42. if(mContentImageSprite != nullptr)
  43. cm_delete<PoolAlloc>(mContentImageSprite);
  44. }
  45. GUIButton* GUIButton::create(GUIWidget& parent, const WString& text, const GUIElementStyle* style)
  46. {
  47. return create(parent, GUIContent(text), style);
  48. }
  49. GUIButton* GUIButton::create(GUIWidget& parent, const WString& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
  50. {
  51. return create(parent, GUIContent(text), layoutOptions, style);
  52. }
  53. GUIButton* GUIButton::create(GUIWidget& parent, const GUIContent& content, const GUIElementStyle* style)
  54. {
  55. if(style == nullptr)
  56. {
  57. const GUISkin& skin = parent.getSkin();
  58. style = skin.getStyle(getGUITypeName());
  59. }
  60. return new (cm_alloc<GUIButton, PoolAlloc>()) GUIButton(parent, style, content, getDefaultLayoutOptions(style));
  61. }
  62. GUIButton* GUIButton::create(GUIWidget& parent, const GUIContent& content, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
  63. {
  64. if(style == nullptr)
  65. {
  66. const GUISkin& skin = parent.getSkin();
  67. style = skin.getStyle(getGUITypeName());
  68. }
  69. return new (cm_alloc<GUIButton, PoolAlloc>()) GUIButton(parent, style, content, layoutOptions);
  70. }
  71. void GUIButton::setContent(const GUIContent& content)
  72. {
  73. mContent = content;
  74. markContentAsDirty();
  75. }
  76. UINT32 GUIButton::getNumRenderElements() const
  77. {
  78. UINT32 numElements = mImageSprite->getNumRenderElements();
  79. numElements += mTextSprite->getNumRenderElements();
  80. if(mContentImageSprite != nullptr)
  81. numElements += mContentImageSprite->getNumRenderElements();
  82. return numElements;
  83. }
  84. const HMaterial& GUIButton::getMaterial(UINT32 renderElementIdx) const
  85. {
  86. UINT32 textSpriteIdx = mImageSprite->getNumRenderElements();
  87. UINT32 contentImgSpriteIdx = textSpriteIdx + mTextSprite->getNumRenderElements();
  88. if(renderElementIdx >= contentImgSpriteIdx)
  89. return mContentImageSprite->getMaterial(contentImgSpriteIdx - renderElementIdx);
  90. else if(renderElementIdx >= textSpriteIdx)
  91. return mTextSprite->getMaterial(textSpriteIdx - renderElementIdx);
  92. else
  93. return mImageSprite->getMaterial(renderElementIdx);
  94. }
  95. UINT32 GUIButton::getNumQuads(UINT32 renderElementIdx) const
  96. {
  97. UINT32 textSpriteIdx = mImageSprite->getNumRenderElements();
  98. UINT32 contentImgSpriteIdx = textSpriteIdx + mTextSprite->getNumRenderElements();
  99. UINT32 numQuads = 0;
  100. if(renderElementIdx >= contentImgSpriteIdx)
  101. numQuads = mContentImageSprite->getNumQuads(contentImgSpriteIdx - renderElementIdx);
  102. else if(renderElementIdx >= textSpriteIdx)
  103. numQuads = mTextSprite->getNumQuads(textSpriteIdx - renderElementIdx);
  104. else
  105. numQuads = mImageSprite->getNumQuads(renderElementIdx);
  106. return numQuads;
  107. }
  108. void GUIButton::updateRenderElementsInternal()
  109. {
  110. mImageDesc.width = mWidth;
  111. mImageDesc.height = mHeight;
  112. mImageSprite->update(mImageDesc);
  113. mTextSprite->update(getTextDesc());
  114. if(mContentImageSprite != nullptr)
  115. {
  116. IMAGE_SPRITE_DESC contentImgDesc;
  117. contentImgDesc.texture = mContent.getImage();
  118. contentImgDesc.width = mContent.getImage()->getTexture()->getWidth();
  119. contentImgDesc.height = mContent.getImage()->getTexture()->getHeight();
  120. mContentImageSprite->update(contentImgDesc);
  121. }
  122. GUIElement::updateRenderElementsInternal();
  123. }
  124. void GUIButton::updateClippedBounds()
  125. {
  126. mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
  127. }
  128. Int2 GUIButton::_getOptimalSize() const
  129. {
  130. UINT32 imageWidth = 0;
  131. UINT32 imageHeight = 0;
  132. if(mImageDesc.texture != nullptr)
  133. {
  134. imageWidth = mImageDesc.texture->getTexture()->getWidth();
  135. imageHeight = mImageDesc.texture->getTexture()->getHeight();
  136. }
  137. Int2 contentSize = GUIHelper::calcOptimalContentsSize(mContent, *mStyle, _getLayoutOptions());
  138. UINT32 contentWidth = std::max(imageWidth, (UINT32)contentSize.x);
  139. UINT32 contentHeight = std::max(imageHeight, (UINT32)contentSize.y);
  140. return Int2(contentWidth, contentHeight);
  141. }
  142. UINT32 GUIButton::_getRenderElementDepth(UINT32 renderElementIdx) const
  143. {
  144. UINT32 textSpriteIdx = mImageSprite->getNumRenderElements();
  145. UINT32 contentImgSpriteIdx = textSpriteIdx + mTextSprite->getNumRenderElements();
  146. if(renderElementIdx >= contentImgSpriteIdx)
  147. return _getDepth();
  148. else if(renderElementIdx >= textSpriteIdx)
  149. return _getDepth();
  150. else
  151. return _getDepth() + 1;
  152. }
  153. void GUIButton::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads,
  154. UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
  155. {
  156. UINT32 textSpriteIdx = mImageSprite->getNumRenderElements();
  157. UINT32 contentImgSpriteIdx = textSpriteIdx + mTextSprite->getNumRenderElements();
  158. if(renderElementIdx < textSpriteIdx)
  159. {
  160. mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads,
  161. vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
  162. return;
  163. }
  164. Rect contentBounds = getContentBounds();
  165. Rect contentClipRect = getContentClipRect();
  166. Rect textBounds = mTextSprite->getBounds(Int2(), Rect());
  167. Int2 textOffset;
  168. Rect textClipRect;
  169. Int2 imageOffset;
  170. Rect imageClipRect;
  171. if(mContentImageSprite != nullptr)
  172. {
  173. Rect imageBounds = mContentImageSprite->getBounds(Int2(), Rect());
  174. UINT32 freeWidth = (UINT32)std::max(0, contentBounds.width - textBounds.width - imageBounds.width);
  175. INT32 imageXOffset = (INT32)(freeWidth / 2);
  176. if(mStyle->imagePosition == GUIImagePosition::Right)
  177. {
  178. INT32 imageReservedWidth = std::max(0, contentBounds.width - textBounds.width);
  179. textOffset = Int2(contentBounds.x, contentBounds.y);
  180. textClipRect = contentClipRect;
  181. textClipRect.width = std::min(contentBounds.width - imageReservedWidth, textClipRect.width);
  182. imageOffset = Int2(contentBounds.x + textBounds.width + imageXOffset, contentBounds.y);
  183. imageClipRect = contentClipRect;
  184. imageClipRect.x -= textBounds.width + imageXOffset;
  185. }
  186. else
  187. {
  188. INT32 imageReservedWidth = imageBounds.width + imageXOffset;
  189. imageOffset = Int2(contentBounds.x + imageXOffset, contentBounds.y);
  190. imageClipRect = contentClipRect;
  191. imageClipRect.x -= imageXOffset;
  192. imageClipRect.width = std::min(imageReservedWidth, imageClipRect.width);
  193. textOffset = Int2(contentBounds.x + imageReservedWidth, contentBounds.y);
  194. textClipRect = contentClipRect;
  195. textClipRect.x -= imageReservedWidth;
  196. }
  197. INT32 imageYOffset = (contentBounds.height - imageBounds.height) / 2;
  198. imageClipRect.y -= imageYOffset;
  199. imageOffset.y += imageYOffset;
  200. }
  201. else
  202. {
  203. textOffset = Int2(contentBounds.x, contentBounds.y);
  204. textClipRect = contentClipRect;
  205. }
  206. if(renderElementIdx >= contentImgSpriteIdx)
  207. {
  208. mContentImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads,
  209. vertexStride, indexStride, contentImgSpriteIdx - renderElementIdx, imageOffset, imageClipRect);
  210. }
  211. else
  212. {
  213. mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads,
  214. vertexStride, indexStride, textSpriteIdx - renderElementIdx, textOffset, textClipRect);
  215. }
  216. }
  217. bool GUIButton::mouseEvent(const GUIMouseEvent& ev)
  218. {
  219. if(ev.getType() == GUIMouseEventType::MouseOver)
  220. {
  221. mImageDesc.texture = mStyle->hover.texture;
  222. markContentAsDirty();
  223. if(!onHover.empty())
  224. onHover();
  225. return true;
  226. }
  227. else if(ev.getType() == GUIMouseEventType::MouseOut)
  228. {
  229. mImageDesc.texture = mStyle->normal.texture;
  230. markContentAsDirty();
  231. if(!onOut.empty())
  232. onOut();
  233. return true;
  234. }
  235. else if(ev.getType() == GUIMouseEventType::MouseDown)
  236. {
  237. mImageDesc.texture = mStyle->active.texture;
  238. markContentAsDirty();
  239. return true;
  240. }
  241. else if(ev.getType() == GUIMouseEventType::MouseUp)
  242. {
  243. mImageDesc.texture = mStyle->hover.texture;
  244. markContentAsDirty();
  245. if(!onClick.empty())
  246. onClick();
  247. return true;
  248. }
  249. return false;
  250. }
  251. TEXT_SPRITE_DESC GUIButton::getTextDesc() const
  252. {
  253. TEXT_SPRITE_DESC textDesc;
  254. textDesc.text = mContent.getText();
  255. textDesc.font = mStyle->font;
  256. textDesc.fontSize = mStyle->fontSize;
  257. Rect textBounds = getContentBounds();
  258. textDesc.width = textBounds.width;
  259. textDesc.height = textBounds.height;
  260. textDesc.horzAlign = mStyle->textHorzAlign;
  261. textDesc.vertAlign = mStyle->textVertAlign;
  262. return textDesc;
  263. }
  264. }