ScrollView.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. setContentElement(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::onWheel(int delta, int buttons, int qualifiers)
  88. {
  89. if (delta > 0)
  90. mVerticalScrollBar->stepBack();
  91. if (delta < 0)
  92. mVerticalScrollBar->stepForward();
  93. }
  94. void ScrollView::onKey(int key, int buttons, int qualifiers)
  95. {
  96. switch (key)
  97. {
  98. case KEY_LEFT:
  99. if (mHorizontalScrollBar->isVisible())
  100. {
  101. if (qualifiers & QUAL_CTRL)
  102. mHorizontalScrollBar->setValue(0.0f);
  103. else
  104. mHorizontalScrollBar->stepBack();
  105. }
  106. break;
  107. case KEY_RIGHT:
  108. if (mHorizontalScrollBar->isVisible())
  109. {
  110. if (qualifiers & QUAL_CTRL)
  111. mHorizontalScrollBar->setValue(mHorizontalScrollBar->getRange());
  112. else
  113. mHorizontalScrollBar->stepForward();
  114. }
  115. break;
  116. case KEY_UP:
  117. if (mVerticalScrollBar->isVisible())
  118. {
  119. if (qualifiers & QUAL_CTRL)
  120. mVerticalScrollBar->setValue(0.0f);
  121. else
  122. mVerticalScrollBar->stepBack();
  123. }
  124. break;
  125. case KEY_DOWN:
  126. if (mVerticalScrollBar->isVisible())
  127. {
  128. if (qualifiers & QUAL_CTRL)
  129. mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
  130. else
  131. mVerticalScrollBar->stepForward();
  132. }
  133. break;
  134. case KEY_PAGEUP:
  135. if (mVerticalScrollBar->isVisible())
  136. mVerticalScrollBar->changeValue(-mPageStep);
  137. break;
  138. case KEY_PAGEDOWN:
  139. if (mVerticalScrollBar->isVisible())
  140. mVerticalScrollBar->changeValue(mPageStep);
  141. break;
  142. case KEY_HOME:
  143. if (mVerticalScrollBar->isVisible())
  144. mVerticalScrollBar->setValue(0.0f);
  145. break;
  146. case KEY_END:
  147. if (mVerticalScrollBar->isVisible())
  148. mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
  149. break;
  150. }
  151. }
  152. void ScrollView::onResize()
  153. {
  154. IntVector2 panelSize = getSize();
  155. if (mVerticalScrollBar->isVisible())
  156. panelSize.mX -= mVerticalScrollBar->getWidth();
  157. if (mHorizontalScrollBar->isVisible())
  158. panelSize.mY -= mHorizontalScrollBar->getHeight();
  159. mScrollPanel->setSize(panelSize);
  160. mHorizontalScrollBar->setWidth(mScrollPanel->getWidth());
  161. mVerticalScrollBar->setHeight(mScrollPanel->getHeight());
  162. updateViewSize();
  163. }
  164. void ScrollView::setContentElement(UIElement* element)
  165. {
  166. if (element == mContentElement)
  167. return;
  168. if (mContentElement)
  169. {
  170. mScrollPanel->removeChild(mContentElement);
  171. unsubscribeFromEvent(mContentElement, EVENT_RESIZED);
  172. }
  173. mContentElement = element;
  174. if (mContentElement)
  175. {
  176. mScrollPanel->addChild(mContentElement);
  177. subscribeToEvent(mContentElement, EVENT_RESIZED, EVENT_HANDLER(ScrollView, handleElementResized));
  178. }
  179. updateViewSize();
  180. }
  181. void ScrollView::setViewPosition(const IntVector2& position)
  182. {
  183. updateView(position);
  184. updateScrollBars();
  185. }
  186. void ScrollView::setViewPosition(int x, int y)
  187. {
  188. setViewPosition(IntVector2(x, y));
  189. }
  190. void ScrollView::setScrollBarsVisible(bool horizontal, bool vertical)
  191. {
  192. mHorizontalScrollBar->setVisible(horizontal);
  193. mVerticalScrollBar->setVisible(vertical);
  194. }
  195. void ScrollView::setScrollStep(float step)
  196. {
  197. mHorizontalScrollBar->setScrollStep(step);
  198. mVerticalScrollBar->setScrollStep(step);
  199. }
  200. void ScrollView::setPageStep(float step)
  201. {
  202. mPageStep = max(step, 0.0f);
  203. }
  204. void ScrollView::setNormalizeScrollStep(bool enable)
  205. {
  206. mHorizontalScrollBar->setNormalizeScrollStep(enable);
  207. mVerticalScrollBar->setNormalizeScrollStep(enable);
  208. }
  209. bool ScrollView::getHorizontalScrollBarVisible() const
  210. {
  211. return mHorizontalScrollBar->isVisible();
  212. }
  213. bool ScrollView::getVerticalScrollBarVisible() const
  214. {
  215. return mVerticalScrollBar->isVisible();
  216. }
  217. float ScrollView::getScrollStep() const
  218. {
  219. return mHorizontalScrollBar->getScrollStep();
  220. }
  221. bool ScrollView::getNormalizeScrollStep() const
  222. {
  223. return mHorizontalScrollBar->getNormalizeScrollStep();
  224. }
  225. void ScrollView::updateViewSize()
  226. {
  227. IntVector2 size(IntVector2::sZero);
  228. if (mContentElement)
  229. size = mContentElement->getSize();
  230. mViewSize.mX = max(size.mX, mScrollPanel->getWidth());
  231. mViewSize.mY = max(size.mY, mScrollPanel->getHeight());
  232. updateView(mViewPosition);
  233. updateScrollBars();
  234. }
  235. void ScrollView::updateScrollBars()
  236. {
  237. mIgnoreEvents = true;
  238. const IntVector2& size = mScrollPanel->getSize();
  239. if ((mHorizontalScrollBar) && (size.mX > 0) && (mViewSize.mX > 0))
  240. {
  241. mHorizontalScrollBar->setRange((float)mViewSize.mX / (float)size.mX - 1.0f);
  242. mHorizontalScrollBar->setValue((float)mViewPosition.mX / (float)size.mX);
  243. }
  244. if ((mVerticalScrollBar) && (size.mY > 0) && (mViewSize.mY > 0))
  245. {
  246. mVerticalScrollBar->setRange((float)mViewSize.mY / (float)size.mY - 1.0f);
  247. mVerticalScrollBar->setValue((float)mViewPosition.mY / (float)size.mY);
  248. }
  249. mIgnoreEvents = false;
  250. }
  251. void ScrollView::updateView(const IntVector2& position)
  252. {
  253. IntVector2 oldPosition = mViewPosition;
  254. mViewPosition.mX = clamp(position.mX, 0, mViewSize.mX - mScrollPanel->getWidth());
  255. mViewPosition.mY = clamp(position.mY, 0, mViewSize.mY - mScrollPanel->getHeight());
  256. mScrollPanel->setChildOffset(-mViewPosition);
  257. if (mViewPosition != oldPosition)
  258. {
  259. using namespace ViewChanged;
  260. VariantMap eventData;
  261. eventData[P_ELEMENT] = (void*)this;
  262. eventData[P_X] = mViewPosition.mX;
  263. eventData[P_Y] = mViewPosition.mY;
  264. sendEvent(EVENT_VIEWCHANGED, eventData);
  265. }
  266. }
  267. void ScrollView::handleScrollBarChanged(StringHash eventType, VariantMap& eventData)
  268. {
  269. if (!mIgnoreEvents)
  270. {
  271. updateView(IntVector2(
  272. (int)(mHorizontalScrollBar->getValue() * (float)mScrollPanel->getWidth()),
  273. (int)(mVerticalScrollBar->getValue() * (float)mScrollPanel->getHeight())
  274. ));
  275. }
  276. }
  277. void ScrollView::handleScrollBarVisibleChanged(StringHash eventType, VariantMap& eventData)
  278. {
  279. // Need to recalculate panel size when scrollbar visibility changes
  280. onResize();
  281. }
  282. void ScrollView::handleElementResized(StringHash eventType, VariantMap& eventData)
  283. {
  284. updateViewSize();
  285. }