2
0

Menu.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2012 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 "Context.h"
  25. #include "InputEvents.h"
  26. #include "Log.h"
  27. #include "Menu.h"
  28. #include "UIEvents.h"
  29. #include "DebugNew.h"
  30. namespace Urho3D
  31. {
  32. static const ShortStringHash originHash("Origin");
  33. OBJECTTYPESTATIC(Menu);
  34. Menu::Menu(Context* context) :
  35. Button(context),
  36. popupOffset_(IntVector2::ZERO),
  37. showPopup_(false),
  38. acceleratorKey_(0),
  39. acceleratorQualifiers_(0)
  40. {
  41. SubscribeToEvent(this, E_PRESSED, HANDLER(Menu, HandlePressedReleased));
  42. SubscribeToEvent(this, E_RELEASED, HANDLER(Menu, HandlePressedReleased));
  43. SubscribeToEvent(E_UIMOUSECLICK, HANDLER(Menu, HandleFocusChanged));
  44. SubscribeToEvent(E_FOCUSCHANGED, HANDLER(Menu, HandleFocusChanged));
  45. }
  46. Menu::~Menu()
  47. {
  48. if (popup_)
  49. ShowPopup(false);
  50. }
  51. void Menu::RegisterObject(Context* context)
  52. {
  53. context->RegisterFactory<Menu>();
  54. }
  55. void Menu::SetStyle(const XMLElement& element)
  56. {
  57. Button::SetStyle(element);
  58. XMLElement popupElem = element.GetChild("popup");
  59. if (popupElem && popupElem.HasAttribute("name"))
  60. {
  61. UIElement* root = GetRoot();
  62. if (root)
  63. SetPopup(root->GetChild(popupElem.GetAttribute("name"), true));
  64. }
  65. if (element.HasChild("popupoffset"))
  66. SetPopupOffset(element.GetChild("popupoffset").GetIntVector2("value"));
  67. }
  68. void Menu::OnShowPopup()
  69. {
  70. }
  71. void Menu::SetPopup(UIElement* popup)
  72. {
  73. if (popup == this)
  74. return;
  75. if (popup_ && !popup)
  76. ShowPopup(false);
  77. popup_ = popup;
  78. // Detach from current parent (if any) to only show when it is time
  79. if (popup_)
  80. popup_->Remove();
  81. }
  82. void Menu::SetPopupOffset(const IntVector2& offset)
  83. {
  84. popupOffset_ = offset;
  85. }
  86. void Menu::SetPopupOffset(int x, int y)
  87. {
  88. popupOffset_ = IntVector2(x, y);
  89. }
  90. void Menu::ShowPopup(bool enable)
  91. {
  92. if (!popup_)
  93. return;
  94. if (enable)
  95. {
  96. // Find the UI root element for showing the popup
  97. UIElement* root = GetRoot();
  98. if (!root)
  99. return;
  100. OnShowPopup();
  101. if (popup_->GetParent() != root)
  102. root->AddChild(popup_);
  103. popup_->SetPosition(GetScreenPosition() + popupOffset_);
  104. popup_->SetVisible(true);
  105. popup_->SetVar(originHash, (void*)this);
  106. popup_->BringToFront();
  107. }
  108. else
  109. {
  110. // If the popup has child menus, hide their popups as well
  111. PODVector<UIElement*> children;
  112. popup_->GetChildren(children, true);
  113. for (PODVector<UIElement*>::ConstIterator i = children.Begin(); i != children.End(); ++i)
  114. {
  115. Menu* menu = dynamic_cast<Menu*>(*i);
  116. if (menu)
  117. menu->ShowPopup(false);
  118. }
  119. popup_->SetVar(originHash, Variant());
  120. popup_->SetVisible(false);
  121. popup_->Remove();
  122. }
  123. showPopup_ = enable;
  124. selected_ = enable;
  125. }
  126. void Menu::SetAccelerator(int key, int qualifiers)
  127. {
  128. acceleratorKey_ = key;
  129. acceleratorQualifiers_ = qualifiers;
  130. if (key)
  131. SubscribeToEvent(E_KEYDOWN, HANDLER(Menu, HandleKeyDown));
  132. else
  133. UnsubscribeFromEvent(E_KEYDOWN);
  134. }
  135. void Menu::HandlePressedReleased(StringHash eventType, VariantMap& eventData)
  136. {
  137. // If this menu shows a sublevel popup, react to button press. Else react to release
  138. if (eventType == E_PRESSED)
  139. {
  140. if (!popup_)
  141. return;
  142. }
  143. if (eventType == E_RELEASED)
  144. {
  145. if (popup_)
  146. return;
  147. }
  148. // Toggle popup visibility if exists
  149. ShowPopup(!showPopup_);
  150. // Send event on each click if no popup, or whenever the popup is opened
  151. if (!popup_ || showPopup_)
  152. {
  153. using namespace MenuSelected;
  154. VariantMap newEventData;
  155. newEventData[P_ELEMENT] = (void*)this;
  156. SendEvent(E_MENUSELECTED, newEventData);
  157. }
  158. }
  159. void Menu::HandleFocusChanged(StringHash eventType, VariantMap& eventData)
  160. {
  161. if (!showPopup_)
  162. return;
  163. using namespace FocusChanged;
  164. UIElement* element = static_cast<UIElement*>(eventData[P_ELEMENT].GetPtr());
  165. UIElement* root = GetRoot();
  166. // If another element was focused due to the menu button being clicked, do not hide the popup
  167. if (eventType == E_FOCUSCHANGED && static_cast<UIElement*>(eventData[P_CLICKEDELEMENT].GetPtr()))
  168. return;
  169. // If clicked emptiness or defocused, hide the popup
  170. if (!element)
  171. {
  172. ShowPopup(false);
  173. return;
  174. }
  175. // Otherwise see if the clicked element has either the menu item or the popup in its parent chain.
  176. // In that case, do not hide
  177. while (element)
  178. {
  179. if (element == this || element == popup_)
  180. return;
  181. if (element->GetParent() == root)
  182. element = static_cast<UIElement*>(element->GetVar(originHash).GetPtr());
  183. else
  184. element = element->GetParent();
  185. }
  186. ShowPopup(false);
  187. }
  188. void Menu::HandleKeyDown(StringHash eventType, VariantMap& eventData)
  189. {
  190. if (!active_)
  191. return;
  192. using namespace KeyDown;
  193. // Activate if accelerator key pressed
  194. if (eventData[P_KEY].GetInt() == acceleratorKey_ && (acceleratorQualifiers_ == QUAL_ANY || eventData[P_QUALIFIERS].GetInt() ==
  195. acceleratorQualifiers_) && eventData[P_REPEAT].GetBool() == false)
  196. HandlePressedReleased(eventType, eventData);
  197. }
  198. }