From 0d30e9b57229905f78e7bd60fe5d3cde72851f28 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Mon, 16 Mar 2015 16:53:05 -0400 Subject: Rewrote map editor so a single file contains all maps Maps are viewed in a tree control on the left. They can be dragged and dropped. Maps are bolded when they are dirty. Saving saves expansion status and order of maps in tree. --- tools/mapedit/CMakeLists.txt | 1 + tools/mapedit/src/frame.cpp | 321 ++++++++++++++++++++++++++++++------- tools/mapedit/src/frame.h | 32 +++- tools/mapedit/src/main.cpp | 2 +- tools/mapedit/src/map.cpp | 289 +++++++++++++-------------------- tools/mapedit/src/map.h | 45 ++++-- tools/mapedit/src/widget.cpp | 7 + tools/mapedit/src/widget.h | 3 +- tools/mapedit/src/world.cpp | 369 +++++++++++++++++++++++++++++++++++++++++++ tools/mapedit/src/world.h | 45 ++++++ 10 files changed, 859 insertions(+), 255 deletions(-) create mode 100644 tools/mapedit/src/world.cpp create mode 100644 tools/mapedit/src/world.h (limited to 'tools/mapedit') diff --git a/tools/mapedit/CMakeLists.txt b/tools/mapedit/CMakeLists.txt index 9343f06..12af38c 100644 --- a/tools/mapedit/CMakeLists.txt +++ b/tools/mapedit/CMakeLists.txt @@ -44,6 +44,7 @@ add_executable(AromatherapyMapEditor src/widget.cpp src/tile_widget.cpp src/object.cpp + src/world.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 a38b861..9d489b8 100644 --- a/tools/mapedit/src/frame.cpp +++ b/tools/mapedit/src/frame.cpp @@ -5,6 +5,7 @@ #include #include "panel.h" #include +#include static std::list openWindows; @@ -15,9 +16,18 @@ enum { MENU_FILE_OPEN, MENU_FILE_SAVE, MENU_FILE_CLOSE, + MENU_MAP_ADD_ROOT, + MENU_MAP_ADD_CHILD, TOOL_FILE_NEW, TOOL_FILE_OPEN, - TOOL_FILE_SAVE + TOOL_FILE_SAVE, + TOOL_MAP_ADD_ROOT, + TOOL_MAP_ADD_CHILD, + MAP_EDITOR_NOTEBOOK, + MAP_EDITOR_TREE, + MAP_TITLE_TEXTBOX, + ADD_ENTITY_BUTTON, + CANCEL_ENTITY_BUTTON }; wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) @@ -27,22 +37,41 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) EVT_MENU(MENU_FILE_NEW, MapeditFrame::OnNew) EVT_MENU(MENU_FILE_OPEN, MapeditFrame::OnOpen) EVT_MENU(MENU_FILE_SAVE, MapeditFrame::OnSave) + EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) + EVT_MENU(MENU_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) + EVT_MENU(MENU_MAP_ADD_CHILD, MapeditFrame::OnAddChild) EVT_TOOL(TOOL_FILE_NEW, MapeditFrame::OnNew) EVT_TOOL(TOOL_FILE_OPEN, MapeditFrame::OnOpen) EVT_TOOL(TOOL_FILE_SAVE, MapeditFrame::OnSave) - EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) + EVT_TOOL(TOOL_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) + EVT_TOOL(TOOL_MAP_ADD_CHILD, MapeditFrame::OnAddChild) 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) + EVT_TEXT(MAP_TITLE_TEXTBOX, MapeditFrame::OnTitleChange) + EVT_BUTTON(ADD_ENTITY_BUTTON, MapeditFrame::OnAddEntity) + EVT_BUTTON(CANCEL_ENTITY_BUTTON, MapeditFrame::OnCancelAddEntity) wxEND_EVENT_TABLE() -MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_ANY, "Map Editor", wxDefaultPosition, wxSize(GAME_WIDTH*3, GAME_HEIGHT*2)), map(map), filename(filename) +MapeditFrame::MapeditFrame(std::unique_ptr world) : wxFrame(NULL, wxID_ANY, "Map Editor", wxDefaultPosition, wxSize(GAME_WIDTH*2+TILE_WIDTH*6*6+10+10+150, GAME_HEIGHT*3)) { - this->map.frame = this; + this->world = std::move(world); + this->world->setParent(this); + currentMap = this->world->getLastMap(); - wxMenu* menuFile = new wxMenu; + menuFile = new wxMenu; menuFile->Append(MENU_FILE_NEW, "New\tCtrl-N"); menuFile->Append(MENU_FILE_OPEN, "Open\tCtrl-O"); menuFile->Append(MENU_FILE_SAVE, "Save\tCtrl-S"); menuFile->Append(MENU_FILE_CLOSE, "Close\tCtrl-W"); + menuFile->AppendSeparator(); + menuFile->Append(MENU_MAP_ADD_ROOT, "New Map\tCtrl-Alt-N"); + menuFile->Append(MENU_MAP_ADD_CHILD, "New Child Map\tCtrl-Alt-Shift-N"); + menuFile->AppendSeparator(); menuFile->Append(wxID_EXIT); wxMenu* menuView = new wxMenu; @@ -59,22 +88,27 @@ MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_A // Layout 2: Non-splitter between layout 3 and notebook // Layout 3: Splitter between map editor and properties editor - wxSplitterWindow* layout3 = new wxSplitterWindow(this, wxID_ANY); + wxSplitterWindow* layout1 = new wxSplitterWindow(this, wxID_ANY); + mapTree = new wxTreeCtrl(layout1, MAP_EDITOR_TREE, wxDefaultPosition, wxSize(200, 0), wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS); + wxTreeItemId mapTreeRoot = mapTree->AddRoot("root"); + populateMapTree(mapTreeRoot, this->world->getRootMaps()); + + wxPanel* layout2 = new wxPanel(layout1, wxID_ANY); + + wxSplitterWindow* layout3 = new wxSplitterWindow(layout2, wxID_ANY); layout3->SetSashGravity(1.0); - layout3->SetMinimumPaneSize(20); - notebook = new wxNotebook(this, wxID_ANY); + notebook = new wxNotebook(layout2, MAP_EDITOR_NOTEBOOK); tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); - notebook->AddPage(tileEditor, "Tile Chooser", true); + notebook->AddPage(tileEditor, "Tile Chooser", false); - mapEditor = new MapeditWidget(layout3, wxID_ANY, &this->map, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); + mapEditor = new MapeditWidget(layout3, wxID_ANY, currentMap, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); mapEditor->frame = this; // Set up property editor wxPanel* propertyEditor = new wxPanel(layout3, wxID_ANY); - titleBox = new wxTextCtrl(propertyEditor, wxID_ANY, map.getTitle()); - titleBox->Bind(wxEVT_TEXT, &MapeditFrame::OnTitleChange, this); + titleBox = new wxTextCtrl(propertyEditor, MAP_TITLE_TEXTBOX, currentMap->getTitle()); wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); @@ -103,12 +137,9 @@ MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_A entityTypeBox->Append(entry.second->getType(), entry.second.get()); } - addEntityButton = new wxButton(entityEditor, wxID_ANY, "Add Entity"); - addEntityButton->Bind(wxEVT_BUTTON, &MapeditFrame::OnAddEntity, this); - - cancelEntityButton = new wxButton(entityEditor, wxID_ANY, "Cancel"); + addEntityButton = new wxButton(entityEditor, ADD_ENTITY_BUTTON, "Add Entity"); + cancelEntityButton = new wxButton(entityEditor, CANCEL_ENTITY_BUTTON, "Cancel"); cancelEntityButton->Disable(); - cancelEntityButton->Bind(wxEVT_BUTTON, &MapeditFrame::OnCancelAddEntity, this); wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); @@ -129,51 +160,65 @@ MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_A // Finish setting up the layouts layout3->SplitHorizontally(mapEditor, propertyEditor); + layout1->SplitVertically(mapTree, layout2); - notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MapeditFrame::OnTabChange, this); - notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, &MapeditFrame::OnTabChanging, this); + wxBoxSizer* sizer1 = new wxBoxSizer(wxHORIZONTAL); + sizer1->Add(layout1, 1, wxEXPAND, 0); + sizer1->Add(mapTree, 0, wxALIGN_TOP | wxALIGN_LEFT, 0); + sizer1->Add(layout2, 1, wxEXPAND, 0); + layout1->SetSizer(sizer1); + sizer1->SetSizeHints(layout1); wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL); sizer2->Add(layout3, 1, wxEXPAND, 0); sizer2->Add(notebook, 0, wxALIGN_TOP | wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxEXPAND, 2); - this->SetSizer(sizer2); - sizer2->SetSizeHints(this); + layout2->SetSizer(sizer2); + sizer2->SetSizeHints(layout2); wxBoxSizer* splitterSizer = new wxBoxSizer(wxVERTICAL); splitterSizer->Add(layout3, 1, wxEXPAND, 0); splitterSizer->Add(mapEditor, 1, wxEXPAND, 0); - splitterSizer->Add(propertyEditor, 0, wxALIGN_TOP, wxALIGN_LEFT, 0); + splitterSizer->Add(propertyEditor, 0, wxALIGN_TOP | wxALIGN_LEFT, 0); layout3->SetSizer(splitterSizer); splitterSizer->SetSizeHints(layout3); // Toolbar time! toolbar = CreateToolBar(); - toolbar->AddTool(TOOL_FILE_NEW, "New", wxBitmap(wxImage("res/page_add.png"))); + toolbar->AddTool(TOOL_FILE_NEW, "New", wxBitmap(wxImage("res/page.png"))); toolbar->AddTool(TOOL_FILE_OPEN, "Open", wxBitmap(wxImage("res/folder_page.png"))); toolbar->AddTool(TOOL_FILE_SAVE, "Save", wxBitmap(wxImage("res/disk.png"))); - toolbar->EnableTool(TOOL_FILE_SAVE, this->map.getDirty()); + toolbar->AddSeparator(); + toolbar->AddTool(TOOL_MAP_ADD_ROOT, "Add Map", wxBitmap(wxImage("res/page_add.png"))); + toolbar->AddTool(TOOL_MAP_ADD_CHILD, "Add Child Map", wxBitmap(wxImage("res/page_white_add.png"))); + toolbar->EnableTool(TOOL_FILE_SAVE, this->world->getDirty()); toolbar->Realize(); + + mapTree->SetFocusedItem(currentMap->getTreeItemId()); + SelectMap(currentMap); + + Maximize(true); } void MapeditFrame::OnExit(wxCloseEvent& event) { - if (event.CanVeto() && map.hasUnsavedChanges()) + if (event.CanVeto() && world->getDirty()) { - switch (wxMessageBox("Current map has unsaved changes. Save before closing?", "Please confirm", wxICON_QUESTION|wxYES_NO|wxCANCEL, this)) + switch (wxMessageBox("One or more maps have unsaved changes. Save before closing?", "Please confirm", wxICON_QUESTION|wxYES_NO|wxCANCEL, this)) { case wxYES: - if (filename == "") + if (world->getFilename() == "") { - wxFileDialog saveFileDialog(this, "Save map", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); + wxFileDialog saveFileDialog(this, "Save world", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); if (saveFileDialog.ShowModal() == wxID_CANCEL) { return; } - filename = saveFileDialog.GetPath().ToStdString(); + world->save(saveFileDialog.GetPath().ToStdString(), mapTree); + } else { + world->save(world->getFilename(), mapTree); } - map.save(filename); break; case wxCANCEL: @@ -204,34 +249,34 @@ void MapeditFrame::ZoomOut(wxCommandEvent&) void MapeditFrame::OnNew(wxCommandEvent&) { - NewMap(); + NewWorld(); } void MapeditFrame::OnOpen(wxCommandEvent&) { - wxFileDialog openFileDialog(this, "Open map", "", "", "XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); + wxFileDialog openFileDialog(this, "Open world", "", "", "XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); if (openFileDialog.ShowModal() == wxID_CANCEL) { return; } - OpenMap(openFileDialog.GetPath().c_str()); + OpenWorld(openFileDialog.GetPath().ToStdString()); } void MapeditFrame::OnSave(wxCommandEvent&) { - if (filename == "") + if (world->getFilename() == "") { - wxFileDialog saveFileDialog(this, "Save map", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); + wxFileDialog saveFileDialog(this, "Save world", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); if (saveFileDialog.ShowModal() == wxID_CANCEL) { return; } - filename = saveFileDialog.GetPath().ToStdString(); + world->save(saveFileDialog.GetPath().ToStdString(), mapTree); + } else { + world->save(world->getFilename(), mapTree); } - - map.save(filename); } void MapeditFrame::OnClose(wxCommandEvent&) @@ -252,24 +297,8 @@ void MapeditFrame::OnQuit(wxCommandEvent&) void MapeditFrame::OnTitleChange(wxCommandEvent&) { - map.setTitle(titleBox->GetLineText(0).ToStdString()); -} - -void MapeditFrame::NewMap() -{ - LaunchWindow(Map(), ""); -} - -void MapeditFrame::OpenMap(const char* filename) -{ - LaunchWindow(Map(filename), filename); -} - -void MapeditFrame::LaunchWindow(Map map, const char* filename) -{ - MapeditFrame* frame = new MapeditFrame(map, filename); - frame->closer = openWindows.insert(end(openWindows), frame); - frame->Show(true); + currentMap->setTitle(titleBox->GetValue().ToStdString()); + mapTree->SetItemText(currentMap->getTreeItemId(), currentMap->getTitle()); } void MapeditFrame::OnTabChange(wxBookCtrlEvent& event) @@ -317,11 +346,113 @@ void MapeditFrame::OnCancelAddEntity(wxCommandEvent&) mapEditor->CancelAddingEntity(); } +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()); +} + +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()); +} + +void MapeditFrame::OnDidSelectMap(wxTreeEvent& event) +{ + MapPtrCtr* data = (MapPtrCtr*) mapTree->GetItemData(event.GetItem()); + SelectMap(data->map); +} + +void MapeditFrame::OnWillSelectMap(wxTreeEvent& event) +{ + if (addingEntity) + { + event.Veto(); + return; + } + + event.Skip(); +} + +void MapeditFrame::OnWillDragMap(wxTreeEvent& event) +{ + if (!addingEntity) + { + event.Allow(); + dragMap = event.GetItem(); + } +} + +void MapeditFrame::OnDidDragMap(wxTreeEvent& event) +{ + if (!dragMap.IsOk()) + { + return; + } + + wxTreeItemId newParent = event.GetItem(); + if (!newParent.IsOk()) + { + newParent = mapTree->GetRootItem(); + } + + wxTreeItemId newChild = MoveTreeNode(dragMap, newParent); + dragMap.Unset(); + mapTree->SelectItem(newChild); +} + +void MapeditFrame::NewWorld() +{ + LaunchWindow(std::unique_ptr(new World())); +} + +void MapeditFrame::OpenWorld(std::string filename) +{ + try + { + auto world = std::unique_ptr(new World(filename)); + + LaunchWindow(std::move(world)); + } catch (std::exception& ex) + { + wxMessageBox(ex.what(), "Error loading world", wxOK | wxCENTRE | wxICON_ERROR); + } +} + +void MapeditFrame::LaunchWindow(std::unique_ptr world) +{ + MapeditFrame* frame = new MapeditFrame(std::move(world)); + frame->closer = openWindows.insert(end(openWindows), frame); + frame->Show(true); +} + void MapeditFrame::StartAddingEntity() { addingEntity = true; addEntityButton->Disable(); cancelEntityButton->Enable(); + + toolbar->EnableTool(TOOL_FILE_NEW, false); + toolbar->EnableTool(TOOL_FILE_OPEN, false); + toolbar->EnableTool(TOOL_FILE_SAVE, false); + toolbar->EnableTool(TOOL_MAP_ADD_ROOT, false); + toolbar->EnableTool(TOOL_MAP_ADD_CHILD, false); + + menuFile->Enable(MENU_FILE_NEW, false); + menuFile->Enable(MENU_FILE_OPEN, false); + menuFile->Enable(MENU_FILE_SAVE, false); + menuFile->Enable(MENU_MAP_ADD_ROOT, false); + menuFile->Enable(MENU_MAP_ADD_CHILD, false); } void MapeditFrame::FinishAddingEntity() @@ -329,9 +460,87 @@ void MapeditFrame::FinishAddingEntity() addingEntity = false; addEntityButton->Enable(); cancelEntityButton->Disable(); + toolbar->Enable(); + + toolbar->EnableTool(TOOL_FILE_NEW, true); + toolbar->EnableTool(TOOL_FILE_OPEN, true); + toolbar->EnableTool(TOOL_FILE_SAVE, world->getDirty()); + toolbar->EnableTool(TOOL_MAP_ADD_ROOT, true); + toolbar->EnableTool(TOOL_MAP_ADD_CHILD, true); + + menuFile->Enable(MENU_FILE_NEW, true); + menuFile->Enable(MENU_FILE_OPEN, true); + menuFile->Enable(MENU_FILE_SAVE, world->getDirty()); + menuFile->Enable(MENU_MAP_ADD_ROOT, true); + menuFile->Enable(MENU_MAP_ADD_CHILD, true); } void MapeditFrame::MapDirtyDidChange(bool dirty) { toolbar->EnableTool(TOOL_FILE_SAVE, dirty); + menuFile->Enable(MENU_FILE_SAVE, dirty); + + if (dirty) + { + mapTree->SetItemBold(currentMap->getTreeItemId(), true); + } else { + for (auto map : world->getMaps()) + { + mapTree->SetItemBold(map.second->getTreeItemId(), false); + } + } +} + +void MapeditFrame::populateMapTree(wxTreeItemId node, std::list> maps) +{ + for (auto map : maps) + { + wxTreeItemId childNode = mapTree->AppendItem(node, map->getTitle()); + mapTree->SetItemData(childNode, new MapPtrCtr(map.get())); + map->setTreeItemId(childNode); + + populateMapTree(childNode, map->getChildren()); + + if (map->getExpanded()) + { + mapTree->Expand(childNode); + } + } +} + +void MapeditFrame::SelectMap(Map* map) +{ + currentMap = map; + mapEditor->SetMap(map); + titleBox->ChangeValue(map->getTitle()); +} + +wxTreeItemId MapeditFrame::MoveTreeNode(wxTreeItemId toCopy, wxTreeItemId newParent) +{ + MapPtrCtr* ctl1 = (MapPtrCtr*) mapTree->GetItemData(toCopy); + MapPtrCtr* ctl2 = new MapPtrCtr(ctl1->map); + + wxTreeItemId copied = mapTree->AppendItem(newParent, mapTree->GetItemText(toCopy), -1, -1, ctl2); + if (mapTree->IsBold(toCopy)) + { + mapTree->SetItemBold(toCopy, true); + } + + if (mapTree->ItemHasChildren(toCopy)) + { + wxTreeItemIdValue cookie; + for (wxTreeItemId it = mapTree->GetFirstChild(toCopy, cookie); it.IsOk(); it = mapTree->GetNextChild(toCopy, cookie)) + { + MoveTreeNode(it, copied); + } + } + + if (mapTree->IsExpanded(toCopy)) + { + mapTree->Expand(copied); + } + + mapTree->Delete(toCopy); + + return copied; } diff --git a/tools/mapedit/src/frame.h b/tools/mapedit/src/frame.h index 4aa44c5..f1e4efc 100644 --- a/tools/mapedit/src/frame.h +++ b/tools/mapedit/src/frame.h @@ -12,24 +12,36 @@ #include "tile_widget.h" #include #include +#include +#include + +class MapPtrCtr : public wxTreeItemData { + public: + Map* map; + + MapPtrCtr(Map* map) : map(map) {} +}; class MapeditFrame : public wxFrame { public: MapeditFrame() {} - MapeditFrame(Map map, std::string filename); + MapeditFrame(std::unique_ptr world); MapeditWidget* GetMapEditor(); void StartAddingEntity(); void FinishAddingEntity(); void MapDirtyDidChange(bool dirty); - static void NewMap(); - static void OpenMap(const char* filename); + static void NewWorld(); + static void OpenWorld(std::string filename); std::list::iterator closer; private: - static void LaunchWindow(Map map, const char* filename); + static void LaunchWindow(std::unique_ptr world); + void populateMapTree(wxTreeItemId node, std::list> maps); + void SelectMap(Map* map); + wxTreeItemId MoveTreeNode(wxTreeItemId toCopy, wxTreeItemId newParent); void ZoomIn(wxCommandEvent& event); void ZoomOut(wxCommandEvent& event); @@ -44,8 +56,15 @@ class MapeditFrame : public wxFrame { void OnTabChanging(wxBookCtrlEvent& event); void OnAddEntity(wxCommandEvent& event); void OnCancelAddEntity(wxCommandEvent& event); + void OnAddRoot(wxCommandEvent& event); + void OnAddChild(wxCommandEvent& event); + void OnDidSelectMap(wxTreeEvent& event); + void OnWillSelectMap(wxTreeEvent& event); + void OnWillDragMap(wxTreeEvent& event); + void OnDidDragMap(wxTreeEvent& event); - Map map; + std::unique_ptr world; + Map* currentMap; MapeditWidget* mapEditor; TileWidget* tileEditor; wxTextCtrl* titleBox; @@ -55,6 +74,9 @@ class MapeditFrame : public wxFrame { wxButton* addEntityButton; wxButton* cancelEntityButton; wxToolBar* toolbar; + wxMenu* menuFile; + wxTreeCtrl* mapTree; + wxTreeItemId dragMap; bool addingEntity = false; diff --git a/tools/mapedit/src/main.cpp b/tools/mapedit/src/main.cpp index 91dd98f..b09ee9a 100644 --- a/tools/mapedit/src/main.cpp +++ b/tools/mapedit/src/main.cpp @@ -18,7 +18,7 @@ bool MapeditApp::OnInit() { wxInitAllImageHandlers(); - MapeditFrame::NewMap(); + MapeditFrame::NewWorld(); return true; } diff --git a/tools/mapedit/src/map.cpp b/tools/mapedit/src/map.cpp index f9c07fc..32541e6 100644 --- a/tools/mapedit/src/map.cpp +++ b/tools/mapedit/src/map.cpp @@ -1,106 +1,27 @@ #include "map.h" -#include -#include -#include #include "frame.h" -Map::Map() +Map::Map(int id, World* world) : id(id), world(world) { mapdata = (int*) calloc(MAP_WIDTH * MAP_HEIGHT, sizeof(int)); } -Map::Map(std::string filename) -{ - xmlDocPtr doc = xmlParseFile(filename.c_str()); - if (doc == nullptr) - { - throw MapLoadException(filename); - } - - xmlNodePtr top = xmlDocGetRootElement(doc); - if (top == nullptr) - { - throw MapLoadException(filename); - } - - if (xmlStrcmp(top->name, (const xmlChar*) "map-def")) - { - throw MapLoadException(filename); - } - - for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) - { - if (!xmlStrcmp(node->name, (const xmlChar*) "name")) - { - xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - title = (char*) key; - xmlFree(key); - } else if (!xmlStrcmp(node->name, (const xmlChar*) "environment")) - { - xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); - mapdata[0] = atoi(strtok((char*) key, ",\n")); - for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) - { - mapdata[i] = atoi(strtok(NULL, ",\n")); - } - xmlFree(key); - } else if (!xmlStrcmp(node->name, (const xmlChar*) "leftmap")) - { - xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - leftmap = (char*) key; - xmlFree(key); - } else if (!xmlStrcmp(node->name, (const xmlChar*) "rightmap")) - { - xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - rightmap = (char*) key; - xmlFree(key); - } else if (!xmlStrcmp(node->name, (const xmlChar*) "entities")) - { - for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) - { - if (!xmlStrcmp(entityNode->name, (const xmlChar*) "entity")) - { - auto data = std::make_shared(); - - for (xmlNodePtr entityDataNode = entityNode->xmlChildrenNode; entityDataNode != NULL; entityDataNode = entityDataNode->next) - { - if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-type")) - { - xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); - data->object = MapObject::getAllObjects().at((char*) key).get(); - xmlFree(key); - } 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); - xmlFree(key); - } - } - - objects.push_back(data); - } - } - } - } - - xmlFreeDoc(doc); -} - Map::Map(const Map& map) { mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); memcpy(mapdata, map.mapdata, MAP_WIDTH*MAP_HEIGHT*sizeof(int)); + id = map.id; title = map.title; leftmap = map.leftmap; rightmap = map.rightmap; - dirty = map.dirty; objects = map.objects; - frame = map.frame; + world = map.world; + treeItemId = map.treeItemId; + children = map.children; } -Map::Map(Map&& map) : Map() +Map::Map(Map&& map) : Map(-1, map.world) { swap(*this, map); } @@ -123,141 +44,157 @@ void swap(Map& first, Map& second) std::swap(first.title, second.title); std::swap(first.leftmap, second.leftmap); std::swap(first.rightmap, second.rightmap); - std::swap(first.dirty, second.dirty); std::swap(first.objects, second.objects); - std::swap(first.frame, second.frame); + std::swap(first.id, second.id); + std::swap(first.world, second.world); + std::swap(first.treeItemId, second.treeItemId); + std::swap(first.children, second.children); } -#define MY_ENCODING "ISO-8859-1" +int Map::getID() const +{ + return id; +} -void Map::save(std::string name) +std::string Map::getTitle() const { - if (!dirty) return; - - int rc; - - xmlTextWriterPtr writer = xmlNewTextWriterFilename(name.c_str(), 0); - if (writer == NULL) throw MapWriteException(name); + return title; +} - rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterStartElement(writer, (xmlChar*) "map-def"); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterWriteElement(writer, (xmlChar*) "name", (xmlChar*) title.c_str()); - if (rc < 0) throw MapWriteException(name); - - std::ostringstream mapdata_out; - for (int y=0; y>& Map::getObjects() const +{ + return objects; +} + +std::shared_ptr Map::getLeftmap() const +{ + if (leftmap == -1) { - for (int x=0; x(); + } else { + return world->getMap(leftmap); } - - rc = xmlTextWriterWriteElement(writer, (xmlChar*) "environment", (xmlChar*) mapdata_out.str().c_str()); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterWriteElement(writer, (xmlChar*) "leftmap", (xmlChar*) leftmap.c_str()); - if (rc < 0) throw MapWriteException(name); +} - rc = xmlTextWriterWriteElement(writer, (xmlChar*) "rightmap", (xmlChar*) rightmap.c_str()); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterStartElement(writer, (xmlChar*) "entities"); - if (rc < 0) throw MapWriteException(name); - - for (auto object : objects) +std::shared_ptr Map::getRightmap() const +{ + if (rightmap == -1) { - rc = xmlTextWriterStartElement(writer, (xmlChar*) "entity"); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-type", (xmlChar*) object->object->getType().c_str()); - if (rc < 0) throw MapWriteException(name); - - std::ostringstream entpos_out; - entpos_out << object->position.first << "," << object->position.second; - - rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-position", (xmlChar*) entpos_out.str().c_str()); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterEndElement(writer); - if (rc < 0) throw MapWriteException(name); + return std::shared_ptr(); + } else { + return world->getMap(rightmap); } - - rc = xmlTextWriterEndElement(writer); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterEndElement(writer); - if (rc < 0) throw MapWriteException(name); - - rc = xmlTextWriterEndDocument(writer); - if (rc < 0) throw MapWriteException(name); - - xmlFreeTextWriter(writer); - - setDirty(false); } -bool Map::hasUnsavedChanges() const +wxTreeItemId Map::getTreeItemId() const { - return dirty; + return treeItemId; } -void Map::setTileAt(int x, int y, int tile) +std::list> Map::getChildren() const { - setDirty(true); - mapdata[x+y*MAP_WIDTH] = tile; + std::list> ret; + + for (auto id : children) + { + ret.push_back(world->getMap(id)); + } + + return ret; } -int Map::getTileAt(int x, int y) const +bool Map::getExpanded() const { - return mapdata[x+y*MAP_WIDTH]; + return expanded; } -std::string Map::getTitle() const +void Map::setTitle(std::string title, bool dirty) { - return title; + this->title = title; + + if (dirty) + { + world->setDirty(true); + } } -void Map::setTitle(std::string title) +void Map::setTileAt(int x, int y, int tile, bool dirty) { - setDirty(true); - this->title = title; + mapdata[x+y*MAP_WIDTH] = tile; + + if (dirty) + { + world->setDirty(true); + } } -const std::list>& Map::getObjects() const +void Map::setMapdata(int* mapdata, bool dirty) { - return objects; + free(this->mapdata); + this->mapdata = mapdata; + + if (dirty) + { + world->setDirty(true); + } } -void Map::addObject(std::shared_ptr& obj) +void Map::addObject(std::shared_ptr& obj, bool dirty) { - setDirty(true); objects.push_back(obj); + + if (dirty) + { + world->setDirty(true); + } } -void Map::removeObject(std::shared_ptr& obj) +void Map::removeObject(std::shared_ptr& obj, bool dirty) { - setDirty(true); objects.remove(obj); + + if (dirty) + { + world->setDirty(true); + } } -bool Map::getDirty() const +void Map::setLeftmap(int id, bool dirty) { - return dirty; + leftmap = id; + + if (dirty) + { + world->setDirty(true); + } } -void Map::setDirty(bool dirty) +void Map::setRightmap(int id, bool dirty) { - this->dirty = dirty; + rightmap = id; - if (frame != nullptr) + if (dirty) { - frame->MapDirtyDidChange(dirty); + world->setDirty(true); } } + +void Map::setTreeItemId(wxTreeItemId id) +{ + this->treeItemId = id; +} + +void Map::addChild(int id) +{ + children.push_back(id); +} + +void Map::setExpanded(bool exp) +{ + expanded = exp; +} diff --git a/tools/mapedit/src/map.h b/tools/mapedit/src/map.h index a2b9cb8..5753cae 100644 --- a/tools/mapedit/src/map.h +++ b/tools/mapedit/src/map.h @@ -1,12 +1,16 @@ #ifndef MAP_H #define MAP_H +class Map; + #include #include #include #include #include "object.h" #include +#include "world.h" +#include class MapeditFrame; @@ -57,36 +61,45 @@ struct MapObjectEntry { class Map { public: - Map(); - Map(std::string name); + Map(int id, World* world); Map(const Map& map); Map(Map&& map); ~Map(); Map& operator= (Map other); friend void swap(Map& first, Map& second); + int getID() const; std::string getTitle() const; - void setTitle(std::string title); - void save(std::string name); - bool hasUnsavedChanges() const; - void setTileAt(int x, int y, int tile); int getTileAt(int x, int y) const; const std::list>& getObjects() const; - void addObject(std::shared_ptr& obj); - void removeObject(std::shared_ptr& obj); - bool getDirty() const; + std::shared_ptr getLeftmap() const; + std::shared_ptr getRightmap() const; + wxTreeItemId getTreeItemId() const; + std::list> getChildren() const; + bool getExpanded() const; - MapeditFrame* frame; + 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 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); private: - void setDirty(bool dirty); - + int id; + World* world; std::list> objects; int* mapdata; - std::string title; - std::string leftmap; - std::string rightmap; - bool dirty; + std::string title {"Untitled Map"}; + std::list children; + int leftmap = -1; + int rightmap = -1; + wxTreeItemId treeItemId; + bool expanded = false; }; #endif diff --git a/tools/mapedit/src/widget.cpp b/tools/mapedit/src/widget.cpp index c1f044c..d50cf91 100644 --- a/tools/mapedit/src/widget.cpp +++ b/tools/mapedit/src/widget.cpp @@ -297,3 +297,10 @@ void MapeditWidget::CancelAddingEntity() { addingEntity = nullptr; } + +void MapeditWidget::SetMap(Map* map) +{ + this->map = map; + + Refresh(); +} diff --git a/tools/mapedit/src/widget.h b/tools/mapedit/src/widget.h index a660f82..34627bc 100644 --- a/tools/mapedit/src/widget.h +++ b/tools/mapedit/src/widget.h @@ -29,6 +29,7 @@ class MapeditWidget : public wxScrolledWindow { void SetEditMode(EditMode editMode); void StartAddingEntity(MapObject* object); void CancelAddingEntity(); + void SetMap(Map* map); MapeditFrame* frame; @@ -46,7 +47,7 @@ class MapeditWidget : public wxScrolledWindow { void SetTile(wxPoint pos); void SetZoomSize(int zoom); - Map* const map = nullptr; + Map* map = nullptr; wxBitmap tiles; TileWidget* tileWidget; bool mouseIsDown = false; diff --git a/tools/mapedit/src/world.cpp b/tools/mapedit/src/world.cpp new file mode 100644 index 0000000..4c42593 --- /dev/null +++ b/tools/mapedit/src/world.cpp @@ -0,0 +1,369 @@ +#include "world.h" +#include +#include +#include "frame.h" +#include + +World::World() +{ + newMap(); + + rootChildren.push_back(0); +} + +World::World(std::string filename) +{ + this->filename = filename; + + xmlDocPtr doc = xmlParseFile(filename.c_str()); + if (doc == nullptr) + { + throw MapLoadException(filename); + } + + xmlNodePtr top = xmlDocGetRootElement(doc); + if (top == nullptr) + { + throw MapLoadException(filename); + } + + if (xmlStrcmp(top->name, (const xmlChar*) "world")) + { + throw MapLoadException(filename); + } + + for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) + { + if (!xmlStrcmp(node->name, (const xmlChar*) "nextmapid")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (key != 0) + { + nextMapID = atoi((char*) key); + } + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "lastmap")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (key != 0) + { + lastmap = atoi((char*) key); + } + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "root")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (key != 0) + { + rootChildren.push_back(atoi((char*) key)); + } + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "map")) + { + xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); + if (idKey == 0) throw MapLoadException(filename); + int id = atoi((char*) idKey); + xmlFree(idKey); + + auto map = std::make_shared(id, this); + + for (xmlNodePtr mapNode = node->xmlChildrenNode; mapNode != NULL; mapNode = mapNode->next) + { + if (!xmlStrcmp(mapNode->name, (const xmlChar*) "name")) + { + xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); + if (key != 0) + { + map->setTitle((char*) key, false); + } + + xmlFree(key); + } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) + { + xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); + int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); + mapdata[0] = atoi(strtok((char*) key, ",\n")); + for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) + { + mapdata[i] = atoi(strtok(NULL, ",\n")); + } + map->setMapdata(mapdata, false); + xmlFree(key); + } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "leftmap")) + { + xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); + if (key != 0) + { + map->setLeftmap(atoi((char*) key), false); + } + xmlFree(key); + } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "rightmap")) + { + xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); + if (key != 0) + { + map->setRightmap(atoi((char*) key)); + } + xmlFree(key); + } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entities")) + { + for (xmlNodePtr entityNode = mapNode->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) + { + if (!xmlStrcmp(entityNode->name, (const xmlChar*) "entity")) + { + auto data = std::make_shared(); + + for (xmlNodePtr entityDataNode = entityNode->xmlChildrenNode; entityDataNode != NULL; entityDataNode = entityDataNode->next) + { + if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-type")) + { + xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); + data->object = MapObject::getAllObjects().at((char*) key).get(); + xmlFree(key); + } 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); + xmlFree(key); + } + } + + map->addObject(data, false); + } + } + } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "child")) + { + xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); + if (key != 0) + { + map->addChild(atoi((char*) key)); + } + xmlFree(key); + } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "expanded")) + { + xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); + if ((key != 0) && ((char) key[0] == '1')) + { + map->setExpanded(true); + } + } + } + + maps[map->getID()] = map; + } + } + + xmlFreeDoc(doc); +} + +std::shared_ptr World::newMap() +{ + auto nm = std::make_shared(nextMapID++, this); + maps[nm->getID()] = nm; + return nm; +} + +std::shared_ptr World::getMap(int id) const +{ + return maps.at(id); +} + +void World::setDirty(bool dirty) +{ + this->dirty = dirty; + parent->MapDirtyDidChange(dirty); +} + +bool World::getDirty() const +{ + return dirty; +} + +std::string World::getFilename() const +{ + return filename; +} + +void World::setParent(MapeditFrame* parent) +{ + this->parent = parent; +} + +Map* World::getLastMap() const +{ + return getMap(lastmap).get(); +} + +#define MY_ENCODING "ISO-8859-1" + +void World::save(std::string name, wxTreeCtrl* mapTree) +{ + int rc; + + xmlTextWriterPtr writer = xmlNewTextWriterFilename(name.c_str(), 0); + if (writer == NULL) throw MapWriteException(name); + + rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); + if (rc < 0) throw MapWriteException(name); + + // + rc = xmlTextWriterStartElement(writer, (xmlChar*) "world"); + if (rc < 0) throw MapWriteException(name); + + // + std::ostringstream nextMap_out; + nextMap_out << nextMapID; + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "nextmapid", (xmlChar*) nextMap_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + std::ostringstream lastMap_out; + lastMap_out << lastmap; + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "lastmap", (xmlChar*) lastMap_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + + // ASSUMPTION: There will always be at least one child of the invisible root element. i.e. you cannot delete to zero maps. + wxTreeItemId root = mapTree->GetRootItem(); + wxTreeItemIdValue cookie1; + for (wxTreeItemId it = mapTree->GetFirstChild(root, cookie1); it.IsOk(); it = mapTree->GetNextChild(root, cookie1)) + { + // + MapPtrCtr* ctl = (MapPtrCtr*) mapTree->GetItemData(it); + std::ostringstream rootid_out; + rootid_out << ctl->map->getID(); + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "root", (xmlChar*) rootid_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + } + + for (auto mapPair : maps) + { + Map& map = *mapPair.second; + + // + rc = xmlTextWriterStartElement(writer, (xmlChar*) "map"); + if (rc < 0) throw MapWriteException(name); + + // id= + std::ostringstream id_out; + id_out << map.getID(); + rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "id", (xmlChar*) id_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "name", (xmlChar*) map.getTitle().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + std::ostringstream mapdata_out; + for (int y=0; y + std::ostringstream leftmap_out; + if (map.getLeftmap()) + { + leftmap_out << map.getLeftmap()->getID(); + } + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "leftmap", (xmlChar*) leftmap_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + std::ostringstream rightmap_out; + if (map.getRightmap()) + { + rightmap_out << map.getRightmap()->getID(); + } + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "rightmap", (xmlChar*) rightmap_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + rc = xmlTextWriterStartElement(writer, (xmlChar*) "entities"); + if (rc < 0) throw MapWriteException(name); + + for (auto object : map.getObjects()) + { + // + rc = xmlTextWriterStartElement(writer, (xmlChar*) "entity"); + if (rc < 0) throw MapWriteException(name); + + // + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-type", (xmlChar*) object->object->getType().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + std::ostringstream entpos_out; + entpos_out << object->position.first << "," << object->position.second; + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-position", (xmlChar*) entpos_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + + // + rc = xmlTextWriterEndElement(writer); + if (rc < 0) throw MapWriteException(name); + } + + // + rc = xmlTextWriterEndElement(writer); + if (rc < 0) throw MapWriteException(name); + + wxTreeItemId node = map.getTreeItemId(); + if (mapTree->ItemHasChildren(node)) + { + wxTreeItemIdValue cookie2; + for (wxTreeItemId it = mapTree->GetFirstChild(node, cookie2); it.IsOk(); it = mapTree->GetNextChild(node, cookie2)) + { + // + MapPtrCtr* ctl = (MapPtrCtr*) mapTree->GetItemData(it); + std::ostringstream childid_out; + childid_out << ctl->map->getID(); + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "child", (xmlChar*) childid_out.str().c_str()); + if (rc < 0) throw MapWriteException(name); + } + + if (mapTree->IsExpanded(node)) + { + // + rc = xmlTextWriterWriteElement(writer, (xmlChar*) "expanded", (xmlChar*) "1"); + if (rc < 0) throw MapWriteException(name); + } + } + + // + rc = xmlTextWriterEndElement(writer); + if (rc < 0) throw MapWriteException(name); + } + + // + rc = xmlTextWriterEndDocument(writer); + if (rc < 0) throw MapWriteException(name); + + xmlFreeTextWriter(writer); + + setDirty(false); +} + +std::list> World::getRootMaps() const +{ + std::list> ret; + + for (auto id : rootChildren) + { + ret.push_back(getMap(id)); + } + + return ret; +} + +const std::map> World::getMaps() const +{ + return maps; +} diff --git a/tools/mapedit/src/world.h b/tools/mapedit/src/world.h new file mode 100644 index 0000000..7d796cc --- /dev/null +++ b/tools/mapedit/src/world.h @@ -0,0 +1,45 @@ +#ifndef WORLD_H +#define WORLD_H + +class World; + +#include + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include +#include +#include "map.h" +#include + +class MapeditFrame; + +class World { + public: + World(); + World(std::string filename); + std::shared_ptr newMap(); + std::shared_ptr getMap(int id) const; + void setDirty(bool dirty); + bool getDirty() const; + std::string getFilename() const; + void setParent(MapeditFrame* parent); + void save(std::string filename, wxTreeCtrl* mapTree); + Map* getLastMap() const; + std::list> getRootMaps() const; + const std::map> getMaps() const; + + private: + MapeditFrame* parent; + std::map> maps; + int nextMapID = 0; + bool dirty = false; + std::string filename; + int lastmap = 0; + std::list rootChildren; +}; + +#endif -- cgit 1.4.1