From e882367d80a0bcdd09b5412d908b0fdb6b6bfe34 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 17 Mar 2015 13:58:32 -0400 Subject: Implemented undo/redo framework in map editor --- tools/mapedit/CMakeLists.txt | 1 + tools/mapedit/src/frame.cpp | 197 +++++++++++++++++++++++++++++++++++++------ tools/mapedit/src/frame.h | 30 +++++-- tools/mapedit/src/map.cpp | 16 +++- tools/mapedit/src/map.h | 9 +- tools/mapedit/src/undo.cpp | 95 +++++++++++++++++++++ tools/mapedit/src/undo.h | 63 ++++++++++++++ tools/mapedit/src/widget.cpp | 110 +++++++++++++++++++++--- tools/mapedit/src/widget.h | 4 + tools/mapedit/src/world.cpp | 4 +- 10 files changed, 482 insertions(+), 47 deletions(-) create mode 100644 tools/mapedit/src/undo.cpp create mode 100644 tools/mapedit/src/undo.h diff --git a/tools/mapedit/CMakeLists.txt b/tools/mapedit/CMakeLists.txt index 12af38c..ca44fc5 100644 --- a/tools/mapedit/CMakeLists.txt +++ b/tools/mapedit/CMakeLists.txt @@ -45,6 +45,7 @@ add_executable(AromatherapyMapEditor src/tile_widget.cpp src/object.cpp src/world.cpp + src/undo.cpp ) target_link_libraries(AromatherapyMapEditor ${ALL_LIBS}) install(TARGETS AromatherapyMapEditor RUNTIME DESTINATION ${BIN_DIR}) diff --git a/tools/mapedit/src/frame.cpp b/tools/mapedit/src/frame.cpp index 66775e1..3646d4e 100644 --- a/tools/mapedit/src/frame.cpp +++ b/tools/mapedit/src/frame.cpp @@ -19,6 +19,8 @@ enum { MENU_FILE_CLOSE, MENU_MAP_ADD_ROOT, MENU_MAP_ADD_CHILD, + MENU_EDIT_UNDO, + MENU_EDIT_REDO, TOOL_FILE_NEW, TOOL_FILE_OPEN, TOOL_FILE_SAVE, @@ -43,6 +45,8 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) EVT_MENU(MENU_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) EVT_MENU(MENU_MAP_ADD_CHILD, MapeditFrame::OnAddChild) + EVT_MENU(MENU_EDIT_UNDO, MapeditFrame::OnUndo) + EVT_MENU(MENU_EDIT_REDO, MapeditFrame::OnRedo) EVT_TOOL(TOOL_FILE_NEW, MapeditFrame::OnNew) EVT_TOOL(TOOL_FILE_OPEN, MapeditFrame::OnOpen) EVT_TOOL(TOOL_FILE_SAVE, MapeditFrame::OnSave) @@ -51,7 +55,6 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) EVT_CLOSE(MapeditFrame::OnExit) EVT_NOTEBOOK_PAGE_CHANGED(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChange) EVT_NOTEBOOK_PAGE_CHANGING(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChanging) - EVT_TREE_SEL_CHANGING(MAP_EDITOR_TREE, MapeditFrame::OnWillSelectMap) EVT_TREE_SEL_CHANGED(MAP_EDITOR_TREE, MapeditFrame::OnDidSelectMap) EVT_TREE_BEGIN_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnWillDragMap) EVT_TREE_END_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnDidDragMap) @@ -80,12 +83,18 @@ MapeditFrame::MapeditFrame(std::unique_ptr world) : wxFrame(NULL, wxID_AN menuFile->AppendSeparator(); menuFile->Append(wxID_EXIT); + menuEdit = new wxMenu; + menuEdit->Append(MENU_EDIT_UNDO, "Undo\tCtrl-Z"); + menuEdit->Append(MENU_EDIT_REDO, "Redo\tCtrl-Shift-Z"); + UpdateUndoLabels(); + wxMenu* menuView = new wxMenu; menuView->Append(MENU_VIEW_ZOOM_IN, "Zoom In\tCtrl-+"); menuView->Append(MENU_VIEW_ZOOM_OUT, "Zoom Out\tCtrl--"); wxMenuBar* menuBar = new wxMenuBar; menuBar->Append(menuFile, "&File"); + menuBar->Append(menuEdit, "&Edit"); menuBar->Append(menuView, "&View"); SetMenuBar(menuBar); @@ -118,7 +127,7 @@ MapeditFrame::MapeditFrame(std::unique_ptr world) : wxFrame(NULL, wxID_AN // Set up property editor wxPanel* propertyEditor = new wxPanel(layout3, wxID_ANY); - titleBox = new wxTextCtrl(propertyEditor, MAP_TITLE_TEXTBOX, currentMap->getTitle()); + titleBox = new UndoableTextBox(propertyEditor, MAP_TITLE_TEXTBOX, currentMap->getTitle(), "Edit Map Title", this); titleBox->SetMaxLength(40); wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); @@ -216,8 +225,9 @@ MapeditFrame::MapeditFrame(std::unique_ptr world) : wxFrame(NULL, wxID_AN toolbar->EnableTool(TOOL_FILE_SAVE, this->world->getDirty()); toolbar->Realize(); - mapTree->SetFocusedItem(currentMap->getTreeItemId()); - SelectMap(currentMap); + dontSelectMap = true; + mapTree->SelectItem(currentMap->getTreeItemId()); + dontSelectMap = false; Maximize(true); } @@ -324,10 +334,12 @@ void MapeditFrame::OnQuit(wxCommandEvent&) } } -void MapeditFrame::OnTitleChange(wxCommandEvent&) +void MapeditFrame::OnTitleChange(wxCommandEvent& event) { currentMap->setTitle(titleBox->GetValue().ToStdString()); - mapTree->SetItemText(currentMap->getTreeItemId(), currentMap->getTitle()); + mapTree->SetItemText(currentMap->getTreeItemId(), titleBox->GetValue()); + + event.Skip(); } void MapeditFrame::OnTabChange(wxBookCtrlEvent& event) @@ -378,33 +390,83 @@ void MapeditFrame::OnCancelAddEntity(wxCommandEvent&) void MapeditFrame::OnAddRoot(wxCommandEvent&) { auto map = world->newMap(); - wxTreeItemId node = mapTree->AppendItem(mapTree->GetItemParent(mapTree->GetSelection()), map->getTitle()); - map->setTreeItemId(node); - mapTree->SetItemData(node, new MapPtrCtr(map.get())); - mapTree->SetFocusedItem(node); - SelectMap(map.get()); + + commitAction(std::make_shared("New Map", [=] () { + map->setHidden(false); + + wxTreeItemId sel = mapTree->GetSelection(); + wxTreeItemId par = mapTree->GetItemParent(sel); + wxTreeItemId node = mapTree->AppendItem(par, map->getTitle()); + map->setTreeItemId(node); + mapTree->SetItemData(node, new MapPtrCtr(map.get())); + + dontSelectMap = true; + mapTree->SelectItem(node); + dontSelectMap = false; + }, [=] () { + map->setHidden(true); + + wxTreeItemId sel = mapTree->GetPrevSibling(map->getTreeItemId()); + mapTree->Delete(map->getTreeItemId()); + + dontSelectMap = true; + mapTree->SelectItem(sel); + dontSelectMap = false; + })); + } void MapeditFrame::OnAddChild(wxCommandEvent&) { auto map = world->newMap(); - wxTreeItemId node = mapTree->AppendItem(mapTree->GetSelection(), map->getTitle()); - map->setTreeItemId(node); - mapTree->SetItemData(node, new MapPtrCtr(map.get())); - mapTree->SetFocusedItem(node); - mapTree->Expand(mapTree->GetSelection()); - SelectMap(map.get()); + + commitAction(std::make_shared("New Map", [=] () { + map->setHidden(false); + + wxTreeItemId sel = mapTree->GetSelection(); + wxTreeItemId node = mapTree->AppendItem(sel, map->getTitle()); + map->setTreeItemId(node); + mapTree->SetItemData(node, new MapPtrCtr(map.get())); + + mapTree->Expand(sel); + + dontSelectMap = true; + mapTree->SelectItem(node); + dontSelectMap = false; + }, [=] () { + map->setHidden(true); + + wxTreeItemId sel = mapTree->GetItemParent(map->getTreeItemId()); + mapTree->Delete(map->getTreeItemId()); + + dontSelectMap = true; + mapTree->SelectItem(sel); + dontSelectMap = false; + })); } void MapeditFrame::OnDidSelectMap(wxTreeEvent& event) { MapPtrCtr* data = (MapPtrCtr*) mapTree->GetItemData(event.GetItem()); SelectMap(data->map); -} - -void MapeditFrame::OnWillSelectMap(wxTreeEvent& event) -{ - event.Skip(); + + if (!dontSelectMap) + { + commitAfter(std::make_shared("Selecting " + data->map->getTitle(), [=] () { + wxTreeItemId toSelect = event.GetItem(); + dontSelectMap = true; + mapTree->SelectItem(toSelect); + dontSelectMap = false; + SelectMap(data->map); + }, [=] () { + wxTreeItemId toSelect = event.GetOldItem(); + MapPtrCtr* oldData = (MapPtrCtr*) mapTree->GetItemData(toSelect); + dontSelectMap = true; + mapTree->SelectItem(toSelect); + dontSelectMap = false; + SelectMap(oldData->map); + })); + } } void MapeditFrame::OnWillDragMap(wxTreeEvent& event) @@ -426,9 +488,24 @@ void MapeditFrame::OnDidDragMap(wxTreeEvent& event) newParent = mapTree->GetRootItem(); } - wxTreeItemId newChild = MoveTreeNode(dragMap, newParent); + wxTreeItemId curParent = mapTree->GetItemParent(event.GetItem()); + wxTreeItemId dragMapCopy = dragMap; dragMap.Unset(); - mapTree->SelectItem(newChild); + + Map* theMap = ((MapPtrCtr*) mapTree->GetItemData(dragMap))->map; + commitAction(std::make_shared("Arranging " + theMap->getTitle(), [=] () { + wxTreeItemId newChild = MoveTreeNode(dragMapCopy, newParent); + + dontSelectMap = true; + mapTree->SelectItem(newChild); + dontSelectMap = false; + }, [=] () { + wxTreeItemId newChild = MoveTreeNode(dragMapCopy, curParent); + + dontSelectMap = true; + mapTree->SelectItem(newChild); + dontSelectMap = false; + })); } void MapeditFrame::OnRightClickTree(wxTreeEvent& event) @@ -451,6 +528,28 @@ void MapeditFrame::OnCancelSetStartpos(wxCommandEvent&) mapEditor->SetIsSettingStart(false); } +void MapeditFrame::OnUndo(wxCommandEvent&) +{ + (*currentAction)->endChanges(); + (*currentAction)->undo(); + currentAction++; + + UpdateUndoLabels(); +} + +void MapeditFrame::OnRedo(wxCommandEvent&) +{ + if (currentAction != end(history)) + { + (*currentAction)->endChanges(); + } + + currentAction--; + (*currentAction)->apply(); + + UpdateUndoLabels(); +} + void MapeditFrame::NewWorld() { LaunchWindow(std::unique_ptr(new World())); @@ -531,6 +630,10 @@ void MapeditFrame::SelectMap(Map* map) { currentMap = map; mapEditor->SetMap(map); + + SetIsAddingEntity(false); + SetIsSettingStart(false); + titleBox->ChangeValue(map->getTitle()); world->setLastMap(map); } @@ -592,3 +695,49 @@ void MapeditFrame::SetStartposLabel() startposLabel->SetLabel(mappos_out.str()); } + +void MapeditFrame::UpdateUndoLabels() +{ + if (currentAction != end(history)) + { + menuEdit->SetLabel(MENU_EDIT_UNDO, "Undo " + (*currentAction)->getTitle() + "\tCtrl-Z"); + menuEdit->Enable(MENU_EDIT_UNDO, true); + } else { + menuEdit->SetLabel(MENU_EDIT_UNDO, "Undo\tCtrl-Z"); + menuEdit->Enable(MENU_EDIT_UNDO, false); + } + + if (currentAction != begin(history)) + { + menuEdit->SetLabel(MENU_EDIT_REDO, "Redo " + (*std::prev(currentAction))->getTitle() + "\tCtrl-Shift-Z"); + menuEdit->Enable(MENU_EDIT_REDO, true); + } else { + menuEdit->SetLabel(MENU_EDIT_REDO, "Redo\tCtrl-Shift-Z"); + menuEdit->Enable(MENU_EDIT_REDO, false); + } +} + +void MapeditFrame::commitAction(std::shared_ptr action) +{ + action->apply(); + + commitAfter(action); +} + +void MapeditFrame::commitAfter(std::shared_ptr action) +{ + if (currentAction != end(history)) + { + (*currentAction)->endChanges(); + } + + history.erase(begin(history), currentAction); + currentAction = history.insert(begin(history), action); + + UpdateUndoLabels(); + + if (history.size() > 100) + { + history.pop_back(); + } +} diff --git a/tools/mapedit/src/frame.h b/tools/mapedit/src/frame.h index 067c848..b0f27e9 100644 --- a/tools/mapedit/src/frame.h +++ b/tools/mapedit/src/frame.h @@ -14,6 +14,7 @@ #include #include #include +#include "undo.h" class MapPtrCtr : public wxTreeItemData { public: @@ -37,7 +38,6 @@ class MapeditFrame : public wxFrame { std::list::iterator closer; - private: static void LaunchWindow(std::unique_ptr world); void populateMapTree(wxTreeItemId node, std::list> maps); void SelectMap(Map* map); @@ -60,7 +60,6 @@ class MapeditFrame : public wxFrame { void OnAddRoot(wxCommandEvent& event); void OnAddChild(wxCommandEvent& event); void OnDidSelectMap(wxTreeEvent& event); - void OnWillSelectMap(wxTreeEvent& event); void OnWillDragMap(wxTreeEvent& event); void OnDidDragMap(wxTreeEvent& event); void OnRightClickTree(wxTreeEvent& event); @@ -69,25 +68,44 @@ class MapeditFrame : public wxFrame { std::unique_ptr world; Map* currentMap; + MapeditWidget* mapEditor; TileWidget* tileEditor; - wxTextCtrl* titleBox; - std::string filename; + wxToolBar* toolbar; + wxMenu* menuFile; + + // Notebook wxNotebook* notebook; wxChoice* entityTypeBox; wxButton* addEntityButton; wxButton* cancelEntityButton; - wxToolBar* toolbar; - wxMenu* menuFile; + + // Map tree wxTreeCtrl* mapTree; wxTreeItemId dragMap; wxMenu* mapTreePopup; + bool dontSelectMap = false; + + // Property editor + UndoableTextBox* titleBox; + wxString prevTitle; wxStaticText* startposLabel; wxButton* setStartposButton; wxButton* cancelStartposButton; + // Undo stuff + wxMenu* menuEdit; + std::list> history; + std::list>::iterator currentAction {begin(history)}; + void OnUndo(wxCommandEvent& event); + void OnRedo(wxCommandEvent& event); + void UpdateUndoLabels(); + void commitAction(std::shared_ptr action); + void commitAfter(std::shared_ptr action); + bool addingEntity = false; + private: wxDECLARE_EVENT_TABLE(); }; diff --git a/tools/mapedit/src/map.cpp b/tools/mapedit/src/map.cpp index 0f8826c..0db7031 100644 --- a/tools/mapedit/src/map.cpp +++ b/tools/mapedit/src/map.cpp @@ -19,6 +19,7 @@ Map::Map(const Map& map) world = map.world; treeItemId = map.treeItemId; children = map.children; + hidden = map.hidden; } Map::Map(Map&& map) : Map(-1, map.world) @@ -49,6 +50,7 @@ void swap(Map& first, Map& second) std::swap(first.world, second.world); std::swap(first.treeItemId, second.treeItemId); std::swap(first.children, second.children); + std::swap(first.hidden, second.hidden); } int Map::getID() const @@ -118,6 +120,11 @@ World* Map::getWorld() const return world; } +bool Map::getHidden() const +{ + return hidden; +} + void Map::setTitle(std::string title, bool dirty) { this->title = title; @@ -149,7 +156,7 @@ void Map::setMapdata(int* mapdata, bool dirty) } } -void Map::addObject(std::shared_ptr& obj, bool dirty) +void Map::addObject(std::shared_ptr obj, bool dirty) { objects.push_back(obj); @@ -159,7 +166,7 @@ void Map::addObject(std::shared_ptr& obj, bool dirty) } } -void Map::removeObject(std::shared_ptr& obj, bool dirty) +void Map::removeObject(std::shared_ptr obj, bool dirty) { objects.remove(obj); @@ -203,3 +210,8 @@ void Map::setExpanded(bool exp) { expanded = exp; } + +void Map::setHidden(bool hid) +{ + hidden = hid; +} diff --git a/tools/mapedit/src/map.h b/tools/mapedit/src/map.h index df3e237..34dcb33 100644 --- a/tools/mapedit/src/map.h +++ b/tools/mapedit/src/map.h @@ -53,7 +53,7 @@ class MapWriteException: public std::exception struct MapObjectEntry { MapObject* object; - std::pair position; + std::pair position; bool operator==(MapObjectEntry& other) const { @@ -85,17 +85,19 @@ class Map { std::list> getChildren() const; bool getExpanded() const; World* getWorld() const; + bool getHidden() const; void setTitle(std::string title, bool dirty = true); void setTileAt(int x, int y, int tile, bool dirty = true); void setMapdata(int* mapdata, bool dirty = true); - void addObject(std::shared_ptr& obj, bool dirty = true); - void removeObject(std::shared_ptr& obj, bool dirty = true); + void addObject(std::shared_ptr obj, bool dirty = true); + void removeObject(std::shared_ptr obj, bool dirty = true); void setLeftmap(int id, bool dirty = true); void setRightmap(int id, bool dirty = true); void setTreeItemId(wxTreeItemId id); void addChild(int id); void setExpanded(bool exp); + void setHidden(bool hid); private: int id; @@ -108,6 +110,7 @@ class Map { int rightmap = -1; wxTreeItemId treeItemId; bool expanded = false; + bool hidden = false; }; #endif diff --git a/tools/mapedit/src/undo.cpp b/tools/mapedit/src/undo.cpp new file mode 100644 index 0000000..bcf7b92 --- /dev/null +++ b/tools/mapedit/src/undo.cpp @@ -0,0 +1,95 @@ +#include "undo.h" +#include "frame.h" + +Undoable::Undoable(std::string title, std::function forward, std::function backward) +{ + this->title = title; + this->forward = forward; + this->backward = backward; +} + +std::string Undoable::getTitle() const +{ + return title; +} + +void Undoable::apply() +{ + forward(); +} + +void Undoable::undo() +{ + backward(); +} + +wxBEGIN_EVENT_TABLE(UndoableTextBox, wxTextCtrl) + EVT_SET_FOCUS(UndoableTextBox::OnFocus) + EVT_KILL_FOCUS(UndoableTextBox::OnKillFocus) +wxEND_EVENT_TABLE() + +UndoableTextBox::UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos, wxSize size, long style) : wxTextCtrl(parent, id, startText, pos, size, style) +{ + this->undoText = undoType; + this->realParent = realParent; + + Init(); +} + +void UndoableTextBox::Init() +{ + Bind(wxEVT_TEXT, &UndoableTextBox::OnTextChange, this); + + curText = GetValue(); +} + +void UndoableTextBox::OnFocus(wxFocusEvent& event) +{ + curText = GetValue(); + + event.Skip(); +} + +void UndoableTextBox::OnKillFocus(wxFocusEvent& event) +{ + undo.reset(); + + event.Skip(); +} + +void UndoableTextBox::OnTextChange(wxCommandEvent& event) +{ + if (!undo) + { + auto tempUndo = std::make_shared(undoText, curText, *this); + + realParent->commitAfter(tempUndo); + + undo = tempUndo; + } + + undo->newText = GetValue(); + curText = GetValue(); + + event.Skip(); +} + +UndoableTextBox::Undo::Undo(std::string title, wxString origText, UndoableTextBox& parent) : origText(origText), parent(parent) +{ + this->title = title; +} + +void UndoableTextBox::Undo::apply() +{ + parent.ChangeValue(newText); +} + +void UndoableTextBox::Undo::undo() +{ + parent.ChangeValue(origText); +} + +void UndoableTextBox::Undo::endChanges() +{ + parent.undo.reset(); +} diff --git a/tools/mapedit/src/undo.h b/tools/mapedit/src/undo.h new file mode 100644 index 0000000..794f993 --- /dev/null +++ b/tools/mapedit/src/undo.h @@ -0,0 +1,63 @@ +#ifndef UNDO_H +#define UNDO_H + +#include + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include +#include + +class MapeditFrame; + +class Undoable { + public: + Undoable(std::string title, std::function forward, std::function backward); + virtual std::string getTitle() const; + virtual void apply(); + virtual void undo(); + virtual void endChanges() {} + + protected: + Undoable() {} + + std::string title; + std::function forward; + std::function backward; +}; + +class UndoableTextBox : public wxTextCtrl { + public: + UndoableTextBox(); + UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize, long style = 0); + + private: + class Undo : public Undoable { + public: + Undo(std::string title, wxString origText, UndoableTextBox& parent); + void apply(); + void undo(); + void endChanges(); + + wxString origText; + wxString newText; + UndoableTextBox& parent; + }; + + void Init(); + void OnFocus(wxFocusEvent& event); + void OnKillFocus(wxFocusEvent& event); + void OnTextChange(wxCommandEvent& event); + + MapeditFrame* realParent; + std::string undoText; + wxString curText; + std::shared_ptr undo; + + wxDECLARE_EVENT_TABLE(); +}; + +#endif diff --git a/tools/mapedit/src/widget.cpp b/tools/mapedit/src/widget.cpp index 6cbedcd..61a8d65 100644 --- a/tools/mapedit/src/widget.cpp +++ b/tools/mapedit/src/widget.cpp @@ -55,6 +55,11 @@ void MapeditWidget::OnPaint(wxPaintEvent&) for (int x=0; xgetTileAt(x, y); + if (changeBuffer.find({x,y}) != end(changeBuffer)) + { + tile = tileWidget->getSelected(); + } + dc.StretchBlit(x*TILE_WIDTH*scale-vX, y*TILE_HEIGHT*scale-vY, TILE_WIDTH*scale, TILE_HEIGHT*scale, &tiles_dc, tile%8*TILE_WIDTH, tile/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT); } } @@ -147,6 +152,21 @@ void MapeditWidget::OnPaint(wxPaintEvent&) dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, addingEntity->getWidth(), addingEntity->getHeight()); + wxPen pen(*wxGREEN, 2); + dc.SetPen(pen); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); + } else if ((editMode == EditEntities) && (movingEntity != nullptr)) + { + wxBitmap sprite = movingEntity->object->getSprite(); + tiles_dc.SelectObject(wxNullBitmap); + tiles_dc.SelectObject(sprite); + + wxPoint pos {mousePos.x - movingEntity->object->getWidth()/2*scale, mousePos.y - movingEntity->object->getHeight()/2*scale}; + wxSize size {movingEntity->object->getWidth()*scale, movingEntity->object->getHeight()*scale}; + + dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, movingEntity->object->getWidth(), movingEntity->object->getHeight()); + wxPen pen(*wxGREEN, 2); dc.SetPen(pen); dc.SetBrush(*wxTRANSPARENT_BRUSH); @@ -167,7 +187,8 @@ void MapeditWidget::SetTile(wxPoint pos) int x = (pos.x + vX) / (TILE_WIDTH * scale); int y = (pos.y + vY) / (TILE_HEIGHT * scale); - map->setTileAt(x, y, tileWidget->getSelected()); + changeBuffer.insert({x,y}); + Refresh(); } @@ -191,17 +212,42 @@ void MapeditWidget::OnClick(wxMouseEvent& event) { int x = (event.GetPosition().x + vX) / scale - (addingEntity->getWidth() / 2); int y = (event.GetPosition().y + vY) / scale - (addingEntity->getHeight() / 2); - + auto data = std::make_shared(); data->object = addingEntity; data->position = std::make_pair(x,y); - map->addObject(data); - addingEntity = nullptr; + frame->commitAction(std::make_shared("Add " + addingEntity->getType(), [=] () { + map->addObject(data); + + Refresh(); + }, [=] () { + map->removeObject(data); + + Refresh(); + })); frame->SetIsAddingEntity(false); + addingEntity = nullptr; + } else if (movingEntity != nullptr) + { + int x = (event.GetPosition().x + vX) / scale - (movingEntity->object->getWidth() / 2); + int y = (event.GetPosition().y + vY) / scale - (movingEntity->object->getHeight() / 2); + auto oldPos = movingEntity->position; + MapObjectEntry* me = movingEntity; - Refresh(); + frame->commitAction(std::make_shared("Move " + movingEntity->object->getType(), [=] () { + me->position = std::make_pair(x,y); + + Refresh(); + }, [=] () { + me->position = oldPos; + + Refresh(); + })); + + frame->SetIsAddingEntity(false); + movingEntity = nullptr; } else { int x = (event.GetPosition().x + vX) / scale; int y = (event.GetPosition().y + vY) / scale; @@ -211,9 +257,7 @@ void MapeditWidget::OnClick(wxMouseEvent& event) if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) { - addingEntity = selectedEntity->object; - map->removeObject(selectedEntity); - selectedEntity.reset(); + movingEntity = selectedEntity.get(); frame->SetIsAddingEntity(true); } else { selectedEntity.reset(); @@ -241,12 +285,23 @@ void MapeditWidget::OnClick(wxMouseEvent& event) { int x = (event.GetPosition().x + vX) / scale - (PLAYER_WIDTH[currentPlayer] / 2); int y = (event.GetPosition().y + vY) / scale - (PLAYER_HEIGHT[currentPlayer] / 2); + auto oldPos = map->getWorld()->getStartingPosition(); + auto oldSMap = map->getWorld()->getStartingMap(); + + frame->commitAction(std::make_shared("Set Starting Position", [=] () { + map->getWorld()->setStart(map, {x, y}); + frame->SetStartposLabel(); + + Refresh(); + }, [=] () { + map->getWorld()->setStart(oldSMap, oldPos); + frame->SetStartposLabel(); + + Refresh(); + })); - map->getWorld()->setStart(map, {x, y}); isSettingPos = false; frame->SetIsSettingStart(false); - - Refresh(); } event.Skip(); @@ -299,6 +354,34 @@ void MapeditWidget::OnMouseMove(wxMouseEvent& event) void MapeditWidget::OnMouseUp(wxMouseEvent&) { mouseIsDown = false; + + if (editMode == EditTiles) + { + std::map, int> localChangeBuffer; + for (auto assign : changeBuffer) + { + localChangeBuffer[assign] = map->getTileAt(assign.first, assign.second); + } + + int localSelection = tileWidget->getSelected(); + frame->commitAction(std::make_shared("Paint Map", [=] () { + for (auto assign : localChangeBuffer) + { + map->setTileAt(assign.first.first, assign.first.second, localSelection); + } + + Refresh(); + }, [=] () { + for (auto assign : localChangeBuffer) + { + map->setTileAt(assign.first.first, assign.first.second, assign.second); + } + + Refresh(); + })); + + changeBuffer.clear(); + } } void MapeditWidget::OnMouseOut(wxMouseEvent&) @@ -350,6 +433,7 @@ void MapeditWidget::StartAddingEntity(MapObject* object) void MapeditWidget::CancelAddingEntity() { addingEntity = nullptr; + movingEntity = nullptr; } void MapeditWidget::SetIsSettingStart(bool isSetting) @@ -369,6 +453,10 @@ void MapeditWidget::SetIsSettingStart(bool isSetting) void MapeditWidget::SetMap(Map* map) { this->map = map; + selectedEntity = nullptr; + addingEntity = nullptr; + movingEntity = nullptr; + isSettingPos = false; Refresh(); } diff --git a/tools/mapedit/src/widget.h b/tools/mapedit/src/widget.h index 67ebc01..4ae22c7 100644 --- a/tools/mapedit/src/widget.h +++ b/tools/mapedit/src/widget.h @@ -11,6 +11,8 @@ #include "tile_widget.h" #include #include +#include +#include class MapeditFrame; @@ -58,8 +60,10 @@ class MapeditWidget : public wxScrolledWindow { EditMode editMode = EditTiles; int currentPlayer = 0; bool isSettingPos = false; + std::set> changeBuffer; MapObject* addingEntity = nullptr; + MapObjectEntry* movingEntity = nullptr; std::shared_ptr selectedEntity; DECLARE_DYNAMIC_CLASS(MapeditWidget) diff --git a/tools/mapedit/src/world.cpp b/tools/mapedit/src/world.cpp index 3145e4e..db1201e 100644 --- a/tools/mapedit/src/world.cpp +++ b/tools/mapedit/src/world.cpp @@ -135,7 +135,7 @@ World::World(std::string filename) } else if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-position")) { xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); - sscanf((char*) key, "%lf,%lf", &data->position.first, &data->position.second); + sscanf((char*) key, "%d,%d", &data->position.first, &data->position.second); xmlFree(key); } } @@ -268,6 +268,8 @@ void World::save(std::string name, wxTreeCtrl* mapTree) { Map& map = *mapPair.second; + if (map.getHidden()) continue; + // rc = xmlTextWriterStartElement(writer, (xmlChar*) "map"); if (rc < 0) throw MapWriteException(name); -- cgit 1.4.1