ScrollView.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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. ScrollView::ScrollView(const std::string& name) :
  31. UIElement(name),
  32. mViewPosition(IntVector2::sZero),
  33. mViewSize(IntVector2::sZero),
  34. mPageStep(1.0f)
  35. {
  36. mClipChildren = true;
  37. mEnabled = true;
  38. mFocusMode = FM_FOCUSABLE_DEFOCUSABLE;
  39. mHorizontalScrollBar = new ScrollBar();
  40. mHorizontalScrollBar->setAlignment(HA_LEFT, VA_BOTTOM);
  41. mHorizontalScrollBar->setOrientation(O_HORIZONTAL);
  42. mVerticalScrollBar = new ScrollBar();
  43. mVerticalScrollBar->setAlignment(HA_RIGHT, VA_TOP);
  44. mVerticalScrollBar->setOrientation(O_VERTICAL);
  45. mScrollPanel = new BorderImage();
  46. mScrollPanel->setEnabled(true);
  47. mScrollPanel->setClipChildren(true);
  48. addChild(mHorizontalScrollBar);
  49. addChild(mVerticalScrollBar);
  50. addChild(mScrollPanel);
  51. subscribeToEvent(mHorizontalScrollBar, EVENT_SCROLLBARCHANGED, EVENT_HANDLER(ScrollView, handleScrollBarChanged));
  52. subscribeToEvent(mHorizontalScrollBar, EVENT_VISIBLECHANGED, EVENT_HANDLER(ScrollView, handleScrollBarVisibleChanged));
  53. subscribeToEvent(mVerticalScrollBar, EVENT_SCROLLBARCHANGED, EVENT_HANDLER(ScrollView, handleScrollBarChanged));
  54. subscribeToEvent(mVerticalScrollBar, EVENT_VISIBLECHANGED, EVENT_HANDLER(ScrollView, handleScrollBarVisibleChanged));
  55. }
  56. ScrollView::~ScrollView()
  57. {
  58. }
  59. void ScrollView::setStyle(const XMLElement& element, ResourceCache* cache)
  60. {
  61. UIElement::setStyle(element, cache);
  62. if (element.hasChildElement("viewposition"))
  63. setViewPosition(element.getChildElement("viewposition").getIntVector2("value"));
  64. if (element.hasChildElement("scrollstep"))
  65. setScrollStep(element.getChildElement("scrollstep").getFloat("value"));
  66. if (element.hasChildElement("pagestep"))
  67. setScrollStep(element.getChildElement("pagestep").getFloat("value"));
  68. if (element.hasChildElement("normalizescrollstep"))
  69. setNormalizeScrollStep(element.getChildElement("normalizescrollstep").getBool("enable"));
  70. XMLElement horizElem = element.getChildElement("horizontalscrollbar");
  71. if (horizElem)
  72. mHorizontalScrollBar->setStyle(horizElem, cache);
  73. XMLElement vertElem = element.getChildElement("verticalscrollbar");
  74. if (vertElem)
  75. mVerticalScrollBar->setStyle(vertElem, cache);
  76. XMLElement panelElem = element.getChildElement("scrollpanel");
  77. if (panelElem)
  78. mScrollPanel->setStyle(panelElem, cache);
  79. UIElement* root = getRootElement();
  80. if ((root) && (element.hasChildElement("contentelement")))
  81. setElement(root->getChild(element.getChildElement("contentelement").getString("name"), true));
  82. // Set the scrollbar orientations again and perform size update now that the style is known
  83. mHorizontalScrollBar->setOrientation(O_HORIZONTAL);
  84. mVerticalScrollBar->setOrientation(O_VERTICAL);
  85. onResize();
  86. }
  87. void ScrollView::onKey(int key, int buttons, int qualifiers)
  88. {
  89. switch (key)
  90. {
  91. case KEY_LEFT:
  92. if (mHorizontalScrollBar)
  93. {
  94. if (qualifiers & QUAL_CTRL)
  95. mHorizontalScrollBar->setValue(0.0f);
  96. else
  97. mHorizontalScrollBar->stepBack();
  98. }
  99. break;
  100. case KEY_RIGHT:
  101. if (mHorizontalScrollBar)
  102. {
  103. if (qualifiers & QUAL_CTRL)
  104. mHorizontalScrollBar->setValue(mHorizontalScrollBar->getRange());
  105. else
  106. mHorizontalScrollBar->stepForward();
  107. }
  108. break;
  109. case KEY_UP:
  110. if (mVerticalScrollBar)
  111. {
  112. if (qualifiers & QUAL_CTRL)
  113. mVerticalScrollBar->setValue(0.0f);
  114. else
  115. mVerticalScrollBar->stepBack();
  116. }
  117. break;
  118. case KEY_DOWN:
  119. if (mVerticalScrollBar)
  120. {
  121. if (qualifiers & QUAL_CTRL)
  122. mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
  123. else
  124. mVerticalScrollBar->stepForward();
  125. }
  126. break;
  127. case KEY_PAGEUP:
  128. if (mVerticalScrollBar)
  129. mVerticalScrollBar->changeValue(-mPageStep);
  130. break;
  131. case KEY_PAGEDOWN:
  132. if (mVerticalScrollBar)
  133. mVerticalScrollBar->changeValue(mPageStep);
  134. break;
  135. case KEY_HOME:
  136. if (mVerticalScrollBar)
  137. mVerticalScrollBar->setValue(0.0f);
  138. break;
  139. case KEY_END:
  140. if (mVerticalScrollBar)
  141. mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
  142. break;
  143. }
  144. }
  145. void ScrollView::onResize()
  146. {
  147. IntVector2 panelSize = getSize();
  148. if (mVerticalScrollBar->isVisible())
  149. panelSize.mX -= mVerticalScrollBar->getWidth();
  150. if (mHorizontalScrollBar->isVisible())
  151. panelSize.mY -= mHorizontalScrollBar->getHeight();
  152. mScrollPanel->setSize(panelSize);
  153. mHorizontalScrollBar->setWidth(mScrollPanel->getWidth());
  154. mVerticalScrollBar->setHeight(mScrollPanel->getHeight());
  155. updateViewSize();
  156. }
  157. void ScrollView::setElement(UIElement* element)
  158. {
  159. if (element == mElement)
  160. return;
  161. if (mElement)
  162. {
  163. mScrollPanel->removeChild(mElement);
  164. unsubscribeFromEvent(mElement, EVENT_RESIZED);
  165. }
  166. mElement = element;
  167. if (mElement)
  168. {
  169. mScrollPanel->addChild(mElement);
  170. subscribeToEvent(mElement, EVENT_RESIZED, EVENT_HANDLER(ScrollView, handleElementResized));
  171. }
  172. updateViewSize();
  173. }
  174. void ScrollView::setViewPosition(const IntVector2& position)
  175. {
  176. updateView(position);
  177. updateScrollBars();
  178. }
  179. void ScrollView::setViewPosition(int x, int y)
  180. {
  181. setViewPosition(IntVector2(x, y));
  182. }
  183. void ScrollView::setScrollBarsVisible(bool horizontal, bool vertical)
  184. {
  185. mHorizontalScrollBar->setVisible(horizontal);
  186. mVerticalScrollBar->setVisible(vertical);
  187. }
  188. void ScrollView::setScrollStep(float step)
  189. {
  190. mHorizontalScrollBar->setScrollStep(step);
  191. mVerticalScrollBar->setScrollStep(step);
  192. }
  193. void ScrollView::setPageStep(float step)
  194. {
  195. mPageStep = max(step, 0.0f);
  196. }
  197. void ScrollView::setNormalizeScrollStep(bool enable)
  198. {
  199. mHorizontalScrollBar->setNormalizeScrollStep(enable);
  200. mVerticalScrollBar->setNormalizeScrollStep(enable);
  201. }
  202. bool ScrollView::getHorizontalScrollBarVisible() const
  203. {
  204. return mHorizontalScrollBar->isVisible();
  205. }
  206. bool ScrollView::getVerticalScrollBarVisible() const
  207. {
  208. return mVerticalScrollBar->isVisible();
  209. }
  210. float ScrollView::getScrollStep() const
  211. {
  212. return mHorizontalScrollBar->getScrollStep();
  213. }
  214. bool ScrollView::getNormalizeScrollStep() const
  215. {
  216. return mHorizontalScrollBar->getNormalizeScrollStep();
  217. }
  218. void ScrollView::updateViewSize()
  219. {
  220. IntVector2 size(IntVector2::sZero);
  221. if (mElement)
  222. size = mElement->getSize();
  223. mViewSize.mX = max(size.mX, mScrollPanel->getWidth());
  224. mViewSize.mY = max(size.mY, mScrollPanel->getHeight());
  225. updateView(mViewPosition);
  226. updateScrollBars();
  227. }
  228. void ScrollView::updateScrollBars()
  229. {
  230. mIgnoreEvents = true;
  231. const IntVector2& size = mScrollPanel->getSize();
  232. if ((mHorizontalScrollBar) && (size.mX > 0) && (mViewSize.mX > 0))
  233. {
  234. mHorizontalScrollBar->setRange((float)mViewSize.mX / (float)size.mX - 1.0f);
  235. mHorizontalScrollBar->setValue((float)mViewPosition.mX / (float)size.mX);
  236. }
  237. if ((mVerticalScrollBar) && (size.mY > 0) && (mViewSize.mY > 0))
  238. {
  239. mVerticalScrollBar->setRange((float)mViewSize.mY / (float)size.mY - 1.0f);
  240. mVerticalScrollBar->setValue((float)mViewPosition.mY / (float)size.mY);
  241. }
  242. mIgnoreEvents = false;
  243. }
  244. void ScrollView::updateView(const IntVector2& position)
  245. {
  246. IntVector2 oldPosition = mViewPosition;
  247. mViewPosition.mX = clamp(position.mX, 0, mViewSize.mX - mScrollPanel->getWidth());
  248. mViewPosition.mY = clamp(position.mY, 0, mViewSize.mY - mScrollPanel->getHeight());
  249. mScrollPanel->setChildOffset(-mViewPosition);
  250. if (mViewPosition != oldPosition)
  251. {
  252. using namespace ViewChanged;
  253. VariantMap eventData;
  254. eventData[P_ELEMENT] = (void*)this;
  255. eventData[P_X] = mViewPosition.mX;
  256. eventData[P_Y] = mViewPosition.mY;
  257. sendEvent(EVENT_VIEWCHANGED, eventData);
  258. }
  259. }
  260. void ScrollView::handleScrollBarChanged(StringHash eventType, VariantMap& eventData)
  261. {
  262. if (!mIgnoreEvents)
  263. {
  264. updateView(IntVector2(
  265. (int)(mHorizontalScrollBar->getValue() * (float)mScrollPanel->getWidth()),
  266. (int)(mVerticalScrollBar->getValue() * (float)mScrollPanel->getHeight())
  267. ));
  268. }
  269. }
  270. void ScrollView::handleScrollBarVisibleChanged(StringHash eventType, VariantMap& eventData)
  271. {
  272. // Need to recalculate panel size when scrollbar visibility changes
  273. onResize();
  274. }
  275. void ScrollView::handleElementResized(StringHash eventType, VariantMap& eventData)
  276. {
  277. updateViewSize();
  278. }