forked from mirror/openmw-tes3mp
Refactor spell window to use model/view and remove duplicated code in QuickKeysMenu
This should also improve window resizing performance, the widgets are now just resized instead of recreated.
This commit is contained in:
parent
7abbca8be9
commit
79237d16a7
13 changed files with 585 additions and 541 deletions
|
@ -40,7 +40,7 @@ add_openmw_dir (mwgui
|
|||
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
||||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow
|
||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "../mwgui/inventorywindow.hpp"
|
||||
|
@ -23,7 +22,8 @@
|
|||
#include "windowmanagerimp.hpp"
|
||||
#include "itemselection.hpp"
|
||||
|
||||
#include "spellwindow.hpp"
|
||||
#include "spellview.hpp"
|
||||
|
||||
|
||||
#include "itemwidget.hpp"
|
||||
#include "sortfilteritemmodel.hpp"
|
||||
|
@ -495,13 +495,15 @@ namespace MWGui
|
|||
MagicSelectionDialog::MagicSelectionDialog(QuickKeysMenu* parent)
|
||||
: WindowModal("openmw_magicselection_dialog.layout")
|
||||
, mParent(parent)
|
||||
, mWidth(0)
|
||||
, mHeight(0)
|
||||
{
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mMagicList, "MagicList");
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onCancelButtonClicked);
|
||||
|
||||
mMagicList->setShowCostColumn(false);
|
||||
mMagicList->setHighlightSelected(false);
|
||||
mMagicList->eventSpellClicked += MyGUI::newDelegate(this, &MagicSelectionDialog::onModelIndexSelected);
|
||||
|
||||
center();
|
||||
}
|
||||
|
||||
|
@ -519,211 +521,17 @@ namespace MWGui
|
|||
{
|
||||
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()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
|
||||
/// \todo lots of copy&pasted code from SpellWindow
|
||||
|
||||
// retrieve powers & spells, sort by name
|
||||
std::vector<std::string> spellList;
|
||||
|
||||
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||
{
|
||||
spellList.push_back (it->first);
|
||||
mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
||||
mMagicList->update();
|
||||
}
|
||||
|
||||
const MWWorld::ESMStore &esmStore =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
std::vector<std::string> powers;
|
||||
std::vector<std::string>::iterator it = spellList.begin();
|
||||
while (it != spellList.end())
|
||||
void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index)
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(*it);
|
||||
if (spell->mData.mType == ESM::Spell::ST_Power)
|
||||
{
|
||||
powers.push_back(*it);
|
||||
it = spellList.erase(it);
|
||||
}
|
||||
else if (spell->mData.mType == ESM::Spell::ST_Ability
|
||||
|| spell->mData.mType == ESM::Spell::ST_Blight
|
||||
|| spell->mData.mType == ESM::Spell::ST_Curse
|
||||
|| spell->mData.mType == ESM::Spell::ST_Disease)
|
||||
{
|
||||
it = spellList.erase(it);
|
||||
}
|
||||
const Spell& spell = mMagicList->getModel()->getItem(index);
|
||||
if (spell.mType == Spell::Type_EnchantedItem)
|
||||
mParent->onAssignMagicItem(spell.mItem);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
std::sort(powers.begin(), powers.end(), sortSpells);
|
||||
std::sort(spellList.begin(), spellList.end(), sortSpells);
|
||||
|
||||
// retrieve usable magic items & sort
|
||||
std::vector<MWWorld::Ptr> items;
|
||||
for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it)
|
||||
{
|
||||
std::string enchantId = it->getClass().getEnchantment(*it);
|
||||
if (enchantId != "")
|
||||
{
|
||||
// only add items with "Cast once" or "Cast on use"
|
||||
const ESM::Enchantment* enchant =
|
||||
esmStore.get<ESM::Enchantment>().find(enchantId);
|
||||
|
||||
int type = enchant->mData.mType;
|
||||
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<std::string>::const_iterator it = powers.begin(); it != powers.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(*it);
|
||||
MyGUI::Button* t = mMagicList->createWidget<MyGUI::Button>("SandTextButton",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(spell->mName);
|
||||
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<std::string>::const_iterator it = spellList.begin(); it != spellList.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(*it);
|
||||
MyGUI::Button* t = mMagicList->createWidget<MyGUI::Button>("SandTextButton",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(spell->mName);
|
||||
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<MWWorld::Ptr>::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<MyGUI::Button>(equipped ? "SandTextButton" : "SpellTextUnequipped",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(item.getClass().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;
|
||||
}
|
||||
|
||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||
mMagicList->setVisibleVScroll(false);
|
||||
mMagicList->setCanvasSize (mWidth, std::max(mMagicList->getHeight(), mHeight));
|
||||
mMagicList->setVisibleVScroll(true);
|
||||
}
|
||||
|
||||
void MagicSelectionDialog::addGroup(const std::string &label, const std::string& label2)
|
||||
{
|
||||
if (mMagicList->getChildCount() > 0)
|
||||
{
|
||||
MyGUI::ImageBox* separator = mMagicList->createWidget<MyGUI::ImageBox>("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<MyGUI::TextBox>("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<MyGUI::TextBox>("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 item = *_sender->getUserData<MWWorld::Ptr>();
|
||||
|
||||
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;
|
||||
mParent->onAssignMagic(spell.mId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "windowbase.hpp"
|
||||
|
||||
#include "spellmodel.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -12,6 +14,7 @@ namespace MWGui
|
|||
class ItemSelectionDialog;
|
||||
class MagicSelectionDialog;
|
||||
class ItemWidget;
|
||||
class SpellView;
|
||||
|
||||
class QuickKeysMenu : public WindowBase
|
||||
{
|
||||
|
@ -94,21 +97,12 @@ namespace MWGui
|
|||
|
||||
private:
|
||||
MyGUI::Button* mCancelButton;
|
||||
MyGUI::ScrollView* mMagicList;
|
||||
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
SpellView* mMagicList;
|
||||
|
||||
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);
|
||||
void onModelIndexSelected(SpellModel::ModelIndex index);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
140
apps/openmw/mwgui/spellmodel.cpp
Normal file
140
apps/openmw/mwgui/spellmodel.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include "spellmodel.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool sortSpells(const MWGui::Spell& left, const MWGui::Spell& right)
|
||||
{
|
||||
if (left.mType != right.mType)
|
||||
return left.mType < right.mType;
|
||||
|
||||
int cmp = left.mName.compare(right.mName);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
SpellModel::SpellModel(const MWWorld::Ptr &actor)
|
||||
: mActor(actor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SpellModel::update()
|
||||
{
|
||||
mSpells.clear();
|
||||
|
||||
MWMechanics::CreatureStats& stats = mActor.getClass().getCreatureStats(mActor);
|
||||
const MWMechanics::Spells& spells = stats.getSpells();
|
||||
|
||||
const MWWorld::ESMStore &esmStore =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(it->first);
|
||||
if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell)
|
||||
continue;
|
||||
|
||||
Spell newSpell;
|
||||
newSpell.mName = spell->mName;
|
||||
if (spell->mData.mType == ESM::Spell::ST_Spell)
|
||||
{
|
||||
newSpell.mType = Spell::Type_Spell;
|
||||
std::string cost = boost::lexical_cast<std::string>(spell->mData.mCost);
|
||||
std::string chance = boost::lexical_cast<std::string>(int(MWMechanics::getSpellSuccessChance(spell, mActor)));
|
||||
newSpell.mCostColumn = cost + "/" + chance;
|
||||
}
|
||||
else
|
||||
newSpell.mType = Spell::Type_Power;
|
||||
newSpell.mId = it->first;
|
||||
|
||||
newSpell.mSelected = (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == it->first);
|
||||
newSpell.mActive = true;
|
||||
mSpells.push_back(newSpell);
|
||||
}
|
||||
|
||||
MWWorld::InventoryStore& invStore = mActor.getClass().getInventoryStore(mActor);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
MWWorld::Ptr item = *it;
|
||||
const std::string enchantId = item.getClass().getEnchantment(item);
|
||||
if (enchantId.empty())
|
||||
continue;
|
||||
const ESM::Enchantment* enchant =
|
||||
esmStore.get<ESM::Enchantment>().find(item.getClass().getEnchantment(item));
|
||||
if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce)
|
||||
continue;
|
||||
|
||||
Spell newSpell;
|
||||
newSpell.mItem = item;
|
||||
newSpell.mId = item.getClass().getId(item);
|
||||
newSpell.mName = item.getClass().getName(item);
|
||||
newSpell.mType = Spell::Type_EnchantedItem;
|
||||
newSpell.mSelected = invStore.getSelectedEnchantItem() == it;
|
||||
|
||||
// FIXME: move to mwmechanics
|
||||
if (enchant->mData.mType == ESM::Enchantment::CastOnce)
|
||||
{
|
||||
newSpell.mCostColumn = "100/100";
|
||||
newSpell.mActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float enchantCost = enchant->mData.mCost;
|
||||
int eSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Enchant);
|
||||
int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
|
||||
|
||||
std::string cost = boost::lexical_cast<std::string>(castCost);
|
||||
int currentCharge = int(item.getCellRef().getEnchantmentCharge());
|
||||
if (currentCharge == -1)
|
||||
currentCharge = enchant->mData.mCharge;
|
||||
std::string charge = boost::lexical_cast<std::string>(currentCharge);
|
||||
newSpell.mCostColumn = cost + "/" + charge;
|
||||
|
||||
bool equipped = false;
|
||||
for (int i=0; i < MWWorld::InventoryStore::Slots; ++i)
|
||||
{
|
||||
if (invStore.getSlot(i) != invStore.end() && *invStore.getSlot(i) == item)
|
||||
{
|
||||
equipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newSpell.mActive = equipped;
|
||||
}
|
||||
mSpells.push_back(newSpell);
|
||||
}
|
||||
|
||||
std::stable_sort(mSpells.begin(), mSpells.end(), sortSpells);
|
||||
}
|
||||
|
||||
size_t SpellModel::getItemCount() const
|
||||
{
|
||||
return mSpells.size();
|
||||
}
|
||||
|
||||
Spell SpellModel::getItem(ModelIndex index) const
|
||||
{
|
||||
if (index < 0 || index >= int(mSpells.size()))
|
||||
throw std::runtime_error("invalid spell index supplied");
|
||||
return mSpells[index];
|
||||
}
|
||||
|
||||
}
|
56
apps/openmw/mwgui/spellmodel.hpp
Normal file
56
apps/openmw/mwgui/spellmodel.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef OPENMW_GUI_SPELLMODEL_H
|
||||
#define OPENMW_GUI_SPELLMODEL_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
struct Spell
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
Type_Power,
|
||||
Type_Spell,
|
||||
Type_EnchantedItem
|
||||
};
|
||||
|
||||
Type mType;
|
||||
std::string mName;
|
||||
std::string mCostColumn; // Cost/chance or Cost/charge
|
||||
std::string mId; // Item ID or spell ID
|
||||
MWWorld::Ptr mItem; // Only for Type_EnchantedItem
|
||||
bool mSelected; // Is this the currently selected spell/item (only one can be selected at a time)
|
||||
bool mActive; // (Items only) is the item equipped?
|
||||
|
||||
Spell()
|
||||
: mSelected(false)
|
||||
, mActive(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
///@brief Model that lists all usable powers, spells and enchanted items for an actor.
|
||||
class SpellModel
|
||||
{
|
||||
public:
|
||||
SpellModel(const MWWorld::Ptr& actor);
|
||||
|
||||
typedef int ModelIndex;
|
||||
|
||||
void update();
|
||||
|
||||
Spell getItem (ModelIndex index) const;
|
||||
///< throws for invalid index
|
||||
|
||||
size_t getItemCount() const;
|
||||
|
||||
private:
|
||||
MWWorld::Ptr mActor;
|
||||
|
||||
std::vector<Spell> mSpells;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
255
apps/openmw/mwgui/spellview.cpp
Normal file
255
apps/openmw/mwgui/spellview.cpp
Normal file
|
@ -0,0 +1,255 @@
|
|||
#include "spellview.hpp"
|
||||
|
||||
#include <MyGUI_FactoryManager.h>
|
||||
#include <MyGUI_ScrollView.h>
|
||||
#include <MyGUI_ImageBox.h>
|
||||
#include <MyGUI_Gui.h>
|
||||
|
||||
#include <components/widgets/sharedstatebutton.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
SpellView::SpellView()
|
||||
: mShowCostColumn(true)
|
||||
, mHighlightSelected(true)
|
||||
, mScrollView(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void SpellView::initialiseOverride()
|
||||
{
|
||||
Base::initialiseOverride();
|
||||
|
||||
assignWidget(mScrollView, "ScrollView");
|
||||
if (mScrollView == NULL)
|
||||
throw std::runtime_error("Item view needs a scroll view");
|
||||
|
||||
mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
}
|
||||
|
||||
void SpellView::registerComponents()
|
||||
{
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<SpellView>("Widget");
|
||||
}
|
||||
|
||||
void SpellView::setModel(SpellModel *model)
|
||||
{
|
||||
mModel.reset(model);
|
||||
update();
|
||||
}
|
||||
|
||||
SpellModel* SpellView::getModel()
|
||||
{
|
||||
return mModel.get();
|
||||
}
|
||||
|
||||
void SpellView::setShowCostColumn(bool show)
|
||||
{
|
||||
if (show != mShowCostColumn)
|
||||
{
|
||||
mShowCostColumn = show;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void SpellView::setHighlightSelected(bool highlight)
|
||||
{
|
||||
if (highlight != mHighlightSelected)
|
||||
{
|
||||
mHighlightSelected = highlight;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void SpellView::update()
|
||||
{
|
||||
if (!mModel.get())
|
||||
return;
|
||||
|
||||
mModel->update();
|
||||
|
||||
int curType = -1;
|
||||
|
||||
const int spellHeight = 18;
|
||||
|
||||
mLines.clear();
|
||||
|
||||
while (mScrollView->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0));
|
||||
|
||||
for (SpellModel::ModelIndex i = 0; i<int(mModel->getItemCount()); ++i)
|
||||
{
|
||||
const Spell& spell = mModel->getItem(i);
|
||||
if (curType != spell.mType)
|
||||
{
|
||||
if (spell.mType == Spell::Type_Power)
|
||||
addGroup("#{sPowers}", "");
|
||||
else if (spell.mType == Spell::Type_Spell)
|
||||
addGroup("#{sSpells}", "#{sCostChance}");
|
||||
else
|
||||
addGroup("#{sMagicItem}", "#{sCostCharge}");
|
||||
curType = spell.mType;
|
||||
}
|
||||
|
||||
const std::string skin = spell.mActive ? "SandTextButton" : "SpellTextUnequipped";
|
||||
|
||||
Gui::SharedStateButton* t = mScrollView->createWidget<Gui::SharedStateButton>(skin,
|
||||
MyGUI::IntCoord(0, 0, 0, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(spell.mName);
|
||||
t->setTextAlign(MyGUI::Align::Left);
|
||||
adjustSpellWidget(spell, i, t);
|
||||
|
||||
if (!spell.mCostColumn.empty() && mShowCostColumn)
|
||||
{
|
||||
Gui::SharedStateButton* costChance = mScrollView->createWidget<Gui::SharedStateButton>(skin,
|
||||
MyGUI::IntCoord(0, 0, 0, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
costChance->setCaption(spell.mCostColumn);
|
||||
costChance->setTextAlign(MyGUI::Align::Right);
|
||||
adjustSpellWidget(spell, i, costChance);
|
||||
|
||||
Gui::ButtonGroup group;
|
||||
group.push_back(t);
|
||||
group.push_back(costChance);
|
||||
Gui::SharedStateButton::createButtonGroup(group);
|
||||
|
||||
mLines.push_back(std::make_pair(t, costChance));
|
||||
}
|
||||
else
|
||||
mLines.push_back(std::make_pair(t, (MyGUI::Widget*)NULL));
|
||||
|
||||
t->setStateSelected(spell.mSelected);
|
||||
}
|
||||
|
||||
layoutWidgets();
|
||||
}
|
||||
|
||||
void SpellView::layoutWidgets()
|
||||
{
|
||||
int height = 0;
|
||||
for (std::vector< std::pair<MyGUI::Widget*, MyGUI::Widget*> >::iterator it = mLines.begin();
|
||||
it != mLines.end(); ++it)
|
||||
{
|
||||
height += (it->first)->getHeight();
|
||||
}
|
||||
|
||||
bool scrollVisible = height > mScrollView->getHeight();
|
||||
int width = mScrollView->getWidth() - (scrollVisible ? 18 : 0);
|
||||
|
||||
height = 0;
|
||||
for (std::vector< std::pair<MyGUI::Widget*, MyGUI::Widget*> >::iterator it = mLines.begin();
|
||||
it != mLines.end(); ++it)
|
||||
{
|
||||
int lineHeight = (it->first)->getHeight();
|
||||
(it->first)->setCoord(4, height, width-8, lineHeight);
|
||||
if (it->second)
|
||||
{
|
||||
(it->second)->setCoord(4, height, width-8, lineHeight);
|
||||
MyGUI::TextBox* second = (it->second)->castType<MyGUI::TextBox>(false);
|
||||
if (second)
|
||||
(it->first)->setSize(width-8-second->getTextSize().width, lineHeight);
|
||||
}
|
||||
|
||||
height += lineHeight;
|
||||
}
|
||||
|
||||
// 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(mScrollView->getWidth(), std::max(mScrollView->getHeight(), height));
|
||||
mScrollView->setVisibleVScroll(true);
|
||||
}
|
||||
|
||||
void SpellView::addGroup(const std::string &label, const std::string& label2)
|
||||
{
|
||||
if (mScrollView->getChildCount() > 0)
|
||||
{
|
||||
MyGUI::ImageBox* separator = mScrollView->createWidget<MyGUI::ImageBox>("MW_HLine",
|
||||
MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18),
|
||||
MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
separator->setNeedMouseFocus(false);
|
||||
mLines.push_back(std::make_pair(separator, (MyGUI::Widget*)NULL));
|
||||
}
|
||||
|
||||
MyGUI::TextBox* groupWidget = mScrollView->createWidget<MyGUI::TextBox>("SandBrightText",
|
||||
MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 24),
|
||||
MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
groupWidget->setCaptionWithReplacing(label);
|
||||
groupWidget->setTextAlign(MyGUI::Align::Left);
|
||||
groupWidget->setNeedMouseFocus(false);
|
||||
|
||||
if (label2 != "")
|
||||
{
|
||||
MyGUI::TextBox* groupWidget2 = mScrollView->createWidget<MyGUI::TextBox>("SandBrightText",
|
||||
MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 24),
|
||||
MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
groupWidget2->setCaptionWithReplacing(label2);
|
||||
groupWidget2->setTextAlign(MyGUI::Align::Right);
|
||||
groupWidget2->setNeedMouseFocus(false);
|
||||
|
||||
mLines.push_back(std::make_pair(groupWidget, groupWidget2));
|
||||
}
|
||||
else
|
||||
mLines.push_back(std::make_pair(groupWidget, (MyGUI::Widget*)NULL));
|
||||
}
|
||||
|
||||
|
||||
void SpellView::setSize(const MyGUI::IntSize &_value)
|
||||
{
|
||||
bool changed = (_value.width != getWidth() || _value.height != getHeight());
|
||||
Base::setSize(_value);
|
||||
if (changed)
|
||||
layoutWidgets();
|
||||
}
|
||||
|
||||
void SpellView::setSize(int _width, int _height)
|
||||
{
|
||||
setSize(MyGUI::IntSize(_width, _height));
|
||||
}
|
||||
|
||||
void SpellView::setCoord(const MyGUI::IntCoord &_value)
|
||||
{
|
||||
bool changed = (_value.width != getWidth() || _value.height != getHeight());
|
||||
Base::setCoord(_value);
|
||||
if (changed)
|
||||
layoutWidgets();
|
||||
}
|
||||
|
||||
void SpellView::setCoord(int _left, int _top, int _width, int _height)
|
||||
{
|
||||
setCoord(MyGUI::IntCoord(_left, _top, _width, _height));
|
||||
}
|
||||
|
||||
void SpellView::adjustSpellWidget(const Spell &spell, SpellModel::ModelIndex index, MyGUI::Widget *widget)
|
||||
{
|
||||
if (spell.mType == Spell::Type_EnchantedItem)
|
||||
{
|
||||
widget->setUserData(spell.mItem);
|
||||
widget->setUserString("ToolTipType", "ItemPtr");
|
||||
}
|
||||
else
|
||||
{
|
||||
widget->setUserString("ToolTipType", "Spell");
|
||||
widget->setUserString("Spell", spell.mId);
|
||||
}
|
||||
|
||||
widget->setUserString("SpellModelIndex", MyGUI::utility::toString(index));
|
||||
|
||||
widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheel);
|
||||
widget->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellView::onSpellSelected);
|
||||
}
|
||||
|
||||
void SpellView::onSpellSelected(MyGUI::Widget* _sender)
|
||||
{
|
||||
SpellModel::ModelIndex i = MyGUI::utility::parseInt(_sender->getUserString("SpellModelIndex"));
|
||||
eventSpellClicked(i);
|
||||
}
|
||||
|
||||
void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||
{
|
||||
if (mScrollView->getViewOffset().top + _rel*0.3 > 0)
|
||||
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||
else
|
||||
mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3));
|
||||
}
|
||||
|
||||
}
|
71
apps/openmw/mwgui/spellview.hpp
Normal file
71
apps/openmw/mwgui/spellview.hpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#ifndef OPENMW_GUI_SPELLVIEW_H
|
||||
#define OPENMW_GUI_SPELLVIEW_H
|
||||
|
||||
#include <MyGUI_Widget.h>
|
||||
|
||||
#include "spellmodel.hpp"
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
class ScrollView;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
class SpellModel;
|
||||
|
||||
///@brief Displays a SpellModel in a list widget
|
||||
class SpellView : public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(SpellView)
|
||||
public:
|
||||
SpellView();
|
||||
|
||||
/// Register needed components with MyGUI's factory manager
|
||||
static void registerComponents ();
|
||||
|
||||
/// Should the cost/chance column be shown?
|
||||
void setShowCostColumn(bool show);
|
||||
|
||||
void setHighlightSelected(bool highlight);
|
||||
|
||||
/// Takes ownership of \a model
|
||||
void setModel (SpellModel* model);
|
||||
|
||||
SpellModel* getModel();
|
||||
|
||||
void update();
|
||||
|
||||
typedef MyGUI::delegates::CMultiDelegate1<SpellModel::ModelIndex> EventHandle_ModelIndex;
|
||||
/// Fired when a spell was clicked
|
||||
EventHandle_ModelIndex eventSpellClicked;
|
||||
|
||||
virtual void initialiseOverride();
|
||||
|
||||
virtual void setSize(const MyGUI::IntSize& _value);
|
||||
virtual void setCoord(const MyGUI::IntCoord& _value);
|
||||
void setSize(int _width, int _height);
|
||||
void setCoord(int _left, int _top, int _width, int _height);
|
||||
|
||||
private:
|
||||
MyGUI::ScrollView* mScrollView;
|
||||
|
||||
std::auto_ptr<SpellModel> mModel;
|
||||
|
||||
std::vector< std::pair<MyGUI::Widget*, MyGUI::Widget*> > mLines;
|
||||
|
||||
bool mShowCostColumn;
|
||||
bool mHighlightSelected;
|
||||
|
||||
void layoutWidgets();
|
||||
void addGroup(const std::string& label1, const std::string& label2);
|
||||
void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget);
|
||||
|
||||
void onSpellSelected(MyGUI::Widget* _sender);
|
||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,10 +1,7 @@
|
|||
#include "spellwindow.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <components/widgets/sharedstatebutton.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -19,44 +16,24 @@
|
|||
#include "spellicons.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "confirmationdialog.hpp"
|
||||
#include "spellview.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||
{
|
||||
int cmp = left.getClass().getName(left).compare(
|
||||
right.getClass().getName(right));
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
bool sortSpells(const std::string& left, const std::string& right)
|
||||
{
|
||||
const MWWorld::Store<ESM::Spell> &spells =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
|
||||
|
||||
const ESM::Spell* a = spells.find(left);
|
||||
const ESM::Spell* b = spells.find(right);
|
||||
|
||||
int cmp = a->mName.compare(b->mName);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
SpellWindow::SpellWindow(DragAndDrop* drag)
|
||||
: WindowPinnableBase("openmw_spell_window.layout")
|
||||
, NoDrop(drag, mMainWidget)
|
||||
, mHeight(0)
|
||||
, mWidth(0)
|
||||
, mWindowSize(mMainWidget->getSize())
|
||||
, mSpellView(NULL)
|
||||
{
|
||||
mSpellIcons = new SpellIcons();
|
||||
|
||||
getWidget(mSpellView, "SpellView");
|
||||
getWidget(mEffectBox, "EffectsBox");
|
||||
|
||||
setCoord(498, 300, 302, 300);
|
||||
mSpellView->eventSpellClicked += MyGUI::newDelegate(this, &SpellWindow::onModelIndexSelected);
|
||||
|
||||
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize);
|
||||
setCoord(498, 300, 302, 300);
|
||||
}
|
||||
|
||||
SpellWindow::~SpellWindow()
|
||||
|
@ -84,261 +61,14 @@ namespace MWGui
|
|||
{
|
||||
mSpellIcons->updateWidgets(mEffectBox, false);
|
||||
|
||||
const int spellHeight = 18;
|
||||
|
||||
mHeight = 0;
|
||||
while (mSpellView->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mSpellView->getChildAt(0));
|
||||
|
||||
// retrieve all player spells, divide them into Powers and Spells and sort them
|
||||
std::vector<std::string> spellList;
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
|
||||
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||
spellList.push_back (it->first);
|
||||
|
||||
const MWWorld::ESMStore &esmStore =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
std::vector<std::string> powers;
|
||||
std::vector<std::string>::iterator it = spellList.begin();
|
||||
while (it != spellList.end())
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(*it);
|
||||
|
||||
if (spell->mData.mType == ESM::Spell::ST_Power)
|
||||
{
|
||||
powers.push_back(*it);
|
||||
it = spellList.erase(it);
|
||||
}
|
||||
else if (spell->mData.mType == ESM::Spell::ST_Ability
|
||||
|| spell->mData.mType == ESM::Spell::ST_Blight
|
||||
|| spell->mData.mType == ESM::Spell::ST_Curse
|
||||
|| spell->mData.mType == 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 player's enchanted items
|
||||
std::vector<MWWorld::Ptr> items;
|
||||
for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it)
|
||||
{
|
||||
std::string enchantId = it->getClass().getEnchantment(*it);
|
||||
if (enchantId != "")
|
||||
{
|
||||
// only add items with "Cast once" or "Cast on use"
|
||||
const ESM::Enchantment* enchant =
|
||||
esmStore.get<ESM::Enchantment>().find(enchantId);
|
||||
|
||||
int type = enchant->mData.mType;
|
||||
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 > mSpellView->getHeight();
|
||||
mWidth = mSpellView->getWidth() - (scrollVisible ? 18 : 0);
|
||||
|
||||
// powers
|
||||
addGroup("#{sPowers}", "");
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = powers.begin(); it != powers.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(*it);
|
||||
MyGUI::Button* t = mSpellView->createWidget<MyGUI::Button>("SandTextButton",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(spell->mName);
|
||||
t->setTextAlign(MyGUI::Align::Left);
|
||||
t->setUserString("ToolTipType", "Spell");
|
||||
t->setUserString("Spell", *it);
|
||||
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||
|
||||
if (*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell())
|
||||
t->setStateSelected(true);
|
||||
|
||||
mHeight += spellHeight;
|
||||
mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
||||
mSpellView->update();
|
||||
}
|
||||
|
||||
// other spells
|
||||
addGroup("#{sSpells}", "#{sCostChance}");
|
||||
for (std::vector<std::string>::const_iterator it = spellList.begin(); it != spellList.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = esmStore.get<ESM::Spell>().find(*it);
|
||||
Gui::SharedStateButton* t = mSpellView->createWidget<Gui::SharedStateButton>("SandTextButton",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(spell->mName);
|
||||
t->setTextAlign(MyGUI::Align::Left);
|
||||
t->setUserString("ToolTipType", "Spell");
|
||||
t->setUserString("Spell", *it);
|
||||
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||
|
||||
// cost / success chance
|
||||
Gui::SharedStateButton* costChance = mSpellView->createWidget<Gui::SharedStateButton>("SandTextButton",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
std::string cost = boost::lexical_cast<std::string>(spell->mData.mCost);
|
||||
std::string chance = boost::lexical_cast<std::string>(int(MWMechanics::getSpellSuccessChance(*it, player)));
|
||||
costChance->setCaption(cost + "/" + chance);
|
||||
costChance->setTextAlign(MyGUI::Align::Right);
|
||||
costChance->setUserString("ToolTipType", "Spell");
|
||||
costChance->setUserString("Spell", *it);
|
||||
costChance->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||
costChance->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||
|
||||
t->setSize(mWidth-12-costChance->getTextSize().width, t->getHeight());
|
||||
|
||||
Gui::ButtonGroup group;
|
||||
group.push_back(t);
|
||||
group.push_back(costChance);
|
||||
Gui::SharedStateButton::createButtonGroup(group);
|
||||
|
||||
t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
|
||||
|
||||
mHeight += spellHeight;
|
||||
}
|
||||
|
||||
|
||||
// enchanted items
|
||||
addGroup("#{sMagicItem}", "#{sCostCharge}");
|
||||
|
||||
for (std::vector<MWWorld::Ptr>::const_iterator it = items.begin(); it != items.end(); ++it)
|
||||
{
|
||||
MWWorld::Ptr item = *it;
|
||||
|
||||
const ESM::Enchantment* enchant =
|
||||
esmStore.get<ESM::Enchantment>().find(item.getClass().getEnchantment(item));
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
Gui::SharedStateButton* t = mSpellView->createWidget<Gui::SharedStateButton>(equipped ? "SandTextButton" : "SpellTextUnequipped",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
t->setCaption(item.getClass().getName(item));
|
||||
t->setTextAlign(MyGUI::Align::Left);
|
||||
t->setUserData(item);
|
||||
t->setUserString("ToolTipType", "ItemPtr");
|
||||
t->setUserString("Equipped", equipped ? "true" : "false");
|
||||
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
|
||||
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||
|
||||
// cost / charge
|
||||
Gui::SharedStateButton* costCharge = mSpellView->createWidget<Gui::SharedStateButton>(equipped ? "SandTextButton" : "SpellTextUnequipped",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
|
||||
float enchantCost = enchant->mData.mCost;
|
||||
int eSkill = player.getClass().getSkill(player, ESM::Skill::Enchant);
|
||||
int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
|
||||
|
||||
std::string cost = boost::lexical_cast<std::string>(castCost);
|
||||
int currentCharge = int(item.getCellRef().getEnchantmentCharge());
|
||||
if (currentCharge == -1)
|
||||
currentCharge = enchant->mData.mCharge;
|
||||
std::string charge = boost::lexical_cast<std::string>(currentCharge);
|
||||
if (enchant->mData.mType == ESM::Enchantment::CastOnce)
|
||||
{
|
||||
// this is Morrowind behaviour
|
||||
cost = "100";
|
||||
charge = "100";
|
||||
}
|
||||
|
||||
|
||||
costCharge->setUserData(item);
|
||||
costCharge->setUserString("ToolTipType", "ItemPtr");
|
||||
costCharge->setUserString("Equipped", equipped ? "true" : "false");
|
||||
costCharge->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
|
||||
costCharge->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||
costCharge->setCaption(cost + "/" + charge);
|
||||
costCharge->setTextAlign(MyGUI::Align::Right);
|
||||
|
||||
Gui::ButtonGroup group;
|
||||
group.push_back(t);
|
||||
group.push_back(costCharge);
|
||||
Gui::SharedStateButton::createButtonGroup(group);
|
||||
|
||||
if (store.getSelectedEnchantItem() != store.end())
|
||||
t->setStateSelected(item == *store.getSelectedEnchantItem());
|
||||
|
||||
t->setSize(mWidth-12-costCharge->getTextSize().width, t->getHeight());
|
||||
|
||||
mHeight += spellHeight;
|
||||
}
|
||||
|
||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||
mSpellView->setVisibleVScroll(false);
|
||||
mSpellView->setCanvasSize(mSpellView->getWidth(), std::max(mSpellView->getHeight(), mHeight));
|
||||
mSpellView->setVisibleVScroll(true);
|
||||
}
|
||||
|
||||
void SpellWindow::addGroup(const std::string &label, const std::string& label2)
|
||||
{
|
||||
if (mSpellView->getChildCount() > 0)
|
||||
{
|
||||
MyGUI::ImageBox* separator = mSpellView->createWidget<MyGUI::ImageBox>("MW_HLine",
|
||||
MyGUI::IntCoord(4, mHeight, mWidth-8, 18),
|
||||
MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
separator->setNeedMouseFocus(false);
|
||||
mHeight += 18;
|
||||
}
|
||||
|
||||
MyGUI::TextBox* groupWidget = mSpellView->createWidget<MyGUI::TextBox>("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 = mSpellView->createWidget<MyGUI::TextBox>("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);
|
||||
|
||||
groupWidget->setSize(mWidth-8-groupWidget2->getTextSize().width, groupWidget->getHeight());
|
||||
}
|
||||
|
||||
mHeight += 24;
|
||||
}
|
||||
|
||||
void SpellWindow::onWindowResize(MyGUI::Window* _sender)
|
||||
{
|
||||
if (mMainWidget->getSize() != mWindowSize)
|
||||
{
|
||||
mWindowSize = mMainWidget->getSize();
|
||||
updateSpells();
|
||||
}
|
||||
}
|
||||
|
||||
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
|
||||
void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
|
||||
|
||||
// retrieve ContainerStoreIterator to the item
|
||||
MWWorld::ContainerStoreIterator it = store.begin();
|
||||
|
@ -352,7 +82,7 @@ namespace MWGui
|
|||
assert(it != store.end());
|
||||
|
||||
// equip, if it can be equipped and is not already equipped
|
||||
if (_sender->getUserString("Equipped") == "false"
|
||||
if (!alreadyEquipped
|
||||
&& !item.getClass().getEquipmentSlots(item).first.empty())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
|
||||
|
@ -364,12 +94,21 @@ namespace MWGui
|
|||
updateSpells();
|
||||
}
|
||||
|
||||
void SpellWindow::onSpellSelected(MyGUI::Widget* _sender)
|
||||
void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index)
|
||||
{
|
||||
std::string spellId = _sender->getUserString("Spell");
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
const Spell& spell = mSpellView->getModel()->getItem(index);
|
||||
if (spell.mType == Spell::Type_EnchantedItem)
|
||||
{
|
||||
onEnchantedItemSelected(spell.mItem, spell.mActive);
|
||||
}
|
||||
else
|
||||
{
|
||||
onSpellSelected(spell.mId);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellWindow::onSpellSelected(const std::string& spellId)
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance().isShiftPressed())
|
||||
{
|
||||
// delete spell, if allowed
|
||||
|
@ -396,6 +135,8 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
store.setSelectedEnchantItem(store.end());
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||
}
|
||||
|
@ -403,22 +144,6 @@ namespace MWGui
|
|||
updateSpells();
|
||||
}
|
||||
|
||||
int SpellWindow::estimateHeight(int numSpells) const
|
||||
{
|
||||
int height = 0;
|
||||
height += 24 * 3 + 18 * 2; // group headings
|
||||
height += numSpells * 18;
|
||||
return height;
|
||||
}
|
||||
|
||||
void SpellWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||
{
|
||||
if (mSpellView->getViewOffset().top + _rel*0.3 > 0)
|
||||
mSpellView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||
else
|
||||
mSpellView->setViewOffset(MyGUI::IntPoint(0, mSpellView->getViewOffset().top + _rel*0.3));
|
||||
}
|
||||
|
||||
void SpellWindow::onDeleteSpellAccept()
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
|
|
@ -4,13 +4,12 @@
|
|||
#include "windowpinnablebase.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include "spellmodel.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class SpellIcons;
|
||||
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right);
|
||||
|
||||
bool sortSpells(const std::string& left, const std::string& right);
|
||||
class SpellView;
|
||||
|
||||
class SpellWindow : public WindowPinnableBase, public NoDrop
|
||||
{
|
||||
|
@ -23,30 +22,20 @@ namespace MWGui
|
|||
void onFrame(float dt) { NoDrop::onFrame(dt); }
|
||||
|
||||
protected:
|
||||
MyGUI::ScrollView* mSpellView;
|
||||
MyGUI::Widget* mEffectBox;
|
||||
|
||||
int mHeight;
|
||||
int mWidth;
|
||||
|
||||
MyGUI::IntSize mWindowSize;
|
||||
|
||||
std::string mSpellToDelete;
|
||||
|
||||
void addGroup(const std::string& label, const std::string& label2);
|
||||
|
||||
int estimateHeight(int numSpells) const;
|
||||
|
||||
void onWindowResize(MyGUI::Window* _sender);
|
||||
void onEnchantedItemSelected(MyGUI::Widget* _sender);
|
||||
void onSpellSelected(MyGUI::Widget* _sender);
|
||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||
void onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped);
|
||||
void onSpellSelected(const std::string& spellId);
|
||||
void onModelIndexSelected(SpellModel::ModelIndex index);
|
||||
void onDeleteSpellAccept();
|
||||
|
||||
virtual void onPinToggled();
|
||||
virtual void onTitleDoubleClicked();
|
||||
virtual void open();
|
||||
|
||||
SpellView* mSpellView;
|
||||
SpellIcons* mSpellIcons;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include "itemwidget.hpp"
|
||||
#include "screenfader.hpp"
|
||||
#include "debugwindow.hpp"
|
||||
#include "spellview.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
@ -179,6 +180,7 @@ namespace MWGui
|
|||
BookPage::registerMyGUIComponents ();
|
||||
ItemView::registerComponents();
|
||||
ItemWidget::registerComponents();
|
||||
SpellView::registerComponents();
|
||||
Gui::registerAllWidgets();
|
||||
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Controllers::ControllerRepeatEvent>("Controller");
|
||||
|
|
|
@ -157,6 +157,15 @@
|
|||
</Child>
|
||||
</Resource>
|
||||
|
||||
<Resource type="ResourceSkin" name="MW_SpellView" size="516 516" align="Left Top">
|
||||
<Child type="Widget" skin="MW_Box" offset="0 0 516 516" align="Stretch"/>
|
||||
|
||||
<Child type="ScrollView" skin="MW_ScrollView" offset="3 3 509 509" align="Stretch" name="ScrollView">
|
||||
<Property key="CanvasAlign" value="Left Top"/>
|
||||
<Property key="NeedMouse" value="true"/>
|
||||
</Child>
|
||||
</Resource>
|
||||
|
||||
<Resource type="ResourceSkin" name="MW_SimpleList" size="516 516" align="Left Top">
|
||||
<Property key="ListItemSkin" value="MW_ListLine"/>
|
||||
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
<Widget type="Window" skin="MW_Dialog" position="0 0 330 370" layer="Windows" name="_Main">
|
||||
|
||||
<Widget type="TextBox" skin="SandText" position="8 8 292 24">
|
||||
<Property key="Caption" value="Select a magic to quick key."/>
|
||||
<Property key="Caption" value="#{sMagicSelectTitle}"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="Widget" skin="MW_Box" position="8 38 306 285" name="box" align="Left Top Stretch">
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 298 277" name="MagicList" align="Left Top Stretch">
|
||||
</Widget>
|
||||
<Widget type="SpellView" skin="MW_SpellView" position="8 38 306 285" align="Left Top Stretch" name="MagicList">
|
||||
</Widget>
|
||||
|
||||
<Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton" position="284 330 32 24" align="Right Bottom">
|
||||
|
|
|
@ -10,10 +10,7 @@
|
|||
</Widget>
|
||||
|
||||
<!-- Spell list -->
|
||||
<Widget type="Widget" skin="MW_Box" position="8 38 268 518" align="Left Top Stretch">
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 260 510" align="Left Top Stretch" name="SpellView">
|
||||
<Property key="CanvasAlign" value="Left Top"/>
|
||||
</Widget>
|
||||
<Widget type="SpellView" skin="MW_SpellView" position="8 38 268 518" align="Left Top Stretch" name="SpellView">
|
||||
</Widget>
|
||||
|
||||
</Widget>
|
||||
|
|
Loading…
Reference in a new issue