| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- //
- // Urho3D Engine
- // Copyright (c) 2008-2011 Lasse Öörni
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #include "Precompiled.h"
- #include "BorderImage.h"
- #include "InputEvents.h"
- #include "ListView.h"
- #include "UIEvents.h"
- #include "DebugNew.h"
- ListView::ListView(const std::string& name) :
- ScrollView(name),
- mSelection(M_MAX_UNSIGNED),
- mShowSelectionAlways(false)
- {
- UIElement* container = new UIElement();
- container->setEnabled(true);
- container->setLayout(LM_VERTICAL);
- setContentElement(container);
-
- subscribeToEvent(EVENT_TRYFOCUS, EVENT_HANDLER(ListView, handleTryFocus));
- }
- ListView::~ListView()
- {
- }
- void ListView::setStyle(const XMLElement& element, ResourceCache* cache)
- {
- ScrollView::setStyle(element, cache);
-
- UIElement* root = getRootElement();
- XMLElement itemElem = element.getChildElement("listitem");
- if (root)
- {
- while (itemElem)
- {
- if (itemElem.hasAttribute("name"))
- addItem(root->getChild(itemElem.getString("name"), true));
- itemElem = itemElem.getNextElement("listitem");
- }
- }
-
- if (element.hasChildElement("selection"))
- setSelection(element.getChildElement("selection").getInt("value"));
- if (element.hasChildElement("showselectionalways"))
- setShowSelectionAlways(element.getChildElement("showselectionalways").getBool("enable"));
- }
- void ListView::onWheel(int delta, int buttons, int qualifiers)
- {
- if (delta > 0)
- changeSelection(-1);
- if (delta < 0)
- changeSelection(1);
- }
- void ListView::onKey(int key, int buttons, int qualifiers)
- {
- // If no selection, can not move with keys
- if ((mSelection == M_MAX_UNSIGNED) || (!getNumItems()))
- return;
-
- switch (key)
- {
- case KEY_UP:
- if (qualifiers & QUAL_CTRL)
- setSelection(0);
- else
- changeSelection(-1);
- break;
-
- case KEY_DOWN:
- if (qualifiers & QUAL_CTRL)
- setSelection(getNumItems() - 1);
- else
- changeSelection(1);
- break;
-
- case KEY_PAGEUP:
- {
- // Convert page step to pixels and see how many items we have to skip to reach that many pixels
- int stepPixels = ((int)(mPageStep * mScrollPanel->getHeight())) - getSelectedItem()->getHeight();
- unsigned newSelection = mSelection;
- while (newSelection)
- {
- int height = getItem(newSelection)->getHeight();
- if (stepPixels < height)
- break;
- stepPixels -= height;
- --newSelection;
- }
- setSelection(newSelection);
- }
- break;
-
- case KEY_PAGEDOWN:
- {
- int stepPixels = ((int)(mPageStep * mScrollPanel->getHeight())) - getSelectedItem()->getHeight();
- unsigned newSelection = mSelection;
- while (newSelection < getNumItems() - 1)
- {
- int height = getItem(newSelection)->getHeight();
- if (stepPixels < height)
- break;
- stepPixels -= height;
- ++newSelection;
- }
- setSelection(newSelection);
- }
- break;
-
- case KEY_HOME:
- setSelection(0);
- break;
-
- case KEY_END:
- setSelection(getNumItems() - 1);
- break;
- }
- }
- void ListView::onResize()
- {
- ScrollView::onResize();
-
- // Set the content element width to match the scrollpanel
- const IntRect& clipBorder = mScrollPanel->getClipBorder();
- mContentElement->setWidth(mScrollPanel->getWidth() - clipBorder.mLeft - clipBorder.mRight);
- }
- void ListView::onFocus()
- {
- updateSelectionEffect();
- }
- void ListView::onDefocus()
- {
- updateSelectionEffect();
- }
- void ListView::addItem(UIElement* item)
- {
- if ((!item) || (item->getParent() == mContentElement))
- return;
-
- // Enable input so that clicking the item can be detected
- item->setEnabled(true);
- mContentElement->addChild(item);
- }
- void ListView::removeItem(UIElement* item)
- {
- std::vector<UIElement*> items = mContentElement->getChildren();
- for (unsigned i = 0; i < items.size(); ++i)
- {
- if (items[i] == item)
- {
- if (mSelection == i)
- clearSelection();
- else if (mSelection > i)
- changeSelection(-1);
- break;
- }
- }
- mContentElement->removeChild(item);
- }
- void ListView::removeItem(unsigned index)
- {
- if (index >= getNumItems())
- return;
- UIElement* item = mContentElement->getChild(index);
- if (mSelection == index)
- clearSelection();
- else if (mSelection > index)
- changeSelection(-1);
- mContentElement->removeChild(item);
- }
- void ListView::removeAllItems()
- {
- mContentElement->removeAllChildren();
- clearSelection();
- }
- void ListView::setSelection(unsigned index)
- {
- if (index >= getNumItems())
- index = M_MAX_UNSIGNED;
-
- bool changed = index != mSelection;
-
- mSelection = index;
- updateSelectionEffect();
- ensureItemVisibility();
-
- if (changed)
- {
- using namespace ItemSelected;
-
- VariantMap eventData;
- eventData[P_ELEMENT] = (void*)this;
- eventData[P_SELECTION] = mSelection;
- sendEvent(EVENT_ITEMSELECTED, eventData);
- }
- }
- void ListView::changeSelection(int delta)
- {
- if (mSelection == M_MAX_UNSIGNED)
- return;
-
- int newSelection = clamp((int)mSelection + delta, 0, (int)getNumItems() - 1);
- setSelection(newSelection);
- }
- void ListView::clearSelection()
- {
- setSelection(M_MAX_UNSIGNED);
- }
- void ListView::setShowSelectionAlways(bool enable)
- {
- mShowSelectionAlways = enable;
- }
- unsigned ListView::getNumItems() const
- {
- return mContentElement->getNumChildren();
- }
- UIElement* ListView::getItem(unsigned index) const
- {
- return mContentElement->getChild(index);
- }
- std::vector<UIElement*> ListView::getItems() const
- {
- return mContentElement->getChildren();
- }
- UIElement* ListView::getSelectedItem() const
- {
- return mContentElement->getChild(mSelection);
- }
- void ListView::updateSelectionEffect()
- {
- unsigned numItems = getNumItems();
- for (unsigned i = 0; i < numItems; ++i)
- getItem(i)->setSelected((i == mSelection) && ((mFocus) || (mShowSelectionAlways)));
- }
- void ListView::ensureItemVisibility()
- {
- UIElement* selected = getSelectedItem();
- if (!selected)
- return;
-
- IntVector2 currentOffset = selected->getScreenPosition() - mScrollPanel->getScreenPosition() - mContentElement->getPosition();
- IntVector2 newView = getViewPosition();
- const IntRect& clipBorder = mScrollPanel->getClipBorder();
- IntVector2 windowSize(mScrollPanel->getWidth() - clipBorder.mLeft - clipBorder.mRight, mScrollPanel->getHeight() -
- clipBorder.mTop - clipBorder.mBottom);
-
- if (currentOffset.mX < 0)
- newView.mX += currentOffset.mX;
- if (currentOffset.mX + selected->getWidth() > windowSize.mX)
- newView.mX += currentOffset.mX + selected->getWidth() - windowSize.mX;
- if (currentOffset.mY < 0)
- newView.mY += currentOffset.mY;
- if (currentOffset.mY + selected->getHeight() > windowSize.mY)
- newView.mY += currentOffset.mY + selected->getHeight() - windowSize.mY;
-
- setViewPosition(newView);
- }
- void ListView::handleTryFocus(StringHash eventType, VariantMap& eventData)
- {
- using namespace TryFocus;
-
- UIElement* focusElement = static_cast<UIElement*>(eventData[P_ELEMENT].getPtr());
-
- unsigned numItems = getNumItems();
- for (unsigned i = 0; i < numItems; ++i)
- {
- if (focusElement == getItem(i))
- {
- setSelection(i);
- return;
- }
- }
- }
|