ScrollView.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "BorderImage.h"
  25. #include "InputEvents.h"
  26. #include "ScrollBar.h"
  27. #include "ScrollView.h"
  28. #include "UIEvents.h"
  29. #include "DebugNew.h"
  30. static const float STEP_FACTOR = 300.0f;
  31. ScrollView::ScrollView(const std::string& name) :
  32. UIElement(name),
  33. mViewPosition(IntVector2::sZero),
  34. mViewSize(IntVector2::sZero),
  35. mPageStep(1.0f)
  36. {
  37. mClipChildren = true;
  38. mEnabled = true;
  39. mFocusMode = FM_FOCUSABLE_DEFOCUSABLE;
  40. mHorizontalScrollBar = new ScrollBar();
  41. mHorizontalScrollBar->setAlignment(HA_LEFT, VA_BOTTOM);
  42. mHorizontalScrollBar->setOrientation(O_HORIZONTAL);
  43. mVerticalScrollBar = new ScrollBar();
  44. mVerticalScrollBar->setAlignment(HA_RIGHT, VA_TOP);
  45. mVerticalScrollBar->setOrientation(O_VERTICAL);
  46. mScrollPanel = new BorderImage();
  47. mScrollPanel->setEnabled(true);
  48. mScrollPanel->setClipChildren(true);
  49. addChild(mHorizontalScrollBar);
  50. addChild(mVerticalScrollBar);
  51. addChild(mScrollPanel);
  52. subscribeToEvent(mHorizontalScrollBar, EVENT_SCROLLBARCHANGED, EVENT_HANDLER(ScrollView, handleScrollBarChanged));
  53. subscribeToEvent(mHorizontalScrollBar, EVENT_VISIBLECHANGED, EVENT_HANDLER(ScrollView, handleScrollBarVisibleChanged));
  54. subscribeToEvent(mVerticalScrollBar, EVENT_SCROLLBARCHANGED, EVENT_HANDLER(ScrollView, handleScrollBarChanged));
  55. subscribeToEvent(mVerticalScrollBar, EVENT_VISIBLECHANGED, EVENT_HANDLER(ScrollView, handleScrollBarVisibleChanged));
  56. }
  57. ScrollView::~ScrollView()
  58. {
  59. }
  60. void ScrollView::setStyle(const XMLElement& element, ResourceCache* cache)
  61. {
  62. UIElement::setStyle(element, cache);
  63. if (element.hasChildElement("viewposition"))
  64. setViewPosition(element.getChildElement("viewposition").getIntVector2("value"));
  65. if (element.hasChildElement("scrollstep"))
  66. setScrollStep(element.getChildElement("scrollstep").getFloat("value"));
  67. if (element.hasChildElement("pagestep"))
  68. setScrollStep(element.getChildElement("pagestep").getFloat("value"));
  69. XMLElement horizElem = element.getChildElement("horizontalscrollbar");
  70. if (horizElem)
  71. mHorizontalScrollBar->setStyle(horizElem, cache);
  72. XMLElement vertElem = element.getChildElement("verticalscrollbar");
  73. if (vertElem)
  74. mVerticalScrollBar->setStyle(vertElem, cache);
  75. XMLElement panelElem = element.getChildElement("scrollpanel");
  76. if (panelElem)
  77. mScrollPanel->setStyle(panelElem, cache);
  78. UIElement* root = getRootElement();
  79. if ((root) && (element.hasChildElement("contentelement")))
  80. setContentElement(root->getChild(element.getChildElement("contentelement").getString("name"), true));
  81. // Set the scrollbar orientations again and perform size update now that the style is known
  82. mHorizontalScrollBar->setOrientation(O_HORIZONTAL);
  83. mVerticalScrollBar->setOrientation(O_VERTICAL);
  84. onResize();
  85. }
  86. void ScrollView::onWheel(int delta, int buttons, int qualifiers)
  87. {
  88. if (delta > 0)
  89. mVerticalScrollBar->stepBack();
  90. if (delta < 0)
  91. mVerticalScrollBar->stepForward();
  92. }
  93. void ScrollView::onKey(int key, int buttons, int qualifiers)
  94. {
  95. switch (key)
  96. {
  97. case KEY_LEFT:
  98. if (mHorizontalScrollBar->isVisible())
  99. {
  100. if (qualifiers & QUAL_CTRL)
  101. mHorizontalScrollBar->setValue(0.0f);
  102. else
  103. mHorizontalScrollBar->stepBack();
  104. }
  105. break;
  106. case KEY_RIGHT:
  107. if (mHorizontalScrollBar->isVisible())
  108. {
  109. if (qualifiers & QUAL_CTRL)
  110. mHorizontalScrollBar->setValue(mHorizontalScrollBar->getRange());
  111. else
  112. mHorizontalScrollBar->stepForward();
  113. }
  114. break;
  115. case KEY_UP:
  116. if (mVerticalScrollBar->isVisible())
  117. {
  118. if (qualifiers & QUAL_CTRL)
  119. mVerticalScrollBar->setValue(0.0f);
  120. else
  121. mVerticalScrollBar->stepBack();
  122. }
  123. break;
  124. case KEY_DOWN:
  125. if (mVerticalScrollBar->isVisible())
  126. {
  127. if (qualifiers & QUAL_CTRL)
  128. mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
  129. else
  130. mVerticalScrollBar->stepForward();
  131. }
  132. break;
  133. case KEY_PAGEUP:
  134. if (mVerticalScrollBar->isVisible())
  135. mVerticalScrollBar->changeValue(-mPageStep);
  136. break;
  137. case KEY_PAGEDOWN:
  138. if (mVerticalScrollBar->isVisible())
  139. mVerticalScrollBar->changeValue(mPageStep);
  140. break;
  141. case KEY_HOME:
  142. if (mVerticalScrollBar->isVisible())
  143. mVerticalScrollBar->setValue(0.0f);
  144. break;
  145. case KEY_END:
  146. if (mVerticalScrollBar->isVisible())
  147. mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
  148. break;
  149. }
  150. }
  151. void ScrollView::onResize()
  152. {
  153. IntVector2 panelSize = getSize();
  154. if (mVerticalScrollBar->isVisible())
  155. panelSize.mX -= mVerticalScrollBar->getWidth();
  156. if (mHorizontalScrollBar->isVisible())
  157. panelSize.mY -= mHorizontalScrollBar->getHeight();
  158. mScrollPanel->setSize(panelSize);
  159. mHorizontalScrollBar->setWidth(mScrollPanel->getWidth());
  160. mVerticalScrollBar->setHeight(mScrollPanel->getHeight());
  161. updateViewSize();
  162. }
  163. void ScrollView::setContentElement(UIElement* element)
  164. {
  165. if (element == mContentElement)
  166. return;
  167. if (mContentElement)
  168. {
  169. mScrollPanel->removeChild(mContentElement);
  170. unsubscribeFromEvent(mContentElement, EVENT_RESIZED);
  171. }
  172. mContentElement = element;
  173. if (mContentElement)
  174. {
  175. mScrollPanel->addChild(mContentElement);
  176. subscribeToEvent(mContentElement, EVENT_RESIZED, EVENT_HANDLER(ScrollView, handleElementResized));
  177. }
  178. updateViewSize();
  179. }
  180. void ScrollView::setViewPosition(const IntVector2& position)
  181. {
  182. updateView(position);
  183. updateScrollBars();
  184. }
  185. void ScrollView::setViewPosition(int x, int y)
  186. {
  187. setViewPosition(IntVector2(x, y));
  188. }
  189. void ScrollView::setScrollBarsVisible(bool horizontal, bool vertical)
  190. {
  191. mHorizontalScrollBar->setVisible(horizontal);
  192. mVerticalScrollBar->setVisible(vertical);
  193. }
  194. void ScrollView::setScrollStep(float step)
  195. {
  196. mHorizontalScrollBar->setScrollStep(step);
  197. mVerticalScrollBar->setScrollStep(step);
  198. }
  199. void ScrollView::setPageStep(float step)
  200. {
  201. mPageStep = max(step, 0.0f);
  202. }
  203. bool ScrollView::getHorizontalScrollBarVisible() const
  204. {
  205. return mHorizontalScrollBar->isVisible();
  206. }
  207. bool ScrollView::getVerticalScrollBarVisible() const
  208. {
  209. return mVerticalScrollBar->isVisible();
  210. }
  211. float ScrollView::getScrollStep() const
  212. {
  213. return mHorizontalScrollBar->getScrollStep();
  214. }
  215. void ScrollView::updateViewSize()
  216. {
  217. IntVector2 size(IntVector2::sZero);
  218. if (mContentElement)
  219. size = mContentElement->getSize();
  220. mViewSize.mX = max(size.mX, mScrollPanel->getWidth());
  221. mViewSize.mY = max(size.mY, mScrollPanel->getHeight());
  222. updateView(mViewPosition);
  223. updateScrollBars();
  224. }
  225. void ScrollView::updateScrollBars()
  226. {
  227. mIgnoreEvents = true;
  228. const IntVector2& size = mScrollPanel->getSize();
  229. if ((mHorizontalScrollBar) && (size.mX > 0) && (mViewSize.mX > 0))
  230. {
  231. mHorizontalScrollBar->setRange((float)mViewSize.mX / (float)size.mX - 1.0f);
  232. mHorizontalScrollBar->setValue((float)mViewPosition.mX / (float)size.mX);
  233. mHorizontalScrollBar->setStepFactor(STEP_FACTOR / (float)size.mX);
  234. }
  235. if ((mVerticalScrollBar) && (size.mY > 0) && (mViewSize.mY > 0))
  236. {
  237. mVerticalScrollBar->setRange((float)mViewSize.mY / (float)size.mY - 1.0f);
  238. mVerticalScrollBar->setValue((float)mViewPosition.mY / (float)size.mY);
  239. mVerticalScrollBar->setStepFactor(STEP_FACTOR / (float)size.mY);
  240. }
  241. mIgnoreEvents = false;
  242. }
  243. void ScrollView::updateView(const IntVector2& position)
  244. {
  245. IntVector2 oldPosition = mViewPosition;
  246. mViewPosition.mX = clamp(position.mX, 0, mViewSize.mX - mScrollPanel->getWidth());
  247. mViewPosition.mY = clamp(position.mY, 0, mViewSize.mY - mScrollPanel->getHeight());
  248. mScrollPanel->setChildOffset(-mViewPosition);
  249. if (mViewPosition != oldPosition)
  250. {
  251. using namespace ViewChanged;
  252. VariantMap eventData;
  253. eventData[P_ELEMENT] = (void*)this;
  254. eventData[P_X] = mViewPosition.mX;
  255. eventData[P_Y] = mViewPosition.mY;
  256. sendEvent(EVENT_VIEWCHANGED, eventData);
  257. }
  258. }
  259. void ScrollView::handleScrollBarChanged(StringHash eventType, VariantMap& eventData)
  260. {
  261. if (!mIgnoreEvents)
  262. {
  263. updateView(IntVector2(
  264. (int)(mHorizontalScrollBar->getValue() * (float)mScrollPanel->getWidth()),
  265. (int)(mVerticalScrollBar->getValue() * (float)mScrollPanel->getHeight())
  266. ));
  267. }
  268. }
  269. void ScrollView::handleScrollBarVisibleChanged(StringHash eventType, VariantMap& eventData)
  270. {
  271. // Need to recalculate panel size when scrollbar visibility changes
  272. onResize();
  273. }
  274. void ScrollView::handleElementResized(StringHash eventType, VariantMap& eventData)
  275. {
  276. updateViewSize();
  277. }