| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- #include "BsGUIDropDownContent.h"
- #include "BsGUILayout.h"
- #include "BsGUITexture.h"
- #include "BsGUIButton.h"
- #include "BsGUILabel.h"
- #include "BsGUISpace.h"
- #include "BsGUIWidget.h"
- #include "BsGUIToggle.h"
- #include "BsGUISkin.h"
- #include "BsGUIMouseEvent.h"
- #include "BsGUICommandEvent.h"
- using namespace std::placeholders;
- namespace BansheeEngine
- {
- const String GUIDropDownContent::ENTRY_STYLE_TYPE = "DropDownEntryBtn";
- const String GUIDropDownContent::ENTRY_EXP_STYLE_TYPE = "DropDownEntryExpBtn";
- const String GUIDropDownContent::SEPARATOR_STYLE_TYPE = "DropDownSeparator";
- GUIDropDownContent::GUIDropDownContent(GUIDropDownBox::DropDownSubMenu* parent, const GUIDropDownData& dropDownData,
- const String& style, const GUIDimensions& dimensions)
- :GUIElementContainer(dimensions, style), mDropDownData(dropDownData),
- mSelectedIdx(UINT_MAX), mRangeStart(0), mRangeEnd(0), mParent(parent)
- {
-
- }
- GUIDropDownContent::~GUIDropDownContent()
- {
- }
- GUIDropDownContent* GUIDropDownContent::create(GUIDropDownBox::DropDownSubMenu* parent,
- const GUIDropDownData& dropDownData, const String& style)
- {
- const String* curStyle = &style;
- if (*curStyle == StringUtil::BLANK)
- curStyle = &GUIDropDownContent::getGUITypeName();
- return new (bs_alloc<GUIDropDownContent>()) GUIDropDownContent(parent, dropDownData, *curStyle, GUIDimensions::create());
- }
- GUIDropDownContent* GUIDropDownContent::create(GUIDropDownBox::DropDownSubMenu* parent,
- const GUIDropDownData& dropDownData, const GUIOptions& options,
- const String& style)
- {
- const String* curStyle = &style;
- if (*curStyle == StringUtil::BLANK)
- curStyle = &GUIDropDownContent::getGUITypeName();
- return new (bs_alloc<GUIDropDownContent>()) GUIDropDownContent(parent, dropDownData, *curStyle, GUIDimensions::create(options));
- }
- void GUIDropDownContent::styleUpdated()
- {
- for (auto& visElem : mVisibleElements)
- {
- GUIDropDownDataEntry& element = mDropDownData.entries[visElem.idx];
- if (element.isSeparator())
- visElem.separator->setStyle(getSubStyleName(SEPARATOR_STYLE_TYPE));
- else if (element.isSubMenu())
- visElem.button->setStyle(getSubStyleName(ENTRY_EXP_STYLE_TYPE));
- else
- visElem.button->setStyle(getSubStyleName(ENTRY_STYLE_TYPE));
- }
- }
- void GUIDropDownContent::setRange(UINT32 start, UINT32 end)
- {
- std::function<void(UINT32, UINT32)> onHover =
- [&](UINT32 idx, UINT32 visIdx)
- {
- setSelected(visIdx);
- mParent->elementSelected(idx);
- };
- std::function<void(UINT32, UINT32)> onClick =
- [&](UINT32 idx, UINT32 visIdx)
- {
- setSelected(visIdx);
- mParent->elementActivated(idx, mVisibleElements[visIdx].button->_getCachedBounds());
- };
- // Remove all elements
- while (_getNumChildren() > 0)
- {
- GUIElementBase* child = _getChild(_getNumChildren() - 1);
- assert(child->_getType() == GUIElementBase::Type::Element);
- GUIElement::destroy(static_cast<GUIElement*>(child));
- }
- mRangeStart = start;
- mRangeEnd = end;
-
- mVisibleElements.clear();
- UINT32 curVisIdx = 0;
- for (UINT32 i = start; i < end; i++)
- {
- mVisibleElements.push_back(VisibleElement());
- VisibleElement& visElem = mVisibleElements.back();
- visElem.idx = i;
- GUIDropDownDataEntry& element = mDropDownData.entries[i];
- if (element.isSeparator())
- {
- visElem.separator = GUITexture::create(GUIImageScaleMode::StretchToFit, getSubStyleName(SEPARATOR_STYLE_TYPE));
- _registerChildElement(visElem.separator);
- }
- else if (element.isSubMenu())
- {
- visElem.button = GUIButton::create(getElementLocalizedName(i), getSubStyleName(ENTRY_EXP_STYLE_TYPE));
- visElem.button->onHover.connect(std::bind(onClick, i, curVisIdx));
- _registerChildElement(visElem.button);
- }
- else
- {
- visElem.button = GUIButton::create(getElementLocalizedName(i), getSubStyleName(ENTRY_STYLE_TYPE));
- visElem.button->onHover.connect(std::bind(onHover, i, curVisIdx));
- visElem.button->onClick.connect(std::bind(onClick, i, curVisIdx));
- _registerChildElement(visElem.button);
- const WString& shortcutTag = element.getShortcutTag();
- if (!shortcutTag.empty())
- {
- visElem.shortcutLabel = GUILabel::create(HString(shortcutTag), "RightAlignedLabel");
- _registerChildElement(visElem.shortcutLabel);
- }
- }
- curVisIdx++;
- }
- markContentAsDirty();
- }
- UINT32 GUIDropDownContent::getElementHeight(UINT32 idx) const
- {
- if (_getParentWidget() == nullptr)
- return 14; // Arbitrary
- if (mDropDownData.entries[idx].isSeparator())
- return _getParentWidget()->getSkin().getStyle(getSubStyleName(SEPARATOR_STYLE_TYPE))->height;
- else if (mDropDownData.entries[idx].isSubMenu())
- return _getParentWidget()->getSkin().getStyle(getSubStyleName(ENTRY_EXP_STYLE_TYPE))->height;
- else
- return _getParentWidget()->getSkin().getStyle(getSubStyleName(ENTRY_STYLE_TYPE))->height;
- }
- HString GUIDropDownContent::getElementLocalizedName(UINT32 idx) const
- {
- const WString& label = mDropDownData.entries[idx].getLabel();
- auto findLocalizedName = mDropDownData.localizedNames.find(label);
- if (findLocalizedName != mDropDownData.localizedNames.end())
- return findLocalizedName->second;
- else
- return HString(label);
- }
- void GUIDropDownContent::setKeyboardFocus(bool focus)
- {
- mKeyboardFocus = focus;
- setFocus(focus);
- }
- bool GUIDropDownContent::_commandEvent(const GUICommandEvent& ev)
- {
- if (!mKeyboardFocus)
- return false;
- UINT32 maxElemIdx = (UINT32)mDropDownData.entries.size();
- switch (ev.getType())
- {
- case GUICommandEventType::MoveDown:
- if (mSelectedIdx == UINT_MAX)
- selectNext(0);
- else
- selectNext(mSelectedIdx + 1);
- return true;
- case GUICommandEventType::MoveUp:
- if (mSelectedIdx == UINT_MAX)
- selectNext(0);
- else
- selectPrevious(mSelectedIdx - 1);
- return true;
- case GUICommandEventType::Escape:
- case GUICommandEventType::MoveLeft:
- mParent->close();
- return true;
- case GUICommandEventType::MoveRight:
- {
- if (mSelectedIdx == UINT_MAX)
- selectNext(0);
- else
- {
- GUIDropDownDataEntry& entry = mDropDownData.entries[mVisibleElements[mSelectedIdx].idx];
- if (entry.isSubMenu())
- mParent->elementActivated(mVisibleElements[mSelectedIdx].idx, mVisibleElements[mSelectedIdx].button->_getCachedBounds());
- }
- }
- return true;
- case GUICommandEventType::Return:
- if (mSelectedIdx == UINT_MAX)
- selectNext(0);
- else
- mParent->elementActivated(mVisibleElements[mSelectedIdx].idx, mVisibleElements[mSelectedIdx].button->_getCachedBounds());
- return true;
- }
- return false;
- }
- void GUIDropDownContent::setSelected(UINT32 idx)
- {
- if (mSelectedIdx != UINT_MAX)
- mVisibleElements[mSelectedIdx].button->_setOn(false);
- mSelectedIdx = idx;
- mVisibleElements[mSelectedIdx].button->_setOn(true);
- mParent->elementSelected(mVisibleElements[mSelectedIdx].idx);
- }
- void GUIDropDownContent::selectNext(UINT32 startIdx)
- {
- UINT32 numElements = (UINT32)mDropDownData.entries.size();
- bool gotNextIndex = false;
- UINT32 nextIdx = startIdx;
- for (UINT32 i = 0; i < numElements; i++)
- {
- if (nextIdx >= numElements)
- nextIdx = 0; // Wrap around
- GUIDropDownDataEntry& entry = mDropDownData.entries[nextIdx];
- if (!entry.isSeparator())
- {
- gotNextIndex = true;
- break;
- }
- nextIdx++;
- }
- if (gotNextIndex)
- {
- while (nextIdx < mRangeStart || nextIdx >= mRangeEnd)
- mParent->scrollDown();
- UINT32 visIdx = 0;
- for (auto& visElem : mVisibleElements)
- {
- if (visElem.idx == nextIdx)
- {
- setSelected(visIdx);
- break;
- }
- visIdx++;
- }
- }
- }
- void GUIDropDownContent::selectPrevious(UINT32 startIdx)
- {
- UINT32 numElements = (UINT32)mDropDownData.entries.size();
- bool gotNextIndex = false;
- INT32 prevIdx = (INT32)startIdx;
- for (UINT32 i = 0; i < numElements; i++)
- {
- if (prevIdx < 0)
- prevIdx = numElements - 1; // Wrap around
- GUIDropDownDataEntry& entry = mDropDownData.entries[prevIdx];
- if (!entry.isSeparator())
- {
- gotNextIndex = true;
- break;
- }
- prevIdx--;
- }
- if (gotNextIndex)
- {
- while (prevIdx < (INT32)mRangeStart || prevIdx >= (INT32)mRangeEnd)
- mParent->scrollUp();
- UINT32 visIdx = 0;
- for (auto& visElem : mVisibleElements)
- {
- if (visElem.idx == prevIdx)
- {
- setSelected(visIdx);
- break;
- }
- visIdx++;
- }
- }
- }
- Vector2I GUIDropDownContent::_getOptimalSize() const
- {
- Vector2I optimalSize;
- for (auto& visElem : mVisibleElements)
- {
- const GUIDropDownDataEntry& element = mDropDownData.entries[visElem.idx];
- optimalSize.y += (INT32)getElementHeight(visElem.idx);
- if (element.isSeparator())
- optimalSize.x = std::max(optimalSize.x, visElem.separator->_getOptimalSize().x);
- else
- optimalSize.x = std::max(optimalSize.x, visElem.button->_getOptimalSize().x);
- }
- return optimalSize;
- }
- void GUIDropDownContent::updateClippedBounds()
- {
- Vector2I offset = _getOffset();
- mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
- Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
- mClippedBounds.clip(localClipRect);
- }
- void GUIDropDownContent::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
- Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
- {
- INT32 yOffset = y;
- for (auto& visElem : mVisibleElements)
- {
- const GUIDropDownDataEntry& element = mDropDownData.entries[visElem.idx];
- GUIElement* guiMainElement = nullptr;
- if (element.isSeparator())
- guiMainElement = visElem.separator;
- else
- guiMainElement = visElem.button;
- UINT32 elemHeight = getElementHeight(visElem.idx);
- Vector2I offset(x, yOffset);
- yOffset += elemHeight;
- guiMainElement->_setPosition(offset);
- guiMainElement->_setWidth(width);
- guiMainElement->_setHeight(elemHeight);
- guiMainElement->_setAreaDepth(panelDepth);
- guiMainElement->_setWidgetDepth(widgetDepth);
- Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
- guiMainElement->_setClipRect(elemClipRect);
- // Shortcut label
- GUILabel* shortcutLabel = visElem.shortcutLabel;
- if (shortcutLabel != nullptr)
- {
- shortcutLabel->_setPosition(offset);
- shortcutLabel->_setWidth(width);
- shortcutLabel->_setHeight(elemHeight);
- shortcutLabel->_setAreaDepth(panelDepth);
- shortcutLabel->_setWidgetDepth(widgetDepth);
- shortcutLabel->_setClipRect(elemClipRect);
- }
- }
- }
- const String& GUIDropDownContent::getGUITypeName()
- {
- static String typeName = "GUIDropDownContent";
- return typeName;
- }
- }
|