ScrollBar.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Core/Context.h"
  5. #include "../Input/InputEvents.h"
  6. #include "../UI/Button.h"
  7. #include "../UI/ScrollBar.h"
  8. #include "../UI/Slider.h"
  9. #include "../UI/UIEvents.h"
  10. namespace Urho3D
  11. {
  12. static const float DEFAULT_SCROLL_STEP = 0.1f;
  13. static const float DEFAULT_REPEAT_DELAY = 0.4f;
  14. static const float DEFAULT_REPEAT_RATE = 20.0f;
  15. extern const char* orientations[];
  16. extern const char* UI_CATEGORY;
  17. ScrollBar::ScrollBar(Context* context) :
  18. BorderImage(context),
  19. scrollStep_(DEFAULT_SCROLL_STEP),
  20. stepFactor_(1.0f),
  21. leftRect_(IntRect::ZERO),
  22. rightRect_(IntRect::ZERO),
  23. upRect_(IntRect::ZERO),
  24. downRect_(IntRect::ZERO)
  25. {
  26. SetEnabled(true);
  27. backButton_ = CreateChild<Button>("SB_Back");
  28. backButton_->SetInternal(true);
  29. backButton_->SetRepeat(DEFAULT_REPEAT_DELAY, DEFAULT_REPEAT_RATE);
  30. backButton_->SetFocusMode(FM_NOTFOCUSABLE);
  31. slider_ = CreateChild<Slider>("SB_Slider");
  32. slider_->SetInternal(true);
  33. slider_->SetRepeatRate(DEFAULT_REPEAT_RATE);
  34. forwardButton_ = CreateChild<Button>("SB_Forward");
  35. forwardButton_->SetInternal(true);
  36. forwardButton_->SetRepeat(DEFAULT_REPEAT_DELAY, DEFAULT_REPEAT_RATE);
  37. forwardButton_->SetFocusMode(FM_NOTFOCUSABLE);
  38. // For backward compatibility
  39. SetColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
  40. SubscribeToEvent(backButton_, E_PRESSED, URHO3D_HANDLER(ScrollBar, HandleBackButtonPressed));
  41. SubscribeToEvent(forwardButton_, E_PRESSED, URHO3D_HANDLER(ScrollBar, HandleForwardButtonPressed));
  42. SubscribeToEvent(slider_, E_SLIDERCHANGED, URHO3D_HANDLER(ScrollBar, HandleSliderChanged));
  43. SubscribeToEvent(slider_, E_SLIDERPAGED, URHO3D_HANDLER(ScrollBar, HandleSliderPaged));
  44. // Set default orientation
  45. SetOrientation(O_HORIZONTAL);
  46. }
  47. ScrollBar::~ScrollBar() = default;
  48. void ScrollBar::RegisterObject(Context* context)
  49. {
  50. context->RegisterFactory<ScrollBar>(UI_CATEGORY);
  51. URHO3D_COPY_BASE_ATTRIBUTES(BorderImage);
  52. URHO3D_UPDATE_ATTRIBUTE_DEFAULT_VALUE("Is Enabled", true);
  53. URHO3D_ENUM_ACCESSOR_ATTRIBUTE("Orientation", GetOrientation, SetOrientation, orientations, O_HORIZONTAL, AM_FILE);
  54. URHO3D_ACCESSOR_ATTRIBUTE("Range", GetRange, SetRange, 1.0f, AM_FILE);
  55. URHO3D_ACCESSOR_ATTRIBUTE("Value", GetValue, SetValue, 0.0f, AM_FILE);
  56. URHO3D_ACCESSOR_ATTRIBUTE("Scroll Step", GetScrollStep, SetScrollStep, DEFAULT_SCROLL_STEP, AM_FILE);
  57. URHO3D_ACCESSOR_ATTRIBUTE("Step Factor", GetStepFactor, SetStepFactor, 1.0f, AM_FILE);
  58. URHO3D_ATTRIBUTE("Left Image Rect", leftRect_, IntRect::ZERO, AM_FILE);
  59. URHO3D_ATTRIBUTE("Right Image Rect", rightRect_, IntRect::ZERO, AM_FILE);
  60. URHO3D_ATTRIBUTE("Up Image Rect", upRect_, IntRect::ZERO, AM_FILE);
  61. URHO3D_ATTRIBUTE("Down Image Rect", downRect_, IntRect::ZERO, AM_FILE);
  62. }
  63. void ScrollBar::ApplyAttributes()
  64. {
  65. BorderImage::ApplyAttributes();
  66. // Reapply orientation to the button images
  67. if (slider_->GetOrientation() == O_HORIZONTAL)
  68. {
  69. backButton_->SetImageRect(leftRect_);
  70. forwardButton_->SetImageRect(rightRect_);
  71. }
  72. else
  73. {
  74. backButton_->SetImageRect(upRect_);
  75. forwardButton_->SetImageRect(downRect_);
  76. }
  77. }
  78. void ScrollBar::OnResize(const IntVector2& newSize, const IntVector2& delta)
  79. {
  80. if (slider_->GetOrientation() == O_HORIZONTAL)
  81. {
  82. int height = newSize.y_;
  83. int sliderWidth = Max(GetWidth() - 2 * height, 0);
  84. backButton_->SetSize(height, height);
  85. slider_->SetSize(sliderWidth, height);
  86. forwardButton_->SetSize(height, height);
  87. backButton_->SetPosition(0, 0);
  88. slider_->SetPosition(height, 0);
  89. forwardButton_->SetPosition(height + sliderWidth, 0);
  90. }
  91. else
  92. {
  93. int width = newSize.x_;
  94. int sliderHeight = Max(GetHeight() - 2 * width, 0);
  95. backButton_->SetSize(width, width);
  96. slider_->SetSize(width, sliderHeight);
  97. forwardButton_->SetSize(width, width);
  98. backButton_->SetPosition(0, 0);
  99. slider_->SetPosition(0, width);
  100. forwardButton_->SetPosition(0, sliderHeight + width);
  101. }
  102. }
  103. void ScrollBar::OnSetEditable()
  104. {
  105. slider_->SetEditable(editable_);
  106. }
  107. void ScrollBar::SetOrientation(Orientation orientation)
  108. {
  109. slider_->SetOrientation(orientation);
  110. if (orientation == O_HORIZONTAL)
  111. {
  112. backButton_->SetImageRect(leftRect_);
  113. forwardButton_->SetImageRect(rightRect_);
  114. }
  115. else
  116. {
  117. backButton_->SetImageRect(upRect_);
  118. forwardButton_->SetImageRect(downRect_);
  119. }
  120. OnResize(GetSize(), IntVector2::ZERO);
  121. }
  122. void ScrollBar::SetRange(float range)
  123. {
  124. slider_->SetRange(range);
  125. }
  126. void ScrollBar::SetValue(float value)
  127. {
  128. slider_->SetValue(value);
  129. }
  130. void ScrollBar::ChangeValue(float delta)
  131. {
  132. slider_->ChangeValue(delta);
  133. }
  134. void ScrollBar::SetScrollStep(float step)
  135. {
  136. scrollStep_ = Max(step, 0.0f);
  137. }
  138. void ScrollBar::SetStepFactor(float factor)
  139. {
  140. stepFactor_ = Max(factor, M_EPSILON);
  141. }
  142. void ScrollBar::StepBack()
  143. {
  144. slider_->SetValue(slider_->GetValue() - GetEffectiveScrollStep());
  145. }
  146. void ScrollBar::StepForward()
  147. {
  148. slider_->SetValue(slider_->GetValue() + GetEffectiveScrollStep());
  149. }
  150. Orientation ScrollBar::GetOrientation() const
  151. {
  152. return slider_->GetOrientation();
  153. }
  154. float ScrollBar::GetRange() const
  155. {
  156. return slider_->GetRange();
  157. }
  158. float ScrollBar::GetValue() const
  159. {
  160. return slider_->GetValue();
  161. }
  162. float ScrollBar::GetEffectiveScrollStep() const
  163. {
  164. return scrollStep_ * stepFactor_;
  165. }
  166. bool ScrollBar::FilterImplicitAttributes(XMLElement& dest) const
  167. {
  168. if (!BorderImage::FilterImplicitAttributes(dest))
  169. return false;
  170. if (!RemoveChildXML(dest, "Layout Mode"))
  171. return false;
  172. XMLElement childElem = dest.GetChild("element");
  173. if (!FilterButtonImplicitAttributes(childElem, "SB_Back"))
  174. return false;
  175. childElem = childElem.GetNext("element");
  176. if (!childElem)
  177. return false;
  178. if (!RemoveChildXML(childElem, "Name", "SB_Slider"))
  179. return false;
  180. if (!RemoveChildXML(childElem, "Repeat Rate", String(DEFAULT_REPEAT_RATE)))
  181. return false;
  182. if (!RemoveChildXML(childElem, "Orientation"))
  183. return false;
  184. if (!RemoveChildXML(childElem, "Range"))
  185. return false;
  186. if (!RemoveChildXML(childElem, "Value"))
  187. return false;
  188. childElem = childElem.GetNext("element");
  189. return FilterButtonImplicitAttributes(childElem, "SB_Forward");
  190. }
  191. bool ScrollBar::FilterButtonImplicitAttributes(XMLElement& dest, const String& name) const
  192. {
  193. if (!dest)
  194. return false;
  195. if (!RemoveChildXML(dest, "Name", name))
  196. return false;
  197. if (!RemoveChildXML(dest, "Repeat Delay", String(DEFAULT_REPEAT_DELAY)))
  198. return false;
  199. if (!RemoveChildXML(dest, "Repeat Rate", String(DEFAULT_REPEAT_RATE)))
  200. return false;
  201. if (!RemoveChildXML(dest, "Image Rect"))
  202. return false;
  203. if (!RemoveChildXML(dest, "Min Size"))
  204. return false;
  205. if (!RemoveChildXML(dest, "Max Size"))
  206. return false;
  207. if (!RemoveChildXML(dest, "Focus Mode", "NotFocusable"))
  208. return false;
  209. return true;
  210. }
  211. void ScrollBar::HandleBackButtonPressed(StringHash eventType, VariantMap& eventData)
  212. {
  213. if (editable_)
  214. StepBack();
  215. }
  216. void ScrollBar::HandleForwardButtonPressed(StringHash eventType, VariantMap& eventData)
  217. {
  218. if (editable_)
  219. StepForward();
  220. }
  221. void ScrollBar::HandleSliderChanged(StringHash eventType, VariantMap& eventData)
  222. {
  223. // Send the event forward
  224. VariantMap& newEventData = GetEventDataMap();
  225. newEventData[ScrollBarChanged::P_ELEMENT] = this;
  226. newEventData[ScrollBarChanged::P_VALUE] = slider_->GetValue();
  227. SendEvent(E_SCROLLBARCHANGED, newEventData);
  228. }
  229. void ScrollBar::HandleSliderPaged(StringHash eventType, VariantMap& eventData)
  230. {
  231. using namespace SliderPaged;
  232. // Synthesize hover event to the forward/back buttons
  233. if (eventData[P_OFFSET].GetI32() < 0)
  234. backButton_->OnHover(IntVector2::ZERO, backButton_->ElementToScreen(IntVector2::ZERO), MOUSEB_NONE, QUAL_NONE, nullptr);
  235. else
  236. forwardButton_->OnHover(IntVector2::ZERO, forwardButton_->ElementToScreen(IntVector2::ZERO), MOUSEB_NONE, QUAL_NONE, nullptr);
  237. // Synthesize click / release events to the buttons
  238. if (eventData[P_PRESSED].GetBool())
  239. {
  240. if (eventData[P_OFFSET].GetI32() < 0)
  241. backButton_->OnClickBegin(IntVector2::ZERO, backButton_->ElementToScreen(IntVector2::ZERO),
  242. MOUSEB_LEFT, MOUSEB_LEFT, QUAL_NONE, nullptr);
  243. else
  244. forwardButton_->OnClickBegin(IntVector2::ZERO, forwardButton_->ElementToScreen(IntVector2::ZERO),
  245. MOUSEB_LEFT, MOUSEB_LEFT, QUAL_NONE, nullptr);
  246. }
  247. else
  248. {
  249. if (eventData[P_OFFSET].GetI32() < 0)
  250. backButton_->OnClickEnd(IntVector2::ZERO, backButton_->ElementToScreen(IntVector2::ZERO),
  251. MOUSEB_LEFT, MOUSEB_NONE, QUAL_NONE, nullptr, backButton_);
  252. else
  253. forwardButton_->OnClickEnd(IntVector2::ZERO, forwardButton_->ElementToScreen(IntVector2::ZERO),
  254. MOUSEB_LEFT, MOUSEB_NONE, QUAL_NONE, nullptr, forwardButton_);
  255. }
  256. }
  257. }