BsGUIScrollBarHandle.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #include "BsGUIScrollBarHandle.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 "CmDebug.h"
  10. #include "CmTexture.h"
  11. using namespace CamelotFramework;
  12. namespace BansheeEngine
  13. {
  14. const String& GUIScrollBarHandle::getGUITypeName()
  15. {
  16. static String name = "ScrollBarHandle";
  17. return name;
  18. }
  19. GUIScrollBarHandle::GUIScrollBarHandle(GUIWidget& parent, bool horizontal, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
  20. :GUIElement(parent, style, layoutOptions), mHorizontal(horizontal), mHandleSize(2), mMouseOverHandle(false), mHandlePos(0), mDragStartPos(0),
  21. mHandleDragged(false)
  22. {
  23. mImageSprite = cm_new<ImageSprite, PoolAlloc>();
  24. mCurTexture = style->normal.texture;
  25. }
  26. GUIScrollBarHandle::~GUIScrollBarHandle()
  27. {
  28. cm_delete<PoolAlloc>(mImageSprite);
  29. }
  30. GUIScrollBarHandle* GUIScrollBarHandle::create(GUIWidget& parent, bool horizontal, const GUIElementStyle* style)
  31. {
  32. if(style == nullptr)
  33. {
  34. const GUISkin* skin = parent.getSkin();
  35. style = skin->getStyle(getGUITypeName());
  36. }
  37. return new (cm_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(parent, horizontal, style, getDefaultLayoutOptions(style));
  38. }
  39. GUIScrollBarHandle* GUIScrollBarHandle::create(GUIWidget& parent, bool horizontal, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
  40. {
  41. if(style == nullptr)
  42. {
  43. const GUISkin* skin = parent.getSkin();
  44. style = skin->getStyle(getGUITypeName());
  45. }
  46. return new (cm_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(parent, horizontal, style, layoutOptions);
  47. }
  48. void GUIScrollBarHandle::setHandleSize(CM::UINT32 size)
  49. {
  50. mHandleSize = std::min(getMaxSize(), size);
  51. markContentAsDirty();
  52. }
  53. void GUIScrollBarHandle::setHandlePos(float pct)
  54. {
  55. pct = Math::Clamp01(pct);
  56. UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
  57. mHandlePos = pct * maxScrollAmount;
  58. markContentAsDirty();
  59. }
  60. float GUIScrollBarHandle::getHandlePos() const
  61. {
  62. UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
  63. return mHandlePos / maxScrollAmount;
  64. }
  65. UINT32 GUIScrollBarHandle::getScrollableSize() const
  66. {
  67. return getMaxSize() - mHandleSize;
  68. }
  69. UINT32 GUIScrollBarHandle::getNumRenderElements() const
  70. {
  71. return mImageSprite->getNumRenderElements();
  72. }
  73. const HMaterial& GUIScrollBarHandle::getMaterial(UINT32 renderElementIdx) const
  74. {
  75. return mImageSprite->getMaterial(renderElementIdx);
  76. }
  77. UINT32 GUIScrollBarHandle::getNumQuads(UINT32 renderElementIdx) const
  78. {
  79. return mImageSprite->getNumQuads(renderElementIdx);
  80. }
  81. void GUIScrollBarHandle::updateRenderElementsInternal()
  82. {
  83. IMAGE_SPRITE_DESC desc;
  84. desc.texture = mCurTexture;
  85. if(mHorizontal)
  86. {
  87. desc.width = mHandleSize;
  88. desc.height = mHeight;
  89. }
  90. else
  91. {
  92. desc.width = mWidth;
  93. desc.height = mHandleSize;
  94. }
  95. mImageSprite->update(desc);
  96. GUIElement::updateRenderElementsInternal();
  97. }
  98. void GUIScrollBarHandle::updateBounds()
  99. {
  100. mBounds = Rect(mOffset.x, mOffset.y, mWidth, mHeight);
  101. Rect localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
  102. mBounds.clip(localClipRect);
  103. }
  104. UINT32 GUIScrollBarHandle::_getOptimalWidth() const
  105. {
  106. if(mCurTexture != nullptr)
  107. {
  108. return mCurTexture->getTexture()->getWidth();
  109. }
  110. return 0;
  111. }
  112. UINT32 GUIScrollBarHandle::_getOptimalHeight() const
  113. {
  114. if(mCurTexture != nullptr)
  115. {
  116. return mCurTexture->getTexture()->getHeight();
  117. }
  118. return 0;
  119. }
  120. void GUIScrollBarHandle::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads,
  121. UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
  122. {
  123. Int2 offset = mOffset;
  124. if(mHorizontal)
  125. offset.x += Math::FloorToInt(mHandlePos);
  126. else
  127. offset.y += Math::FloorToInt(mHandlePos);
  128. Rect clipRect = mClipRect;
  129. if(mHorizontal)
  130. clipRect.x -= Math::FloorToInt(mHandlePos);
  131. else
  132. clipRect.y -= Math::FloorToInt(mHandlePos);
  133. mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads,
  134. vertexStride, indexStride, renderElementIdx, offset, clipRect);
  135. }
  136. bool GUIScrollBarHandle::mouseEvent(const GUIMouseEvent& ev)
  137. {
  138. if(ev.getType() == GUIMouseEventType::MouseMove)
  139. {
  140. if(mMouseOverHandle)
  141. {
  142. if(!isOnHandle(ev.getPosition()))
  143. {
  144. mMouseOverHandle = false;
  145. mCurTexture = mStyle->normal.texture;
  146. markContentAsDirty();
  147. return true;
  148. }
  149. }
  150. else
  151. {
  152. if(isOnHandle(ev.getPosition()))
  153. {
  154. mMouseOverHandle = true;
  155. mCurTexture = mStyle->hover.texture;
  156. markContentAsDirty();
  157. return true;
  158. }
  159. }
  160. }
  161. if(ev.getType() == GUIMouseEventType::MouseDown && mMouseOverHandle)
  162. {
  163. mCurTexture = mStyle->active.texture;
  164. markContentAsDirty();
  165. if(mHorizontal)
  166. {
  167. INT32 left = (INT32)mOffset.x + Math::FloorToInt(mHandlePos);
  168. mDragStartPos = ev.getPosition().x - left;
  169. }
  170. else
  171. {
  172. INT32 top = (INT32)mOffset.y + Math::FloorToInt(mHandlePos);
  173. mDragStartPos = ev.getPosition().y - top;
  174. }
  175. mHandleDragged = true;
  176. return true;
  177. }
  178. if(ev.getType() == GUIMouseEventType::MouseDrag && mHandleDragged)
  179. {
  180. if(mHorizontal)
  181. {
  182. mHandlePos = (float)(ev.getPosition().x - mDragStartPos - mOffset.x);
  183. }
  184. else
  185. {
  186. mHandlePos = float(ev.getPosition().y - mDragStartPos - mOffset.y);
  187. }
  188. float maxScrollAmount = (float)getMaxSize() - mHandleSize;
  189. mHandlePos = Math::Clamp(mHandlePos, 0.0f, maxScrollAmount);
  190. if(!onHandleMoved.empty())
  191. {
  192. float pct = mHandlePos / maxScrollAmount;
  193. onHandleMoved(pct);
  194. }
  195. markContentAsDirty();
  196. return true;
  197. }
  198. if(ev.getType() == GUIMouseEventType::MouseOut && !mHandleDragged)
  199. {
  200. mCurTexture = mStyle->normal.texture;
  201. markContentAsDirty();
  202. return true;
  203. }
  204. if(ev.getType() == GUIMouseEventType::MouseUp)
  205. {
  206. if(mMouseOverHandle)
  207. mCurTexture = mStyle->hover.texture;
  208. else
  209. mCurTexture = mStyle->normal.texture;
  210. // If we clicked above or below the scroll handle, scroll by one page
  211. INT32 handleOffset = 0;
  212. if(mHorizontal)
  213. {
  214. INT32 handleLeft = (INT32)mOffset.x + Math::FloorToInt(mHandlePos);
  215. INT32 handleRight = handleLeft + mHandleSize;
  216. if(ev.getPosition().x < handleLeft)
  217. handleOffset -= mHandleSize;
  218. else if(ev.getPosition().x > handleRight)
  219. handleOffset += mHandleSize;
  220. }
  221. else
  222. {
  223. INT32 handleTop = (INT32)mOffset.y + Math::FloorToInt(mHandlePos);
  224. INT32 handleBottom = handleTop + mHandleSize;
  225. if(ev.getPosition().y < handleTop)
  226. handleOffset -= mHandleSize;
  227. else if(ev.getPosition().y > handleBottom)
  228. handleOffset += mHandleSize;
  229. }
  230. mHandlePos += handleOffset;
  231. float maxScrollAmount = (float)getMaxSize() - mHandleSize;
  232. mHandlePos = Math::Clamp(mHandlePos, 0.0f, maxScrollAmount);
  233. if(!onHandleMoved.empty())
  234. {
  235. float pct = (float)mHandlePos / maxScrollAmount;
  236. onHandleMoved(pct);
  237. }
  238. markContentAsDirty();
  239. return true;
  240. }
  241. if(ev.getType() == GUIMouseEventType::MouseDragEnd)
  242. {
  243. mHandleDragged = false;
  244. if(mMouseOverHandle)
  245. mCurTexture = mStyle->hover.texture;
  246. else
  247. mCurTexture = mStyle->normal.texture;
  248. markContentAsDirty();
  249. return true;
  250. }
  251. return false;
  252. }
  253. bool GUIScrollBarHandle::isOnHandle(const CM::Int2& pos) const
  254. {
  255. if(mHorizontal)
  256. {
  257. INT32 left = (INT32)mOffset.x + Math::FloorToInt(mHandlePos);
  258. INT32 right = left + mHandleSize;
  259. if(pos.x >= left && pos.x < right)
  260. return true;
  261. }
  262. else
  263. {
  264. INT32 top = (INT32)mOffset.y + Math::FloorToInt(mHandlePos);
  265. INT32 bottom = top + mHandleSize;
  266. if(pos.y >= top && pos.y < bottom)
  267. return true;
  268. }
  269. return false;
  270. }
  271. UINT32 GUIScrollBarHandle::getMaxSize() const
  272. {
  273. UINT32 maxSize = mHeight;
  274. if(mHorizontal)
  275. maxSize = mWidth;
  276. return maxSize;
  277. }
  278. }