mirror of
https://github.com/OpenMW/openmw.git
synced 2025-10-16 22:46:34 +00:00
Merge branch 'OpenMW:master' into master
This commit is contained in:
commit
51f9ce890e
7 changed files with 42 additions and 143 deletions
|
@ -10,6 +10,7 @@
|
|||
#include <QPair>
|
||||
#include <QProgressDialog>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
@ -202,8 +203,14 @@ Launcher::DataFilesPage::DataFilesPage(const Files::ConfigurationManager& cfg, C
|
|||
// the addons and don't want to get signals of the system doing it during startup.
|
||||
connect(mSelector, &ContentSelectorView::ContentSelector::signalAddonDataChanged, this,
|
||||
&DataFilesPage::slotAddonDataChanged);
|
||||
|
||||
mReloadCellsTimer = new QTimer(this);
|
||||
mReloadCellsTimer->setSingleShot(true);
|
||||
mReloadCellsTimer->setInterval(200);
|
||||
connect(mReloadCellsTimer, &QTimer::timeout, this, &DataFilesPage::onReloadCellsTimerTimeout);
|
||||
|
||||
// Call manually to indicate all changes to addon data during startup.
|
||||
slotAddonDataChanged();
|
||||
onReloadCellsTimerTimeout();
|
||||
}
|
||||
|
||||
Launcher::DataFilesPage::~DataFilesPage()
|
||||
|
@ -1001,6 +1008,11 @@ bool Launcher::DataFilesPage::showDeleteMessageBox(const QString& text)
|
|||
}
|
||||
|
||||
void Launcher::DataFilesPage::slotAddonDataChanged()
|
||||
{
|
||||
mReloadCellsTimer->start();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::onReloadCellsTimerTimeout()
|
||||
{
|
||||
const ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||
QStringList selectedFiles;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
class QSortFilterProxyModel;
|
||||
class QAbstractItemModel;
|
||||
class QMenu;
|
||||
class QTimer;
|
||||
|
||||
namespace Files
|
||||
{
|
||||
|
@ -137,6 +138,7 @@ namespace Launcher
|
|||
std::mutex mReloadCellsMutex;
|
||||
std::condition_variable mStartReloadCells;
|
||||
std::thread mReloadCellsThread;
|
||||
QTimer* mReloadCellsTimer;
|
||||
|
||||
void addArchive(const QString& name, Qt::CheckState selected, int row = -1);
|
||||
void addArchivesFromDir(const QString& dir);
|
||||
|
@ -151,6 +153,7 @@ namespace Launcher
|
|||
void addProfile(const QString& profile, bool setAsCurrent);
|
||||
void checkForDefaultProfile();
|
||||
void populateFileViews(const QString& contentModelName);
|
||||
void onReloadCellsTimerTimeout();
|
||||
void reloadCells();
|
||||
void refreshDataFilesView();
|
||||
void updateNavMeshProgress(int minDataSize);
|
||||
|
|
|
@ -193,15 +193,6 @@ namespace MWMechanics
|
|||
mLevel = level;
|
||||
}
|
||||
|
||||
void CreatureStats::modifyMagicEffects(const MagicEffects& effects)
|
||||
{
|
||||
bool recalc = effects.getOrDefault(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()
|
||||
!= mMagicEffects.getOrDefault(ESM::MagicEffect::FortifyMaximumMagicka).getModifier();
|
||||
mMagicEffects.setModifiers(effects);
|
||||
if (recalc)
|
||||
recalculateMagicka();
|
||||
}
|
||||
|
||||
void CreatureStats::setAiSetting(AiSetting index, Stat<int> value)
|
||||
{
|
||||
mAiSettings[static_cast<std::underlying_type_t<AiSetting>>(index)] = value;
|
||||
|
|
|
@ -155,9 +155,6 @@ namespace MWMechanics
|
|||
|
||||
void setDynamic(int index, const DynamicStat<float>& value);
|
||||
|
||||
/// Set Modifier for each magic effect according to \a effects. Does not touch Base values.
|
||||
void modifyMagicEffects(const MagicEffects& effects);
|
||||
|
||||
void setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; }
|
||||
|
||||
void setAttackType(std::string_view attackType) { mAttackType = attackType; }
|
||||
|
|
|
@ -121,11 +121,6 @@ namespace MWMechanics
|
|||
return *this;
|
||||
}
|
||||
|
||||
void MagicEffects::remove(const EffectKey& key)
|
||||
{
|
||||
mCollection.erase(key);
|
||||
}
|
||||
|
||||
void MagicEffects::add(const EffectKey& key, const EffectParam& param)
|
||||
{
|
||||
Collection::iterator iter = mCollection.find(key);
|
||||
|
@ -145,19 +140,6 @@ namespace MWMechanics
|
|||
mCollection[key].modifyBase(diff);
|
||||
}
|
||||
|
||||
void MagicEffects::setModifiers(const MagicEffects& effects)
|
||||
{
|
||||
for (Collection::iterator it = mCollection.begin(); it != mCollection.end(); ++it)
|
||||
{
|
||||
it->second.setModifier(effects.getOrDefault(it->first).getModifier());
|
||||
}
|
||||
|
||||
for (Collection::const_iterator it = effects.begin(); it != effects.end(); ++it)
|
||||
{
|
||||
mCollection[it->first].setModifier(it->second.getModifier());
|
||||
}
|
||||
}
|
||||
|
||||
EffectParam MagicEffects::getOrDefault(const EffectKey& key) const
|
||||
{
|
||||
return get(key).value_or(EffectParam());
|
||||
|
@ -174,40 +156,6 @@ namespace MWMechanics
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
MagicEffects MagicEffects::diff(const MagicEffects& prev, const MagicEffects& now)
|
||||
{
|
||||
MagicEffects result;
|
||||
|
||||
// adding/changing
|
||||
for (Collection::const_iterator iter(now.begin()); iter != now.end(); ++iter)
|
||||
{
|
||||
Collection::const_iterator other = prev.mCollection.find(iter->first);
|
||||
|
||||
if (other == prev.end())
|
||||
{
|
||||
// adding
|
||||
result.add(iter->first, iter->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// changing
|
||||
result.add(iter->first, iter->second - other->second);
|
||||
}
|
||||
}
|
||||
|
||||
// removing
|
||||
for (Collection::const_iterator iter(prev.begin()); iter != prev.end(); ++iter)
|
||||
{
|
||||
Collection::const_iterator other = now.mCollection.find(iter->first);
|
||||
if (other == now.end())
|
||||
{
|
||||
result.add(iter->first, EffectParam() - iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MagicEffects::writeState(ESM::MagicEffects& state) const
|
||||
{
|
||||
for (const auto& [key, params] : mCollection)
|
||||
|
|
|
@ -103,19 +103,12 @@ namespace MWMechanics
|
|||
void writeState(ESM::MagicEffects& state) const;
|
||||
|
||||
void add(const EffectKey& key, const EffectParam& param);
|
||||
void remove(const EffectKey& key);
|
||||
|
||||
void modifyBase(const EffectKey& key, int diff);
|
||||
|
||||
/// Copy Modifier values from \a effects, but keep original mBase values.
|
||||
void setModifiers(const MagicEffects& effects);
|
||||
|
||||
EffectParam getOrDefault(const EffectKey& key) const;
|
||||
std::optional<EffectParam> get(const EffectKey& key) const;
|
||||
///< This function can safely be used for keys that are not present.
|
||||
|
||||
static MagicEffects diff(const MagicEffects& prev, const MagicEffects& now);
|
||||
///< Return changes from \a prev to \a now.
|
||||
};
|
||||
|
||||
std::string getMagicEffectString(
|
||||
|
|
|
@ -241,9 +241,6 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
|
|||
return false;
|
||||
|
||||
EsmFile* file = item(index.row());
|
||||
QString fileName = file->fileName();
|
||||
bool success = false;
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::EditRole:
|
||||
|
@ -257,65 +254,23 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
|
|||
file->setFileProperty(EsmFile::FileProperty_GameFile, list.at(i));
|
||||
|
||||
emit dataChanged(index, index);
|
||||
|
||||
success = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::UserRole + 1:
|
||||
{
|
||||
success = (flags(index) & Qt::ItemIsEnabled);
|
||||
|
||||
if (success)
|
||||
{
|
||||
success = setCheckState(file, value.toBool());
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
return isEnabled(index) && setCheckState(file, value.toBool());
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::CheckStateRole:
|
||||
{
|
||||
int checkValue = value.toInt();
|
||||
bool setState = false;
|
||||
if (file->builtIn() || file->fromAnotherConfigFile())
|
||||
{
|
||||
setState = false;
|
||||
success = false;
|
||||
}
|
||||
else if (checkValue == Qt::Checked && !mCheckedFiles.contains(file))
|
||||
{
|
||||
setState = true;
|
||||
success = true;
|
||||
}
|
||||
else if (checkValue == Qt::Checked && mCheckedFiles.contains(file))
|
||||
setState = true;
|
||||
else if (checkValue == Qt::Unchecked)
|
||||
setState = true;
|
||||
|
||||
if (setState)
|
||||
{
|
||||
setCheckState(file, success);
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
else
|
||||
return success;
|
||||
|
||||
for (EsmFile* file2 : mFiles)
|
||||
{
|
||||
if (file2->gameFiles().contains(fileName, Qt::CaseInsensitive))
|
||||
{
|
||||
QModelIndex idx = indexFromItem(file2);
|
||||
emit dataChanged(idx, idx);
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
if (checkValue == Qt::Checked)
|
||||
return mCheckedFiles.contains(file) || setCheckState(file, true);
|
||||
if (checkValue == Qt::Unchecked)
|
||||
return !mCheckedFiles.contains(file) || setCheckState(file, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return success;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContentSelectorModel::ContentModel::insertRows(int position, int rows, const QModelIndex& parent)
|
||||
|
@ -709,6 +664,7 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
|
|||
{
|
||||
// setCheckState already gracefully handles builtIn and fromAnotherConfigFile
|
||||
// as necessary, move plug-ins in visible list to match sequence of supplied filelist
|
||||
// FIXME: setCheckState also does tons of other things which we don't want to happen
|
||||
int filePosition = indexFromItem(file).row();
|
||||
if (filePosition < previousPosition)
|
||||
{
|
||||
|
@ -802,38 +758,37 @@ bool ContentSelectorModel::ContentModel::setCheckState(const EsmFile* file, bool
|
|||
else
|
||||
mCheckedFiles.erase(file);
|
||||
|
||||
emit dataChanged(indexFromItem(file), indexFromItem(file));
|
||||
QModelIndex fileIndex = indexFromItem(file);
|
||||
emit dataChanged(fileIndex, fileIndex);
|
||||
|
||||
// FIXME: this should not happen per-file.
|
||||
// Consider not hiding files if their game is disabled so that this is completely unnecessary.
|
||||
if (file->isGameFile())
|
||||
refreshModel();
|
||||
|
||||
// if we're checking an item, ensure all "upstream" files (dependencies) are checked as well.
|
||||
// Check "upstream" files (dependencies) if the file is checked,
|
||||
// uncheck downstream files if the file is unchecked.
|
||||
// Update the data for downstream files unconditionally (load order warnings).
|
||||
// FIXME: downstream files of toggled upstream/downstream files should be updated, but that would be slow.
|
||||
if (checkState)
|
||||
{
|
||||
for (const QString& upstreamName : file->gameFiles())
|
||||
{
|
||||
const EsmFile* upstreamFile = item(upstreamName);
|
||||
|
||||
if (!upstreamFile)
|
||||
if (upstreamFile == nullptr || !mCheckedFiles.insert(upstreamFile).second)
|
||||
continue;
|
||||
|
||||
mCheckedFiles.insert(upstreamFile);
|
||||
|
||||
emit dataChanged(indexFromItem(upstreamFile), indexFromItem(upstreamFile));
|
||||
QModelIndex upstreamIndex = indexFromItem(upstreamFile);
|
||||
emit dataChanged(upstreamIndex, upstreamIndex);
|
||||
}
|
||||
}
|
||||
// otherwise, if we're unchecking an item (or the file is a game file) ensure all downstream files are unchecked.
|
||||
else
|
||||
for (const EsmFile* otherFile : mFiles)
|
||||
{
|
||||
for (const EsmFile* downstreamFile : mFiles)
|
||||
{
|
||||
if (downstreamFile->gameFiles().contains(file->fileName(), Qt::CaseInsensitive))
|
||||
{
|
||||
mCheckedFiles.erase(downstreamFile);
|
||||
|
||||
emit dataChanged(indexFromItem(downstreamFile), indexFromItem(downstreamFile));
|
||||
}
|
||||
}
|
||||
if (!otherFile->gameFiles().contains(file->fileName(), Qt::CaseInsensitive))
|
||||
continue;
|
||||
if (!checkState)
|
||||
mCheckedFiles.erase(otherFile);
|
||||
QModelIndex otherIndex = indexFromItem(otherFile);
|
||||
emit dataChanged(otherIndex, otherIndex);
|
||||
}
|
||||
|
||||
// Need to manually let Bloodmoon entry know if Tribunal is checked/unchecked
|
||||
|
|
Loading…
Reference in a new issue