1 /* editWindows.cc
2 Implements all the windows in the editMode
3
4 Copyright (C) 2003-2004 Mathias Broxvall
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "editWindows.h"
22 #include "editMode.h"
23 #include "map.h"
24 #include "menuMode.h"
25 #include "menusystem.h"
26 #include "settings.h"
27
28 #include <SDL2/SDL_keyboard.h>
29 #include <SDL2/SDL_keycode.h>
30 #include <SDL2/SDL_mouse.h>
31 #include <SDL2/SDL_timer.h>
32 #include <dirent.h>
33
EMenuWindow()34 EMenuWindow::EMenuWindow() : MyWindow(0, 0, screenWidth, 30) {
35 activeSubID = -1;
36 activeSubWindow = NULL;
37 spacing = screenWidth / N_SUBMENUS;
38 for (int i = 0; i < N_SUBMENUS; i++) subWindows[i] = new ESubWindow(i, spacing * i, 30);
39 }
~EMenuWindow()40 EMenuWindow::~EMenuWindow() {
41 for (int i = 0; i < N_SUBMENUS; i++) delete subWindows[i];
42 }
refreshChildPositions()43 void EMenuWindow::refreshChildPositions() {
44 this->resize(screenWidth, 30);
45 spacing = screenWidth / N_SUBMENUS;
46 for (int i = 0; i < N_SUBMENUS; i++) { subWindows[i]->moveTo(spacing * i, 30); }
47 }
48
draw()49 void EMenuWindow::draw() {
50 int fontSize = 20; // 16;
51 char str[256];
52
53 this->MyWindow::draw();
54 for (int i = 0; i < N_SUBMENUS; i++) {
55 snprintf(str, sizeof(str), "F%d %s", i + 1, cMenuNames[i]);
56 addText_Center(CODE_FROM_MENU(i), fontSize / 2, height / 2, str,
57 spacing * i + spacing / 2);
58 }
59 }
mouseDown(int,int,int)60 void EMenuWindow::mouseDown(int /*state*/, int /*x*/, int /*y*/) {
61 int code = getSelectedArea();
62 int menu = CODE_TO_MENU(code);
63 if (menu >= 0 && menu < N_SUBMENUS) openSubMenu(menu);
64 }
openSubMenu(int id)65 void EMenuWindow::openSubMenu(int id) {
66 if (activeSubWindow) activeSubWindow->remove();
67 if (activeSubID == id) { /* Close window instead if already opened */
68 activeSubID = -1;
69 return;
70 }
71 activeSubID = id;
72 activeSubWindow = subWindows[id];
73 activeSubWindow->attach();
74 }
keyToMenuEntry(int key,int shift) const75 int EMenuWindow::keyToMenuEntry(int key, int shift) const {
76 /* Convert keypad numbers to normal numbers */
77 if (key >= SDLK_KP_0 && key <= SDLK_KP_9) key = '0' + key - SDLK_KP_0;
78 if (key == SDLK_KP_PLUS) key = '+';
79 if (key == SDLK_KP_MINUS) key = '-';
80
81 /* Make all keys lower case since SHIFT and uppercase keys have
82 a special meaning */
83 if (shift) key = key - 'A' + 'a';
84 if (key == SDLK_UP) key = 'U';
85 if (key == SDLK_LEFT) key = 'L';
86 if (key == SDLK_RIGHT) key = 'R';
87 if (key == SDLK_DOWN) key = 'D';
88
89 /* Search current menu first */
90 int i = activeSubID;
91 if (i != -1)
92 for (int j = 0; cKeyShortcuts[i][j]; j++)
93 if (cKeyShortcuts[i][j] == key) return i * MAX_MENU_ENTRIES + j;
94 for (i = 0; i < N_SUBMENUS; i++)
95 for (int j = 0; cKeyShortcuts[i][j]; j++)
96 if (cKeyShortcuts[i][j] == key) return i * MAX_MENU_ENTRIES + j;
97 return -1;
98 }
key(int key,int shift,int,int)99 void EMenuWindow::key(int key, int shift, int /*x*/, int /*y*/) {
100 if (key >= SDLK_F1 && key <= SDLK_F12) {
101 int menu = key - SDLK_F1;
102 if (menu >= 0 && menu < N_SUBMENUS) openSubMenu(menu);
103 } else {
104 int command = keyToMenuEntry(key, shift);
105 if (command >= 0) EditMode::editMode->doCommand(command);
106 }
107 }
108
ESubWindow(int id,int x,int y)109 ESubWindow::ESubWindow(int id, int x, int y) : MyWindow(x, y, 100, 0) {
110 fontSize = 16;
111
112 this->id = id;
113 rows = countRows();
114 resize(180, fontSize * rows + 2);
115 }
116
draw()117 void ESubWindow::draw() {
118 char str[256];
119
120 this->MyWindow::draw();
121 for (int i = 0; i < rows; i++) {
122 if (cMenuEntries[id][i][0] == '*') {
123 snprintf(str, 255, "%s", cMenuEntries[id][i] + 1);
124 addText_Left(0, fontSize / 2, y + 2 + fontSize * i + fontSize / 2, str,
125 x + 2 + fontSize / 2);
126 } else {
127 if (cMenuEntries[id][i][0] == '/')
128 snprintf(str, 255, "%s", cMenuEntries[id][i] + 1); /* Shortcut already part of name */
129 else
130 snprintf(str, 255, "%c %s", cKeyShortcuts[id][i], cMenuEntries[id][i]);
131
132 addText_Left(CODE_FROM_MENUENTRY(id * MAX_MENU_ENTRIES + i), fontSize / 2,
133 y + 2 + fontSize * i + fontSize / 2, str, x + 2 + fontSize / 2);
134 if (id == FLAGS_MENU && i < 9) {
135 /* The flags current status can only be added if we have a map loaded */
136 if (EditMode::editMode->map) {
137 Cell& cell =
138 EditMode::editMode->map->cell(EditMode::editMode->x, EditMode::editMode->y);
139 if (cell.flags & (1 << i) || (cell.flags & (1 << 11) && i == 9))
140 addText_Left(CODE_FROM_MENUENTRY(id * MAX_MENU_ENTRIES + i), fontSize / 2,
141 y + 2 + fontSize * i + fontSize / 2, _("y"),
142 x + 2 + fontSize / 2 + 160);
143 else
144 addText_Left(CODE_FROM_MENUENTRY(id * MAX_MENU_ENTRIES + i), fontSize / 2,
145 y + 2 + fontSize * i + fontSize / 2, _("n"),
146 x + 2 + fontSize / 2 + 160);
147 }
148 } else if (id == FLAGS_MENU && i == 10) {
149 /* The current texture can only be added if we have a map loaded */
150 if (EditMode::editMode->map) {
151 Cell& cell =
152 EditMode::editMode->map->cell(EditMode::editMode->x, EditMode::editMode->y);
153 snprintf(str, sizeof(str), "%d", cell.texture);
154 addText_Left(CODE_FROM_MENUENTRY(id * MAX_MENU_ENTRIES + i), fontSize / 2,
155 y + 2 + fontSize * i + fontSize / 2, str, x + 2 + fontSize / 2 + 160);
156 }
157 }
158 }
159 }
160 }
161
162 /** Count how many menu entries exists for a given menu. Uses the length of the shortcut key
163 * string for this */
countRows() const164 int ESubWindow::countRows() const {
165 for (int i = 0; i < MAX_MENU_ENTRIES; i++)
166 if (!cMenuEntries[id][i]) return i;
167 return MAX_MENU_ENTRIES;
168 }
169
mouseDown(int,int,int)170 void ESubWindow::mouseDown(int /*state*/, int /*x*/, int /*y*/) {
171 int code = getSelectedArea();
172 int menuentry = CODE_TO_MENUENTRY(code);
173 if (menuentry >= id * MAX_MENU_ENTRIES && menuentry < (id + 1) * MAX_MENU_ENTRIES)
174 EditMode::editMode->doCommand(menuentry);
175 }
176
EStatusWindow()177 EStatusWindow::EStatusWindow() : MyWindow(0, screenHeight - 110, screenWidth, 110) {}
178
draw()179 void EStatusWindow::draw() {
180 int fontSize = 24;
181
182 this->MyWindow::draw();
183 if (!EditMode::editMode->map) return;
184 int row1 = y + fontSize / 2 + 2;
185 int row2 = row1 + fontSize + 2;
186 int row3 = row2 + fontSize + 2;
187 int row4 = row3 + fontSize + 2;
188 int col0 = x + 2 + fontSize / 2;
189 int col1 = x + 2 + fontSize / 2 + fontSize * 10;
190 int area3x = x + 520;
191 char str[512];
192
193 const char* editModeNames[6] = {_("height"), _("color"), _("water"),
194 _("velocity"), _("lines"), _("feature")};
195
196 snprintf(str, 255, _("Pos: %d,%d"), EditMode::editMode->x, EditMode::editMode->y);
197 addText_Left(0, fontSize / 2, row2, str, col0);
198 snprintf(str, 255, _("Increment: %3.2f"), EditMode::editMode->scale);
199 addText_Left(CODE_INCREMENT, fontSize / 2, row3, str, col0);
200 snprintf(str, 255, _("Edit: %s"), editModeNames[EditMode::editMode->currentEditMode]);
201 addText_Left(CODE_EDITMODE, fontSize / 2, row4, str, col0);
202
203 /* Small separator between area 1 - 2 */
204 draw2DRectangle(col1 - fontSize - 1, y, 2, height, 0., 0., 1., 1., 0.5, 0.5, 0.5, 1.0);
205 /* Small separator between area 2 - 3 */
206 draw2DRectangle(area3x - 1, y, 2, height, 0., 0., 1., 1., 0.5, 0.5, 0.5, 1.0);
207
208 /* TODO. Make the height/colour etc. text selectable areas
209 with the same effect as corresponding menu choice */
210
211 Cell& cell = EditMode::editMode->map->cell(EditMode::editMode->x, EditMode::editMode->y);
212
213 if (EditMode::editMode->currentEditMode == EDITMODE_HEIGHT) {
214 addText_Left(0, fontSize / 2, row1, _("Heights"), col1 + fontSize * 1);
215 snprintf(str, sizeof(str), "%2.1f", cell.heights[3]);
216 addText_Left(CODE_FROM_MENUENTRY(EDIT_UPPER), fontSize / 2, row2, str,
217 col1 + fontSize * 2);
218 snprintf(str, sizeof(str), "%2.1f", cell.heights[1]);
219 addText_Left(CODE_FROM_MENUENTRY(EDIT_LEFT), fontSize / 2, row3, str, col1 + fontSize * 0);
220 snprintf(str, sizeof(str), "%2.1f", cell.heights[Cell::CENTER]);
221 addText_Left(CODE_FROM_MENUENTRY(EDIT_CENTER), fontSize / 2, row3, str,
222 col1 + fontSize * 2);
223 snprintf(str, sizeof(str), "%2.1f", cell.heights[2]);
224 addText_Left(CODE_FROM_MENUENTRY(EDIT_RIGHT), fontSize / 2, row3, str,
225 col1 + fontSize * 4);
226 snprintf(str, sizeof(str), "%2.1f", cell.heights[0]);
227 addText_Left(CODE_FROM_MENUENTRY(EDIT_BOTTOM), fontSize / 2, row4, str,
228 col1 + fontSize * 2);
229 } else if (EditMode::editMode->currentEditMode == EDITMODE_WATER) {
230 addText_Left(0, fontSize / 2, row1, _("Water heights"), col1 + fontSize * 1);
231 snprintf(str, sizeof(str), "%2.1f", cell.waterHeights[3]);
232 addText_Left(CODE_FROM_MENUENTRY(EDIT_UPPER), fontSize / 2, row2, str,
233 col1 + fontSize * 2);
234 snprintf(str, sizeof(str), "%2.1f", cell.waterHeights[1]);
235 addText_Left(CODE_FROM_MENUENTRY(EDIT_LEFT), fontSize / 2, row3, str, col1 + fontSize * 0);
236 snprintf(str, sizeof(str), "%2.1f", cell.waterHeights[Cell::CENTER]);
237 addText_Left(CODE_FROM_MENUENTRY(EDIT_CENTER), fontSize / 2, row3, str,
238 col1 + fontSize * 2);
239 snprintf(str, sizeof(str), "%2.1f", cell.waterHeights[2]);
240 addText_Left(CODE_FROM_MENUENTRY(EDIT_RIGHT), fontSize / 2, row3, str,
241 col1 + fontSize * 4);
242 snprintf(str, sizeof(str), "%2.1f", cell.waterHeights[0]);
243 addText_Left(CODE_FROM_MENUENTRY(EDIT_BOTTOM), fontSize / 2, row4, str,
244 col1 + fontSize * 2);
245 } else if (EditMode::editMode->currentEditMode == EDITMODE_COLOR) {
246 snprintf(str, 255, _("red: %2.2f"), EditMode::editMode->color.f0());
247 addText_Left(CODE_FROM_MENUENTRY(COLOR_RED), fontSize / 2, row2, str, col1 + fontSize * 3);
248 snprintf(str, 255, _("green: %2.2f"), EditMode::editMode->color.f1());
249 addText_Left(CODE_FROM_MENUENTRY(COLOR_GREEN), fontSize / 2, row3, str,
250 col1 + fontSize * 3);
251 snprintf(str, 255, _("blue: %2.2f"), EditMode::editMode->color.f2());
252 addText_Left(CODE_FROM_MENUENTRY(COLOR_BLUE), fontSize / 2, row4, str,
253 col1 + fontSize * 3);
254 snprintf(str, 255, _("alpha: %2.2f"), EditMode::editMode->color.f3());
255 addText_Left(CODE_FROM_MENUENTRY(COLOR_ALPHA), fontSize / 2, row1, str,
256 col1 + fontSize * 3);
257
258 draw2DRectangle(col1, row2, 2 * fontSize, row4 - row2, 0., 0., 1., 1.,
259 EditMode::editMode->color.f0(), EditMode::editMode->color.f1(),
260 EditMode::editMode->color.f2(), EditMode::editMode->color.f3());
261 } else if (EditMode::editMode->currentEditMode == EDITMODE_VELOCITY) {
262 Cell& cell = EditMode::editMode->map->cell(EditMode::editMode->x, EditMode::editMode->y);
263 snprintf(str, 255, _("dx: %2.2f"), cell.velocity[0]);
264 addText_Left(0, fontSize / 2, row1, str, col1 + fontSize * 1);
265 snprintf(str, 255, _("dy: %2.2f"), cell.velocity[1]);
266 addText_Left(0, fontSize / 2, row1, str, col1 + fontSize * 7);
267 } else if (EditMode::editMode->currentEditMode == EDITMODE_NOLINES) {
268 addText_Left(0, fontSize / 2, row1, _("Lines"), col1);
269
270 GLfloat line_off[4][4] = {
271 {1., 1., 1., 1.}, {1., 1., 1., 1.}, {1., 1., 1., 1.}, {1., 1., 1., 1.}};
272 GLfloat line_on[4][4] = {
273 {0., 0., 0., 1.}, {0., 0., 0., 1.}, {0., 0., 0., 1.}, {0., 0., 0., 1.}};
274 GLfloat txco[4][2] = {{0., 0.}, {0., 0.}, {0., 0.}, {0., 0.}};
275
276 GLfloat r = 1.5;
277 GLfloat lineA[4][2] = {{col1 + 0.f, row3 - r},
278 {col1 + 0.f, row3 + r},
279 {col1 + fontSize * 1.5f, row2 - r},
280 {col1 + fontSize * 1.5f, row2 + r}};
281 draw2DQuad(lineA, txco, (cell.flags & CELL_NOLINENORTH) ? line_off : line_on);
282
283 GLfloat lineB[4][2] = {{col1 + fontSize * 3.f, row3 - r},
284 {col1 + fontSize * 3.f, row3 + r},
285 {col1 + fontSize * 1.5f, row2 - r},
286 {col1 + fontSize * 1.5f, row2 + r}};
287 draw2DQuad(lineB, txco, (cell.flags & CELL_NOLINEEAST) ? line_off : line_on);
288
289 GLfloat lineC[4][2] = {{col1 + fontSize * 3.f, row3 - r},
290 {col1 + fontSize * 3.f, row3 + r},
291 {col1 + fontSize * 1.5f, row4 - r},
292 {col1 + fontSize * 1.5f, row4 + r}};
293 draw2DQuad(lineC, txco, (cell.flags & CELL_NOLINESOUTH) ? line_off : line_on);
294
295 GLfloat lineD[4][2] = {{col1 + 0.f, row3 - r},
296 {col1 + 0.f, row3 + r},
297 {col1 + fontSize * 1.5f, row4 - r},
298 {col1 + fontSize * 1.5f, row4 + r}};
299 draw2DQuad(lineD, txco, (cell.flags & CELL_NOLINEWEST) ? line_off : line_on);
300 } else if (EditMode::editMode->currentEditMode == EDITMODE_FEATURES) {
301 const char* feature = "";
302 switch (EditMode::editMode->currentFeature) {
303 case FEATURE_SPIKE:
304 feature = _("spike");
305 break;
306 case FEATURE_SMALL_HILL:
307 feature = _("small hill");
308 break;
309 case FEATURE_MEDIUM_HILL:
310 feature = _("medium hill");
311 break;
312 case FEATURE_LARGE_HILL:
313 feature = _("large hill");
314 break;
315 case FEATURE_HUGE_HILL:
316 feature = _("huge hill");
317 break;
318 case FEATURE_SMALL_SMOOTH:
319 feature = _("small smooth");
320 break;
321 case FEATURE_LARGE_SMOOTH:
322 feature = _("large smooth");
323 break;
324 }
325 addText_Center(0, fontSize / 2, row1, feature, (col1 + area3x) / 2);
326 }
327
328 /* Draw area 3, eg. some extra info */
329 snprintf(str, sizeof(str), "%s/%s", EditMode::editMode->pathname,
330 EditMode::editMode->levelname);
331 addText_Left(0, fontSize / 3, row1, str, area3x + 10);
332 }
mouseDown(int button,int,int)333 void EStatusWindow::mouseDown(int button, int /*x*/, int /*y*/) {
334 int code = getSelectedArea();
335 if (code == CODE_INCREMENT) {
336 if (button == SDL_BUTTON_LEFT)
337 EditMode::editMode->doCommand(EDIT_RAISE_INCREMENT);
338 else
339 EditMode::editMode->doCommand(EDIT_LOWER_INCREMENT);
340 }
341 if (code == CODE_EDITMODE)
342 EditMode::editMode->currentEditMode =
343 (EditMode::editMode->currentEditMode +
344 ((button == SDL_BUTTON_LEFT) ? 1 : N_EDITMODES - 1)) %
345 N_EDITMODES;
346
347 if (CODE_TO_MENUENTRY(code) >= 0 && CODE_TO_MENUENTRY(code) <= 170)
348 EditMode::editMode->doCommand(CODE_TO_MENUENTRY(code));
349 }
350
351 /***********************************
352 QuitWindow
353 ***********************************/
354
EQuitWindow()355 EQuitWindow::EQuitWindow() : MyWindow(0, 0, 300, 80) {}
draw()356 void EQuitWindow::draw() {
357 int fontSize = 24;
358 this->MyWindow::draw();
359 int row1 = y + fontSize + 2;
360 int row2 = row1 + fontSize + 2;
361
362 addText_Center(0, fontSize / 2, row1, _("Quit without saving?"), x + width / 2);
363 addText_Center(CODE_YES, fontSize / 2, row2, _("Yes"), x + fontSize * 5);
364 addText_Center(CODE_NO, fontSize / 2, row2, _("No"), x + width - fontSize * 5);
365 }
mouseDown(int,int,int)366 void EQuitWindow::mouseDown(int /*state*/, int /*x*/, int /*y*/) {
367 int code = getSelectedArea();
368 if (code == CODE_YES)
369 yes();
370 else if (code == CODE_NO)
371 no();
372 }
373
yes()374 void EQuitWindow::yes() {
375 remove();
376 EditMode::editMode->closeMap();
377 Settings::settings->doSpecialLevel = 0;
378 GameMode::activate(MenuMode::init());
379 }
380
no()381 void EQuitWindow::no() { remove(); }
382
383 /***********************************
384 SaveWindow
385 ***********************************/
386
387 /* The private variable saveCnt is used to delay the save action
388 until we have drawing the text "saving..." on the screen. The actual
389 saving will be done during the drawing cycle when saveCnt reaches 1 */
ESaveWindow()390 ESaveWindow::ESaveWindow() : MyWindow(0, 0, 400, 80) { saveCnt = 0; }
draw()391 void ESaveWindow::draw() {
392 int fontSize = 24;
393 this->MyWindow::draw();
394 int row1 = y + fontSize + 2;
395 int row2 = row1 + fontSize + 2;
396 char str[512];
397
398 if (!saveCnt) {
399 addText_Center(0, fontSize / 2, row1, _("Save map?"), x + width / 2);
400 addText_Center(CODE_YES, fontSize / 2, row2, _("Yes"), x + fontSize * 5);
401 addText_Center(CODE_NO, fontSize / 2, row2, _("No"), x + width - fontSize * 5);
402 } else if (saveCnt == 2) {
403 addText_Center(0, fontSize / 2, row1, _("Saving"), x + width / 2);
404 snprintf(str, sizeof(str), "%s/levels/%s", effectiveLocalDir,
405 EditMode::editMode->levelname);
406 // addText_Center(0,fontSize/2,row2,str,x+width/2);
407 addText_Center(0, fontSize / 3, row2, str, x + width / 2);
408 saveCnt = 1;
409 } else if (saveCnt == 1) {
410 struct timespec t0 = getMonotonicTime();
411 EditMode::editMode->saveMap();
412 remove();
413 saveCnt = 0;
414 /* Make sure it takes atleast three seconds to save, so user can see the message above
415 * properly */
416 struct timespec t1;
417 do {
418 t1 = getMonotonicTime();
419 SDL_Delay(10);
420 } while (getTimeDifference(t0, t1) < 3.0);
421 }
422 }
mouseDown(int,int,int)423 void ESaveWindow::mouseDown(int /*state*/, int /*x*/, int /*y*/) {
424 int code = getSelectedArea();
425 if (code == CODE_YES)
426 yes();
427 else if (code == CODE_NO)
428 no();
429 }
430
yes()431 void ESaveWindow::yes() { saveCnt = 2; }
432
no()433 void ESaveWindow::no() { remove(); }
434
435 /***********************************
436 CloseWindow
437 ***********************************/
438
ECloseWindow()439 ECloseWindow::ECloseWindow() : MyWindow(0, 0, 300, 80) {}
draw()440 void ECloseWindow::draw() {
441 int fontSize = 24;
442 this->MyWindow::draw();
443 int row1 = y + fontSize + 2;
444 int row2 = row1 + fontSize + 2;
445
446 addText_Center(0, fontSize / 2, row1, _("Close without saving?"), x + width / 2);
447 addText_Center(CODE_YES, fontSize / 2, row2, _("Yes"), x + fontSize * 5);
448 addText_Center(CODE_NO, fontSize / 2, row2, _("No"), x + width - fontSize * 5);
449 }
mouseDown(int,int,int)450 void ECloseWindow::mouseDown(int /*state*/, int /*x*/, int /*y*/) {
451 int code = getSelectedArea();
452 if (code == CODE_YES)
453 yes();
454 else if (code == CODE_NO)
455 no();
456 }
457
yes()458 void ECloseWindow::yes() {
459 remove();
460 EditMode::editMode->closeMap();
461 }
462
no()463 void ECloseWindow::no() { remove(); }
464
465 /***********************************
466 NewWindow
467 ***********************************/
468
ENewWindow()469 ENewWindow::ENewWindow() : MyWindow(0, 0, 300, 100) { name[0] = 0; }
draw()470 void ENewWindow::draw() {
471 int fontSize = 24;
472 this->MyWindow::draw();
473 int row1 = y + fontSize + 2;
474 int row2 = row1 + fontSize + 2;
475 int row3 = row1 + fontSize * 2 + 2;
476
477 addText_Center(0, fontSize / 2, row1, _("Name of map"), x + width / 2);
478 addText_Center(0, fontSize / 2, row2, name, x + width / 2);
479 addText_Left(CODE_CANCEL, fontSize / 2, row3, _("Cancel"), x + fontSize / 2 + 2 + 10);
480 addText_Right(CODE_OK, fontSize / 2, row3, _("Open"), x + width - fontSize / 2 - 2);
481 }
mouseDown(int,int,int)482 void ENewWindow::mouseDown(int /*state*/, int /*x*/, int /*y*/) {
483 int code = getSelectedArea();
484 if (code == CODE_CANCEL)
485 remove();
486 else if (code == CODE_OK) {
487 EditMode::editMode->loadMap(name);
488 remove();
489 }
490 }
key(int key,int shift,int,int)491 void ENewWindow::key(int key, int shift, int /*x*/, int /*y*/) {
492 if (key == SDLK_BACKSPACE) {
493 int len = strlen(name);
494 if (len > 0) name[len - 1] = 0;
495 } else if ((key < 128 && isalnum(key)) || key == ' ' || key == '_' || key == '-') {
496 if (shift && islower(key)) key = toupper(key);
497 int len = strlen(name);
498 if (len >= 255) return;
499 name[len++] = key;
500 name[len] = 0;
501 }
502 }
503
504 /***********************************
505 OpenWindow
506 ***********************************/
507 #define PAGE_SIZE 8
508
EOpenWindow()509 EOpenWindow::EOpenWindow() : MyWindow(0, 0, 400, 300) {
510 nNames = 0;
511 currPage = 0;
512 memset(names, 0, sizeof(names));
513 }
draw()514 void EOpenWindow::draw() {
515 int fontSize = 24;
516 this->MyWindow::draw();
517
518 int nPages = (nNames + PAGE_SIZE - 1) / PAGE_SIZE;
519 int row1 = y + fontSize + 2;
520 int rowN = y + 300 - fontSize;
521 int col0 = x + 2 + fontSize / 2;
522 int colN = x + 400 - fontSize / 2;
523 char str[256];
524
525 addText_Center(0, fontSize / 2, row1, _("Open map"), x + width / 2);
526 for (int i = 0; i < PAGE_SIZE; i++) {
527 int n = i + currPage * PAGE_SIZE;
528 if (n < nNames)
529 addText_Left(CODE_MAP0 + n, fontSize / 2, row1 + fontSize * (i + 1), names[n], col0);
530 }
531
532 snprintf(str, sizeof(str), _("page %d / %d"), currPage + 1, nPages);
533 addText_Left(CODE_PAGE, fontSize / 2, rowN, str, col0);
534 addText_Right(CODE_CANCEL, fontSize / 2, rowN, _("Cancel"), colN);
535 }
mouseDown(int button,int,int)536 void EOpenWindow::mouseDown(int button, int /*x*/, int /*y*/) {
537 int code = getSelectedArea();
538 int nPages = (nNames + PAGE_SIZE - 1) / PAGE_SIZE;
539
540 if (code >= CODE_MAP0 && code <= CODE_MAP0 + nNames) {
541 /* A map has been selected */
542 int mapNumber = code - CODE_MAP0;
543 EditMode::editMode->loadMap(names[mapNumber]);
544 remove();
545 } else
546 switch (code) {
547 case CODE_CANCEL:
548 remove();
549 break;
550 case CODE_PAGE:
551 if (button == SDL_BUTTON_LEFT)
552 currPage = (currPage + 1) % nPages;
553 else
554 currPage = (currPage + nPages - 1) % nPages;
555 break;
556 }
557 }
558
sortstrcmp(const void * n1,const void * n2)559 int sortstrcmp(const void* n1, const void* n2) { return strcmp((char*)n1, (char*)n2); }
560
refreshMapList()561 void EOpenWindow::refreshMapList() {
562 char str[512];
563 struct dirent* dirent;
564 DIR* dir;
565
566 nNames = 0;
567 currPage = 0;
568
569 /* Add all maps from the home directory */
570 snprintf(str, sizeof(str), "%s/levels", effectiveLocalDir);
571 dir = opendir(str);
572 if (dir) {
573 /* This iteratives over all files there */
574 while ((dirent = readdir(dir))) {
575 /* And adds the ones ending with .map */
576 if (strlen(dirent->d_name) > 4 &&
577 (strcmp(&dirent->d_name[strlen(dirent->d_name) - 4], ".map") == 0)) {
578 strncpy(str, dirent->d_name, sizeof(str));
579 str[strlen(str) - 4] = 0; /* Remove .map ending */
580 strncpy(names[nNames++], str, 256);
581 }
582 }
583 closedir(dir);
584 }
585 qsort(names, nNames, sizeof(char[256]), sortstrcmp);
586 int divNames = nNames;
587
588 /* Add all maps from the share directory */
589 snprintf(str, sizeof(str), "%s/levels", effectiveShareDir);
590 dir = opendir(str);
591 if (dir) {
592 /* This iteratives over all files there */
593 while ((dirent = readdir(dir))) {
594 /* And adds the ones ending with .map *but* not if they already where added from the home
595 * directory */
596 if (strlen(dirent->d_name) > 4 &&
597 (strcmp(&dirent->d_name[strlen(dirent->d_name) - 4], ".map") == 0)) {
598 strncpy(str, dirent->d_name, sizeof(str));
599 str[strlen(str) - 4] = 0; /* Remove .map ending */
600 int i;
601 for (i = 0; i < nNames; i++)
602 if (strncasecmp(str, names[i], 256) == 0) break;
603 if (i == nNames) strncpy(names[nNames++], str, 256);
604 }
605 }
606 closedir(dir);
607 }
608 qsort(&names[divNames][0], nNames - divNames, sizeof(char[256]), sortstrcmp);
609 }
610