mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-31 14:36:39 +00:00
updating region map on changes to region and cell records
This commit is contained in:
parent
d389b70ec4
commit
c808bf2b23
2 changed files with 337 additions and 36 deletions
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
#include "regionmap.hpp"
|
#include "regionmap.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
@ -10,14 +12,20 @@
|
||||||
|
|
||||||
CSMWorld::RegionMap::CellDescription::CellDescription() : mDeleted (false) {}
|
CSMWorld::RegionMap::CellDescription::CellDescription() : mDeleted (false) {}
|
||||||
|
|
||||||
std::pair<int, int> CSMWorld::RegionMap::getIndex (const QModelIndex& index) const
|
CSMWorld::RegionMap::CellIndex CSMWorld::RegionMap::getIndex (const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
return CellIndex (index.column()+mMin.first, index.row()+mMin.second);
|
return CellIndex (index.column()+mMin.first, index.row()+mMin.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::buildRegions (Data& data)
|
QModelIndex CSMWorld::RegionMap::getIndex (const CellIndex& index) const
|
||||||
{
|
{
|
||||||
const IdCollection<ESM::Region>& regions = data.getRegions();
|
// I hate you, Qt API naming scheme!
|
||||||
|
return QAbstractTableModel::index (index.second-mMin.second, index.first-mMin.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::buildRegions()
|
||||||
|
{
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
int size = regions.getSize();
|
int size = regions.getSize();
|
||||||
|
|
||||||
|
@ -31,14 +39,12 @@ void CSMWorld::RegionMap::buildRegions (Data& data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::buildMap (Data& data)
|
void CSMWorld::RegionMap::buildMap()
|
||||||
{
|
{
|
||||||
const IdCollection<Cell>& cells = data.getCells();
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
int size = cells.getSize();
|
int size = cells.getSize();
|
||||||
|
|
||||||
mMin = mMax = std::make_pair (0, 0);
|
|
||||||
|
|
||||||
for (int i=0; i<size; ++i)
|
for (int i=0; i<size; ++i)
|
||||||
{
|
{
|
||||||
const Record<Cell>& cell = cells.getRecord (i);
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
@ -56,33 +62,237 @@ void CSMWorld::RegionMap::buildMap (Data& data)
|
||||||
|
|
||||||
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
if (mMap.empty())
|
mMap.insert (std::make_pair (index, description));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<CellIndex, CellIndex> mapSize = getSize();
|
||||||
|
|
||||||
|
mMin = mapSize.first;
|
||||||
|
mMax = mapSize.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::addCell (const CellIndex& index, const CellDescription& description)
|
||||||
|
{
|
||||||
|
std::map<CellIndex, CellDescription>::iterator cell = mMap.find (index);
|
||||||
|
|
||||||
|
if (cell!=mMap.end())
|
||||||
{
|
{
|
||||||
mMin = index;
|
cell->second = description;
|
||||||
mMax = std::make_pair (mMin.first+1, mMin.second+1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (index.first<mMin.first)
|
updateSize();
|
||||||
mMin.first = index.first;
|
|
||||||
else if (index.first>=mMax.first)
|
|
||||||
mMax.first = index.first + 1;
|
|
||||||
|
|
||||||
if (index.second<mMin.second)
|
|
||||||
mMin.second = index.second;
|
|
||||||
else if (index.second>=mMax.second)
|
|
||||||
mMax.second = index.second + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mMap.insert (std::make_pair (index, description));
|
mMap.insert (std::make_pair (index, description));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QModelIndex index2 = getIndex (index);
|
||||||
|
|
||||||
|
dataChanged (index2, index2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::addCells (int start, int end)
|
||||||
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
CellDescription description;
|
||||||
|
|
||||||
|
if (cell.isDeleted())
|
||||||
|
description.mDeleted = true;
|
||||||
|
else
|
||||||
|
description.mRegion = cell2.mRegion;
|
||||||
|
|
||||||
|
addCell (index, description);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::RegionMap::RegionMap (Data& data)
|
void CSMWorld::RegionMap::removeCell (const CellIndex& index)
|
||||||
{
|
{
|
||||||
buildRegions (data);
|
std::map<CellIndex, CellDescription>::iterator cell = mMap.find (index);
|
||||||
buildMap (data);
|
|
||||||
|
if (cell!=mMap.end())
|
||||||
|
{
|
||||||
|
mMap.erase (cell);
|
||||||
|
|
||||||
|
QModelIndex index2 = getIndex (index);
|
||||||
|
|
||||||
|
dataChanged (index2, index2);
|
||||||
|
|
||||||
|
updateSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::addRegion (const std::string& region, unsigned int colour)
|
||||||
|
{
|
||||||
|
mColours[Misc::StringUtils::lowerCase (region)] = colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::removeRegion (const std::string& region)
|
||||||
|
{
|
||||||
|
std::map<std::string, unsigned int>::iterator iter (
|
||||||
|
mColours.find (Misc::StringUtils::lowerCase (region)));
|
||||||
|
|
||||||
|
if (iter!=mColours.end())
|
||||||
|
mColours.erase (iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::updateRegions (const std::vector<std::string>& regions)
|
||||||
|
{
|
||||||
|
std::vector<std::string> regions2 (regions);
|
||||||
|
|
||||||
|
std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase);
|
||||||
|
std::sort (regions2.begin(), regions2.end());
|
||||||
|
|
||||||
|
for (std::map<CellIndex, CellDescription>::const_iterator iter (mMap.begin());
|
||||||
|
iter!=mMap.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (!iter->second.mRegion.empty() &&
|
||||||
|
std::find (regions2.begin(), regions2.end(),
|
||||||
|
Misc::StringUtils::lowerCase (iter->second.mRegion))!=regions2.end())
|
||||||
|
{
|
||||||
|
QModelIndex index = getIndex (iter->first);
|
||||||
|
|
||||||
|
dataChanged (index, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::updateSize()
|
||||||
|
{
|
||||||
|
std::pair<CellIndex, CellIndex> size = getSize();
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.first.first - mMin.first;
|
||||||
|
|
||||||
|
if (diff<0)
|
||||||
|
{
|
||||||
|
beginInsertColumns (QModelIndex(), 0, -diff-1);
|
||||||
|
mMin.first = size.first.first;
|
||||||
|
endInsertColumns();
|
||||||
|
}
|
||||||
|
else if (diff>0)
|
||||||
|
{
|
||||||
|
beginRemoveColumns (QModelIndex(), 0, diff-1);
|
||||||
|
mMin.first = size.first.first;
|
||||||
|
endRemoveColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.first.second - mMin.second;
|
||||||
|
|
||||||
|
if (diff<0)
|
||||||
|
{
|
||||||
|
beginInsertRows (QModelIndex(), 0, -diff-1);
|
||||||
|
mMin.second = size.first.second;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
else if (diff>0)
|
||||||
|
{
|
||||||
|
beginRemoveRows (QModelIndex(), 0, diff-1);
|
||||||
|
mMin.second = size.first.second;
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.second.first - mMax.first;
|
||||||
|
|
||||||
|
if (diff>0)
|
||||||
|
{
|
||||||
|
int columns = columnCount();
|
||||||
|
beginInsertColumns (QModelIndex(), columns, columns+diff-1);
|
||||||
|
mMax.first = size.second.first;
|
||||||
|
endInsertColumns();
|
||||||
|
}
|
||||||
|
else if (diff<0)
|
||||||
|
{
|
||||||
|
int columns = columnCount();
|
||||||
|
beginRemoveColumns (QModelIndex(), columns+diff, columns-1);
|
||||||
|
mMax.first = size.second.first;
|
||||||
|
endRemoveColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.second.second - mMax.second;
|
||||||
|
|
||||||
|
if (diff>0)
|
||||||
|
{
|
||||||
|
int rows = rowCount();
|
||||||
|
beginInsertRows (QModelIndex(), rows, rows+diff-1);
|
||||||
|
mMax.second = size.second.second;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
else if (diff<0)
|
||||||
|
{
|
||||||
|
int rows = rowCount();
|
||||||
|
beginRemoveRows (QModelIndex(), rows+diff, rows-1);
|
||||||
|
mMax.second = size.second.second;
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<CSMWorld::RegionMap::CellIndex, CSMWorld::RegionMap::CellIndex> CSMWorld::RegionMap::getSize()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
int size = cells.getSize();
|
||||||
|
|
||||||
|
CellIndex min (0, 0);
|
||||||
|
CellIndex max (0, 0);
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
if (min==max)
|
||||||
|
{
|
||||||
|
min = index;
|
||||||
|
max = std::make_pair (min.first+1, min.second+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (index.first<min.first)
|
||||||
|
min.first = index.first;
|
||||||
|
else if (index.first>=max.first)
|
||||||
|
max.first = index.first + 1;
|
||||||
|
|
||||||
|
if (index.second<min.second)
|
||||||
|
min.second = index.second;
|
||||||
|
else if (index.second>=max.second)
|
||||||
|
max.second = index.second + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::RegionMap::RegionMap (Data& data) : mData (data)
|
||||||
|
{
|
||||||
|
buildRegions();
|
||||||
|
buildMap();
|
||||||
|
|
||||||
QAbstractItemModel *regions = data.getTableModel (UniversalId (UniversalId::Type_Regions));
|
QAbstractItemModel *regions = data.getTableModel (UniversalId (UniversalId::Type_Regions));
|
||||||
|
|
||||||
|
@ -96,11 +306,11 @@ CSMWorld::RegionMap::RegionMap (Data& data)
|
||||||
QAbstractItemModel *cells = data.getTableModel (UniversalId (UniversalId::Type_Cells));
|
QAbstractItemModel *cells = data.getTableModel (UniversalId (UniversalId::Type_Cells));
|
||||||
|
|
||||||
connect (cells, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
connect (cells, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (regionsAboutToBeRemoved (const QModelIndex&, int, int)));
|
this, SLOT (cellsAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
this, SLOT (regionsInserted (const QModelIndex&, int, int)));
|
this, SLOT (cellsInserted (const QModelIndex&, int, int)));
|
||||||
connect (cells, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
connect (cells, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
this, SLOT (regionsChanged (const QModelIndex&, const QModelIndex&)));
|
this, SLOT (cellsChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMWorld::RegionMap::rowCount (const QModelIndex& parent) const
|
int CSMWorld::RegionMap::rowCount (const QModelIndex& parent) const
|
||||||
|
@ -166,35 +376,95 @@ Qt::ItemFlags CSMWorld::RegionMap::flags (const QModelIndex& index) const
|
||||||
|
|
||||||
void CSMWorld::RegionMap::regionsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
void CSMWorld::RegionMap::regionsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> update;
|
||||||
|
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
update.push_back (region.get().mId);
|
||||||
|
|
||||||
|
removeRegion (region.get().mId);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRegions (update);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::regionsInserted (const QModelIndex& parent, int start, int end)
|
void CSMWorld::RegionMap::regionsInserted (const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> update;
|
||||||
|
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
if (!region.isDeleted())
|
||||||
|
{
|
||||||
|
update.push_back (region.get().mId);
|
||||||
|
|
||||||
|
addRegion (region.get().mId, region.get().mMapColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRegions (update);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::regionsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
void CSMWorld::RegionMap::regionsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
// Note: At this point an additional check could be inserted to see if there is any change to the
|
||||||
|
// columns we are interested in. If not we can exit the function here and avoid all updating.
|
||||||
|
|
||||||
|
std::vector<std::string> update;
|
||||||
|
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
for (int i=topLeft.row(); i<=bottomRight.column(); ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
update.push_back (region.get().mId);
|
||||||
|
|
||||||
|
if (!region.isDeleted())
|
||||||
|
addRegion (region.get().mId, region.get().mMapColor);
|
||||||
|
else
|
||||||
|
removeRegion (region.get().mId);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRegions (update);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::cellsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
void CSMWorld::RegionMap::cellsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
removeCell (index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::cellsInserted (const QModelIndex& parent, int start, int end)
|
void CSMWorld::RegionMap::cellsInserted (const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
|
addCells (start, end);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
;
|
// Note: At this point an additional check could be inserted to see if there is any change to the
|
||||||
|
// columns we are interested in. If not we can exit the function here and avoid all updating.
|
||||||
|
|
||||||
|
addCells (topLeft.row(), bottomRight.row());
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ namespace CSMWorld
|
||||||
CellDescription();
|
CellDescription();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Data& mData;
|
||||||
std::map<CellIndex, CellDescription> mMap;
|
std::map<CellIndex, CellDescription> mMap;
|
||||||
CellIndex mMin; ///< inclusive
|
CellIndex mMin; ///< inclusive
|
||||||
CellIndex mMax; ///< exclusive
|
CellIndex mMax; ///< exclusive
|
||||||
|
@ -39,9 +41,38 @@ namespace CSMWorld
|
||||||
CellIndex getIndex (const QModelIndex& index) const;
|
CellIndex getIndex (const QModelIndex& index) const;
|
||||||
///< Translates a Qt model index into a cell index (which can contain negative components)
|
///< Translates a Qt model index into a cell index (which can contain negative components)
|
||||||
|
|
||||||
void buildRegions (Data& data);
|
QModelIndex getIndex (const CellIndex& index) const;
|
||||||
|
|
||||||
void buildMap (Data& data);
|
void buildRegions();
|
||||||
|
|
||||||
|
void buildMap();
|
||||||
|
|
||||||
|
void addCell (const CellIndex& index, const CellDescription& description);
|
||||||
|
///< May be called on a cell that is already in the map (in which case an update is
|
||||||
|
// performed)
|
||||||
|
|
||||||
|
void addCells (int start, int end);
|
||||||
|
|
||||||
|
void removeCell (const CellIndex& index);
|
||||||
|
///< May be called on a cell that is not in the map (in which case the call is ignored)
|
||||||
|
|
||||||
|
void addRegion (const std::string& region, unsigned int colour);
|
||||||
|
///< May be called on a region that is already listed (in which case an update is
|
||||||
|
/// performed)
|
||||||
|
///
|
||||||
|
/// \note This function does not update the region map.
|
||||||
|
|
||||||
|
void removeRegion (const std::string& region);
|
||||||
|
///< May be called on a region that is not listed (in which case the call is ignored)
|
||||||
|
///
|
||||||
|
/// \note This function does not update the region map.
|
||||||
|
|
||||||
|
void updateRegions (const std::vector<std::string>& regions);
|
||||||
|
///< Update cells affected by the listed regions
|
||||||
|
|
||||||
|
void updateSize();
|
||||||
|
|
||||||
|
std::pair<CellIndex, CellIndex> getSize() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue