From 1930eb7cc2b82dbd88e4195fb3602b48fbd16a4d Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Tue, 3 Jun 2025 13:37:56 -0500 Subject: [PATCH] undo/redo for creating/deleting terrain types --- src/scenedit/scen.actions.cpp | 38 +++++++++++++++++++++++++++-------- src/scenedit/scen.undo.cpp | 16 +++++++++++++++ src/scenedit/scen.undo.hpp | 18 +++++++++++++++++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/scenedit/scen.actions.cpp b/src/scenedit/scen.actions.cpp index d716f005..c3bf1050 100644 --- a/src/scenedit/scen.actions.cpp +++ b/src/scenedit/scen.actions.cpp @@ -1301,23 +1301,45 @@ static bool handle_terpal_action(location cur_point, bool option_hit) { return true; } if(option_hit) { - if(i == size_before - 1 && !scenario.is_ter_used(i)) - scenario.ter_types.pop_back(); - else if(i == size_before) { + // option-click the plus button: create a new row of terrains + if(i == size_before){ + terrain_type_changes_t terrains; scenario.ter_types.resize(size_before + 16); - for(; i < scenario.ter_types.size(); i++) + for(; i < scenario.ter_types.size(); i++){ scenario.ter_types[i].name = "New Terrain"; - } else { - scenario.ter_types[i] = cTerrain(); - scenario.ter_types[i].name = "Unused Terrain"; + terrains.push_back(scenario.ter_types[i]); + } + + undo_list.add(action_ptr(new aCreateDeleteTerrain(terrains))); + update_edit_menu(); + } + else{ + // option-click the last one and it's safe to delete: delete it + if(i == size_before - 1 && !scenario.is_ter_used(i)){ + undo_list.add(action_ptr(new aCreateDeleteTerrain(false, scenario.ter_types.back()))); + update_edit_menu(); + scenario.ter_types.pop_back(); + } + // option-click terrain that can't be deleted (because it would break other terrains' numbers, or is in use somewhere): + // reset type info + else{ + scenario.ter_types[i] = cTerrain(); + scenario.ter_types[i].name = "Unused Terrain"; + } } } else { + // Click the plus button: create a new terrain and edit it immediately if(i == size_before) { scenario.ter_types.emplace_back(); scenario.ter_types.back().name = "New Terrain"; } - if(!edit_ter_type(i) && i == size_before && scenario.ter_types.back().name == "New Terrain") + if(!edit_ter_type(i) && i == size_before && scenario.ter_types.back().name == "New Terrain"){ + // Canceled: scenario.ter_types.pop_back(); + }else{ + undo_list.add(action_ptr(new aCreateDeleteTerrain(true, scenario.ter_types.back()))); + update_edit_menu(); + } } if(size_before / 16 > scenario.ter_types.size() / 16) pos_before--; diff --git a/src/scenedit/scen.undo.cpp b/src/scenedit/scen.undo.cpp index 61d18c01..b8a4869b 100644 --- a/src/scenedit/scen.undo.cpp +++ b/src/scenedit/scen.undo.cpp @@ -94,6 +94,22 @@ aCreateDeleteTown::~aCreateDeleteTown() { if(isDone() == reversed) delete theTown; } +bool aCreateDeleteTerrain::undo_me() { + // TODO if not in MODE_EDIT_TYPES, show it + for(cTerrain ter : terrains){ + scenario.ter_types.pop_back(); + } + return true; +} + +bool aCreateDeleteTerrain::redo_me() { + // TODO if not in MODE_EDIT_TYPES, show it + for(cTerrain ter : terrains){ + scenario.ter_types.push_back(ter); + } + return true; +} + bool aDrawTerrain::undo_me() { cArea* cur_area = get_current_area(); for(auto change : changes){ diff --git a/src/scenedit/scen.undo.hpp b/src/scenedit/scen.undo.hpp index 40f7e4cd..90433b41 100644 --- a/src/scenedit/scen.undo.hpp +++ b/src/scenedit/scen.undo.hpp @@ -4,6 +4,9 @@ #include "location.hpp" #include "tools/undo.hpp" #include "scenario/town.hpp" +#include "scenario/scenario.hpp" + +extern cScenario scenario; struct area_ref_t { bool is_town; @@ -21,6 +24,7 @@ struct ter_change_t { typedef std::map stroke_ter_changes_t; typedef std::map item_changes_t; typedef std::map creature_changes_t; +typedef std::vector terrain_type_changes_t; // Action that modified something in town or outdoor terrain, so we should show the modified area when undoing or redoing class cTerrainAction : public cAction { @@ -94,5 +98,19 @@ public: ~aCreateDeleteTown(); }; +/// Action which adds new terrain type(s) to the end of the list, or deletes from the end of the list +class aCreateDeleteTerrain : public cAction { + terrain_type_changes_t terrains; + bool undo_me() override; + bool redo_me() override; +public: + aCreateDeleteTerrain(bool create, cTerrain terrain) : + cAction(create ? "Create Terrain Type" : "Delete Terrain Type", !create), + terrains({terrain}) {} + aCreateDeleteTerrain(terrain_type_changes_t terrains) : + cAction("Create Terrain Types", false), + terrains(terrains) {} +}; + #endif \ No newline at end of file