void Selection::finish(SessionFlags flags) { erase_iterator = tiles.begin(); if(!(flags & INTERNAL)) { if(flags & SUBTHREAD) { ASSERT(subsession); subsession = NULL; } else { ASSERT(session); ASSERT(subsession); // We need to exit the session before we do the action, else peril awaits us! BatchAction* tmp = session; session = NULL; tmp->addAndCommitAction(subsession); editor.addBatch(tmp, 2); session = NULL; subsession = NULL; } } busy = false; }
void ActionQueue::undo() { if(current > 0) { current--; BatchAction* batch = actions[current]; batch->undo(); } }
void ActionQueue::redo() { if(current < actions.size()) { BatchAction* batch = actions[current]; batch->redo(); current++; } }
void ActionQueue::addAction(Action* action, int stacking_delay) { BatchAction* batch = createBatch(action->getType()); batch->addAndCommitAction(action); if(batch->size() == 0) { delete batch; return; } addBatch(batch, stacking_delay); }
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 ActionQueue::addBatch(BatchAction* batch, int stacking_delay) { ASSERT(batch); ASSERT(current <= actions.size()); if(batch->size() == 0) { delete batch; return; } // Commit any uncommited actions... batch->commit(); // Update title if(editor.map.doChange()) gui.UpdateTitle(); if(batch->type == ACTION_REMOTE) { delete batch; return; } while(current != actions.size()) { memory_size -= actions.back()->memsize(); BatchAction* todelete = actions.back(); actions.pop_back(); delete todelete; } while(memory_size > size_t(1024 * 1024 * settings.getInteger(Config::UNDO_MEM_SIZE)) && actions.empty() == false) { memory_size -= actions.front()->memsize(); delete actions.front(); actions.pop_front(); current--; } if(actions.size() > size_t(settings.getInteger(Config::UNDO_SIZE)) && actions.empty() == false) { memory_size -= actions.front()->memsize(); BatchAction* todelete = actions.front(); actions.pop_front(); delete todelete; current--; } do { if(actions.empty() == false) { BatchAction* lastAction = actions.back(); if(lastAction->type == batch->type && settings.getInteger(Config::GROUP_ACTIONS) && time(nullptr) - stacking_delay < lastAction->timestamp) { lastAction->merge(batch); lastAction->timestamp = time(nullptr); memory_size -= lastAction->memsize(); memory_size += lastAction->memsize(true); delete batch; break; } } memory_size += batch->memsize(); actions.push_back(batch); batch->timestamp = time(nullptr); current++; } while(false); }
void CopyBuffer::paste(Editor& editor, const Position& toPosition) { if(!tiles) { return; } BatchAction* batchAction = editor.actionQueue->createBatch(ACTION_PASTE_TILES); Action* action = editor.actionQueue->createAction(batchAction); for(MapIterator it = tiles->begin(); it != tiles->end(); ++it) { Tile* buffer_tile = (*it)->get(); Position pos = buffer_tile->getPosition() - copyPos + toPosition; if(!pos.isValid()) continue; TileLocation* location = editor.map.createTileL(pos); Tile* copy_tile = buffer_tile->deepCopy(editor.map); Tile* old_dest_tile = location->get(); Tile* new_dest_tile = nullptr; copy_tile->setLocation(location); if(settings.getInteger(Config::MERGE_PASTE) || !copy_tile->ground) { if(old_dest_tile) new_dest_tile = old_dest_tile->deepCopy(editor.map); else new_dest_tile = editor.map.allocator(location); new_dest_tile->merge(copy_tile); delete copy_tile; } else { // If the copied tile has ground, replace target tile new_dest_tile = copy_tile; } // Add all surrounding tiles to the map, so they get borders editor.map.createTile(pos.x-1, pos.y-1, pos.z); editor.map.createTile(pos.x , pos.y-1, pos.z); editor.map.createTile(pos.x+1, pos.y-1, pos.z); editor.map.createTile(pos.x-1, pos.y , pos.z); editor.map.createTile(pos.x+1, pos.y , pos.z); editor.map.createTile(pos.x-1, pos.y+1, pos.z); editor.map.createTile(pos.x , pos.y+1, pos.z); editor.map.createTile(pos.x+1, pos.y+1, pos.z); action->addChange(newd Change(new_dest_tile)); } batchAction->addAndCommitAction(action); if(settings.getInteger(Config::USE_AUTOMAGIC) && settings.getInteger(Config::BORDERIZE_PASTE)) { action = editor.actionQueue->createAction(batchAction); TileList borderize_tiles; Map& map = editor.map; // Go through all modified (selected) tiles (might be slow) for(MapIterator it = tiles->begin(); it != tiles->end(); ++it) { bool add_me = false; // If this tile is touched Position pos = (*it)->getPosition() - copyPos + toPosition; if(pos.z < 0 || pos.z >= MAP_HEIGHT) { continue; } // Go through all neighbours Tile* t; t = map.getTile(pos.x-1, pos.y-1, pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x , pos.y-1, pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x+1, pos.y-1, pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x-1, pos.y , pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x+1, pos.y , pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x-1, pos.y+1, pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x , pos.y+1, pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} t = map.getTile(pos.x+1, pos.y+1, pos.z); if(t && !t->isSelected()) {borderize_tiles.push_back(t); add_me = true;} if(add_me) borderize_tiles.push_back(map.getTile(pos)); } // Remove duplicates borderize_tiles.sort(); borderize_tiles.unique(); for(Tile* tile : borderize_tiles) { if(tile) { Tile* newTile = tile->deepCopy(editor.map); newTile->borderize(&map); if(tile->ground && tile->ground->isSelected()) { newTile->selectGround(); } newTile->wallize(&map); action->addChange(newd Change(newTile)); } } // Commit changes to map batchAction->addAndCommitAction(action); } editor.addBatch(batchAction); }
void CopyBuffer::cut(Editor& editor, int floor) { if(editor.selection.size() == 0) { gui.SetStatusText(wxT("No tiles to cut.")); return; } clear(); tiles = newd BaseMap(); int tile_count = 0; int item_count = 0; copyPos = Position(0xFFFF, 0xFFFF, floor); BatchAction* batch = editor.actionQueue->createBatch(ACTION_CUT_TILES); Action* action = editor.actionQueue->createAction(batch); PositionList tilestoborder; for(TileVector::iterator it = editor.selection.begin(); it != editor.selection.end(); ++it) { tile_count++; Tile* tile = *it; Tile* newtile = tile->deepCopy(editor.map); Tile* copied_tile = tiles->allocator(tile->getLocation()); if(tile->ground && tile->ground->isSelected()) { copied_tile->house_id = newtile->house_id; newtile->house_id = 0; copied_tile->setMapFlags(tile->getMapFlags()); newtile->setMapFlags(TILESTATE_NONE); } ItemVector tile_selection = newtile->popSelectedItems(); for(ItemVector::iterator iit = tile_selection.begin(); iit != tile_selection.end(); ++iit) { item_count++; // Add items to copybuffer copied_tile->addItem(*iit); } if(newtile->creature && newtile->creature->isSelected()) { copied_tile->creature = newtile->creature; newtile->creature = nullptr; } if(newtile->spawn && newtile->spawn->isSelected()) { copied_tile->spawn = newtile->spawn; newtile->spawn = nullptr; } tiles->setTile(copied_tile->getPosition(), copied_tile); if(copied_tile->getX() < copyPos.x) { copyPos.x = copied_tile->getX(); } if(copied_tile->getY() < copyPos.y) { copyPos.y = copied_tile->getY(); } if(settings.getInteger(Config::USE_AUTOMAGIC)) { for(int y = -1; y <= 1; y++) for(int x = -1; x <= 1; x++) tilestoborder.push_back(Position(tile->getX() + x, tile->getY() + y, tile->getZ())); } action->addChange(newd Change(newtile)); } batch->addAndCommitAction(action); // Remove duplicates tilestoborder.sort(); tilestoborder.unique(); if(settings.getInteger(Config::USE_AUTOMAGIC)) { action = editor.actionQueue->createAction(batch); for(PositionList::iterator it = tilestoborder.begin(); it != tilestoborder.end(); ++it) { TileLocation* location = editor.map.createTileL(*it); if(location->get()) { Tile* new_tile = location->get()->deepCopy(editor.map); new_tile->borderize(&editor.map); new_tile->wallize(&editor.map); action->addChange(newd Change(new_tile)); } else { Tile* new_tile = editor.map.allocator(location); new_tile->borderize(&editor.map); if(new_tile->size()) { action->addChange(newd Change(new_tile)); } else { delete new_tile; } } } batch->addAndCommitAction(action); } editor.addBatch(batch); std::stringstream ss; ss << "Cut out " << tile_count << " tile" << (tile_count > 1 ? "s" : "") << " (" << item_count << " item" << (item_count > 1? "s" : "") << ")"; gui.SetStatusText(wxstr(ss.str())); }