DropDownList.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 "DropDownList.h"
  25. #include "ListView.h"
  26. #include "UIEvents.h"
  27. #include "Window.h"
  28. #include "DebugNew.h"
  29. DropDownList::DropDownList(const std::string& name) :
  30. Menu(name),
  31. mResizePopup(false)
  32. {
  33. Window* window = new Window();
  34. setPopup(window);
  35. mListView = new ListView();
  36. mListView->setScrollBarsVisible(false, false);
  37. mListView->setFocusMode(FM_RESETFOCUS);
  38. mPopup->setLayout(LM_VERTICAL);
  39. mPopup->addChild(mListView);
  40. mPlaceholder = new UIElement();
  41. addChild(mPlaceholder);
  42. subscribeToEvent(mListView, EVENT_ITEMSELECTED, EVENT_HANDLER(DropDownList, handleItemSelected));
  43. }
  44. DropDownList::~DropDownList()
  45. {
  46. }
  47. void DropDownList::setStyle(const XMLElement& element, ResourceCache* cache)
  48. {
  49. Menu::setStyle(element, cache);
  50. XMLElement listElem = element.getChildElement("listview");
  51. if (listElem)
  52. mListView->setStyle(listElem, cache);
  53. XMLElement popupElem = element.getChildElement("popup");
  54. if (popupElem)
  55. mPopup->setStyle(popupElem, cache);
  56. XMLElement placeholderElem = element.getChildElement("placeholder");
  57. if (placeholderElem)
  58. mPlaceholder->setStyle(placeholderElem, cache);
  59. UIElement* root = getRootElement();
  60. XMLElement itemElem = element.getChildElement("popupitem");
  61. if (root)
  62. {
  63. while (itemElem)
  64. {
  65. if (itemElem.hasAttribute("name"))
  66. addItem(root->getChild(itemElem.getString("name"), true));
  67. itemElem = itemElem.getNextElement("popupitem");
  68. }
  69. }
  70. if (element.hasChildElement("selection"))
  71. setSelection(element.getChildElement("selection").getInt("value"));
  72. if (element.hasChildElement("resizepopup"))
  73. setResizePopup(element.getChildElement("resizepopup").getBool("enable"));
  74. }
  75. void DropDownList::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
  76. {
  77. Button::getBatches(batches, quads, currentScissor);
  78. UIElement* selectedItem = getSelectedItem();
  79. if (selectedItem)
  80. {
  81. // We can not easily copy the selected item. However, we can re-render it on the placeholder's position
  82. const IntVector2& targetPos = mPlaceholder->getScreenPosition();
  83. const IntVector2& originalPos = selectedItem->getScreenPosition();
  84. IntVector2 offset = targetPos - originalPos;
  85. // getBatches() usually resets the hover flag. Therefore get its value and then reset it for the real rendering
  86. bool hover = selectedItem->isHovering();
  87. selectedItem->setHovering(false);
  88. selectedItem->getBatchesWithOffset(offset, batches, quads, currentScissor);
  89. selectedItem->setHovering(hover);
  90. }
  91. }
  92. void DropDownList::onShowPopup()
  93. {
  94. // Resize the popup to match the size of the list content, and optionally match the button width
  95. UIElement* content = mListView->getContentElement();
  96. content->updateLayout();
  97. const IntVector2& contentSize = content->getSize();
  98. const IntRect& border = mPopup->getLayoutBorder();
  99. mPopup->setSize(mResizePopup ? getWidth() : contentSize.mX + border.mLeft + border.mRight, contentSize.mY + border.mTop +
  100. border.mBottom);
  101. // Check if popup fits below the button. If not, show above instead
  102. bool showAbove = false;
  103. UIElement* root = getRootElement();
  104. if (root)
  105. {
  106. const IntVector2& screenPos = getScreenPosition();
  107. if ((screenPos.mY + getHeight() + mPopup->getHeight() > root->getHeight()) && (screenPos.mY - mPopup->getHeight() >= 0))
  108. showAbove = true;
  109. }
  110. if (!showAbove)
  111. setPopupOffset(0, getHeight());
  112. else
  113. setPopupOffset(0, -mPopup->getHeight());
  114. }
  115. void DropDownList::addItem(UIElement* item)
  116. {
  117. mListView->addItem(item);
  118. // If there was no selection, set to the first
  119. if (mListView->getSelection() == M_MAX_UNSIGNED)
  120. mListView->setSelection(0);
  121. }
  122. void DropDownList::removeItem(UIElement* item)
  123. {
  124. mListView->removeItem(item);
  125. }
  126. void DropDownList::removeItem(unsigned index)
  127. {
  128. mListView->removeItem(index);
  129. }
  130. void DropDownList::removeAllItems()
  131. {
  132. mListView->removeAllItems();
  133. }
  134. void DropDownList::setSelection(unsigned index)
  135. {
  136. // The list should always show a selection if possible, so clamp the selection
  137. unsigned numItems = getNumItems();
  138. if (index >= numItems)
  139. index = numItems - 1;
  140. mListView->setSelection(index);
  141. }
  142. void DropDownList::setResizePopup(bool enable)
  143. {
  144. mResizePopup = enable;
  145. }
  146. unsigned DropDownList::getNumItems() const
  147. {
  148. return mListView->getNumItems();
  149. }
  150. UIElement* DropDownList::getItem(unsigned index) const
  151. {
  152. return mListView->getItem(index);
  153. }
  154. std::vector<UIElement*> DropDownList::getItems() const
  155. {
  156. return mListView->getContentElement()->getChildren();
  157. }
  158. unsigned DropDownList::getSelection() const
  159. {
  160. return mListView->getSelection();
  161. }
  162. UIElement* DropDownList::getSelectedItem() const
  163. {
  164. return mListView->getSelectedItem();
  165. }
  166. void DropDownList::handleItemSelected(StringHash eventType, VariantMap& eventData)
  167. {
  168. // Resize the selection placeholder to match the selected item
  169. UIElement* selectedItem = getSelectedItem();
  170. if (selectedItem)
  171. mPlaceholder->setSize(selectedItem->getSize());
  172. // Close the popup as the selection was made
  173. if (getShowPopup())
  174. showPopup(false);
  175. // Send the event forward
  176. using namespace ItemSelected;
  177. VariantMap newEventData;
  178. newEventData[P_ELEMENT] = (void*)this;
  179. newEventData[P_SELECTION] = getSelection();
  180. sendEvent(EVENT_ITEMSELECTED, eventData);
  181. }