Setting and removal of starting positions are now undoable operations.

Cleanups of the undo/redo code.
This commit is contained in:
Kristoffer Erlandsson 2004-05-17 22:43:07 +00:00
parent e1ac7dce53
commit a7a37ac0fc
5 changed files with 98 additions and 51 deletions

View file

@ -50,8 +50,9 @@ CVS HEAD:
* editor improvements:
* added map resizing
* added revert from disk functionality
* selection of terrain is kep through undo and redo operations
* selection of terrain is kept through undo and redo operations
* preferences dialog
* setting and removal of starting positions are now undoable operations
* fixed name of the currently selected terrain not being displayed
* fixed compile problems on some architectures
* fixed 'show enemy moves' and 'best possible enemy moves' showing in context menu when no enemies visible

View file

@ -58,6 +58,17 @@ namespace {
return dist;
}
// Return the side that has it's starting position at hex, or -1 if
// none has.
int starting_side_at(const gamemap& map, const gamemap::location hex) {
int start_side = -1;
for (int i = 0; i < 10; i++) {
if (map.starting_position(i) == hex) {
start_side = i;
}
}
return start_side;
}
}
namespace map_editor {
@ -162,7 +173,9 @@ void map_editor::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
if (button == SDL_BUTTON_RIGHT) {
selected_hex_ = gui_.hex_clicked_on(mousex, mousey);
const theme::menu* const m = gui_.get_theme().context_menu();
show_menu(m->items(), mousex, mousey + 1, true);
if (m != NULL) {
show_menu(m->items(), mousex, mousey + 1, true);
}
}
if (button == SDL_BUTTON_LEFT) {
gamemap::location hex_clicked = gui_.hex_clicked_on(mousex, mousey);
@ -262,8 +275,8 @@ void map_editor::edit_flood_fill() {
action.add_terrain((*it).second, palette_.selected_terrain(),
(*it).first);
}
terrain_changed(to_invalidate, action);
save_undo_action(action);
invalidate_all_and_adjacent(to_invalidate);
}
void map_editor::edit_save_map() {
@ -342,7 +355,7 @@ void map_editor::edit_paste() {
}
}
undo_action.set_selection(selected_hexes_, filled);
invalidate_all_and_adjacent(filled);
terrain_changed(filled, undo_action);
selected_hexes_ = filled;
save_undo_action(undo_action);
}
@ -482,6 +495,14 @@ void map_editor::undo() {
to_invalidate.push_back(it->first);
}
}
if (action.starting_location_set()) {
for (std::map<gamemap::location, int>::const_iterator it =
action.undo_starting_locations().begin();
it != action.undo_starting_locations().end(); it++) {
map_.set_starting_position((*it).second, (*it).first);
to_invalidate.push_back((*it).first);
}
}
invalidate_all_and_adjacent(to_invalidate);
if (action.map_data_set()) {
throw new_map_exception(action.old_map_data(), filename_);
@ -508,6 +529,14 @@ void map_editor::redo() {
to_invalidate.push_back(it->first);
}
}
if (action.starting_location_set()) {
for (std::map<gamemap::location, int>::const_iterator it =
action.redo_starting_locations().begin();
it != action.redo_starting_locations().end(); it++) {
map_.set_starting_position((*it).second, (*it).first);
to_invalidate.push_back((*it).first);
}
}
invalidate_all_and_adjacent(to_invalidate);
if (action.map_data_set()) {
throw new_map_exception(action.new_map_data(), filename_);
@ -546,10 +575,13 @@ bool map_editor::changed_since_save() const {
void map_editor::set_starting_position(const int player, const gamemap::location loc) {
if(map_.on_board(loc)) {
map_undo_action action;
num_operations_since_save_ = 1000;
action.add_terrain(map_.get_terrain(selected_hex_), gamemap::KEEP,
selected_hex_);
map_.set_terrain(selected_hex_, gamemap::KEEP);
terrain_changed(selected_hex_, action);
action.add_starting_location(player, player, map_.starting_position(player), loc);
map_.set_starting_position(player, loc);
invalidate_adjacent(loc);
save_undo_action(action);
}
else {
gui::show_dialog(gui_, NULL, "",
@ -647,8 +679,8 @@ void map_editor::left_button_down(const int mousex, const int mousey) {
}
}
if (!to_invalidate.empty()) {
terrain_changed(to_invalidate, action);
save_undo_action(action);
invalidate_all_and_adjacent(to_invalidate);
}
}
}
@ -697,9 +729,9 @@ void map_editor::perform_selection_move() {
}
}
undo_action.set_selection(selected_hexes_, new_selection);
invalidate_all_and_adjacent(selected_hexes_);
terrain_changed(selected_hexes_, undo_action);
selected_hexes_ = new_selection;
invalidate_all_and_adjacent(selected_hexes_);
terrain_changed(selected_hexes_, undo_action);
save_undo_action(undo_action);
}
@ -708,54 +740,52 @@ void map_editor::draw_terrain(const gamemap::TERRAIN terrain,
const gamemap::TERRAIN current_terrain = map_[hex.x][hex.y];
map_undo_action undo_action;
undo_action.add_terrain(current_terrain, terrain, hex);
save_undo_action(undo_action);
map_.set_terrain(hex, terrain);
invalidate_adjacent(hex);
terrain_changed(hex, undo_action);
save_undo_action(undo_action);
}
void map_editor::terrain_changed(const gamemap::location &hex) {
// If we painted something else than a keep on a starting position,
// unset the starting position.
int start_side = -1;
for (int i = 0; i < 10; i++) {
if (map_.starting_position(i) == hex) {
start_side = i;
void map_editor::terrain_changed(const gamemap::location &hex,
map_undo_action &undo_action) {
std::vector<gamemap::location> v;
v.push_back(hex);
terrain_changed(v, undo_action);
}
void map_editor::terrain_changed(const std::vector<gamemap::location> &hexes,
map_undo_action &undo_action) {
for (std::vector<gamemap::location>::const_iterator it = hexes.begin();
it != hexes.end(); it++) {
const int start_side = starting_side_at(map_, *it);
if (start_side != -1 && map_.get_terrain(*it) != gamemap::KEEP) {
// A terrain which had a starting position has changed, save
// this position in the undo_action and unset it.
map_.set_starting_position(start_side, gamemap::location());
undo_action.add_starting_location(start_side, start_side,
*it, gamemap::location());
}
}
if (start_side != -1 && map_.get_terrain(hex) != gamemap::KEEP) {
//undo_action.add_starting_location(
map_.set_starting_position(start_side, gamemap::location());
}
invalidate_all_and_adjacent(hexes);
}
void map_editor::terrain_changed(const std::set<gamemap::location> &hexes,
map_undo_action &undo_action) {
std::vector<gamemap::location> v;
std::copy(hexes.begin(), hexes.end(), std::back_inserter(v));
terrain_changed(v, undo_action);
}
void map_editor::invalidate_adjacent(const gamemap::location hex) {
terrain_changed(hex);
gamemap::location locs[7];
locs[0] = hex;
get_adjacent_tiles(hex,locs+1);
for(int i = 0; i != 7; ++i) {
if (!map_.on_board(locs[i])) {
// One adjacent square is not on the board, clear it from
// the border cache so it will be redrawn correctly.
gamemap::TERRAIN terrain_before = map_.get_terrain(locs[i]);
map_.remove_from_border_cache(locs[i]);
gamemap::TERRAIN terrain_after = map_.get_terrain(locs[i]);
if (terrain_before != terrain_after) {
invalidate_adjacent(locs[i]);
}
}
gui_.rebuild_terrain(locs[i]);
gui_.invalidate(locs[i]);
}
map_dirty_ = true;
std::set<gamemap::location> s;
s.insert(hex);
invalidate_all_and_adjacent(s);
}
void map_editor::invalidate_all_and_adjacent(const std::vector<gamemap::location> &hexes) {
std::set<gamemap::location> to_invalidate;
std::vector<gamemap::location>::const_iterator it;
for (it = hexes.begin(); it != hexes.end(); it++) {
terrain_changed(*it);
gamemap::location locs[7];
locs[0] = *it;
get_adjacent_tiles(*it, locs+1);
@ -806,7 +836,6 @@ bool map_editor::confirm_exit_and_save() {
return true;
}
bool map_editor::save_map(const std::string fn, const bool display_confirmation) {
std::string filename = fn;
if (filename == "") {

View file

@ -198,10 +198,17 @@ private:
/// highlighted.
void highlight_selected_hexes(const bool clear_old=true);
/// If a starting position is at the specified hex, unset it if
/// something else than a keep is the terrain at the hex. Save the
/// starting position change in undo_action.
void terrain_changed(const gamemap::location &hex);
/// Terrain has changed at the specified hex. If the hex was a
/// starting position, remove this position. Save additional
/// information in the undo_action and invalidate the hex and the
/// adjacent ones.
void terrain_changed(const gamemap::location &hex,
map_undo_action &undo_action);
void terrain_changed(const std::vector<gamemap::location> &hexes,
map_undo_action &undo_action);
void terrain_changed(const std::set<gamemap::location> &hexes,
map_undo_action &undo_action);
/// Save an action so that it may be undone. Add an operation to the
/// number done since save.

View file

@ -95,12 +95,17 @@ bool map_undo_action::map_data_set() const {
}
void map_undo_action::add_starting_location(const int old_side, const int new_side,
const gamemap::location &loc) {
old_starting_locations_[loc] = old_side;
new_starting_locations_[loc] = new_side;
const gamemap::location &old_loc,
const gamemap::location &new_loc) {
old_starting_locations_[old_loc] = old_side;
new_starting_locations_[new_loc] = new_side;
starting_locations_set_ = true;
}
bool map_undo_action::starting_location_set() const {
return starting_locations_set_;
}
void add_undo_action(const map_undo_action &action) {
undo_stack.push_back(action);
if (undo_stack.size() > undo_limit) {

View file

@ -64,7 +64,12 @@ public:
bool map_data_set() const;
void add_starting_location(const int old_side, const int new_side,
const gamemap::location &loc);
const gamemap::location &old_loc,
const gamemap::location &new_loc);
/// Return true if starting locations have been saved in this undo
/// action.
bool starting_location_set() const;
private:
std::map<gamemap::location,gamemap::TERRAIN> old_terrain_;