Button.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright (c) 2008-2022 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/UI.h"
  8. #include "../UI/UIEvents.h"
  9. #include "../DebugNew.h"
  10. namespace Urho3D
  11. {
  12. extern const char* UI_CATEGORY;
  13. Button::Button(Context* context) :
  14. BorderImage(context),
  15. pressedOffset_(IntVector2::ZERO),
  16. pressedChildOffset_(IntVector2::ZERO),
  17. repeatDelay_(1.0f),
  18. repeatRate_(0.0f),
  19. repeatTimer_(0.0f),
  20. pressed_(false)
  21. {
  22. SetEnabled(true);
  23. focusMode_ = FM_FOCUSABLE;
  24. }
  25. Button::~Button() = default;
  26. void Button::RegisterObject(Context* context)
  27. {
  28. context->RegisterFactory<Button>(UI_CATEGORY);
  29. URHO3D_COPY_BASE_ATTRIBUTES(BorderImage);
  30. URHO3D_UPDATE_ATTRIBUTE_DEFAULT_VALUE("Is Enabled", true);
  31. URHO3D_UPDATE_ATTRIBUTE_DEFAULT_VALUE("Focus Mode", FM_FOCUSABLE);
  32. URHO3D_ACCESSOR_ATTRIBUTE("Pressed Image Offset", GetPressedOffset, SetPressedOffset, IntVector2::ZERO, AM_FILE);
  33. URHO3D_ACCESSOR_ATTRIBUTE("Pressed Child Offset", GetPressedChildOffset, SetPressedChildOffset, IntVector2::ZERO, AM_FILE);
  34. URHO3D_ACCESSOR_ATTRIBUTE("Repeat Delay", GetRepeatDelay, SetRepeatDelay, 1.0f, AM_FILE);
  35. URHO3D_ACCESSOR_ATTRIBUTE("Repeat Rate", GetRepeatRate, SetRepeatRate, 0.0f, AM_FILE);
  36. }
  37. void Button::Update(float timeStep)
  38. {
  39. if (!hovering_ && pressed_)
  40. SetPressed(false);
  41. // Send repeat events if pressed
  42. if (pressed_ && repeatRate_ > 0.0f)
  43. {
  44. repeatTimer_ -= timeStep;
  45. if (repeatTimer_ <= 0.0f)
  46. {
  47. repeatTimer_ += 1.0f / repeatRate_;
  48. using namespace Pressed;
  49. VariantMap& eventData = GetEventDataMap();
  50. eventData[P_ELEMENT] = this;
  51. SendEvent(E_PRESSED, eventData);
  52. }
  53. }
  54. }
  55. void Button::GetBatches(Vector<UIBatch>& batches, Vector<float>& vertexData, const IntRect& currentScissor)
  56. {
  57. IntVector2 offset(IntVector2::ZERO);
  58. if (enabled_)
  59. {
  60. if (hovering_ || HasFocus())
  61. offset += hoverOffset_;
  62. if (pressed_ || selected_)
  63. offset += pressedOffset_;
  64. }
  65. else
  66. {
  67. offset += disabledOffset_;
  68. }
  69. BorderImage::GetBatches(batches, vertexData, currentScissor, offset);
  70. }
  71. void Button::OnClickBegin(const IntVector2& position, const IntVector2& screenPosition, MouseButton button, MouseButtonFlags buttons, QualifierFlags qualifiers,
  72. Cursor* cursor)
  73. {
  74. if (button == MOUSEB_LEFT)
  75. {
  76. SetPressed(true);
  77. repeatTimer_ = repeatDelay_;
  78. hovering_ = true;
  79. using namespace Pressed;
  80. VariantMap& eventData = GetEventDataMap();
  81. eventData[P_ELEMENT] = this;
  82. SendEvent(E_PRESSED, eventData);
  83. }
  84. }
  85. void Button::OnClickEnd(const IntVector2& position, const IntVector2& screenPosition, MouseButton button, MouseButtonFlags buttons, QualifierFlags qualifiers,
  86. Cursor* cursor, UIElement* beginElement)
  87. {
  88. if (pressed_ && button == MOUSEB_LEFT)
  89. {
  90. SetPressed(false);
  91. // If mouse was released on top of the element, consider it hovering on this frame yet (see issue #1453)
  92. if (IsInside(screenPosition, true))
  93. hovering_ = true;
  94. using namespace Released;
  95. VariantMap& eventData = GetEventDataMap();
  96. eventData[P_ELEMENT] = this;
  97. SendEvent(E_RELEASED, eventData);
  98. }
  99. }
  100. void Button::OnDragMove(const IntVector2& position, const IntVector2& screenPosition, const IntVector2& deltaPos, MouseButtonFlags buttons,
  101. QualifierFlags qualifiers, Cursor* cursor)
  102. {
  103. SetPressed(true);
  104. }
  105. void Button::OnKey(Key key, MouseButtonFlags buttons, QualifierFlags qualifiers)
  106. {
  107. if (HasFocus() && (key == KEY_RETURN || key == KEY_RETURN2 || key == KEY_KP_ENTER || key == KEY_SPACE))
  108. {
  109. // Simulate LMB click
  110. OnClickBegin(IntVector2(), IntVector2(), MOUSEB_LEFT, MOUSEB_NONE, QUAL_NONE, nullptr);
  111. OnClickEnd(IntVector2(), IntVector2(), MOUSEB_LEFT, MOUSEB_NONE, QUAL_NONE, nullptr, nullptr);
  112. }
  113. }
  114. void Button::SetPressedOffset(const IntVector2& offset)
  115. {
  116. pressedOffset_ = offset;
  117. }
  118. void Button::SetPressedOffset(int x, int y)
  119. {
  120. pressedOffset_ = IntVector2(x, y);
  121. }
  122. void Button::SetPressedChildOffset(const IntVector2& offset)
  123. {
  124. pressedChildOffset_ = offset;
  125. }
  126. void Button::SetPressedChildOffset(int x, int y)
  127. {
  128. pressedChildOffset_ = IntVector2(x, y);
  129. }
  130. void Button::SetRepeat(float delay, float rate)
  131. {
  132. SetRepeatDelay(delay);
  133. SetRepeatRate(rate);
  134. }
  135. void Button::SetRepeatDelay(float delay)
  136. {
  137. repeatDelay_ = Max(delay, 0.0f);
  138. }
  139. void Button::SetRepeatRate(float rate)
  140. {
  141. repeatRate_ = Max(rate, 0.0f);
  142. }
  143. void Button::SetPressed(bool enable)
  144. {
  145. pressed_ = enable;
  146. SetChildOffset(pressed_ ? pressedChildOffset_ : IntVector2::ZERO);
  147. }
  148. }