From c0f27bd5ef3f1420dd88aef367bc49d4788c9879 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Aug 2012 11:37:33 +0200 Subject: [PATCH] magic selection window --- apps/openmw/mwgui/quickkeysmenu.cpp | 257 +++++++++++++++++- apps/openmw/mwgui/quickkeysmenu.hpp | 13 + .../mygui/openmw_magicselection_dialog.layout | 2 +- 3 files changed, 270 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index a9aa3e616..6739b3d1b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -5,10 +5,33 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/spells.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "windowmanagerimp.hpp" #include "itemselection.hpp" + +namespace +{ + bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right) + { + int cmp = MWWorld::Class::get(left).getName(left).compare( + MWWorld::Class::get(right).getName(right)); + return cmp < 0; + } + + bool sortSpells(const std::string& left, const std::string& right) + { + const ESM::Spell* a = MWBase::Environment::get().getWorld()->getStore().spells.find(left); + const ESM::Spell* b = MWBase::Environment::get().getWorld()->getStore().spells.find(right); + + int cmp = a->name.compare(b->name); + return cmp < 0; + } +} + namespace MWGui { @@ -157,12 +180,35 @@ namespace MWGui void QuickKeysMenu::onAssignMagicItem (MWWorld::Ptr item) { - + onAssignItem(item); + mMagicSelectionDialog->setVisible(false); } void QuickKeysMenu::onAssignMagic (const std::string& spellId) { + MyGUI::Button* button = mQuickKeyButtons[mSelectedIndex]; + while (button->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (button->getChildAt(0)); + + MyGUI::ImageBox* image = button->createWidget("ImageBox", MyGUI::IntCoord(9, 8, 42, 42), MyGUI::Align::Default); + image->setUserString ("ToolTipType", "Spell"); + image->setUserString ("Spell", spellId); + + // use the icon of the first effect + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(spell->effects.list.front().effectID); + std::string path = effect->icon; + int slashPos = path.find("\\"); + path.insert(slashPos+1, "b_"); + path = std::string("icons\\") + path; + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + + image->setImageTexture (path); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); + mMagicSelectionDialog->setVisible(false); } void QuickKeysMenu::onAssignMagicCancel () @@ -222,8 +268,11 @@ namespace MWGui MagicSelectionDialog::MagicSelectionDialog(MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) : WindowModal("openmw_magicselection_dialog.layout", parWindowManager) , mParent(parent) + , mWidth(0) + , mHeight(0) { getWidget(mCancelButton, "CancelButton"); + getWidget(mMagicList, "MagicList"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onCancelButtonClicked); center(); @@ -234,4 +283,210 @@ namespace MWGui mParent->onAssignMagicCancel (); } + void MagicSelectionDialog::open () + { + WindowModal::open(); + + while (mMagicList->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mMagicList->getChildAt (0)); + + mHeight = 0; + + const int spellHeight = 18; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWMechanics::Spells& spells = stats.getSpells(); + + /// \todo lots of copy&pasted code from SpellWindow + + // retrieve powers & spells, sort by name + std::vector spellList; + + for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) + { + spellList.push_back(*it); + } + + std::vector powers; + std::vector::iterator it = spellList.begin(); + while (it != spellList.end()) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + if (spell->data.type == ESM::Spell::ST_Power) + { + powers.push_back(*it); + it = spellList.erase(it); + } + else if (spell->data.type == ESM::Spell::ST_Ability + || spell->data.type == ESM::Spell::ST_Blight + || spell->data.type == ESM::Spell::ST_Curse + || spell->data.type == ESM::Spell::ST_Disease) + { + it = spellList.erase(it); + } + else + ++it; + } + std::sort(powers.begin(), powers.end(), sortSpells); + std::sort(spellList.begin(), spellList.end(), sortSpells); + + // retrieve usable magic items & sort + std::vector items; + for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it) + { + std::string enchantId = MWWorld::Class::get(*it).getEnchantment(*it); + if (enchantId != "") + { + // only add items with "Cast once" or "Cast on use" + const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(enchantId); + int type = enchant->data.type; + if (type != ESM::Enchantment::CastOnce + && type != ESM::Enchantment::WhenUsed) + continue; + + items.push_back(*it); + } + } + std::sort(items.begin(), items.end(), sortItems); + + + int height = estimateHeight(items.size() + powers.size() + spellList.size()); + bool scrollVisible = height > mMagicList->getHeight(); + mWidth = mMagicList->getWidth() - scrollVisible * 18; + + + // powers + addGroup("#{sPowers}", ""); + + for (std::vector::const_iterator it = powers.begin(); it != powers.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + MyGUI::Button* t = mMagicList->createWidget("SpellText", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setCaption(spell->name); + t->setTextAlign(MyGUI::Align::Left); + t->setUserString("ToolTipType", "Spell"); + t->setUserString("Spell", *it); + t->eventMouseWheel += MyGUI::newDelegate(this, &MagicSelectionDialog::onMouseWheel); + t->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onSpellSelected); + + mHeight += spellHeight; + } + + // other spells + addGroup("#{sSpells}", ""); + for (std::vector::const_iterator it = spellList.begin(); it != spellList.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + MyGUI::Button* t = mMagicList->createWidget("SpellText", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setCaption(spell->name); + t->setTextAlign(MyGUI::Align::Left); + t->setUserString("ToolTipType", "Spell"); + t->setUserString("Spell", *it); + t->eventMouseWheel += MyGUI::newDelegate(this, &MagicSelectionDialog::onMouseWheel); + t->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onSpellSelected); + + mHeight += spellHeight; + } + + + // enchanted items + addGroup("#{sMagicItem}", ""); + + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + MWWorld::Ptr item = *it; + + // check if the item is currently equipped (will display in a different color) + bool equipped = false; + for (int i=0; i < MWWorld::InventoryStore::Slots; ++i) + { + if (store.getSlot(i) != store.end() && *store.getSlot(i) == item) + { + equipped = true; + break; + } + } + + MyGUI::Button* t = mMagicList->createWidget(equipped ? "SpellText" : "SpellTextUnequipped", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setCaption(MWWorld::Class::get(item).getName(item)); + t->setTextAlign(MyGUI::Align::Left); + t->setUserData(item); + t->setUserString("ToolTipType", "ItemPtr"); + t->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onEnchantedItemSelected); + t->eventMouseWheel += MyGUI::newDelegate(this, &MagicSelectionDialog::onMouseWheel); + + mHeight += spellHeight; + } + + + mMagicList->setCanvasSize (mWidth, std::max(mMagicList->getHeight(), mHeight)); + + } + + void MagicSelectionDialog::addGroup(const std::string &label, const std::string& label2) + { + if (mMagicList->getChildCount() > 0) + { + MyGUI::ImageBox* separator = mMagicList->createWidget("MW_HLine", + MyGUI::IntCoord(4, mHeight, mWidth-8, 18), + MyGUI::Align::Left | MyGUI::Align::Top); + separator->setNeedMouseFocus(false); + mHeight += 18; + } + + MyGUI::TextBox* groupWidget = mMagicList->createWidget("SandBrightText", + MyGUI::IntCoord(0, mHeight, mWidth, 24), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + groupWidget->setCaptionWithReplacing(label); + groupWidget->setTextAlign(MyGUI::Align::Left); + groupWidget->setNeedMouseFocus(false); + + if (label2 != "") + { + MyGUI::TextBox* groupWidget2 = mMagicList->createWidget("SandBrightText", + MyGUI::IntCoord(0, mHeight, mWidth-4, 24), + MyGUI::Align::Left | MyGUI::Align::Top); + groupWidget2->setCaptionWithReplacing(label2); + groupWidget2->setTextAlign(MyGUI::Align::Right); + groupWidget2->setNeedMouseFocus(false); + } + + mHeight += 24; + } + + + void MagicSelectionDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mMagicList->getViewOffset().top + _rel*0.3 > 0) + mMagicList->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mMagicList->setViewOffset(MyGUI::IntPoint(0, mMagicList->getViewOffset().top + _rel*0.3)); + } + + void MagicSelectionDialog::onEnchantedItemSelected(MyGUI::Widget* _sender) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Ptr item = *_sender->getUserData(); + + mParent->onAssignMagicItem (item); + } + + void MagicSelectionDialog::onSpellSelected(MyGUI::Widget* _sender) + { + mParent->onAssignMagic (_sender->getUserString("Spell")); + } + + int MagicSelectionDialog::estimateHeight(int numSpells) const + { + int height = 0; + height += 24 * 3 + 18 * 2; // group headings + height += numSpells * 18; + return height; + } + } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 496806109..44e48d3b0 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -71,12 +71,25 @@ namespace MWGui public: MagicSelectionDialog(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + virtual void open(); + private: MyGUI::Button* mCancelButton; + MyGUI::ScrollView* mMagicList; + + int mWidth; + int mHeight; QuickKeysMenu* mParent; void onCancelButtonClicked (MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onEnchantedItemSelected(MyGUI::Widget* _sender); + void onSpellSelected(MyGUI::Widget* _sender); + int estimateHeight(int numSpells) const; + + + void addGroup(const std::string& label, const std::string& label2); }; } diff --git a/files/mygui/openmw_magicselection_dialog.layout b/files/mygui/openmw_magicselection_dialog.layout index 7834b0ed9..bf942b32f 100644 --- a/files/mygui/openmw_magicselection_dialog.layout +++ b/files/mygui/openmw_magicselection_dialog.layout @@ -7,7 +7,7 @@ - +