ScrollView.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../../Core/Context.h"
  23. #include "../../Input/InputEvents.h"
  24. #include "BorderImage.h"
  25. #include "ScrollBar.h"
  26. #include "ScrollView.h"
  27. #include "Slider.h"
  28. #include "UI.h"
  29. #include "UIEvents.h"
  30. #include "../../DebugNew.h"
  31. namespace Atomic
  32. {
  33. static const float STEP_FACTOR = 300.0f;
  34. extern const char* UI_CATEGORY;
  35. ScrollView::ScrollView(Context* context) :
  36. UIElement(context),
  37. viewPosition_(IntVector2::ZERO),
  38. viewSize_(IntVector2::ZERO),
  39. viewPositionAttr_(IntVector2::ZERO),
  40. touchScrollSpeed_(Vector2::ZERO),
  41. touchScrollSpeedMax_(Vector2::ZERO),
  42. pageStep_(1.0f),
  43. scrollBarsAutoVisible_(true),
  44. ignoreEvents_(false),
  45. resizeContentWidth_(false),
  46. scrollDeceleration_(30.0f),
  47. scrollSnapEpsilon_(M_EPSILON),
  48. scrollTouchDown_(false),
  49. barScrolling_(false),
  50. autoDisableChildren_(false),
  51. scrollChildrenDisable_(false),
  52. touchDistanceSum_(0.0f),
  53. autoDisableThreshold_(25.0f)
  54. {
  55. clipChildren_ = true;
  56. SetEnabled(true);
  57. focusMode_ = FM_FOCUSABLE_DEFOCUSABLE;
  58. horizontalScrollBar_ = CreateChild<ScrollBar>("SV_HorizontalScrollBar");
  59. horizontalScrollBar_->SetInternal(true);
  60. horizontalScrollBar_->SetAlignment(HA_LEFT, VA_BOTTOM);
  61. horizontalScrollBar_->SetOrientation(O_HORIZONTAL);
  62. verticalScrollBar_ = CreateChild<ScrollBar>("SV_VerticalScrollBar");
  63. verticalScrollBar_->SetInternal(true);
  64. verticalScrollBar_->SetAlignment(HA_RIGHT, VA_TOP);
  65. verticalScrollBar_->SetOrientation(O_VERTICAL);
  66. scrollPanel_ = CreateChild<BorderImage>("SV_ScrollPanel");
  67. scrollPanel_->SetInternal(true);
  68. scrollPanel_->SetEnabled(true);
  69. scrollPanel_->SetClipChildren(true);
  70. SubscribeToEvent(horizontalScrollBar_, E_SCROLLBARCHANGED, HANDLER(ScrollView, HandleScrollBarChanged));
  71. SubscribeToEvent(horizontalScrollBar_, E_VISIBLECHANGED, HANDLER(ScrollView, HandleScrollBarVisibleChanged));
  72. SubscribeToEvent(verticalScrollBar_, E_SCROLLBARCHANGED, HANDLER(ScrollView, HandleScrollBarChanged));
  73. SubscribeToEvent(verticalScrollBar_, E_VISIBLECHANGED, HANDLER(ScrollView, HandleScrollBarVisibleChanged));
  74. SubscribeToEvent(E_TOUCHMOVE, HANDLER(ScrollView, HandleTouchMove));
  75. SubscribeToEvent(E_TOUCHBEGIN, HANDLER(ScrollView, HandleTouchMove));
  76. SubscribeToEvent(E_TOUCHEND, HANDLER(ScrollView, HandleTouchMove));
  77. }
  78. ScrollView::~ScrollView()
  79. {
  80. }
  81. void ScrollView::RegisterObject(Context* context)
  82. {
  83. context->RegisterFactory<ScrollView>(UI_CATEGORY);
  84. COPY_BASE_ATTRIBUTES(UIElement);
  85. UPDATE_ATTRIBUTE_DEFAULT_VALUE("Clip Children", true);
  86. UPDATE_ATTRIBUTE_DEFAULT_VALUE("Is Enabled", true);
  87. UPDATE_ATTRIBUTE_DEFAULT_VALUE("Focus Mode", FM_FOCUSABLE_DEFOCUSABLE);
  88. ACCESSOR_ATTRIBUTE("View Position", GetViewPosition, SetViewPositionAttr, IntVector2, IntVector2::ZERO, AM_FILE);
  89. ACCESSOR_ATTRIBUTE("Scroll Step", GetScrollStep, SetScrollStep, float, 0.1f, AM_FILE);
  90. ACCESSOR_ATTRIBUTE("Page Step", GetPageStep, SetPageStep, float, 1.0f, AM_FILE);
  91. ACCESSOR_ATTRIBUTE("Auto Show/Hide Scrollbars", GetScrollBarsAutoVisible, SetScrollBarsAutoVisible, bool, true, AM_FILE);
  92. ACCESSOR_ATTRIBUTE("Scroll Deceleration", GetScrollDeceleration, SetScrollDeceleration, float, 30.0f, AM_FILE);
  93. ACCESSOR_ATTRIBUTE("Scroll Snap Epsilon", GetScrollSnapEpsilon, SetScrollSnapEpsilon, float, 1.0f, AM_FILE);
  94. ACCESSOR_ATTRIBUTE("Auto Disable Children", GetAutoDisableChildren, SetAutoDisableChildren, bool, false, AM_FILE);
  95. ACCESSOR_ATTRIBUTE("Auto Disable Threshold", GetAutoDisableThreshold, SetAutoDisableThreshold, float, 25.0f, AM_FILE);
  96. }
  97. void ScrollView::Update(float timeStep)
  98. {
  99. // Update touch scrolling here if necessary
  100. if (touchScrollSpeed_ == Vector2::ZERO && touchScrollSpeedMax_ == Vector2::ZERO && !barScrolling_)
  101. return;
  102. // Check if we should not scroll:
  103. // - ScrollView is not visible, is not enabled, or doesn't have focus
  104. // - The element being dragged is not a child of the ScrollView, or is one of our scrollbars
  105. if (!IsVisible() || !IsEnabled() || !HasFocus())
  106. {
  107. touchScrollSpeed_ = Vector2::ZERO;
  108. touchScrollSpeedMax_ = Vector2::ZERO;
  109. return;
  110. }
  111. if (GetSubsystem<UI>()->IsDragging())
  112. {
  113. Vector<UIElement*> dragElements = GetSubsystem<UI>()->GetDragElements();
  114. for (unsigned i = 0; i < dragElements.Size(); i++)
  115. {
  116. UIElement* dragElement = dragElements[i];
  117. int dragButtons = dragElement->GetDragButtonCombo();
  118. if (dragButtons != MOUSEB_LEFT)
  119. continue;
  120. UIElement* dragParent = dragElement->GetParent();
  121. bool dragElementIsChild = false;
  122. while (dragParent)
  123. {
  124. if (dragParent == this)
  125. {
  126. dragElementIsChild = true;
  127. break;
  128. }
  129. dragParent = dragParent->GetParent();
  130. }
  131. if (!dragElementIsChild || dragElement == horizontalScrollBar_->GetSlider() ||
  132. dragElement == verticalScrollBar_->GetSlider())
  133. {
  134. touchScrollSpeed_ = Vector2::ZERO;
  135. touchScrollSpeedMax_ = Vector2::ZERO;
  136. return;
  137. }
  138. }
  139. }
  140. // Update view position
  141. IntVector2 newPosition = viewPosition_;
  142. newPosition.x_ += (int)touchScrollSpeed_.x_;
  143. newPosition.y_ += (int)touchScrollSpeed_.y_;
  144. SetViewPosition(newPosition);
  145. // Smooth deceleration
  146. ScrollSmooth(timeStep);
  147. }
  148. void ScrollView::ApplyAttributes()
  149. {
  150. UIElement::ApplyAttributes();
  151. // Set the scrollbar orientations again and perform size update now that the style is known
  152. horizontalScrollBar_->SetOrientation(O_HORIZONTAL);
  153. verticalScrollBar_->SetOrientation(O_VERTICAL);
  154. // If the scroll panel has a child, it should be the content element, which has some special handling
  155. if (scrollPanel_->GetNumChildren())
  156. SetContentElement(scrollPanel_->GetChild(0));
  157. OnResize();
  158. // Reapply view position with proper content element and size
  159. SetViewPosition(viewPositionAttr_);
  160. }
  161. void ScrollView::OnWheel(int delta, int buttons, int qualifiers)
  162. {
  163. if (delta > 0)
  164. verticalScrollBar_->StepBack();
  165. if (delta < 0)
  166. verticalScrollBar_->StepForward();
  167. }
  168. void ScrollView::OnKey(int key, int buttons, int qualifiers)
  169. {
  170. switch (key)
  171. {
  172. case KEY_LEFT:
  173. if (horizontalScrollBar_->IsVisible())
  174. {
  175. if (qualifiers & QUAL_CTRL)
  176. horizontalScrollBar_->SetValue(0.0f);
  177. else
  178. horizontalScrollBar_->StepBack();
  179. }
  180. break;
  181. case KEY_RIGHT:
  182. if (horizontalScrollBar_->IsVisible())
  183. {
  184. if (qualifiers & QUAL_CTRL)
  185. horizontalScrollBar_->SetValue(horizontalScrollBar_->GetRange());
  186. else
  187. horizontalScrollBar_->StepForward();
  188. }
  189. break;
  190. case KEY_HOME:
  191. qualifiers |= QUAL_CTRL;
  192. // Fallthru
  193. case KEY_UP:
  194. if (verticalScrollBar_->IsVisible())
  195. {
  196. if (qualifiers & QUAL_CTRL)
  197. verticalScrollBar_->SetValue(0.0f);
  198. else
  199. verticalScrollBar_->StepBack();
  200. }
  201. break;
  202. case KEY_END:
  203. qualifiers |= QUAL_CTRL;
  204. // Fallthru
  205. case KEY_DOWN:
  206. if (verticalScrollBar_->IsVisible())
  207. {
  208. if (qualifiers & QUAL_CTRL)
  209. verticalScrollBar_->SetValue(verticalScrollBar_->GetRange());
  210. else
  211. verticalScrollBar_->StepForward();
  212. }
  213. break;
  214. case KEY_PAGEUP:
  215. if (verticalScrollBar_->IsVisible())
  216. verticalScrollBar_->ChangeValue(-pageStep_);
  217. break;
  218. case KEY_PAGEDOWN:
  219. if (verticalScrollBar_->IsVisible())
  220. verticalScrollBar_->ChangeValue(pageStep_);
  221. break;
  222. default: break;
  223. }
  224. }
  225. void ScrollView::OnResize()
  226. {
  227. UpdatePanelSize();
  228. UpdateViewSize();
  229. // If scrollbar auto visibility is enabled, check whether scrollbars should be visible.
  230. // This may force another update of the panel size
  231. if (scrollBarsAutoVisible_)
  232. {
  233. ignoreEvents_ = true;
  234. horizontalScrollBar_->SetVisible(horizontalScrollBar_->GetRange() > M_EPSILON);
  235. verticalScrollBar_->SetVisible(verticalScrollBar_->GetRange() > M_EPSILON);
  236. ignoreEvents_ = false;
  237. UpdatePanelSize();
  238. }
  239. }
  240. void ScrollView::SetContentElement(UIElement* element)
  241. {
  242. if (element == contentElement_)
  243. return;
  244. if (contentElement_)
  245. {
  246. scrollPanel_->RemoveChild(contentElement_);
  247. UnsubscribeFromEvent(contentElement_, E_RESIZED);
  248. }
  249. contentElement_ = element;
  250. if (contentElement_)
  251. {
  252. scrollPanel_->AddChild(contentElement_);
  253. SubscribeToEvent(contentElement_, E_RESIZED, HANDLER(ScrollView, HandleElementResized));
  254. }
  255. OnResize();
  256. }
  257. void ScrollView::SetViewPosition(const IntVector2& position)
  258. {
  259. UpdateView(position);
  260. UpdateScrollBars();
  261. }
  262. void ScrollView::SetViewPosition(int x, int y)
  263. {
  264. SetViewPosition(IntVector2(x, y));
  265. }
  266. void ScrollView::SetScrollBarsVisible(bool horizontal, bool vertical)
  267. {
  268. scrollBarsAutoVisible_ = false;
  269. horizontalScrollBar_->SetVisible(horizontal);
  270. verticalScrollBar_->SetVisible(vertical);
  271. }
  272. void ScrollView::SetScrollBarsAutoVisible(bool enable)
  273. {
  274. if (enable != scrollBarsAutoVisible_)
  275. {
  276. scrollBarsAutoVisible_ = enable;
  277. // Check whether scrollbars should be visible now
  278. if (enable)
  279. OnResize();
  280. else
  281. {
  282. horizontalScrollBar_->SetVisible(true);
  283. verticalScrollBar_->SetVisible(true);
  284. }
  285. }
  286. }
  287. void ScrollView::SetScrollStep(float step)
  288. {
  289. horizontalScrollBar_->SetScrollStep(step);
  290. verticalScrollBar_->SetScrollStep(step);
  291. }
  292. void ScrollView::SetPageStep(float step)
  293. {
  294. pageStep_ = Max(step, 0.0f);
  295. }
  296. float ScrollView::GetScrollStep() const
  297. {
  298. return horizontalScrollBar_->GetScrollStep();
  299. }
  300. void ScrollView::SetViewPositionAttr(const IntVector2& value)
  301. {
  302. viewPositionAttr_ = value;
  303. SetViewPosition(value);
  304. }
  305. bool ScrollView::FilterImplicitAttributes(XMLElement& dest) const
  306. {
  307. if (!UIElement::FilterImplicitAttributes(dest))
  308. return false;
  309. XMLElement childElem = dest.GetChild("element");
  310. if (!FilterScrollBarImplicitAttributes(childElem, "SV_HorizontalScrollBar"))
  311. return false;
  312. if (!RemoveChildXML(childElem, "Vert Alignment", "Bottom"))
  313. return false;
  314. childElem = childElem.GetNext("element");
  315. if (!FilterScrollBarImplicitAttributes(childElem, "SV_VerticalScrollBar"))
  316. return false;
  317. if (!RemoveChildXML(childElem, "Horiz Alignment", "Right"))
  318. return false;
  319. childElem = childElem.GetNext("element");
  320. if (!childElem)
  321. return false;
  322. if (!RemoveChildXML(childElem, "Name", "SV_ScrollPanel"))
  323. return false;
  324. if (!RemoveChildXML(childElem, "Is Enabled", "true"))
  325. return false;
  326. if (!RemoveChildXML(childElem, "Clip Children", "true"))
  327. return false;
  328. if (!RemoveChildXML(childElem, "Size"))
  329. return false;
  330. return true;
  331. }
  332. bool ScrollView::FilterScrollBarImplicitAttributes(XMLElement& dest, const String& name) const
  333. {
  334. if (!dest)
  335. return false;
  336. if (!RemoveChildXML(dest, "Name", name))
  337. return false;
  338. if (!RemoveChildXML(dest, "Orientation"))
  339. return false;
  340. if (!RemoveChildXML(dest, "Range"))
  341. return false;
  342. if (!RemoveChildXML(dest, "Step Factor"))
  343. return false;
  344. if (scrollBarsAutoVisible_)
  345. {
  346. if (!RemoveChildXML(dest, "Is Visible"))
  347. return false;
  348. }
  349. return true;
  350. }
  351. void ScrollView::UpdatePanelSize()
  352. {
  353. // Ignore events in case content element resizes itself along with the panel
  354. // (content element resize triggers our OnResize(), so it could lead to infinite recursion)
  355. ignoreEvents_ = true;
  356. IntVector2 panelSize = GetSize();
  357. if (verticalScrollBar_->IsVisible())
  358. panelSize.x_ -= verticalScrollBar_->GetWidth();
  359. if (horizontalScrollBar_->IsVisible())
  360. panelSize.y_ -= horizontalScrollBar_->GetHeight();
  361. scrollPanel_->SetSize(panelSize);
  362. horizontalScrollBar_->SetWidth(scrollPanel_->GetWidth());
  363. verticalScrollBar_->SetHeight(scrollPanel_->GetHeight());
  364. if (resizeContentWidth_ && contentElement_)
  365. {
  366. IntRect panelBorder = scrollPanel_->GetClipBorder();
  367. contentElement_->SetWidth(scrollPanel_->GetWidth() - panelBorder.left_ - panelBorder.right_);
  368. UpdateViewSize();
  369. }
  370. ignoreEvents_ = false;
  371. }
  372. void ScrollView::UpdateViewSize()
  373. {
  374. IntVector2 size(IntVector2::ZERO);
  375. if (contentElement_)
  376. size = contentElement_->GetSize();
  377. IntRect panelBorder = scrollPanel_->GetClipBorder();
  378. viewSize_.x_ = Max(size.x_, scrollPanel_->GetWidth() - panelBorder.left_ - panelBorder.right_);
  379. viewSize_.y_ = Max(size.y_, scrollPanel_->GetHeight() - panelBorder.top_ - panelBorder.bottom_);
  380. UpdateView(viewPosition_);
  381. UpdateScrollBars();
  382. }
  383. void ScrollView::UpdateScrollBars()
  384. {
  385. ignoreEvents_ = true;
  386. IntVector2 size = scrollPanel_->GetSize();
  387. IntRect panelBorder = scrollPanel_->GetClipBorder();
  388. size.x_ -= panelBorder.left_ + panelBorder.right_;
  389. size.y_ -= panelBorder.top_ + panelBorder.bottom_;
  390. if (size.x_ > 0 && viewSize_.x_ > 0)
  391. {
  392. float range = (float)viewSize_.x_ / (float)size.x_ - 1.0f;
  393. horizontalScrollBar_->SetRange(range);
  394. horizontalScrollBar_->SetValue((float)viewPosition_.x_ / (float)size.x_);
  395. horizontalScrollBar_->SetStepFactor(STEP_FACTOR / (float)size.x_);
  396. }
  397. if (size.y_ > 0 && viewSize_.y_ > 0)
  398. {
  399. float range = (float)viewSize_.y_ / (float)size.y_ - 1.0f;
  400. verticalScrollBar_->SetRange(range);
  401. verticalScrollBar_->SetValue((float)viewPosition_.y_ / (float)size.y_);
  402. verticalScrollBar_->SetStepFactor(STEP_FACTOR / (float)size.y_);
  403. }
  404. ignoreEvents_ = false;
  405. }
  406. void ScrollView::UpdateView(const IntVector2& position)
  407. {
  408. IntVector2 oldPosition = viewPosition_;
  409. IntRect panelBorder = scrollPanel_->GetClipBorder();
  410. IntVector2 panelSize(scrollPanel_->GetWidth() - panelBorder.left_ - panelBorder.right_,
  411. scrollPanel_->GetHeight() - panelBorder.top_ - panelBorder.bottom_);
  412. viewPosition_.x_ = Clamp(position.x_, 0, viewSize_.x_ - panelSize.x_);
  413. viewPosition_.y_ = Clamp(position.y_, 0, viewSize_.y_ - panelSize.y_);
  414. scrollPanel_->SetChildOffset(IntVector2(-viewPosition_.x_ + panelBorder.left_, -viewPosition_.y_ + panelBorder.top_));
  415. if (viewPosition_ != oldPosition)
  416. {
  417. using namespace ViewChanged;
  418. VariantMap& eventData = GetEventDataMap();
  419. eventData[P_ELEMENT] = this;
  420. eventData[P_X] = viewPosition_.x_;
  421. eventData[P_Y] = viewPosition_.y_;
  422. SendEvent(E_VIEWCHANGED, eventData);
  423. }
  424. }
  425. void ScrollView::HandleScrollBarChanged(StringHash eventType, VariantMap& eventData)
  426. {
  427. if (!ignoreEvents_)
  428. {
  429. IntVector2 size = scrollPanel_->GetSize();
  430. IntRect panelBorder = scrollPanel_->GetClipBorder();
  431. size.x_ -= panelBorder.left_ + panelBorder.right_;
  432. size.y_ -= panelBorder.top_ + panelBorder.bottom_;
  433. UpdateView(IntVector2(
  434. (int)(horizontalScrollBar_->GetValue() * (float)size.x_),
  435. (int)(verticalScrollBar_->GetValue() * (float)size.y_)
  436. ));
  437. }
  438. }
  439. void ScrollView::HandleScrollBarVisibleChanged(StringHash eventType, VariantMap& eventData)
  440. {
  441. // Need to recalculate panel size when scrollbar visibility changes
  442. if (!ignoreEvents_)
  443. OnResize();
  444. }
  445. void ScrollView::HandleElementResized(StringHash eventType, VariantMap& eventData)
  446. {
  447. if (!ignoreEvents_)
  448. OnResize();
  449. }
  450. void ScrollView::HandleTouchMove(StringHash eventType, VariantMap& eventData)
  451. {
  452. using namespace TouchMove;
  453. if (eventType == E_TOUCHMOVE && !barScrolling_)
  454. {
  455. scrollTouchDown_ = true;
  456. // Take new scrolling speed if it's faster than the current accumulated value
  457. float dX = (float)-eventData[P_DX].GetInt();
  458. float dY = (float)-eventData[P_DY].GetInt();
  459. if (Abs(dX) > Abs(touchScrollSpeed_.x_))
  460. touchScrollSpeed_.x_ = dX;
  461. if (Abs(dY) > Abs(touchScrollSpeed_.y_))
  462. touchScrollSpeed_.y_ = dY;
  463. // Auto disable children
  464. touchDistanceSum_ += dX * dX + dY * dY;
  465. if (autoDisableChildren_ && touchDistanceSum_ >= autoDisableThreshold_)
  466. {
  467. if (visible_ && !scrollChildrenDisable_)
  468. {
  469. scrollChildrenDisable_ = true;
  470. scrollPanel_->SetDeepEnabled(false);
  471. }
  472. }
  473. touchScrollSpeedMax_.x_ = dX;
  474. touchScrollSpeedMax_.y_ = dY;
  475. }
  476. else if (eventType == E_TOUCHBEGIN)
  477. {
  478. int X = eventData[P_X].GetInt();
  479. int Y = eventData[P_Y].GetInt();
  480. IntVector2 pos = IntVector2(X, Y);
  481. // Prevent conflict between touch scroll and scrollbar scroll
  482. if (horizontalScrollBar_->IsVisible() && horizontalScrollBar_->IsInsideCombined(pos, true))
  483. barScrolling_ = true;
  484. if (verticalScrollBar_->IsVisible() && verticalScrollBar_->IsInsideCombined(pos, true))
  485. barScrolling_ = true;
  486. // Stop the smooth scrolling
  487. touchScrollSpeed_ = Vector2::ZERO;
  488. touchScrollSpeedMax_ = Vector2::ZERO;
  489. }
  490. else if (eventType == E_TOUCHEND)
  491. {
  492. // 'Flick' action
  493. // Release any auto disabled children
  494. if (scrollChildrenDisable_)
  495. {
  496. touchDistanceSum_ = 0.0f;
  497. scrollChildrenDisable_ = false;
  498. scrollPanel_->ResetDeepEnabled();
  499. }
  500. barScrolling_ = false;
  501. scrollTouchDown_ = false;
  502. if (Abs(touchScrollSpeedMax_.x_) > scrollSnapEpsilon_)
  503. touchScrollSpeed_.x_ = touchScrollSpeedMax_.x_;
  504. else
  505. touchScrollSpeed_.x_ = 0;
  506. if (Abs(touchScrollSpeedMax_.y_) > scrollSnapEpsilon_)
  507. touchScrollSpeed_.y_ = touchScrollSpeedMax_.y_;
  508. else
  509. touchScrollSpeed_.y_ = 0;
  510. touchScrollSpeedMax_ = Vector2::ZERO;
  511. }
  512. }
  513. void ScrollView::ScrollSmooth(float timeStep)
  514. {
  515. // Decay the momentum
  516. if (touchScrollSpeedMax_.x_ >= scrollSnapEpsilon_)
  517. {
  518. touchScrollSpeedMax_.x_ -= scrollDeceleration_ * timeStep;
  519. touchScrollSpeedMax_.x_ = touchScrollSpeedMax_.x_ > 0 ? touchScrollSpeedMax_.x_ : 0;
  520. }
  521. else if (touchScrollSpeedMax_.x_ <= -scrollSnapEpsilon_)
  522. {
  523. touchScrollSpeedMax_.x_ += scrollDeceleration_ * timeStep;
  524. touchScrollSpeedMax_.x_ = touchScrollSpeedMax_.x_ < 0 ? touchScrollSpeedMax_.x_ : 0;
  525. }
  526. else
  527. touchScrollSpeedMax_.x_ = 0;
  528. if (touchScrollSpeedMax_.y_ >= scrollSnapEpsilon_)
  529. {
  530. touchScrollSpeedMax_.y_ -= scrollDeceleration_ * timeStep;
  531. touchScrollSpeedMax_.y_ = touchScrollSpeedMax_.y_ > 0 ? touchScrollSpeedMax_.y_ : 0;
  532. }
  533. else if (touchScrollSpeedMax_.y_ <= -scrollSnapEpsilon_)
  534. {
  535. touchScrollSpeedMax_.y_ += scrollDeceleration_ * timeStep;
  536. touchScrollSpeedMax_.y_ = touchScrollSpeedMax_.y_ < 0 ? touchScrollSpeedMax_.y_ : 0;
  537. }
  538. else
  539. touchScrollSpeedMax_.y_ = 0;
  540. // Control vs flick
  541. if (scrollTouchDown_)
  542. {
  543. // Finger is held down: control = instant stop
  544. touchScrollSpeed_ = Vector2::ZERO;
  545. }
  546. else
  547. {
  548. // Finger is released: flick = smooth deceleration
  549. if (touchScrollSpeed_.x_ >= scrollSnapEpsilon_)
  550. {
  551. touchScrollSpeed_.x_ -= scrollDeceleration_ * timeStep;
  552. if (touchScrollSpeed_.x_ < 0)
  553. {
  554. touchScrollSpeed_.x_ = 0;
  555. }
  556. if (horizontalScrollBar_->GetValue() >= horizontalScrollBar_->GetRange() - M_EPSILON)
  557. {
  558. // Stop movement when we reach end of scroll
  559. touchScrollSpeed_.x_ = 0;
  560. }
  561. }
  562. else if (touchScrollSpeed_.x_ < -scrollSnapEpsilon_)
  563. {
  564. touchScrollSpeed_.x_ += scrollDeceleration_ * timeStep;
  565. if (touchScrollSpeed_.x_ > 0)
  566. {
  567. touchScrollSpeed_.x_ = 0;
  568. }
  569. if (horizontalScrollBar_->GetValue() <= M_EPSILON)
  570. {
  571. // Stop movement when we reach end of scroll
  572. touchScrollSpeed_.x_ = 0;
  573. }
  574. }
  575. else
  576. touchScrollSpeed_.x_ = 0;
  577. if (touchScrollSpeed_.y_ >= scrollSnapEpsilon_)
  578. {
  579. touchScrollSpeed_.y_ -= scrollDeceleration_ * timeStep;
  580. if (touchScrollSpeed_.y_ < 0)
  581. {
  582. touchScrollSpeed_.y_ = 0;
  583. }
  584. if (verticalScrollBar_->GetValue() >= verticalScrollBar_->GetRange() - M_EPSILON)
  585. {
  586. // Stop movement when we reach end of scroll
  587. touchScrollSpeed_.y_ = 0;
  588. }
  589. }
  590. else if (touchScrollSpeed_.y_ < -scrollSnapEpsilon_)
  591. {
  592. touchScrollSpeed_.y_ += scrollDeceleration_ * timeStep;
  593. if (touchScrollSpeed_.y_ > 0)
  594. {
  595. touchScrollSpeed_.y_ = 0;
  596. }
  597. if (verticalScrollBar_->GetValue() <= M_EPSILON)
  598. {
  599. // Stop movement when we reach end of scroll
  600. touchScrollSpeed_.y_ = 0;
  601. }
  602. }
  603. else
  604. touchScrollSpeed_.y_ = 0;
  605. }
  606. }
  607. }