#include "list.hpp" #include #include #include #include namespace Gui { MWList::MWList() : mScrollView(nullptr) , mClient(nullptr) , mItemHeight(0) { } void MWList::initialiseOverride() { Base::initialiseOverride(); assignWidget(mClient, "Client"); if (mClient == nullptr) mClient = this; mScrollView = mClient->createWidgetReal("MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); } void MWList::addItem(std::string_view name) { mItems.emplace_back(name); } void MWList::addSeparator() { mItems.emplace_back(std::string{}); } void MWList::adjustSize() { redraw(); } void MWList::redraw(bool scrollbarShown) { constexpr int _scrollBarWidth = 20; // fetch this from skin? const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; constexpr int spacing = 3; int viewPosition = -mScrollView->getViewOffset().top; while (mScrollView->getChildCount()) { MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); } mItemHeight = 0; int i = 0; for (const auto& item : mItems) { if (!item.empty()) { if (mListItemSkin.empty()) return; MyGUI::Button* button = mScrollView->createWidget(mListItemSkin, MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + item); button->setCaption(item); button->getSubWidgetText()->setWordWrap(true); button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheelMoved); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); button->setNeedKeyFocus(true); int height = button->getTextSize().height; button->setSize(MyGUI::IntSize(button->getSize().width, height)); button->setUserData(i); mItemHeight += height + spacing; } else { MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth() - scrollBarWidth - 4, 18), MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); separator->setNeedMouseFocus(false); mItemHeight += 18 + spacing; } ++i; } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mScrollView->setVisibleVScroll(false); mScrollView->setCanvasSize(mClient->getSize().width, std::max(mItemHeight, mClient->getSize().height)); mScrollView->setVisibleVScroll(true); if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); int viewRange = mScrollView->getCanvasSize().height; if (viewPosition > viewRange) viewPosition = viewRange; mScrollView->setViewOffset(MyGUI::IntPoint(0, -viewPosition)); } void MWList::setPropertyOverride(std::string_view _key, std::string_view _value) { if (_key == "ListItemSkin") mListItemSkin = _value; else Base::setPropertyOverride(_key, _value); } size_t MWList::getItemCount() { return mItems.size(); } const std::string& MWList::getItemNameAt(size_t at) { assert(at < mItems.size() && "List item out of bounds"); return mItems[at]; } void MWList::sort() { // A special case for separators is not needed for now std::sort(mItems.begin(), mItems.end(), Misc::StringUtils::ciLess); } void MWList::removeItem(const std::string& name) { auto it = std::find(mItems.begin(), mItems.end(), name); assert(it != mItems.end()); mItems.erase(it); } void MWList::clear() { mItems.clear(); } void MWList::onMouseWheelMoved(MyGUI::Widget* _sender, int _rel) { // NB view offset is negative if (mScrollView->getViewOffset().top + _rel * 0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else mScrollView->setViewOffset( MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel * 0.3))); } void MWList::onItemSelected(MyGUI::Widget* _sender) { std::string name = _sender->castType()->getCaption(); int id = *_sender->getUserData(); eventItemSelected(name, id); eventWidgetSelected(_sender); } MyGUI::Button* MWList::getItemWidget(std::string_view name) { std::string search = getName() + "_item_"; search += name; return mScrollView->findWidget(search)->castType(); } void MWList::scrollToTop() { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } }