diff --git a/data/menubar.xml b/data/menubar.xml index c9f852e6..63c4d397 100644 --- a/data/menubar.xml +++ b/data/menubar.xml @@ -16,6 +16,7 @@ + diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 752de380..aba6bbbe 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -101,6 +101,8 @@ target_sources(${PROJECT_NAME} about_window.cpp action.cpp actions_history_window.cpp + add_item_window.cpp + add_tileset_window.cpp application.cpp artprovider.cpp basemap.cpp @@ -194,6 +196,7 @@ target_sources(${PROJECT_NAME} templatemapclassic.cpp tile.cpp tileset.cpp + tileset_window.cpp town.cpp updater.cpp wall_brush.cpp diff --git a/source/add_item_window.cpp b/source/add_item_window.cpp new file mode 100644 index 00000000..d5d3d9f2 --- /dev/null +++ b/source/add_item_window.cpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////// +// This file is part of Remere's Map Editor +////////////////////////////////////////////////////////////////////// +// Remere's Map Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Remere's Map Editor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +////////////////////////////////////////////////////////////////////// + +#include "main.h" + +#include + +#include "tile.h" +#include "item.h" +#include "complexitem.h" +#include "town.h" +#include "house.h" +#include "map.h" +#include "editor.h" +#include "materials.h" +#include "tileset.h" + +#include "gui.h" +#include "application.h" +#include "add_item_window.h" +#include "container_properties_window.h" +#include "find_item_window.h" + +// ============================================================================ +// Add Item Window + +BEGIN_EVENT_TABLE(AddItemWindow, wxDialog) +EVT_BUTTON(wxID_OK, AddItemWindow::OnClickOK) +EVT_BUTTON(wxID_CANCEL, AddItemWindow::OnClickCancel) +END_EVENT_TABLE() + +AddItemWindow::AddItemWindow(wxWindow* win_parent, TilesetCategoryType categoryType, Tileset* tilesetItem, wxPoint pos) : + ObjectPropertiesWindowBase(win_parent, "Add a Item", pos), + item_id(0), + tileset_item(tilesetItem), + category_type(categoryType), + item_id_field(nullptr), + item_id_label(nullptr), + item_name_label(nullptr), + item_button(nullptr) { + wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL); + wxString description = "Add a Item"; + + wxSizer* boxsizer = newd wxStaticBoxSizer(wxVERTICAL, this, description); + + wxFlexGridSizer* subsizer = newd wxFlexGridSizer(2, 10, 10); + subsizer->AddGrowableCol(1); + + uint16_t itemId = 0; + std::string itemName = "None"; + item_id_label = newd wxStaticText(this, wxID_ANY, "ID " + i2ws(itemId)); + subsizer->Add(item_id_label); + item_name_label = newd wxStaticText(this, wxID_ANY, "\"" + wxstr(itemName) + "\""); + subsizer->Add(item_name_label); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Item"), wxSizerFlags(1).CenterVertical()); + item_button = newd DCButton(this, wxID_ANY, wxDefaultPosition, DC_BTN_TOGGLE, RENDER_SIZE_32x32, 0); + subsizer->Add(item_button); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Item Id")); + item_id_field = newd wxSpinCtrl(this, wxID_ANY, i2ws(itemId), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 100, 100000); + item_id_field->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler(AddItemWindow::OnChangeItemId), NULL, this); + subsizer->Add(item_id_field, wxSizerFlags(1).Expand()); + + boxsizer->Add(subsizer, wxSizerFlags(1).Expand()); + + topsizer->Add(boxsizer, wxSizerFlags(0).Expand().Border(wxLEFT | wxRIGHT, 20)); + + wxSizer* subsizer_ = newd wxBoxSizer(wxHORIZONTAL); + subsizer_->Add(newd wxButton(this, wxID_OK, "Add"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); + subsizer_->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); + topsizer->Add(subsizer_, wxSizerFlags(0).Center().Border(wxLEFT | wxRIGHT, 20)); + + SetSizerAndFit(topsizer); + Centre(wxBOTH); + + item_button->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(AddItemWindow::OnItemClicked), NULL, this); +} + +void AddItemWindow::OnClickOK(wxCommandEvent &WXUNUSED(event)) { + const ItemType &it = g_items.getItemType(item_id_field->GetValue()); + if (it.id != 0) { + g_materials.addToTileset(tileset_item->name, it.id, category_type); + g_materials.modify(); + g_gui.PopupDialog("Item added to Tileset", "'" + it.name + "' has been added to tileset '" + tileset_item->name + "'", wxOK); + + EndModal(1); + } else { + g_gui.PopupDialog("Something went wrong", "You need to select any item", wxOK); + } +} + +void AddItemWindow::OnClickCancel(wxCommandEvent &WXUNUSED(event)) { + // Just close this window + EndModal(0); +} + +void AddItemWindow::OnChangeItemId(wxCommandEvent &WXUNUSED(event)) { + uint16_t itemId = item_id_field->GetValue(); + ItemType &it = g_items[itemId]; + if (it.id != 0) { + item_id_label->SetLabelText("ID " + i2ws(it.id)); + item_name_label->SetLabelText("\"" + wxstr(it.name) + "\""); + + item_button->SetSprite(it.clientID); + } else { + item_id_field->SetValue(100); + } +} + +void AddItemWindow::OnItemClicked(wxMouseEvent &WXUNUSED(event)) { + FindItemDialog dialog(this, "Item"); + if (dialog.ShowModal() == wxID_OK) { + uint16_t id = dialog.getResultID(); + SetItemIdToItemButton(id); + } + dialog.Destroy(); +} + +void AddItemWindow::SetItemIdToItemButton(uint16_t id) { + if (!item_button) { + return; + } + + if (id != 0) { + const ItemType &it = g_items.getItemType(id); + if (it.id != 0) { + item_id_field->SetValue(it.id); + item_id_label->SetLabelText("ID " + i2ws(it.id)); + item_name_label->SetLabelText("\"" + wxstr(it.name) + "\""); + + item_button->SetSprite(it.clientID); + return; + } + } + + item_button->SetSprite(0); +} diff --git a/source/add_item_window.h b/source/add_item_window.h new file mode 100644 index 00000000..1b2b7e99 --- /dev/null +++ b/source/add_item_window.h @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////// +// This file is part of Remere's Map Editor +////////////////////////////////////////////////////////////////////// +// Remere's Map Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Remere's Map Editor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +////////////////////////////////////////////////////////////////////// + +#ifndef RME_ADD_ITEM_WINDOW_H_ +#define RME_ADD_ITEM_WINDOW_H_ + +#include "main.h" + +#include "common_windows.h" + +class ContainerItemButton; +class ContainerItemPopupMenu; + +class AddItemWindow : public ObjectPropertiesWindowBase { +public: + AddItemWindow(wxWindow* parent, TilesetCategoryType categoryType, Tileset* tilesetItem, wxPoint = wxDefaultPosition); + + void OnItemClicked(wxMouseEvent &event); + void SetItemIdToItemButton(uint16_t id); + void OnChangeItemId(wxCommandEvent &WXUNUSED(event)); + + void OnClickOK(wxCommandEvent &); + void OnClickCancel(wxCommandEvent &); + +protected: + int item_id; + + wxSpinCtrl* item_id_field; + wxStaticText* item_id_label; + wxStaticText* item_name_label; + DCButton* item_button; + + TilesetCategoryType category_type; + Tileset* tileset_item; + + DECLARE_EVENT_TABLE(); +}; + +#endif diff --git a/source/add_tileset_window.cpp b/source/add_tileset_window.cpp new file mode 100644 index 00000000..0d2f2f48 --- /dev/null +++ b/source/add_tileset_window.cpp @@ -0,0 +1,157 @@ +////////////////////////////////////////////////////////////////////// +// This file is part of Remere's Map Editor +////////////////////////////////////////////////////////////////////// +// Remere's Map Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Remere's Map Editor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +////////////////////////////////////////////////////////////////////// + +#include "main.h" + +#include + +#include "tile.h" +#include "item.h" +#include "complexitem.h" +#include "town.h" +#include "house.h" +#include "map.h" +#include "editor.h" +#include "materials.h" +#include "tileset.h" + +#include "gui.h" +#include "application.h" +#include "add_tileset_window.h" +#include "container_properties_window.h" +#include "find_item_window.h" + +// ============================================================================ +// Add Tileset Window + +BEGIN_EVENT_TABLE(AddTilesetWindow, wxDialog) +EVT_BUTTON(wxID_OK, AddTilesetWindow::OnClickOK) +EVT_BUTTON(wxID_CANCEL, AddTilesetWindow::OnClickCancel) +END_EVENT_TABLE() + +AddTilesetWindow::AddTilesetWindow(wxWindow* win_parent, TilesetCategoryType categoryType, wxPoint pos) : + ObjectPropertiesWindowBase(win_parent, "Add a Tileset", pos), + category_type(categoryType), + item_id_label(nullptr), + item_name_label(nullptr), + tileset_name_field(nullptr), + item_id_field(nullptr), + item_button(nullptr) { + wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL); + wxString description = "Add a Tileset"; + + wxSizer* boxsizer = newd wxStaticBoxSizer(wxVERTICAL, this, description); + + wxFlexGridSizer* subsizer = newd wxFlexGridSizer(2, 10, 10); + subsizer->AddGrowableCol(1); + + uint16_t itemId = 0; + std::string itemName = "None"; + item_id_label = newd wxStaticText(this, wxID_ANY, "ID " + i2ws(itemId)); + subsizer->Add(item_id_label); + item_name_label = newd wxStaticText(this, wxID_ANY, "\"" + wxstr(itemName) + "\""); + subsizer->Add(item_name_label); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Item"), wxSizerFlags(1).CenterVertical()); + item_button = newd DCButton(this, wxID_ANY, wxDefaultPosition, DC_BTN_TOGGLE, RENDER_SIZE_32x32, 0); + subsizer->Add(item_button); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Item Id of First Item")); + item_id_field = newd wxSpinCtrl(this, wxID_ANY, i2ws(itemId), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 100, 100000); + subsizer->Add(item_id_field, wxSizerFlags(1).Expand()); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Tileset Name")); + tileset_name_field = newd wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + subsizer->Add(tileset_name_field); + + boxsizer->Add(subsizer, wxSizerFlags(1).Expand()); + + topsizer->Add(boxsizer, wxSizerFlags(0).Expand().Border(wxLEFT | wxRIGHT, 20)); + + wxSizer* subsizer_ = newd wxBoxSizer(wxHORIZONTAL); + subsizer_->Add(newd wxButton(this, wxID_OK, "Add"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); + subsizer_->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); + topsizer->Add(subsizer_, wxSizerFlags(0).Center().Border(wxLEFT | wxRIGHT, 20)); + + SetSizerAndFit(topsizer); + Centre(wxBOTH); + + item_id_field->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler(AddTilesetWindow::OnChangeItemId), NULL, this); + item_button->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(AddTilesetWindow::OnItemClicked), NULL, this); +} + +void AddTilesetWindow::OnChangeItemId(wxCommandEvent &WXUNUSED(event)) { + uint16_t itemId = item_id_field->GetValue(); + ItemType &it = g_items[itemId]; + if (it.id != 0) { + item_id_label->SetLabelText("ID " + i2ws(it.id)); + item_name_label->SetLabelText("\"" + wxstr(it.name) + "\""); + + item_button->SetSprite(it.clientID); + } else { + item_id_field->SetValue(100); + } +} + +void AddTilesetWindow::OnItemClicked(wxMouseEvent &WXUNUSED(event)) { + FindItemDialog dialog(this, "Item"); + if (dialog.ShowModal() == wxID_OK) { + uint16_t id = dialog.getResultID(); + SetItemIdToItemButton(id); + } + dialog.Destroy(); +} + +void AddTilesetWindow::SetItemIdToItemButton(uint16_t id) { + if (!item_button) { + return; + } + + if (id != 0) { + const ItemType &it = g_items.getItemType(id); + if (it.id != 0) { + item_id_field->SetValue(it.id); + item_id_label->SetLabelText("ID " + i2ws(it.id)); + item_name_label->SetLabelText("\"" + wxstr(it.name) + "\""); + + item_button->SetSprite(it.clientID); + return; + } + } + + item_button->SetSprite(0); +} + +void AddTilesetWindow::OnClickOK(wxCommandEvent &WXUNUSED(event)) { + uint16_t itemId = item_id_field->GetValue(); + ItemType &it = g_items[itemId]; + if (it.id != 0) { + std::string tilesetName = std::string(tileset_name_field->GetValue().mb_str()); + g_materials.addToTileset(tilesetName, it.id, category_type); + g_materials.modify(); + g_gui.PopupDialog("Added Tileset", "'" + it.name + "' has been added to new tileset '" + tilesetName + "'", wxOK); + + EndModal(1); + } else { + g_gui.PopupDialog(this, "Error", "Item does not exist.", wxOK); + } +} + +void AddTilesetWindow::OnClickCancel(wxCommandEvent &WXUNUSED(event)) { + // Just close this window + EndModal(0); +} diff --git a/source/add_tileset_window.h b/source/add_tileset_window.h new file mode 100644 index 00000000..bd5c3281 --- /dev/null +++ b/source/add_tileset_window.h @@ -0,0 +1,52 @@ +////////////////////////////////////////////////////////////////////// +// This file is part of Remere's Map Editor +////////////////////////////////////////////////////////////////////// +// Remere's Map Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Remere's Map Editor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +////////////////////////////////////////////////////////////////////// + +#ifndef RME_ADD_TILESET_WINDOW_H_ +#define RME_ADD_TILESET_WINDOW_H_ + +#include "main.h" + +#include "common_windows.h" + +class ContainerItemButton; +class ContainerItemPopupMenu; + +class AddTilesetWindow : public ObjectPropertiesWindowBase { +public: + AddTilesetWindow(wxWindow* parent, TilesetCategoryType categoryType, wxPoint = wxDefaultPosition); + + void OnItemClicked(wxMouseEvent &event); + void SetItemIdToItemButton(uint16_t id); + void OnChangeItemId(wxCommandEvent &WXUNUSED(event)); + + void OnClickOK(wxCommandEvent &); + void OnClickCancel(wxCommandEvent &); + +private: + wxTextCtrl* tileset_name_field; + wxSpinCtrl* item_id_field; + + wxStaticText* item_id_label; + wxStaticText* item_name_label; + + TilesetCategoryType category_type; + DCButton* item_button; + + DECLARE_EVENT_TABLE(); +}; + +#endif diff --git a/source/application.cpp b/source/application.cpp index 86f129b3..ff116564 100644 --- a/source/application.cpp +++ b/source/application.cpp @@ -485,11 +485,45 @@ bool MainFrame::DoQueryClose() { return true; } +bool MainFrame::DoQuerySaveTileset(bool doclose) { + if (!g_materials.needSave()) { + // skip dialog when there is nothing to save + return true; + } + + long ret = g_gui.PopupDialog( + "Export tileset", + "Do you want to export your tileset changes before exiting?", + wxYES | wxNO | wxCANCEL + ); + + if (ret == wxID_NO) { + // "no" - exit without saving + return true; + } else if (ret == wxID_CANCEL) { + // "cancel" - just close the dialog + return false; + } + + // "yes" button was pressed, open tileset exporting dialog + if (g_gui.GetCurrentEditor()) { + ExportTilesetsWindow dlg(this, *g_gui.GetCurrentEditor()); + dlg.ShowModal(); + dlg.Destroy(); + } + + return !g_materials.needSave(); +} + bool MainFrame::DoQuerySave(bool doclose) { if (!g_gui.IsEditorOpen()) { return true; } + if (!DoQuerySaveTileset()) { + return false; + } + Editor &editor = *g_gui.GetCurrentEditor(); if (editor.IsLiveClient()) { long ret = g_gui.PopupDialog( @@ -617,6 +651,9 @@ bool MainFrame::LoadMap(FileName name) { } void MainFrame::OnExit(wxCloseEvent &event) { + // clicking 'x' button + + // do you want to save map changes? while (g_gui.IsEditorOpen()) { if (!DoQuerySave()) { if (event.CanVeto()) { diff --git a/source/application.h b/source/application.h index 80910183..1362a9af 100644 --- a/source/application.h +++ b/source/application.h @@ -69,6 +69,7 @@ class MainFrame : public wxFrame { void UpdateMenubar(); bool DoQueryClose(); bool DoQuerySave(bool doclose = true); + bool DoQuerySaveTileset(bool doclose = true); bool DoQueryImportCreatures(); bool LoadMap(FileName name); diff --git a/source/common_windows.cpp b/source/common_windows.cpp index f49d4b30..9bcc39d4 100644 --- a/source/common_windows.cpp +++ b/source/common_windows.cpp @@ -680,6 +680,194 @@ void ExportMiniMapWindow::CheckValues() { ok_button->Enable(true); } +// ============================================================================ +// Export Tilesets window + +BEGIN_EVENT_TABLE(ExportTilesetsWindow, wxDialog) +EVT_BUTTON(TILESET_FILE_BUTTON, ExportTilesetsWindow::OnClickBrowse) +EVT_BUTTON(wxID_OK, ExportTilesetsWindow::OnClickOK) +EVT_BUTTON(wxID_CANCEL, ExportTilesetsWindow::OnClickCancel) +END_EVENT_TABLE() + +ExportTilesetsWindow::ExportTilesetsWindow(wxWindow* parent, Editor &editor) : + wxDialog(parent, wxID_ANY, "Export Tilesets", wxDefaultPosition, wxSize(400, 230)), + editor(editor) { + wxSizer* sizer = newd wxBoxSizer(wxVERTICAL); + wxSizer* tmpsizer; + + // Error field + error_field = newd wxStaticText(this, wxID_VIEW_DETAILS, "", wxDefaultPosition, wxDefaultSize); + error_field->SetForegroundColour(*wxRED); + tmpsizer = newd wxBoxSizer(wxHORIZONTAL); + tmpsizer->Add(error_field, 0, wxALL, 5); + sizer->Add(tmpsizer, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); + + // Output folder + directory_text_field = newd wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize); + directory_text_field->Bind(wxEVT_KEY_UP, &ExportTilesetsWindow::OnDirectoryChanged, this); + directory_text_field->SetValue(wxString(g_settings.getString(Config::TILESET_EXPORT_DIR))); + tmpsizer = newd wxStaticBoxSizer(wxHORIZONTAL, this, "Output Folder"); + tmpsizer->Add(directory_text_field, 1, wxALL, 5); + tmpsizer->Add(newd wxButton(this, TILESET_FILE_BUTTON, "Browse"), 0, wxALL, 5); + sizer->Add(tmpsizer, 0, wxALL | wxEXPAND, 5); + + // File name + file_name_text_field = newd wxTextCtrl(this, wxID_ANY, "tilesets", wxDefaultPosition, wxDefaultSize); + file_name_text_field->Bind(wxEVT_KEY_UP, &ExportTilesetsWindow::OnFileNameChanged, this); + tmpsizer = newd wxStaticBoxSizer(wxHORIZONTAL, this, "File Name"); + tmpsizer->Add(file_name_text_field, 1, wxALL, 5); + sizer->Add(tmpsizer, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); + + // OK/Cancel buttons + tmpsizer = newd wxBoxSizer(wxHORIZONTAL); + tmpsizer->Add(ok_button = newd wxButton(this, wxID_OK, "OK"), wxSizerFlags(1).Center()); + tmpsizer->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center()); + sizer->Add(tmpsizer, 0, wxCENTER, 10); + + SetSizer(sizer); + Layout(); + Centre(wxBOTH); + CheckValues(); +} + +ExportTilesetsWindow::~ExportTilesetsWindow() = default; + +void ExportTilesetsWindow::OnClickBrowse(wxCommandEvent &WXUNUSED(event)) { + wxDirDialog dialog(NULL, "Select the output folder", "", wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); + if (dialog.ShowModal() == wxID_OK) { + const wxString &directory = dialog.GetPath(); + directory_text_field->ChangeValue(directory); + } + CheckValues(); +} + +void ExportTilesetsWindow::OnDirectoryChanged(wxKeyEvent &event) { + CheckValues(); + event.Skip(); +} + +void ExportTilesetsWindow::OnFileNameChanged(wxKeyEvent &event) { + CheckValues(); + event.Skip(); +} + +void ExportTilesetsWindow::OnClickOK(wxCommandEvent &WXUNUSED(event)) { + g_gui.CreateLoadBar("Exporting Tilesets"); + + try { + FileName directory(directory_text_field->GetValue()); + g_settings.setString(Config::TILESET_EXPORT_DIR, directory_text_field->GetValue().ToStdString()); + + FileName file(file_name_text_field->GetValue() + ".xml"); + file.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_CASE | wxPATH_NORM_ABSOLUTE, directory.GetFullPath()); + + pugi::xml_document doc; + pugi::xml_node node = doc.append_child("materials"); + + std::map palettes { + { "Terrain", TILESET_TERRAIN }, + { "Doodad", TILESET_DOODAD }, + { "Items", TILESET_ITEM }, + { "Raw", TILESET_RAW } + }; + for (TilesetContainer::iterator iter = g_materials.tilesets.begin(); iter != g_materials.tilesets.end(); ++iter) { + std::string _data = iter->second->name; + std::transform(_data.begin(), _data.end(), _data.begin(), [](unsigned char c) { return std::tolower(c); }); + if (_data == "others") { + bool blocked = 1; + + for (const auto &kv : palettes) { + TilesetCategory* tilesetCategory = iter->second->getCategory(kv.second); + + if (kv.second != TILESET_RAW && tilesetCategory->brushlist.size() > 0) { + blocked = 0; + } + } + + if (blocked) { + continue; + } + } + + pugi::xml_node tileset = node.append_child("tileset"); + tileset.append_attribute("name") = iter->second->name.c_str(); + + for (const auto &kv : palettes) { + TilesetCategory* tilesetCategory = iter->second->getCategory(kv.second); + + if (tilesetCategory->brushlist.size() > 0) { + std::string data = kv.first; + std::transform(data.begin(), data.end(), data.begin(), [](unsigned char c) { return std::tolower(c); }); + + pugi::xml_node palette = tileset.append_child(data.c_str()); + for (BrushVector::const_iterator _iter = tilesetCategory->brushlist.begin(); _iter != tilesetCategory->brushlist.end(); ++_iter) { + if (!(*_iter)->isRaw()) { + pugi::xml_node brush = palette.append_child("brush"); + brush.append_attribute("name") = (*_iter)->getName().c_str(); + } else { + ItemType &it = g_items[(*_iter)->asRaw()->getItemID()]; + if (it.id != 0) { + pugi::xml_node item = palette.append_child("item"); + item.append_attribute("id") = it.id; + } + } + } + } + } + + size_t n = std::distance(tileset.begin(), tileset.end()); + if (n <= 0) { + node.remove_child(tileset); + } + } + + doc.save_file(file.GetFullPath().mb_str()); + g_gui.PopupDialog("Successfully saved Tilesets", "Saved tilesets to '" + std::string(file.GetFullPath().mb_str()) + "'", wxOK); + g_materials.modify(false); + } catch (std::bad_alloc &) { + g_gui.PopupDialog("Error", "There is not enough memory available to complete the operation.", wxOK); + } + + g_gui.DestroyLoadBar(); + EndModal(1); +} + +void ExportTilesetsWindow::OnClickCancel(wxCommandEvent &WXUNUSED(event)) { + // Just close this window + EndModal(0); +} + +void ExportTilesetsWindow::CheckValues() { + if (directory_text_field->IsEmpty()) { + error_field->SetLabel("Type or select an output folder."); + ok_button->Enable(false); + return; + } + + if (file_name_text_field->IsEmpty()) { + error_field->SetLabel("Type a name for the file."); + ok_button->Enable(false); + return; + } + + FileName directory(directory_text_field->GetValue()); + + if (!directory.Exists()) { + error_field->SetLabel("Output folder not found."); + ok_button->Enable(false); + return; + } + + if (!directory.IsDirWritable()) { + error_field->SetLabel("Output folder is not writable."); + ok_button->Enable(false); + return; + } + + error_field->SetLabel(wxEmptyString); + ok_button->Enable(true); +} + // ============================================================================ // Numkey forwarding text control @@ -1168,6 +1356,11 @@ ObjectPropertiesWindowBase::ObjectPropertiesWindowBase(wxWindow* parent, wxStrin //// } +ObjectPropertiesWindowBase::ObjectPropertiesWindowBase(wxWindow* parent, wxString title, wxPoint position /* = wxDefaultPosition */) : + wxDialog(parent, wxID_ANY, title, position, wxSize(600, 400), wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER) { + //// +} + Item* ObjectPropertiesWindowBase::getItemBeingEdited() { return edit_item; } diff --git a/source/common_windows.h b/source/common_windows.h index 8923ab2d..aec203ba 100644 --- a/source/common_windows.h +++ b/source/common_windows.h @@ -137,6 +137,33 @@ class ExportMiniMapWindow : public wxDialog { DECLARE_EVENT_TABLE(); }; +/** + * The export tilesets dialog, select output path. + */ +class ExportTilesetsWindow : public wxDialog { +public: + ExportTilesetsWindow(wxWindow* parent, Editor &editor); + virtual ~ExportTilesetsWindow(); + + void OnClickBrowse(wxCommandEvent &); + void OnDirectoryChanged(wxKeyEvent &); + void OnFileNameChanged(wxKeyEvent &); + void OnClickOK(wxCommandEvent &); + void OnClickCancel(wxCommandEvent &); + +protected: + void CheckValues(); + + Editor &editor; + + wxStaticText* error_field; + wxTextCtrl* directory_text_field; + wxTextCtrl* file_name_text_field; + wxButton* ok_button; + + DECLARE_EVENT_TABLE(); +}; + /** * Text control that will forward up/down pgup / pgdown keys to parent window */ @@ -292,6 +319,9 @@ class ObjectPropertiesWindowBase : public wxDialog { const Map* map, const Tile* tile, Monster* monster, wxPoint position = wxDefaultPosition ); + ObjectPropertiesWindowBase( + wxWindow* parent, wxString title, wxPoint position = wxDefaultPosition + ); Item* getItemBeingEdited(); Monster* getMonsterBeingEdited(); diff --git a/source/editor.h b/source/editor.h index b1fe90c7..ce139b78 100644 --- a/source/editor.h +++ b/source/editor.h @@ -160,6 +160,7 @@ class Editor { Editor &operator=(const Editor &); private: + friend class MapCanvas; Map map; Selection selection; ActionQueue* actionQueue; diff --git a/source/gui.h b/source/gui.h index 9ed11227..5228d4d2 100644 --- a/source/gui.h +++ b/source/gui.h @@ -56,6 +56,7 @@ class MinimapWindow; class ActionsHistoryWindow; class PaletteWindow; class OldPropertiesWindow; +class TilesetWindow; class EditTownsDialog; class ItemButton; @@ -398,9 +399,9 @@ class GUI { // Returns list of all palette, first in the list is primary const std::list &GetPalettes(); + void DestroyPalettes(); // Hidden from public view protected: - void DestroyPalettes(); PaletteWindow* CreatePalette(); //========================================================================= diff --git a/source/gui_ids.h b/source/gui_ids.h index c413540a..ed7eed70 100644 --- a/source/gui_ids.h +++ b/source/gui_ids.h @@ -72,6 +72,7 @@ enum EditorActionID { MAP_POPUP_MENU_SELECT_CARPET_BRUSH, MAP_POPUP_MENU_SELECT_HOUSE_BRUSH, MAP_POPUP_MENU_PROPERTIES, + MAP_POPUP_MENU_MOVE_TO_TILESET, CONTAINER_POPUP_MENU_ADD, CONTAINER_POPUP_MENU_EDIT, @@ -95,6 +96,7 @@ enum EditorActionID { EXTENSIONS_OPEN_FOLDER_BUTTON, MAP_WINDOW_FILE_BUTTON, + TILESET_FILE_BUTTON, PALETTE_ITEM_CHOICEBOOK, PALETTE_CHOICEBOOK, diff --git a/source/items.cpp b/source/items.cpp index 9e9049f6..aad2aa20 100644 --- a/source/items.cpp +++ b/source/items.cpp @@ -126,6 +126,10 @@ ItemDatabase::~ItemDatabase() { clear(); } +ItemType &ItemDatabase::operator[](uint16_t id) { + return getItemType(id); +} + void ItemDatabase::clear() { for (size_t i = 0; i < items.size(); i++) { delete items[i]; diff --git a/source/items.h b/source/items.h index e1417dc0..31a7768b 100644 --- a/source/items.h +++ b/source/items.h @@ -393,6 +393,8 @@ class ItemDatabase { ItemDatabase(); ~ItemDatabase(); + ItemType &operator[](uint16_t id); + void clear(); uint16_t getMinID() const noexcept { diff --git a/source/main_menubar.cpp b/source/main_menubar.cpp index 090cc16f..92c90c61 100644 --- a/source/main_menubar.cpp +++ b/source/main_menubar.cpp @@ -63,6 +63,7 @@ MainMenuBar::MainMenuBar(MainFrame* frame) : MAKE_ACTION(IMPORT_NPCS, wxITEM_NORMAL, OnImportNpcData); MAKE_ACTION(IMPORT_MINIMAP, wxITEM_NORMAL, OnImportMinimap); MAKE_ACTION(EXPORT_MINIMAP, wxITEM_NORMAL, OnExportMinimap); + MAKE_ACTION(EXPORT_TILESETS, wxITEM_NORMAL, OnExportTilesets); MAKE_ACTION(RELOAD_DATA, wxITEM_NORMAL, OnReloadDataFiles); // MAKE_ACTION(RECENT_FILES, wxITEM_NORMAL, OnRecent); @@ -342,6 +343,7 @@ void MainMenuBar::Update() { EnableItem(IMPORT_MONSTERS, is_local); EnableItem(IMPORT_MINIMAP, false); EnableItem(EXPORT_MINIMAP, is_local); + EnableItem(EXPORT_TILESETS, loaded); EnableItem(FIND_ITEM, is_host); EnableItem(REPLACE_ITEMS, is_local); @@ -850,6 +852,14 @@ void MainMenuBar::OnExportMinimap(wxCommandEvent &WXUNUSED(event)) { dialog.ShowModal(); } +void MainMenuBar::OnExportTilesets(wxCommandEvent &WXUNUSED(event)) { + if (g_gui.GetCurrentEditor()) { + ExportTilesetsWindow dlg(frame, *g_gui.GetCurrentEditor()); + dlg.ShowModal(); + dlg.Destroy(); + } +} + void MainMenuBar::OnDebugViewDat(wxCommandEvent &WXUNUSED(event)) { wxDialog dlg(frame, wxID_ANY, "Debug .dat file", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); new DatDebugView(&dlg); diff --git a/source/main_menubar.h b/source/main_menubar.h index 083525ad..b5042bd7 100644 --- a/source/main_menubar.h +++ b/source/main_menubar.h @@ -35,6 +35,7 @@ namespace MenuBar { IMPORT_NPCS, IMPORT_MINIMAP, EXPORT_MINIMAP, + EXPORT_TILESETS, RELOAD_DATA, RECENT_FILES, PREFERENCES, @@ -210,6 +211,7 @@ class MainMenuBar : public wxEvtHandler { void OnImportNpcData(wxCommandEvent &event); void OnImportMinimap(wxCommandEvent &event); void OnExportMinimap(wxCommandEvent &event); + void OnExportTilesets(wxCommandEvent &event); void OnReloadDataFiles(wxCommandEvent &event); // Edit Menu diff --git a/source/map_display.cpp b/source/map_display.cpp index 06168797..3ff31f9f 100644 --- a/source/map_display.cpp +++ b/source/map_display.cpp @@ -25,6 +25,7 @@ #include "tile.h" #include "old_properties_window.h" #include "properties_window.h" +#include "tileset_window.h" #include "palette_window.h" #include "map_display.h" #include "map_drawer.h" @@ -95,6 +96,7 @@ EVT_MENU(MAP_POPUP_MENU_SELECT_SPAWN_BRUSH, MapCanvas::OnSelectSpawnBrush) EVT_MENU(MAP_POPUP_MENU_SELECT_NPC_BRUSH, MapCanvas::OnSelectNpcBrush) EVT_MENU(MAP_POPUP_MENU_SELECT_SPAWN_NPC_BRUSH, MapCanvas::OnSelectSpawnNpcBrush) EVT_MENU(MAP_POPUP_MENU_SELECT_HOUSE_BRUSH, MapCanvas::OnSelectHouseBrush) +EVT_MENU(MAP_POPUP_MENU_MOVE_TO_TILESET, MapCanvas::OnSelectMoveTo) // ---- EVT_MENU(MAP_POPUP_MENU_PROPERTIES, MapCanvas::OnProperties) // ---- @@ -2318,6 +2320,51 @@ void MapCanvas::OnSelectSpawnNpcBrush(wxCommandEvent &WXUNUSED(event)) { g_gui.SelectBrush(g_gui.spawn_npc_brush, TILESET_NPC); } +void MapCanvas::OnSelectMoveTo(wxCommandEvent &WXUNUSED(event)) { + if (editor.selection.size() != 1) { + return; + } + + Tile* tile = editor.selection.getSelectedTile(); + if (!tile) { + return; + } + ASSERT(tile->isSelected()); + Tile* new_tile = tile->deepCopy(editor.map); + + wxDialog* w = nullptr; + + ItemVector selected_items = new_tile->getSelectedItems(); + + Item* item = nullptr; + int count = 0; + for (ItemVector::iterator it = selected_items.begin(); it != selected_items.end(); ++it) { + ++count; + if ((*it)->isSelected()) { + item = *it; + } + } + + if (item) { + w = newd TilesetWindow(g_gui.root, &editor.map, new_tile, item); + } else { + return; + } + + int ret = w->ShowModal(); + if (ret != 0) { + Action* action = editor.actionQueue->createAction(ACTION_CHANGE_PROPERTIES); + action->addChange(newd Change(new_tile)); + editor.addAction(action); + + g_gui.RebuildPalettes(); + } else { + // Cancel! + delete new_tile; + } + w->Destroy(); +} + void MapCanvas::OnProperties(wxCommandEvent &WXUNUSED(event)) { if (editor.getSelection().size() != 1) { return; @@ -2575,6 +2622,10 @@ void MapPopupMenu::Update() { Append(MAP_POPUP_MENU_SELECT_RAW_BRUSH, "Select RAW", "Uses the top item as a RAW brush"); + if (g_settings.getBoolean(Config::SHOW_TILESET_EDITOR)) { + Append(MAP_POPUP_MENU_MOVE_TO_TILESET, "Move To Tileset", "Move this item to any tileset"); + } + if (hasWall) { Append(MAP_POPUP_MENU_SELECT_WALL_BRUSH, "Select Wallbrush", "Uses the current item as a wallbrush"); } diff --git a/source/map_display.h b/source/map_display.h index 5a58ebbc..9158e463 100644 --- a/source/map_display.h +++ b/source/map_display.h @@ -92,6 +92,7 @@ class MapCanvas : public wxGLCanvas { void OnSelectNpcBrush(wxCommandEvent &event); void OnSelectSpawnNpcBrush(wxCommandEvent &event); void OnSelectHouseBrush(wxCommandEvent &event); + void OnSelectMoveTo(wxCommandEvent &event); // --- void OnProperties(wxCommandEvent &event); diff --git a/source/materials.cpp b/source/materials.cpp index 2b793a12..6f0c14a1 100644 --- a/source/materials.cpp +++ b/source/materials.cpp @@ -329,6 +329,43 @@ bool Materials::unserializeTileset(pugi::xml_node node, wxArrayString &warnings) return true; } +void Materials::addToTileset(std::string tilesetName, int itemId, TilesetCategoryType categoryType) { + ItemType &it = g_items[itemId]; + + if (it.id == 0) { + return; + } + + Tileset* tileset; + auto _it = tilesets.find(tilesetName); + if (_it != tilesets.end()) { + tileset = _it->second; + } else { + tileset = newd Tileset(g_brushes, tilesetName); + tilesets.insert(std::make_pair(tilesetName, tileset)); + } + + TilesetCategory* category = tileset->getCategory(categoryType); + + if (!it.isMetaItem()) { + Brush* brush; + if (it.in_other_tileset) { + category->brushlist.push_back(it.raw_brush); + return; + } else if (it.raw_brush == nullptr) { + brush = it.raw_brush = newd RAWBrush(it.id); + it.has_raw = true; + g_brushes.addBrush(it.raw_brush); + } else { + brush = it.raw_brush; + } + + brush->flagAsVisible(); + category->brushlist.push_back(it.raw_brush); + it.in_other_tileset = true; + } +} + bool Materials::isInTileset(Item* item, std::string tilesetName) const { const ItemType &type = g_items.getItemType(item->getID()); return type.id != 0 && (isInTileset(type.brush, tilesetName) || isInTileset(type.doodad_brush, tilesetName) || isInTileset(type.raw_brush, tilesetName)); diff --git a/source/materials.h b/source/materials.h index a8995821..c0895463 100644 --- a/source/materials.h +++ b/source/materials.h @@ -35,10 +35,18 @@ class Materials { bool loadMaterials(const FileName &identifier, wxString &error, wxArrayString &warnings); bool loadExtensions(FileName identifier, wxString &error, wxArrayString &warnings); void createOtherTileset(); + void addToTileset(std::string tilesetName, int itemId, TilesetCategoryType categoryType); void createNpcTileset(); bool isInTileset(Item* item, std::string tileset) const; bool isInTileset(Brush* brush, std::string tileset) const; + bool needSave() const { + return modified; + } + + void modify(bool newValue = true) { + this->modified = newValue; + } protected: bool unserializeMaterials(const FileName &filename, pugi::xml_node node, wxString &error, wxArrayString &warnings); @@ -47,6 +55,7 @@ class Materials { MaterialsExtensionList extensions; private: + bool modified = false; Materials(const Materials &); Materials &operator=(const Materials &); }; diff --git a/source/palette_brushlist.cpp b/source/palette_brushlist.cpp index 4e605d67..4b7b3a47 100644 --- a/source/palette_brushlist.cpp +++ b/source/palette_brushlist.cpp @@ -20,12 +20,17 @@ #include "palette_brushlist.h" #include "gui.h" #include "brush.h" +#include "add_tileset_window.h" +#include "add_item_window.h" +#include "materials.h" // ============================================================================ // Brush Palette Panel // A common class for terrain/doodad/item/raw palette BEGIN_EVENT_TABLE(BrushPalettePanel, PalettePanel) +EVT_BUTTON(wxID_ADD, BrushPalettePanel::OnClickAddItemToTileset) +EVT_BUTTON(wxID_NEW, BrushPalettePanel::OnClickAddTileset) EVT_CHOICEBOOK_PAGE_CHANGING(wxID_ANY, BrushPalettePanel::OnSwitchingPage) EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, BrushPalettePanel::OnPageChanged) END_EVENT_TABLE() @@ -43,6 +48,17 @@ BrushPalettePanel::BrushPalettePanel(wxWindow* parent, const TilesetContainer &t ts_sizer->Add(tmp_choicebook, 1, wxEXPAND); topsizer->Add(ts_sizer, 1, wxEXPAND); + if (g_settings.getBoolean(Config::SHOW_TILESET_EDITOR)) { + wxSizer* tmpsizer = newd wxBoxSizer(wxHORIZONTAL); + wxButton* buttonAddTileset = newd wxButton(this, wxID_NEW, "Add new Tileset"); + tmpsizer->Add(buttonAddTileset, wxSizerFlags(0).Center()); + + wxButton* buttonAddItemToTileset = newd wxButton(this, wxID_ADD, "Add new Item"); + tmpsizer->Add(buttonAddItemToTileset, wxSizerFlags(0).Center()); + + topsizer->Add(tmpsizer, 0, wxCENTER, 10); + } + for (TilesetContainer::const_iterator iter = tilesets.begin(); iter != tilesets.end(); ++iter) { const TilesetCategory* tcg = iter->second->getCategory(category); if (tcg && tcg->size() > 0) { @@ -220,6 +236,39 @@ void BrushPalettePanel::OnSwitchIn() { OnUpdateBrushSize(g_gui.GetBrushShape(), last_brush_size); } +void BrushPalettePanel::OnClickAddTileset(wxCommandEvent &WXUNUSED(event)) { + if (!choicebook) { + return; + } + + wxDialog* w = newd AddTilesetWindow(g_gui.root, palette_type); + int ret = w->ShowModal(); + w->Destroy(); + + if (ret != 0) { + g_gui.DestroyPalettes(); + g_gui.NewPalette(); + } +} + +void BrushPalettePanel::OnClickAddItemToTileset(wxCommandEvent &WXUNUSED(event)) { + if (!choicebook) { + return; + } + std::string tilesetName = choicebook->GetPageText(choicebook->GetSelection()).ToStdString(); + + auto _it = g_materials.tilesets.find(tilesetName); + if (_it != g_materials.tilesets.end()) { + wxDialog* w = newd AddItemWindow(g_gui.root, palette_type, _it->second); + int ret = w->ShowModal(); + w->Destroy(); + + if (ret != 0) { + g_gui.RebuildPalettes(); + } + } +} + // ============================================================================ // Brush Panel // A container of brush buttons diff --git a/source/palette_brushlist.h b/source/palette_brushlist.h index f3ea0e94..672a45f8 100644 --- a/source/palette_brushlist.h +++ b/source/palette_brushlist.h @@ -189,6 +189,8 @@ class BrushPalettePanel : public PalettePanel { // Event handler for child window void OnSwitchingPage(wxChoicebookEvent &event); void OnPageChanged(wxChoicebookEvent &event); + void OnClickAddTileset(wxCommandEvent &WXUNUSED(event)); + void OnClickAddItemToTileset(wxCommandEvent &WXUNUSED(event)); protected: PaletteType palette_type; diff --git a/source/preferences.cpp b/source/preferences.cpp index 98463019..39132f8d 100644 --- a/source/preferences.cpp +++ b/source/preferences.cpp @@ -86,6 +86,11 @@ wxNotebookPage* PreferencesWindow::CreateGeneralPage() { only_one_instance_chkbox->SetToolTip("When checked, maps opened using the shell will all be opened in the same instance."); sizer->Add(only_one_instance_chkbox, 0, wxLEFT | wxTOP, 5); + enable_tileset_editing_chkbox = newd wxCheckBox(general_page, wxID_ANY, "Enable tileset editing"); + enable_tileset_editing_chkbox->SetValue(g_settings.getInteger(Config::SHOW_TILESET_EDITOR) == 1); + enable_tileset_editing_chkbox->SetToolTip("Show tileset editing options."); + sizer->Add(enable_tileset_editing_chkbox, 0, wxLEFT | wxTOP, 5); + sizer->AddSpacer(10); auto* grid_sizer = newd wxFlexGridSizer(2, 10, 10); @@ -590,6 +595,8 @@ void PreferencesWindow::OnCollapsiblePane(wxCollapsiblePaneEvent &event) { void PreferencesWindow::Apply() { bool must_restart = false; + bool palette_update_needed = false; + // General g_settings.setInteger(Config::WELCOME_DIALOG, show_welcome_dialog_chkbox->GetValue()); g_settings.setInteger(Config::ALWAYS_MAKE_BACKUP, always_make_backup_chkbox->GetValue()); @@ -601,6 +608,10 @@ void PreferencesWindow::Apply() { g_settings.setInteger(Config::REPLACE_SIZE, replace_size_spin->GetValue()); g_settings.setInteger(Config::COPY_POSITION_FORMAT, position_format->GetSelection()); g_settings.setInteger(Config::COPY_AREA_FORMAT, area_format->GetSelection()); + if (g_settings.getBoolean(Config::SHOW_TILESET_EDITOR) != enable_tileset_editing_chkbox->GetValue()) { + palette_update_needed = true; + } + g_settings.setInteger(Config::SHOW_TILESET_EDITOR, enable_tileset_editing_chkbox->GetValue()); // Editor g_settings.setInteger(Config::GROUP_ACTIONS, group_actions_chkbox->GetValue()); @@ -724,5 +735,16 @@ void PreferencesWindow::Apply() { if (must_restart) { g_gui.PopupDialog(this, "Notice", "You must restart the editor for the changes to take effect.", wxOK); } - g_gui.RebuildPalettes(); + + if (!palette_update_needed) { + // update palette icons + g_gui.RebuildPalettes(); + } else { + // change palette structure + wxString error; + wxArrayString warnings; + g_gui.LoadVersion(g_gui.GetCurrentVersionID(), error, warnings, true); + g_gui.PopupDialog("Error", error, wxOK); + g_gui.ListDialog("Warnings", warnings); + } } diff --git a/source/preferences.h b/source/preferences.h index ff6b725e..402b0306 100644 --- a/source/preferences.h +++ b/source/preferences.h @@ -46,6 +46,7 @@ class PreferencesWindow : public wxDialog { wxCheckBox* update_check_on_startup_chkbox; wxCheckBox* only_one_instance_chkbox; wxCheckBox* show_welcome_dialog_chkbox; + wxCheckBox* enable_tileset_editing_chkbox; wxSpinCtrl* undo_size_spin; wxSpinCtrl* undo_mem_size_spin; wxSpinCtrl* worker_threads_spin; diff --git a/source/settings.cpp b/source/settings.cpp index b950674f..6d8d1bf0 100644 --- a/source/settings.cpp +++ b/source/settings.cpp @@ -266,6 +266,7 @@ void Settings::IO(IOMode mode) { Int(DEFAULT_CLIENT_VERSION, CLIENT_VERSION_NONE); Int(RAW_LIKE_SIMONE, 1); Int(ONLY_ONE_INSTANCE, 1); + Int(SHOW_TILESET_EDITOR, 0); Int(USE_OTBM_4_FOR_ALL_MAPS, 0); Int(USE_OTGZ, 1); Int(SAVE_WITH_OTB_MAGIC_NUMBER, 0); @@ -289,6 +290,7 @@ void Settings::IO(IOMode mode) { Int(MINIMAP_UPDATE_DELAY, 333); Int(MINIMAP_VIEW_BOX, 1); String(MINIMAP_EXPORT_DIR, ""); + String(TILESET_EXPORT_DIR, ""); Int(CURSOR_RED, 0); Int(CURSOR_GREEN, 166); diff --git a/source/settings.h b/source/settings.h index 26f60540..4a5b61b7 100644 --- a/source/settings.h +++ b/source/settings.h @@ -146,6 +146,7 @@ namespace Config { INDIRECTORY_INSTALLATION, AUTOCHECK_FOR_UPDATES, ONLY_ONE_INSTANCE, + SHOW_TILESET_EDITOR, PALETTE_LAYOUT, MINIMAP_VISIBLE, @@ -153,6 +154,7 @@ namespace Config { MINIMAP_UPDATE_DELAY, MINIMAP_VIEW_BOX, MINIMAP_EXPORT_DIR, + TILESET_EXPORT_DIR, ACTIONS_HISTORY_VISIBLE, ACTIONS_HISTORY_LAYOUT, WINDOW_HEIGHT, diff --git a/source/tileset.cpp b/source/tileset.cpp index 65581e29..c0bdf178 100644 --- a/source/tileset.cpp +++ b/source/tileset.cpp @@ -245,7 +245,7 @@ void TilesetCategory::loadBrush(pugi::xml_node node, wxArrayString &warnings) { for (uint16_t id = fromId; id <= toId; ++id) { ItemType* type = g_items.getRawItemType(id); if (!type) { - warnings.push_back(wxString::Format("Brush: %s, From: %d, To: %d", wxstr(brushName), fromId, toId)); + warnings.push_back(wxString::Format("Tileset: %s, Brush: %s, Previous %d, From: %d, To: %d", wxstr(tileset.name), wxstr(brushName), tileset.previousId, fromId, toId)); warnings.push_back("Unknown item id #" + std::to_string(id) + "."); continue; } @@ -265,6 +265,8 @@ void TilesetCategory::loadBrush(pugi::xml_node node, wxArrayString &warnings) { brush->flagAsVisible(); tempBrushVector.push_back(brush); + + tileset.previousId = id; } auto insertPosition = brushlist.end(); diff --git a/source/tileset.h b/source/tileset.h index af4e5bc7..ddfb093d 100644 --- a/source/tileset.h +++ b/source/tileset.h @@ -80,6 +80,7 @@ class Tileset { public: std::string name; + int16_t previousId; TilesetCategoryArray categories; protected: diff --git a/source/tileset_window.cpp b/source/tileset_window.cpp new file mode 100644 index 00000000..6381fc2f --- /dev/null +++ b/source/tileset_window.cpp @@ -0,0 +1,124 @@ +////////////////////////////////////////////////////////////////////// +// This file is part of Remere's Map Editor +////////////////////////////////////////////////////////////////////// +// Remere's Map Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Remere's Map Editor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +////////////////////////////////////////////////////////////////////// + +#include "main.h" + +#include + +#include "tile.h" +#include "item.h" +#include "complexitem.h" +#include "town.h" +#include "house.h" +#include "map.h" +#include "editor.h" +#include "materials.h" +#include "tileset.h" + +#include "gui.h" +#include "application.h" +#include "tileset_window.h" +#include "container_properties_window.h" + +// ============================================================================ +// Tileset Window + +BEGIN_EVENT_TABLE(TilesetWindow, wxDialog) +EVT_BUTTON(wxID_OK, TilesetWindow::OnClickOK) +EVT_BUTTON(wxID_CANCEL, TilesetWindow::OnClickCancel) +END_EVENT_TABLE() + +static constexpr int OUTFIT_COLOR_MAX = 133; + +TilesetWindow::TilesetWindow(wxWindow* win_parent, const Map* map, const Tile* tile_parent, Item* item, wxPoint pos) : + ObjectPropertiesWindowBase(win_parent, "Move to Tileset", map, tile_parent, item, pos), + palette_field(nullptr), + tileset_field(nullptr) { + ASSERT(edit_item); + + wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL); + wxString description = "Move to Tileset"; + + wxSizer* boxsizer = newd wxStaticBoxSizer(wxVERTICAL, this, description); + + wxFlexGridSizer* subsizer = newd wxFlexGridSizer(2, 10, 10); + subsizer->AddGrowableCol(1); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "ID " + i2ws(item->getID()))); + subsizer->Add(newd wxStaticText(this, wxID_ANY, "\"" + wxstr(item->getName()) + "\"")); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Palette")); + palette_field = newd wxChoice(this, wxID_ANY); + + palette_field->Append("Terrain", newd int(TILESET_TERRAIN)); + palette_field->Append("Doodad", newd int(TILESET_DOODAD)); + palette_field->Append("Item", newd int(TILESET_ITEM)); + palette_field->Append("Raw", newd int(TILESET_RAW)); + palette_field->SetSelection(3); + + palette_field->Connect(wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(TilesetWindow::OnChangePalette), NULL, this); + subsizer->Add(palette_field, wxSizerFlags(1).Expand()); + + subsizer->Add(newd wxStaticText(this, wxID_ANY, "Tileset")); + tileset_field = newd wxChoice(this, wxID_ANY); + + for (TilesetContainer::iterator iter = g_materials.tilesets.begin(); iter != g_materials.tilesets.end(); ++iter) { + tileset_field->Append(wxstr(iter->second->name), newd std::string(iter->second->name)); + } + tileset_field->SetSelection(0); + subsizer->Add(tileset_field, wxSizerFlags(1).Expand()); + + boxsizer->Add(subsizer, wxSizerFlags(1).Expand()); + + topsizer->Add(boxsizer, wxSizerFlags(0).Expand().Border(wxLEFT | wxRIGHT, 20)); + + wxSizer* subsizer_ = newd wxBoxSizer(wxHORIZONTAL); + subsizer_->Add(newd wxButton(this, wxID_OK, "OK"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); + subsizer_->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); + topsizer->Add(subsizer_, wxSizerFlags(0).Center().Border(wxLEFT | wxRIGHT, 20)); + + SetSizerAndFit(topsizer); + Centre(wxBOTH); +} + +void TilesetWindow::OnChangePalette(wxCommandEvent &WXUNUSED(event)) { + tileset_field->Clear(); + + for (TilesetContainer::iterator iter = g_materials.tilesets.begin(); iter != g_materials.tilesets.end(); ++iter) { + if (iter->second->getCategory(TilesetCategoryType(*static_cast(palette_field->GetClientData(palette_field->GetSelection()))))->brushlist.size() > 0) { + tileset_field->Append(wxstr(iter->second->name), newd std::string(iter->second->name)); + } + } + + tileset_field->SetSelection(0); +} + +void TilesetWindow::OnClickOK(wxCommandEvent &WXUNUSED(event)) { + if (edit_item) { + TilesetCategoryType categoryType = TilesetCategoryType(*reinterpret_cast(palette_field->GetClientData(palette_field->GetSelection()))); + std::string tilesetName = *static_cast(tileset_field->GetClientData(tileset_field->GetSelection())); + + g_materials.addToTileset(tilesetName, edit_item->getID(), categoryType); + g_gui.PopupDialog("Added to Tileset", "'" + edit_item->getName() + "' has been added to tileset '" + tilesetName + "' of palette '" + palette_field->GetStringSelection() + "'", wxOK); + } + EndModal(1); +} + +void TilesetWindow::OnClickCancel(wxCommandEvent &WXUNUSED(event)) { + // Just close this window + EndModal(0); +} diff --git a/source/tileset_window.h b/source/tileset_window.h new file mode 100644 index 00000000..bfd4c262 --- /dev/null +++ b/source/tileset_window.h @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////// +// This file is part of Remere's Map Editor +////////////////////////////////////////////////////////////////////// +// Remere's Map Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Remere's Map Editor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +////////////////////////////////////////////////////////////////////// + +#ifndef RME_TILESET_WINDOW_H_ +#define RME_TILESET_WINDOW_H_ + +#include "main.h" + +#include "common_windows.h" + +class ContainerItemButton; +class ContainerItemPopupMenu; + +class TilesetWindow : public ObjectPropertiesWindowBase { +public: + TilesetWindow(wxWindow* parent, const Map* map, const Tile* tile, Item* item, wxPoint = wxDefaultPosition); + + void OnChangePalette(wxCommandEvent &event); + + void OnClickOK(wxCommandEvent &); + void OnClickCancel(wxCommandEvent &); + +protected: + // tileset + wxChoice* palette_field; + wxChoice* tileset_field; + + DECLARE_EVENT_TABLE(); +}; + +#endif diff --git a/vcproj/Project/RME.vcxproj b/vcproj/Project/RME.vcxproj index de70b1c0..94a1f9b9 100644 --- a/vcproj/Project/RME.vcxproj +++ b/vcproj/Project/RME.vcxproj @@ -222,6 +222,8 @@ + + @@ -230,10 +232,13 @@ + + + @@ -380,6 +385,7 @@ +