diff options
| author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2015-03-17 13:58:32 -0400 |
|---|---|---|
| committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2015-03-17 13:58:32 -0400 |
| commit | e882367d80a0bcdd09b5412d908b0fdb6b6bfe34 (patch) | |
| tree | e5a023fc51f02cf37b97bfbb9ef09d2ddfc6591e | |
| parent | 29f818c314f86f9a842840c20d9634f0711507a6 (diff) | |
| download | therapy-e882367d80a0bcdd09b5412d908b0fdb6b6bfe34.tar.gz therapy-e882367d80a0bcdd09b5412d908b0fdb6b6bfe34.tar.bz2 therapy-e882367d80a0bcdd09b5412d908b0fdb6b6bfe34.zip | |
Implemented undo/redo framework in map editor
| -rw-r--r-- | tools/mapedit/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tools/mapedit/src/frame.cpp | 197 | ||||
| -rw-r--r-- | tools/mapedit/src/frame.h | 30 | ||||
| -rw-r--r-- | tools/mapedit/src/map.cpp | 16 | ||||
| -rw-r--r-- | tools/mapedit/src/map.h | 9 | ||||
| -rw-r--r-- | tools/mapedit/src/undo.cpp | 95 | ||||
| -rw-r--r-- | tools/mapedit/src/undo.h | 63 | ||||
| -rw-r--r-- | tools/mapedit/src/widget.cpp | 110 | ||||
| -rw-r--r-- | tools/mapedit/src/widget.h | 4 | ||||
| -rw-r--r-- | tools/mapedit/src/world.cpp | 4 |
10 files changed, 482 insertions, 47 deletions
| 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 | |||
| 45 | src/tile_widget.cpp | 45 | src/tile_widget.cpp |
| 46 | src/object.cpp | 46 | src/object.cpp |
| 47 | src/world.cpp | 47 | src/world.cpp |
| 48 | src/undo.cpp | ||
| 48 | ) | 49 | ) |
| 49 | target_link_libraries(AromatherapyMapEditor ${ALL_LIBS}) | 50 | target_link_libraries(AromatherapyMapEditor ${ALL_LIBS}) |
| 50 | install(TARGETS AromatherapyMapEditor RUNTIME DESTINATION ${BIN_DIR}) | 51 | 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 { | |||
| 19 | MENU_FILE_CLOSE, | 19 | MENU_FILE_CLOSE, |
| 20 | MENU_MAP_ADD_ROOT, | 20 | MENU_MAP_ADD_ROOT, |
| 21 | MENU_MAP_ADD_CHILD, | 21 | MENU_MAP_ADD_CHILD, |
| 22 | MENU_EDIT_UNDO, | ||
| 23 | MENU_EDIT_REDO, | ||
| 22 | TOOL_FILE_NEW, | 24 | TOOL_FILE_NEW, |
| 23 | TOOL_FILE_OPEN, | 25 | TOOL_FILE_OPEN, |
| 24 | TOOL_FILE_SAVE, | 26 | TOOL_FILE_SAVE, |
| @@ -43,6 +45,8 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | |||
| 43 | EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) | 45 | EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) |
| 44 | EVT_MENU(MENU_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) | 46 | EVT_MENU(MENU_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) |
| 45 | EVT_MENU(MENU_MAP_ADD_CHILD, MapeditFrame::OnAddChild) | 47 | EVT_MENU(MENU_MAP_ADD_CHILD, MapeditFrame::OnAddChild) |
| 48 | EVT_MENU(MENU_EDIT_UNDO, MapeditFrame::OnUndo) | ||
| 49 | EVT_MENU(MENU_EDIT_REDO, MapeditFrame::OnRedo) | ||
| 46 | EVT_TOOL(TOOL_FILE_NEW, MapeditFrame::OnNew) | 50 | EVT_TOOL(TOOL_FILE_NEW, MapeditFrame::OnNew) |
| 47 | EVT_TOOL(TOOL_FILE_OPEN, MapeditFrame::OnOpen) | 51 | EVT_TOOL(TOOL_FILE_OPEN, MapeditFrame::OnOpen) |
| 48 | EVT_TOOL(TOOL_FILE_SAVE, MapeditFrame::OnSave) | 52 | EVT_TOOL(TOOL_FILE_SAVE, MapeditFrame::OnSave) |
| @@ -51,7 +55,6 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | |||
| 51 | EVT_CLOSE(MapeditFrame::OnExit) | 55 | EVT_CLOSE(MapeditFrame::OnExit) |
| 52 | EVT_NOTEBOOK_PAGE_CHANGED(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChange) | 56 | EVT_NOTEBOOK_PAGE_CHANGED(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChange) |
| 53 | EVT_NOTEBOOK_PAGE_CHANGING(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChanging) | 57 | EVT_NOTEBOOK_PAGE_CHANGING(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChanging) |
| 54 | EVT_TREE_SEL_CHANGING(MAP_EDITOR_TREE, MapeditFrame::OnWillSelectMap) | ||
| 55 | EVT_TREE_SEL_CHANGED(MAP_EDITOR_TREE, MapeditFrame::OnDidSelectMap) | 58 | EVT_TREE_SEL_CHANGED(MAP_EDITOR_TREE, MapeditFrame::OnDidSelectMap) |
| 56 | EVT_TREE_BEGIN_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnWillDragMap) | 59 | EVT_TREE_BEGIN_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnWillDragMap) |
| 57 | EVT_TREE_END_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnDidDragMap) | 60 | EVT_TREE_END_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnDidDragMap) |
| @@ -80,12 +83,18 @@ MapeditFrame::MapeditFrame(std::unique_ptr<World> world) : wxFrame(NULL, wxID_AN | |||
| 80 | menuFile->AppendSeparator(); | 83 | menuFile->AppendSeparator(); |
| 81 | menuFile->Append(wxID_EXIT); | 84 | menuFile->Append(wxID_EXIT); |
| 82 | 85 | ||
| 86 | menuEdit = new wxMenu; | ||
| 87 | menuEdit->Append(MENU_EDIT_UNDO, "Undo\tCtrl-Z"); | ||
| 88 | menuEdit->Append(MENU_EDIT_REDO, "Redo\tCtrl-Shift-Z"); | ||
| 89 | UpdateUndoLabels(); | ||
| 90 | |||
| 83 | wxMenu* menuView = new wxMenu; | 91 | wxMenu* menuView = new wxMenu; |
| 84 | menuView->Append(MENU_VIEW_ZOOM_IN, "Zoom In\tCtrl-+"); | 92 | menuView->Append(MENU_VIEW_ZOOM_IN, "Zoom In\tCtrl-+"); |
| 85 | menuView->Append(MENU_VIEW_ZOOM_OUT, "Zoom Out\tCtrl--"); | 93 | menuView->Append(MENU_VIEW_ZOOM_OUT, "Zoom Out\tCtrl--"); |
| 86 | 94 | ||
| 87 | wxMenuBar* menuBar = new wxMenuBar; | 95 | wxMenuBar* menuBar = new wxMenuBar; |
| 88 | menuBar->Append(menuFile, "&File"); | 96 | menuBar->Append(menuFile, "&File"); |
| 97 | menuBar->Append(menuEdit, "&Edit"); | ||
| 89 | menuBar->Append(menuView, "&View"); | 98 | menuBar->Append(menuView, "&View"); |
| 90 | 99 | ||
| 91 | SetMenuBar(menuBar); | 100 | SetMenuBar(menuBar); |
| @@ -118,7 +127,7 @@ MapeditFrame::MapeditFrame(std::unique_ptr<World> world) : wxFrame(NULL, wxID_AN | |||
| 118 | 127 | ||
| 119 | // Set up property editor | 128 | // Set up property editor |
| 120 | wxPanel* propertyEditor = new wxPanel(layout3, wxID_ANY); | 129 | wxPanel* propertyEditor = new wxPanel(layout3, wxID_ANY); |
| 121 | titleBox = new wxTextCtrl(propertyEditor, MAP_TITLE_TEXTBOX, currentMap->getTitle()); | 130 | titleBox = new UndoableTextBox(propertyEditor, MAP_TITLE_TEXTBOX, currentMap->getTitle(), "Edit Map Title", this); |
| 122 | titleBox->SetMaxLength(40); | 131 | titleBox->SetMaxLength(40); |
| 123 | 132 | ||
| 124 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); | 133 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); |
| @@ -216,8 +225,9 @@ MapeditFrame::MapeditFrame(std::unique_ptr<World> world) : wxFrame(NULL, wxID_AN | |||
| 216 | toolbar->EnableTool(TOOL_FILE_SAVE, this->world->getDirty()); | 225 | toolbar->EnableTool(TOOL_FILE_SAVE, this->world->getDirty()); |
| 217 | toolbar->Realize(); | 226 | toolbar->Realize(); |
| 218 | 227 | ||
| 219 | mapTree->SetFocusedItem(currentMap->getTreeItemId()); | 228 | dontSelectMap = true; |
| 220 | SelectMap(currentMap); | 229 | mapTree->SelectItem(currentMap->getTreeItemId()); |
| 230 | dontSelectMap = false; | ||
| 221 | 231 | ||
| 222 | Maximize(true); | 232 | Maximize(true); |
| 223 | } | 233 | } |
| @@ -324,10 +334,12 @@ void MapeditFrame::OnQuit(wxCommandEvent&) | |||
| 324 | } | 334 | } |
| 325 | } | 335 | } |
| 326 | 336 | ||
| 327 | void MapeditFrame::OnTitleChange(wxCommandEvent&) | 337 | void MapeditFrame::OnTitleChange(wxCommandEvent& event) |
| 328 | { | 338 | { |
| 329 | currentMap->setTitle(titleBox->GetValue().ToStdString()); | 339 | currentMap->setTitle(titleBox->GetValue().ToStdString()); |
| 330 | mapTree->SetItemText(currentMap->getTreeItemId(), currentMap->getTitle()); | 340 | mapTree->SetItemText(currentMap->getTreeItemId(), titleBox->GetValue()); |
| 341 | |||
| 342 | event.Skip(); | ||
| 331 | } | 343 | } |
| 332 | 344 | ||
| 333 | void MapeditFrame::OnTabChange(wxBookCtrlEvent& event) | 345 | void MapeditFrame::OnTabChange(wxBookCtrlEvent& event) |
| @@ -378,33 +390,83 @@ void MapeditFrame::OnCancelAddEntity(wxCommandEvent&) | |||
| 378 | void MapeditFrame::OnAddRoot(wxCommandEvent&) | 390 | void MapeditFrame::OnAddRoot(wxCommandEvent&) |
| 379 | { | 391 | { |
| 380 | auto map = world->newMap(); | 392 | auto map = world->newMap(); |
| 381 | wxTreeItemId node = mapTree->AppendItem(mapTree->GetItemParent(mapTree->GetSelection()), map->getTitle()); | 393 | |
| 382 | map->setTreeItemId(node); | 394 | commitAction(std::make_shared<Undoable>("New Map", [=] () { |
| 383 | mapTree->SetItemData(node, new MapPtrCtr(map.get())); | 395 | map->setHidden(false); |
| 384 | mapTree->SetFocusedItem(node); | 396 | |
| 385 | SelectMap(map.get()); | 397 | wxTreeItemId sel = mapTree->GetSelection(); |
| 398 | wxTreeItemId par = mapTree->GetItemParent(sel); | ||
| 399 | wxTreeItemId node = mapTree->AppendItem(par, map->getTitle()); | ||
| 400 | map->setTreeItemId(node); | ||
| 401 | mapTree->SetItemData(node, new MapPtrCtr(map.get())); | ||
| 402 | |||
| 403 | dontSelectMap = true; | ||
| 404 | mapTree->SelectItem(node); | ||
| 405 | dontSelectMap = false; | ||
| 406 | }, [=] () { | ||
| 407 | map->setHidden(true); | ||
| 408 | |||
| 409 | wxTreeItemId sel = mapTree->GetPrevSibling(map->getTreeItemId()); | ||
| 410 | mapTree->Delete(map->getTreeItemId()); | ||
| 411 | |||
| 412 | dontSelectMap = true; | ||
| 413 | mapTree->SelectItem(sel); | ||
| 414 | dontSelectMap = false; | ||
| 415 | })); | ||
| 416 | |||
| 386 | } | 417 | } |
| 387 | 418 | ||
| 388 | void MapeditFrame::OnAddChild(wxCommandEvent&) | 419 | void MapeditFrame::OnAddChild(wxCommandEvent&) |
| 389 | { | 420 | { |
| 390 | auto map = world->newMap(); | 421 | auto map = world->newMap(); |
| 391 | wxTreeItemId node = mapTree->AppendItem(mapTree->GetSelection(), map->getTitle()); | 422 | |
| 392 | map->setTreeItemId(node); | 423 | commitAction(std::make_shared<Undoable>("New Map", [=] () { |
| 393 | mapTree->SetItemData(node, new MapPtrCtr(map.get())); | 424 | map->setHidden(false); |
| 394 | mapTree->SetFocusedItem(node); | 425 | |
| 395 | mapTree->Expand(mapTree->GetSelection()); | 426 | wxTreeItemId sel = mapTree->GetSelection(); |
| 396 | SelectMap(map.get()); | 427 | wxTreeItemId node = mapTree->AppendItem(sel, map->getTitle()); |
| 428 | map->setTreeItemId(node); | ||
| 429 | mapTree->SetItemData(node, new MapPtrCtr(map.get())); | ||
| 430 | |||
| 431 | mapTree->Expand(sel); | ||
| 432 | |||
| 433 | dontSelectMap = true; | ||
| 434 | mapTree->SelectItem(node); | ||
| 435 | dontSelectMap = false; | ||
| 436 | }, [=] () { | ||
| 437 | map->setHidden(true); | ||
| 438 | |||
| 439 | wxTreeItemId sel = mapTree->GetItemParent(map->getTreeItemId()); | ||
| 440 | mapTree->Delete(map->getTreeItemId()); | ||
| 441 | |||
| 442 | dontSelectMap = true; | ||
| 443 | mapTree->SelectItem(sel); | ||
| 444 | dontSelectMap = false; | ||
| 445 | })); | ||
| 397 | } | 446 | } |
| 398 | 447 | ||
| 399 | void MapeditFrame::OnDidSelectMap(wxTreeEvent& event) | 448 | void MapeditFrame::OnDidSelectMap(wxTreeEvent& event) |
| 400 | { | 449 | { |
| 401 | MapPtrCtr* data = (MapPtrCtr*) mapTree->GetItemData(event.GetItem()); | 450 | MapPtrCtr* data = (MapPtrCtr*) mapTree->GetItemData(event.GetItem()); |
| 402 | SelectMap(data->map); | 451 | SelectMap(data->map); |
| 403 | } | 452 | |
| 404 | 453 | if (!dontSelectMap) | |
| 405 | void MapeditFrame::OnWillSelectMap(wxTreeEvent& event) | 454 | { |
| 406 | { | 455 | commitAfter(std::make_shared<Undoable>("Selecting " + data->map->getTitle(), [=] () { |
| 407 | event.Skip(); | 456 | wxTreeItemId toSelect = event.GetItem(); |
| 457 | dontSelectMap = true; | ||
| 458 | mapTree->SelectItem(toSelect); | ||
| 459 | dontSelectMap = false; | ||
| 460 | SelectMap(data->map); | ||
| 461 | }, [=] () { | ||
| 462 | wxTreeItemId toSelect = event.GetOldItem(); | ||
| 463 | MapPtrCtr* oldData = (MapPtrCtr*) mapTree->GetItemData(toSelect); | ||
| 464 | dontSelectMap = true; | ||
| 465 | mapTree->SelectItem(toSelect); | ||
| 466 | dontSelectMap = false; | ||
| 467 | SelectMap(oldData->map); | ||
| 468 | })); | ||
| 469 | } | ||
| 408 | } | 470 | } |
| 409 | 471 | ||
| 410 | void MapeditFrame::OnWillDragMap(wxTreeEvent& event) | 472 | void MapeditFrame::OnWillDragMap(wxTreeEvent& event) |
| @@ -426,9 +488,24 @@ void MapeditFrame::OnDidDragMap(wxTreeEvent& event) | |||
| 426 | newParent = mapTree->GetRootItem(); | 488 | newParent = mapTree->GetRootItem(); |
| 427 | } | 489 | } |
| 428 | 490 | ||
| 429 | wxTreeItemId newChild = MoveTreeNode(dragMap, newParent); | 491 | wxTreeItemId curParent = mapTree->GetItemParent(event.GetItem()); |
| 492 | wxTreeItemId dragMapCopy = dragMap; | ||
| 430 | dragMap.Unset(); | 493 | dragMap.Unset(); |
| 431 | mapTree->SelectItem(newChild); | 494 | |
| 495 | Map* theMap = ((MapPtrCtr*) mapTree->GetItemData(dragMap))->map; | ||
| 496 | commitAction(std::make_shared<Undoable>("Arranging " + theMap->getTitle(), [=] () { | ||
| 497 | wxTreeItemId newChild = MoveTreeNode(dragMapCopy, newParent); | ||
| 498 | |||
| 499 | dontSelectMap = true; | ||
| 500 | mapTree->SelectItem(newChild); | ||
| 501 | dontSelectMap = false; | ||
| 502 | }, [=] () { | ||
| 503 | wxTreeItemId newChild = MoveTreeNode(dragMapCopy, curParent); | ||
| 504 | |||
| 505 | dontSelectMap = true; | ||
| 506 | mapTree->SelectItem(newChild); | ||
| 507 | dontSelectMap = false; | ||
| 508 | })); | ||
| 432 | } | 509 | } |
| 433 | 510 | ||
| 434 | void MapeditFrame::OnRightClickTree(wxTreeEvent& event) | 511 | void MapeditFrame::OnRightClickTree(wxTreeEvent& event) |
| @@ -451,6 +528,28 @@ void MapeditFrame::OnCancelSetStartpos(wxCommandEvent&) | |||
| 451 | mapEditor->SetIsSettingStart(false); | 528 | mapEditor->SetIsSettingStart(false); |
| 452 | } | 529 | } |
| 453 | 530 | ||
| 531 | void MapeditFrame::OnUndo(wxCommandEvent&) | ||
| 532 | { | ||
| 533 | (*currentAction)->endChanges(); | ||
| 534 | (*currentAction)->undo(); | ||
| 535 | currentAction++; | ||
| 536 | |||
| 537 | UpdateUndoLabels(); | ||
| 538 | } | ||
| 539 | |||
| 540 | void MapeditFrame::OnRedo(wxCommandEvent&) | ||
| 541 | { | ||
| 542 | if (currentAction != end(history)) | ||
| 543 | { | ||
| 544 | (*currentAction)->endChanges(); | ||
| 545 | } | ||
| 546 | |||
| 547 | currentAction--; | ||
| 548 | (*currentAction)->apply(); | ||
| 549 | |||
| 550 | UpdateUndoLabels(); | ||
| 551 | } | ||
| 552 | |||
| 454 | void MapeditFrame::NewWorld() | 553 | void MapeditFrame::NewWorld() |
| 455 | { | 554 | { |
| 456 | LaunchWindow(std::unique_ptr<World>(new World())); | 555 | LaunchWindow(std::unique_ptr<World>(new World())); |
| @@ -531,6 +630,10 @@ void MapeditFrame::SelectMap(Map* map) | |||
| 531 | { | 630 | { |
| 532 | currentMap = map; | 631 | currentMap = map; |
| 533 | mapEditor->SetMap(map); | 632 | mapEditor->SetMap(map); |
| 633 | |||
| 634 | SetIsAddingEntity(false); | ||
| 635 | SetIsSettingStart(false); | ||
| 636 | |||
| 534 | titleBox->ChangeValue(map->getTitle()); | 637 | titleBox->ChangeValue(map->getTitle()); |
| 535 | world->setLastMap(map); | 638 | world->setLastMap(map); |
| 536 | } | 639 | } |
| @@ -592,3 +695,49 @@ void MapeditFrame::SetStartposLabel() | |||
| 592 | 695 | ||
| 593 | startposLabel->SetLabel(mappos_out.str()); | 696 | startposLabel->SetLabel(mappos_out.str()); |
| 594 | } | 697 | } |
| 698 | |||
| 699 | void MapeditFrame::UpdateUndoLabels() | ||
| 700 | { | ||
| 701 | if (currentAction != end(history)) | ||
| 702 | { | ||
| 703 | menuEdit->SetLabel(MENU_EDIT_UNDO, "Undo " + (*currentAction)->getTitle() + "\tCtrl-Z"); | ||
| 704 | menuEdit->Enable(MENU_EDIT_UNDO, true); | ||
| 705 | } else { | ||
| 706 | menuEdit->SetLabel(MENU_EDIT_UNDO, "Undo\tCtrl-Z"); | ||
| 707 | menuEdit->Enable(MENU_EDIT_UNDO, false); | ||
| 708 | } | ||
| 709 | |||
| 710 | if (currentAction != begin(history)) | ||
| 711 | { | ||
| 712 | menuEdit->SetLabel(MENU_EDIT_REDO, "Redo " + (*std::prev(currentAction))->getTitle() + "\tCtrl-Shift-Z"); | ||
| 713 | menuEdit->Enable(MENU_EDIT_REDO, true); | ||
| 714 | } else { | ||
| 715 | menuEdit->SetLabel(MENU_EDIT_REDO, "Redo\tCtrl-Shift-Z"); | ||
| 716 | menuEdit->Enable(MENU_EDIT_REDO, false); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | void MapeditFrame::commitAction(std::shared_ptr<Undoable> action) | ||
| 721 | { | ||
| 722 | action->apply(); | ||
| 723 | |||
| 724 | commitAfter(action); | ||
| 725 | } | ||
| 726 | |||
| 727 | void MapeditFrame::commitAfter(std::shared_ptr<Undoable> action) | ||
| 728 | { | ||
| 729 | if (currentAction != end(history)) | ||
| 730 | { | ||
| 731 | (*currentAction)->endChanges(); | ||
| 732 | } | ||
| 733 | |||
| 734 | history.erase(begin(history), currentAction); | ||
| 735 | currentAction = history.insert(begin(history), action); | ||
| 736 | |||
| 737 | UpdateUndoLabels(); | ||
| 738 | |||
| 739 | if (history.size() > 100) | ||
| 740 | { | ||
| 741 | history.pop_back(); | ||
| 742 | } | ||
| 743 | } | ||
| 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 @@ | |||
| 14 | #include <wx/notebook.h> | 14 | #include <wx/notebook.h> |
| 15 | #include <memory> | 15 | #include <memory> |
| 16 | #include <wx/treectrl.h> | 16 | #include <wx/treectrl.h> |
| 17 | #include "undo.h" | ||
| 17 | 18 | ||
| 18 | class MapPtrCtr : public wxTreeItemData { | 19 | class MapPtrCtr : public wxTreeItemData { |
| 19 | public: | 20 | public: |
| @@ -37,7 +38,6 @@ class MapeditFrame : public wxFrame { | |||
| 37 | 38 | ||
| 38 | std::list<wxWindow*>::iterator closer; | 39 | std::list<wxWindow*>::iterator closer; |
| 39 | 40 | ||
| 40 | private: | ||
| 41 | static void LaunchWindow(std::unique_ptr<World> world); | 41 | static void LaunchWindow(std::unique_ptr<World> world); |
| 42 | void populateMapTree(wxTreeItemId node, std::list<std::shared_ptr<Map>> maps); | 42 | void populateMapTree(wxTreeItemId node, std::list<std::shared_ptr<Map>> maps); |
| 43 | void SelectMap(Map* map); | 43 | void SelectMap(Map* map); |
| @@ -60,7 +60,6 @@ class MapeditFrame : public wxFrame { | |||
| 60 | void OnAddRoot(wxCommandEvent& event); | 60 | void OnAddRoot(wxCommandEvent& event); |
| 61 | void OnAddChild(wxCommandEvent& event); | 61 | void OnAddChild(wxCommandEvent& event); |
| 62 | void OnDidSelectMap(wxTreeEvent& event); | 62 | void OnDidSelectMap(wxTreeEvent& event); |
| 63 | void OnWillSelectMap(wxTreeEvent& event); | ||
| 64 | void OnWillDragMap(wxTreeEvent& event); | 63 | void OnWillDragMap(wxTreeEvent& event); |
| 65 | void OnDidDragMap(wxTreeEvent& event); | 64 | void OnDidDragMap(wxTreeEvent& event); |
| 66 | void OnRightClickTree(wxTreeEvent& event); | 65 | void OnRightClickTree(wxTreeEvent& event); |
| @@ -69,25 +68,44 @@ class MapeditFrame : public wxFrame { | |||
| 69 | 68 | ||
| 70 | std::unique_ptr<World> world; | 69 | std::unique_ptr<World> world; |
| 71 | Map* currentMap; | 70 | Map* currentMap; |
| 71 | |||
| 72 | MapeditWidget* mapEditor; | 72 | MapeditWidget* mapEditor; |
| 73 | TileWidget* tileEditor; | 73 | TileWidget* tileEditor; |
| 74 | wxTextCtrl* titleBox; | 74 | wxToolBar* toolbar; |
| 75 | std::string filename; | 75 | wxMenu* menuFile; |
| 76 | |||
| 77 | // Notebook | ||
| 76 | wxNotebook* notebook; | 78 | wxNotebook* notebook; |
| 77 | wxChoice* entityTypeBox; | 79 | wxChoice* entityTypeBox; |
| 78 | wxButton* addEntityButton; | 80 | wxButton* addEntityButton; |
| 79 | wxButton* cancelEntityButton; | 81 | wxButton* cancelEntityButton; |
| 80 | wxToolBar* toolbar; | 82 | |
| 81 | wxMenu* menuFile; | 83 | // Map tree |
| 82 | wxTreeCtrl* mapTree; | 84 | wxTreeCtrl* mapTree; |
| 83 | wxTreeItemId dragMap; | 85 | wxTreeItemId dragMap; |
| 84 | wxMenu* mapTreePopup; | 86 | wxMenu* mapTreePopup; |
| 87 | bool dontSelectMap = false; | ||
| 88 | |||
| 89 | // Property editor | ||
| 90 | UndoableTextBox* titleBox; | ||
| 91 | wxString prevTitle; | ||
| 85 | wxStaticText* startposLabel; | 92 | wxStaticText* startposLabel; |
| 86 | wxButton* setStartposButton; | 93 | wxButton* setStartposButton; |
| 87 | wxButton* cancelStartposButton; | 94 | wxButton* cancelStartposButton; |
| 88 | 95 | ||
| 96 | // Undo stuff | ||
| 97 | wxMenu* menuEdit; | ||
| 98 | std::list<std::shared_ptr<Undoable>> history; | ||
| 99 | std::list<std::shared_ptr<Undoable>>::iterator currentAction {begin(history)}; | ||
| 100 | void OnUndo(wxCommandEvent& event); | ||
| 101 | void OnRedo(wxCommandEvent& event); | ||
| 102 | void UpdateUndoLabels(); | ||
| 103 | void commitAction(std::shared_ptr<Undoable> action); | ||
| 104 | void commitAfter(std::shared_ptr<Undoable> action); | ||
| 105 | |||
| 89 | bool addingEntity = false; | 106 | bool addingEntity = false; |
| 90 | 107 | ||
| 108 | private: | ||
| 91 | wxDECLARE_EVENT_TABLE(); | 109 | wxDECLARE_EVENT_TABLE(); |
| 92 | }; | 110 | }; |
| 93 | 111 | ||
| 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) | |||
| 19 | world = map.world; | 19 | world = map.world; |
| 20 | treeItemId = map.treeItemId; | 20 | treeItemId = map.treeItemId; |
| 21 | children = map.children; | 21 | children = map.children; |
| 22 | hidden = map.hidden; | ||
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | Map::Map(Map&& map) : Map(-1, map.world) | 25 | Map::Map(Map&& map) : Map(-1, map.world) |
| @@ -49,6 +50,7 @@ void swap(Map& first, Map& second) | |||
| 49 | std::swap(first.world, second.world); | 50 | std::swap(first.world, second.world); |
| 50 | std::swap(first.treeItemId, second.treeItemId); | 51 | std::swap(first.treeItemId, second.treeItemId); |
| 51 | std::swap(first.children, second.children); | 52 | std::swap(first.children, second.children); |
| 53 | std::swap(first.hidden, second.hidden); | ||
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | int Map::getID() const | 56 | int Map::getID() const |
| @@ -118,6 +120,11 @@ World* Map::getWorld() const | |||
| 118 | return world; | 120 | return world; |
| 119 | } | 121 | } |
| 120 | 122 | ||
| 123 | bool Map::getHidden() const | ||
| 124 | { | ||
| 125 | return hidden; | ||
| 126 | } | ||
| 127 | |||
| 121 | void Map::setTitle(std::string title, bool dirty) | 128 | void Map::setTitle(std::string title, bool dirty) |
| 122 | { | 129 | { |
| 123 | this->title = title; | 130 | this->title = title; |
| @@ -149,7 +156,7 @@ void Map::setMapdata(int* mapdata, bool dirty) | |||
| 149 | } | 156 | } |
| 150 | } | 157 | } |
| 151 | 158 | ||
| 152 | void Map::addObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty) | 159 | void Map::addObject(std::shared_ptr<MapObjectEntry> obj, bool dirty) |
| 153 | { | 160 | { |
| 154 | objects.push_back(obj); | 161 | objects.push_back(obj); |
| 155 | 162 | ||
| @@ -159,7 +166,7 @@ void Map::addObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty) | |||
| 159 | } | 166 | } |
| 160 | } | 167 | } |
| 161 | 168 | ||
| 162 | void Map::removeObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty) | 169 | void Map::removeObject(std::shared_ptr<MapObjectEntry> obj, bool dirty) |
| 163 | { | 170 | { |
| 164 | objects.remove(obj); | 171 | objects.remove(obj); |
| 165 | 172 | ||
| @@ -203,3 +210,8 @@ void Map::setExpanded(bool exp) | |||
| 203 | { | 210 | { |
| 204 | expanded = exp; | 211 | expanded = exp; |
| 205 | } | 212 | } |
| 213 | |||
| 214 | void Map::setHidden(bool hid) | ||
| 215 | { | ||
| 216 | hidden = hid; | ||
| 217 | } | ||
| 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 | |||
| 53 | 53 | ||
| 54 | struct MapObjectEntry { | 54 | struct MapObjectEntry { |
| 55 | MapObject* object; | 55 | MapObject* object; |
| 56 | std::pair<double, double> position; | 56 | std::pair<int, int> position; |
| 57 | 57 | ||
| 58 | bool operator==(MapObjectEntry& other) const | 58 | bool operator==(MapObjectEntry& other) const |
| 59 | { | 59 | { |
| @@ -85,17 +85,19 @@ class Map { | |||
| 85 | std::list<std::shared_ptr<Map>> getChildren() const; | 85 | std::list<std::shared_ptr<Map>> getChildren() const; |
| 86 | bool getExpanded() const; | 86 | bool getExpanded() const; |
| 87 | World* getWorld() const; | 87 | World* getWorld() const; |
| 88 | bool getHidden() const; | ||
| 88 | 89 | ||
| 89 | void setTitle(std::string title, bool dirty = true); | 90 | void setTitle(std::string title, bool dirty = true); |
| 90 | void setTileAt(int x, int y, int tile, bool dirty = true); | 91 | void setTileAt(int x, int y, int tile, bool dirty = true); |
| 91 | void setMapdata(int* mapdata, bool dirty = true); | 92 | void setMapdata(int* mapdata, bool dirty = true); |
| 92 | void addObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty = true); | 93 | void addObject(std::shared_ptr<MapObjectEntry> obj, bool dirty = true); |
| 93 | void removeObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty = true); | 94 | void removeObject(std::shared_ptr<MapObjectEntry> obj, bool dirty = true); |
| 94 | void setLeftmap(int id, bool dirty = true); | 95 | void setLeftmap(int id, bool dirty = true); |
| 95 | void setRightmap(int id, bool dirty = true); | 96 | void setRightmap(int id, bool dirty = true); |
| 96 | void setTreeItemId(wxTreeItemId id); | 97 | void setTreeItemId(wxTreeItemId id); |
| 97 | void addChild(int id); | 98 | void addChild(int id); |
| 98 | void setExpanded(bool exp); | 99 | void setExpanded(bool exp); |
| 100 | void setHidden(bool hid); | ||
| 99 | 101 | ||
| 100 | private: | 102 | private: |
| 101 | int id; | 103 | int id; |
| @@ -108,6 +110,7 @@ class Map { | |||
| 108 | int rightmap = -1; | 110 | int rightmap = -1; |
| 109 | wxTreeItemId treeItemId; | 111 | wxTreeItemId treeItemId; |
| 110 | bool expanded = false; | 112 | bool expanded = false; |
| 113 | bool hidden = false; | ||
| 111 | }; | 114 | }; |
| 112 | 115 | ||
| 113 | #endif | 116 | #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 @@ | |||
| 1 | #include "undo.h" | ||
| 2 | #include "frame.h" | ||
| 3 | |||
| 4 | Undoable::Undoable(std::string title, std::function<void ()> forward, std::function<void ()> backward) | ||
| 5 | { | ||
| 6 | this->title = title; | ||
| 7 | this->forward = forward; | ||
| 8 | this->backward = backward; | ||
| 9 | } | ||
| 10 | |||
| 11 | std::string Undoable::getTitle() const | ||
| 12 | { | ||
| 13 | return title; | ||
| 14 | } | ||
| 15 | |||
| 16 | void Undoable::apply() | ||
| 17 | { | ||
| 18 | forward(); | ||
| 19 | } | ||
| 20 | |||
| 21 | void Undoable::undo() | ||
| 22 | { | ||
| 23 | backward(); | ||
| 24 | } | ||
| 25 | |||
| 26 | wxBEGIN_EVENT_TABLE(UndoableTextBox, wxTextCtrl) | ||
| 27 | EVT_SET_FOCUS(UndoableTextBox::OnFocus) | ||
| 28 | EVT_KILL_FOCUS(UndoableTextBox::OnKillFocus) | ||
| 29 | wxEND_EVENT_TABLE() | ||
| 30 | |||
| 31 | 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) | ||
| 32 | { | ||
| 33 | this->undoText = undoType; | ||
| 34 | this->realParent = realParent; | ||
| 35 | |||
| 36 | Init(); | ||
| 37 | } | ||
| 38 | |||
| 39 | void UndoableTextBox::Init() | ||
| 40 | { | ||
| 41 | Bind(wxEVT_TEXT, &UndoableTextBox::OnTextChange, this); | ||
| 42 | |||
| 43 | curText = GetValue(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void UndoableTextBox::OnFocus(wxFocusEvent& event) | ||
| 47 | { | ||
| 48 | curText = GetValue(); | ||
| 49 | |||
| 50 | event.Skip(); | ||
| 51 | } | ||
| 52 | |||
| 53 | void UndoableTextBox::OnKillFocus(wxFocusEvent& event) | ||
| 54 | { | ||
| 55 | undo.reset(); | ||
| 56 | |||
| 57 | event.Skip(); | ||
| 58 | } | ||
| 59 | |||
| 60 | void UndoableTextBox::OnTextChange(wxCommandEvent& event) | ||
| 61 | { | ||
| 62 | if (!undo) | ||
| 63 | { | ||
| 64 | auto tempUndo = std::make_shared<Undo>(undoText, curText, *this); | ||
| 65 | |||
| 66 | realParent->commitAfter(tempUndo); | ||
| 67 | |||
| 68 | undo = tempUndo; | ||
| 69 | } | ||
| 70 | |||
| 71 | undo->newText = GetValue(); | ||
| 72 | curText = GetValue(); | ||
| 73 | |||
| 74 | event.Skip(); | ||
| 75 | } | ||
| 76 | |||
| 77 | UndoableTextBox::Undo::Undo(std::string title, wxString origText, UndoableTextBox& parent) : origText(origText), parent(parent) | ||
| 78 | { | ||
| 79 | this->title = title; | ||
| 80 | } | ||
| 81 | |||
| 82 | void UndoableTextBox::Undo::apply() | ||
| 83 | { | ||
| 84 | parent.ChangeValue(newText); | ||
| 85 | } | ||
| 86 | |||
| 87 | void UndoableTextBox::Undo::undo() | ||
| 88 | { | ||
| 89 | parent.ChangeValue(origText); | ||
| 90 | } | ||
| 91 | |||
| 92 | void UndoableTextBox::Undo::endChanges() | ||
| 93 | { | ||
| 94 | parent.undo.reset(); | ||
| 95 | } | ||
| 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 @@ | |||
| 1 | #ifndef UNDO_H | ||
| 2 | #define UNDO_H | ||
| 3 | |||
| 4 | #include <wx/wxprec.h> | ||
| 5 | |||
| 6 | #ifndef WX_PRECOMP | ||
| 7 | #include <wx/wx.h> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #include <functional> | ||
| 11 | #include <string> | ||
| 12 | #include <list> | ||
| 13 | |||
| 14 | class MapeditFrame; | ||
| 15 | |||
| 16 | class Undoable { | ||
| 17 | public: | ||
| 18 | Undoable(std::string title, std::function<void ()> forward, std::function<void ()> backward); | ||
| 19 | virtual std::string getTitle() const; | ||
| 20 | virtual void apply(); | ||
| 21 | virtual void undo(); | ||
| 22 | virtual void endChanges() {} | ||
| 23 | |||
| 24 | protected: | ||
| 25 | Undoable() {} | ||
| 26 | |||
| 27 | std::string title; | ||
| 28 | std::function<void ()> forward; | ||
| 29 | std::function<void ()> backward; | ||
| 30 | }; | ||
| 31 | |||
| 32 | class UndoableTextBox : public wxTextCtrl { | ||
| 33 | public: | ||
| 34 | UndoableTextBox(); | ||
| 35 | UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize, long style = 0); | ||
| 36 | |||
| 37 | private: | ||
| 38 | class Undo : public Undoable { | ||
| 39 | public: | ||
| 40 | Undo(std::string title, wxString origText, UndoableTextBox& parent); | ||
| 41 | void apply(); | ||
| 42 | void undo(); | ||
| 43 | void endChanges(); | ||
| 44 | |||
| 45 | wxString origText; | ||
| 46 | wxString newText; | ||
| 47 | UndoableTextBox& parent; | ||
| 48 | }; | ||
| 49 | |||
| 50 | void Init(); | ||
| 51 | void OnFocus(wxFocusEvent& event); | ||
| 52 | void OnKillFocus(wxFocusEvent& event); | ||
| 53 | void OnTextChange(wxCommandEvent& event); | ||
| 54 | |||
| 55 | MapeditFrame* realParent; | ||
| 56 | std::string undoText; | ||
| 57 | wxString curText; | ||
| 58 | std::shared_ptr<Undo> undo; | ||
| 59 | |||
| 60 | wxDECLARE_EVENT_TABLE(); | ||
| 61 | }; | ||
| 62 | |||
| 63 | #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&) | |||
| 55 | for (int x=0; x<MAP_WIDTH; x++) | 55 | for (int x=0; x<MAP_WIDTH; x++) |
| 56 | { | 56 | { |
| 57 | int tile = map->getTileAt(x, y); | 57 | int tile = map->getTileAt(x, y); |
| 58 | if (changeBuffer.find({x,y}) != end(changeBuffer)) | ||
| 59 | { | ||
| 60 | tile = tileWidget->getSelected(); | ||
| 61 | } | ||
| 62 | |||
| 58 | 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); | 63 | 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); |
| 59 | } | 64 | } |
| 60 | } | 65 | } |
| @@ -151,6 +156,21 @@ void MapeditWidget::OnPaint(wxPaintEvent&) | |||
| 151 | dc.SetPen(pen); | 156 | dc.SetPen(pen); |
| 152 | dc.SetBrush(*wxTRANSPARENT_BRUSH); | 157 | dc.SetBrush(*wxTRANSPARENT_BRUSH); |
| 153 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); | 158 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); |
| 159 | } else if ((editMode == EditEntities) && (movingEntity != nullptr)) | ||
| 160 | { | ||
| 161 | wxBitmap sprite = movingEntity->object->getSprite(); | ||
| 162 | tiles_dc.SelectObject(wxNullBitmap); | ||
| 163 | tiles_dc.SelectObject(sprite); | ||
| 164 | |||
| 165 | wxPoint pos {mousePos.x - movingEntity->object->getWidth()/2*scale, mousePos.y - movingEntity->object->getHeight()/2*scale}; | ||
| 166 | wxSize size {movingEntity->object->getWidth()*scale, movingEntity->object->getHeight()*scale}; | ||
| 167 | |||
| 168 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, movingEntity->object->getWidth(), movingEntity->object->getHeight()); | ||
| 169 | |||
| 170 | wxPen pen(*wxGREEN, 2); | ||
| 171 | dc.SetPen(pen); | ||
| 172 | dc.SetBrush(*wxTRANSPARENT_BRUSH); | ||
| 173 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); | ||
| 154 | } | 174 | } |
| 155 | } | 175 | } |
| 156 | } | 176 | } |
| @@ -167,7 +187,8 @@ void MapeditWidget::SetTile(wxPoint pos) | |||
| 167 | int x = (pos.x + vX) / (TILE_WIDTH * scale); | 187 | int x = (pos.x + vX) / (TILE_WIDTH * scale); |
| 168 | int y = (pos.y + vY) / (TILE_HEIGHT * scale); | 188 | int y = (pos.y + vY) / (TILE_HEIGHT * scale); |
| 169 | 189 | ||
| 170 | map->setTileAt(x, y, tileWidget->getSelected()); | 190 | changeBuffer.insert({x,y}); |
| 191 | |||
| 171 | Refresh(); | 192 | Refresh(); |
| 172 | } | 193 | } |
| 173 | 194 | ||
| @@ -191,17 +212,42 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
| 191 | { | 212 | { |
| 192 | int x = (event.GetPosition().x + vX) / scale - (addingEntity->getWidth() / 2); | 213 | int x = (event.GetPosition().x + vX) / scale - (addingEntity->getWidth() / 2); |
| 193 | int y = (event.GetPosition().y + vY) / scale - (addingEntity->getHeight() / 2); | 214 | int y = (event.GetPosition().y + vY) / scale - (addingEntity->getHeight() / 2); |
| 194 | 215 | ||
| 195 | auto data = std::make_shared<MapObjectEntry>(); | 216 | auto data = std::make_shared<MapObjectEntry>(); |
| 196 | data->object = addingEntity; | 217 | data->object = addingEntity; |
| 197 | data->position = std::make_pair(x,y); | 218 | data->position = std::make_pair(x,y); |
| 198 | map->addObject(data); | ||
| 199 | 219 | ||
| 200 | addingEntity = nullptr; | 220 | frame->commitAction(std::make_shared<Undoable>("Add " + addingEntity->getType(), [=] () { |
| 221 | map->addObject(data); | ||
| 222 | |||
| 223 | Refresh(); | ||
| 224 | }, [=] () { | ||
| 225 | map->removeObject(data); | ||
| 226 | |||
| 227 | Refresh(); | ||
| 228 | })); | ||
| 201 | 229 | ||
| 202 | frame->SetIsAddingEntity(false); | 230 | frame->SetIsAddingEntity(false); |
| 231 | addingEntity = nullptr; | ||
| 232 | } else if (movingEntity != nullptr) | ||
| 233 | { | ||
| 234 | int x = (event.GetPosition().x + vX) / scale - (movingEntity->object->getWidth() / 2); | ||
| 235 | int y = (event.GetPosition().y + vY) / scale - (movingEntity->object->getHeight() / 2); | ||
| 236 | auto oldPos = movingEntity->position; | ||
| 237 | MapObjectEntry* me = movingEntity; | ||
| 203 | 238 | ||
| 204 | Refresh(); | 239 | frame->commitAction(std::make_shared<Undoable>("Move " + movingEntity->object->getType(), [=] () { |
| 240 | me->position = std::make_pair(x,y); | ||
| 241 | |||
| 242 | Refresh(); | ||
| 243 | }, [=] () { | ||
| 244 | me->position = oldPos; | ||
| 245 | |||
| 246 | Refresh(); | ||
| 247 | })); | ||
| 248 | |||
| 249 | frame->SetIsAddingEntity(false); | ||
| 250 | movingEntity = nullptr; | ||
| 205 | } else { | 251 | } else { |
| 206 | int x = (event.GetPosition().x + vX) / scale; | 252 | int x = (event.GetPosition().x + vX) / scale; |
| 207 | int y = (event.GetPosition().y + vY) / scale; | 253 | int y = (event.GetPosition().y + vY) / scale; |
| @@ -211,9 +257,7 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
| 211 | if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) | 257 | if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) |
| 212 | && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) | 258 | && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) |
| 213 | { | 259 | { |
| 214 | addingEntity = selectedEntity->object; | 260 | movingEntity = selectedEntity.get(); |
| 215 | map->removeObject(selectedEntity); | ||
| 216 | selectedEntity.reset(); | ||
| 217 | frame->SetIsAddingEntity(true); | 261 | frame->SetIsAddingEntity(true); |
| 218 | } else { | 262 | } else { |
| 219 | selectedEntity.reset(); | 263 | selectedEntity.reset(); |
| @@ -241,12 +285,23 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
| 241 | { | 285 | { |
| 242 | int x = (event.GetPosition().x + vX) / scale - (PLAYER_WIDTH[currentPlayer] / 2); | 286 | int x = (event.GetPosition().x + vX) / scale - (PLAYER_WIDTH[currentPlayer] / 2); |
| 243 | int y = (event.GetPosition().y + vY) / scale - (PLAYER_HEIGHT[currentPlayer] / 2); | 287 | int y = (event.GetPosition().y + vY) / scale - (PLAYER_HEIGHT[currentPlayer] / 2); |
| 288 | auto oldPos = map->getWorld()->getStartingPosition(); | ||
| 289 | auto oldSMap = map->getWorld()->getStartingMap(); | ||
| 290 | |||
| 291 | frame->commitAction(std::make_shared<Undoable>("Set Starting Position", [=] () { | ||
| 292 | map->getWorld()->setStart(map, {x, y}); | ||
| 293 | frame->SetStartposLabel(); | ||
| 294 | |||
| 295 | Refresh(); | ||
| 296 | }, [=] () { | ||
| 297 | map->getWorld()->setStart(oldSMap, oldPos); | ||
| 298 | frame->SetStartposLabel(); | ||
| 299 | |||
| 300 | Refresh(); | ||
| 301 | })); | ||
| 244 | 302 | ||
| 245 | map->getWorld()->setStart(map, {x, y}); | ||
| 246 | isSettingPos = false; | 303 | isSettingPos = false; |
| 247 | frame->SetIsSettingStart(false); | 304 | frame->SetIsSettingStart(false); |
| 248 | |||
| 249 | Refresh(); | ||
| 250 | } | 305 | } |
| 251 | 306 | ||
| 252 | event.Skip(); | 307 | event.Skip(); |
| @@ -299,6 +354,34 @@ void MapeditWidget::OnMouseMove(wxMouseEvent& event) | |||
| 299 | void MapeditWidget::OnMouseUp(wxMouseEvent&) | 354 | void MapeditWidget::OnMouseUp(wxMouseEvent&) |
| 300 | { | 355 | { |
| 301 | mouseIsDown = false; | 356 | mouseIsDown = false; |
| 357 | |||
| 358 | if (editMode == EditTiles) | ||
| 359 | { | ||
| 360 | std::map<std::pair<int, int>, int> localChangeBuffer; | ||
| 361 | for (auto assign : changeBuffer) | ||
| 362 | { | ||
| 363 | localChangeBuffer[assign] = map->getTileAt(assign.first, assign.second); | ||
| 364 | } | ||
| 365 | |||
| 366 | int localSelection = tileWidget->getSelected(); | ||
| 367 | frame->commitAction(std::make_shared<Undoable>("Paint Map", [=] () { | ||
| 368 | for (auto assign : localChangeBuffer) | ||
| 369 | { | ||
| 370 | map->setTileAt(assign.first.first, assign.first.second, localSelection); | ||
| 371 | } | ||
| 372 | |||
| 373 | Refresh(); | ||
| 374 | }, [=] () { | ||
| 375 | for (auto assign : localChangeBuffer) | ||
| 376 | { | ||
| 377 | map->setTileAt(assign.first.first, assign.first.second, assign.second); | ||
| 378 | } | ||
| 379 | |||
| 380 | Refresh(); | ||
| 381 | })); | ||
| 382 | |||
| 383 | changeBuffer.clear(); | ||
| 384 | } | ||
| 302 | } | 385 | } |
| 303 | 386 | ||
| 304 | void MapeditWidget::OnMouseOut(wxMouseEvent&) | 387 | void MapeditWidget::OnMouseOut(wxMouseEvent&) |
| @@ -350,6 +433,7 @@ void MapeditWidget::StartAddingEntity(MapObject* object) | |||
| 350 | void MapeditWidget::CancelAddingEntity() | 433 | void MapeditWidget::CancelAddingEntity() |
| 351 | { | 434 | { |
| 352 | addingEntity = nullptr; | 435 | addingEntity = nullptr; |
| 436 | movingEntity = nullptr; | ||
| 353 | } | 437 | } |
| 354 | 438 | ||
| 355 | void MapeditWidget::SetIsSettingStart(bool isSetting) | 439 | void MapeditWidget::SetIsSettingStart(bool isSetting) |
| @@ -369,6 +453,10 @@ void MapeditWidget::SetIsSettingStart(bool isSetting) | |||
| 369 | void MapeditWidget::SetMap(Map* map) | 453 | void MapeditWidget::SetMap(Map* map) |
| 370 | { | 454 | { |
| 371 | this->map = map; | 455 | this->map = map; |
| 456 | selectedEntity = nullptr; | ||
| 457 | addingEntity = nullptr; | ||
| 458 | movingEntity = nullptr; | ||
| 459 | isSettingPos = false; | ||
| 372 | 460 | ||
| 373 | Refresh(); | 461 | Refresh(); |
| 374 | } | 462 | } |
| 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 @@ | |||
| 11 | #include "tile_widget.h" | 11 | #include "tile_widget.h" |
| 12 | #include <list> | 12 | #include <list> |
| 13 | #include <memory> | 13 | #include <memory> |
| 14 | #include <utility> | ||
| 15 | #include <set> | ||
| 14 | 16 | ||
| 15 | class MapeditFrame; | 17 | class MapeditFrame; |
| 16 | 18 | ||
| @@ -58,8 +60,10 @@ class MapeditWidget : public wxScrolledWindow { | |||
| 58 | EditMode editMode = EditTiles; | 60 | EditMode editMode = EditTiles; |
| 59 | int currentPlayer = 0; | 61 | int currentPlayer = 0; |
| 60 | bool isSettingPos = false; | 62 | bool isSettingPos = false; |
| 63 | std::set<std::pair<int,int>> changeBuffer; | ||
| 61 | 64 | ||
| 62 | MapObject* addingEntity = nullptr; | 65 | MapObject* addingEntity = nullptr; |
| 66 | MapObjectEntry* movingEntity = nullptr; | ||
| 63 | std::shared_ptr<MapObjectEntry> selectedEntity; | 67 | std::shared_ptr<MapObjectEntry> selectedEntity; |
| 64 | 68 | ||
| 65 | DECLARE_DYNAMIC_CLASS(MapeditWidget) | 69 | 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) | |||
| 135 | } else if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-position")) | 135 | } else if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-position")) |
| 136 | { | 136 | { |
| 137 | xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); | 137 | xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); |
| 138 | sscanf((char*) key, "%lf,%lf", &data->position.first, &data->position.second); | 138 | sscanf((char*) key, "%d,%d", &data->position.first, &data->position.second); |
| 139 | xmlFree(key); | 139 | xmlFree(key); |
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| @@ -268,6 +268,8 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
| 268 | { | 268 | { |
| 269 | Map& map = *mapPair.second; | 269 | Map& map = *mapPair.second; |
| 270 | 270 | ||
| 271 | if (map.getHidden()) continue; | ||
| 272 | |||
| 271 | // <map> | 273 | // <map> |
| 272 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "map"); | 274 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "map"); |
| 273 | if (rc < 0) throw MapWriteException(name); | 275 | if (rc < 0) throw MapWriteException(name); |
