Map Editor

RD Core / Commit #3

Commit Map Editor

Alex Alex committed 18/10/2026 23:40 main Patch
436 files +250,791 -0
A RD_Map_Editor/source/application.h +110-0 View file
@@ -0,0 +1,110 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_APPLICATION_H_
19+#define RME_APPLICATION_H_
20+
21+#include "gui.h"
22+#include "main_toolbar.h"
23+#include "action.h"
24+#include "settings.h"
25+
26+#include "process_com.h"
27+#include "map_display.h"
28+#include "welcome_dialog.h"
29+
30+class Item;
31+class Creature;
32+
33+class MainFrame;
34+class MapWindow;
35+class wxEventLoopBase;
36+class wxSingleInstanceChecker;
37+
38+class Application : public wxApp {
39+public:
40+ ~Application();
41+ virtual bool OnInit();
42+ virtual void OnEventLoopEnter(wxEventLoopBase* loop);
43+ virtual void MacOpenFiles(const wxArrayString& fileNames);
44+ virtual int OnExit();
45+ virtual bool OnExceptionInMainLoop();
46+ void Unload();
47+
48+private:
49+ bool m_startup;
50+ wxString m_file_to_open;
51+ void FixVersionDiscrapencies();
52+ bool ParseCommandLineMap(wxString& fileName);
53+
54+ virtual void OnFatalException();
55+
56+#ifdef _USE_PROCESS_COM
57+ RMEProcessServer* m_proc_server;
58+ wxSingleInstanceChecker* m_single_instance_checker;
59+#endif
60+};
61+
62+class MainMenuBar;
63+
64+class MainFrame : public wxFrame {
65+public:
66+ MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
67+ ~MainFrame();
68+
69+ void UpdateMenubar();
70+ bool DoQueryClose();
71+ bool DoQuerySave(bool doclose = true);
72+ bool DoQuerySaveTileset(bool doclose = true);
73+ bool DoQueryImportCreatures();
74+ bool LoadMap(FileName name);
75+
76+ void AddRecentFile(const FileName& file);
77+ void LoadRecentFiles();
78+ void SaveRecentFiles();
79+ std::vector<wxString> GetRecentFiles();
80+
81+ MainToolBar* GetAuiToolBar() const {
82+ return tool_bar;
83+ }
84+
85+ void OnUpdateMenus(wxCommandEvent& event);
86+ void UpdateFloorMenu();
87+ void OnIdle(wxIdleEvent& event);
88+ void OnExit(wxCloseEvent& event);
89+
90+#ifdef _USE_UPDATER_
91+ void OnUpdateReceived(wxCommandEvent& event);
92+#endif
93+
94+#ifdef __WINDOWS__
95+ virtual bool MSWTranslateMessage(WXMSG* msg);
96+#endif
97+
98+ void PrepareDC(wxDC& dc);
99+
100+protected:
101+ MainMenuBar* menu_bar;
102+ MainToolBar* tool_bar;
103+
104+ friend class Application;
105+ friend class GUI;
106+
107+ DECLARE_EVENT_TABLE()
108+};
109+
110+#endif
A RD_Map_Editor/source/artprovider.cpp +109-0 View file
@@ -0,0 +1,109 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+#include "artprovider.h"
20+
21+#include "../icons/circular_1.xpm"
22+#include "../icons/circular_2.xpm"
23+#include "../icons/circular_3.xpm"
24+#include "../icons/circular_4.xpm"
25+#include "../icons/circular_5.xpm"
26+#include "../icons/circular_6.xpm"
27+#include "../icons/circular_7.xpm"
28+#include "../icons/nologout_zone.xpm"
29+#include "../icons/nopvp_zone.xpm"
30+#include "../icons/position_go.xpm"
31+#include "../icons/protected_zone.xpm"
32+#include "../icons/pvp_zone.xpm"
33+#include "../icons/rectangular_1.xpm"
34+#include "../icons/rectangular_2.xpm"
35+#include "../icons/rectangular_3.xpm"
36+#include "../icons/rectangular_4.xpm"
37+#include "../icons/rectangular_5.xpm"
38+#include "../icons/rectangular_6.xpm"
39+#include "../icons/rectangular_7.xpm"
40+#include "../brushes/door_normal_small.xpm"
41+#include "../brushes/door_locked_small.xpm"
42+#include "../brushes/door_magic_small.xpm"
43+#include "../brushes/door_quest_small.xpm"
44+#include "../brushes/door_normal_alt_small.xpm"
45+#include "../brushes/door_archway_small.xpm"
46+
47+wxBitmap ArtProvider::CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& WXUNUSED(size)) {
48+ if (client == wxART_TOOLBAR) {
49+ if (id == ART_CIRCULAR) {
50+ return wxBitmap(circular_4_xpm);
51+ } else if (id == ART_CIRCULAR_1) {
52+ return wxBitmap(circular_1_xpm);
53+ } else if (id == ART_CIRCULAR_2) {
54+ return wxBitmap(circular_2_xpm);
55+ } else if (id == ART_CIRCULAR_3) {
56+ return wxBitmap(circular_3_xpm);
57+ } else if (id == ART_CIRCULAR_4) {
58+ return wxBitmap(circular_4_xpm);
59+ } else if (id == ART_CIRCULAR_5) {
60+ return wxBitmap(circular_5_xpm);
61+ } else if (id == ART_CIRCULAR_6) {
62+ return wxBitmap(circular_6_xpm);
63+ } else if (id == ART_CIRCULAR_7) {
64+ return wxBitmap(circular_7_xpm);
65+ } else if (id == ART_NOLOOUT_BRUSH) {
66+ return wxBitmap(nologout_zone_xpm);
67+ } else if (id == ART_NOPVP_BRUSH) {
68+ return wxBitmap(nopvp_zone_xpm);
69+ } else if (id == ART_POSITION_GO) {
70+ return wxBitmap(position_go_xpm);
71+ } else if (id == ART_PVP_BRUSH) {
72+ return wxBitmap(pvp_zone_xpm);
73+ } else if (id == ART_PZ_BRUSH) {
74+ return wxBitmap(protected_zone_xpm);
75+ } else if (id == ART_RECTANGULAR) {
76+ return wxBitmap(rectangular_4_xpm);
77+ } else if (id == ART_RECTANGULAR_1) {
78+ return wxBitmap(rectangular_1_xpm);
79+ } else if (id == ART_RECTANGULAR_2) {
80+ return wxBitmap(rectangular_2_xpm);
81+ } else if (id == ART_RECTANGULAR_3) {
82+ return wxBitmap(rectangular_3_xpm);
83+ } else if (id == ART_RECTANGULAR_4) {
84+ return wxBitmap(rectangular_4_xpm);
85+ } else if (id == ART_RECTANGULAR_5) {
86+ return wxBitmap(rectangular_5_xpm);
87+ } else if (id == ART_RECTANGULAR_6) {
88+ return wxBitmap(rectangular_6_xpm);
89+ } else if (id == ART_RECTANGULAR_7) {
90+ return wxBitmap(rectangular_7_xpm);
91+ }
92+
93+ else if (id == ART_DOOR_NORMAL_SMALL) {
94+ return wxBitmap(door_normal_small_xpm);
95+ } else if (id == ART_DOOR_LOCKED_SMALL) {
96+ return wxBitmap(door_locked_small_xpm);
97+ } else if (id == ART_DOOR_MAGIC_SMALL) {
98+ return wxBitmap(door_magic_small_xpm);
99+ } else if (id == ART_DOOR_QUEST_SMALL) {
100+ return wxBitmap(door_quest_small_xpm);
101+ } else if (id == ART_DOOR_NORMAL_ALT_SMALL) {
102+ return wxBitmap(door_normal_alt_small_xpm);
103+ } else if (id == ART_DOOR_ARCHWAY_SMALL) {
104+ return wxBitmap(door_archway_small_xpm);
105+ }
106+ }
107+
108+ return wxNullBitmap;
109+}
A RD_Map_Editor/source/artprovider.h +63-0 View file
@@ -0,0 +1,63 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_ART_PROVIDER_H_
19+#define RME_ART_PROVIDER_H_
20+
21+#include <wx/artprov.h>
22+
23+#define ART_CIRCULAR wxART_MAKE_ART_ID(ART_CIRCULAR)
24+#define ART_CIRCULAR_1 wxART_MAKE_ART_ID(ART_CIRCULAR_1)
25+#define ART_CIRCULAR_2 wxART_MAKE_ART_ID(ART_CIRCULAR_2)
26+#define ART_CIRCULAR_3 wxART_MAKE_ART_ID(ART_CIRCULAR_3)
27+#define ART_CIRCULAR_4 wxART_MAKE_ART_ID(ART_CIRCULAR_4)
28+#define ART_CIRCULAR_5 wxART_MAKE_ART_ID(ART_CIRCULAR_5)
29+#define ART_CIRCULAR_6 wxART_MAKE_ART_ID(ART_CIRCULAR_6)
30+#define ART_CIRCULAR_7 wxART_MAKE_ART_ID(ART_CIRCULAR_7)
31+#define ART_NOLOOUT_BRUSH wxART_MAKE_ART_ID(ART_NOLOOUT_BRUSH)
32+#define ART_NOPVP_BRUSH wxART_MAKE_ART_ID(ART_NOPVP_BRUSH)
33+#define ART_POSITION_GO wxART_MAKE_ART_ID(ART_POSITION_GO)
34+#define ART_PVP_BRUSH wxART_MAKE_ART_ID(ART_PVP_BRUSH)
35+#define ART_PZ_BRUSH wxART_MAKE_ART_ID(ART_PZ_BRUSH)
36+#define ART_RECTANGULAR wxART_MAKE_ART_ID(ART_RECTANGULAR)
37+#define ART_RECTANGULAR_1 wxART_MAKE_ART_ID(ART_RECTANGULAR_1)
38+#define ART_RECTANGULAR_2 wxART_MAKE_ART_ID(ART_RECTANGULAR_2)
39+#define ART_RECTANGULAR_3 wxART_MAKE_ART_ID(ART_RECTANGULAR_3)
40+#define ART_RECTANGULAR_4 wxART_MAKE_ART_ID(ART_RECTANGULAR_4)
41+#define ART_RECTANGULAR_5 wxART_MAKE_ART_ID(ART_RECTANGULAR_5)
42+#define ART_RECTANGULAR_6 wxART_MAKE_ART_ID(ART_RECTANGULAR_6)
43+#define ART_RECTANGULAR_7 wxART_MAKE_ART_ID(ART_RECTANGULAR_7)
44+
45+#define ART_DOOR_NORMAL wxART_MAKE_ART_ID(ART_DOOR_NORMAL)
46+#define ART_DOOR_NORMAL_SMALL wxART_MAKE_ART_ID(ART_DOOR_NORMAL_SMALL)
47+#define ART_DOOR_LOCKED wxART_MAKE_ART_ID(ART_DOOR_LOCKED)
48+#define ART_DOOR_LOCKED_SMALL wxART_MAKE_ART_ID(ART_DOOR_LOCKED_SMALL)
49+#define ART_DOOR_MAGIC wxART_MAKE_ART_ID(ART_DOOR_MAGIC)
50+#define ART_DOOR_MAGIC_SMALL wxART_MAKE_ART_ID(ART_DOOR_MAGIC_SMALL)
51+#define ART_DOOR_QUEST wxART_MAKE_ART_ID(ART_DOOR_QUEST)
52+#define ART_DOOR_QUEST_SMALL wxART_MAKE_ART_ID(ART_DOOR_QUEST_SMALL)
53+#define ART_DOOR_NORMAL_ALT wxART_MAKE_ART_ID(ART_DOOR_NORMAL_ALT)
54+#define ART_DOOR_NORMAL_ALT_SMALL wxART_MAKE_ART_ID(ART_DOOR_NORMAL_ALT_SMALL)
55+#define ART_DOOR_ARCHWAY wxART_MAKE_ART_ID(ART_DOOR_ARCHWAY)
56+#define ART_DOOR_ARCHWAY_SMALL wxART_MAKE_ART_ID(ART_DOOR_ARCHWAY_SMALL)
57+
58+class ArtProvider : public wxArtProvider {
59+protected:
60+ virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size) override;
61+};
62+
63+#endif // RME_ART_PROVIDER_H_
A RD_Map_Editor/source/automagic_settings.cpp +216-0 View file
@@ -0,0 +1,216 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+#include "automagic_settings.h"
20+#include "settings.h"
21+#include "gui.h"
22+
23+BEGIN_EVENT_TABLE(AutomagicSettingsDialog, wxDialog)
24+ EVT_BUTTON(wxID_OK, AutomagicSettingsDialog::OnClickOK)
25+ EVT_BUTTON(wxID_CANCEL, AutomagicSettingsDialog::OnClickCancel)
26+ EVT_CHECKBOX(wxID_ANY, AutomagicSettingsDialog::OnAutomagicCheck)
27+ EVT_CLOSE(AutomagicSettingsDialog::OnClose)
28+END_EVENT_TABLE()
29+
30+AutomagicSettingsDialog::AutomagicSettingsDialog(wxWindow* parent) :
31+ wxDialog(parent, wxID_ANY, "Automagic Settings", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
32+{
33+ // Create main sizer
34+ wxBoxSizer* main_sizer = newd wxBoxSizer(wxVERTICAL);
35+
36+ // Create a static box for the settings
37+ wxStaticBoxSizer* settings_sizer = newd wxStaticBoxSizer(wxVERTICAL, this, "Border Settings");
38+
39+ // Create checkboxes
40+ automagic_enabled_checkbox = newd wxCheckBox(this, wxID_ANY, "Enable Automagic");
41+ automagic_enabled_checkbox->SetValue(g_settings.getBoolean(Config::USE_AUTOMAGIC));
42+ automagic_enabled_checkbox->SetToolTip("Automatically apply borders and wall connections when editing");
43+ settings_sizer->Add(automagic_enabled_checkbox, 0, wxALL, 5);
44+
45+ same_ground_type_checkbox = newd wxCheckBox(this, wxID_ANY, "Same Ground Type Border");
46+ same_ground_type_checkbox->SetValue(g_settings.getBoolean(Config::SAME_GROUND_TYPE_BORDER));
47+ same_ground_type_checkbox->SetToolTip("Preserve existing borders and only apply borders for the current ground type");
48+ same_ground_type_checkbox->Enable(automagic_enabled_checkbox->GetValue());
49+ settings_sizer->Add(same_ground_type_checkbox, 0, wxALL, 5);
50+
51+ walls_repel_borders_checkbox = newd wxCheckBox(this, wxID_ANY, "Walls Repel Borders");
52+ walls_repel_borders_checkbox->SetValue(g_settings.getBoolean(Config::WALLS_REPEL_BORDERS));
53+ walls_repel_borders_checkbox->SetToolTip("When enabled, walls will block border generation, preventing borders from crossing through walls");
54+ walls_repel_borders_checkbox->Enable(automagic_enabled_checkbox->GetValue());
55+ settings_sizer->Add(walls_repel_borders_checkbox, 0, wxALL, 5);
56+
57+ layer_carpets_checkbox = newd wxCheckBox(this, wxID_ANY, "Layer Carpets");
58+ layer_carpets_checkbox->SetValue(g_settings.getBoolean(Config::LAYER_CARPETS));
59+ layer_carpets_checkbox->SetToolTip("When enabled, carpet brushes will be placed on top of existing carpets instead of replacing them");
60+ layer_carpets_checkbox->Enable(automagic_enabled_checkbox->GetValue());
61+ settings_sizer->Add(layer_carpets_checkbox, 0, wxALL, 5);
62+
63+ borderize_delete_checkbox = newd wxCheckBox(this, wxID_ANY, "Borderize on Delete");
64+ borderize_delete_checkbox->SetValue(g_settings.getBoolean(Config::BORDERIZE_DELETE));
65+ borderize_delete_checkbox->SetToolTip("When enabled, deleting items will trigger automatic bordering of surrounding tiles");
66+ borderize_delete_checkbox->Enable(automagic_enabled_checkbox->GetValue());
67+ settings_sizer->Add(borderize_delete_checkbox, 0, wxALL, 5);
68+
69+ // Create custom border controls
70+ wxBoxSizer* custom_border_sizer = newd wxBoxSizer(wxHORIZONTAL);
71+
72+ custom_border_checkbox = newd wxCheckBox(this, wxID_ANY, "Use Custom Border");
73+ custom_border_checkbox->SetValue(g_settings.getBoolean(Config::CUSTOM_BORDER_ENABLED));
74+ custom_border_checkbox->SetToolTip("Override automatic border selection with a specific border ID");
75+ custom_border_checkbox->Enable(automagic_enabled_checkbox->GetValue());
76+ custom_border_sizer->Add(custom_border_checkbox, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
77+
78+ custom_border_id_label = newd wxStaticText(this, wxID_ANY, "Border ID:");
79+ custom_border_id_label->Enable(custom_border_checkbox->GetValue() && automagic_enabled_checkbox->GetValue());
80+ custom_border_sizer->Add(custom_border_id_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
81+
82+ custom_border_id_field = newd wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(80, -1));
83+ custom_border_id_field->SetRange(1, 65535);
84+ custom_border_id_field->SetValue(g_settings.getInteger(Config::CUSTOM_BORDER_ID) > 0 ?
85+ g_settings.getInteger(Config::CUSTOM_BORDER_ID) : 1);
86+ custom_border_id_field->Enable(custom_border_checkbox->GetValue() && automagic_enabled_checkbox->GetValue());
87+ custom_border_id_field->SetToolTip("The ID of the border to use when drawing any tile");
88+ custom_border_sizer->Add(custom_border_id_field, 0, wxALIGN_CENTER_VERTICAL);
89+
90+ settings_sizer->Add(custom_border_sizer, 0, wxALL, 5);
91+
92+ // Add description text
93+ wxStaticText* description = newd wxStaticText(this, wxID_ANY,
94+ "When 'Same Ground Type Border' is enabled, the editor will:\n"
95+ "- Preserve existing borders on tiles\n"
96+ "- Only apply borders for the current ground type\n"
97+ "- Respect Z-axis positioning of existing borders\n"
98+ "- Allow multiple border layering\n\n"
99+ "When 'Walls Repel Borders' is enabled, the editor will:\n"
100+ "- Prevent borders from crossing through walls\n"
101+ "- Treat walls as barriers for border generation\n"
102+ "- Preserve the structure of buildings and houses\n\n"
103+ "When 'Layer Carpets' is enabled, the editor will:\n"
104+ "- Place new carpets on top of existing carpets\n"
105+ "- Allow creating multi-layered carpet designs\n\n"
106+ "When 'Use Custom Border' is enabled, the editor will:\n"
107+ "- Override automatic border selection with the specified border ID\n"
108+ "- Apply the same border pattern around any tile you draw\n"
109+ "- Ignore terrain type border transitions");
110+ settings_sizer->Add(description, 0, wxALL, 5);
111+
112+ main_sizer->Add(settings_sizer, 0, wxEXPAND | wxALL, 10);
113+
114+ // Create buttons
115+ buttons_sizer = newd wxStdDialogButtonSizer();
116+ ok_button = newd wxButton(this, wxID_OK, "OK");
117+ cancel_button = newd wxButton(this, wxID_CANCEL, "Cancel");
118+
119+ buttons_sizer->AddButton(ok_button);
120+ buttons_sizer->AddButton(cancel_button);
121+ buttons_sizer->Realize();
122+
123+ main_sizer->Add(buttons_sizer, 0, wxALIGN_CENTER | wxALL, 10);
124+
125+ // Set sizer and fit
126+ SetSizer(main_sizer);
127+ Fit();
128+ Centre();
129+}
130+
131+AutomagicSettingsDialog::~AutomagicSettingsDialog() {
132+ // Nothing to clean up
133+}
134+
135+bool AutomagicSettingsDialog::IsAutomagicEnabled() const {
136+ return automagic_enabled_checkbox->GetValue();
137+}
138+
139+bool AutomagicSettingsDialog::IsSameGroundTypeBorderEnabled() const {
140+ return same_ground_type_checkbox->GetValue();
141+}
142+
143+bool AutomagicSettingsDialog::IsWallsRepelBordersEnabled() const {
144+ return walls_repel_borders_checkbox->GetValue();
145+}
146+
147+bool AutomagicSettingsDialog::IsLayerCarpetsEnabled() const {
148+ return layer_carpets_checkbox->GetValue();
149+}
150+
151+bool AutomagicSettingsDialog::IsBorderizeDeleteEnabled() const {
152+ return borderize_delete_checkbox->GetValue();
153+}
154+
155+bool AutomagicSettingsDialog::IsCustomBorderEnabled() const {
156+ return custom_border_checkbox->GetValue();
157+}
158+
159+int AutomagicSettingsDialog::GetCustomBorderId() const {
160+ return custom_border_id_field->GetValue();
161+}
162+
163+void AutomagicSettingsDialog::OnClickOK(wxCommandEvent& event) {
164+ // Save settings
165+ g_settings.setInteger(Config::USE_AUTOMAGIC, IsAutomagicEnabled() ? 1 : 0);
166+ g_settings.setInteger(Config::BORDER_IS_GROUND, IsAutomagicEnabled() ? 1 : 0);
167+ g_settings.setInteger(Config::SAME_GROUND_TYPE_BORDER, IsSameGroundTypeBorderEnabled() ? 1 : 0);
168+ g_settings.setInteger(Config::WALLS_REPEL_BORDERS, IsWallsRepelBordersEnabled() ? 1 : 0);
169+ g_settings.setInteger(Config::LAYER_CARPETS, IsLayerCarpetsEnabled() ? 1 : 0);
170+ g_settings.setInteger(Config::BORDERIZE_DELETE, IsBorderizeDeleteEnabled() ? 1 : 0);
171+
172+ // Save custom border settings
173+ g_settings.setInteger(Config::CUSTOM_BORDER_ENABLED, IsCustomBorderEnabled() ? 1 : 0);
174+ g_settings.setInteger(Config::CUSTOM_BORDER_ID, GetCustomBorderId());
175+
176+ // Update status text
177+ if (IsAutomagicEnabled()) {
178+ g_gui.SetStatusText("Automagic enabled.");
179+ } else {
180+ g_gui.SetStatusText("Automagic disabled.");
181+ }
182+
183+ EndModal(wxID_OK);
184+}
185+
186+void AutomagicSettingsDialog::OnClickCancel(wxCommandEvent& event) {
187+ // Don't save settings
188+ EndModal(wxID_CANCEL);
189+}
190+
191+void AutomagicSettingsDialog::OnAutomagicCheck(wxCommandEvent& event) {
192+ // Get the checkbox that triggered the event
193+ wxCheckBox* checkbox = dynamic_cast<wxCheckBox*>(event.GetEventObject());
194+
195+ // Update all checkbox states based on automagic checkbox
196+ bool automagic_enabled = automagic_enabled_checkbox->GetValue();
197+
198+ // If this is the automagic checkbox, update all dependent checkboxes
199+ if (checkbox == automagic_enabled_checkbox) {
200+ same_ground_type_checkbox->Enable(automagic_enabled);
201+ walls_repel_borders_checkbox->Enable(automagic_enabled);
202+ layer_carpets_checkbox->Enable(automagic_enabled);
203+ borderize_delete_checkbox->Enable(automagic_enabled);
204+ custom_border_checkbox->Enable(automagic_enabled);
205+ }
206+
207+ // Always update the custom border fields based on both checkboxes
208+ bool custom_border_enabled = custom_border_checkbox->GetValue() && automagic_enabled;
209+ custom_border_id_label->Enable(custom_border_enabled);
210+ custom_border_id_field->Enable(custom_border_enabled);
211+}
212+
213+void AutomagicSettingsDialog::OnClose(wxCloseEvent& event) {
214+ // Same as cancel
215+ EndModal(wxID_CANCEL);
216+}
A RD_Map_Editor/source/automagic_settings.h +53-0 View file
@@ -0,0 +1,53 @@
1+#ifndef RME_AUTOMAGIC_SETTINGS_H_
2+#define RME_AUTOMAGIC_SETTINGS_H_
3+
4+#include <wx/dialog.h>
5+#include <wx/checkbox.h>
6+#include <wx/button.h>
7+#include <wx/sizer.h>
8+#include <wx/stattext.h>
9+#include <wx/statbox.h>
10+#include <wx/spinctrl.h>
11+
12+class AutomagicSettingsDialog : public wxDialog {
13+public:
14+ AutomagicSettingsDialog(wxWindow* parent);
15+ virtual ~AutomagicSettingsDialog();
16+
17+ // Get the current settings from the dialog
18+ bool IsAutomagicEnabled() const;
19+ bool IsSameGroundTypeBorderEnabled() const;
20+ bool IsWallsRepelBordersEnabled() const;
21+ bool IsLayerCarpetsEnabled() const;
22+ bool IsBorderizeDeleteEnabled() const;
23+ // New custom border methods
24+ bool IsCustomBorderEnabled() const;
25+ int GetCustomBorderId() const;
26+
27+protected:
28+ // Event handlers
29+ void OnClickOK(wxCommandEvent& event);
30+ void OnClickCancel(wxCommandEvent& event);
31+ void OnAutomagicCheck(wxCommandEvent& event);
32+ void OnSameGroundTypeCheck(wxCommandEvent& event);
33+ void OnClose(wxCloseEvent& event);
34+ void OnCustomBorderCheck(wxCommandEvent& event); // New event handler
35+
36+ // UI elements
37+ wxCheckBox* automagic_enabled_checkbox;
38+ wxCheckBox* same_ground_type_checkbox;
39+ wxCheckBox* walls_repel_borders_checkbox;
40+ wxCheckBox* layer_carpets_checkbox;
41+ wxCheckBox* borderize_delete_checkbox;
42+ // New UI elements for custom border
43+ wxCheckBox* custom_border_checkbox;
44+ wxSpinCtrl* custom_border_id_field;
45+ wxStaticText* custom_border_id_label;
46+ wxStdDialogButtonSizer* buttons_sizer;
47+ wxButton* ok_button;
48+ wxButton* cancel_button;
49+
50+ DECLARE_EVENT_TABLE()
51+};
52+
53+#endif // RME_AUTOMAGIC_SETTINGS_H_
A RD_Map_Editor/source/basemap.cpp +306-0 View file
@@ -0,0 +1,306 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+
20+#include "tile.h"
21+#include "basemap.h"
22+
23+BaseMap::BaseMap() :
24+ allocator(),
25+ tilecount(0),
26+ root(*this) {
27+ ////
28+}
29+
30+BaseMap::~BaseMap() {
31+ ////
32+}
33+
34+void BaseMap::clear(bool del) {
35+ PositionVector pos_vec;
36+ for (MapIterator map_iter = begin(); map_iter != end(); ++map_iter) {
37+ Tile* t = (*map_iter)->get();
38+ pos_vec.push_back(t->getPosition());
39+ }
40+ for (PositionVector::iterator pos_iter = pos_vec.begin(); pos_iter != pos_vec.end(); ++pos_iter) {
41+ setTile(*pos_iter, nullptr, del);
42+ }
43+}
44+
45+void BaseMap::clearVisible(uint32_t mask) {
46+ root.clearVisible(mask);
47+}
48+
49+Tile* BaseMap::createTile(int x, int y, int z) {
50+ ASSERT(z < MAP_LAYERS);
51+ QTreeNode* leaf = root.getLeafForce(x, y);
52+ TileLocation* loc = leaf->createTile(x, y, z);
53+ if (loc->get()) {
54+ return loc->get();
55+ }
56+ Tile* t = allocator(loc);
57+ leaf->setTile(x, y, z, t);
58+ return t;
59+}
60+
61+Tile* BaseMap::getOrCreateTile(const Position& pos) {
62+ if (Tile* t = getTile(pos)) {
63+ return t;
64+ }
65+
66+ Tile* newTile = createTile(pos.x, pos.y, pos.z);
67+ newTile->setLocation(createTileL(pos));
68+ return newTile;
69+}
70+
71+TileLocation* BaseMap::getTileL(int x, int y, int z) {
72+ ASSERT(z < MAP_LAYERS);
73+ QTreeNode* leaf = root.getLeaf(x, y);
74+ if (leaf) {
75+ Floor* floor = leaf->getFloor(z);
76+ if (floor) {
77+ return &floor->locs[(x & 3) * 4 + (y & 3)];
78+ }
79+ }
80+
81+ return nullptr;
82+}
83+
84+const TileLocation* BaseMap::getTileL(int x, int y, int z) const {
85+ // Don't create static const maps!
86+ BaseMap* self = const_cast<BaseMap*>(this);
87+ return self->getTileL(x, y, z);
88+}
89+
90+TileLocation* BaseMap::getTileL(const Position& pos) {
91+ return getTileL(pos.x, pos.y, pos.z);
92+}
93+
94+const TileLocation* BaseMap::getTileL(const Position& pos) const {
95+ return getTileL(pos.x, pos.y, pos.z);
96+}
97+
98+TileLocation* BaseMap::createTileL(int x, int y, int z) {
99+ ASSERT(z < MAP_LAYERS);
100+
101+ QTreeNode* leaf = root.getLeafForce(x, y);
102+ Floor* floor = leaf->createFloor(x, y, z);
103+ uint32_t offsetX = x & 3;
104+ uint32_t offsetY = y & 3;
105+
106+ return &floor->locs[offsetX * 4 + offsetY];
107+}
108+
109+TileLocation* BaseMap::createTileL(const Position& pos) {
110+ return createTileL(pos.x, pos.y, pos.z);
111+}
112+
113+void BaseMap::setTile(int x, int y, int z, Tile* newtile, bool remove) {
114+ ASSERT(!newtile || newtile->getX() == int(x));
115+ ASSERT(!newtile || newtile->getY() == int(y));
116+ ASSERT(!newtile || newtile->getZ() == int(z));
117+
118+ QTreeNode* leaf = root.getLeafForce(x, y);
119+ Tile* old = leaf->setTile(x, y, z, newtile);
120+ if (remove) {
121+ delete old;
122+ }
123+}
124+
125+Tile* BaseMap::swapTile(int x, int y, int z, Tile* newtile) {
126+ ASSERT(z < MAP_LAYERS);
127+ ASSERT(!newtile || newtile->getX() == int(x));
128+ ASSERT(!newtile || newtile->getY() == int(y));
129+ ASSERT(!newtile || newtile->getZ() == int(z));
130+
131+ QTreeNode* leaf = root.getLeafForce(x, y);
132+ return leaf->setTile(x, y, z, newtile);
133+}
134+
135+// Iterators
136+
137+MapIterator::MapIterator(BaseMap* _map) :
138+ local_i(0),
139+ local_z(0),
140+ current_tile(nullptr),
141+ map(_map) {
142+ ////
143+}
144+
145+MapIterator::~MapIterator() {
146+ ////
147+}
148+
149+MapIterator::MapIterator(const MapIterator& other) {
150+ for (std::vector<MapIterator::NodeIndex>::const_iterator it = other.nodestack.begin(); it != other.nodestack.end(); it++) {
151+ nodestack.push_back(MapIterator::NodeIndex(*it));
152+ }
153+ local_i = other.local_i;
154+ local_z = other.local_z;
155+ map = other.map;
156+ current_tile = other.current_tile;
157+}
158+
159+MapIterator BaseMap::begin() {
160+ MapIterator it(this);
161+ it.nodestack.push_back(MapIterator::NodeIndex(&root));
162+
163+ while (true) {
164+ MapIterator::NodeIndex& current = it.nodestack.back();
165+ QTreeNode* node = current.node;
166+ int& index = current.index;
167+ // printf("Contemplating %p of %p (stack size %d)\n", node, this, it.nodestack.size());
168+
169+ bool unwind = false;
170+ for (; index < MAP_LAYERS; ++index) {
171+ // printf("\tChecking index %d of %p\n", index, node);
172+ if (QTreeNode* child = node->child[index]) {
173+ if (child->isLeaf) {
174+ QTreeNode* leaf = child;
175+ // printf("\t%p is leaf\n", child);
176+ for (it.local_z = 0; it.local_z < MAP_LAYERS; ++it.local_z) {
177+ if (Floor* floor = leaf->array[it.local_z]) {
178+ for (it.local_i = 0; it.local_i < MAP_LAYERS; ++it.local_i) {
179+ // printf("\tit(%d;%d;%d)\n", it.local_x, it.local_y, it.local_z);
180+ TileLocation& t = floor->locs[it.local_i];
181+ if (t.get()) {
182+ // printf("return it\n");
183+ it.current_tile = &t;
184+ return it;
185+ }
186+ }
187+ }
188+ }
189+ } else {
190+ // printf("\tAdding %p\n", child);
191+ ++index;
192+ it.nodestack.push_back(MapIterator::NodeIndex(child));
193+ unwind = true;
194+ break;
195+ }
196+ }
197+ }
198+ if (unwind) {
199+ continue;
200+ }
201+
202+ // printf("Discarding dead node %p\n", node);
203+ it.nodestack.pop_back();
204+ if (it.nodestack.empty()) {
205+ break;
206+ }
207+ }
208+ return end();
209+}
210+
211+MapIterator BaseMap::end() {
212+ MapIterator it(this);
213+ it.local_i = -1;
214+ it.local_z = -1;
215+ return it;
216+}
217+
218+TileLocation* MapIterator::operator*() {
219+ return current_tile;
220+}
221+
222+TileLocation* MapIterator::operator->() {
223+ return current_tile;
224+}
225+
226+MapIterator& MapIterator::operator++() {
227+ // printf("MapIterator::operator++");
228+ bool increased = false;
229+ bool first = true;
230+ while (true) {
231+ MapIterator::NodeIndex& current = nodestack.back();
232+ QTreeNode* node = current.node;
233+ int& index = current.index;
234+ // printf("Contemplating %p (stack size %d)\n", node, nodestack.size());
235+
236+ bool unwind = false;
237+ for (; index < MAP_LAYERS; ++index) {
238+ // printf("\tChecking index %d of %p\n", index, node);
239+ if (QTreeNode* child = node->child[index]) {
240+ if (child->isLeaf) {
241+ QTreeNode* leaf = child;
242+ // printf("\t%p is leaf\n", child);
243+ for (; local_z < MAP_LAYERS; ++local_z) {
244+ // printf("\t\tIterating over Z:%d of %p", local_z, child);
245+ if (Floor* floor = leaf->array[local_z]) {
246+ // printf("\n");
247+ for (; local_i < MAP_LAYERS; ++local_i) {
248+ // printf("\t\tIterating over Y:%d of %p\n", local_y, child);
249+ TileLocation& t = floor->locs[local_i];
250+ if (t.get()) {
251+ if (increased) {
252+ // printf("Modified %p to %p\n", current_tile, t);
253+ current_tile = &t;
254+ return *this;
255+ } else {
256+ increased = true;
257+ }
258+ } else if (first) {
259+ increased = true;
260+ first = false;
261+ }
262+ }
263+
264+ if (local_i > MAP_MAX_LAYER) {
265+ // printf("\t\tReset local_x\n");
266+ local_i = 0;
267+ }
268+ } else {
269+ // printf(":dead floor\n");
270+ }
271+ }
272+ if (local_z == MAP_LAYERS) {
273+ // printf("\t\tReset local_z\n");
274+ local_z = 0;
275+ }
276+ } else {
277+ // printf("\tAdding %p\n", child);
278+ ++index;
279+ nodestack.push_back(MapIterator::NodeIndex(child));
280+ unwind = true;
281+ break;
282+ }
283+ }
284+ }
285+ if (unwind) {
286+ continue;
287+ }
288+
289+ // printf("Discarding dead node %p\n", node);
290+ nodestack.pop_back();
291+ if (nodestack.size() == 0) {
292+ // Set all values to "end"
293+ // printf("END\n");
294+ local_z = -1;
295+ local_i = -1;
296+ return *this;
297+ }
298+ }
299+ return *this;
300+}
301+
302+MapIterator MapIterator::operator++(int) {
303+ MapIterator i(*this);
304+ ++*this;
305+ return i;
306+}
A RD_Map_Editor/source/basemap.h +173-0 View file
@@ -0,0 +1,173 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_BASE_MAP_H_
19+#define RME_BASE_MAP_H_
20+
21+#include "main.h"
22+#include "position.h"
23+#include "filehandle.h"
24+#include "map_allocator.h"
25+#include "tile.h"
26+
27+// Class declarations
28+class QTreeNode;
29+class BaseMap;
30+class MapIterator;
31+class Floor;
32+class QTreeNode;
33+class TileLocation;
34+
35+class MapIterator {
36+public:
37+ MapIterator(BaseMap* _map = nullptr);
38+ ~MapIterator();
39+ MapIterator(const MapIterator& other);
40+
41+ TileLocation* operator*();
42+ TileLocation* operator->();
43+ MapIterator& operator++();
44+ MapIterator operator++(int);
45+ bool operator==(const MapIterator& other) const {
46+ if (other.local_z != local_z) {
47+ return false;
48+ }
49+ if (other.local_i != local_i) {
50+ return false;
51+ }
52+ if (other.nodestack == nodestack) {
53+ return true;
54+ }
55+ if (other.current_tile == current_tile) {
56+ return true;
57+ }
58+ return false;
59+ }
60+ bool operator!=(const MapIterator& other) const {
61+ return !(other == *this);
62+ }
63+
64+ struct NodeIndex {
65+ NodeIndex(QTreeNode* _node) :
66+ index(0), node(_node) { }
67+ NodeIndex(const NodeIndex& other) :
68+ index(other.index), node(other.node) { }
69+ int index;
70+ QTreeNode* node;
71+
72+ bool operator==(const NodeIndex& n) const {
73+ return n.node == node && n.index == index;
74+ }
75+ };
76+
77+private:
78+ std::vector<NodeIndex> nodestack;
79+ int local_i, local_z;
80+ TileLocation* current_tile;
81+ BaseMap* map;
82+
83+ friend class BaseMap;
84+};
85+
86+class BaseMap {
87+public:
88+ BaseMap();
89+ virtual ~BaseMap();
90+
91+ // This doesn't destroy the map structure, just clears it, if param is true, delete all tiles too.
92+ void clear(bool del = true);
93+ MapIterator begin();
94+ MapIterator end();
95+ uint64_t size() const {
96+ return tilecount;
97+ }
98+
99+ // these functions take a position and returns a tile on the map
100+ Tile* createTile(int x, int y, int z);
101+ Tile* getTile(int x, int y, int z);
102+ Tile* getTile(const Position& pos);
103+ Tile* getOrCreateTile(const Position& pos);
104+ const Tile* getTile(int x, int y, int z) const;
105+ const Tile* getTile(const Position& pos) const;
106+ TileLocation* getTileL(int x, int y, int z);
107+ TileLocation* getTileL(const Position& pos);
108+ TileLocation* createTileL(int x, int y, int z);
109+ TileLocation* createTileL(const Position& pos);
110+ const TileLocation* getTileL(int x, int y, int z) const;
111+ const TileLocation* getTileL(const Position& pos) const;
112+
113+ // Get a Quad Tree Leaf from the map
114+ QTreeNode* getLeaf(int x, int y) {
115+ return root.getLeaf(x, y);
116+ }
117+ QTreeNode* createLeaf(int x, int y) {
118+ return root.getLeafForce(x, y);
119+ }
120+
121+ // Assigns a tile, it might seem pointless to provide position, but it is not, as the passed tile may be nullptr
122+ void setTile(int _x, int _y, int _z, Tile* newtile, bool remove = false);
123+ void setTile(const Position& pos, Tile* newtile, bool remove = false) {
124+ setTile(pos.x, pos.y, pos.z, newtile, remove);
125+ }
126+ void setTile(Tile* newtile, bool remove = false) {
127+ setTile(newtile->getX(), newtile->getY(), newtile->getZ(), newtile, remove);
128+ }
129+ // Replaces a tile and returns the old one
130+ Tile* swapTile(int _x, int _y, int _z, Tile* newtile);
131+ Tile* swapTile(const Position& pos, Tile* newtile) {
132+ return swapTile(pos.x, pos.y, pos.z, newtile);
133+ }
134+
135+ // Clears the visiblity according to the mask passed
136+ void clearVisible(uint32_t mask);
137+
138+ uint64_t getTileCount() const {
139+ return tilecount;
140+ }
141+
142+public:
143+ MapAllocator allocator;
144+
145+protected:
146+ uint64_t tilecount;
147+
148+ QTreeNode root; // The Quad Tree root
149+
150+ friend class QTreeNode;
151+};
152+
153+inline Tile* BaseMap::getTile(int x, int y, int z) {
154+ TileLocation* l = getTileL(x, y, z);
155+ return l ? l->get() : nullptr;
156+}
157+
158+inline Tile* BaseMap::getTile(const Position& pos) {
159+ TileLocation* l = getTileL(pos);
160+ return l ? l->get() : nullptr;
161+}
162+
163+inline const Tile* BaseMap::getTile(int x, int y, int z) const {
164+ const TileLocation* l = getTileL(x, y, z);
165+ return l ? l->get() : nullptr;
166+}
167+
168+inline const Tile* BaseMap::getTile(const Position& pos) const {
169+ const TileLocation* l = getTileL(pos);
170+ return l ? l->get() : nullptr;
171+}
172+
173+#endif
A RD_Map_Editor/source/borderize_window.cpp +129-0 View file
@@ -0,0 +1,129 @@
1+#include "main.h"
2+#include "borderize_window.h"
3+#include <wx/gauge.h>
4+#include <wx/stattext.h>
5+#include <wx/button.h>
6+#include <wx/spinctrl.h>
7+#include "gui.h"
8+
9+BEGIN_EVENT_TABLE(BorderizeWindow, wxDialog)
10+ EVT_BUTTON(wxID_ANY, BorderizeWindow::OnClickNext)
11+
12+ EVT_SPINCTRL(wxID_ANY, BorderizeWindow::OnChunkSizeChange)
13+END_EVENT_TABLE()
14+
15+BorderizeWindow::BorderizeWindow(wxWindow* parent, Editor& editor) :
16+ wxDialog(parent, wxID_ANY, "Borderize Progress", wxDefaultPosition, wxDefaultSize),
17+ editor(editor),
18+ current_chunk(0),
19+ total_chunks(0),
20+ processing_whole_map(false)
21+{
22+ wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
23+
24+ // Add chunk size control
25+ wxBoxSizer* chunk_sizer = new wxBoxSizer(wxHORIZONTAL);
26+ chunk_sizer->Add(new wxStaticText(this, wxID_ANY, "Tiles per chunk:"), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
27+ chunk_size_spin = new wxSpinCtrl(this, wxID_ANY, "500", wxDefaultPosition, wxDefaultSize,
28+ wxSP_ARROW_KEYS, 100, 10000, 500);
29+ chunk_sizer->Add(chunk_size_spin, 0, wxALL, 5);
30+ sizer->Add(chunk_sizer);
31+
32+ status_text = new wxStaticText(this, wxID_ANY, "Preparing to borderize...");
33+ sizer->Add(status_text, 0, wxALL, 5);
34+
35+ progress = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(300, 20));
36+ sizer->Add(progress, 0, wxEXPAND | wxALL, 5);
37+
38+ wxBoxSizer* button_sizer = new wxBoxSizer(wxHORIZONTAL);
39+ next_button = new wxButton(this, wxID_ANY, "Process Next Chunk");
40+
41+
42+ button_sizer->Add(next_button, 1, wxALL, 5);
43+ button_sizer->Add(cancel_button, 1, wxALL, 5);
44+ sizer->Add(button_sizer, 0, wxEXPAND | wxALL, 5);
45+
46+ SetSizer(sizer);
47+ Fit();
48+ Centre();
49+
50+ Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) {
51+ // Clear remaining tiles and close without processing
52+ remaining_tiles.clear();
53+ EndModal(0);
54+ });
55+}
56+
57+BorderizeWindow::~BorderizeWindow() {}
58+
59+void BorderizeWindow::Start() {
60+ // Initialize the tile list based on whether we're processing selection or whole map
61+ if (editor.selection.size() > 0) {
62+ processing_whole_map = false;
63+ for (Tile* tile : editor.selection) {
64+ remaining_tiles.push_back(tile);
65+ }
66+ } else {
67+ processing_whole_map = true;
68+ for (TileLocation* tileLocation : editor.map) {
69+ if (Tile* tile = tileLocation->get()) {
70+ remaining_tiles.push_back(tile);
71+ }
72+ }
73+ }
74+
75+ total_chunks = (remaining_tiles.size() + 499) / 500; // Process 500 tiles per chunk
76+ UpdateProgress(0, total_chunks);
77+ ShowModal();
78+}
79+
80+void BorderizeWindow::UpdateProgress(int current, int total) {
81+ progress->SetValue((current * 100) / total);
82+ status_text->SetLabel(wxString::Format("Processing chunk %d of %d (%d tiles remaining)",
83+ current + 1, total, (int)remaining_tiles.size()));
84+}
85+
86+void BorderizeWindow::OnChunkSizeChange(wxSpinEvent& event) {
87+ // Recalculate total chunks based on new chunk size
88+ if (!remaining_tiles.empty()) {
89+ total_chunks = (remaining_tiles.size() + chunk_size_spin->GetValue() - 1) / chunk_size_spin->GetValue();
90+ UpdateProgress(current_chunk, total_chunks);
91+ }
92+}
93+
94+void BorderizeWindow::OnClickNext(wxCommandEvent& WXUNUSED(event)) {
95+ if (remaining_tiles.empty()) {
96+ EndModal(1);
97+ return;
98+ }
99+
100+ // Process next chunk of tiles using the user-defined chunk size
101+ Action* action = editor.actionQueue->createAction(ACTION_BORDERIZE);
102+
103+ size_t chunk_size = chunk_size_spin->GetValue();
104+ size_t tiles_to_process = std::min<size_t>(chunk_size, remaining_tiles.size());
105+
106+ for (size_t i = 0; i < tiles_to_process; ++i) {
107+ Tile* tile = remaining_tiles.front();
108+ remaining_tiles.pop_front();
109+
110+ Tile* newTile = tile->deepCopy(editor.map);
111+ newTile->borderize(&editor.map);
112+ if (!processing_whole_map) {
113+ newTile->select();
114+ }
115+ action->addChange(newd Change(newTile));
116+ }
117+
118+ editor.addAction(action);
119+ current_chunk++;
120+ UpdateProgress(current_chunk, total_chunks);
121+
122+ if (remaining_tiles.empty()) {
123+ next_button->SetLabel("Finish");
124+ }
125+
126+ editor.map.doChange();
127+ // Refresh the view after each chunk
128+ g_gui.RefreshView();
129+}
A RD_Map_Editor/source/borderize_window.h +39-0 View file
@@ -0,0 +1,39 @@
1+#ifndef RME_BORDERIZE_WINDOW_H
2+#define RME_BORDERIZE_WINDOW_H
3+
4+#include <wx/dialog.h>
5+#include "editor.h"
6+
7+class wxGauge;
8+class wxStaticText;
9+class wxSpinCtrl;
10+
11+class BorderizeWindow : public wxDialog {
12+public:
13+ BorderizeWindow(wxWindow* parent, Editor& editor);
14+ ~BorderizeWindow();
15+
16+ void Start();
17+ void UpdateProgress(int current, int total);
18+
19+private:
20+ void OnClickNext(wxCommandEvent& event);
21+ void OnClickCancel(wxCommandEvent& event);
22+ void OnChunkSizeChange(wxSpinEvent& event);
23+
24+ Editor& editor;
25+ wxGauge* progress;
26+ wxStaticText* status_text;
27+ wxButton* next_button;
28+ wxButton* cancel_button;
29+ wxSpinCtrl* chunk_size_spin;
30+
31+ size_t current_chunk;
32+ size_t total_chunks;
33+ bool processing_whole_map;
34+ TileList remaining_tiles;
35+
36+ DECLARE_EVENT_TABLE()
37+};
38+
39+#endif
Top