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.
moveref
scrawl 10 years ago
parent 7abbca8be9
commit 79237d16a7

@ -40,7 +40,7 @@ add_openmw_dir (mwgui
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog 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 add_openmw_dir (mwdialogue

@ -13,7 +13,6 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/spells.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwgui/inventorywindow.hpp" #include "../mwgui/inventorywindow.hpp"
@ -23,7 +22,8 @@
#include "windowmanagerimp.hpp" #include "windowmanagerimp.hpp"
#include "itemselection.hpp" #include "itemselection.hpp"
#include "spellwindow.hpp" #include "spellview.hpp"
#include "itemwidget.hpp" #include "itemwidget.hpp"
#include "sortfilteritemmodel.hpp" #include "sortfilteritemmodel.hpp"
@ -495,13 +495,15 @@ namespace MWGui
MagicSelectionDialog::MagicSelectionDialog(QuickKeysMenu* parent) MagicSelectionDialog::MagicSelectionDialog(QuickKeysMenu* parent)
: WindowModal("openmw_magicselection_dialog.layout") : WindowModal("openmw_magicselection_dialog.layout")
, mParent(parent) , mParent(parent)
, mWidth(0)
, mHeight(0)
{ {
getWidget(mCancelButton, "CancelButton"); getWidget(mCancelButton, "CancelButton");
getWidget(mMagicList, "MagicList"); getWidget(mMagicList, "MagicList");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onCancelButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MagicSelectionDialog::onCancelButtonClicked);
mMagicList->setShowCostColumn(false);
mMagicList->setHighlightSelected(false);
mMagicList->eventSpellClicked += MyGUI::newDelegate(this, &MagicSelectionDialog::onModelIndexSelected);
center(); center();
} }
@ -519,211 +521,17 @@ namespace MWGui
{ {
WindowModal::open(); WindowModal::open();
while (mMagicList->getChildCount ()) mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr()));
MyGUI::Gui::getInstance ().destroyWidget (mMagicList->getChildAt (0)); mMagicList->update();
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);
} }
const MWWorld::ESMStore &esmStore = void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index)
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); const Spell& spell = mMagicList->getModel()->getItem(index);
it = spellList.erase(it); if (spell.mType == Spell::Type_EnchantedItem)
} mParent->onAssignMagicItem(spell.mItem);
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 else
++it; mParent->onAssignMagic(spell.mId);
}
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;
} }
} }

@ -5,6 +5,8 @@
#include "windowbase.hpp" #include "windowbase.hpp"
#include "spellmodel.hpp"
namespace MWGui namespace MWGui
{ {
@ -12,6 +14,7 @@ namespace MWGui
class ItemSelectionDialog; class ItemSelectionDialog;
class MagicSelectionDialog; class MagicSelectionDialog;
class ItemWidget; class ItemWidget;
class SpellView;
class QuickKeysMenu : public WindowBase class QuickKeysMenu : public WindowBase
{ {
@ -94,21 +97,12 @@ namespace MWGui
private: private:
MyGUI::Button* mCancelButton; MyGUI::Button* mCancelButton;
MyGUI::ScrollView* mMagicList; SpellView* mMagicList;
int mWidth;
int mHeight;
QuickKeysMenu* mParent; QuickKeysMenu* mParent;
void onCancelButtonClicked (MyGUI::Widget* sender); void onCancelButtonClicked (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onModelIndexSelected(SpellModel::ModelIndex index);
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);
}; };
} }

@ -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];
}
}

@ -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

@ -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));
}
}

@ -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 "spellwindow.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <components/widgets/sharedstatebutton.hpp>
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -19,44 +16,24 @@
#include "spellicons.hpp" #include "spellicons.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
#include "confirmationdialog.hpp" #include "confirmationdialog.hpp"
#include "spellview.hpp"
namespace MWGui 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) SpellWindow::SpellWindow(DragAndDrop* drag)
: WindowPinnableBase("openmw_spell_window.layout") : WindowPinnableBase("openmw_spell_window.layout")
, NoDrop(drag, mMainWidget) , NoDrop(drag, mMainWidget)
, mHeight(0) , mSpellView(NULL)
, mWidth(0)
, mWindowSize(mMainWidget->getSize())
{ {
mSpellIcons = new SpellIcons(); mSpellIcons = new SpellIcons();
getWidget(mSpellView, "SpellView"); getWidget(mSpellView, "SpellView");
getWidget(mEffectBox, "EffectsBox"); 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() SpellWindow::~SpellWindow()
@ -84,261 +61,14 @@ namespace MWGui
{ {
mSpellIcons->updateWidgets(mEffectBox, false); mSpellIcons->updateWidgets(mEffectBox, false);
const int spellHeight = 18; mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr()));
mSpellView->update();
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;
} }
// other spells void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped)
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)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
// retrieve ContainerStoreIterator to the item // retrieve ContainerStoreIterator to the item
MWWorld::ContainerStoreIterator it = store.begin(); MWWorld::ContainerStoreIterator it = store.begin();
@ -352,7 +82,7 @@ namespace MWGui
assert(it != store.end()); assert(it != store.end());
// equip, if it can be equipped and is not already equipped // equip, if it can be equipped and is not already equipped
if (_sender->getUserString("Equipped") == "false" if (!alreadyEquipped
&& !item.getClass().getEquipmentSlots(item).first.empty()) && !item.getClass().getEquipmentSlots(item).first.empty())
{ {
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
@ -364,12 +94,21 @@ namespace MWGui
updateSpells(); updateSpells();
} }
void SpellWindow::onSpellSelected(MyGUI::Widget* _sender) void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index)
{ {
std::string spellId = _sender->getUserString("Spell"); const Spell& spell = mSpellView->getModel()->getItem(index);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (spell.mType == Spell::Type_EnchantedItem)
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); {
onEnchantedItemSelected(spell.mItem, spell.mActive);
}
else
{
onSpellSelected(spell.mId);
}
}
void SpellWindow::onSpellSelected(const std::string& spellId)
{
if (MyGUI::InputManager::getInstance().isShiftPressed()) if (MyGUI::InputManager::getInstance().isShiftPressed())
{ {
// delete spell, if allowed // delete spell, if allowed
@ -396,6 +135,8 @@ namespace MWGui
} }
else else
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
store.setSelectedEnchantItem(store.end()); store.setSelectedEnchantItem(store.end());
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
} }
@ -403,22 +144,6 @@ namespace MWGui
updateSpells(); 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() void SpellWindow::onDeleteSpellAccept()
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();

@ -4,13 +4,12 @@
#include "windowpinnablebase.hpp" #include "windowpinnablebase.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "spellmodel.hpp"
namespace MWGui namespace MWGui
{ {
class SpellIcons; class SpellIcons;
class SpellView;
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right);
bool sortSpells(const std::string& left, const std::string& right);
class SpellWindow : public WindowPinnableBase, public NoDrop class SpellWindow : public WindowPinnableBase, public NoDrop
{ {
@ -23,30 +22,20 @@ namespace MWGui
void onFrame(float dt) { NoDrop::onFrame(dt); } void onFrame(float dt) { NoDrop::onFrame(dt); }
protected: protected:
MyGUI::ScrollView* mSpellView;
MyGUI::Widget* mEffectBox; MyGUI::Widget* mEffectBox;
int mHeight;
int mWidth;
MyGUI::IntSize mWindowSize;
std::string mSpellToDelete; std::string mSpellToDelete;
void addGroup(const std::string& label, const std::string& label2); void onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped);
void onSpellSelected(const std::string& spellId);
int estimateHeight(int numSpells) const; void onModelIndexSelected(SpellModel::ModelIndex index);
void onWindowResize(MyGUI::Window* _sender);
void onEnchantedItemSelected(MyGUI::Widget* _sender);
void onSpellSelected(MyGUI::Widget* _sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void onDeleteSpellAccept(); void onDeleteSpellAccept();
virtual void onPinToggled(); virtual void onPinToggled();
virtual void onTitleDoubleClicked(); virtual void onTitleDoubleClicked();
virtual void open(); virtual void open();
SpellView* mSpellView;
SpellIcons* mSpellIcons; SpellIcons* mSpellIcons;
}; };
} }

@ -73,6 +73,7 @@
#include "itemwidget.hpp" #include "itemwidget.hpp"
#include "screenfader.hpp" #include "screenfader.hpp"
#include "debugwindow.hpp" #include "debugwindow.hpp"
#include "spellview.hpp"
namespace MWGui namespace MWGui
{ {
@ -179,6 +180,7 @@ namespace MWGui
BookPage::registerMyGUIComponents (); BookPage::registerMyGUIComponents ();
ItemView::registerComponents(); ItemView::registerComponents();
ItemWidget::registerComponents(); ItemWidget::registerComponents();
SpellView::registerComponents();
Gui::registerAllWidgets(); Gui::registerAllWidgets();
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Controllers::ControllerRepeatEvent>("Controller"); MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Controllers::ControllerRepeatEvent>("Controller");

@ -157,6 +157,15 @@
</Child> </Child>
</Resource> </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"> <Resource type="ResourceSkin" name="MW_SimpleList" size="516 516" align="Left Top">
<Property key="ListItemSkin" value="MW_ListLine"/> <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="Window" skin="MW_Dialog" position="0 0 330 370" layer="Windows" name="_Main">
<Widget type="TextBox" skin="SandText" position="8 8 292 24"> <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>
<Widget type="Widget" skin="MW_Box" position="8 38 306 285" name="box" align="Left Top Stretch"> <Widget type="SpellView" skin="MW_SpellView" position="8 38 306 285" align="Left Top Stretch" name="MagicList">
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 298 277" name="MagicList" align="Left Top Stretch">
</Widget>
</Widget> </Widget>
<Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton" position="284 330 32 24" align="Right Bottom"> <Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton" position="284 330 32 24" align="Right Bottom">

@ -10,10 +10,7 @@
</Widget> </Widget>
<!-- Spell list --> <!-- Spell list -->
<Widget type="Widget" skin="MW_Box" position="8 38 268 518" align="Left Top Stretch"> <Widget type="SpellView" skin="MW_SpellView" position="8 38 268 518" align="Left Top Stretch" name="SpellView">
<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> </Widget>
</Widget> </Widget>

Loading…
Cancel
Save