1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-28 14:53:58 +00:00
OpenMW/apps/openmw/mwgui/birth.cpp
florent.teppe 65cdd489fb create a specific esm reader function for RefID to avoid allocation for string and then again for RefId
Fixed some types

removed useless header

applied clang format

fixed compile tests

fixed clang tidy, and closer to logic before this MR

Removed hardcoded refids

unless there is a returned value we don't use static RefIds
can use == between RefId and hardcoded string

Fix clang format

Fixed a few instances where std::string was used, when only const std::string& was needed

removed unused variable
2022-12-27 19:15:57 +01:00

274 lines
9.2 KiB
C++

#include "birth.hpp"
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_ListBox.h>
#include <MyGUI_ScrollView.h>
#include <components/esm3/loadbsgn.hpp>
#include <components/esm3/loadspel.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp"
#include "ustring.hpp"
#include "widgets.hpp"
namespace
{
bool sortBirthSigns(const std::pair<ESM::RefId, const ESM::BirthSign*>& left,
const std::pair<ESM::RefId, const ESM::BirthSign*>& right)
{
return left.second->mName.compare(right.second->mName) < 0;
}
}
namespace MWGui
{
BirthDialog::BirthDialog()
: WindowModal("openmw_chargen_birth.layout")
{
// Centre dialog
center();
getWidget(mSpellArea, "SpellArea");
getWidget(mBirthImage, "BirthsignImage");
getWidget(mBirthList, "BirthsignList");
mBirthList->setScrollVisible(true);
mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onAccept);
mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
MyGUI::Button* backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked);
MyGUI::Button* okButton;
getWidget(okButton, "OKButton");
okButton->setCaption(toUString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {})));
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked);
updateBirths();
updateSpells();
}
void BirthDialog::setNextButtonShow(bool shown)
{
MyGUI::Button* okButton;
getWidget(okButton, "OKButton");
if (shown)
okButton->setCaption(
toUString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {})));
else
okButton->setCaption(
toUString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {})));
}
void BirthDialog::onOpen()
{
WindowModal::onOpen();
updateBirths();
updateSpells();
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList);
// Show the current birthsign by default
const auto& signId = MWBase::Environment::get().getWorld()->getPlayer().getBirthSign();
if (!signId.empty())
setBirthId(signId);
}
void BirthDialog::setBirthId(const ESM::RefId& birthId)
{
mCurrentBirthId = birthId;
mBirthList->setIndexSelected(MyGUI::ITEM_NONE);
size_t count = mBirthList->getItemCount();
for (size_t i = 0; i < count; ++i)
{
if (ESM::RefId::stringRefId(*mBirthList->getItemDataAt<std::string>(i)) == birthId)
{
mBirthList->setIndexSelected(i);
break;
}
}
updateSpells();
}
// widget controls
void BirthDialog::onOkClicked(MyGUI::Widget* _sender)
{
if (mBirthList->getIndexSelected() == MyGUI::ITEM_NONE)
return;
eventDone(this);
}
void BirthDialog::onAccept(MyGUI::ListBox* _sender, size_t _index)
{
onSelectBirth(_sender, _index);
if (mBirthList->getIndexSelected() == MyGUI::ITEM_NONE)
return;
eventDone(this);
}
void BirthDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
const ESM::RefId birthId = ESM::RefId::stringRefId(*mBirthList->getItemDataAt<std::string>(_index));
if (mCurrentBirthId == birthId)
return;
mCurrentBirthId = birthId;
updateSpells();
}
// update widget content
void BirthDialog::updateBirths()
{
mBirthList->removeAllItems();
const MWWorld::Store<ESM::BirthSign>& signs
= MWBase::Environment::get().getWorld()->getStore().get<ESM::BirthSign>();
// sort by name
std::vector<std::pair<ESM::RefId, const ESM::BirthSign*>> birthSigns;
for (const ESM::BirthSign& sign : signs)
{
birthSigns.emplace_back(sign.mId, &sign);
}
std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns);
int index = 0;
for (auto& birthsignPair : birthSigns)
{
mBirthList->addItem(birthsignPair.second->mName, birthsignPair.first);
if (mCurrentBirthId.empty())
{
mBirthList->setIndexSelected(index);
mCurrentBirthId = birthsignPair.first;
}
else if (birthsignPair.first == mCurrentBirthId)
{
mBirthList->setIndexSelected(index);
}
index++;
}
}
void BirthDialog::updateSpells()
{
for (MyGUI::Widget* widget : mSpellItems)
{
MyGUI::Gui::getInstance().destroyWidget(widget);
}
mSpellItems.clear();
if (mCurrentBirthId.empty())
return;
Widgets::MWSpellPtr spellWidget;
const int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2;
MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), lineHeight);
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
const ESM::BirthSign* birth = store.get<ESM::BirthSign>().find(mCurrentBirthId);
mBirthImage->setImageTexture(Misc::ResourceHelpers::correctTexturePath(
birth->mTexture, MWBase::Environment::get().getResourceSystem()->getVFS()));
std::vector<ESM::RefId> abilities, powers, spells;
std::vector<ESM::RefId>::const_iterator it = birth->mPowers.mList.begin();
std::vector<ESM::RefId>::const_iterator end = birth->mPowers.mList.end();
for (; it != end; ++it)
{
const ESM::RefId& spellId = *it;
const ESM::Spell* spell = store.get<ESM::Spell>().search(spellId);
if (!spell)
continue; // Skip spells which cannot be found
ESM::Spell::SpellType type = static_cast<ESM::Spell::SpellType>(spell->mData.mType);
if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power)
continue; // We only want spell, ability and powers.
if (type == ESM::Spell::ST_Ability)
abilities.push_back(spellId);
else if (type == ESM::Spell::ST_Power)
powers.push_back(spellId);
else if (type == ESM::Spell::ST_Spell)
spells.push_back(spellId);
}
int i = 0;
struct
{
const std::vector<ESM::RefId>& spells;
const char* label;
} categories[3] = { { abilities, "sBirthsignmenu1" }, { powers, "sPowers" }, { spells, "sBirthsignmenu2" } };
for (int category = 0; category < 3; ++category)
{
if (!categories[category].spells.empty())
{
MyGUI::TextBox* label = mSpellArea->createWidget<MyGUI::TextBox>(
"SandBrightText", coord, MyGUI::Align::Default, std::string("Label"));
label->setCaption(toUString(MWBase::Environment::get().getWindowManager()->getGameSettingString(
categories[category].label, {})));
mSpellItems.push_back(label);
coord.top += lineHeight;
end = categories[category].spells.end();
for (it = categories[category].spells.begin(); it != end; ++it)
{
const ESM::RefId& spellId = *it;
spellWidget = mSpellArea->createWidget<Widgets::MWSpell>("MW_StatName", coord,
MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i));
spellWidget->setSpellId(spellId);
mSpellItems.push_back(spellWidget);
coord.top += lineHeight;
MyGUI::IntCoord spellCoord = coord;
spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget
// in the layout as a template?
spellWidget->createEffectWidgets(
mSpellItems, mSpellArea, spellCoord, (category == 0) ? Widgets::MWEffectList::EF_Constant : 0);
coord.top = spellCoord.top;
++i;
}
}
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the
// scrollbar is hidden
mSpellArea->setVisibleVScroll(false);
mSpellArea->setCanvasSize(MyGUI::IntSize(mSpellArea->getWidth(), std::max(mSpellArea->getHeight(), coord.top)));
mSpellArea->setVisibleVScroll(true);
mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0));
}
}