scenedit undo/redo infrastructure

This commit is contained in:
2025-05-31 12:01:08 -05:00
parent 79cd86f7dc
commit b6fb93f199
8 changed files with 163 additions and 32 deletions

View File

@@ -65,6 +65,7 @@
413AAF672D38A4A5002E9BF1 /* living.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914698FB1A7362D900F20F5E /* living.cpp */; };
413FE08F2CECFAFF000D97DC /* winutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 413FE08E2CECFAFF000D97DC /* winutil.cpp */; };
415EEEB02D5534A500B47408 /* prefs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 415EEEAF2D5534A500B47408 /* prefs.cpp */; };
41E550542DEB8C2A00A7DF52 /* scen.undo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41E550532DEB8C2A00A7DF52 /* scen.undo.cpp */; };
91034D211B225E4A008F01C1 /* scen.appleevents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91034D201B225E49008F01C1 /* scen.appleevents.mm */; };
911A14031B8FAFC600900FD9 /* town_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C2A6EC1B8FA91400346948 /* town_read.cpp */; };
911A14041B8FB00300900FD9 /* talk_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C2A6EE1B8FAA8E00346948 /* talk_read.cpp */; };
@@ -635,6 +636,8 @@
410CEEE72D84618C00FFF8CD /* profile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = profile.hpp; sourceTree = "<group>"; };
413FE08E2CECFAFF000D97DC /* winutil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = winutil.cpp; sourceTree = "<group>"; };
415EEEAF2D5534A500B47408 /* prefs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = prefs.cpp; sourceTree = "<group>"; };
41E550522DEB8C1400A7DF52 /* scen.undo.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = scen.undo.hpp; sourceTree = "<group>"; };
41E550532DEB8C2A00A7DF52 /* scen.undo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scen.undo.cpp; sourceTree = "<group>"; };
91034D201B225E49008F01C1 /* scen.appleevents.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = scen.appleevents.mm; sourceTree = "<group>"; };
9103DC652C6A406600849E60 /* cli.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = cli.hpp; sourceTree = "<group>"; };
910BBA170FB8BECA001E34EA /* dialog.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = dialog.hpp; sourceTree = "<group>"; };
@@ -1468,6 +1471,7 @@
91B3EEE70F969BA700BF5B67 /* scen.btnmg.hpp */,
91B3EEE10F969BA700BF5B67 /* scen.core.hpp */,
91B3EEE40F969BA700BF5B67 /* scen.fileio.hpp */,
41E550522DEB8C1400A7DF52 /* scen.undo.hpp */,
91B3EEDE0F969BA700BF5B67 /* scen.global.hpp */,
91B3EEE50F969BA700BF5B67 /* scen.graphics.hpp */,
91B3EEE00F969BA700BF5B67 /* scen.keydlgs.hpp */,
@@ -1482,6 +1486,7 @@
91B3EEEA0F969BA700BF5B67 /* src */ = {
isa = PBXGroup;
children = (
41E550532DEB8C2A00A7DF52 /* scen.undo.cpp */,
91B3EEF10F969BA700BF5B67 /* scen.actions.cpp */,
91034D201B225E49008F01C1 /* scen.appleevents.mm */,
91B3EEF50F969BA700BF5B67 /* scen.btnmg.cpp */,
@@ -2250,6 +2255,7 @@
914CA45819074E0100B6ADD1 /* scen.menus.mac.mm in Sources */,
91034D211B225E4A008F01C1 /* scen.appleevents.mm in Sources */,
91B0D5D21E344300002BE4DA /* view_dialogs.cpp in Sources */,
41E550542DEB8C2A00A7DF52 /* scen.undo.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -12,6 +12,7 @@ scened_sources = Split("""
scen.main.cpp
scen.sdfpicker.cpp
scen.townout.cpp
scen.undo.cpp
../view_dialogs.cpp
../fileio/fileio_party.cpp
../damage.cpp

View File

@@ -20,6 +20,7 @@
#include "scen.keydlgs.hpp"
#include "scen.townout.hpp"
#include "scen.menus.hpp"
#include "scen.undo.hpp"
#include "mathutil.hpp"
#include "fileio/fileio.hpp"
#include "tools/keymods.hpp"
@@ -710,6 +711,7 @@ static bool handle_rb_action(location the_point, bool option_hit) {
static bool handle_terrain_action(location the_point, bool ctrl_hit) {
cArea* cur_area = get_current_area();
std::shared_ptr<cAction> undo_action = nullptr;
if(mouse_spot.x >= 0 && mouse_spot.y >= 0) {
if(cur_viewing_mode == 0) {
spot_hit.x = cen_x + mouse_spot.x - 4;
@@ -1090,6 +1092,7 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
auto& specials = cur_area->special_locs;
for(short x = 0; x < specials.size(); x++)
if(specials[x] == spot_hit && specials[x].spec >= 0) {
spec_loc_t for_redo = specials[x];
specials[x] = {-1,-1};
specials[x].spec = -1;
if(x == specials.size() - 1) {
@@ -1098,6 +1101,7 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
specials.pop_back();
} while(!specials.empty() && specials.back().spec < 0);
}
undo_action.reset(new aEraseSpecial(for_redo));
break;
}
overall_mode = MODE_DRAWING;
@@ -1204,6 +1208,11 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) {
if((overall_mode == MODE_DRAWING) && (old_mode != MODE_DRAWING))
set_string("Drawing mode",scenario.ter_types[current_terrain_type].name);
draw_terrain();
if(undo_action != nullptr){
undo_list.add(undo_action);
update_edit_menu();
}
return true;
}
bool need_redraw = false;

View File

@@ -48,13 +48,3 @@ bool monst_on_space(location loc,short m_num);
void place_edit_special(location loc);
void set_special(location spot_hit);
bool save_check(std::string which_dlog, bool allow_no = true);
/// Represents the action of adding a new town to the end of the list
class aNewTown : public cAction {
class cTown* theTown;
bool undo_me() override;
bool redo_me() override;
public:
aNewTown(class cTown* t);
~aNewTown();
};

View File

@@ -17,6 +17,7 @@
#include "scen.sdfpicker.hpp"
#include "scen.fileio.hpp"
#include "scen.core.hpp"
#include "scen.undo.hpp"
#include "mathutil.hpp"
#include "dialogxml/widgets/button.hpp"
#include "dialogxml/widgets/field.hpp"
@@ -1642,27 +1643,6 @@ void set_current_out(location out_sec, bool continuous_shift, bool first_restore
set_up_main_screen();
}
aNewTown::aNewTown(cTown* t)
: cAction("add town")
, theTown(t)
{}
bool aNewTown::undo_me() {
scenario.towns.resize(scenario.towns.size() - 1);
set_current_town(scenario.towns.size() - 1);
return true;
}
bool aNewTown::redo_me() {
scenario.towns.push_back(theTown);
set_current_town(scenario.towns.size() - 1);
return true;
}
aNewTown::~aNewTown() {
if(!isDone()) delete theTown;
}
bool new_town() {
ter_num_t preset = 0;
cChoiceDlog new_dlg("new-town", {"okay", "cancel"});

View File

@@ -0,0 +1,93 @@
#include "scen.undo.hpp"
#include "scenario/scenario.hpp"
#include "scenario/area.hpp"
extern bool editing_town;
extern short cur_town;
extern short cur_town;
extern location cur_out;
extern short cen_x;
extern short cen_y;
extern cScenario scenario;
extern cArea* get_current_area();
extern void start_town_edit();
extern void start_out_edit();
extern void redraw_screen();
cTerrainAction::cTerrainAction(std::string name, short town_num, location where) : cAction(name) {
area.is_town = true;
area.town_num = town_num;
area.where = where;
}
cTerrainAction::cTerrainAction(std::string name, location out_sec, location where) : cAction(name) {
area.is_town = false;
area.out_sec = out_sec;
area.where = where;
}
cTerrainAction::cTerrainAction(std::string name, location where) : cAction(name) {
area.is_town = editing_town;
// One of these two will be ignored
area.town_num = cur_town;
area.out_sec = cur_out;
area.where = where;
}
void cTerrainAction::showChangeSite() {
if(area.is_town){
cur_town = area.town_num;
}else{
cur_out = area.out_sec;
}
editing_town = area.is_town;
// TODO this isn't working and I don't know why:
cen_x = area.where.x;
cen_y = area.where.y;
redraw_screen();
}
void cTerrainAction::undo() {
showChangeSite();
cAction::undo();
}
void cTerrainAction::redo() {
showChangeSite();
cAction::redo();
}
// Undo/Redo implementations for actions:
bool aEraseSpecial::undo_me() {
cArea* cur_area = get_current_area();
auto& specials = cur_area->special_locs;
specials.push_back(for_redo);
return true;
}
bool aEraseSpecial::redo_me() {
cArea* cur_area = get_current_area();
auto& specials = cur_area->special_locs;
specials.pop_back();
return true;
}
aNewTown::aNewTown(cTown* t)
: cAction("Add Town")
, theTown(t)
{}
bool aNewTown::undo_me() {
scenario.towns.resize(scenario.towns.size() - 1);
cur_town = min(cur_town, scenario.towns.size() - 1);
return true;
}
bool aNewTown::redo_me() {
scenario.towns.push_back(theTown);
return true;
}
aNewTown::~aNewTown() {
if(!isDone()) delete theTown;
}

View File

@@ -0,0 +1,51 @@
#ifndef BoE_scen_undo_h
#define BoE_scen_undo_h
#include "location.hpp"
#include "tools/undo.hpp"
struct area_ref_t {
bool is_town;
// Can't just make the next two a union for compiler reasons.
short town_num;
location out_sec;
location where;
};
// Action that modified town or outdoor terrain, so we should show the modified area when undoing or redoing
class cTerrainAction : public cAction {
public:
cTerrainAction(std::string name, short town_num, location where);
cTerrainAction(std::string name, location out_sec, location where);
cTerrainAction(std::string name, location where);
void undo();
void redo();
bool undo_me() = 0;
bool redo_me() = 0;
private:
/// Show where the change happened
void showChangeSite();
area_ref_t area;
};
/// Represents the action of adding a new town to the end of the list
class aNewTown : public cAction {
class cTown* theTown;
bool undo_me() override;
bool redo_me() override;
public:
aNewTown(class cTown* t);
~aNewTown();
};
class aEraseSpecial : public cTerrainAction {
public:
aEraseSpecial(spec_loc_t special) : cTerrainAction("Erase Special Encounter", special), for_redo(special) {}
bool undo_me() override;
bool redo_me() override;
private:
spec_loc_t for_redo;
bool editing_town;
};
#endif

View File

@@ -15,6 +15,7 @@
#include <list>
#include <memory>
#include <string>
#include "location.hpp"
class cAction {
std::string actname;
@@ -93,6 +94,6 @@ public:
static size_t maxUndoSize;
};
// As a special convention, I will prefix action classes with 'a' instead of 'c'
// As a special convention, I will prefix non-abstract action classes with 'a' instead of 'c'
#endif