1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2010 by The Allacrost Project
3 // All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /*!****************************************************************************
11 * \file editor.cpp
12 * \author Philip Vorsilak, gorzuate@allacrost.org
13 * \brief Source file for editor's main window and user interface.
14 *****************************************************************************/
15
16 #include "editor.h"
17
18 using namespace hoa_script;
19 using namespace hoa_utils;
20 using namespace hoa_editor;
21 using namespace hoa_video;
22 using namespace std;
23
Editor()24 Editor::Editor() : QMainWindow(),
25 _skill_editor(NULL)
26 {
27 // create the undo stack
28 _undo_stack = new QUndoStack();
29
30 // set scollview to NULL because it's being checked inside _TilesEnableActions
31 _ed_scrollview = NULL;
32
33 // create actions, menus, and toolbars
34 _CreateActions();
35 _CreateMenus();
36 _CreateToolbars();
37 _TilesEnableActions();
38
39 connect(_undo_stack, SIGNAL(canRedoChanged(bool)), _redo_action, SLOT(setEnabled(bool)));
40 connect(_undo_stack, SIGNAL(canUndoChanged(bool)), _undo_action, SLOT(setEnabled(bool)));
41
42 // initialize viewing items
43 _grid_on = false;
44 _select_on = false;
45 _ll_on = false;
46 _ml_on = false;
47 _ul_on = false;
48 _ol_on = false;
49 _coord_type = 0;
50
51 // create the main widget and layout
52 _ed_splitter = new QSplitter(this);
53 _ed_splitter->setOrientation(Qt::Vertical);
54 _ed_tabs = NULL;
55 setCentralWidget(_ed_splitter);
56 resize(600, 400);
57
58 // set the window icon
59 setWindowIcon(QIcon("img/logos/program_icon.bmp"));
60
61 // create error message for exceeding maximum number of contexts
62 _error_max_contexts = new QErrorMessage(this);
63
64 // create the video engine's singleton
65 // VideoManager = VideoEngine::SingletonCreate();
66 // Commented out grid and tileset editor create and destroy VideoManager
67
68 } // Editor constructor
69
~Editor()70 Editor::~Editor()
71 {
72 if (_ed_scrollview != NULL)
73 delete _ed_scrollview;
74 if (_ed_tabs != NULL)
75 delete _ed_tabs;
76 delete _ed_splitter;
77 if (_skill_editor != NULL)
78 delete _skill_editor;
79 delete _undo_stack;
80
81 ScriptEngine::SingletonDestroy();
82 VideoEngine::SingletonDestroy();
83 } // Editor destructor
84
85
86
87 // ********** Protected function **********
88
closeEvent(QCloseEvent *)89 void Editor::closeEvent(QCloseEvent*)
90 {
91 _FileQuit();
92 } // closeEvent(...)
93
94 // ********** Private slots **********
95
_FileMenuSetup()96 void Editor::_FileMenuSetup()
97 {
98 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
99 {
100 _save_as_action->setEnabled(true);
101 _save_action->setEnabled(_ed_scrollview->_map->GetChanged());
102 _close_action->setEnabled(true);
103 } // map must exist in order to save or close it
104 else
105 {
106 _save_as_action->setEnabled(false);
107 _save_action->setEnabled(false);
108 _close_action->setEnabled(false);
109 } // map does not exist, can't save or close it
110 } // _FileMenuSetup()
111
_ViewMenuSetup()112 void Editor::_ViewMenuSetup()
113 {
114 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
115 {
116 _toggle_grid_action->setEnabled(true);
117 _toggle_ll_action->setEnabled(true);
118 _toggle_ml_action->setEnabled(true);
119 _toggle_ul_action->setEnabled(true);
120 _toggle_ol_action->setEnabled(true);
121 _coord_tile_action->setEnabled(true);
122 _coord_collision_action->setEnabled(true);
123 _view_textures_action->setEnabled(true);
124 } // map must exist in order to set view options
125 else
126 {
127 _toggle_grid_action->setEnabled(false);
128 _toggle_ll_action->setEnabled(false);
129 _toggle_ml_action->setEnabled(false);
130 _toggle_ul_action->setEnabled(false);
131 _toggle_ol_action->setEnabled(false);
132 _coord_tile_action->setEnabled(false);
133 _coord_collision_action->setEnabled(false);
134 _view_textures_action->setEnabled(false);
135 } // map does not exist, can't view it*/
136 } // _ViewMenuSetup()
137
_TilesEnableActions()138 void Editor::_TilesEnableActions()
139 {
140 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
141 {
142 _undo_action->setText("Undo " + _undo_stack->undoText());
143 _redo_action->setText("Redo " + _undo_stack->redoText());
144 _layer_fill_action->setEnabled(true);
145 _layer_clear_action->setEnabled(true);
146 _toggle_select_action->setEnabled(true);
147 _mode_paint_action->setEnabled(true);
148 _mode_move_action->setEnabled(true);
149 _mode_delete_action->setEnabled(true);
150 _edit_ll_action->setEnabled(true);
151 _edit_ml_action->setEnabled(true);
152 _edit_ul_action->setEnabled(true);
153 _edit_ol_action->setEnabled(true);
154 _context_cbox->setEnabled(true);
155 } // map must exist in order to paint it
156 else
157 {
158 _undo_action->setEnabled(false);
159 _redo_action->setEnabled(false);
160 _layer_fill_action->setEnabled(false);
161 _layer_clear_action->setEnabled(false);
162 _toggle_select_action->setEnabled(false);
163 _mode_paint_action->setEnabled(false);
164 _mode_move_action->setEnabled(false);
165 _mode_delete_action->setEnabled(false);
166 _edit_ll_action->setEnabled(false);
167 _edit_ml_action->setEnabled(false);
168 _edit_ul_action->setEnabled(false);
169 _edit_ol_action->setEnabled(false);
170 _context_cbox->setEnabled(false);
171 } // map does not exist, can't paint it*/
172 } // _TilesEnableActions()
173
_TilesetMenuSetup()174 void Editor::_TilesetMenuSetup()
175 {
176 // TODO: temp fix for bug 161: don't edit tilesets if a map is open
177 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
178 _edit_tileset_action->setEnabled(false);
179 else
180 _edit_tileset_action->setEnabled(true);
181 } // _TilesetMenuSetup
182
_MapMenuSetup()183 void Editor::_MapMenuSetup()
184 {
185 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
186 {
187 _select_music_action->setEnabled(true);
188 _map_properties_action->setEnabled(true);
189 _context_properties_action->setEnabled(true);
190 } // map must exist in order to set properties
191 else
192 {
193 _select_music_action->setEnabled(false);
194 _map_properties_action->setEnabled(false);
195 _context_properties_action->setEnabled(false);
196 } // map does not exist, can't modify it
197 } // _MapMenuSetup()
198
_ScriptMenuSetup()199 void Editor::_ScriptMenuSetup()
200 {
201 _edit_skill_action->setEnabled(false);
202 } // _ScriptMenuSetup
203
_FileNew()204 void Editor::_FileNew()
205 {
206 if (_EraseOK())
207 {
208 MapPropertiesDialog* new_map = new MapPropertiesDialog(this, "new_map", false);
209
210 if (new_map->exec() == QDialog::Accepted)
211 {
212 if (_ed_scrollview != NULL)
213 delete _ed_scrollview;
214 _ed_scrollview = new EditorScrollView(NULL, "map", new_map->GetWidth(), new_map->GetHeight());
215
216 if (_ed_tabs != NULL)
217 delete _ed_tabs;
218 _ed_tabs = new QTabWidget();
219 _ed_tabs->setTabPosition(QTabWidget::South);
220
221 _ed_splitter->addWidget(_ed_scrollview);
222 _ed_splitter->addWidget(_ed_tabs);
223
224 QTreeWidget* tilesets = new_map->GetTilesetTree();
225 int num_items = tilesets->topLevelItemCount();
226 int checked_items = 0;
227 for (int i = 0; i < num_items; i++)
228 if (tilesets->topLevelItem(i)->checkState(0) == Qt::Checked)
229 checked_items++;
230
231 // Used to show the progress of tilesets that have been loaded.
232 QProgressDialog* new_map_progress =
233 new QProgressDialog(tr("Loading tilesets..."), NULL, 0, checked_items, this,
234 Qt::Widget | Qt::FramelessWindowHint | Qt::WindowTitleHint);
235 new_map_progress->setWindowTitle(tr("Creating Map..."));
236
237 // Set location of and show the progress dialog
238 new_map_progress->move(this->pos().x() + this->width()/2 - new_map_progress->width()/2,
239 this->pos().y() + this->height()/2 - new_map_progress->height()/2);
240 new_map_progress->show();
241
242 checked_items = 0;
243 for (int i = 0; i < num_items; i++)
244 {
245 if (tilesets->topLevelItem(i)->checkState(0) == Qt::Checked)
246 {
247 new_map_progress->setValue(checked_items++);
248
249 TilesetTable* a_tileset = new TilesetTable();
250 if (a_tileset->Load(tilesets->topLevelItem(i)->text(0)) == false)
251 QMessageBox::critical(this, tr("HoA Level Editor"),
252 tr("Failed to load tileset image: " +
253 tilesets->topLevelItem(i)->text(0)));
254
255 _ed_tabs->addTab(a_tileset->table, tilesets->topLevelItem(i)->text(0));
256 _ed_scrollview->_map->tilesets.push_back(a_tileset);
257 _ed_scrollview->_map->tileset_names.push_back(a_tileset->tileset_name);
258 } // tileset must be checked
259 } // iterate through all possible tilesets
260 new_map_progress->setValue(checked_items);
261
262 _ed_scrollview->_map->SetInitialized(true);
263 _ed_scrollview->resize(new_map->GetWidth() * TILE_WIDTH, new_map->GetHeight() * TILE_HEIGHT);
264 _ed_splitter->show();
265
266 _grid_on = false;
267 _textures_on = true;
268 _ll_on = false;
269 _ml_on = false;
270 _ul_on = false;
271 _ol_on = false;
272 _coord_type = 0;
273 if (_select_on)
274 _TileToggleSelect();
275 _ViewToggleGrid();
276 _ViewToggleLL();
277 _ViewToggleML();
278 _ViewToggleUL();
279 _ViewToggleOL();
280 _ViewCoordTile();
281 _ViewTextures();
282
283 // Populate the context combobox
284 // _context_cbox->clear() doesn't work, it seg faults.
285 // I guess it can't have an empty combobox?
286 int count = _context_cbox->count();
287 _context_cbox->addItems(_ed_scrollview->_map->context_names);
288 for (int i = 0; i < count; i++)
289 _context_cbox->removeItem(0);
290
291 // Enable appropriate actions
292 _TilesEnableActions();
293
294 // Set default edit mode
295 _ed_scrollview->_layer_edit = LOWER_LAYER;
296 _ed_scrollview->_tile_mode = PAINT_TILE;
297
298 _undo_stack->setClean();
299
300 // Hide and delete progress bar
301 new_map_progress->hide();
302 delete new_map_progress;
303
304 statusBar()->showMessage("New map created", 5000);
305 } // only if the user pressed OK
306 else
307 statusBar()->showMessage("No map created!", 5000);
308
309 delete new_map;
310 } // make sure an unsaved map is not lost
311 } // _FileNew()
312
_FileOpen()313 void Editor::_FileOpen()
314 {
315 if (_EraseOK())
316 {
317 // file to open
318 QString file_name = QFileDialog::getOpenFileName(this, "HoA Level Editor -- File Open",
319 "dat/maps", "Maps (*.lua)");
320
321 if (!file_name.isEmpty())
322 {
323 if (_ed_scrollview != NULL)
324 delete _ed_scrollview;
325 _ed_scrollview = new EditorScrollView(NULL, "map", 0, 0);
326
327 if (_ed_tabs != NULL)
328 delete _ed_tabs;
329 _ed_tabs = new QTabWidget();
330 _ed_tabs->setTabPosition(QTabWidget::South);
331
332 _ed_splitter->addWidget(_ed_scrollview);
333 _ed_splitter->addWidget(_ed_tabs);
334
335 _ed_scrollview->_map->SetFileName(file_name);
336 _ed_scrollview->_map->LoadMap();
337
338 // Count for the tileset names
339 int num_items = _ed_scrollview->_map->tileset_names.count();
340 int progress_steps = 0;
341
342 // Used to show the progress of tilesets has been loaded.
343 QProgressDialog* new_map_progress =
344 new QProgressDialog(tr("Loading tilesets..."), NULL, 0, num_items, this,
345 Qt::Widget | Qt::FramelessWindowHint | Qt::WindowTitleHint);
346 new_map_progress->setWindowTitle(tr("Creating Map..."));
347
348 // Set the progress bar
349 new_map_progress->move(this->pos().x() + this->width()/2 - new_map_progress->width()/2,
350 this->pos().y() + this->height()/2 - new_map_progress->height()/2);
351 new_map_progress->show();
352
353 for (QStringList::ConstIterator it = _ed_scrollview->_map->tileset_names.begin();
354 it != _ed_scrollview->_map->tileset_names.end(); it++)
355 {
356 new_map_progress->setValue(progress_steps++);
357
358 TilesetTable* a_tileset = new TilesetTable();
359 if (a_tileset->Load(*it) == false)
360 QMessageBox::critical(this, tr("HoA Level Editor"),
361 tr("Failed to load tileset image: " + *it));
362
363 _ed_tabs->addTab(a_tileset->table, *it);
364 _ed_scrollview->_map->tilesets.push_back(a_tileset);
365 } // iterate through all tilesets in the map
366 new_map_progress->setValue(progress_steps);
367
368 _ed_scrollview->_map->SetInitialized(true);
369 _ed_scrollview->resize(_ed_scrollview->_map->GetWidth(),
370 _ed_scrollview->_map->GetHeight());
371 _ed_splitter->show();
372
373 _grid_on = false;
374 _textures_on = true;
375 _ll_on = false;
376 _ml_on = false;
377 _ul_on = false;
378 _ol_on = false;
379 _coord_type = 0;
380 if (_select_on)
381 _TileToggleSelect();
382 _ViewToggleGrid();
383 _ViewToggleLL();
384 _ViewToggleML();
385 _ViewToggleUL();
386 _ViewToggleOL();
387 _ViewCoordTile();
388 _ViewTextures();
389
390 // Populate the context combobox
391 // _context_cbox->clear() doesn't work, it seg faults.
392 // I guess it can't have an empty combobox?
393 int count = _context_cbox->count();
394 _context_cbox->addItems(_ed_scrollview->_map->context_names);
395 for (int i = 0; i < count; i++)
396 _context_cbox->removeItem(0);
397
398 // Enable appropriate actions
399 _TilesEnableActions();
400
401 // Set default edit mode
402 _ed_scrollview->_layer_edit = LOWER_LAYER;
403 _ed_scrollview->_tile_mode = PAINT_TILE;
404
405 // Hide and delete progress bar
406 new_map_progress->hide();
407 delete new_map_progress;
408
409 _undo_stack->setClean();
410 statusBar()->showMessage(QString("Opened \'%1\'").
411 arg(_ed_scrollview->_map->GetFileName()), 5000);
412 } // file must exist in order to open it
413 else
414 statusBar()->showMessage("No map created!", 5000);
415 } // make sure an unsaved map is not lost
416 } // _FileOpen()
417
_FileSaveAs()418 void Editor::_FileSaveAs()
419 {
420 // get the file name from the user
421 QString file_name = QFileDialog::getSaveFileName(this,
422 "HoA Level Editor -- File Save", "dat/maps", "Maps (*.lua)");
423
424 if (!file_name.isEmpty())
425 {
426 _ed_scrollview->_map->SetFileName(file_name);
427 _FileSave();
428 return;
429 } // make sure the file name is not blank
430
431 statusBar()->showMessage("Save abandoned.", 5000);
432 } // _FileSaveAs()
433
_FileSave()434 void Editor::_FileSave()
435 {
436 if (_ed_scrollview->_map->GetFileName().isEmpty() ||
437 _ed_scrollview->_map->GetFileName() == "Untitled")
438 {
439 _FileSaveAs();
440 return;
441 } // gets a file name if it is blank
442
443 _ed_scrollview->_map->SaveMap(); // actually saves the map
444 _undo_stack->setClean();
445 setCaption(QString("%1").arg(_ed_scrollview->_map->GetFileName()));
446 statusBar()->showMessage(QString("Saved \'%1\' successfully!").
447 arg(_ed_scrollview->_map->GetFileName()), 5000);
448 } // _FileSave()
449
_FileClose()450 void Editor::_FileClose()
451 {
452 // Checks to see if the map is unsaved.
453 if (_EraseOK())
454 {
455 if (_ed_scrollview != NULL)
456 {
457 delete _ed_scrollview;
458 _ed_scrollview = NULL;
459 _undo_stack->clear();
460
461 // Clear the context combobox
462 // _context_cbox->clear() doesn't work, it seg faults.
463 // I guess it can't have an empty combobox?
464 int count = _context_cbox->count();
465 for (int i = 0; i < count; i++)
466 _context_cbox->removeItem(0);
467
468 // Enable appropriate actions
469 _TilesEnableActions();
470 } // scrollview must exist first
471
472 if (_ed_tabs != NULL)
473 {
474 delete _ed_tabs;
475 _ed_tabs = NULL;
476 } // tabs must exist first
477
478 setCaption("Hero of Allacrost Level Editor");
479 } // make sure an unsaved map is not lost
480 } // _FileClose()
481
_FileQuit()482 void Editor::_FileQuit()
483 {
484 // Checks to see if the map is unsaved.
485 if (_EraseOK())
486 qApp->exit(0);
487 } // _FileQuit()
488
_ViewToggleGrid()489 void Editor::_ViewToggleGrid()
490 {
491 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
492 {
493 _grid_on = !_grid_on;
494 _toggle_grid_action->setChecked(_grid_on);
495 _ed_scrollview->_map->SetGridOn(_grid_on);
496 } // map must exist in order to view things on it
497 } // _ViewToggleGrid()
498
_ViewToggleLL()499 void Editor::_ViewToggleLL()
500 {
501 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
502 {
503 _ll_on = !_ll_on;
504 _toggle_ll_action->setChecked(_ll_on);
505 _ed_scrollview->_map->SetLLOn(_ll_on);
506 } // map must exist in order to view things on it
507 } // _ViewToggleLL()
508
_ViewToggleML()509 void Editor::_ViewToggleML()
510 {
511 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
512 {
513 _ml_on = !_ml_on;
514 _toggle_ml_action->setChecked(_ml_on);
515 _ed_scrollview->_map->SetMLOn(_ml_on);
516 } // map must exist in order to view things on it
517 } // _ViewToggleML()
518
_ViewToggleUL()519 void Editor::_ViewToggleUL()
520 {
521 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
522 {
523 _ul_on = !_ul_on;
524 _toggle_ul_action->setChecked(_ul_on);
525 _ed_scrollview->_map->SetULOn(_ul_on);
526 } // map must exist in order to view things on it
527 } // _ViewToggleUL()
528
_ViewToggleOL()529 void Editor::_ViewToggleOL()
530 {
531 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
532 {
533 _ol_on = !_ol_on;
534 _toggle_ol_action->setChecked(_ol_on);
535 _ed_scrollview->_map->SetOLOn(_ol_on);
536 } // map must exist in order to view things on it
537 } // _ViewToggleOL()
538
_ViewCoordTile()539 void Editor::_ViewCoordTile()
540 {
541 _coord_type = 0;
542 _coord_tile_action->setChecked(true);
543 _coord_collision_action->setChecked(false);
544 }
545
_ViewCoordCollision()546 void Editor::_ViewCoordCollision()
547 {
548 _coord_type = 1;
549 _coord_collision_action->setChecked(true);
550 _coord_tile_action->setChecked(false);
551 }
552
_ViewTextures()553 void Editor::_ViewTextures()
554 {
555 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
556 {
557 _textures_on = !_textures_on;
558 if(_textures_on)
559 {
560 VideoManager->Textures()->DEBUG_NextTexSheet();
561 }
562 _ed_scrollview->_map->SetTexturesOn(_textures_on);
563 } // map must exist in order to view things on it
564 } // _ViewTextures()
565
_TileLayerFill()566 void Editor::_TileLayerFill()
567 {
568 // get reference to current tileset
569 Q3Table* table = static_cast<Q3Table*> (_ed_tabs->currentPage());
570
571 // put selected tile from tileset into tile array at correct position
572 int32 tileset_index = table->currentRow() * 16 + table->currentColumn();
573 int32 multiplier = _ed_scrollview->_map->tileset_names.findIndex(_ed_tabs->tabText(_ed_tabs->currentIndex()));
574 if (multiplier == -1)
575 {
576 _ed_scrollview->_map->tileset_names.append(_ed_tabs->tabText(_ed_tabs->currentIndex()));
577 multiplier = _ed_scrollview->_map->tileset_names.findIndex(_ed_tabs->tabText(_ed_tabs->currentIndex()));
578 } // calculate index of current tileset
579
580 vector<int32>& current_layer = _ed_scrollview->GetCurrentLayer();
581
582 // Record the information for undo/redo operations.
583 vector<int32> previous = current_layer;
584 vector<int32> modified;
585 vector<int32> indeces(current_layer.size());
586 for (int32 i = 0; i < static_cast<int32>(current_layer.size()); i++)
587 indeces[i] = i;
588
589 // Fill the layer.
590 for (vector<int32>::iterator iter = current_layer.begin(); iter != current_layer.end(); iter++)
591 {
592 _ed_scrollview->_AutotileRandomize(multiplier, tileset_index);
593 *iter = tileset_index + multiplier * 256;
594 modified.push_back(tileset_index + multiplier * 256);
595 } // iterate through the entire layer
596
597 LayerCommand* fill_command = new LayerCommand(indeces, previous, modified,
598 _ed_scrollview->_layer_edit, _ed_scrollview->_map->GetContext(), this,
599 "Fill Layer");
600 _undo_stack->push(fill_command);
601 indeces.clear();
602 previous.clear();
603 modified.clear();
604
605 // Draw the changes.
606 _ed_scrollview->_map->SetChanged(true);
607 _ed_scrollview->_map->updateGL();
608 } // _TileLayerFill()
609
_TileLayerClear()610 void Editor::_TileLayerClear()
611 {
612 vector<int32>::iterator it; // used to iterate over an entire layer
613 vector<int32>& current_layer = _ed_scrollview->GetCurrentLayer();
614
615 // Record the information for undo/redo operations.
616 vector<int32> previous = current_layer;
617 vector<int32> modified(current_layer.size(), -1);
618 vector<int32> indeces(current_layer.size());
619 for (int32 i = 0; i < static_cast<int32>(current_layer.size()); i++)
620 indeces[i] = i;
621
622 // Clear the layer.
623 for (it = current_layer.begin(); it != current_layer.end(); it++)
624 *it = -1;
625
626 LayerCommand* clear_command = new LayerCommand(indeces, previous, modified,
627 _ed_scrollview->_layer_edit, _ed_scrollview->_map->GetContext(), this,
628 "Clear Layer");
629 _undo_stack->push(clear_command);
630 indeces.clear();
631 previous.clear();
632 modified.clear();
633
634 // Draw the changes.
635 _ed_scrollview->_map->SetChanged(true);
636 _ed_scrollview->_map->updateGL();
637 } // _TileLayerClear()
638
_TileToggleSelect()639 void Editor::_TileToggleSelect()
640 {
641 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
642 {
643 _select_on = !_select_on;
644 _toggle_select_action->setChecked(_select_on);
645 _ed_scrollview->_map->SetSelectOn(_select_on);
646 } // map must exist in order to view things on it
647 } // _TileToggleSelect()
648
_TileModePaint()649 void Editor::_TileModePaint()
650 {
651 if (_ed_scrollview != NULL)
652 {
653 // Clear the selection layer.
654 if (_ed_scrollview->_moving == true && _select_on == true)
655 {
656 vector<int32>::iterator it; // used to iterate over an entire layer
657 vector<int32>& select_layer = _ed_scrollview->_map->GetLayer(SELECT_LAYER, 0);
658 for (it = select_layer.begin(); it != select_layer.end(); it++)
659 *it = -1;
660 } // clears when selected tiles were going to be moved but
661 // user changed their mind in the midst of the move operation
662
663 _ed_scrollview->_tile_mode = PAINT_TILE;
664 _ed_scrollview->_moving = false;
665 } // scrollview must exist in order to switch modes
666 } // _TileModePaint()
667
_TileModeMove()668 void Editor::_TileModeMove()
669 {
670 if (_ed_scrollview != NULL)
671 {
672 // Clear the selection layer.
673 if (_ed_scrollview->_moving == true && _select_on == true)
674 {
675 vector<int32>::iterator it; // used to iterate over an entire layer
676 vector<int32>& select_layer = _ed_scrollview->_map->GetLayer(SELECT_LAYER, 0);
677 for (it = select_layer.begin(); it != select_layer.end(); it++)
678 *it = -1;
679 } // clears when selected tiles were going to be moved but
680 // user changed their mind in the midst of the move operation
681
682 _ed_scrollview->_tile_mode = MOVE_TILE;
683 _ed_scrollview->_moving = false;
684 } // scrollview must exist in order to switch modes
685 } // _TileModeMove()
686
_TileModeDelete()687 void Editor::_TileModeDelete()
688 {
689 if (_ed_scrollview != NULL)
690 {
691 // Clear the selection layer.
692 if (_ed_scrollview->_moving == true && _select_on == true)
693 {
694 vector<int32>::iterator it; // used to iterate over an entire layer
695 vector<int32>& select_layer = _ed_scrollview->_map->GetLayer(SELECT_LAYER, 0);
696 for (it = select_layer.begin(); it != select_layer.end(); it++)
697 *it = -1;
698 } // clears when selected tiles were going to be moved but
699 // user changed their mind in the midst of the move operation
700
701 _ed_scrollview->_tile_mode = DELETE_TILE;
702 _ed_scrollview->_moving = false;
703 } // scrollview must exist in order to switch modes
704 } // _TileModeDelete()
705
_TileEditLL()706 void Editor::_TileEditLL()
707 {
708 if (_ed_scrollview != NULL)
709 _ed_scrollview->_layer_edit = LOWER_LAYER;
710 } // _TileEditLL()
711
_TileEditML()712 void Editor::_TileEditML()
713 {
714 if (_ed_scrollview != NULL)
715 _ed_scrollview->_layer_edit = MIDDLE_LAYER;
716 } // _TileEditML()
717
_TileEditUL()718 void Editor::_TileEditUL()
719 {
720 if (_ed_scrollview != NULL)
721 _ed_scrollview->_layer_edit = UPPER_LAYER;
722 } // _TileEditUL()
723
_TileEditOL()724 void Editor::_TileEditOL()
725 {
726 if (_ed_scrollview != NULL)
727 _ed_scrollview->_layer_edit = OBJECT_LAYER;
728 } // _TileEditOL()
729
730
_TilesetEdit()731 void Editor::_TilesetEdit()
732 {
733 TilesetEditor* tileset_editor = new TilesetEditor(this, "tileset_editor", true);
734
735 if (tileset_editor->exec() == QDialog::Accepted)
736 {
737 } // only process results if user selected okay
738 else
739 statusBar()->showMessage("Properties not modified!", 5000);
740
741 delete tileset_editor;
742 } // _TilesetEdit
743
_MapSelectMusic()744 void Editor::_MapSelectMusic()
745 {
746 if (_ed_scrollview == NULL)
747 return;
748
749 MusicDialog* music = new MusicDialog(this, "music_dialog");
750
751 if (music->exec() == QDialog::Accepted)
752 {
753 // Turn the items in the listwidget into a stringlist that the map
754 // will understand
755 QStringList music_names;
756 QListWidget* music_list = music->GetMusicList();
757 for (unsigned int i = 0; i < music_list->count(); i++)
758 music_names << music_list->item(i)->text();
759
760 _ed_scrollview->_map->music_files = music_names;
761 _ed_scrollview->_map->SetChanged(true);
762 } // only process results if user selected okay
763
764 delete music;
765 } // _MapSelectMusic()
766
_MapProperties()767 void Editor::_MapProperties()
768 {
769 MapPropertiesDialog* props = new
770 MapPropertiesDialog(this, "map_properties", true);
771
772 if (props->exec() == QDialog::Accepted)
773 {
774 #if !defined(WIN32)
775 if (_ed_scrollview->_map->GetWidth() < props->GetWidth())
776 {
777 // User wants to make map wider so we must insert columns of tiles at the edge of the map.
778
779 int map_width = _ed_scrollview->_map->GetWidth();
780 int map_height = _ed_scrollview->_map->GetHeight();
781 int extra_columns = props->GetWidth() - map_width;
782
783 // Add in the extra columns one by one.
784 for (int col = extra_columns; col > 0; col--)
785 {
786 vector<int32>& lower_layer = _ed_scrollview->_map->GetLayer(LOWER_LAYER, _ed_scrollview->_map->GetContext());
787 vector<int32>::iterator it = lower_layer.begin() + map_width;
788 for (int row = 0; row < map_height; row++)
789 {
790 lower_layer.insert(it, -1);
791 it += map_width + 1;
792 } // iterate through the rows of the lower layer
793
794 vector<int32>& middle_layer = _ed_scrollview->_map->GetLayer(MIDDLE_LAYER, _ed_scrollview->_map->GetContext());
795 it = middle_layer.begin() + map_width;
796 for (int row = 0; row < map_height; row++)
797 {
798 middle_layer.insert(it, -1);
799 it += map_width + 1;
800 } // iterate through the rows of the middle layer
801
802 vector<int32>& upper_layer = _ed_scrollview->_map->GetLayer(UPPER_LAYER, _ed_scrollview->_map->GetContext());
803 it = upper_layer.begin() + map_width;
804 for (int row = 0; row < map_height; row++)
805 {
806 upper_layer.insert(it, -1);
807 it += map_width + 1;
808 } // iterate through the rows of the upper layer
809
810 map_width++;
811 _ed_scrollview->_map->SetWidth(map_width);
812 } // add in all the extra columns
813 } // insert columns
814 else if (_ed_scrollview->_map->GetWidth() > props->GetWidth())
815 {
816 // User wants to make map less wide so we must delete columns of tiles from the edge of the map.
817
818 int map_width = _ed_scrollview->_map->GetWidth();
819 int map_height = _ed_scrollview->_map->GetHeight();
820 int extra_columns = map_width - props->GetWidth();
821
822 // Delete all the extra columns one by one.
823 for (int col = extra_columns; col > 0; col--)
824 {
825 vector<int32>& lower_layer = _ed_scrollview->_map->GetLayer(LOWER_LAYER, _ed_scrollview->_map->GetContext());
826 vector<int32>::iterator it = lower_layer.begin() + map_width - 1;
827 for (int row = 0; row < map_height; row++)
828 {
829 lower_layer.erase(it);
830 it += map_width - 1;
831 } // iterate through the rows of the lower layer
832
833 vector<int32>& middle_layer = _ed_scrollview->_map->GetLayer(MIDDLE_LAYER, _ed_scrollview->_map->GetContext());
834 it = middle_layer.begin() + map_width - 1;
835 for (int row = 0; row < map_height; row++)
836 {
837 middle_layer.erase(it);
838 it += map_width - 1;
839 } // iterate through the rows of the middle layer
840
841 vector<int32>& upper_layer = _ed_scrollview->_map->GetLayer(UPPER_LAYER, _ed_scrollview->_map->GetContext());
842 it = upper_layer.begin() + map_width - 1;
843 for (int row = 0; row < map_height; row++)
844 {
845 upper_layer.erase(it);
846 it += map_width - 1;
847 } // iterate through the rows of the upper layer
848
849 map_width--;
850 _ed_scrollview->_map->SetWidth(map_width);
851 } // delete all the extra columns
852 } // delete columns
853
854 if (_ed_scrollview->_map->GetHeight() < props->GetHeight())
855 {
856 // User wants to make map taller so we must insert rows of tiles at the edge of the map.
857
858 int map_width = _ed_scrollview->_map->GetWidth();
859 int extra_rows = props->GetHeight() - _ed_scrollview->_map->GetHeight();
860
861 vector<int32>& lower_layer = _ed_scrollview->_map->GetLayer(LOWER_LAYER, _ed_scrollview->_map->GetContext());
862 vector<int32>& middle_layer = _ed_scrollview->_map->GetLayer(MIDDLE_LAYER, _ed_scrollview->_map->GetContext());
863 vector<int32>& upper_layer = _ed_scrollview->_map->GetLayer(UPPER_LAYER, _ed_scrollview->_map->GetContext());
864 lower_layer.insert( lower_layer.end(), extra_rows * map_width, -1);
865 middle_layer.insert(middle_layer.end(), extra_rows * map_width, -1);
866 upper_layer.insert( upper_layer.end(), extra_rows * map_width, -1);
867 } // add rows
868 else if (_ed_scrollview->_map->GetHeight() > props->GetHeight())
869 {
870 // User wants to make map less tall so we must delete rows of tiles from the edge of the map.
871
872 int map_width = _ed_scrollview->_map->GetWidth();
873 int extra_rows = _ed_scrollview->_map->GetHeight() - props->GetHeight();
874
875 vector<int32>& lower_layer = _ed_scrollview->_map->GetLayer(LOWER_LAYER, _ed_scrollview->_map->GetContext());
876 vector<int32>& middle_layer = _ed_scrollview->_map->GetLayer(MIDDLE_LAYER, _ed_scrollview->_map->GetContext());
877 vector<int32>& upper_layer = _ed_scrollview->_map->GetLayer(UPPER_LAYER, _ed_scrollview->_map->GetContext());
878 lower_layer.erase( lower_layer.end() - extra_rows * map_width, lower_layer.end());
879 middle_layer.erase(middle_layer.end() - extra_rows * map_width, middle_layer.end());
880 upper_layer.erase( upper_layer.end() - extra_rows * map_width, upper_layer.end());
881 } // delete rows
882
883 // Resize the map, QOpenGL and QScrollView widgets.
884 _ed_scrollview->_map->SetHeight(props->GetHeight());
885 _ed_scrollview->_map->resize(props->GetWidth() * TILE_WIDTH, props->GetHeight() * TILE_HEIGHT);
886 _ed_scrollview->resize(props->GetWidth() * TILE_WIDTH, props->GetHeight() * TILE_HEIGHT);
887 #endif
888
889
890
891 // User has the ability to add or remove tilesets being used. We don't want
892 // to reload tilesets that have already been loaded before.
893
894 QTreeWidget* tilesets = props->GetTilesetTree();
895
896 // Put the names of the tabs into a nice list that can be easily searched
897 // with one command instead of a loop.
898 QStringList tab_names;
899 for (int i = 0; i < _ed_tabs->count(); i++)
900 tab_names << _ed_tabs->tabText(i);
901
902 // Go through the list of tilesets, adding selected tilesets and removing
903 // any unwanted tilesets.
904 int num_items = tilesets->topLevelItemCount();
905 for (int i = 0; i < num_items; i++)
906 {
907 if (tilesets->topLevelItem(i)->checkState(0) == Qt::Checked)
908 {
909 if (tab_names.contains(tilesets->topLevelItem(i)->text(0)) == false)
910 {
911 TilesetTable* a_tileset = new TilesetTable();
912 a_tileset->Load(tilesets->topLevelItem(i)->text(0));
913 _ed_tabs->addTab(a_tileset->table, tilesets->topLevelItem(i)->text(0));
914 _ed_scrollview->_map->tilesets.push_back(a_tileset);
915 } // only add a tileset if it isn't already loaded
916 } // tileset must be checked in order to add it
917 else if (tilesets->topLevelItem(i)->checkState(0) == Qt::Unchecked &&
918 tab_names.contains(tilesets->topLevelItem(i)->text(0)))
919 _ed_tabs->removeTab(tab_names.indexOf(tilesets->topLevelItem(i)->text(0)));
920 // FIXME:
921 // Where to add and remove tileset name from the tilesets list
922 // in the _map? Do it here or when actually painting and deleting
923 // tiles? Here the assumption is made that if the user is adding a
924 // tileset, then s/he expects to use tiles from that tileset and we
925 // can safely add the tileset name to the _map. Otherwise we would
926 // have to constantly check every time a paint operation occurs
927 // whether or not the tileset name of the selected tile was present
928 // in the tileset name list in _map. That's cumbersome.
929 //
930 // When removing a tileset however, there might still be tiles in
931 // the map from that tileset, and the user is only removing the
932 // tileset from the view in the bottom of the map to unclutter
933 // things. In this case we wouldn't want to remove the tileset name
934 // from the list in _map.
935 } // iterate through all possible tilesets
936
937 _ed_splitter->addWidget(_ed_tabs);
938 } // only if the user pressed OK
939 else
940 statusBar()->showMessage("Properties not modified!", 5000);
941
942 delete props;
943 } // _MapProperties()
944
_MapAddContext()945 void Editor::_MapAddContext()
946 {
947 if (_ed_scrollview->_map->context_names.size() >= MAX_CONTEXTS)
948 {
949 _error_max_contexts->move(this->pos().x() + this->width()/2 - _error_max_contexts->width()/2,
950 this->pos().y() + this->height()/2 - _error_max_contexts->height()/2);
951 _error_max_contexts->showMessage(
952 QString("Maximum number of contexts (%1) reached. No new context will be created.").
953 arg(MAX_CONTEXTS));
954 statusBar()->showMessage("Maximum number of contexts reached. No new context created!", 5000);
955 return;
956 } // don't want more than the max allowable contexts
957
958 ContextPropertiesDialog* props = new
959 ContextPropertiesDialog(this, "context_properties");
960
961 if (props->exec() == QDialog::Accepted)
962 {
963 _ed_scrollview->_map->context_names << props->GetName();
964 QStringList context_names = _ed_scrollview->_map->context_names;
965
966 // Gets the index of the context to inherit from. Default is the
967 // base context, which is index 0. If no context is selected in the
968 // dialog, use the default, since a new context cannot be created without
969 // inheriting from another.
970 int inherit_context;
971 if (props->GetContextTree()->currentItem() == NULL)
972 inherit_context = 0;
973 else
974 inherit_context = context_names.indexOf(
975 props->GetContextTree()->currentItem()->text(0));
976
977 // Perform the copy from one context to another.
978 _ed_scrollview->_map->CreateNewContext(inherit_context);
979
980 // Add new context to context combobox.
981 _context_cbox->addItem(props->GetName());
982
983 // Switch to newly created context.
984 _context_cbox->setCurrentIndex(context_names.size() - 1);
985 _ed_scrollview->_map->SetContext(context_names.size() - 1);
986 } // only if the user pressed OK
987 else
988 statusBar()->showMessage("No new context created!", 5000);
989
990 delete props;
991 } // _MapAddContext()
992
_ScriptEditSkills()993 void Editor::_ScriptEditSkills()
994 {
995 if (_skill_editor == NULL)
996 {
997 // create the skill editor window
998 _skill_editor = new SkillEditor(NULL, "skill_editor");
999 _skill_editor->resize(600,400);
1000 }
1001 _skill_editor->show();
1002 //SkillEditor *skill_editor = new SkillEditor(this, "skill_editor");
1003 //skill_editor->exec();
1004 //delete skill_editor;
1005 } // _ScriptEditSkills()
1006
_HelpHelp()1007 void Editor::_HelpHelp()
1008 {
1009 statusBar()->showMessage(tr("See http://allacrost.sourceforge.net/wiki/index.php/Code_Documentation#Map_Editor_Documentation for more details"), 10000);
1010 } // _HelpHelp()
1011
_HelpAbout()1012 void Editor::_HelpAbout()
1013 {
1014 QMessageBox::about(this, "HoA Level Editor -- About",
1015 "<center><h1><font color=blue>Hero of Allacrost Level Editor<font>"
1016 "</h1></center>"
1017 "<center><h2><font color=blue>Copyright (c) 2004-2010<font></h2></center>"
1018 "<p>A level editor created for the Hero of Allacrost project."
1019 " See 'http://www.allacrost.org/' for more details</p>");
1020 } // _HelpAbout()
1021
_HelpAboutQt()1022 void Editor::_HelpAboutQt()
1023 {
1024 QMessageBox::aboutQt(this, "HoA Level Editor -- About Qt");
1025 } // _HelpAboutQt()
1026
_SwitchMapContext(int context)1027 void Editor::_SwitchMapContext(int context)
1028 {
1029 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
1030 {
1031 _ed_scrollview->_map->SetContext(context);
1032 _ed_scrollview->_map->updateGL();
1033 } // map must exist in order to change the context
1034 } // _SwitchMapContext()
1035
1036
1037
1038 // ********** Private functions **********
1039
_CreateActions()1040 void Editor::_CreateActions()
1041 {
1042 // Create menu actions related to the File menu
1043
1044 _new_action = new QAction("&New...", this);
1045 _new_action->setShortcut(tr("Ctrl+N"));
1046 _new_action->setStatusTip("Create a new map");
1047 connect(_new_action, SIGNAL(triggered()), this, SLOT(_FileNew()));
1048
1049 _open_action = new QAction("&Open...", this);
1050 _open_action->setShortcut(tr("Ctrl+O"));
1051 _open_action->setStatusTip("Open an existing map");
1052 connect(_open_action, SIGNAL(triggered()), this, SLOT(_FileOpen()));
1053
1054 _save_as_action = new QAction("Save &As...", this);
1055 _save_as_action->setStatusTip("Save the map with another name");
1056 connect(_save_as_action, SIGNAL(triggered()), this, SLOT(_FileSaveAs()));
1057
1058 _save_action = new QAction("&Save", this);
1059 _save_action->setShortcut(tr("Ctrl+S"));
1060 _save_action->setStatusTip("Save the map");
1061 connect(_save_action, SIGNAL(triggered()), this, SLOT(_FileSave()));
1062
1063 _close_action = new QAction("&Close", this);
1064 _close_action->setShortcut(tr("Ctrl+W"));
1065 _close_action->setStatusTip("Close the map");
1066 connect(_close_action, SIGNAL(triggered()), this, SLOT(_FileClose()));
1067
1068 _quit_action = new QAction("&Quit", this);
1069 _quit_action->setShortcut(tr("Ctrl+Q"));
1070 _quit_action->setStatusTip("Quits from the editor");
1071 connect(_quit_action, SIGNAL(triggered()), this, SLOT(_FileQuit()));
1072
1073
1074
1075 // Create menu actions related to the View menu
1076
1077 _toggle_grid_action = new QAction("&Grid", this);
1078 _toggle_grid_action->setStatusTip("Switches the grid on and off");
1079 _toggle_grid_action->setShortcut(tr("G"));
1080 _toggle_grid_action->setCheckable(true);
1081 connect(_toggle_grid_action, SIGNAL(triggered()), this, SLOT(_ViewToggleGrid()));
1082
1083 _toggle_ll_action = new QAction("&Lower Layer", this);
1084 _toggle_ll_action->setStatusTip("Switches the lower layer on and off");
1085 _toggle_ll_action->setShortcut(tr("L"));
1086 _toggle_ll_action->setCheckable(true);
1087 connect(_toggle_ll_action, SIGNAL(triggered()), this, SLOT(_ViewToggleLL()));
1088
1089 _toggle_ml_action = new QAction("&Middle Layer", this);
1090 _toggle_ml_action->setStatusTip("Switches the middle layer on and off");
1091 _toggle_ml_action->setShortcut(tr("M"));
1092 _toggle_ml_action->setCheckable(true);
1093 connect(_toggle_ml_action, SIGNAL(triggered()), this, SLOT(_ViewToggleML()));
1094
1095 _toggle_ul_action = new QAction("&Upper Layer", this);
1096 _toggle_ul_action->setStatusTip("Switches the upper layer on and off");
1097 _toggle_ul_action->setShortcut(tr("U"));
1098 _toggle_ul_action->setCheckable(true);
1099 connect(_toggle_ul_action, SIGNAL(triggered()), this, SLOT(_ViewToggleUL()));
1100
1101 _toggle_ol_action = new QAction("&Object Layer", this);
1102 _toggle_ol_action->setStatusTip("Switches the object layer on and off");
1103 _toggle_ol_action->setShortcut(tr("O"));
1104 _toggle_ol_action->setCheckable(true);
1105 connect(_toggle_ol_action, SIGNAL(triggered()), this, SLOT(_ViewToggleOL()));
1106
1107 _coord_tile_action = new QAction("Tile Coordinates", this);
1108 _coord_tile_action->setStatusTip("Switch the coordinate display to tile coordinates");
1109 _coord_tile_action->setCheckable(true);
1110 connect(_coord_tile_action, SIGNAL(triggered()), this, SLOT(_ViewCoordTile()));
1111
1112 _coord_collision_action = new QAction("Collision Coordinates", this);
1113 _coord_collision_action->setStatusTip("Switch the coordinate display to collision coordinates");
1114 _coord_collision_action->setCheckable(true);
1115 connect(_coord_collision_action, SIGNAL(triggered()), this, SLOT(_ViewCoordCollision()));
1116
1117 _view_textures_action = new QAction("&Texture sheets", this);
1118 _view_textures_action->setShortcut(tr("Ctrl+T"));
1119 _view_textures_action->setStatusTip("Cycles through the video engine's texture sheets");
1120 connect(_view_textures_action, SIGNAL(triggered()), this, SLOT(_ViewTextures()));
1121
1122
1123
1124 // Create menu actions related to the Tiles menu
1125
1126 _undo_action = new QAction(
1127 QIcon("img/misc/editor-tools/arrow-left.png"),
1128 "&Undo", this);
1129 _undo_action->setShortcut(tr("Ctrl+Z"));
1130 _undo_action->setStatusTip("Undoes the previous command");
1131 connect(_undo_action, SIGNAL(triggered()), _undo_stack, SLOT(undo()));
1132
1133 _redo_action = new QAction(
1134 QIcon("img/misc/editor-tools/arrow-right.png"),
1135 "&Redo", this);
1136 _redo_action->setShortcut(tr("Ctrl+Y"));
1137 _redo_action->setStatusTip("Redoes the next command");
1138 connect(_redo_action, SIGNAL(triggered()), _undo_stack, SLOT(redo()));
1139
1140 _layer_fill_action = new QAction(
1141 QIcon("img/misc/editor-tools/stock-tool-bucket-fill-22.png"),
1142 "&Fill layer", this);
1143 _layer_fill_action->setStatusTip("Fills current layer with selected tile");
1144 connect(_layer_fill_action, SIGNAL(triggered()), this, SLOT(_TileLayerFill()));
1145
1146 _layer_clear_action = new QAction("&Clear layer", this);
1147 _layer_clear_action->setStatusTip("Clears current layer from any tiles");
1148 connect(_layer_clear_action, SIGNAL(triggered()), this, SLOT(_TileLayerClear()));
1149
1150 _toggle_select_action = new QAction(
1151 QIcon("img/misc/editor-tools/stock-tool-rect-select-22.png"),
1152 "Marquee &Select", this);
1153 _toggle_select_action->setShortcut(tr("Shift+S"));
1154 _toggle_select_action->setStatusTip("Rectangularly select tiles on the map");
1155 _toggle_select_action->setCheckable(true);
1156 connect(_toggle_select_action, SIGNAL(triggered()), this, SLOT(_TileToggleSelect()));
1157
1158 _mode_paint_action = new QAction(
1159 QIcon("img/misc/editor-tools/stock-tool-pencil-22.png"),
1160 "&Paint mode", this);
1161 _mode_paint_action->setShortcut(tr("Shift+P"));
1162 _mode_paint_action->setStatusTip("Switches to paint mode to draw tiles on the map");
1163 _mode_paint_action->setCheckable(true);
1164 connect(_mode_paint_action, SIGNAL(triggered()), this, SLOT(_TileModePaint()));
1165
1166 _mode_move_action = new QAction(
1167 QIcon("img/misc/editor-tools/stock-tool-arrow.png"),
1168 "Mo&ve mode", this);
1169 _mode_move_action->setShortcut(tr("Shift+V"));
1170 _mode_move_action->setStatusTip("Switches to move mode to move tiles around on the map");
1171 _mode_move_action->setCheckable(true);
1172 connect(_mode_move_action, SIGNAL(triggered()), this, SLOT(_TileModeMove()));
1173
1174 _mode_delete_action = new QAction(
1175 QIcon("img/misc/editor-tools/stock-tool-eraser-22.png"),
1176 "&Delete mode", this);
1177 _mode_delete_action->setShortcut(tr("Shift+D"));
1178 _mode_delete_action->setStatusTip("Switches to delete mode to erase tiles from the map");
1179 _mode_delete_action->setCheckable(true);
1180 connect(_mode_delete_action, SIGNAL(triggered()), this, SLOT(_TileModeDelete()));
1181
1182 _mode_group = new QActionGroup(this);
1183 _mode_group->addAction(_mode_paint_action);
1184 _mode_group->addAction(_mode_move_action);
1185 _mode_group->addAction(_mode_delete_action);
1186 _mode_paint_action->setChecked(true);
1187
1188 _edit_ll_action = new QAction("Edit &lower layer", this);
1189 _edit_ll_action->setShortcut(tr("Shift+L"));
1190 _edit_ll_action->setStatusTip("Makes lower layer of the map current");
1191 _edit_ll_action->setCheckable(true);
1192 connect(_edit_ll_action, SIGNAL(triggered()), this, SLOT(_TileEditLL()));
1193
1194 _edit_ml_action = new QAction("Edit &middle layer", this);
1195 _edit_ml_action->setShortcut(tr("Shift+M"));
1196 _edit_ml_action->setStatusTip("Makes middle layer of the map current");
1197 _edit_ml_action->setCheckable(true);
1198 connect(_edit_ml_action, SIGNAL(triggered()), this, SLOT(_TileEditML()));
1199
1200 _edit_ul_action = new QAction("Edit &upper layer", this);
1201 _edit_ul_action->setShortcut(tr("Shift+U"));
1202 _edit_ul_action->setStatusTip("Makes upper layer of the map current");
1203 _edit_ul_action->setCheckable(true);
1204 connect(_edit_ul_action, SIGNAL(triggered()), this, SLOT(_TileEditUL()));
1205
1206 _edit_ol_action = new QAction("Edit &object layer", this);
1207 _edit_ol_action->setShortcut(tr("Shift+O"));
1208 _edit_ol_action->setStatusTip("Makes object layer of the map current");
1209 _edit_ol_action->setCheckable(true);
1210 connect(_edit_ol_action, SIGNAL(triggered()), this, SLOT(_TileEditOL()));
1211
1212 _edit_group = new QActionGroup(this);
1213 _edit_group->addAction(_edit_ll_action);
1214 _edit_group->addAction(_edit_ml_action);
1215 _edit_group->addAction(_edit_ul_action);
1216 _edit_group->addAction(_edit_ol_action);
1217 _edit_ll_action->setChecked(true);
1218
1219
1220
1221 // Create tileset actions related to the Tileset Menu
1222
1223 _edit_tileset_action = new QAction("Edit &Tileset", this);
1224 _edit_tileset_action->setStatusTip("Lets the user paint walkability on the tileset");
1225 //_edit_walkability_action->setCheckable(true);
1226 connect(_edit_tileset_action, SIGNAL(triggered()), this, SLOT(_TilesetEdit()));
1227
1228
1229
1230 // Create menu actions related to the Map menu
1231
1232 _select_music_action = new QAction("&Select map music...", this);
1233 _select_music_action->setStatusTip("Choose background music for the map");
1234 connect(_select_music_action, SIGNAL(triggered()), this, SLOT(_MapSelectMusic()));
1235
1236 _context_properties_action = new QAction("&Add Context...", this);
1237 _context_properties_action->setStatusTip("Create a new context on the map");
1238 connect(_context_properties_action, SIGNAL(triggered()), this, SLOT(_MapAddContext()));
1239
1240 _map_properties_action = new QAction("&Properties...", this);
1241 _map_properties_action->setStatusTip("Modify the properties of the map");
1242 connect(_map_properties_action, SIGNAL(triggered()), this, SLOT(_MapProperties()));
1243
1244
1245
1246 // Create menu actions related to the Script menu
1247 _edit_skill_action = new QAction("Edit S&kills", this);
1248 _edit_skill_action->setStatusTip("Add/Edit skills");
1249 connect(_edit_skill_action, SIGNAL(triggered()), this, SLOT(_ScriptEditSkills()));
1250
1251
1252
1253 // Create menu actions related to the Help menu
1254
1255 _help_action = new QAction("&Help", this);
1256 _help_action->setShortcut(Qt::Key_F1);
1257 _help_action->setStatusTip("Brings up help documentation for the editor");
1258 connect(_help_action, SIGNAL(triggered()), this, SLOT(_HelpHelp()));
1259
1260 _about_action = new QAction("&About", this);
1261 _about_action->setStatusTip("Brings up information about the editor");
1262 connect(_about_action, SIGNAL(triggered()), this, SLOT(_HelpAbout()));
1263
1264 _about_qt_action = new QAction("About &Qt", this);
1265 _about_qt_action->setStatusTip("Brings up information about Qt");
1266 connect(_about_qt_action, SIGNAL(triggered()), this, SLOT(_HelpAboutQt()));
1267 } // _CreateActions()
1268
_CreateMenus()1269 void Editor::_CreateMenus()
1270 {
1271 // file menu creation
1272 _file_menu = menuBar()->addMenu("&File");
1273 _file_menu->addAction(_new_action);
1274 _file_menu->addAction(_open_action);
1275 _file_menu->addSeparator();
1276 _file_menu->addAction(_save_action);
1277 _file_menu->addAction(_save_as_action);
1278 _file_menu->addSeparator();
1279 _file_menu->addAction(_close_action);
1280 _file_menu->addAction(_quit_action);
1281 connect(_file_menu, SIGNAL(aboutToShow()), this, SLOT(_FileMenuSetup()));
1282
1283 // view menu creation
1284 _view_menu = menuBar()->addMenu("&View");
1285 _view_menu->addAction(_toggle_grid_action);
1286 _view_menu->addSeparator();
1287 _view_menu->addAction(_toggle_ll_action);
1288 _view_menu->addAction(_toggle_ml_action);
1289 _view_menu->addAction(_toggle_ul_action);
1290 _view_menu->addAction(_toggle_ol_action);
1291 _view_menu->addSeparator();
1292 _view_menu->addAction(_coord_tile_action);
1293 _view_menu->addAction(_coord_collision_action);
1294 _view_menu->addSeparator();
1295 _view_menu->addAction(_view_textures_action);
1296 _view_menu->setTearOffEnabled(true);
1297 connect(_view_menu, SIGNAL(aboutToShow()), this, SLOT(_ViewMenuSetup()));
1298
1299 // tile menu creation
1300 _tiles_menu = menuBar()->addMenu("&Tiles");
1301 _tiles_menu->addAction(_undo_action);
1302 _tiles_menu->addAction(_redo_action);
1303 _tiles_menu->addSeparator();
1304 _tiles_menu->addAction(_layer_fill_action);
1305 _tiles_menu->addAction(_layer_clear_action);
1306 _tiles_menu->addSeparator();
1307 _tiles_menu->addAction(_toggle_select_action);
1308 _tiles_menu->addSeparator()->setText("Editing Mode");
1309 _tiles_menu->addAction(_mode_paint_action);
1310 _tiles_menu->addAction(_mode_move_action);
1311 _tiles_menu->addAction(_mode_delete_action);
1312 _tiles_menu->addSeparator()->setText("Current Layer");
1313 _tiles_menu->addAction(_edit_ll_action);
1314 _tiles_menu->addAction(_edit_ml_action);
1315 _tiles_menu->addAction(_edit_ul_action);
1316 _tiles_menu->addAction(_edit_ol_action);
1317
1318 _tiles_menu->setTearOffEnabled(true);
1319 connect(_tiles_menu, SIGNAL(aboutToShow()), this, SLOT(_TilesEnableActions()));
1320
1321 // tileset menu creation
1322 _tileset_menu = menuBar()->addMenu("Tile&set");
1323 _tileset_menu->addAction(_edit_tileset_action);
1324 connect(_tileset_menu, SIGNAL(aboutToShow()), this, SLOT(_TilesetMenuSetup()));
1325
1326 // map menu creation
1327 _map_menu = menuBar()->addMenu("&Map");
1328 _map_menu->addAction(_select_music_action);
1329 _map_menu->addAction(_context_properties_action);
1330 _map_menu->addSeparator();
1331 _map_menu->addAction(_map_properties_action);
1332 connect(_map_menu, SIGNAL(aboutToShow()), this, SLOT(_MapMenuSetup()));
1333
1334 // script menu creation
1335 _script_menu = menuBar()->addMenu("&Script");
1336 _script_menu->addAction(_edit_skill_action);
1337 connect(_script_menu, SIGNAL(aboutToShow()), this, SLOT(_ScriptMenuSetup()));
1338
1339 // help menu creation
1340 _help_menu = menuBar()->addMenu("&Help");
1341 _help_menu->addAction(_help_action);
1342 _help_menu->addAction(_about_action);
1343 _help_menu->addAction(_about_qt_action);
1344 } // _CreateMenus()
1345
_CreateToolbars()1346 void Editor::_CreateToolbars()
1347 {
1348 _tiles_toolbar = addToolBar("Tiles");
1349 _tiles_toolbar->addAction(_layer_fill_action);
1350 _tiles_toolbar->addSeparator();
1351 _tiles_toolbar->addAction(_mode_paint_action);
1352 _tiles_toolbar->addAction(_mode_move_action);
1353 _tiles_toolbar->addAction(_mode_delete_action);
1354 _tiles_toolbar->addSeparator();
1355 _tiles_toolbar->addAction(_undo_action);
1356 _tiles_toolbar->addAction(_redo_action);
1357 _tiles_toolbar->addSeparator();
1358 _tiles_toolbar->addAction(_toggle_select_action);
1359 _tiles_toolbar->addSeparator();
1360
1361 QLabel* context_label = new QLabel("Context:", this);
1362 _tiles_toolbar->addWidget(context_label);
1363 _context_cbox = new QComboBox(this);
1364 _context_cbox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
1365 _context_cbox->addItem("Base");
1366 _tiles_toolbar->addWidget(_context_cbox);
1367 connect(_context_cbox, SIGNAL(currentIndexChanged(int)), this,
1368 SLOT(_SwitchMapContext(int)));
1369 } // _CreateToolbars()
1370
_EraseOK()1371 bool Editor::_EraseOK()
1372 {
1373 if (_ed_scrollview != NULL && _ed_scrollview->_map != NULL)
1374 {
1375 if (_ed_scrollview->_map->GetChanged())
1376 {
1377 switch(QMessageBox::warning(this, "Unsaved File", "The document contains unsaved changes!\n"
1378 "Do you want to save the changes before proceeding?", "&Save", "&Discard", "Cancel",
1379 0, // Enter == button 0
1380 2)) // Escape == button 2
1381 {
1382 case 0: // Save clicked or Alt+S pressed or Enter pressed.
1383 // save and exit
1384 _FileSave();
1385 break;
1386 case 1: // Discard clicked or Alt+D pressed
1387 // don't save but exit
1388 break;
1389 default: // Cancel clicked or Escape pressed
1390 // don't exit
1391 statusBar()->showMessage("Save abandoned", 5000);
1392 return false;
1393 } // warn the user to save
1394 } // map has been modified
1395 } // map must exist first
1396
1397 return true;
1398 } // _EraseOK()
1399
1400
1401
1402 /************************
1403 EditorScrollView class functions follow
1404 ************************/
1405
EditorScrollView(QWidget * parent,const QString & name,int width,int height)1406 EditorScrollView::EditorScrollView(QWidget* parent, const QString& name,
1407 int width, int height)
1408 : Q3ScrollView(parent, (const char*) name,
1409 Qt::WNoAutoErase|Qt::WStaticContents)
1410 {
1411 // Set default editing modes.
1412 _tile_mode = PAINT_TILE;
1413 _layer_edit = LOWER_LAYER;
1414 _moving = false;
1415
1416 // Clear the undo/redo vectors.
1417 _tile_indeces.clear();
1418 _previous_tiles.clear();
1419 _modified_tiles.clear();
1420
1421 // set viewport
1422 viewport()->setMouseTracking(true);
1423
1424 // for tracking key events
1425 setFocusPolicy(Qt::StrongFocus);
1426
1427 // Create a new map.
1428 _map = new Grid(viewport(), "Untitled", width, height);
1429 _map->_ed_scrollview = this;
1430 addChild(_map);
1431
1432 // Create menu actions related to the Context menu.
1433 _insert_row_action = new QAction("Insert row", this);
1434 _insert_row_action->setStatusTip("Inserts a row of empty tiles on all layers above the currently selected tile");
1435 connect(_insert_row_action, SIGNAL(triggered()), this, SLOT(_ContextInsertRow()));
1436 _insert_column_action = new QAction("Insert column", this);
1437 _insert_column_action->setStatusTip("Inserts a column of empty tiles on all layers to the left of the currently selected tile");
1438 connect(_insert_column_action, SIGNAL(triggered()), this, SLOT(_ContextInsertColumn()));
1439 _delete_row_action = new QAction("Delete row", this);
1440 _delete_row_action->setStatusTip("Deletes the currently selected row of tiles from all layers");
1441 connect(_delete_row_action, SIGNAL(triggered()), this, SLOT(_ContextDeleteRow()));
1442 _delete_column_action = new QAction("Delete column", this);
1443 _delete_column_action->setStatusTip("Deletes the currently selected column of tiles from all layers");
1444 connect(_delete_column_action, SIGNAL(triggered()), this, SLOT(_ContextDeleteColumn()));
1445
1446 // Context menu creation.
1447 _context_menu = new QMenu(this);
1448 _context_menu->addAction(_insert_row_action);
1449 _context_menu->addAction(_insert_column_action);
1450 _context_menu->addSeparator();
1451 _context_menu->addAction(_delete_row_action);
1452 _context_menu->addAction(_delete_column_action);
1453 } // EditorScrollView constructor
1454
~EditorScrollView()1455 EditorScrollView::~EditorScrollView()
1456 {
1457 delete _map;
1458 _map = NULL;
1459 delete _context_menu;
1460 _context_menu = NULL;
1461 } // EditorScrollView destructor
1462
Resize(int width,int height)1463 void EditorScrollView::Resize(int width, int height)
1464 {
1465 _map->resize(width * TILE_WIDTH, height * TILE_HEIGHT);
1466 _map->SetHeight(height);
1467 _map->SetWidth(width);
1468 } // Resize(...)
1469
GetCurrentLayer()1470 vector<int32>& EditorScrollView::GetCurrentLayer()
1471 {
1472 return _map->GetLayer(_layer_edit, _map->GetContext());
1473 } // GetCurrentLayer()
1474
1475
1476
1477 // ********** Protected functions **********
1478
contentsMousePressEvent(QMouseEvent * evt)1479 void EditorScrollView::contentsMousePressEvent(QMouseEvent* evt)
1480 {
1481 // don't draw outside the map
1482 if ((evt->y() / TILE_HEIGHT) >= static_cast<uint32>(_map->GetHeight()) ||
1483 (evt->x() / TILE_WIDTH) >= static_cast<uint32>(_map->GetWidth()) ||
1484 evt->x() < 0 || evt->y() < 0)
1485 return;
1486
1487 // get reference to Editor
1488 Editor* editor = static_cast<Editor*> (topLevelWidget());
1489
1490 _map->SetChanged(true);
1491
1492 int16 selection_count = 0;
1493 if(_layer_edit != OBJECT_LAYER) {
1494 // record location of pressed tile
1495 _tile_index = static_cast<int32>
1496 (evt->y() / TILE_HEIGHT * _map->GetWidth() + evt->x() / TILE_WIDTH);
1497
1498 // record the location of the beginning of the selection rectangle
1499 if (evt->button() == Qt::LeftButton && editor->_select_on == true &&
1500 _moving == false)
1501 {
1502 _first_corner_index = _tile_index;
1503 _map->GetLayer(SELECT_LAYER, 0)[_tile_index] = 1;
1504 } // selection mode is on
1505 } else {
1506 // select sprites
1507
1508 // check for selection amounts
1509 for( std::list<MapSprite*>::iterator it=_map->sprites.begin(); it!=_map->sprites.end(); it++ )
1510 if( (*it)->is_selected == true )
1511 selection_count++;
1512
1513 for( std::list<MapSprite*>::iterator it=_map->sprites.begin(); it!=_map->sprites.end(); it++ )
1514 {
1515 if( (*it)->IsInHoverArea(static_cast<float>(evt->x())/TILE_WIDTH, static_cast<float>(evt->y())/ TILE_HEIGHT) )
1516 { // in the hovering area
1517
1518 (*it)->is_selected = true;
1519 if(selection_count <= 0) // the last one selection, if there's 2 more selections, substract it...
1520 break;
1521 else // deselect it unless we got the last one selection
1522 {
1523 selection_count--;
1524 (*it)->is_selected = false;
1525 }
1526 }
1527 else // if not in the hovering area, deselect it
1528 (*it)->is_selected = false;
1529 }
1530 }
1531
1532 if (_layer_edit != OBJECT_LAYER)
1533 {
1534 switch (_tile_mode)
1535 {
1536 case PAINT_TILE: // start painting tiles
1537 {
1538 if (evt->button() == Qt::LeftButton && editor->_select_on == false)
1539 _PaintTile(_tile_index);
1540
1541 break;
1542 } // edit mode PAINT_TILE
1543
1544 case MOVE_TILE: // start moving a tile
1545 {
1546 // select tiles
1547 if(_layer_edit != OBJECT_LAYER) {
1548 _move_source_index = _tile_index;
1549 if (editor->_select_on == false)
1550 _moving = true;
1551 }
1552 break;
1553 } // edit mode MOVE_TILE
1554
1555 case DELETE_TILE: // start deleting tiles
1556 {
1557 if (evt->button() == Qt::LeftButton && editor->_select_on == false)
1558 _DeleteTile(_tile_index);
1559
1560 break;
1561 } // edit mode DELETE_TILE
1562
1563 default:
1564 QMessageBox::warning(this, "Tile editing mode",
1565 "ERROR: Invalid tile editing mode!");
1566 } // switch on tile editing mode
1567 } // don't manipulate tiles on the object layer
1568
1569 // Draw the changes.
1570 _map->updateGL();
1571 } // contentsMousePressEvent(...)
1572
contentsMouseMoveEvent(QMouseEvent * evt)1573 void EditorScrollView::contentsMouseMoveEvent(QMouseEvent *evt)
1574 {
1575 // get reference to Editor
1576 Editor* editor = static_cast<Editor*> (topLevelWidget());
1577
1578 // don't draw outside the map
1579 if ((evt->y() / TILE_HEIGHT) >= static_cast<uint32>(_map->GetHeight()) ||
1580 (evt->x() / TILE_WIDTH) >= static_cast<uint32>(_map->GetWidth()) ||
1581 evt->x() < 0 || evt->y() < 0 )
1582 {
1583 editor->statusBar()->clear();
1584 return;
1585 }
1586
1587 // Move sprites
1588 bool is_object_layer = (_layer_edit == OBJECT_LAYER);
1589 if(is_object_layer && evt->buttons() == Qt::LeftButton) {
1590 for( std::list<MapSprite*>::iterator it=_map->sprites.begin(); it!=_map->sprites.end(); it++ )
1591 if( (*it)->is_selected ) {
1592 float x = evt->x();
1593 float y = evt->y();
1594 float x_position = x*2/TILE_WIDTH + (*it)->img_half_width/2;
1595 float y_position = y*2/TILE_HEIGHT + (*it)->img_height/2;
1596 (*it)->SetXPosition( x_position, 0 );
1597 (*it)->SetYPosition( y_position, 0 );
1598 }
1599 }
1600 int32 index = static_cast<int32>
1601 (evt->y() / TILE_HEIGHT * _map->GetWidth() + evt->x() / TILE_WIDTH);
1602
1603 if (index != _tile_index && !is_object_layer) // user has moved onto another tile
1604 // ignore the object layer
1605 {
1606 _tile_index = index;
1607
1608 if (evt->state() == Qt::LeftButton && editor->_select_on == true &&
1609 _moving == false)
1610 {
1611 // Calculate the actual selection rectangle here, otherwise it's just
1612 // like selecting individual tiles...
1613 int x_old = _first_corner_index % _map->GetWidth();
1614 int y_old = _first_corner_index / _map->GetWidth();
1615 int x_new = _tile_index % _map->GetWidth();
1616 int y_new = _tile_index / _map->GetWidth();
1617
1618 // Swap the coordinates around so *_old is always smaller than *_new.
1619 int temp;
1620 if (x_old > x_new)
1621 {
1622 temp = x_old;
1623 x_old = x_new;
1624 x_new = temp;
1625 }
1626 if (y_old > y_new)
1627 {
1628 temp = y_old;
1629 y_old = y_new;
1630 y_new = temp;
1631 }
1632
1633 for (int y = y_old; y <= y_new; y++)
1634 for (int x = x_old; x <= x_new; x++)
1635 _map->GetLayer(SELECT_LAYER, 0)[y * _map->GetWidth() + x] = 1;
1636 } // left mouse button was pressed and selection mode is on
1637
1638 switch (_tile_mode)
1639 {
1640 case PAINT_TILE: // continue painting tiles
1641 {
1642 if (evt->state() == Qt::LeftButton && editor->_select_on == false)
1643 _PaintTile(_tile_index);
1644
1645 break;
1646 } // edit mode PAINT_TILE
1647
1648 case MOVE_TILE: // continue moving a tile
1649 {
1650 break;
1651 } // edit mode MOVE_TILE
1652
1653 case DELETE_TILE: // continue deleting tiles
1654 {
1655 if (evt->state() == Qt::LeftButton && editor->_select_on == false)
1656 _DeleteTile(_tile_index);
1657
1658 break;
1659 } // edit mode DELETE_TILE
1660
1661 default:
1662 QMessageBox::warning(this, "Tile editing mode",
1663 "ERROR: Invalid tile editing mode!");
1664 } // switch on tile editing mode
1665 } // mouse has moved to a new tile position
1666
1667 // Display mouse position in the format specified by _coord_type
1668 QString position;
1669 if (editor->_coord_type == 0)
1670 position = QString("x: %1 y: %2").arg(static_cast<double>(evt->x() / TILE_WIDTH), 0, 'f', 0).arg(
1671 static_cast<double>(evt->y() / TILE_HEIGHT), 0, 'f', 0);
1672 else if (editor->_coord_type == 1)
1673 position = QString("x: %1 y: %2").arg(static_cast<double>(evt->x() * 2 / TILE_WIDTH), 0, 'f', 0).arg(
1674 static_cast<double>(evt->y() * 2 / TILE_HEIGHT), 0, 'f', 0);
1675 else
1676 position = QString("x: %1 y: %2").arg(evt->x() / static_cast<float>(TILE_WIDTH), 0, 'f', 1).arg(
1677 evt->y() / static_cast<float>(TILE_HEIGHT), 0, 'f', 1);
1678 editor->statusBar()->showMessage(position);
1679
1680 // Draw the changes.
1681 _map->updateGL();
1682 } // contentsMouseMoveEvent(...)
1683
contentsMouseReleaseEvent(QMouseEvent * evt)1684 void EditorScrollView::contentsMouseReleaseEvent(QMouseEvent *evt)
1685 {
1686 vector<int32>::iterator it; // used to iterate over an entire layer
1687
1688 // get reference to Editor so we can access the undo stack
1689 Editor* editor = static_cast<Editor*> (topLevelWidget());
1690
1691 bool is_object_layer = (_layer_edit == OBJECT_LAYER);
1692 if( !is_object_layer )
1693 {
1694 switch (_tile_mode)
1695 {
1696 case PAINT_TILE: // wrap up painting tiles
1697 {
1698 if (editor->_select_on == true)
1699 {
1700 vector<int32> select_layer = _map->GetLayer(SELECT_LAYER, 0);
1701 for (int32 i = 0; i < static_cast<int32>(select_layer.size()); i++)
1702 {
1703 // Works because the selection layer and the current layer
1704 // are the same size.
1705 if (select_layer[i] != -1)
1706 _PaintTile(i);
1707 } // iterate over selection layer
1708 } // only if painting a bunch of tiles
1709
1710 // Push command onto the undo stack.
1711 LayerCommand* paint_command = new LayerCommand(_tile_indeces,
1712 _previous_tiles, _modified_tiles, _layer_edit,
1713 _map->GetContext(), editor, "Paint");
1714 editor->_undo_stack->push(paint_command);
1715 _tile_indeces.clear();
1716 _previous_tiles.clear();
1717 _modified_tiles.clear();
1718 break;
1719 } // edit mode PAINT_TILE
1720
1721 case MOVE_TILE: // wrap up moving tiles
1722 {
1723 if (_moving == true)
1724 {
1725 // record location of released tile
1726 _tile_index = static_cast<int32>
1727 (evt->y() / TILE_HEIGHT * _map->GetWidth() + evt->x() / TILE_WIDTH);
1728 vector<int32>& layer = GetCurrentLayer();
1729
1730 if (editor->_select_on == false)
1731 {
1732 // Record information for undo/redo action.
1733 _tile_indeces.push_back(_move_source_index);
1734 _previous_tiles.push_back(layer[_move_source_index]);
1735 _modified_tiles.push_back(-1);
1736 _tile_indeces.push_back(_tile_index);
1737 _previous_tiles.push_back(layer[_tile_index]);
1738 _modified_tiles.push_back(layer[_move_source_index]);
1739
1740 // Perform the move.
1741 layer[_tile_index] = layer[_move_source_index];
1742 layer[_move_source_index] = -1;
1743 } // only moving one tile at a time
1744 else
1745 {
1746 vector<int32> select_layer = _map->GetLayer(SELECT_LAYER, 0);
1747 for (int32 i = 0; i < static_cast<int32>(select_layer.size()); i++)
1748 {
1749 // Works because the selection layer and the current layer
1750 // are the same size.
1751 if (select_layer[i] != -1)
1752 {
1753 // Record information for undo/redo action.
1754 _tile_indeces.push_back(i);
1755 _previous_tiles.push_back(layer[i]);
1756 _modified_tiles.push_back(-1);
1757 _tile_indeces.push_back(i + _tile_index - _move_source_index);
1758 _previous_tiles.push_back(layer[i + _tile_index - _move_source_index]);
1759 _modified_tiles.push_back(layer[i]);
1760
1761 // Perform the move.
1762 layer[i + _tile_index - _move_source_index] = layer[i];
1763 layer[i] = -1;
1764 } // only if current tile is selected
1765 } // iterate over selection layer
1766 } // moving a bunch of tiles at once
1767
1768 // Push command onto the undo stack.
1769 LayerCommand* move_command = new LayerCommand(_tile_indeces,
1770 _previous_tiles, _modified_tiles, _layer_edit,
1771 _map->GetContext(), editor, "Move");
1772 editor->_undo_stack->push(move_command);
1773 _tile_indeces.clear();
1774 _previous_tiles.clear();
1775 _modified_tiles.clear();
1776 } // moving tiles and not selecting them
1777
1778 break;
1779 } // edit mode MOVE_TILE
1780
1781 case DELETE_TILE: // wrap up deleting tiles
1782 {
1783 if (editor->_select_on == true)
1784 {
1785 vector<int32> select_layer = _map->GetLayer(SELECT_LAYER, 0);
1786 for (int32 i = 0; i < static_cast<int32>(select_layer.size()); i++)
1787 {
1788 // Works because the selection layer and the current layer
1789 // are the same size.
1790 if (select_layer[i] != -1)
1791 _DeleteTile(i);
1792 } // iterate over selection layer
1793 } // only if deleting a bunch of tiles
1794
1795 // Push command onto undo stack.
1796 LayerCommand* delete_command = new LayerCommand(_tile_indeces,
1797 _previous_tiles, _modified_tiles, _layer_edit,
1798 _map->GetContext(), editor, "Delete");
1799 editor->_undo_stack->push(delete_command);
1800 _tile_indeces.clear();
1801 _previous_tiles.clear();
1802 _modified_tiles.clear();
1803 break;
1804 } // edit mode DELETE_TILE
1805
1806 default:
1807 QMessageBox::warning(this, "Tile editing mode",
1808 "ERROR: Invalid tile editing mode!");
1809 } // switch on tile editing mode
1810 } // don't manipulate tiles on the object layer
1811
1812 // Clear the selection layer.
1813 if ((_tile_mode != MOVE_TILE || _moving == true) && editor->_select_on == true && !is_object_layer )
1814 {
1815 vector<int32>& select_layer = _map->GetLayer(SELECT_LAYER, 0);
1816 for (it = select_layer.begin(); it != select_layer.end(); it++)
1817 *it = -1;
1818 } // clears when not moving tiles or when moving tiles and not selecting them
1819
1820 if (editor->_select_on == true && _moving == false && _tile_mode == MOVE_TILE && !is_object_layer)
1821 _moving = true;
1822 else
1823 _moving = false;
1824
1825 // Draw the changes.
1826 _map->updateGL();
1827 } // contentsMouseReleaseEvent(...)
1828
contentsContextMenuEvent(QContextMenuEvent * evt)1829 void EditorScrollView::contentsContextMenuEvent(QContextMenuEvent *evt)
1830 {
1831 // Don't popup a menu outside the map.
1832 if ((evt->y() / TILE_HEIGHT) >= static_cast<uint32>(_map->GetHeight()) ||
1833 (evt->x() / TILE_WIDTH) >= static_cast<uint32>(_map->GetWidth()) ||
1834 evt->x() < 0 || evt->y() < 0)
1835 return;
1836
1837 _tile_index = evt->y() / TILE_HEIGHT * _map->GetWidth() + evt->x() / TILE_WIDTH;
1838 _context_menu->exec(QCursor::pos());
1839 (static_cast<Editor*> (topLevelWidget()))->statusBar()->clear();
1840 } // contentsContextMenuEvent(...)
1841
keyPressEvent(QKeyEvent * evt)1842 void EditorScrollView::keyPressEvent(QKeyEvent *evt)
1843 {
1844 if(evt->key() == Qt::Key_Delete && _layer_edit == OBJECT_LAYER)
1845 for( std::list<MapSprite*>::iterator it=_map->sprites.begin(); it!=_map->sprites.end(); it++ )
1846 if( (*it)->is_selected ) {
1847 _map->sprites.remove(*it);
1848 break; // break is needed for preventing iterator error
1849 }
1850
1851 } // keyPressEvent(...)
1852
1853
1854 // ********** Private slots **********
1855
_ContextInsertRow()1856 void EditorScrollView::_ContextInsertRow()
1857 {
1858 _map->InsertRow(_tile_index);
1859 } // _ContextInsertRow()
1860
_ContextInsertColumn()1861 void EditorScrollView::_ContextInsertColumn()
1862 {
1863 _map->InsertCol(_tile_index);
1864 } // _ContextInsertColumn()
1865
_ContextDeleteRow()1866 void EditorScrollView::_ContextDeleteRow()
1867 {
1868 _map->DeleteRow(_tile_index);
1869 } // _ContextDeleteRow()
1870
_ContextDeleteColumn()1871 void EditorScrollView::_ContextDeleteColumn()
1872 {
1873 _map->DeleteCol(_tile_index);
1874 } // _ContextDeleteColumn()
1875
1876
1877
1878 // ********** Private functions **********
1879
_PaintTile(int32 index)1880 void EditorScrollView::_PaintTile(int32 index)
1881 {
1882 // get reference to current tileset
1883 Editor* editor = static_cast<Editor*> (topLevelWidget());
1884 Q3Table* table = static_cast<Q3Table*> (editor->_ed_tabs->currentPage());
1885 QString tileset_name = editor->_ed_tabs->tabText(editor->_ed_tabs->currentIndex());
1886 Q3TableSelection selection = table->selection(0);
1887
1888 int32 multiplier = _map->tileset_names.findIndex(tileset_name);
1889 if (multiplier == -1)
1890 {
1891 _map->tileset_names.append(tileset_name);
1892 multiplier = _map->tileset_names.findIndex(tileset_name);
1893 } // calculate index of current tileset
1894
1895 if (selection.isActive() && (selection.numCols() * selection.numRows() > 1))
1896 {
1897 int32 map_row = index / _map->GetWidth();
1898 int32 map_col = index % _map->GetWidth();
1899
1900 // Draw tiles from tileset selection onto map, one tile at a time.
1901 for (int32 i = 0; i < selection.numRows() && map_row + i < _map->GetHeight(); i++)
1902 {
1903 for (int32 j = 0; j < selection.numCols() && map_col + j < _map->GetWidth(); j++)
1904 {
1905 int32 tileset_index = (selection.topRow() + i) * 16 + (selection.leftCol() + j);
1906 int32 tile = (map_row + i) * _map->GetWidth() + map_col + j;
1907
1908 // perform randomization for autotiles
1909 _AutotileRandomize(multiplier, tileset_index);
1910
1911 // Record information for undo/redo action.
1912 _tile_indeces.push_back(tile);
1913 _previous_tiles.push_back(GetCurrentLayer()[tile]);
1914 _modified_tiles.push_back(tileset_index + multiplier * 256);
1915
1916 GetCurrentLayer()[tile] = tileset_index + multiplier * 256;
1917 } // iterate through columns of selection
1918 } // iterate through rows of selection
1919 } // multiple tiles are selected
1920 else
1921 {
1922 // put selected tile from tileset into tile array at correct position
1923 int32 tileset_index = table->currentRow() * 16 + table->currentColumn();
1924
1925 // perform randomization for autotiles
1926 _AutotileRandomize(multiplier, tileset_index);
1927
1928 // Record information for undo/redo action.
1929 _tile_indeces.push_back(index);
1930 _previous_tiles.push_back(GetCurrentLayer()[index]);
1931 _modified_tiles.push_back(tileset_index + multiplier * 256);
1932
1933 GetCurrentLayer()[index] = tileset_index + multiplier * 256;
1934 } // a single tile is selected
1935
1936 } // _PaintTile(...)
1937
_DeleteTile(int32 index)1938 void EditorScrollView::_DeleteTile(int32 index)
1939 {
1940 // Record information for undo/redo action.
1941 _tile_indeces.push_back(index);
1942 _previous_tiles.push_back(GetCurrentLayer()[index]);
1943 _modified_tiles.push_back(-1);
1944
1945 // Delete the tile.
1946 GetCurrentLayer()[index] = -1;
1947 } // _DeleteTile(...)
1948
_AutotileRandomize(int32 & tileset_num,int32 & tile_index)1949 void EditorScrollView::_AutotileRandomize(int32& tileset_num, int32& tile_index)
1950 {
1951 map<int, string>::iterator it = _map->tilesets[tileset_num]->
1952 autotileability.find(tile_index);
1953
1954 if (it != _map->tilesets[tileset_num]->autotileability.end())
1955 {
1956 // Set up for opening autotiling.lua.
1957 ReadScriptDescriptor read_data;
1958 if (read_data.OpenFile("dat/tilesets/autotiling.lua", true) == false)
1959 QMessageBox::warning(this, "Loading File...",
1960 QString("ERROR: could not open dat/tilesets/autotiling.lua for reading!"));
1961
1962 read_data.OpenTable(it->second);
1963 int32 random_index = RandomBoundedInteger(1, static_cast<int32>(read_data.GetTableSize()));
1964 read_data.OpenTable(random_index);
1965 string tileset_name = read_data.ReadString(1);
1966 tile_index = read_data.ReadInt(2);
1967 read_data.CloseTable();
1968 tileset_num = _map->tileset_names.indexOf(
1969 QString(tileset_name.c_str()));
1970 read_data.CloseTable();
1971
1972 read_data.CloseFile();
1973
1974 _AutotileTransitions(tileset_num, tile_index, it->second);
1975 } // must have an autotileable tile
1976 } // _AutotileRandomize(...)
1977
_AutotileTransitions(int32 & tileset_num,int32 & tile_index,const string tile_group)1978 void EditorScrollView::_AutotileTransitions(int32& tileset_num, int32& tile_index, const string tile_group)
1979 {
1980 // These 2 vectors have a one-to-one correspondence. They should always
1981 // contain 8 entries.
1982 vector<int32> existing_tiles; // This vector will contain all the tiles around the current painted tile that need to be examined.
1983 vector<string> existing_groups; // This vector will contain the autotileable groups of the existing tiles.
1984
1985 // These booleans are used to know whether the current tile being painted is on the edge of the map.
1986 // This will affect the transition/border algorithm.
1987 bool top_edge = (_tile_index - _map->GetWidth()) < 0;
1988 bool bottom_edge = (_tile_index + _map->GetWidth()) >= (_map->GetWidth() * _map->GetHeight());
1989 bool left_edge = (_tile_index % _map->GetWidth()) == 0;
1990 bool right_edge = (_tile_index & _map->GetWidth()) == (_map->GetWidth() - 1);
1991
1992
1993 // Now figure out which tiles surround the current painted one and put them into the existing_tiles vector.
1994 if (!top_edge)
1995 {
1996 if (!left_edge)
1997 existing_tiles.push_back(GetCurrentLayer()[_tile_index - _map->GetWidth() - 1]);
1998 else
1999 existing_tiles.push_back(-1);
2000 existing_tiles.push_back(GetCurrentLayer()[_tile_index - _map->GetWidth()]);
2001 if (!right_edge)
2002 existing_tiles.push_back(GetCurrentLayer()[_tile_index - _map->GetWidth() + 1]);
2003 else
2004 existing_tiles.push_back(-1);
2005 } // make sure there is a row of tiles above the painted one
2006 else
2007 {
2008 existing_tiles.push_back(-1);
2009 existing_tiles.push_back(-1);
2010 existing_tiles.push_back(-1);
2011 } // these tiles don't exist
2012
2013 if (!left_edge)
2014 existing_tiles.push_back(GetCurrentLayer()[_tile_index - 1]);
2015 else
2016 existing_tiles.push_back(-1);
2017
2018 if (!right_edge)
2019 existing_tiles.push_back(GetCurrentLayer()[_tile_index + 1]);
2020 else
2021 existing_tiles.push_back(-1);
2022
2023 if (!bottom_edge)
2024 {
2025 if (!left_edge)
2026 existing_tiles.push_back(GetCurrentLayer()[_tile_index + _map->GetWidth() - 1]);
2027 else
2028 existing_tiles.push_back(-1);
2029 existing_tiles.push_back(GetCurrentLayer()[_tile_index + _map->GetWidth()]);
2030 if (!right_edge)
2031 existing_tiles.push_back(GetCurrentLayer()[_tile_index + _map->GetWidth() + 1]);
2032 else
2033 existing_tiles.push_back(-1);
2034 } // make sure there is a row of tiles below the painted one
2035 else
2036 {
2037 existing_tiles.push_back(-1);
2038 existing_tiles.push_back(-1);
2039 existing_tiles.push_back(-1);
2040 } // these tiles don't exist
2041
2042
2043 // Now figure out what groups the existing tiles belong to.
2044 for (unsigned int i = 0; i < existing_tiles.size(); i++)
2045 {
2046 int32 multiplier = existing_tiles[i] / 256;
2047 int32 tileset_index = existing_tiles[i] % 256;
2048 map<int, string>::iterator it = _map->tilesets[multiplier]->
2049 autotileability.find(tileset_index);
2050
2051 // Here we check to make sure the tile exists in the autotileability
2052 // table. But if the tile in question is a transition tile with multiple
2053 // variations, we want to assign it a group name of "none", otherwise
2054 // the pattern detection algorithm won't work properly. Transition tiles
2055 // with multiple variations are still handled correctly.
2056 if (it != _map->tilesets[multiplier]->autotileability.end() &&
2057 it->second.find("east", 0) == string::npos &&
2058 it->second.find("north", 0) == string::npos &&
2059 it->second.find("_ne", 0) == string::npos &&
2060 it->second.find("ne_corner", 0) == string::npos &&
2061 it->second.find("_nw", 0) == string::npos &&
2062 it->second.find("nw_corner", 0) == string::npos &&
2063 it->second.find("_se", 0) == string::npos &&
2064 it->second.find("se_corner", 0) == string::npos &&
2065 it->second.find("south", 0) == string::npos &&
2066 it->second.find("_sw", 0) == string::npos &&
2067 it->second.find("sw_corner", 0) == string::npos &&
2068 it->second.find("west", 0) == string::npos)
2069 existing_groups.push_back(it->second);
2070 else
2071 existing_groups.push_back("none");
2072 } // iterate through the existing_tiles vector
2073
2074
2075 // Transition tiles exist only for certain patterns of tiles surrounding the painted tile.
2076 // Check for any of these patterns, and if one exists, transition magic begins!
2077
2078 string transition_group = "none"; // autotileable grouping for the border tile if it exists
2079 TRANSITION_PATTERN_TYPE pattern = _CheckForTransitionPattern(tile_group, existing_groups,
2080 transition_group);
2081
2082 if (pattern != INVALID_PATTERN)
2083 {
2084 transition_group = tile_group + "_" + transition_group;
2085
2086 // Set up for opening autotiling.lua.
2087 ReadScriptDescriptor read_data;
2088 if (read_data.OpenFile("dat/tilesets/autotiling.lua", true) == false)
2089 QMessageBox::warning(this, "Loading File...",
2090 QString("ERROR: could not open dat/tilesets/autotiling.lua for reading!"));
2091
2092 // Extract the correct transition tile from autotiling.lua as determined by
2093 // _CheckForTransitionPattern(...).
2094 if (read_data.DoesTableExist(transition_group) == true)
2095 {
2096 read_data.OpenTable(transition_group);
2097
2098 switch (pattern)
2099 {
2100 case NW_BORDER_PATTERN:
2101 //cerr << "nw_border" << endl;
2102 read_data.OpenTable(1);
2103 break;
2104 case N_BORDER_PATTERN:
2105 //cerr << "n_border" << endl;
2106 read_data.OpenTable(2);
2107 break;
2108 case NE_BORDER_PATTERN:
2109 //cerr << "ne_border" << endl;
2110 read_data.OpenTable(3);
2111 break;
2112 case E_BORDER_PATTERN:
2113 //cerr << "e_border" << endl;
2114 read_data.OpenTable(4);
2115 break;
2116 case SE_BORDER_PATTERN:
2117 //cerr << "se_border" << endl;
2118 read_data.OpenTable(5);
2119 break;
2120 case S_BORDER_PATTERN:
2121 //cerr << "s_border" << endl;
2122 read_data.OpenTable(6);
2123 break;
2124 case SW_BORDER_PATTERN:
2125 //cerr << "sw_border" << endl;
2126 read_data.OpenTable(7);
2127 break;
2128 case W_BORDER_PATTERN:
2129 //cerr << "w_border" << endl;
2130 read_data.OpenTable(8);
2131 break;
2132 case NW_CORNER_PATTERN:
2133 //cerr << "nw_corner" << endl;
2134 read_data.OpenTable(9);
2135 break;
2136 case NE_CORNER_PATTERN:
2137 //cerr << "ne_corner" << endl;
2138 read_data.OpenTable(10);
2139 break;
2140 case SE_CORNER_PATTERN:
2141 //cerr << "se_corner" << endl;
2142 read_data.OpenTable(11);
2143 break;
2144 case SW_CORNER_PATTERN:
2145 //cerr << "sw_corner" << endl;
2146 read_data.OpenTable(12);
2147 break;
2148 default: // should never get here
2149 read_data.CloseTable();
2150 read_data.CloseFile();
2151 QMessageBox::warning(this, "Transition detection...",
2152 QString("ERROR: Invalid pattern detected! No autotiling will occur for this tile!"));
2153 return;
2154 } // switch on transition pattern
2155
2156 string tileset_name = read_data.ReadString(1);
2157 tile_index = read_data.ReadInt(2);
2158 read_data.CloseTable();
2159 tileset_num = _map->tileset_names.indexOf(
2160 QString(tileset_name.c_str()));
2161
2162 read_data.CloseTable();
2163
2164 // Border/transition tiles may also have variations, so randomize them.
2165 //assert(tileset_num != -1);
2166 _AutotileRandomize(tileset_num, tile_index);
2167 } // make sure the selected transition tiles exist
2168
2169 read_data.CloseFile();
2170 } // make sure a transition pattern exists
2171 } // _AutotileTransitions(...)
2172
_CheckForTransitionPattern(const string current_group,const vector<string> & surrounding_groups,string & border_group)2173 TRANSITION_PATTERN_TYPE EditorScrollView::_CheckForTransitionPattern(const string current_group,
2174 const vector<string>& surrounding_groups, string& border_group)
2175 {
2176 // Assumes that surrounding_groups always has 8 entries. Well, it's an error if it doesn't,
2177 // and technically should never happen.
2178
2179 if (
2180 (surrounding_groups[0] == surrounding_groups[1] || surrounding_groups[0] == "none") &&
2181 (surrounding_groups[2] == surrounding_groups[1] || surrounding_groups[2] == "none") &&
2182 (surrounding_groups[1] != current_group && surrounding_groups[1] != "none" &&
2183 current_group != "none") &&
2184 (surrounding_groups[3] == current_group ||
2185 surrounding_groups[3] == "none" ||
2186 surrounding_groups[3] == surrounding_groups[1]) &&
2187 (surrounding_groups[4] == current_group ||
2188 surrounding_groups[4] == "none" ||
2189 surrounding_groups[4] == surrounding_groups[1]) &&
2190 (surrounding_groups[5] != surrounding_groups[1]) &&
2191 (surrounding_groups[7] != surrounding_groups[1]) &&
2192 (surrounding_groups[6] != surrounding_groups[1]))
2193 {
2194 border_group = surrounding_groups[1];
2195 return N_BORDER_PATTERN;
2196 } // check for the northern border pattern
2197
2198 else if (
2199 (surrounding_groups[2] == surrounding_groups[4] || surrounding_groups[2] == "none") &&
2200 (surrounding_groups[7] == surrounding_groups[4] || surrounding_groups[7] == "none") &&
2201 (surrounding_groups[4] != current_group && surrounding_groups[4] != "none" &&
2202 current_group != "none") &&
2203 (surrounding_groups[1] == current_group ||
2204 surrounding_groups[1] == "none" ||
2205 surrounding_groups[1] == surrounding_groups[4]) &&
2206 (surrounding_groups[6] == current_group ||
2207 surrounding_groups[6] == "none" ||
2208 surrounding_groups[6] == surrounding_groups[4]) &&
2209 (surrounding_groups[0] != surrounding_groups[4]) &&
2210 (surrounding_groups[5] != surrounding_groups[4]) &&
2211 (surrounding_groups[3] != surrounding_groups[4]))
2212 {
2213 border_group = surrounding_groups[4];
2214 return E_BORDER_PATTERN;
2215 } // check for the eastern border pattern
2216
2217 else if (
2218 (surrounding_groups[7] == surrounding_groups[6] || surrounding_groups[7] == "none") &&
2219 (surrounding_groups[5] == surrounding_groups[6] || surrounding_groups[5] == "none") &&
2220 (surrounding_groups[6] != current_group && surrounding_groups[6] != "none" &&
2221 current_group != "none") &&
2222 (surrounding_groups[3] == current_group ||
2223 surrounding_groups[3] == "none" ||
2224 surrounding_groups[3] == surrounding_groups[6]) &&
2225 (surrounding_groups[4] == current_group ||
2226 surrounding_groups[4] == "none" ||
2227 surrounding_groups[4] == surrounding_groups[6]) &&
2228 (surrounding_groups[2] != surrounding_groups[6]) &&
2229 (surrounding_groups[0] != surrounding_groups[6]) &&
2230 (surrounding_groups[1] != surrounding_groups[6]))
2231 {
2232 border_group = surrounding_groups[6];
2233 return S_BORDER_PATTERN;
2234 } // check for the southern border pattern
2235
2236 else if (
2237 (surrounding_groups[0] == surrounding_groups[3] || surrounding_groups[0] == "none") &&
2238 (surrounding_groups[5] == surrounding_groups[3] || surrounding_groups[5] == "none") &&
2239 (surrounding_groups[3] != current_group && surrounding_groups[3] != "none" &&
2240 current_group != "none") &&
2241 (surrounding_groups[1] == current_group ||
2242 surrounding_groups[1] == "none" ||
2243 surrounding_groups[1] == surrounding_groups[3]) &&
2244 (surrounding_groups[6] == current_group ||
2245 surrounding_groups[6] == "none" ||
2246 surrounding_groups[6] == surrounding_groups[3]) &&
2247 (surrounding_groups[2] != surrounding_groups[3]) &&
2248 (surrounding_groups[7] != surrounding_groups[3]) &&
2249 (surrounding_groups[4] != surrounding_groups[3]))
2250 {
2251 border_group = surrounding_groups[3];
2252 return W_BORDER_PATTERN;
2253 } // check for the western border pattern
2254
2255 else if (
2256 (surrounding_groups[1] == surrounding_groups[0]) &&
2257 (surrounding_groups[3] == surrounding_groups[0]) &&
2258 (surrounding_groups[0] != current_group && surrounding_groups[0] != "none" &&
2259 current_group != "none") &&
2260 (surrounding_groups[4] == current_group || surrounding_groups[4] == "none") &&
2261 (surrounding_groups[6] == current_group || surrounding_groups[6] == "none") &&
2262 (surrounding_groups[7] != surrounding_groups[0]))
2263 {
2264 border_group = surrounding_groups[0];
2265 return NW_BORDER_PATTERN;
2266 } // check for the northwestern border pattern
2267
2268 else if (
2269 (surrounding_groups[1] == surrounding_groups[2]) &&
2270 (surrounding_groups[4] == surrounding_groups[2]) &&
2271 (surrounding_groups[2] != current_group && surrounding_groups[2] != "none" &&
2272 current_group != "none") &&
2273 (surrounding_groups[3] == current_group || surrounding_groups[3] == "none") &&
2274 (surrounding_groups[6] == current_group || surrounding_groups[6] == "none") &&
2275 (surrounding_groups[5] != surrounding_groups[2]))
2276 {
2277 border_group = surrounding_groups[2];
2278 return NE_BORDER_PATTERN;
2279 } // check for the northeastern border pattern
2280
2281 else if (
2282 (surrounding_groups[4] == surrounding_groups[7]) &&
2283 (surrounding_groups[6] == surrounding_groups[7]) &&
2284 (surrounding_groups[7] != current_group && surrounding_groups[7] != "none" &&
2285 current_group != "none") &&
2286 (surrounding_groups[1] == current_group || surrounding_groups[1] == "none") &&
2287 (surrounding_groups[3] == current_group || surrounding_groups[3] == "none") &&
2288 (surrounding_groups[0] != surrounding_groups[7]))
2289 {
2290 border_group = surrounding_groups[7];
2291 return SE_BORDER_PATTERN;
2292 } // check for the southeastern border pattern
2293
2294 else if (
2295 (surrounding_groups[3] == surrounding_groups[5]) &&
2296 (surrounding_groups[6] == surrounding_groups[5]) &&
2297 (surrounding_groups[5] != current_group && surrounding_groups[5] != "none" &&
2298 current_group != "none") &&
2299 (surrounding_groups[1] == current_group || surrounding_groups[1] == "none") &&
2300 (surrounding_groups[4] == current_group || surrounding_groups[4] == "none") &&
2301 (surrounding_groups[2] != surrounding_groups[5]))
2302 {
2303 border_group = surrounding_groups[5];
2304 return SW_BORDER_PATTERN;
2305 } // check for the southwestern border pattern
2306
2307 else if (
2308 (surrounding_groups[0] != current_group && surrounding_groups[0] != "none" &&
2309 current_group != "none") &&
2310 (surrounding_groups[1] == current_group || surrounding_groups[1] == "none") &&
2311 (surrounding_groups[3] == current_group || surrounding_groups[3] == "none") &&
2312 (surrounding_groups[2] != surrounding_groups[0]) &&
2313 (surrounding_groups[4] != surrounding_groups[0]) &&
2314 (surrounding_groups[5] != surrounding_groups[0]) &&
2315 (surrounding_groups[6] != surrounding_groups[0]) &&
2316 (surrounding_groups[7] != surrounding_groups[0]))
2317 {
2318 border_group = surrounding_groups[0];
2319 return NW_CORNER_PATTERN;
2320 } // check for the northwestern corner pattern
2321
2322 else if (
2323 (surrounding_groups[2] != current_group && surrounding_groups[2] != "none" &&
2324 current_group != "none") &&
2325 (surrounding_groups[1] == current_group || surrounding_groups[1] == "none") &&
2326 (surrounding_groups[4] == current_group || surrounding_groups[4] == "none") &&
2327 (surrounding_groups[0] != surrounding_groups[2]) &&
2328 (surrounding_groups[3] != surrounding_groups[2]) &&
2329 (surrounding_groups[5] != surrounding_groups[2]) &&
2330 (surrounding_groups[6] != surrounding_groups[2]) &&
2331 (surrounding_groups[7] != surrounding_groups[2]))
2332 {
2333 border_group = surrounding_groups[2];
2334 return NE_CORNER_PATTERN;
2335 } // check for the northeastern corner pattern
2336
2337 else if (
2338 (surrounding_groups[7] != current_group && surrounding_groups[7] != "none" &&
2339 current_group != "none") &&
2340 (surrounding_groups[4] == current_group || surrounding_groups[4] == "none") &&
2341 (surrounding_groups[6] == current_group || surrounding_groups[6] == "none") &&
2342 (surrounding_groups[0] != surrounding_groups[7]) &&
2343 (surrounding_groups[1] != surrounding_groups[7]) &&
2344 (surrounding_groups[2] != surrounding_groups[7]) &&
2345 (surrounding_groups[3] != surrounding_groups[7]) &&
2346 (surrounding_groups[5] != surrounding_groups[7]))
2347 {
2348 border_group = surrounding_groups[7];
2349 return SE_CORNER_PATTERN;
2350 } // check for the southeastern corner pattern
2351
2352 else if (
2353 (surrounding_groups[5] != current_group && surrounding_groups[5] != "none" &&
2354 current_group != "none") &&
2355 (surrounding_groups[3] == current_group || surrounding_groups[3] == "none") &&
2356 (surrounding_groups[6] == current_group || surrounding_groups[6] == "none") &&
2357 (surrounding_groups[0] != surrounding_groups[5]) &&
2358 (surrounding_groups[1] != surrounding_groups[5]) &&
2359 (surrounding_groups[2] != surrounding_groups[5]) &&
2360 (surrounding_groups[4] != surrounding_groups[5]) &&
2361 (surrounding_groups[7] != surrounding_groups[5]))
2362 {
2363 border_group = surrounding_groups[5];
2364 return SW_CORNER_PATTERN;
2365 } // check for the southwestern corner pattern
2366
2367 return INVALID_PATTERN;
2368 } // _CheckForTransitionPattern(...)
2369
2370
2371 /************************
2372 LayerCommand class functions follow
2373 ************************/
2374
LayerCommand(vector<int32> indeces,vector<int32> previous,vector<int32> modified,LAYER_TYPE layer,int context,Editor * editor,const QString & text,QUndoCommand * parent)2375 LayerCommand::LayerCommand(vector<int32> indeces, vector<int32> previous,
2376 vector<int32> modified, LAYER_TYPE layer, int context, Editor* editor,
2377 const QString& text, QUndoCommand* parent)
2378 : QUndoCommand(text, parent)
2379 {
2380 _tile_indeces = indeces;
2381 _previous_tiles = previous;
2382 _modified_tiles = modified;
2383 _edited_layer = layer;
2384 _context = context;
2385 _editor = editor;
2386 } // constructor
2387
undo()2388 void LayerCommand::undo()
2389 {
2390 for (int32 i = 0; i < static_cast<int32>(_tile_indeces.size()); i++)
2391 _editor->_ed_scrollview->_map->GetLayer(_edited_layer, _context)
2392 [_tile_indeces[i]] = _previous_tiles[i];
2393 _editor->_ed_scrollview->_map->updateGL();
2394 } // undo()
2395
redo()2396 void LayerCommand::redo()
2397 {
2398 for (int32 i = 0; i < static_cast<int32>(_tile_indeces.size()); i++)
2399 _editor->_ed_scrollview->_map->GetLayer(_edited_layer, _context)
2400 [_tile_indeces[i]] = _modified_tiles[i];
2401 _editor->_ed_scrollview->_map->updateGL();
2402 } // redo()
2403
2404