1 // ==============================================================
2 //	This file is part of Glest (www.glest.org)
3 //
4 //	Copyright (C) 2001-2008 Martiño Figueroa
5 //
6 //	You can redistribute this code and/or modify it under
7 //	the terms of the GNU General Public License as published
8 //	by the Free Software Foundation; either version 2 of the
9 //	License, or (at your option) any later version
10 // ==============================================================
11 
12 #include "main.h"
13 #include <ctime>
14 #include "conversion.h"
15 #include "icons.h"
16 #include "platform_common.h"
17 #include "config.h"
18 #include <iostream>
19 #include"platform_util.h"
20 #include <wx/stdpaths.h>
21 #ifndef WIN32
22 #include <errno.h>
23 #endif
24 #include "common_scoped_ptr.h"
25 //#include <memory>
26 
27 using namespace Shared::Util;
28 using namespace Shared::PlatformCommon;
29 using namespace Glest::Game;
30 using namespace std;
31 
32 namespace Glest { namespace Game {
getGameReadWritePath(string lookupKey)33 string getGameReadWritePath(string lookupKey) {
34 	string path = "";
35     if(path == "" && getenv("GLESTHOME") != NULL) {
36         path = getenv("GLESTHOME");
37         if(path != "" && EndsWith(path, "/") == false && EndsWith(path, "\\") == false) {
38             path += "/";
39         }
40 
41         //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] path to be used for read/write files [%s]\n",__FILE__,__FUNCTION__,__LINE__,path.c_str());
42     }
43 
44     return path;
45 }
46 }}
47 
48 namespace MapEditor {
49 
50 const string mapeditorVersionString = "v3.13.0";
51 const string MainWindow::winHeader = "MegaGlest Map Editor " + mapeditorVersionString;
52 
53 // ===============================================
54 //	class Global functions
55 // ===============================================
56 
ToUnicode(const char * str)57 wxString ToUnicode(const char* str) {
58 	return wxString(str, wxConvUTF8);
59 }
60 
ToUnicode(const string & str)61 wxString ToUnicode(const string& str) {
62 	return wxString(str.c_str(), wxConvUTF8);
63 }
64 
65 // ===============================================
66 // class MainWindow
67 // ===============================================
68 
MainWindow(string appPath)69 MainWindow::MainWindow(string appPath)
70 		: wxFrame(NULL, -1,  ToUnicode(winHeader), wxPoint(0,0), wxSize(1024, 768))
71 		, glCanvas(NULL)
72 		, program(NULL)
73 		, lastX(0)
74 		, lastY(0)
75 		, panel(NULL)
76 		, menuBar(NULL)
77 		, fileDialog(NULL)
78 
79 		, currentBrush(btHeight)
80 		, height(0)
81 		, surface(1)
82 		, radius(1)
83 		, object(0)
84 		, resource(0)
85 		, startLocation(1)
86 		, enabledGroup(ctHeight)
87 		, fileModified(false)
88         , boxsizer(NULL)
89         ,startupSettingsInited(false) {
90 
91 	menuFile=NULL;
92 	menuEdit=NULL;
93 	menuEditMirror=NULL;
94 	menuView=NULL;
95 	menuBrush=NULL;
96 	menuBrushHeight=NULL;
97 	menuBrushGradient=NULL;
98 	menuBrushSurface=NULL;
99 	menuBrushObject=NULL;
100 	menuBrushResource=NULL;
101 	menuBrushStartLocation=NULL;
102 	menuRadius=NULL;
103 	fileDialog=NULL;
104 	resourceUnderMouse=0;
105 	objectUnderMouse=0;
106 
107 	// default values for random height calculation that turned out to be quite useful
108 	randomWithReset=true;
109 	randomMinimumHeight=-300;
110 	randomMaximumHeight=400;
111 	randomChanceDivider=30;
112 	randomRecursions=3;
113 
114 	this->appPath = appPath;
115 	Properties::setApplicationPath(executable_path(appPath));
116 
117 	this->panel = new wxPanel(this, wxID_ANY);
118 }
119 
onToolPlayer(wxCommandEvent & event)120 void MainWindow::onToolPlayer(wxCommandEvent& event){
121 	PopupMenu(menuBrushStartLocation);
122 }
123 
onMouseMove(wxMouseEvent & event)124 void MainToolBar::onMouseMove(wxMouseEvent &event) {
125 #ifdef WIN32
126 	if(this->GetParent() != NULL && this->GetParent()->GetParent() != NULL) {
127 		MainWindow *mainWindow = dynamic_cast<MainWindow *>(this->GetParent()->GetParent());
128 		if(mainWindow != NULL) {
129 			mainWindow->refreshMapRender();
130 		}
131 	}
132 #endif
133 	event.Skip();
134 }
135 
BEGIN_EVENT_TABLE(MainToolBar,wxToolBar)136 BEGIN_EVENT_TABLE(MainToolBar, wxToolBar)
137 
138 	EVT_MOTION(MainToolBar::onMouseMove)
139 
140 END_EVENT_TABLE()
141 
142 void MainWindow::init(string fname) {
143 
144 	//menus
145 	menuBar = new wxMenuBar();
146 
147 	//file
148 	menuFile = new wxMenu();
149 	menuFile->Append(wxID_NEW);
150 	menuFile->Append(wxID_OPEN);
151 	menuFile->AppendSeparator();
152 	menuFile->Append(wxID_SAVE);
153 	menuFile->Append(wxID_SAVEAS);
154 	menuFile->AppendSeparator();
155 	menuFile->Append(wxID_EXIT);
156 	menuBar->Append(menuFile, wxT("&File"));
157 
158 	//edit
159 	menuEdit = new wxMenu();
160 	menuEdit->Append(miEditUndo, wxT("&Undo\tCTRL+Z"));
161 	menuEdit->Append(miEditRedo, wxT("&Redo\tCTRL+Y"));
162 	menuEdit->AppendSeparator();
163 //	menuEdit->Append(miEditReset, wxT("Rese&t..."));
164 	menuEdit->Append(miEditResetPlayers, wxT("Reset &Players..."));
165 	menuEdit->Append(miEditResize, wxT("Re&size..."));
166 	menuEdit->Append(miEditFlipDiagonal, wxT("Flip &Diagonal"));
167 	menuEdit->Append(miEditFlipX, wxT("Flip &X"));
168 	menuEdit->Append(miEditFlipY, wxT("Flip &Y"));
169 
170     // Mirror submenu-------------------------------------------
171 	menuEditMirror = new wxMenu();
172 	menuEditMirror->Append(miEditMirrorX, wxT("Copy &Left to Right"));
173 	menuEditMirror->Append(miEditMirrorY, wxT("Copy &Top to Bottom"));
174 	menuEditMirror->Append(miEditMirrorXY, wxT("Copy &BottomLeft to TopRight"));
175 	menuEditMirror->AppendSeparator();
176 	menuEditMirror->Append(miEditRotatecopyX, wxT("&Rotate Left to Right"));
177 	menuEditMirror->Append(miEditRotatecopyY, wxT("Rotate T&op to Bottom"));
178 	menuEditMirror->Append(miEditRotatecopyXY, wxT("Rotate Botto&mLeft to TopRight"));
179 	menuEditMirror->Append(miEditRotatecopyCorner, wxT("Rotate TopLeft &corner to TopRight"));
180     menuEdit->Append(miEditMirror, wxT("&Mirror"), menuEditMirror);
181     // ---------------------------------------------------------
182 
183 	menuEdit->Append(miEditRandomizeHeights, wxT("Randomize &Heights"));
184 	menuEdit->Append(miEditRandomize, wxT("Randomi&ze Players"));
185 	menuEdit->Append(miEditSwitchSurfaces, wxT("Switch Sur&faces..."));
186 	menuEdit->Append(miEditInfo, wxT("&Info..."));
187 	menuEdit->Append(miEditAdvanced, wxT("&Advanced..."));
188 	menuBar->Append(menuEdit, wxT("&Edit"));
189 
190 	//view
191 	menuView = new wxMenu();
192 	menuView->Append(miViewResetZoomAndPos, wxT("&Reset zoom and pos"));
193     menuView->AppendCheckItem(miViewGrid, wxT("&Grid"));
194 	menuView->AppendCheckItem(miViewHeightMap, wxT("H&eightMap"));
195 	menuView->AppendCheckItem(miHideWater, wxT("Hide&Water"));
196 	menuView->AppendSeparator();
197 	menuView->Append(miViewHelp, wxT("&Help..."));
198 	menuView->Append(miViewAbout, wxT("&About..."));
199 	menuBar->Append(menuView, wxT("&View"));
200 
201 	//brush
202 	// menuBrush = new wxMenu();
203 
204 	//surface
205 	menuBrushSurface = new wxMenu();
206 	menuBrushSurface->AppendCheckItem(miBrushSurface + 1, wxT("&Grass"));
207 	menuBrushSurface->AppendCheckItem(miBrushSurface + 2, wxT("S&econdary grass"));
208 	menuBrushSurface->AppendCheckItem(miBrushSurface + 3, wxT("&Road"));
209 	menuBrushSurface->AppendCheckItem(miBrushSurface + 4, wxT("&Stone"));
210 	menuBrushSurface->AppendCheckItem(miBrushSurface + 5, wxT("Gr&ound"));
211 	menuBar->Append(menuBrushSurface, wxT("&Surface"));
212 
213 	//resources
214 	menuBrushResource = new wxMenu();
215 	//menuBrushResource->AppendCheckItem(miBrushResource + 1, wxT("&0 - None"));
216 	menuBrushResource->AppendCheckItem(miBrushResource+2, wxT("&Gold  (unwalkable)"));
217 	menuBrushResource->AppendCheckItem(miBrushResource+3, wxT("&Stone (unwalkable)"));
218 	menuBrushResource->AppendCheckItem(miBrushResource+4, wxT("&3 - custom"));
219 	menuBrushResource->AppendCheckItem(miBrushResource+5, wxT("&4 - custom"));
220 	menuBrushResource->AppendCheckItem(miBrushResource+6, wxT("&5 - custom"));
221 	menuBar->Append(menuBrushResource, wxT("&Resource"));
222 
223 	//objects
224 	menuBrushObject = new wxMenu();
225 	menuBrushObject->AppendCheckItem(miBrushObject+1, wxT("&None (erase)\tALT+0"));
226 	menuBrushObject->AppendSeparator();
227 	menuBrushObject->AppendCheckItem(miBrushObject+2, wxT("&Tree (harvestable)"));
228 	menuBrushObject->AppendCheckItem(miBrushObject+3, wxT("&Dead tree/Cactuses/Thornbush"));
229 	menuBrushObject->AppendCheckItem(miBrushObject+4, wxT("&Stone"));
230 	menuBrushObject->AppendCheckItem(miBrushObject+5, wxT("&Bush/Grass/Fern (walkable)"));
231 	menuBrushObject->AppendCheckItem(miBrushObject+6, wxT("&Water object/Reed/Papyrus (walkable)"));
232 	menuBrushObject->AppendCheckItem(miBrushObject+7, wxT("Big tree/&Old palm"));
233 	menuBrushObject->AppendCheckItem(miBrushObject+8, wxT("&Hanged/Impaled "));
234 	menuBrushObject->AppendCheckItem(miBrushObject+9, wxT("St&atues"));
235 	menuBrushObject->AppendCheckItem(miBrushObject+10, wxT("&Mountain"));
236 	menuBrushObject->AppendCheckItem(miBrushObject+11, wxT("&Invisible blocking object"));
237 	menuBar->Append(menuBrushObject, wxT("&Object"));
238 
239 	// ZombiePirate height brush
240 	menuBrushGradient = new wxMenu();
241 	for (int i = 0; i < heightCount; ++i) {
242 		menuBrushGradient->AppendCheckItem(miBrushGradient + i + 1, ToUnicode((i>4?"&":"") +intToStr(i - heightCount / 2)));
243 	}
244 	menuBar->Append(menuBrushGradient, wxT("&Gradient"));
245 
246 	// Glest height brush
247 	menuBrushHeight = new wxMenu();
248 	for (int i = 0; i < heightCount; ++i) {
249 		menuBrushHeight->AppendCheckItem(miBrushHeight + i + 1, ToUnicode((i>4?"&":"") +intToStr(i - heightCount / 2)));
250 	}
251 	menuBrushHeight->Check(miBrushHeight + (heightCount + 1) / 2, true);
252 	menuBar->Append(menuBrushHeight, wxT("&Height"));
253 
254 	enabledGroup = ctHeight;
255 
256 	//radius
257 	menuRadius = new wxMenu();
258 	for (int i = 1; i <= radiusCount; ++i) {
259 		menuRadius->AppendCheckItem(miRadius + i, ToUnicode("&" + intToStr(i) + " (diameter "+intToStr(i*2-1)+ ")"+ "\tALT+" + intToStr(i)));
260 	}
261 	menuRadius->Check(miRadius + 1, true);
262 	menuBar->Append(menuRadius, wxT("R&adius"));
263 
264 	//players
265 	menuBrushStartLocation = new wxMenu();
266 	wxMenuItem *pmi1 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 1, wxT("Player &1 Red"));
267 	pmi1->SetBitmap(wxBitmap(brush_players_red));
268 	menuBrushStartLocation->Append(pmi1);
269 	wxMenuItem *pmi2 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 2, wxT("Player &2 Blue"));
270 	pmi2->SetBitmap(wxBitmap(brush_players_blue));
271 	menuBrushStartLocation->Append(pmi2);
272 	wxMenuItem *pmi3 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 3, wxT("Player &3 Green"));
273 	pmi3->SetBitmap(wxBitmap(brush_players_green));
274 	menuBrushStartLocation->Append(pmi3);
275 	wxMenuItem *pmi4 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 4, wxT("Player &4 Yellow"));
276 	pmi4->SetBitmap(wxBitmap(brush_players_yellow));
277 	menuBrushStartLocation->Append(pmi4);
278 	wxMenuItem *pmi5 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 5, wxT("Player &5 White"));
279 	pmi5->SetBitmap(wxBitmap(brush_players_white));
280 	menuBrushStartLocation->Append(pmi5);
281 	wxMenuItem *pmi6 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 6, wxT("Player &6 Cyan"));
282 	pmi6->SetBitmap(wxBitmap(brush_players_cyan));
283 	menuBrushStartLocation->Append(pmi6);
284 	wxMenuItem *pmi7 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 7, wxT("Player &7 Orange"));
285 	pmi7->SetBitmap(wxBitmap(brush_players_orange));
286 	menuBrushStartLocation->Append(pmi7);
287 	wxMenuItem *pmi8 = new wxMenuItem(menuBrushStartLocation, miBrushStartLocation + 8, wxT("Player &8 Pink")); // = Light Magenta :-)
288 	pmi8->SetBitmap(wxBitmap(brush_players_pink));
289 	menuBrushStartLocation->Append(pmi8);
290 	menuBar->Append(menuBrushStartLocation, wxT("&Player"));
291 	//menuBar->Append(menuBrush, wxT("&Brush"));
292 
293 
294 	SetMenuBar(menuBar);
295 
296 	fileName = "New (unsaved) map";
297 	int status_widths[siCOUNT] = {
298 		10, // empty
299 		-25, // File name
300 		-6, // File type
301 		-20, // Current Object
302 		-14, // Brush Type
303 		-20, // Brush 'Value'
304 		-10, // Brush Radius
305 		-25, // Position
306 	};
307 	CreateStatusBar(siCOUNT);
308 	GetStatusBar()->SetStatusWidths(siCOUNT, status_widths);
309 
310 	SetStatusText(wxT("File: ") + ToUnicode(fileName), siFILE_NAME);
311 	SetStatusText(wxT(".mgm"), siFILE_TYPE);
312 	SetStatusText(wxT("Object: None (Erase)"), siCURR_OBJECT);
313 	SetStatusText(wxT("Brush: Height"), siBRUSH_TYPE);
314 	SetStatusText(wxT("Value: 0"), siBRUSH_VALUE);
315 	SetStatusText(wxT("Radius: 1"), siBRUSH_RADIUS);
316 	SetStatusText(wxT("Pos (Ingame): 0"), siPOS_VALUE);
317 
318 	wxToolBar *toolbar = new MainToolBar(this->panel, wxID_ANY);
319 	toolbar->AddTool(miEditUndo, _("undo"), wxBitmap(edit_undo), _("Undo"));
320 	toolbar->AddTool(miEditRedo, _("redo"), wxBitmap(edit_redo), _("Redo"));
321 	toolbar->AddTool(miEditRandomizeHeights, _("randomizeHeights"), wxBitmap(edit_randomize_heights), _("Randomize Heights"));
322 //	toolbar->AddTool(miEditRandomize, _("randomize"), wxBitmap(edit_randomize), _("Randomize"));
323 	toolbar->AddTool(miEditSwitchSurfaces, _("switch"), wxBitmap(edit_switch_surfaces), _("Switch Surfaces"));
324 	toolbar->AddSeparator();
325 	toolbar->AddTool(miBrushSurface + 1, _("brush_grass1"), wxBitmap(brush_surface_grass1), _("Grass"));
326 	toolbar->AddTool(miBrushSurface + 2, _("brush_grass2"), wxBitmap(brush_surface_grass2), _("Secondary grass"));
327 	toolbar->AddTool(miBrushSurface + 3, _("brush_road"), wxBitmap(brush_surface_road), _("Road"));
328 	toolbar->AddTool(miBrushSurface + 4, _("brush_stone"), wxBitmap(brush_surface_stone), _("Stone"));
329 	toolbar->AddTool(miBrushSurface + 5, _("brush_custom"), wxBitmap(brush_surface_custom), _("Ground"));
330 	toolbar->AddSeparator();
331 	toolbar->AddTool(miBrushResource + 2, _("resource1"), wxBitmap(brush_resource_1_gold), _("gold  (unwalkable)"));
332 	toolbar->AddTool(miBrushResource + 3, _("resource2"), wxBitmap(brush_resource_2_stone), _("stone (unwalkable)"));
333 	toolbar->AddTool(miBrushResource + 4, _("resource3"), wxBitmap(brush_resource_3), _("custom3"));
334 	toolbar->AddTool(miBrushResource + 5, _("resource4"), wxBitmap(brush_resource_4), _("custom4"));
335 	toolbar->AddTool(miBrushResource + 6, _("resource5"), wxBitmap(brush_resource_5), _("custom5"));
336 	toolbar->AddSeparator();
337 	toolbar->AddTool(miBrushObject + 1, _("brush_none"), wxBitmap(brush_none), _("None (erase)"));
338 	toolbar->AddTool(miBrushObject + 2, _("brush_tree"), wxBitmap(brush_object_tree), _("Tree (unwalkable/harvestable)"));
339 	toolbar->AddTool(miBrushObject + 3, _("brush_dead_tree"), wxBitmap(brush_object_dead_tree), _("Dead tree/Cactuses/Thornbush (unwalkable)"));
340 	toolbar->AddTool(miBrushObject + 4, _("brush_stone"), wxBitmap(brush_object_stone), _("Stone (unwalkable/not harvestable)"));
341 	toolbar->AddTool(miBrushObject + 5, _("brush_bush"), wxBitmap(brush_object_bush), _("Bush/Grass/Fern (walkable)"));
342 	toolbar->AddTool(miBrushObject + 6, _("brush_water"), wxBitmap(brush_object_water_object), _("Water object/Reed/Papyrus (walkable)"));
343 	toolbar->AddTool(miBrushObject + 7, _("brush_c1_bigtree"), wxBitmap(brush_object_c1_bigtree), _("Big tree/Old palm (unwalkable/not harvestable)"));
344 	toolbar->AddTool(miBrushObject + 8, _("brush_c2_hanged"), wxBitmap(brush_object_c2_hanged), _("Hanged/Impaled (unwalkable)"));
345 	toolbar->AddTool(miBrushObject + 9, _("brush_c3_statue"), wxBitmap(brush_object_c3_statue), _("Statues (unwalkable)"));
346 	toolbar->AddTool(miBrushObject +10, _("brush_c4_bigrock"), wxBitmap(brush_object_c4_bigrock), _("Mountain (unwalkable)"));
347 	toolbar->AddTool(miBrushObject +11, _("brush_c5_blocking"), wxBitmap(brush_object_c5_blocking), _("Invisible blocking object (unwalkable)"));
348 	toolbar->AddSeparator();
349 	toolbar->AddTool(toolPlayer, _("brush_player"), wxBitmap(brush_players_player),  _("Player start position"));
350 	toolbar->Realize();
351 
352 	wxToolBar *toolbar2 = new MainToolBar(this->panel, wxID_ANY);
353 	toolbar2->AddTool(miBrushGradient + 1, _("brush_gradient_n5"), wxBitmap(brush_gradient_n5));
354 	toolbar2->AddTool(miBrushGradient + 2, _("brush_gradient_n4"), wxBitmap(brush_gradient_n4));
355 	toolbar2->AddTool(miBrushGradient + 3, _("brush_gradient_n3"), wxBitmap(brush_gradient_n3));
356 	toolbar2->AddTool(miBrushGradient + 4, _("brush_gradient_n2"), wxBitmap(brush_gradient_n2));
357 	toolbar2->AddTool(miBrushGradient + 5, _("brush_gradient_n1"), wxBitmap(brush_gradient_n1));
358 	toolbar2->AddTool(miBrushGradient + 6, _("brush_gradient_0"), wxBitmap(brush_gradient_0));
359 	toolbar2->AddTool(miBrushGradient + 7, _("brush_gradient_p1"), wxBitmap(brush_gradient_p1));
360 	toolbar2->AddTool(miBrushGradient + 8, _("brush_gradient_p2"), wxBitmap(brush_gradient_p2));
361 	toolbar2->AddTool(miBrushGradient + 9, _("brush_gradient_p3"), wxBitmap(brush_gradient_p3));
362 	toolbar2->AddTool(miBrushGradient +10, _("brush_gradient_p4"), wxBitmap(brush_gradient_p4));
363 	toolbar2->AddTool(miBrushGradient +11, _("brush_gradient_p5"), wxBitmap(brush_gradient_p5));
364 	toolbar2->AddSeparator();
365 	toolbar2->AddTool(miBrushHeight + 1, _("brush_height_n5"), wxBitmap(brush_height_n5));
366 	toolbar2->AddTool(miBrushHeight + 2, _("brush_height_n4"), wxBitmap(brush_height_n4));
367 	toolbar2->AddTool(miBrushHeight + 3, _("brush_height_n3"), wxBitmap(brush_height_n3));
368 	toolbar2->AddTool(miBrushHeight + 4, _("brush_height_n2"), wxBitmap(brush_height_n2));
369 	toolbar2->AddTool(miBrushHeight + 5, _("brush_height_n1"), wxBitmap(brush_height_n1));
370 	toolbar2->AddTool(miBrushHeight + 6, _("brush_height_0"), wxBitmap(brush_height_0));
371 	toolbar2->AddTool(miBrushHeight + 7, _("brush_height_p1"), wxBitmap(brush_height_p1));
372 	toolbar2->AddTool(miBrushHeight + 8, _("brush_height_p2"), wxBitmap(brush_height_p2));
373 	toolbar2->AddTool(miBrushHeight + 9, _("brush_height_p3"), wxBitmap(brush_height_p3));
374 	toolbar2->AddTool(miBrushHeight +10, _("brush_height_p4"), wxBitmap(brush_height_p4));
375 	toolbar2->AddTool(miBrushHeight +11, _("brush_height_p5"), wxBitmap(brush_height_p5));
376 	toolbar2->AddSeparator();
377 	toolbar2->AddTool(miRadius + 1, _("radius1"), wxBitmap(radius_1), _("1 (1x1)"));
378 	toolbar2->AddTool(miRadius + 2, _("radius2"), wxBitmap(radius_2), _("2 (3x3)"));
379 	toolbar2->AddTool(miRadius + 3, _("radius3"), wxBitmap(radius_3), _("3 (5x5)"));
380 	toolbar2->AddTool(miRadius + 4, _("radius4"), wxBitmap(radius_4), _("4 (7x7)"));
381 	toolbar2->AddTool(miRadius + 5, _("radius5"), wxBitmap(radius_5), _("5 (9x9)"));
382 	toolbar2->AddTool(miRadius + 6, _("radius6"), wxBitmap(radius_6), _("6 (11x11)"));
383 	toolbar2->AddTool(miRadius + 7, _("radius7"), wxBitmap(radius_7), _("7 (13x13)"));
384 	toolbar2->AddTool(miRadius + 8, _("radius8"), wxBitmap(radius_8), _("8 (15x15)"));
385 	toolbar2->AddTool(miRadius + 9, _("radius9"), wxBitmap(radius_9), _("9 (17x17)"));
386 	toolbar2->Realize();
387 
388 	Config &config = Config::getInstance();
389 
390     string userData = config.getString("UserData_Root","");
391     if(userData != "") {
392     	endPathWithSlash(userData);
393     }
394 
395 	//std::cout << "A" << std::endl;
396 	wxInitAllImageHandlers();
397 #ifdef WIN32
398 	//std::cout << "B" << std::endl;
399 //	#if defined(__MINGW32__)
400 		wxIcon icon(ToUnicode("IDI_ICON1"));
401 //	#else
402 //		wxIcon icon("IDI_ICON1");
403 //	#endif
404 
405 #else
406 	//std::cout << "B" << std::endl;
407 	wxIcon icon;
408 	string iniFilePath = extractDirectoryPathFromFile(config.getFileName(false));
409 	string icon_file = iniFilePath + "editor.ico";
410 	std::ifstream testFile(icon_file.c_str());
411 	if(testFile.good())	{
412 		testFile.close();
413 		icon.LoadFile(ToUnicode(icon_file.c_str()),wxBITMAP_TYPE_ICO);
414 	}
415 #endif
416 	//std::cout << "C" << std::endl;
417 	SetIcon(icon);
418 	fileDialog = new wxFileDialog(this);
419     string defaultPath = userData + "maps/";
420     fileDialog->SetDirectory(ToUnicode(defaultPath));
421 
422 	//printf("Default Path [%s]\n",defaultPath.c_str());
423 
424 	lastPaintEvent.start();
425 
426 	boxsizer = new wxBoxSizer(wxVERTICAL);
427 	boxsizer->Add(toolbar, 0, wxEXPAND);
428 	boxsizer->Add(toolbar2, 0, wxEXPAND);
429 	//boxsizer->Add(glCanvas, 1, wxEXPAND);
430 
431 	this->panel->SetSizer(boxsizer);
432 	//this->Layout();
433 
434 	//program = new Program(glCanvas->GetClientSize().x, glCanvas->GetClientSize().y);
435 
436 	fileName = "New (unsaved) Map";
437 
438 	//printf("Does file exist, fname [%s]\n",fname.c_str());
439 
440 	if (fname.empty() == false && fileExists(fname)) {
441 		//printf("YES file exist, fname [%s]\n",fname.c_str());
442 
443 		//program->loadMap(fname);
444 		currentFile = fname;
445 		fileName = cutLastExt(extractFileFromDirectoryPath(fname.c_str()));
446 		fileDialog->SetPath(ToUnicode(fname));
447 	}
448 	SetTitle(ToUnicode(currentFile + " - " + winHeader));
449 	//setDirty(false);
450 	//setExtension();
451 
452 	initGlCanvas();
453 	#if wxCHECK_VERSION(2, 9, 3)
454 		//glCanvas->setCurrentGLContext();
455 		//printf("setcurrent #1\n");
456 	#elif wxCHECK_VERSION(2, 9, 1)
457 
458 	#else
459 		if(glCanvas) glCanvas->SetCurrent();
460 		//printf("setcurrent #2\n");
461 	#endif
462 
463 	if(startupSettingsInited == false) {
464 		startupSettingsInited = true;
465 		setupStartupSettings();
466 	}
467 }
468 
onClose(wxCloseEvent & event)469 void MainWindow::onClose(wxCloseEvent &event) {
470 	if(program != NULL && program->getMap()->getHasChanged() == true) {
471 		if( wxMessageDialog(NULL, ToUnicode("Do you want to save the current map?"),
472 			ToUnicode("Question"), wxYES_NO | wxYES_DEFAULT).ShowModal() == wxID_YES) {
473 			wxCommandEvent ev;
474 			MainWindow::onMenuFileSave(ev);
475 		}
476 	}
477 	delete program;
478 	program = NULL;
479 
480 	//delete glCanvas;
481 	if(glCanvas) glCanvas->Destroy();
482 	glCanvas = NULL;
483 
484 	this->Destroy();
485 }
486 
initGlCanvas()487 void MainWindow::initGlCanvas(){
488 	if(glCanvas == NULL) {
489 		int args[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_MIN_ALPHA,  8 };
490 		glCanvas = new GlCanvas(this, this->panel, args);
491 
492 		boxsizer->Add(glCanvas, 1, wxEXPAND);
493 	}
494 }
495 
setupStartupSettings()496 void MainWindow::setupStartupSettings() {
497 
498 	//gl canvas
499 	if(glCanvas == NULL) {
500 		initGlCanvas();
501 
502 		boxsizer->Add(glCanvas, 1, wxEXPAND);
503 
504 		this->panel->SetSizer(boxsizer);
505 		this->Layout();
506 	}
507 	glCanvas->setCurrentGLContext();
508 	glCanvas->SetFocus();
509 
510 	string playerName = Config::getInstance().getString("NetPlayerName","");
511 	program = new Program(glCanvas->GetClientSize().x, glCanvas->GetClientSize().y, playerName);
512 	fileName = "New (unsaved) Map";
513 
514 	//printf("#0 file load [%s]\n",currentFile.c_str());
515 
516 	if (!currentFile.empty() && fileExists(currentFile)) {
517 		//printf("#0 exists file load [%s]\n",currentFile.c_str());
518 
519 		program->loadMap(currentFile);
520 		//currentFile = fname;
521 		fileName = cutLastExt(extractFileFromDirectoryPath(currentFile.c_str()));
522 		fileDialog->SetPath(ToUnicode(currentFile));
523 	}
524 	SetTitle(ToUnicode(currentFile + " - " + winHeader));
525 	setDirty(false);
526 	setExtension();
527 }
528 
~MainWindow()529 MainWindow::~MainWindow() {
530 	delete fileDialog;
531 	fileDialog = NULL;
532 
533 	delete program;
534 	program = NULL;
535 
536 	delete glCanvas;
537 	glCanvas = NULL;
538 }
539 
setDirty(bool val)540 void MainWindow::setDirty(bool val) {
541 	wxPaintEvent ev;
542 	onPaint(ev);
543 	if (fileModified && val) {
544 		return;
545 	}
546 	fileModified = val;
547 	if (fileModified) {
548 		SetStatusText(wxT("File: ") + ToUnicode(fileName) + wxT("*"), siFILE_NAME);
549 	} else {
550 		SetStatusText(wxT("File: ") + ToUnicode(fileName), siFILE_NAME);
551 	}
552 }
553 
setExtension()554 void MainWindow::setExtension() {
555 	if (currentFile.empty() || program == NULL) {
556 		return;
557 	}
558 
559 	string extnsn = ext(currentFile);
560 
561 	//printf("#A currentFile [%s] extnsn [%s]\n",currentFile.c_str(),extnsn.c_str());
562 
563 	if (extnsn == "gbm" || extnsn == "mgm") {
564 		currentFile = cutLastExt(currentFile);
565 	}
566 	SetStatusText(wxT(".mgm"), siFILE_TYPE);
567 	currentFile += ".mgm";
568 }
569 
onMouseDown(wxMouseEvent & event,int x,int y)570 void MainWindow::onMouseDown(wxMouseEvent &event, int x, int y) {
571 	if (event.LeftIsDown() && program != NULL) {
572 		program->setUndoPoint(enabledGroup);
573 		program->setRefAlt(x, y);
574 		change(x, y);
575 		if (!isDirty()) {
576 			setDirty(true);
577 		}
578 		wxPaintEvent ev;
579 		onPaint(ev);
580 	}
581 	event.Skip();
582 }
583 
584 // for the mousewheel
onMouseWheelDown(wxMouseEvent & event)585 void MainWindow::onMouseWheelDown(wxMouseEvent &event) {
586 	if(program == NULL) {
587 		return;
588 	}
589 	wxPaintEvent ev;
590 	program->incCellSize(1);
591 	onPaint(ev);
592 }
593 
onMouseWheelUp(wxMouseEvent & event)594 void MainWindow::onMouseWheelUp(wxMouseEvent &event) {
595 	if(program == NULL) {
596 		return;
597 	}
598 	wxPaintEvent ev;
599 	program->incCellSize(-1);
600 	onPaint(ev);
601 }
602 
onMouseMove(wxMouseEvent & event,int x,int y)603 void MainWindow::onMouseMove(wxMouseEvent &event, int x, int y) {
604 	if(program == NULL) {
605 		return;
606 	}
607 	bool repaint = false;
608 	if (event.LeftIsDown()) {
609 		change(x, y);
610 		repaint = true;
611 	} else if (event.MiddleIsDown()) {
612 		int dif = (y - lastY);
613 		if (dif != 0) {
614 			program->incCellSize(dif / abs(dif));
615 			repaint = true;
616 		}
617 	} else if (event.RightIsDown()) {
618 		program->setOfset(x - lastX, y - lastY);
619 		repaint = true;
620 	} else {
621 		int currResource = program->getResource(x, y);
622 		if (currResource > 0) {
623 			SetStatusText(wxT("Resource: ") + ToUnicode(resource_descs[currResource]), siCURR_OBJECT);
624 			resourceUnderMouse = currResource;
625 			objectUnderMouse = 0;
626 		} else {
627 			int currObject = program->getObject(x, y);
628 			SetStatusText(wxT("Object: ") + ToUnicode(object_descs[currObject]), siCURR_OBJECT);
629 			resourceUnderMouse = 0;
630 			objectUnderMouse = currObject;
631 		}
632 
633 		SetStatusText(wxT("Pos (Ingame): ")
634 				+ ToUnicode(intToStr(program->getCellX(x))
635 				+ ","
636 				+ intToStr(program->getCellY(y))
637 				+ " ("
638 				+ intToStr(2*(program->getCellX(x)))
639 				+ ","
640 				+ intToStr(2*(program->getCellY(y)))
641 				+ ")"), siPOS_VALUE);
642 //#ifdef WIN32
643 		//repaint = true;
644 //#endif
645 	}
646 	lastX = x;
647 	lastY = y;
648 
649 	if (repaint) {
650 		wxPaintEvent ev;
651 		onPaint(ev);
652 	}
653 	event.Skip();
654 }
655 
onPaint(wxPaintEvent & event)656 void MainWindow::onPaint(wxPaintEvent &event) {
657 	//printf("onPaint map\n");
658 
659 	if(!IsShown()) {
660 		//printf("onPaint skip map\n");
661 
662 		event.Skip();
663 		return;
664 	}
665 
666 //#if wxCHECK_VERSION(2, 9, 3)
667 
668 //#elif wxCHECK_VERSION(2, 9, 1)
669 //	glCanvas->setCurrentGLContext();
670 //#endif
671 
672 	//static bool contextSet = false;
673 	//if(contextSet == false) {
674 	//	contextSet = true;
675 	glCanvas->setCurrentGLContext();
676 	//}
677 
678 	//printf("lastPaintEvent.getMillis() map\n");
679 	if(lastPaintEvent.getMillis() < 30) {
680 		sleep(1);
681 		event.Skip();
682 		return;
683 	}
684 
685 	//printf("wxPaintDC dc map\n");
686 	wxPaintDC dc(this); // "In a paint event handler must always create a wxPaintDC object even if you do not use it.  (?)
687 	                    //  Otherwise, under MS Windows, refreshing for this and other windows will go wrong"
688                         //  http://docs.wxwidgets.org/2.6/wx_wxpaintevent.html
689 
690 	lastPaintEvent.start();
691 
692 	if(panel) panel->Refresh(false);
693 	if(menuBar) menuBar->Refresh(false);
694 
695 	refreshMapRender();
696 	event.Skip();
697 }
698 
refreshMapRender()699 void MainWindow::refreshMapRender() {
700 	//printf("refreshMapRender map\n");
701 
702 	if(program && glCanvas) {
703 		program->renderMap(glCanvas->GetClientSize().x, glCanvas->GetClientSize().y);
704 		glCanvas->SwapBuffers();
705 	}
706 }
707 
onMenuFileLoad(wxCommandEvent & event)708 void MainWindow::onMenuFileLoad(wxCommandEvent &event) {
709 	if(program == NULL) {
710 		return;
711 	}
712 
713 	try {
714 		fileDialog->SetMessage(wxT("Select Glestmap to load"));
715 		fileDialog->SetWildcard(wxT("Glest&Mega Map (*.gbm *.mgm)|*.gbm;*.mgm|Glest Map (*.gbm)|*.gbm|Mega Map (*.mgm)|*.mgm"));
716 		if (fileDialog->ShowModal() == wxID_OK) {
717 #ifdef WIN32
718 			const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(wxFNCONV(fileDialog->GetPath()));
719 			currentFile = tmp_buf;
720 
721 			auto_ptr<wchar_t> wstr(Ansi2WideString(currentFile.c_str()));
722 			currentFile = utf8_encode(wstr.get());
723 #else
724 			//currentFile = fileDialog->GetPath().ToAscii();
725 
726 			const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(fileDialog->GetPath());
727 			currentFile = tmp_buf;
728 #endif
729 
730 			//printf("#1 file load [%s]\n",currentFile.c_str());
731 
732 			program->loadMap(currentFile);
733 			fileName = cutLastExt(extractFileFromDirectoryPath(currentFile.c_str()));
734 			setDirty(false);
735 			setExtension();
736 			SetTitle(ToUnicode(winHeader + "; " + currentFile));
737 		}
738 	}
739 	catch (const string &e) {
740 		MsgDialog(this, ToUnicode(e), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
741 	}
742 	catch (const exception &e) {
743 		MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
744 	}
745 
746 }
747 
onMenuFileSave(wxCommandEvent & event)748 void MainWindow::onMenuFileSave(wxCommandEvent &event) {
749 	if(program == NULL) {
750 		return;
751 	}
752 
753 	if (currentFile.empty()) {
754 		wxCommandEvent ev;
755 		onMenuFileSaveAs(ev);
756 	}
757 	else {
758 		setExtension();
759 
760 		//printf("#1 save load [%s]\n",currentFile.c_str());
761 
762 		program->saveMap(currentFile);
763 		setDirty(false);
764 	}
765 }
766 
onMenuFileSaveAs(wxCommandEvent & event)767 void MainWindow::onMenuFileSaveAs(wxCommandEvent &event) {
768 	if(program == NULL) {
769 		return;
770 	}
771 
772 #if wxCHECK_VERSION(2, 9, 1)
773 	wxFileDialog fd(this, wxT("Select file"), wxT(""), wxT(""), wxT("*.mgm|*.gbm"), wxFD_SAVE);
774 #else
775 	wxFileDialog fd(this, wxT("Select file"), wxT(""), wxT(""), wxT("*.mgm|*.gbm"), wxSAVE);
776 #endif
777 
778 	if(fileDialog->GetPath() != ToUnicode("")) {
779 		fd.SetPath(fileDialog->GetPath());
780 	}
781 	else {
782 		Config &config = Config::getInstance();
783 		string userData = config.getString("UserData_Root","");
784 		if(userData != "") {
785 			endPathWithSlash(userData);
786 		}
787 		string defaultPath = userData + "maps/";
788 		fd.SetDirectory(ToUnicode(defaultPath));
789 	}
790 
791 	fd.SetWildcard(wxT("MegaGlest Map (*.mgm)|*.mgm|Glest Map (*.gbm)|*.gbm"));
792 	if (fd.ShowModal() == wxID_OK) {
793 #ifdef WIN32
794 		const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(wxFNCONV(fd.GetPath()));
795 		currentFile = tmp_buf;
796 
797 		auto_ptr<wchar_t> wstr(Ansi2WideString(currentFile.c_str()));
798 		currentFile = utf8_encode(wstr.get());
799 #else
800 		 //currentFile = fd.GetPath().ToAscii();
801 		const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(fd.GetPath());
802 		currentFile = tmp_buf;
803 #endif
804 
805 		fileDialog->SetPath(fd.GetPath());
806 		setExtension();
807 
808 		//printf("#2 file save [%s]\n",currentFile.c_str());
809 
810 		program->saveMap(currentFile);
811 		fileName = cutLastExt(extractFileFromDirectoryPath(currentFile.c_str()));
812 		setDirty(false);
813 	}
814 	SetTitle(ToUnicode(winHeader + "; " + currentFile));
815 }
816 
onMenuFileExit(wxCommandEvent & event)817 void MainWindow::onMenuFileExit(wxCommandEvent &event) {
818 	Close();
819 }
820 
onMenuEditUndo(wxCommandEvent & event)821 void MainWindow::onMenuEditUndo(wxCommandEvent &event) {
822 	if(program == NULL) {
823 		return;
824 	}
825 
826 	// std::cout << "Undo Pressed" << std::endl;
827 	if (program->undo()) {
828 		wxPaintEvent e;
829 		onPaint(e);
830 		setDirty();
831 	}
832 }
833 
onMenuEditRedo(wxCommandEvent & event)834 void MainWindow::onMenuEditRedo(wxCommandEvent &event) {
835 	if(program == NULL) {
836 		return;
837 	}
838 
839 	if (program->redo()) {
840 		wxPaintEvent e;
841 		onPaint(e);
842 		setDirty();
843 	}
844 }
845 
onMenuEditReset(wxCommandEvent & event)846 void MainWindow::onMenuEditReset(wxCommandEvent &event) {
847 	if(program == NULL) {
848 		return;
849 	}
850 
851 	program->setUndoPoint(ctAll);
852 	SimpleDialog simpleDialog;
853 	simpleDialog.addValue("Width", "128","(must be 16,32,64,128,256,512...)"); // must be an exponent of two
854 	simpleDialog.addValue("Height", "128","(must be 16,32,64,128,256,512...)");
855 	simpleDialog.addValue("Surface", "1","(Default surface material)");
856 	simpleDialog.addValue("Altitude", "10","(Default surface height)");
857 	simpleDialog.addValue("Number of players", "8");
858 	if (!simpleDialog.show()) return;
859 
860 	try {
861 		program->reset(
862 			strToInt(simpleDialog.getValue("Width")),
863 			strToInt(simpleDialog.getValue("Height")),
864 			strToInt(simpleDialog.getValue("Altitude")),
865 			strToInt(simpleDialog.getValue("Surface")));
866 			program->resetFactions(strToInt(simpleDialog.getValue("Number of players")));
867 	}
868 	catch (const exception &e) {
869 		MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
870 	}
871 	currentFile = "";
872 	fileName = "New (unsaved) map";
873 
874 	wxPaintEvent ev;
875 	onPaint(ev);
876 }
877 
onMenuEditResetPlayers(wxCommandEvent & event)878 void MainWindow::onMenuEditResetPlayers(wxCommandEvent &event) {
879 	if(program == NULL) {
880 		return;
881 	}
882 
883 	SimpleDialog simpleDialog;
884 	simpleDialog.addValue("Number of players", intToStr(program->getMap()->getMaxFactions()));
885 	if (!simpleDialog.show("Reset players")) return;
886 
887 	try {
888 		program->resetFactions(strToInt(simpleDialog.getValue("Number of players")));
889 	}
890 	catch (const exception &e) {
891 		MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
892 	}
893 	setDirty();
894 	setExtension();
895 }
896 
897 
onMenuEditFlipDiagonal(wxCommandEvent & event)898 void MainWindow::onMenuEditFlipDiagonal(wxCommandEvent &event) {
899 	if(program == NULL) {
900 		return;
901 	}
902 	program->setUndoPoint(ctAll);
903 		program->flipDiagonal();
904 		setDirty();
905 }
906 
onMenuEditResize(wxCommandEvent & event)907 void MainWindow::onMenuEditResize(wxCommandEvent &event) {
908 	if(program == NULL) {
909 		return;
910 	}
911 
912 	SimpleDialog simpleDialog;
913 	simpleDialog.addValue("Width", intToStr(program->getMap()->getW()),"(must be 16,32,64,128,256,512...)");
914 	simpleDialog.addValue("Height", intToStr(program->getMap()->getH()),"(must be 16,32,64,128,256,512...)");
915 	simpleDialog.addValue("Surface", "1","(surface material for new area around map)");
916 	simpleDialog.addValue("Altitude", "10","(surface height for new area around map)");
917 	if (!simpleDialog.show("Resize - expand around, shrink to topleft")) return;
918 
919 	try {
920 		program->resize(
921 			strToInt(simpleDialog.getValue("Width")),
922 			strToInt(simpleDialog.getValue("Height")),
923 			strToInt(simpleDialog.getValue("Altitude")),
924 			strToInt(simpleDialog.getValue("Surface")));
925 	}
926 	catch (const exception &e) {
927 		MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
928 	}
929 	setDirty();
930 }
931 
onMenuEditFlipX(wxCommandEvent & event)932 void MainWindow::onMenuEditFlipX(wxCommandEvent &event) {
933 	if(program == NULL) {
934 		return;
935 	}
936 
937 	program->setUndoPoint(ctAll);
938 	program->flipX();
939 	setDirty();
940 }
941 
onMenuEditFlipY(wxCommandEvent & event)942 void MainWindow::onMenuEditFlipY(wxCommandEvent &event) {
943 	if(program == NULL) {
944 		return;
945 	}
946 
947 	program->setUndoPoint(ctAll);
948 	program->flipY();
949 	setDirty();
950 }
951 
onMenuEditMirrorX(wxCommandEvent & event)952 void MainWindow::onMenuEditMirrorX(wxCommandEvent &event) { // copy left to right
953 	if(program == NULL) {
954 		return;
955 	}
956 
957 	program->setUndoPoint(ctAll);
958 	program->mirrorX();
959 	setDirty();
960 }
961 
onMenuEditMirrorY(wxCommandEvent & event)962 void MainWindow::onMenuEditMirrorY(wxCommandEvent &event) { // copy top to bottom
963 	if(program == NULL) {
964 		return;
965 	}
966 
967 	program->setUndoPoint(ctAll);
968 	program->mirrorY();
969 	setDirty();
970 }
971 
onMenuEditMirrorXY(wxCommandEvent & event)972 void MainWindow::onMenuEditMirrorXY(wxCommandEvent &event) { // copy bottomleft tp topright
973 	if(program == NULL) {
974 		return;
975 	}
976 
977 	program->setUndoPoint(ctAll);
978 	program->mirrorXY();
979 	setDirty();
980 }
981 
onMenuEditRotatecopyX(wxCommandEvent & event)982 void MainWindow::onMenuEditRotatecopyX(wxCommandEvent &event) { // copy left to right, rotated
983 	if(program == NULL) {
984 		return;
985 	}
986 
987 	program->setUndoPoint(ctAll);
988 	program->rotatecopyX();
989 	setDirty();
990 }
991 
onMenuEditRotatecopyY(wxCommandEvent & event)992 void MainWindow::onMenuEditRotatecopyY(wxCommandEvent &event) { // copy top to bottom, rotated
993 	if(program == NULL) {
994 		return;
995 	}
996 
997 	program->setUndoPoint(ctAll);
998 	program->rotatecopyY();
999 	setDirty();
1000 }
1001 
onMenuEditRotatecopyXY(wxCommandEvent & event)1002 void MainWindow::onMenuEditRotatecopyXY(wxCommandEvent &event) { // copy bottomleft to topright, rotated
1003 	if(program == NULL) {
1004 		return;
1005 	}
1006 
1007 	program->setUndoPoint(ctAll);
1008 	program->rotatecopyXY();
1009 	setDirty();
1010 }
1011 
onMenuEditRotatecopyCorner(wxCommandEvent & event)1012 void MainWindow::onMenuEditRotatecopyCorner(wxCommandEvent &event) { // copy top left 1/4 to top right 1/4, rotated
1013 	if(program == NULL) {
1014 		return;
1015 	}
1016 
1017 	program->setUndoPoint(ctAll);
1018 	program->rotatecopyCorner();
1019 	setDirty();
1020 }
1021 
1022 
onMenuEditRandomizeHeights(wxCommandEvent & event)1023 void MainWindow::onMenuEditRandomizeHeights(wxCommandEvent &event) {
1024 	if(program == NULL) {
1025 		return;
1026 	}
1027 	while(true){
1028 
1029 		SimpleDialog simpleDialog;
1030 		simpleDialog.addValue("Initial Reset", boolToStr(randomWithReset),"(1 = true, 0 = false) If set to '0' no height reset is done before calculating");
1031 		simpleDialog.addValue("Min Height", intToStr(randomMinimumHeight),"Lowest random height. example: -300 or below if you want water , 0 if you don't want water.");
1032 		simpleDialog.addValue("Max Height", intToStr(randomMaximumHeight),"Max random height. A good value is 400");
1033 		simpleDialog.addValue("Chance Divider", intToStr(randomChanceDivider),"Defines how often you get a hill or hole default is 30. Bigger number, less hills/holes.");
1034 		simpleDialog.addValue("Smooth Recursions", intToStr(randomRecursions),"Number of recursions cycles to smooth the hills and holes. 0<x<50 default is 3.");
1035 		if (!simpleDialog.show("Randomize Height")) return;
1036 
1037 		try {
1038 			string checkValue = simpleDialog.getValue("Initial Reset");
1039 			if(checkValue != "" && strToInt(checkValue) > 1) {
1040 				randomWithReset = true;
1041 			}
1042 			else {
1043 				randomWithReset = strToBool(simpleDialog.getValue("Initial Reset"));
1044 			}
1045 			randomMinimumHeight=strToInt(simpleDialog.getValue("Min Height"));
1046 			randomMaximumHeight=strToInt(simpleDialog.getValue("Max Height"));
1047 			randomChanceDivider=strToInt(simpleDialog.getValue("Chance Divider"));
1048 			randomRecursions=strToInt(simpleDialog.getValue("Smooth Recursions"));
1049 
1050 			// set insane inputs to something that does not crash
1051 			if(randomMinimumHeight>=randomMaximumHeight) randomMinimumHeight=randomMaximumHeight-1;
1052 			if(randomChanceDivider<1) randomChanceDivider=1;
1053 
1054 			// set randomRecursions to something useful
1055 			if(randomRecursions<0) randomRecursions=0;
1056 			if(randomRecursions>50) randomRecursions=50;
1057 
1058 			program->setUndoPoint(ctAll);
1059 			program->randomizeMapHeights(randomWithReset, randomMinimumHeight, randomMaximumHeight,
1060 					randomChanceDivider, randomRecursions);
1061 		}
1062 		catch (const exception &e) {
1063 			MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
1064 		}
1065 		setDirty();
1066 	}
1067 }
1068 
onMenuEditRandomize(wxCommandEvent & event)1069 void MainWindow::onMenuEditRandomize(wxCommandEvent &event) {
1070 	if(program == NULL) {
1071 		return;
1072 	}
1073 
1074 	program->setUndoPoint(ctAll);
1075 	program->randomizeFactions();
1076 	setDirty();
1077 }
1078 
onMenuEditSwitchSurfaces(wxCommandEvent & event)1079 void MainWindow::onMenuEditSwitchSurfaces(wxCommandEvent &event) {
1080 	if(program == NULL) {
1081 		return;
1082 	}
1083 
1084 	SimpleDialog simpleDialog;
1085 	simpleDialog.addValue("Surface1", "1","replace this surface with...");
1086 	simpleDialog.addValue("Surface2", "2","...this and vice versa");
1087 	if (!simpleDialog.show("Switch surfaces")) return;
1088 
1089 	try {
1090         program->setUndoPoint(ctSurface);
1091 		program->switchMapSurfaces(
1092 			strToInt(simpleDialog.getValue("Surface1")),
1093 			strToInt(simpleDialog.getValue("Surface2")));
1094 	}
1095 	catch (const exception &e) {
1096 		MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
1097 	}
1098 	setDirty();
1099 }
1100 
onMenuEditInfo(wxCommandEvent & event)1101 void MainWindow::onMenuEditInfo(wxCommandEvent &event) {
1102 	if(program == NULL) {
1103 		return;
1104 	}
1105 
1106 	SimpleDialog simpleDialog;
1107 	simpleDialog.addValue("Title", program->getMap()->getTitle());
1108 	simpleDialog.addValue("Description", program->getMap()->getDesc());
1109 	simpleDialog.addValue("Author", program->getMap()->getAuthor());
1110 	if (!simpleDialog.show("Info",true)) return;
1111 
1112     bool ischanged = program->setMapTitle(simpleDialog.getValue("Title"));
1113 	ischanged = (program->setMapDesc(simpleDialog.getValue("Description")) || ischanged);
1114 	ischanged = (program->setMapAuthor(simpleDialog.getValue("Author")) || ischanged);
1115 	if (ischanged)
1116 		if (!isDirty()) {
1117 			setDirty(true);
1118 		}
1119 
1120 }
1121 
onMenuEditAdvanced(wxCommandEvent & event)1122 void MainWindow::onMenuEditAdvanced(wxCommandEvent &event) {
1123 	if(program == NULL) {
1124 		return;
1125 	}
1126 
1127 	SimpleDialog simpleDialog;
1128 	simpleDialog.addValue("Height Factor", intToStr(program->getMap()->getHeightFactor()),"lower means more hill effect. Numbers above 100 are handled like this:\nx=x/100 ,so a 150 will mean 1.5 in the game.");
1129 	simpleDialog.addValue("Water Level", intToStr(program->getMap()->getWaterLevel()),"water is visible below this, and walkable until 1.5 less");
1130 	simpleDialog.addValue("Cliff Level", intToStr(program->getMap()->getCliffLevel()),"neighboring fields with at least this heights difference are cliffs");
1131 	simpleDialog.addValue("Camera Height", intToStr(program->getMap()->getCameraHeight()),"you can give a camera height here default is 0 ;ignored if <20");
1132 	if (!simpleDialog.show("Advanced")) return;
1133 
1134 	try {
1135 		program->setMapAdvanced(
1136 			strToInt(simpleDialog.getValue("Height Factor")),
1137 			strToInt(simpleDialog.getValue("Water Level")),
1138 			strToInt(simpleDialog.getValue("Cliff Level")),
1139 			strToInt(simpleDialog.getValue("Camera Height")));
1140 	}
1141 	catch (const exception &e) {
1142 		MsgDialog(this, ToUnicode(e.what()), wxT("Exception"), wxOK | wxICON_ERROR).ShowModal();
1143 	}
1144 	setDirty();
1145 }
1146 
onMenuViewResetZoomAndPos(wxCommandEvent & event)1147 void MainWindow::onMenuViewResetZoomAndPos(wxCommandEvent &event) {
1148 	if(program == NULL) {
1149 		return;
1150 	}
1151 
1152 	program->resetOfset();
1153 	wxPaintEvent e;
1154 	onPaint(e);
1155 }
1156 
onMenuViewGrid(wxCommandEvent & event)1157 void MainWindow::onMenuViewGrid(wxCommandEvent &event) {
1158 	if(program == NULL) {
1159 		return;
1160 	}
1161 
1162 	menuView->Check(miViewGrid, program->setGridOnOff());    // miViewGrid event.GetId()
1163 	wxPaintEvent e;
1164 	onPaint(e);
1165 }
1166 
1167 
onMenuViewHeightMap(wxCommandEvent & event)1168 void MainWindow::onMenuViewHeightMap(wxCommandEvent &event) {
1169 	if(program == NULL) {
1170 		return;
1171 	}
1172 
1173 	menuView->Check(miViewHeightMap, program->setHeightMapOnOff());    // miViewGrid event.GetId()
1174 	wxPaintEvent e;
1175 	onPaint(e);
1176 }
onMenuHideWater(wxCommandEvent & event)1177 void MainWindow::onMenuHideWater(wxCommandEvent &event) {
1178 	if(program == NULL) {
1179 		return;
1180 	}
1181 
1182 	menuView->Check(miHideWater, program->setHideWaterOnOff());    // miViewGrid event.GetId()
1183 	wxPaintEvent e;
1184 	onPaint(e);
1185 }
onMenuViewAbout(wxCommandEvent & event)1186 void MainWindow::onMenuViewAbout(wxCommandEvent &event) {
1187 	MsgDialog(
1188 		this,
1189 		wxT("\n    Glest Map Editor\n    Copyright 2004-2010 The Glest Team\n    Copyright 2010-2017 The MegaGlest Team    \n"),
1190 		wxT("About")).ShowModal();
1191 }
1192 
onMenuViewHelp(wxCommandEvent & event)1193 void MainWindow::onMenuViewHelp(wxCommandEvent &event) {
1194 	MsgDialog(this,
1195 		wxT("Draw with left mouse\nMove viewport with right mouse drag\nZoom with center mouse drag, or mousewheel\n\n\
1196 You can change brush in the same category with key 1-9\n\
1197 and change category with their first letter (keys S, R, O, G, H)\n\
1198 Press Space to set brush to the resource or object under the mouse cursor\n\
1199 To center things in the map shift it with Shift-Up/Down/Left/Right keys\n\
1200 Height tool (blue) builds with integer height steps 0-20, \nwhile Gradient tool (red) uses any real number \n\
1201 Units can go over water as long as it is less than 1.5 deep\n\n\
1202 A good idea is to put some stone, gold and tree near starting position\n\
1203 Starting position needs an open area for the tower and the starting units\n"),
1204 		wxT("Help")).ShowModal();
1205 		/* 5 away and 10x10 empty area? */
1206 }
1207 
onMenuBrushHeight(wxCommandEvent & e)1208 void MainWindow::onMenuBrushHeight(wxCommandEvent &e) {
1209 	uncheckBrush();
1210 	menuBrushHeight->Check(e.GetId(), true);
1211 	height = e.GetId() - miBrushHeight - heightCount / 2 - 1;
1212 	enabledGroup = ctHeight;
1213 	currentBrush = btHeight;
1214 	SetStatusText(wxT("Brush: Height"), siBRUSH_TYPE);
1215 	SetStatusText(wxT("Value: ") + ToUnicode(intToStr(height)), siBRUSH_VALUE);
1216 }
1217 
onMenuBrushGradient(wxCommandEvent & e)1218 void MainWindow::onMenuBrushGradient(wxCommandEvent &e) {
1219 	uncheckBrush();
1220 	menuBrushGradient->Check(e.GetId(), true);
1221 	height = e.GetId() - miBrushGradient - heightCount / 2 - 1;
1222 	enabledGroup = ctGradient;
1223 	currentBrush = btGradient;
1224 	SetStatusText(wxT("Brush: Gradient"), siBRUSH_TYPE);
1225 	SetStatusText(wxT("Value: ") + ToUnicode(intToStr(height)), siBRUSH_VALUE);
1226 }
1227 
1228 
onMenuBrushSurface(wxCommandEvent & e)1229 void MainWindow::onMenuBrushSurface(wxCommandEvent &e) {
1230 	uncheckBrush();
1231 	menuBrushSurface->Check(e.GetId(), true);
1232 	surface = e.GetId() - miBrushSurface;
1233 	enabledGroup = ctSurface;
1234 	currentBrush = btSurface;
1235 	SetStatusText(wxT("Brush: Surface"), siBRUSH_TYPE);
1236 	SetStatusText(
1237 		wxT("Value: ") + ToUnicode(intToStr(surface)) + wxT(" ")
1238 		+ ToUnicode(surface_descs[surface - 1]), siBRUSH_VALUE);
1239 }
1240 
onMenuBrushObject(wxCommandEvent & e)1241 void MainWindow::onMenuBrushObject(wxCommandEvent &e) {
1242 	uncheckBrush();
1243 	menuBrushObject->Check(e.GetId(), true);
1244 	object = e.GetId() - miBrushObject - 1;
1245 	enabledGroup = ctObject;
1246 	currentBrush = btObject;
1247 	SetStatusText(wxT("Brush: Object"), siBRUSH_TYPE);
1248 	SetStatusText(
1249 		wxT("Value: ") + ToUnicode(intToStr(object)) + wxT(" ")
1250 		+ ToUnicode(object_descs[object]), siBRUSH_VALUE);
1251 }
1252 
onMenuBrushResource(wxCommandEvent & e)1253 void MainWindow::onMenuBrushResource(wxCommandEvent &e) {
1254 	uncheckBrush();
1255 	menuBrushResource->Check(e.GetId(), true);
1256 	resource = e.GetId() - miBrushResource - 1;
1257 	enabledGroup = ctResource;
1258 	currentBrush = btResource;
1259 	SetStatusText(wxT("Brush: Resource"), siBRUSH_TYPE);
1260 	SetStatusText(
1261 		wxT("Value: ") + ToUnicode(intToStr(resource)) + wxT(" ")
1262 		+ ToUnicode(resource_descs[resource]), siBRUSH_VALUE);
1263 }
1264 
onMenuBrushStartLocation(wxCommandEvent & e)1265 void MainWindow::onMenuBrushStartLocation(wxCommandEvent &e) {
1266 	uncheckBrush();
1267 	menuBrushStartLocation->Check(e.GetId(), true);
1268 	startLocation = e.GetId() - miBrushStartLocation;
1269 	enabledGroup = ctLocation;
1270 	currentBrush = btStartLocation;
1271 	SetStatusText(wxT("Brush: Start Locations"), siBRUSH_TYPE);
1272 	SetStatusText(wxT("Value: ") + ToUnicode(intToStr(startLocation)), siBRUSH_VALUE);
1273 }
1274 
onMenuRadius(wxCommandEvent & e)1275 void MainWindow::onMenuRadius(wxCommandEvent &e) {
1276 	uncheckRadius();
1277 	menuRadius->Check(e.GetId(), true);
1278 	radius = e.GetId() - miRadius;
1279 	SetStatusText(wxT("Radius: ") + ToUnicode(intToStr(radius)), siBRUSH_RADIUS);
1280 }
1281 
change(int x,int y)1282 void MainWindow::change(int x, int y) {
1283 	if(program == NULL) {
1284 		return;
1285 	}
1286 
1287 	switch (enabledGroup) {
1288 	case ctHeight:
1289 		program->glestChangeMapHeight(x, y, height, radius);
1290 		break;
1291 	case ctSurface:
1292 		program->changeMapSurface(x, y, surface, radius);
1293 		break;
1294 	case ctObject:
1295 		program->changeMapObject(x, y, object, radius);
1296 		break;
1297 	case ctResource:
1298 		program->changeMapResource(x, y, resource, radius);
1299 		break;
1300 	case ctLocation:
1301 		program->changeStartLocation(x, y, startLocation - 1);
1302 		break;
1303 	case ctGradient:
1304 		program->pirateChangeMapHeight(x, y, height, radius);
1305 		break;
1306 	}
1307 }
1308 
uncheckBrush()1309 void MainWindow::uncheckBrush() {
1310 	for (int i = 0; i < heightCount; ++i) {
1311 		menuBrushHeight->Check(miBrushHeight + i + 1, false);
1312 	}
1313 	for (int i = 0; i < heightCount; ++i) {
1314 		menuBrushGradient->Check(miBrushGradient + i + 1, false);
1315 	}
1316 	for (int i = 0; i < surfaceCount; ++i) {
1317 		menuBrushSurface->Check(miBrushSurface + i + 1, false);
1318 	}
1319 	for (int i = 0; i < objectCount; ++i) {
1320 		menuBrushObject->Check(miBrushObject + i + 1, false);
1321 	}
1322 	for (int i = 0; i < resourceCount; ++i) {
1323 		menuBrushResource->Check(miBrushResource + i + 1, false);
1324 	}
1325 	for (int i = 0; i < startLocationCount; ++i) {
1326 		menuBrushStartLocation->Check(miBrushStartLocation + i + 1, false);
1327 	}
1328 }
1329 
uncheckRadius()1330 void MainWindow::uncheckRadius() {
1331 	for (int i = 1; i <= radiusCount; ++i) {
1332 		menuRadius->Check(miRadius + i, false);
1333 	}
1334 }
1335 
onKeyDown(wxKeyEvent & e)1336  void MainWindow::onKeyDown(wxKeyEvent &e) {
1337 	if(program == NULL) {
1338 		return;
1339 	}
1340 
1341 	if(e.GetModifiers() == wxMOD_CONTROL || e.GetModifiers() == wxMOD_ALT){
1342 		e.Skip();
1343 	}
1344 	// WARNING: don't add any Ctrl or ALt key shortcuts below those are reserved for internal menu use.
1345 
1346  	if (currentBrush == btSurface) { // surface texture
1347  		if (e.GetKeyCode() >= '1' && e.GetKeyCode() <= '5') {
1348  			surface = e.GetKeyCode() - 48; // '1'-'5' == 1-5
1349  			wxCommandEvent evt(wxEVT_NULL, miBrushSurface + surface);
1350  			onMenuBrushSurface(evt);
1351  			return;
1352  		}
1353  	}
1354  	if (currentBrush == btObject) {
1355  		bool valid = true;
1356  		if (e.GetKeyCode() >= '1' && e.GetKeyCode() <= '9') {
1357  			object = e.GetKeyCode() - 48; // '1'-'9' == 1-9
1358  		} else if (e.GetKeyCode() == '0') { // '0' == 10
1359  			object = 10;
1360  		} else if (e.GetKeyCode() == '-') {	// '-' == 0
1361  			object = 0;
1362  		} else {
1363  			valid = false;
1364  		}
1365  		if (valid) {
1366  			wxCommandEvent evt(wxEVT_NULL, miBrushObject + object + 1);
1367  			onMenuBrushObject(evt);
1368  			return;
1369  		}
1370  	}
1371  	if (currentBrush == btResource) {
1372  		if (e.GetKeyCode() >= '0' && e.GetKeyCode() <= '5') {
1373  			resource = e.GetKeyCode() - 48;	// '0'-'5' == 0-5
1374  			wxCommandEvent evt(wxEVT_NULL, miBrushResource + resource + 1);
1375  			onMenuBrushResource(evt);
1376  			return;
1377  		}
1378  	}
1379  	if (currentBrush == btStartLocation) {
1380  		if (e.GetKeyCode() >= '1' && e.GetKeyCode() <= '8') {
1381  			startLocation = e.GetKeyCode() - 48; // '1'-'8' == 0-7
1382  			wxCommandEvent evt(wxEVT_NULL, miBrushStartLocation + startLocation);
1383  			onMenuBrushStartLocation(evt);
1384  			return;
1385  		}
1386  	}
1387  	if (e.GetKeyCode() == 'H') {
1388  		wxCommandEvent evt(wxEVT_NULL, miBrushHeight + height + heightCount / 2 + 1);
1389  		onMenuBrushHeight(evt);
1390  	} else if (e.GetKeyCode() == ' ') {
1391 		if (resourceUnderMouse != 0) {
1392 			wxCommandEvent evt(wxEVT_NULL, miBrushResource + resourceUnderMouse + 1);
1393  			onMenuBrushResource(evt);
1394 		} else {
1395 			wxCommandEvent evt(wxEVT_NULL, miBrushObject + objectUnderMouse + 1);
1396  			onMenuBrushObject(evt);
1397 		}
1398  	} else if (e.GetKeyCode() == 'G') {
1399  		wxCommandEvent evt(wxEVT_NULL, miBrushGradient + height + heightCount / 2 + 1);
1400  		onMenuBrushGradient(evt);
1401  	} else if (e.GetKeyCode() == 'S') {
1402 		wxCommandEvent evt(wxEVT_NULL, miBrushSurface + surface);
1403 		onMenuBrushSurface(evt);
1404  	} else if (e.GetKeyCode() == 'O') {
1405  		wxCommandEvent evt(wxEVT_NULL, miBrushObject + object + 1);
1406  		onMenuBrushObject(evt);
1407  	} else if (e.GetKeyCode() == 'R') {
1408  		wxCommandEvent evt(wxEVT_NULL, miBrushResource + resource + 1);
1409  		onMenuBrushResource(evt);
1410  	} else if (e.GetKeyCode() == 'L') {
1411  		wxCommandEvent evt(wxEVT_NULL, miBrushStartLocation + startLocation + 1);
1412  		onMenuBrushStartLocation(evt);
1413  	} else if (e.GetKeyCode() == WXK_LEFT && e.GetModifiers() == wxMOD_SHIFT) { // shift-left/right/up/down to shift the map one square
1414  	    program->setUndoPoint(ctAll);
1415  	    program->shiftLeft();
1416  		setDirty();
1417  	} else if (e.GetKeyCode() == WXK_RIGHT && e.GetModifiers() == wxMOD_SHIFT) {
1418  	    program->setUndoPoint(ctAll);
1419  	    program->shiftRight();
1420  		setDirty();
1421  	} else if (e.GetKeyCode() == WXK_UP && e.GetModifiers() == wxMOD_SHIFT) {
1422  	    program->setUndoPoint(ctAll);
1423  	    program->shiftUp();
1424  		setDirty();
1425  	} else if (e.GetKeyCode() == WXK_DOWN && e.GetModifiers() == wxMOD_SHIFT) {
1426  	    program->setUndoPoint(ctAll);
1427  	    program->shiftDown();
1428  		setDirty();
1429  	} else {
1430  		e.Skip();
1431 	}
1432 }
1433 
BEGIN_EVENT_TABLE(MainWindow,wxFrame)1434 BEGIN_EVENT_TABLE(MainWindow, wxFrame)
1435 
1436 	EVT_CLOSE(MainWindow::onClose)
1437 
1438 	// these are 'handled' by GlCanvas and funneled to these handlers. See BEGIN_EVENT_TABLE(GlCanvas, wxGLCanvas) below.
1439 	//EVT_LEFT_DOWN(MainWindow::onMouseDown)
1440 	//EVT_MOTION(MainWindow::onMouseMove)
1441 	//EVT_KEY_DOWN(MainWindow::onKeyDown)
1442 
1443 	EVT_MENU(wxID_NEW, MainWindow::onMenuEditReset)
1444 	EVT_MENU(wxID_OPEN, MainWindow::onMenuFileLoad)
1445 	EVT_MENU(wxID_SAVE, MainWindow::onMenuFileSave)
1446 	EVT_MENU(wxID_SAVEAS, MainWindow::onMenuFileSaveAs)
1447 	EVT_MENU(wxID_EXIT, MainWindow::onMenuFileExit)
1448 
1449 	EVT_MENU(miEditUndo, MainWindow::onMenuEditUndo)
1450 	EVT_MENU(miEditRedo, MainWindow::onMenuEditRedo)
1451 	EVT_MENU(miEditResetPlayers, MainWindow::onMenuEditResetPlayers)
1452 	EVT_MENU(miEditResize, MainWindow::onMenuEditResize)
1453 	EVT_MENU(miEditFlipDiagonal, MainWindow::onMenuEditFlipDiagonal)
1454 	EVT_MENU(miEditFlipX, MainWindow::onMenuEditFlipX)
1455 	EVT_MENU(miEditFlipY, MainWindow::onMenuEditFlipY)
1456 
1457     EVT_MENU(miEditMirrorX, MainWindow::onMenuEditMirrorX)
1458 	EVT_MENU(miEditMirrorY, MainWindow::onMenuEditMirrorY)
1459 	EVT_MENU(miEditMirrorXY, MainWindow::onMenuEditMirrorXY)
1460 	EVT_MENU(miEditRotatecopyX, MainWindow::onMenuEditRotatecopyX)
1461 	EVT_MENU(miEditRotatecopyY, MainWindow::onMenuEditRotatecopyY)
1462 	EVT_MENU(miEditRotatecopyXY, MainWindow::onMenuEditRotatecopyXY)
1463 	EVT_MENU(miEditRotatecopyCorner, MainWindow::onMenuEditRotatecopyCorner)
1464 
1465 	EVT_MENU(miEditRandomizeHeights, MainWindow::onMenuEditRandomizeHeights)
1466 	EVT_MENU(miEditRandomize, MainWindow::onMenuEditRandomize)
1467 	EVT_MENU(miEditSwitchSurfaces, MainWindow::onMenuEditSwitchSurfaces)
1468 	EVT_MENU(miEditInfo, MainWindow::onMenuEditInfo)
1469 	EVT_MENU(miEditAdvanced, MainWindow::onMenuEditAdvanced)
1470 
1471 	EVT_MENU(miViewResetZoomAndPos, MainWindow::onMenuViewResetZoomAndPos)
1472 	EVT_MENU(miViewGrid, MainWindow::onMenuViewGrid)
1473 	EVT_MENU(miViewHeightMap, MainWindow::onMenuViewHeightMap)
1474 	EVT_MENU(miHideWater, MainWindow::onMenuHideWater)
1475 	EVT_MENU(miViewAbout, MainWindow::onMenuViewAbout)
1476 	EVT_MENU(miViewHelp, MainWindow::onMenuViewHelp)
1477 
1478 	EVT_MENU_RANGE(miBrushHeight + 1, miBrushHeight + heightCount, MainWindow::onMenuBrushHeight)
1479 	EVT_MENU_RANGE(miBrushGradient + 1, miBrushGradient + heightCount, MainWindow::onMenuBrushGradient)
1480 	EVT_MENU_RANGE(miBrushSurface + 1, miBrushSurface + surfaceCount, MainWindow::onMenuBrushSurface)
1481 	EVT_MENU_RANGE(miBrushObject + 1, miBrushObject + objectCount, MainWindow::onMenuBrushObject)
1482 	EVT_MENU_RANGE(miBrushResource + 1, miBrushResource + resourceCount, MainWindow::onMenuBrushResource)
1483 	EVT_MENU_RANGE(miBrushStartLocation + 1, miBrushStartLocation + startLocationCount, MainWindow::onMenuBrushStartLocation)
1484 	EVT_MENU_RANGE(miRadius, miRadius + radiusCount, MainWindow::onMenuRadius)
1485 
1486 	EVT_PAINT(MainWindow::onPaint)
1487 
1488 	EVT_TOOL(toolPlayer, MainWindow::onToolPlayer)
1489 END_EVENT_TABLE()
1490 
1491 // =====================================================
1492 // class GlCanvas
1493 // =====================================================
1494 
1495 GlCanvas::GlCanvas(MainWindow *mainWindow, wxWindow *parent, int *args)
1496 #if wxCHECK_VERSION(2, 9, 1)
1497 		: wxGLCanvas(parent, -1, args, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas")) {
1498 	this->context = new wxGLContext(this);
1499 #else
1500 		: wxGLCanvas(parent, -1, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas"), args) {
1501 	this->context = NULL;
1502 #endif
1503 
1504 	this->mainWindow = mainWindow;
1505 }
1506 
1507 GlCanvas::~GlCanvas() {
1508 	delete this->context;
1509 	this->context = NULL;
1510 }
1511 
1512 void GlCanvas::setCurrentGLContext() {
1513 #ifndef __APPLE__
1514 
1515 #if wxCHECK_VERSION(2, 9, 1)
1516 	if(this->context == NULL) {
1517 		this->context = new wxGLContext(this);
1518 	}
1519 #endif
1520 
1521 	if(this->context) {
1522 		this->SetCurrent(*this->context);
1523 	}
1524 #else
1525         this->SetCurrent();
1526 #endif
1527 }
1528 
1529 void translateCoords(wxWindow *wnd, int &x, int &y) {
1530 /*
1531 #ifdef WIN32
1532 	int cx, cy;
1533 	wnd->GetPosition(&cx, &cy);
1534 	x += cx;
1535 	y += cy;
1536 #endif
1537 	*/
1538 }
1539 
1540 // for the mousewheel
1541 void GlCanvas::onMouseWheel(wxMouseEvent &event) {
1542 	if(event.GetWheelRotation()>0) mainWindow->onMouseWheelDown(event);
1543 	else mainWindow->onMouseWheelUp(event);
1544 }
1545 
1546 void GlCanvas::onMouseDown(wxMouseEvent &event) {
1547 	int x, y;
1548 	event.GetPosition(&x, &y);
1549 	translateCoords(this, x, y);
1550 	mainWindow->onMouseDown(event, x, y);
1551 }
1552 
1553 void GlCanvas::onMouseMove(wxMouseEvent &event) {
1554 	int x, y;
1555 	event.GetPosition(&x, &y);
1556 	translateCoords(this, x, y);
1557 	mainWindow->onMouseMove(event, x, y);
1558 }
1559 
1560 void GlCanvas::onKeyDown(wxKeyEvent &event) {
1561 	int x, y;
1562 	event.GetPosition(&x, &y);
1563 	translateCoords(this, x, y);
1564 	mainWindow->onKeyDown(event);
1565 }
1566 
1567 void GlCanvas::onPaint(wxPaintEvent &event) {
1568 //	wxPaintDC dc(this); //N "In a paint event handler must always create a wxPaintDC object even if you do not use it.  (?)
1569 //    mainWindow->program->renderMap(GetClientSize().x, GetClientSize().y);
1570 //	SwapBuffers();
1571 //	event.Skip();
1572 	//printf("gl onPaint skip map\n");
1573   mainWindow->onPaint(event);
1574 }
1575 
1576 BEGIN_EVENT_TABLE(GlCanvas, wxGLCanvas)
1577 	EVT_KEY_DOWN(GlCanvas::onKeyDown)
1578     EVT_MOUSEWHEEL(GlCanvas::onMouseWheel)
1579 	EVT_LEFT_DOWN(GlCanvas::onMouseDown)
1580 	EVT_MOTION(GlCanvas::onMouseMove)
1581 	EVT_PAINT(GlCanvas::onPaint)  // Because the drawing area needs to be repainted too.
1582 END_EVENT_TABLE()
1583 
1584 // ===============================================
1585 //  class SimpleDialog
1586 // ===============================================
1587 
1588 void SimpleDialog::addValue(const string &key, const string &value, const string &help) {
1589 	values.push_back(pair<string, string>(key, value+"|"+help)); // I guess I need map<,> instead but I don't know how to do it
1590 }
1591 
1592 string SimpleDialog::getValue(const string &key) {
1593 	for (unsigned int i = 0; i < values.size(); ++i) {
1594 		if (values[i].first == key) {
1595 			return values[i].second;
1596 		}
1597 	}
1598 	return "";
1599 }
1600 
1601 bool SimpleDialog::show(const string &title, bool wide) {
1602 	Create(NULL, -1, ToUnicode(title));
1603 	wxSizer *sizer2 = new wxBoxSizer(wxVERTICAL);
1604 	wxSizer *sizer = new wxFlexGridSizer(3);
1605 
1606 	vector<wxTextCtrl*> texts;
1607 	for (Values::iterator it = values.begin(); it != values.end(); ++it) {
1608 	    size_t helptextpos = it->second.find_first_of('|');
1609 		sizer->Add(new wxStaticText(this, -1, ToUnicode(it->first)), 0, wxALL, 5);
1610 		wxTextCtrl *text = new wxTextCtrl(this, -1, ToUnicode(it->second.substr(0,helptextpos)));
1611 		if(wide) text->SetMinSize( wxSize((text->GetSize().GetWidth())*4, text->GetSize().GetHeight()));  // 4 time as wide as default
1612 		sizer->Add(text, 0, wxALL, 5);
1613 		texts.push_back(text);
1614 	    sizer->Add(new wxStaticText(this, -1, ToUnicode(it->second.substr(helptextpos+1))), 0, wxALL, 5);
1615 	}
1616 	sizer2->Add(sizer);
1617     sizer2->Add(CreateButtonSizer(wxOK|wxCANCEL),0,wxALIGN_RIGHT); // enable Cancel button
1618 	SetSizerAndFit(sizer2);
1619 
1620 	ShowModal();
1621 	if(m_returnCode==wxID_CANCEL) return false; // don't change values if canceled
1622 
1623 	for (unsigned int i = 0; i < texts.size(); ++i) {
1624 #ifdef WIN32
1625 		const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(wxFNCONV(texts[i]->GetValue()));
1626 		values[i].second = tmp_buf;
1627 #else
1628 		values[i].second = texts[i]->GetValue().ToAscii();
1629 #endif
1630 	}
1631 	return true;
1632 }
1633 
1634 
1635 // ===============================================
1636 //  class App
1637 // ===============================================
1638 
1639 bool App::OnInit() {
1640 	SystemFlags::VERBOSE_MODE_ENABLED  = false;
1641 	SystemFlags::ENABLE_THREADED_LOGGING = false;
1642 
1643 	string fileparam;
1644 	if(argc==2){
1645 		if(argv[1][0]=='-') {   // any flag gives help and exits program.
1646 			std::cout << "MegaGlest map editor " << mapeditorVersionString << " [Using " << (const char *)wxConvCurrent->cWX2MB(wxVERSION_STRING) << "]" << std::endl << std::endl;
1647 			std::cout << "glest_map_editor [MGM FILE]" << std::endl << std::endl;
1648 			std::cout << "Creates or edits glest/megaglest maps."  << std::endl;
1649 			std::cout << "Draw with left mouse button"  << std::endl;
1650 			std::cout << "Move map with right mouse button"  << std::endl;
1651 			std::cout << "Zoom with middle mouse button or mousewheel"  << std::endl;
1652 
1653 //			std::cout << " ~ more helps should be written here ~"  << std::endl;
1654 			std::cout << std::endl;
1655 			exit (0);
1656 		}
1657 //#if defined(__MINGW32__)
1658 		const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(argv[1]);
1659 		fileparam = tmp_buf;
1660 
1661 #ifdef WIN32
1662 		auto_ptr<wchar_t> wstr(Ansi2WideString(fileparam.c_str()));
1663 		fileparam = utf8_encode(wstr.get());
1664 #endif
1665 
1666 //#else
1667 //        fileparam = wxFNCONV(argv[1]);
1668 //#endif
1669 	}
1670 
1671 #if defined(wxMAJOR_VERSION) && defined(wxMINOR_VERSION) && defined(wxRELEASE_NUMBER) && defined(wxSUBRELEASE_NUMBER)
1672 	printf("Using wxWidgets version [%d.%d.%d.%d]\n",wxMAJOR_VERSION,wxMINOR_VERSION,wxRELEASE_NUMBER,wxSUBRELEASE_NUMBER);
1673 #endif
1674 
1675 	wxString exe_path = wxStandardPaths::Get().GetExecutablePath();
1676     //wxString path_separator = wxFileName::GetPathSeparator();
1677     //exe_path = exe_path.BeforeLast(path_separator[0]);
1678     //exe_path += path_separator;
1679 
1680 	string appPath;
1681 //#if defined(__MINGW32__)
1682 
1683 #ifdef WIN32
1684 	const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(wxFNCONV(exe_path));
1685 	appPath = tmp_buf;
1686 
1687 	auto_ptr<wchar_t> wstr(Ansi2WideString(appPath.c_str()));
1688 	appPath = utf8_encode(wstr.get());
1689 #else
1690 	appPath = wxFNCONV(exe_path);
1691 #endif
1692 
1693 //#else
1694 //		const wxWX2MBbuf tmp_buf = wxConvCurrent->cWX2MB(wxFNCONV(exe_path));
1695 //		appPath = tmp_buf;
1696 //#endif
1697 
1698 	mainWindow = new MainWindow(appPath);
1699 	mainWindow->Show();
1700 	mainWindow->init(fileparam);
1701 	mainWindow->Update();
1702 
1703 #ifdef WIN32
1704 	wxPoint pos = mainWindow->GetScreenPosition();
1705 	wxSize size = mainWindow->GetSize();
1706 
1707 	mainWindow->SetSize(pos.x, pos.y, 1, 1, wxSIZE_FORCE);
1708 	//mainWindow->Update();
1709 
1710 	mainWindow->SetSize(pos.x, pos.y, size.x-1, size.y, wxSIZE_FORCE);
1711 	mainWindow->Update();
1712 #endif
1713 
1714 	return true;
1715 }
1716 
1717 int App::MainLoop() {
1718 	try {
1719 		//throw megaglest_runtime_error("test");
1720 		return wxApp::MainLoop();
1721 	}
1722 	catch (const exception &e) {
1723 		MsgDialog(NULL, ToUnicode(e.what()), wxT("Exception")).ShowModal();
1724 	}
1725 	return 0;
1726 }
1727 
1728 int App::OnExit() {
1729 	SystemFlags::Close();
1730 	SystemFlags::SHUTDOWN_PROGRAM_MODE=true;
1731 
1732 	return 0;
1733 }
1734 
1735 MsgDialog::MsgDialog(wxWindow *parent,
1736                      const wxString& message,
1737                      const wxString& caption,
1738                      long style,
1739 					 const wxPoint& pos) {
1740 
1741 	m_sizerText = NULL;
1742     if ( !wxDialog::Create(parent, wxID_ANY, caption,
1743                            pos, wxDefaultSize,
1744 						   style) ) {
1745         return;
1746 	}
1747     m_sizerText = new wxBoxSizer(wxVERTICAL);
1748     wxStaticText *label = new wxStaticText(this, wxID_ANY, message);
1749     wxFont font(*wxNORMAL_FONT);
1750     font.SetPointSize(font.GetPointSize());
1751     font.SetWeight(wxFONTWEIGHT_NORMAL);
1752     label->SetFont(font);
1753 
1754     m_sizerText->Add(label, wxSizerFlags().Centre().Border());
1755 
1756     wxSizer *sizerIconAndText = new wxBoxSizer(wxHORIZONTAL);
1757     sizerIconAndText->Add(m_sizerText, wxSizerFlags(1).Expand());
1758 
1759     wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
1760     sizerTop->Add(sizerIconAndText, wxSizerFlags(1).Expand().Border());
1761 
1762     wxSizer *sizerBtns = CreateButtonSizer(wxOK);
1763     if ( sizerBtns )
1764     {
1765         sizerTop->Add(sizerBtns, wxSizerFlags().Expand().Border());
1766     }
1767 
1768     SetSizerAndFit(sizerTop);
1769     CentreOnScreen();
1770 }
1771 MsgDialog::~MsgDialog() {
1772 
1773 }
1774 
1775 }// end namespace
1776 
1777 IMPLEMENT_APP(MapEditor::App)
1778