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 "map_window.h"
21#include "gui.h"
22#include "sprites.h"
23#include "editor.h"
24
25MapWindow::MapWindow(wxWindow* parent, Editor& editor) :
26 wxPanel(parent, PANE_MAIN),
27 editor(editor),
28 replaceItemsDialog(nullptr),
29 islandGeneratorDialog(nullptr) {
30 int GL_settings[3];
31 GL_settings[0] = WX_GL_RGBA;
32 GL_settings[1] = WX_GL_DOUBLEBUFFER;
33 GL_settings[2] = 0;
34 canvas = newd MapCanvas(this, editor, GL_settings);
35
36 vScroll = newd MapScrollBar(this, MAP_WINDOW_VSCROLL, wxVERTICAL, canvas);
37 hScroll = newd MapScrollBar(this, MAP_WINDOW_HSCROLL, wxHORIZONTAL, canvas);
38
39 gem = newd DCButton(this, MAP_WINDOW_GEM, wxDefaultPosition, DC_BTN_NORMAL, RENDER_SIZE_16x16, EDITOR_SPRITE_SELECTION_GEM);
40
41 wxFlexGridSizer* topsizer = newd wxFlexGridSizer(2, 0, 0);
42
43 topsizer->AddGrowableCol(0);
44 topsizer->AddGrowableRow(0);
45
46 topsizer->Add(canvas, wxSizerFlags(1).Expand());
47 topsizer->Add(vScroll, wxSizerFlags(1).Expand());
48 topsizer->Add(hScroll, wxSizerFlags(1).Expand());
49 topsizer->Add(gem, wxSizerFlags(1));
50
51 SetSizerAndFit(topsizer);
52}
53
54MapWindow::~MapWindow() {
55 ////
56}
57
58void MapWindow::ShowReplaceItemsDialog(bool selectionOnly) {
59 if (replaceItemsDialog) {
60 return;
61 }
62
63 replaceItemsDialog = new ReplaceItemsDialog(this, selectionOnly);
64 replaceItemsDialog->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MapWindow::OnReplaceItemsDialogClose), NULL, this);
65 replaceItemsDialog->Show();
66}
67
68void MapWindow::CloseReplaceItemsDialog() {
69 if (replaceItemsDialog) {
70 replaceItemsDialog->Close();
71 }
72}
73
74void MapWindow::OnReplaceItemsDialogClose(wxCloseEvent& event) {
75 if (replaceItemsDialog) {
76 replaceItemsDialog->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MapWindow::OnReplaceItemsDialogClose), NULL, this);
77 replaceItemsDialog->Destroy();
78 replaceItemsDialog = nullptr;
79 }
80}
81
82void MapWindow::ShowIslandGeneratorDialog() {
83 if (islandGeneratorDialog) {
84 return;
85 }
86
87 islandGeneratorDialog = new IslandGeneratorDialog(this);
88 islandGeneratorDialog->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MapWindow::OnIslandGeneratorDialogClose), NULL, this);
89 islandGeneratorDialog->Show();
90}
91
92void MapWindow::CloseIslandGeneratorDialog() {
93 if (islandGeneratorDialog) {
94 islandGeneratorDialog->Close();
95 }
96}
97
98void MapWindow::OnIslandGeneratorDialogClose(wxCloseEvent& event) {
99 if (islandGeneratorDialog) {
100 islandGeneratorDialog->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MapWindow::OnIslandGeneratorDialogClose), NULL, this);
101 islandGeneratorDialog->Destroy();
102 islandGeneratorDialog = nullptr;
103 }
104}
105
106void MapWindow::ShowGroundValidationDialog() {
107 if (groundValidationDialog) {
108 return;
109 }
110
111 groundValidationDialog = new GroundValidationDialog(this);
112 if (groundValidationDialog->ShowModal() == wxID_OK) {
113 // Get validation options
114 bool validateStack = groundValidationDialog->shouldValidateGroundStack();
115 bool generateEmpty = groundValidationDialog->shouldGenerateEmptySurroundedGrounds();
116 bool removeDuplicates = groundValidationDialog->shouldRemoveDuplicateGrounds();
117
118 // Perform validation
119 uint32_t changes = editor.validateGrounds(validateStack, generateEmpty, removeDuplicates);
120
121 // Show results
122 wxString message;
123 message << changes << " ground tiles have been modified.";
124 g_gui.PopupDialog("Ground Validation", message, wxOK);
125
126 // Refresh view
127 g_gui.RefreshView();
128 }
129
130 groundValidationDialog->Destroy();
131 groundValidationDialog = nullptr;
132}
133
134void MapWindow::SetSize(int x, int y, bool center) {
135 if (x == 0 || y == 0) {
136 return;
137 }
138
139 int windowSizeX;
140 int windowSizeY;
141
142 canvas->GetSize(&windowSizeX, &windowSizeY);
143
144 hScroll->SetScrollbar(center ? (x - windowSizeX) / 2 : hScroll->GetThumbPosition(), windowSizeX / x, x, windowSizeX / x);
145 vScroll->SetScrollbar(center ? (y - windowSizeY) / 2 : vScroll->GetThumbPosition(), windowSizeY / y, y, windowSizeX / y);
146 // wxPanel::SetSize(x, y);
147}
148
149void MapWindow::UpdateScrollbars(int nx, int ny) {
150 // nx and ny are size of this window
151 hScroll->SetScrollbar(hScroll->GetThumbPosition(), nx / max(1, hScroll->GetRange()), max(1, hScroll->GetRange()), 96);
152 vScroll->SetScrollbar(vScroll->GetThumbPosition(), ny / max(1, vScroll->GetRange()), max(1, vScroll->GetRange()), 96);
153}
154
155void MapWindow::UpdateDialogs(bool show) {
156 if (replaceItemsDialog) {
157 replaceItemsDialog->Show(show);
158 }
159 if (islandGeneratorDialog) {
160 islandGeneratorDialog->Show(show);
161 }
162}
163
164void MapWindow::GetViewStart(int* x, int* y) {
165 *x = hScroll->GetThumbPosition();
166 *y = vScroll->GetThumbPosition();
167}
168
169void MapWindow::GetViewSize(int* x, int* y) {
170 canvas->GetSize(x, y);
171 *x *= canvas->GetContentScaleFactor();
172 *y *= canvas->GetContentScaleFactor();
173}
174
175void MapWindow::FitToMap() {
176 SetSize(editor.map.getWidth() * TileSize, editor.map.getHeight() * TileSize, true);
177}
178
179Position MapWindow::GetScreenCenterPosition() const {
180 int x, y;
181 canvas->GetScreenCenter(&x, &y);
182 return Position(x, y, canvas->GetFloor());
183}
184
185void MapWindow::SetScreenCenterPosition(const Position& position) {
186 if (position == Position()) {
187 return;
188 }
189
190 int x = position.x * TileSize;
191 int y = position.y * TileSize;
192 if (position.z <= GROUND_LAYER) {
193 // Compensate for floor offset above ground
194 x -= (GROUND_LAYER - position.z) * TileSize;
195 y -= (GROUND_LAYER - position.z) * TileSize;
196 }
197
198 const Position& center = GetScreenCenterPosition();
199 if (previous_position != center) {
200 previous_position.x = center.x;
201 previous_position.y = center.y;
202 previous_position.z = center.z;
203 }
204
205 Scroll(x, y, true);
206 canvas->ChangeFloor(position.z);
207}
208
209void MapWindow::GoToPreviousCenterPosition() {
210 SetScreenCenterPosition(previous_position);
211}
212
213void MapWindow::Scroll(int x, int y, bool center) {
214 if (center) {
215 int windowSizeX, windowSizeY;
216
217 canvas->GetSize(&windowSizeX, &windowSizeY);
218 x -= int((windowSizeX * g_gui.GetCurrentZoom()) / 2.0);
219 y -= int((windowSizeY * g_gui.GetCurrentZoom()) / 2.0);
220 }
221
222 hScroll->SetThumbPosition(x);
223 vScroll->SetThumbPosition(y);
224 g_gui.UpdateMinimap();
225}
226
227void MapWindow::ScrollRelative(int x, int y) {
228 hScroll->SetThumbPosition(hScroll->GetThumbPosition() + x);
229 vScroll->SetThumbPosition(vScroll->GetThumbPosition() + y);
230 g_gui.UpdateMinimap();
231}
232
233void MapWindow::OnGem(wxCommandEvent& WXUNUSED(event)) {
234 g_gui.SwitchMode();
235}
236
237void MapWindow::OnSize(wxSizeEvent& event) {
238 UpdateScrollbars(event.GetSize().GetWidth(), event.GetSize().GetHeight());
239 event.Skip();
240}
241
242void MapWindow::OnScroll(wxScrollEvent& event) {
243 Refresh();
244}
245
246void MapWindow::OnScrollLineDown(wxScrollEvent& event) {
247 if (event.GetOrientation() == wxHORIZONTAL) {
248 ScrollRelative(96, 0);
249 } else {
250 ScrollRelative(0, 96);
251 }
252 Refresh();
253}
254
255void MapWindow::OnScrollLineUp(wxScrollEvent& event) {
256 if (event.GetOrientation() == wxHORIZONTAL) {
257 ScrollRelative(-96, 0);
258 } else {
259 ScrollRelative(0, -96);
260 }
261 Refresh();
262}
263
264void MapWindow::OnScrollPageDown(wxScrollEvent& event) {
265 if (event.GetOrientation() == wxHORIZONTAL) {
266 ScrollRelative(5 * 96, 0);
267 } else {
268 ScrollRelative(0, 5 * 96);
269 }
270 Refresh();
271}
272
273void MapWindow::OnScrollPageUp(wxScrollEvent& event) {
274 if (event.GetOrientation() == wxHORIZONTAL) {
275 ScrollRelative(-5 * 96, 0);
276 } else {
277 ScrollRelative(0, -5 * 96);
278 }
279 Refresh();
280}
281