tibia-rme/source/selection.cpp
dalkon 886cbc23a7 Lots of changes
Removed libxml2 to use pugixml.
Fixed a bug with the progress bar.
Changed some things in most xml files that pugixml did not like.
Updated the Visual Studio project.
Any NULL symbol has been changed to nullptr.
This most probably broke the CMake that was recently added.
And probably some other things.
2014-01-22 20:16:17 +01:00

398 lines
8 KiB
C++

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////
// $URL: http://svn.rebarp.se/svn/RME/trunk/source/selection.hpp $
// $Id: selection.hpp 310 2010-02-26 18:03:48Z admin $
#include "main.h"
#include "selection.h"
#include "tile.h"
#include "creature.h"
#include "item.h"
#include "editor.h"
#include "gui.h"
Selection::Selection(Editor& editor) :
busy(false),
editor(editor),
session(nullptr),
subsession(nullptr)
{
}
Selection::~Selection()
{
delete subsession;
delete session;
}
Position Selection::minPosition() const
{
Position minPos(0x10000, 0x10000, 0x10);
for (TileVector::const_iterator tile = tiles.begin(); tile != tiles.end(); ++tile)
{
Position pos((*tile)->getPosition());
if (minPos.x > pos.x)
minPos.x = pos.x;
if (minPos.y > pos.y)
minPos.y = pos.y;
if (minPos.z > pos.z)
minPos.z = pos.z;
}
return minPos;
}
Position Selection::maxPosition() const
{
Position maxPos(0, 0, 0);
for (TileVector::const_iterator tile = tiles.begin(); tile != tiles.end(); ++tile)
{
Position pos((*tile)->getPosition());
if (maxPos.x < pos.x)
maxPos.x = pos.x;
if (maxPos.y < pos.y)
maxPos.y = pos.y;
if (maxPos.z < pos.z)
maxPos.z = pos.z;
}
return maxPos;
}
void Selection::add(Tile* tile, Item* item)
{
ASSERT(subsession);
ASSERT(tile);
ASSERT(item);
if(item->isSelected()) return;
// Make a copy of the tile with the item selected
item->select();
Tile* new_tile = tile->deepCopy(editor.map);
item->deselect();
if(settings.getInteger(Config::BORDER_IS_GROUND))
if(item->isBorder())
new_tile->selectGround();
subsession->addChange(newd Change(new_tile));
}
void Selection::add(Tile* tile, Spawn* spawn)
{
ASSERT(subsession);
ASSERT(tile);
ASSERT(spawn);
if(spawn->isSelected()) return;
// Make a copy of the tile with the item selected
spawn->select();
Tile* new_tile = tile->deepCopy(editor.map);
spawn->deselect();
subsession->addChange(newd Change(new_tile));
}
void Selection::add(Tile* tile, Creature* creature)
{
ASSERT(subsession);
ASSERT(tile);
ASSERT(creature);
if(creature->isSelected()) return;
// Make a copy of the tile with the item selected
creature->select();
Tile* new_tile = tile->deepCopy(editor.map);
creature->deselect();
subsession->addChange(newd Change(new_tile));
}
void Selection::add(Tile* tile)
{
ASSERT(subsession);
ASSERT(tile);
Tile* new_tile = tile->deepCopy(editor.map);
new_tile->select();
subsession->addChange(newd Change(new_tile));
}
void Selection::remove(Tile* tile, Item* item)
{
ASSERT(subsession);
ASSERT(tile);
ASSERT(item);
bool tmp = item->isSelected();
item->deselect();
Tile* new_tile = tile->deepCopy(editor.map);
if(tmp) item->select();
if(item->isBorder() && settings.getInteger(Config::BORDER_IS_GROUND)) new_tile->deselectGround();
subsession->addChange(newd Change(new_tile));
}
void Selection::remove(Tile* tile, Spawn* spawn)
{
ASSERT(subsession);
ASSERT(tile);
ASSERT(spawn);
bool tmp = spawn->isSelected();
spawn->deselect();
Tile* new_tile = tile->deepCopy(editor.map);
if(tmp) spawn->select();
subsession->addChange(newd Change(new_tile));
}
void Selection::remove(Tile* tile, Creature* creature)
{
ASSERT(subsession);
ASSERT(tile);
ASSERT(creature);
bool tmp = creature->isSelected();
creature->deselect();
Tile* new_tile = tile->deepCopy(editor.map);
if(tmp) creature->select();
subsession->addChange(newd Change(new_tile));
}
void Selection::remove(Tile* tile)
{
ASSERT(subsession);
Tile* new_tile = tile->deepCopy(editor.map);
new_tile->deselect();
subsession->addChange(newd Change(new_tile));
}
void Selection::addInternal(Tile* tile)
{
ASSERT(tile);
tiles.push_back(tile);
erase_iterator = tiles.begin();
}
void Selection::removeInternal(Tile* tile)
{
ASSERT(tile);
#ifdef __DEBUG_MODE__
TileVector::iterator erase_begin = erase_iterator;
#endif
if(tiles.size() == 0)
return;
TileVector::iterator end_iter = tiles.end();
do {
if(erase_iterator == end_iter)
{
erase_iterator = tiles.begin();
}
if(*erase_iterator == tile)
{
// Swap & pop trick
if(*erase_iterator == tiles.back())
{
tiles.pop_back();
erase_iterator = tiles.begin();
}
else
{
std::swap(*erase_iterator, tiles.back());
tiles.pop_back();
erase_iterator = tiles.begin() + (erase_iterator - tiles.begin());
}
return;
}
++erase_iterator;
#ifdef __DEBUG_MODE__
ASSERT(/* This shouldn't happend*/ erase_iterator != erase_begin);
#endif
} while(true);
}
void Selection::clear()
{
if(session)
{
for(TileVector::iterator it = tiles.begin(); it != tiles.end(); it++)
{
Tile* new_tile = (*it)->deepCopy(editor.map);
new_tile->deselect();
subsession->addChange(newd Change(new_tile));
}
}
else
{
for(TileVector::iterator it = tiles.begin(); it != tiles.end(); it++)
{
(*it)->deselect();
}
tiles.clear();
}
}
void Selection::start(SessionFlags flags)
{
if(!(flags & INTERNAL))
{
if(flags & SUBTHREAD)
{
;
}
else
{
session = editor.actionQueue->createBatch(ACTION_SELECT);
}
subsession = editor.actionQueue->createAction(ACTION_SELECT);
}
erase_iterator = tiles.begin();
busy = true;
}
void Selection::commit()
{
erase_iterator = tiles.begin();
if(session)
{
ASSERT(subsession);
// We need to step out of the session before we do the action, else peril awaits us!
BatchAction* tmp = session;
session = nullptr;
// Do the action
tmp->addAndCommitAction(subsession);
// Create a newd action for subsequent selects
subsession = editor.actionQueue->createAction(ACTION_SELECT);
session = tmp;
}
}
void Selection::finish(SessionFlags flags)
{
erase_iterator = tiles.begin();
if(!(flags & INTERNAL))
{
if(flags & SUBTHREAD)
{
ASSERT(subsession);
subsession = nullptr;
}
else
{
ASSERT(session);
ASSERT(subsession);
// We need to exit the session before we do the action, else peril awaits us!
BatchAction* tmp = session;
session = nullptr;
tmp->addAndCommitAction(subsession);
editor.addBatch(tmp, 2);
session = nullptr;
subsession = nullptr;
}
}
busy = false;
}
void Selection::updateSelectionCount()
{
if(size() > 0)
{
wxString ss;
if(size() == 1)
{
ss << wxT("One tile selected.");
}
else
{
ss << size() << wxT(" tiles selected.");
}
gui.SetStatusText(ss);
}
}
void Selection::join(SelectionThread* thread)
{
thread->Wait();
ASSERT(session);
session->addAction(thread->result);
thread->selection.subsession = nullptr;
delete thread;
}
SelectionThread::SelectionThread(Editor& editor, Position start, Position end) :
wxThread(wxTHREAD_JOINABLE),
editor(editor),
start(start),
end(end),
selection(editor),
result(nullptr)
{
}
SelectionThread::~SelectionThread()
{
}
void SelectionThread::Execute()
{
Create();
Run();
}
wxThread::ExitCode SelectionThread::Entry()
{
selection.start(Selection::SUBTHREAD);
for(int z = start.z; z >= end.z; --z)
{
for(int x = start.x; x <= end.x; ++x)
{
for(int y = start.y; y <= end.y; ++y)
{
Tile* tile = editor.map.getTile(x, y, z);
if(!tile)
continue;
selection.add(tile);
}
}
if(z <= 7 && settings.getInteger(Config::COMPENSATED_SELECT))
{
++start.x; ++start.y;
++end.x; ++end.y;
}
}
result = selection.subsession;
selection.finish(Selection::SUBTHREAD);
return nullptr;
}