1 /* 2 Copyright (C) 2010-2014 Kristian Duske 3 4 This file is part of TrenchBroom. 5 6 TrenchBroom 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 3 of the License, or 9 (at your option) any later version. 10 11 TrenchBroom 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 TrenchBroom. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "MapFrame.h" 21 22 #include "TrenchBroomApp.h" 23 #include "Preferences.h" 24 #include "PreferenceManager.h" 25 #include "IO/DiskFileSystem.h" 26 #include "IO/ResourceUtils.h" 27 #include "Model/EditorContext.h" 28 #include "Model/Node.h" 29 #include "Model/NodeCollection.h" 30 #include "Model/PointFile.h" 31 #include "View/ActionManager.h" 32 #include "View/Autosaver.h" 33 #include "View/BorderLine.h" 34 #include "View/CachingLogger.h" 35 #include "View/CommandIds.h" 36 #include "View/Console.h" 37 #include "View/GLContextManager.h" 38 #include "View/Grid.h" 39 #include "View/InfoPanel.h" 40 #include "View/Inspector.h" 41 #include "View/MapDocument.h" 42 #include "View/MapFrameDropTarget.h" 43 #include "View/Menu.h" 44 #include "View/ReplaceTextureFrame.h" 45 #include "View/SplitterWindow2.h" 46 #include "View/SwitchableMapViewContainer.h" 47 #include "View/ViewUtils.h" 48 49 #include <wx/clipbrd.h> 50 #include <wx/display.h> 51 #include <wx/filedlg.h> 52 #include <wx/msgdlg.h> 53 #include <wx/persist.h> 54 #include <wx/sizer.h> 55 #include <wx/stdpaths.h> 56 #include <wx/timer.h> 57 58 #include <cassert> 59 60 namespace TrenchBroom { 61 namespace View { MapFrame()62 MapFrame::MapFrame() : 63 wxFrame(NULL, wxID_ANY, "TrenchBroom"), 64 m_frameManager(NULL), 65 m_autosaver(NULL), 66 m_autosaveTimer(NULL), 67 m_contextManager(NULL), 68 m_mapView(NULL), 69 m_console(NULL), 70 m_inspector(NULL), 71 m_lastFocus(NULL), 72 m_gridChoice(NULL) {} 73 MapFrame(FrameManager * frameManager,MapDocumentSPtr document)74 MapFrame::MapFrame(FrameManager* frameManager, MapDocumentSPtr document) : 75 wxFrame(NULL, wxID_ANY, "TrenchBroom"), 76 m_frameManager(NULL), 77 m_autosaver(NULL), 78 m_autosaveTimer(NULL), 79 m_contextManager(NULL), 80 m_mapView(NULL), 81 m_console(NULL), 82 m_inspector(NULL), 83 m_lastFocus(NULL), 84 m_gridChoice(NULL) { 85 Create(frameManager, document); 86 } 87 Create(FrameManager * frameManager,MapDocumentSPtr document)88 void MapFrame::Create(FrameManager* frameManager, MapDocumentSPtr document) { 89 assert(frameManager != NULL); 90 assert(document.get() != NULL); 91 92 m_frameManager = frameManager; 93 m_document = document; 94 m_autosaver = new Autosaver(m_document); 95 96 m_contextManager = new GLContextManager(); 97 98 createGui(); 99 createToolBar(); 100 createMenuBar(); 101 102 m_document->setParentLogger(logger()); 103 m_document->setViewEffectsService(m_mapView); 104 105 m_autosaveTimer = new wxTimer(this); 106 m_autosaveTimer->Start(1000); 107 108 bindObservers(); 109 bindEvents(); 110 111 clearDropTarget(); 112 } 113 ~MapFrame()114 MapFrame::~MapFrame() { 115 unbindObservers(); 116 removeRecentDocumentsMenu(GetMenuBar()); 117 118 delete m_autosaveTimer; 119 m_autosaveTimer = NULL; 120 121 delete m_autosaver; 122 m_autosaver = NULL; 123 124 // The order of deletion here is important because both the document and the children 125 // need the context manager (and its embedded VBO) to clean up their resources. 126 127 m_document->setViewEffectsService(NULL); 128 m_document.reset(); 129 DestroyChildren(); 130 131 delete m_contextManager; 132 m_contextManager = NULL; 133 } 134 positionOnScreen(wxFrame * reference)135 void MapFrame::positionOnScreen(wxFrame* reference) { 136 const wxDisplay display; 137 const wxRect displaySize = display.GetClientArea(); 138 if (reference == NULL) { 139 SetSize(std::min(displaySize.width, 1024), std::min(displaySize.height, 768)); 140 CenterOnScreen(); 141 } else { 142 wxPoint position = reference->GetPosition(); 143 position.x += 23; 144 position.y += 23; 145 146 if (displaySize.GetBottom() - position.x < 100 || 147 displaySize.GetRight() - position.y < 70) 148 position = displaySize.GetTopLeft(); 149 150 SetPosition(position); 151 SetSize(std::min(displaySize.GetRight() - position.x, 1024), std::min(displaySize.GetBottom() - position.y, 768)); 152 } 153 } 154 logger() const155 Logger* MapFrame::logger() const { 156 return m_console; 157 } 158 setToolBoxDropTarget()159 void MapFrame::setToolBoxDropTarget() { 160 SetDropTarget(NULL); 161 m_mapView->setToolBoxDropTarget(); 162 } 163 clearDropTarget()164 void MapFrame::clearDropTarget() { 165 m_mapView->clearDropTarget(); 166 SetDropTarget(new MapFrameDropTarget(m_document, this)); 167 } 168 newDocument(Model::GamePtr game,const Model::MapFormat::Type mapFormat)169 bool MapFrame::newDocument(Model::GamePtr game, const Model::MapFormat::Type mapFormat) { 170 if (!confirmOrDiscardChanges()) 171 return false; 172 m_document->newDocument(mapFormat, MapDocument::DefaultWorldBounds, game); 173 return true; 174 } 175 openDocument(Model::GamePtr game,const Model::MapFormat::Type mapFormat,const IO::Path & path)176 bool MapFrame::openDocument(Model::GamePtr game, const Model::MapFormat::Type mapFormat, const IO::Path& path) { 177 if (!confirmOrDiscardChanges()) 178 return false; 179 m_document->loadDocument(mapFormat, MapDocument::DefaultWorldBounds, game, path); 180 return true; 181 } 182 saveDocument()183 bool MapFrame::saveDocument() { 184 try { 185 const IO::Path& path = m_document->path(); 186 if (path.isAbsolute() && IO::Disk::fileExists(IO::Disk::fixPath(path))) { 187 m_document->saveDocument(); 188 logger()->info("Saved " + m_document->path().asString()); 189 return true; 190 } 191 return saveDocumentAs(); 192 } catch (FileSystemException e) { 193 ::wxMessageBox(e.what(), "", wxOK | wxICON_ERROR, this); 194 return false; 195 } catch (...) { 196 ::wxMessageBox("Unknown error while saving " + m_document->path().asString(), "", wxOK | wxICON_ERROR, this); 197 return false; 198 } 199 } 200 saveDocumentAs()201 bool MapFrame::saveDocumentAs() { 202 try { 203 const IO::Path& originalPath = m_document->path(); 204 const IO::Path directory = originalPath.deleteLastComponent(); 205 const IO::Path fileName = originalPath.lastComponent(); 206 wxFileDialog saveDialog(this, "Save map file", directory.asString(), fileName.asString(), "Map files (*.map)|*.map", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); 207 if (saveDialog.ShowModal() == wxID_CANCEL) 208 return false; 209 210 const IO::Path path(saveDialog.GetPath().ToStdString()); 211 m_document->saveDocumentAs(path); 212 logger()->info("Saved " + m_document->path().asString()); 213 return true; 214 } catch (FileSystemException e) { 215 ::wxMessageBox(e.what(), "", wxOK | wxICON_ERROR, this); 216 return false; 217 } catch (...) { 218 ::wxMessageBox("Unknown error while saving " + m_document->filename(), "", wxOK | wxICON_ERROR, this); 219 return false; 220 } 221 } 222 confirmOrDiscardChanges()223 bool MapFrame::confirmOrDiscardChanges() { 224 if (!m_document->modified()) 225 return true; 226 const int result = ::wxMessageBox(m_document->filename() + " has been modified. Do you want to save the changes?", "TrenchBroom", wxYES_NO | wxCANCEL, this); 227 switch (result) { 228 case wxYES: 229 return saveDocument(); 230 case wxNO: 231 return true; 232 default: 233 return false; 234 } 235 } 236 updateTitle()237 void MapFrame::updateTitle() { 238 #ifdef __APPLE__ 239 SetTitle(m_document->filename()); 240 OSXSetModified(m_document->modified()); 241 #else 242 SetTitle(wxString(m_document->filename()) + wxString(m_document->modified() ? "*" : "") + wxString(" - TrenchBroom")); 243 #endif 244 SetRepresentedFilename(m_document->path().asString()); 245 } 246 OnChildFocus(wxChildFocusEvent & event)247 void MapFrame::OnChildFocus(wxChildFocusEvent& event) { 248 if (IsBeingDeleted()) return; 249 250 wxWindow* focus = FindFocus(); 251 if (focus != m_lastFocus && focus != this) { 252 rebuildMenuBar(); 253 m_lastFocus = focus; 254 } 255 } 256 rebuildMenuBar()257 void MapFrame::rebuildMenuBar() { 258 wxMenuBar* oldMenuBar = GetMenuBar(); 259 removeRecentDocumentsMenu(oldMenuBar); 260 createMenuBar(); 261 #ifndef __LINUX__ 262 #ifndef wxUSE_IDLEMENUUPDATES 263 // Don't delete the old menu bar on Ubuntu. It will leak, but otherwise we crash on the next idle update. 264 oldMenuBar->Destroy(); 265 #endif 266 #endif 267 } 268 createMenuBar()269 void MapFrame::createMenuBar() { 270 const ActionManager& actionManager = ActionManager::instance(); 271 wxMenuBar* menuBar = actionManager.createMenuBar(m_mapView->viewportHasFocus()); 272 SetMenuBar(menuBar); 273 addRecentDocumentsMenu(menuBar); 274 } 275 addRecentDocumentsMenu(wxMenuBar * menuBar)276 void MapFrame::addRecentDocumentsMenu(wxMenuBar* menuBar) { 277 const ActionManager& actionManager = ActionManager::instance(); 278 wxMenu* recentDocumentsMenu = actionManager.findRecentDocumentsMenu(menuBar); 279 assert(recentDocumentsMenu != NULL); 280 281 TrenchBroomApp& app = TrenchBroomApp::instance(); 282 app.addRecentDocumentMenu(recentDocumentsMenu); 283 } 284 removeRecentDocumentsMenu(wxMenuBar * menuBar)285 void MapFrame::removeRecentDocumentsMenu(wxMenuBar* menuBar) { 286 const ActionManager& actionManager = ActionManager::instance(); 287 wxMenu* recentDocumentsMenu = actionManager.findRecentDocumentsMenu(menuBar); 288 assert(recentDocumentsMenu != NULL); 289 290 TrenchBroomApp& app = TrenchBroomApp::instance(); 291 app.removeRecentDocumentMenu(recentDocumentsMenu); 292 } 293 updateRecentDocumentsMenu()294 void MapFrame::updateRecentDocumentsMenu() { 295 if (m_document->path().isAbsolute()) 296 View::TrenchBroomApp::instance().updateRecentDocument(m_document->path()); 297 } 298 createGui()299 void MapFrame::createGui() { 300 SetIcon(wxIcon(wxStandardPaths::Get().GetInstallPrefix() + "/share/icons/hicolor/128x128/apps/trenchbroom.png", wxBITMAP_TYPE_PNG)); 301 302 m_hSplitter = new SplitterWindow2(this); 303 m_hSplitter->setSashGravity(1.0); 304 m_hSplitter->SetName("MapFrameHSplitter"); 305 306 m_vSplitter = new SplitterWindow2(m_hSplitter); 307 m_vSplitter->setSashGravity(1.0); 308 m_vSplitter->SetName("MapFrameVSplitter"); 309 310 InfoPanel* infoPanel = new InfoPanel(m_vSplitter, m_document); 311 m_console = infoPanel->console(); 312 m_mapView = new SwitchableMapViewContainer(m_vSplitter, m_console, m_document, *m_contextManager); 313 m_inspector = new Inspector(m_hSplitter, m_document, *m_contextManager); 314 315 m_mapView->connectTopWidgets(m_inspector); 316 317 m_vSplitter->splitHorizontally(m_mapView, infoPanel, wxSize(100, 100), wxSize(100, 100)); 318 m_hSplitter->splitVertically(m_vSplitter, m_inspector, wxSize(100, 100), wxSize(350, 100)); 319 320 wxSizer* frameSizer = new wxBoxSizer(wxVERTICAL); 321 #if !defined __APPLE__ 322 frameSizer->Add(new BorderLine(this), 1, wxEXPAND); 323 #endif 324 frameSizer->Add(m_hSplitter, 1, wxEXPAND); 325 326 SetSizer(frameSizer); 327 328 wxPersistenceManager::Get().RegisterAndRestore(m_hSplitter); 329 wxPersistenceManager::Get().RegisterAndRestore(m_vSplitter); 330 } 331 createToolBar()332 void MapFrame::createToolBar() { 333 wxToolBar* toolBar = CreateToolBar(wxTB_DEFAULT_STYLE | wxTB_NODIVIDER | wxTB_FLAT); 334 toolBar->SetMargins(2, 2); 335 toolBar->AddRadioTool(CommandIds::Menu::EditDeactivateTool, "Default Tool", IO::loadImageResource("NoTool.png"), wxNullBitmap, "Disable Current Tool"); 336 toolBar->AddRadioTool(CommandIds::Menu::EditToggleCreateComplexBrushTool, "Brush Tool", IO::loadImageResource("BrushTool.png"), wxNullBitmap, "Brush Tool"); 337 toolBar->AddRadioTool(CommandIds::Menu::EditToggleClipTool, "Clip Tool", IO::loadImageResource("ClipTool.png"), wxNullBitmap, "Clip Tool"); 338 toolBar->AddRadioTool(CommandIds::Menu::EditToggleVertexTool, "Vertex Tool", IO::loadImageResource("VertexTool.png"), wxNullBitmap, "Vertex Tool"); 339 toolBar->AddRadioTool(CommandIds::Menu::EditToggleRotateObjectsTool, "Rotate Tool", IO::loadImageResource("RotateTool.png"), wxNullBitmap, "Rotate Tool"); 340 toolBar->AddSeparator(); 341 toolBar->AddTool(wxID_DUPLICATE, "Duplicate Objects", IO::loadImageResource("DuplicateObjects.png"), wxNullBitmap, wxITEM_NORMAL, "Duplicate Objects"); 342 toolBar->AddTool(CommandIds::Actions::FlipObjectsHorizontally, "Flip Horizontally", IO::loadImageResource("FlipHorizontally.png"), wxNullBitmap, wxITEM_NORMAL, "Flip Horizontally"); 343 toolBar->AddTool(CommandIds::Actions::FlipObjectsVertically, "Flip Vertically", IO::loadImageResource("FlipVertically.png"), wxNullBitmap, wxITEM_NORMAL, "Flip Vertically"); 344 toolBar->AddSeparator(); 345 toolBar->AddCheckTool(CommandIds::Menu::EditToggleTextureLock, "Texture Lock", textureLockBitmap(), wxNullBitmap, "Toggle Texture Lock"); 346 toolBar->AddSeparator(); 347 348 const wxString gridSizes[9] = { "Grid 1", "Grid 2", "Grid 4", "Grid 8", "Grid 16", "Grid 32", "Grid 64", "Grid 128", "Grid 256" }; 349 m_gridChoice = new wxChoice(toolBar, wxID_ANY, wxDefaultPosition, wxDefaultSize, 9, gridSizes); 350 m_gridChoice->SetSelection(static_cast<int>(m_document->grid().size())); 351 toolBar->AddControl(m_gridChoice); 352 353 toolBar->Realize(); 354 } 355 bindObservers()356 void MapFrame::bindObservers() { 357 PreferenceManager& prefs = PreferenceManager::instance(); 358 prefs.preferenceDidChangeNotifier.addObserver(this, &MapFrame::preferenceDidChange); 359 360 m_document->documentWasClearedNotifier.addObserver(this, &MapFrame::documentWasCleared); 361 m_document->documentWasNewedNotifier.addObserver(this, &MapFrame::documentDidChange); 362 m_document->documentWasLoadedNotifier.addObserver(this, &MapFrame::documentDidChange); 363 m_document->documentWasSavedNotifier.addObserver(this, &MapFrame::documentDidChange); 364 m_document->documentModificationStateDidChangeNotifier.addObserver(this, &MapFrame::documentModificationStateDidChange); 365 366 Grid& grid = m_document->grid(); 367 grid.gridDidChangeNotifier.addObserver(this, &MapFrame::gridDidChange); 368 } 369 unbindObservers()370 void MapFrame::unbindObservers() { 371 PreferenceManager& prefs = PreferenceManager::instance(); 372 prefs.preferenceDidChangeNotifier.removeObserver(this, &MapFrame::preferenceDidChange); 373 374 m_document->documentWasClearedNotifier.removeObserver(this, &MapFrame::documentWasCleared); 375 m_document->documentWasNewedNotifier.removeObserver(this, &MapFrame::documentDidChange); 376 m_document->documentWasLoadedNotifier.removeObserver(this, &MapFrame::documentDidChange); 377 m_document->documentWasSavedNotifier.removeObserver(this, &MapFrame::documentDidChange); 378 m_document->documentModificationStateDidChangeNotifier.removeObserver(this, &MapFrame::documentModificationStateDidChange); 379 380 Grid& grid = m_document->grid(); 381 grid.gridDidChangeNotifier.removeObserver(this, &MapFrame::gridDidChange); 382 } 383 documentWasCleared(View::MapDocument * document)384 void MapFrame::documentWasCleared(View::MapDocument* document) { 385 updateTitle(); 386 } 387 documentDidChange(View::MapDocument * document)388 void MapFrame::documentDidChange(View::MapDocument* document) { 389 updateTitle(); 390 updateRecentDocumentsMenu(); 391 } 392 documentModificationStateDidChange()393 void MapFrame::documentModificationStateDidChange() { 394 updateTitle(); 395 } 396 preferenceDidChange(const IO::Path & path)397 void MapFrame::preferenceDidChange(const IO::Path& path) { 398 const ActionManager& actionManager = ActionManager::instance(); 399 if (actionManager.isMenuShortcutPreference(path)) { 400 rebuildMenuBar(); 401 } else if (path == Preferences::MapViewLayout.path()) 402 m_mapView->switchToMapView(static_cast<MapViewLayout>(pref(Preferences::MapViewLayout))); 403 } 404 gridDidChange()405 void MapFrame::gridDidChange() { 406 const Grid& grid = m_document->grid(); 407 m_gridChoice->SetSelection(static_cast<int>(grid.size())); 408 } 409 bindEvents()410 void MapFrame::bindEvents() { 411 Bind(wxEVT_MENU, &MapFrame::OnFileSave, this, wxID_SAVE); 412 Bind(wxEVT_MENU, &MapFrame::OnFileSaveAs, this, wxID_SAVEAS); 413 Bind(wxEVT_MENU, &MapFrame::OnFileLoadPointFile, this, CommandIds::Menu::FileLoadPointFile); 414 Bind(wxEVT_MENU, &MapFrame::OnFileUnloadPointFile, this, CommandIds::Menu::FileUnloadPointFile); 415 Bind(wxEVT_MENU, &MapFrame::OnFileClose, this, wxID_CLOSE); 416 417 Bind(wxEVT_MENU, &MapFrame::OnEditUndo, this, wxID_UNDO); 418 Bind(wxEVT_MENU, &MapFrame::OnEditRedo, this, wxID_REDO); 419 Bind(wxEVT_MENU, &MapFrame::OnEditRepeat, this, CommandIds::Menu::EditRepeat); 420 Bind(wxEVT_MENU, &MapFrame::OnEditClearRepeat, this, CommandIds::Menu::EditClearRepeat); 421 422 Bind(wxEVT_MENU, &MapFrame::OnEditCut, this, wxID_CUT); 423 Bind(wxEVT_MENU, &MapFrame::OnEditCopy, this, wxID_COPY); 424 Bind(wxEVT_MENU, &MapFrame::OnEditPaste, this, wxID_PASTE); 425 Bind(wxEVT_MENU, &MapFrame::OnEditPasteAtOriginalPosition, this, CommandIds::Menu::EditPasteAtOriginalPosition); 426 Bind(wxEVT_MENU, &MapFrame::OnEditDuplicate, this, wxID_DUPLICATE); 427 Bind(wxEVT_MENU, &MapFrame::OnEditDelete, this, wxID_DELETE); 428 429 Bind(wxEVT_MENU, &MapFrame::OnEditSelectAll, this, CommandIds::Menu::EditSelectAll); 430 Bind(wxEVT_MENU, &MapFrame::OnEditSelectSiblings, this, CommandIds::Menu::EditSelectSiblings); 431 Bind(wxEVT_MENU, &MapFrame::OnEditSelectTouching, this, CommandIds::Menu::EditSelectTouching); 432 Bind(wxEVT_MENU, &MapFrame::OnEditSelectInside, this, CommandIds::Menu::EditSelectInside); 433 Bind(wxEVT_MENU, &MapFrame::OnEditSelectTall, this, CommandIds::Menu::EditSelectTall); 434 Bind(wxEVT_MENU, &MapFrame::OnEditSelectByLineNumber, this, CommandIds::Menu::EditSelectByFilePosition); 435 Bind(wxEVT_MENU, &MapFrame::OnEditSelectNone, this, CommandIds::Menu::EditSelectNone); 436 437 Bind(wxEVT_MENU, &MapFrame::OnEditGroupSelectedObjects, this, CommandIds::Menu::EditGroupSelection); 438 Bind(wxEVT_MENU, &MapFrame::OnEditUngroupSelectedObjects, this, CommandIds::Menu::EditUngroupSelection); 439 440 Bind(wxEVT_MENU, &MapFrame::OnEditDeactivateTool, this, CommandIds::Menu::EditDeactivateTool); 441 Bind(wxEVT_MENU, &MapFrame::OnEditToggleCreateComplexBrushTool, this, CommandIds::Menu::EditToggleCreateComplexBrushTool); 442 Bind(wxEVT_MENU, &MapFrame::OnEditToggleClipTool, this, CommandIds::Menu::EditToggleClipTool); 443 Bind(wxEVT_MENU, &MapFrame::OnEditToggleRotateObjectsTool, this, CommandIds::Menu::EditToggleRotateObjectsTool); 444 Bind(wxEVT_MENU, &MapFrame::OnEditToggleVertexTool, this, CommandIds::Menu::EditToggleVertexTool); 445 446 Bind(wxEVT_MENU, &MapFrame::OnEditCsgConvexMerge, this, CommandIds::Menu::EditCsgConvexMerge); 447 Bind(wxEVT_MENU, &MapFrame::OnEditCsgSubtract, this, CommandIds::Menu::EditCsgSubtract); 448 Bind(wxEVT_MENU, &MapFrame::OnEditCsgIntersect, this, CommandIds::Menu::EditCsgIntersect); 449 450 Bind(wxEVT_MENU, &MapFrame::OnEditReplaceTexture, this, CommandIds::Menu::EditReplaceTexture); 451 Bind(wxEVT_MENU, &MapFrame::OnEditToggleTextureLock, this, CommandIds::Menu::EditToggleTextureLock); 452 Bind(wxEVT_MENU, &MapFrame::OnEditSnapVerticesToInteger, this, CommandIds::Menu::EditSnapVerticesToInteger); 453 Bind(wxEVT_MENU, &MapFrame::OnEditSnapVerticesToGrid, this, CommandIds::Menu::EditSnapVerticesToGrid); 454 455 Bind(wxEVT_MENU, &MapFrame::OnViewToggleShowGrid, this, CommandIds::Menu::ViewToggleShowGrid); 456 Bind(wxEVT_MENU, &MapFrame::OnViewToggleSnapToGrid, this, CommandIds::Menu::ViewToggleSnapToGrid); 457 Bind(wxEVT_MENU, &MapFrame::OnViewIncGridSize, this, CommandIds::Menu::ViewIncGridSize); 458 Bind(wxEVT_MENU, &MapFrame::OnViewDecGridSize, this, CommandIds::Menu::ViewDecGridSize); 459 Bind(wxEVT_MENU, &MapFrame::OnViewSetGridSize, this, CommandIds::Menu::ViewSetGridSize1, CommandIds::Menu::ViewSetGridSize256); 460 461 Bind(wxEVT_MENU, &MapFrame::OnViewMoveCameraToNextPoint, this, CommandIds::Menu::ViewMoveCameraToNextPoint); 462 Bind(wxEVT_MENU, &MapFrame::OnViewMoveCameraToPreviousPoint, this, CommandIds::Menu::ViewMoveCameraToPreviousPoint); 463 Bind(wxEVT_MENU, &MapFrame::OnViewFocusCameraOnSelection, this, CommandIds::Menu::ViewFocusCameraOnSelection); 464 Bind(wxEVT_MENU, &MapFrame::OnViewMoveCameraToPosition, this, CommandIds::Menu::ViewMoveCameraToPosition); 465 466 Bind(wxEVT_MENU, &MapFrame::OnViewHideSelectedObjects, this, CommandIds::Menu::ViewHideSelection); 467 Bind(wxEVT_MENU, &MapFrame::OnViewIsolateSelectedObjects, this, CommandIds::Menu::ViewIsolateSelection); 468 Bind(wxEVT_MENU, &MapFrame::OnViewShowHiddenObjects, this, CommandIds::Menu::ViewUnhideAll); 469 470 Bind(wxEVT_MENU, &MapFrame::OnViewSwitchToMapInspector, this, CommandIds::Menu::ViewSwitchToMapInspector); 471 Bind(wxEVT_MENU, &MapFrame::OnViewSwitchToEntityInspector, this, CommandIds::Menu::ViewSwitchToEntityInspector); 472 Bind(wxEVT_MENU, &MapFrame::OnViewSwitchToFaceInspector, this, CommandIds::Menu::ViewSwitchToFaceInspector); 473 474 Bind(wxEVT_MENU, &MapFrame::OnViewToggleMaximizeCurrentView, this, CommandIds::Menu::ViewToggleMaximizeCurrentView); 475 Bind(wxEVT_MENU, &MapFrame::OnViewToggleInfoPanel, this, CommandIds::Menu::ViewToggleInfoPanel); 476 Bind(wxEVT_MENU, &MapFrame::OnViewToggleInspector, this, CommandIds::Menu::ViewToggleInspector); 477 478 Bind(wxEVT_MENU, &MapFrame::OnDebugPrintVertices, this, CommandIds::Menu::DebugPrintVertices); 479 Bind(wxEVT_MENU, &MapFrame::OnDebugCreateBrush, this, CommandIds::Menu::DebugCreateBrush); 480 Bind(wxEVT_MENU, &MapFrame::OnDebugCopyJSShortcutMap, this, CommandIds::Menu::DebugCopyJSShortcuts); 481 482 Bind(wxEVT_MENU, &MapFrame::OnFlipObjectsHorizontally, this, CommandIds::Actions::FlipObjectsHorizontally); 483 Bind(wxEVT_MENU, &MapFrame::OnFlipObjectsVertically, this, CommandIds::Actions::FlipObjectsVertically); 484 485 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_SAVE); 486 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_SAVEAS); 487 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_CLOSE); 488 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_UNDO); 489 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_REDO); 490 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_CUT); 491 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_COPY); 492 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_PASTE); 493 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, wxID_DUPLICATE); 494 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, CommandIds::Menu::Lowest, CommandIds::Menu::Highest); 495 496 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, CommandIds::Actions::FlipObjectsHorizontally); 497 Bind(wxEVT_UPDATE_UI, &MapFrame::OnUpdateUI, this, CommandIds::Actions::FlipObjectsVertically); 498 499 Bind(wxEVT_CLOSE_WINDOW, &MapFrame::OnClose, this); 500 Bind(wxEVT_TIMER, &MapFrame::OnAutosaveTimer, this); 501 Bind(wxEVT_CHILD_FOCUS, &MapFrame::OnChildFocus, this); 502 503 m_gridChoice->Bind(wxEVT_CHOICE, &MapFrame::OnToolBarSetGridSize, this); 504 } 505 OnFileSave(wxCommandEvent & event)506 void MapFrame::OnFileSave(wxCommandEvent& event) { 507 if (IsBeingDeleted()) return; 508 509 saveDocument(); 510 } 511 OnFileSaveAs(wxCommandEvent & event)512 void MapFrame::OnFileSaveAs(wxCommandEvent& event) { 513 if (IsBeingDeleted()) return; 514 515 saveDocumentAs(); 516 } 517 OnFileLoadPointFile(wxCommandEvent & event)518 void MapFrame::OnFileLoadPointFile(wxCommandEvent& event) { 519 if (IsBeingDeleted()) return; 520 if (canLoadPointFile()) 521 m_document->loadPointFile(); 522 } 523 OnFileUnloadPointFile(wxCommandEvent & event)524 void MapFrame::OnFileUnloadPointFile(wxCommandEvent& event) { 525 if (IsBeingDeleted()) return; 526 if (canUnloadPointFile()) 527 m_document->unloadPointFile(); 528 } 529 OnFileClose(wxCommandEvent & event)530 void MapFrame::OnFileClose(wxCommandEvent& event) { 531 if (IsBeingDeleted()) return; 532 533 Close(); 534 } 535 OnEditUndo(wxCommandEvent & event)536 void MapFrame::OnEditUndo(wxCommandEvent& event) { 537 if (IsBeingDeleted()) return; 538 539 if (canUndo()) 540 m_document->undoLastCommand(); 541 } 542 OnEditRedo(wxCommandEvent & event)543 void MapFrame::OnEditRedo(wxCommandEvent& event) { 544 if (IsBeingDeleted()) return; 545 546 if (canRedo()) 547 m_document->redoNextCommand(); 548 } 549 OnEditRepeat(wxCommandEvent & event)550 void MapFrame::OnEditRepeat(wxCommandEvent& event) { 551 if (IsBeingDeleted()) return; 552 553 m_document->repeatLastCommands(); 554 } 555 OnEditClearRepeat(wxCommandEvent & event)556 void MapFrame::OnEditClearRepeat(wxCommandEvent& event) { 557 if (IsBeingDeleted()) return; 558 559 m_document->clearRepeatableCommands(); 560 } 561 OnEditCut(wxCommandEvent & event)562 void MapFrame::OnEditCut(wxCommandEvent& event) { 563 if (IsBeingDeleted()) return; 564 565 if (canCut()) { 566 copyToClipboard(); 567 Transaction transaction(m_document, "Cut"); 568 m_document->deleteObjects(); 569 } 570 } 571 OnEditCopy(wxCommandEvent & event)572 void MapFrame::OnEditCopy(wxCommandEvent& event) { 573 if (IsBeingDeleted()) return; 574 575 if (canCopy()) 576 copyToClipboard(); 577 } 578 579 class OpenClipboard { 580 public: OpenClipboard()581 OpenClipboard() { 582 if (!wxTheClipboard->IsOpened()) 583 wxTheClipboard->Open(); 584 } 585 ~OpenClipboard()586 ~OpenClipboard() { 587 if (wxTheClipboard->IsOpened()) 588 wxTheClipboard->Close(); 589 } 590 }; 591 copyToClipboard()592 void MapFrame::copyToClipboard() { 593 OpenClipboard openClipboard; 594 if (wxTheClipboard->IsOpened()) { 595 String str; 596 if (m_document->hasSelectedNodes()) 597 str = m_document->serializeSelectedNodes(); 598 else if (m_document->hasSelectedBrushFaces()) 599 str = m_document->serializeSelectedBrushFaces(); 600 wxTheClipboard->SetData(new wxTextDataObject(str)); 601 } 602 } 603 OnEditPaste(wxCommandEvent & event)604 void MapFrame::OnEditPaste(wxCommandEvent& event) { 605 if (IsBeingDeleted()) return; 606 607 if (canPaste()) { 608 const BBox3 referenceBounds = m_document->referenceBounds(); 609 Transaction transaction(m_document); 610 if (paste() == PT_Node && m_document->hasSelectedNodes()) { 611 const BBox3 bounds = m_document->selectionBounds(); 612 const Vec3 delta = m_mapView->pasteObjectsDelta(bounds, referenceBounds); 613 m_document->translateObjects(delta); 614 } 615 } 616 } 617 OnEditPasteAtOriginalPosition(wxCommandEvent & event)618 void MapFrame::OnEditPasteAtOriginalPosition(wxCommandEvent& event) { 619 if (IsBeingDeleted()) return; 620 621 if (canPaste()) 622 paste(); 623 } 624 paste()625 PasteType MapFrame::paste() { 626 OpenClipboard openClipboard; 627 if (!wxTheClipboard->IsOpened() || !wxTheClipboard->IsSupported(wxDF_TEXT)) { 628 logger()->error("Clipboard is empty"); 629 return PT_Failed; 630 } 631 632 wxTextDataObject textData; 633 if (!wxTheClipboard->GetData(textData)) { 634 logger()->error("Could not get clipboard contents"); 635 return PT_Failed; 636 } 637 638 const String text = textData.GetText().ToStdString(); 639 return m_document->paste(text); 640 } 641 OnEditDelete(wxCommandEvent & event)642 void MapFrame::OnEditDelete(wxCommandEvent& event) { 643 if (IsBeingDeleted()) return; 644 645 if (canDelete()) 646 m_document->deleteObjects(); 647 } 648 OnEditDuplicate(wxCommandEvent & event)649 void MapFrame::OnEditDuplicate(wxCommandEvent& event) { 650 if (IsBeingDeleted()) return; 651 652 if (canDuplicate()) 653 m_document->duplicateObjects(); 654 } 655 OnEditSelectAll(wxCommandEvent & event)656 void MapFrame::OnEditSelectAll(wxCommandEvent& event) { 657 if (IsBeingDeleted()) return; 658 659 if (canSelect()) 660 m_document->selectAllNodes(); 661 } 662 OnEditSelectSiblings(wxCommandEvent & event)663 void MapFrame::OnEditSelectSiblings(wxCommandEvent& event) { 664 if (IsBeingDeleted()) return; 665 666 if (canSelectSiblings()) 667 m_document->selectSiblings(); 668 } 669 OnEditSelectTouching(wxCommandEvent & event)670 void MapFrame::OnEditSelectTouching(wxCommandEvent& event) { 671 if (IsBeingDeleted()) return; 672 673 if (canSelectByBrush()) 674 m_document->selectTouching(true); 675 } 676 OnEditSelectInside(wxCommandEvent & event)677 void MapFrame::OnEditSelectInside(wxCommandEvent& event) { 678 if (IsBeingDeleted()) return; 679 680 if (canSelectByBrush()) 681 m_document->selectInside(true); 682 } 683 OnEditSelectTall(wxCommandEvent & event)684 void MapFrame::OnEditSelectTall(wxCommandEvent& event) { 685 if (IsBeingDeleted()) return; 686 687 if (canSelectTall()) 688 m_mapView->selectTall(); 689 } 690 OnEditSelectByLineNumber(wxCommandEvent & event)691 void MapFrame::OnEditSelectByLineNumber(wxCommandEvent& event) { 692 if (IsBeingDeleted()) return; 693 694 if (canSelect()) { 695 const wxString string = wxGetTextFromUser("Enter a comma- or space separated list of line numbers.", "Select by Line Numbers", "", this); 696 if (string.empty()) 697 return; 698 699 std::vector<size_t> positions; 700 wxStringTokenizer tokenizer(string, ", "); 701 while (tokenizer.HasMoreTokens()) { 702 const wxString token = tokenizer.NextToken(); 703 long position; 704 if (token.ToLong(&position) && position > 0) { 705 positions.push_back(static_cast<size_t>(position)); 706 } 707 } 708 709 m_document->selectNodesWithFilePosition(positions); 710 } 711 } 712 OnEditSelectNone(wxCommandEvent & event)713 void MapFrame::OnEditSelectNone(wxCommandEvent& event) { 714 if (IsBeingDeleted()) return; 715 716 if (canDeselect()) 717 m_document->deselectAll(); 718 } 719 OnEditGroupSelectedObjects(wxCommandEvent & event)720 void MapFrame::OnEditGroupSelectedObjects(wxCommandEvent& event) { 721 if (IsBeingDeleted()) return; 722 723 if (canGroup()) { 724 const String name = queryGroupName(this); 725 if (!name.empty()) 726 m_document->groupSelection(name); 727 } 728 } 729 OnEditUngroupSelectedObjects(wxCommandEvent & event)730 void MapFrame::OnEditUngroupSelectedObjects(wxCommandEvent& event) { 731 if (IsBeingDeleted()) return; 732 733 if (canUngroup()) 734 m_document->ungroupSelection(); 735 } 736 OnEditReplaceTexture(wxCommandEvent & event)737 void MapFrame::OnEditReplaceTexture(wxCommandEvent& event) { 738 if (IsBeingDeleted()) return; 739 740 ReplaceTextureFrame* frame = new ReplaceTextureFrame(this, m_document, *m_contextManager); 741 frame->CenterOnParent(); 742 frame->Show(); 743 } 744 OnEditDeactivateTool(wxCommandEvent & event)745 void MapFrame::OnEditDeactivateTool(wxCommandEvent& event) { 746 if (IsBeingDeleted()) return; 747 748 m_mapView->deactivateTool(); 749 } 750 OnEditToggleCreateComplexBrushTool(wxCommandEvent & event)751 void MapFrame::OnEditToggleCreateComplexBrushTool(wxCommandEvent& event) { 752 if (IsBeingDeleted()) return; 753 754 m_mapView->toggleCreateComplexBrushTool(); 755 } 756 OnEditToggleClipTool(wxCommandEvent & event)757 void MapFrame::OnEditToggleClipTool(wxCommandEvent& event) { 758 if (IsBeingDeleted()) return; 759 760 m_mapView->toggleClipTool(); 761 } 762 OnEditToggleRotateObjectsTool(wxCommandEvent & event)763 void MapFrame::OnEditToggleRotateObjectsTool(wxCommandEvent& event) { 764 if (IsBeingDeleted()) return; 765 766 m_mapView->toggleRotateObjectsTool(); 767 } 768 OnEditToggleVertexTool(wxCommandEvent & event)769 void MapFrame::OnEditToggleVertexTool(wxCommandEvent& event) { 770 if (IsBeingDeleted()) return; 771 772 m_mapView->toggleVertexTool(); 773 } 774 OnEditCsgConvexMerge(wxCommandEvent & event)775 void MapFrame::OnEditCsgConvexMerge(wxCommandEvent& event) { 776 if (IsBeingDeleted()) return; 777 778 if (canDoCsgConvexMerge()) 779 m_document->csgConvexMerge(); 780 } 781 OnEditCsgSubtract(wxCommandEvent & event)782 void MapFrame::OnEditCsgSubtract(wxCommandEvent& event) { 783 if (IsBeingDeleted()) return; 784 785 if (canDoCsgSubtract()) 786 m_document->csgSubtract(); 787 } 788 OnEditCsgIntersect(wxCommandEvent & event)789 void MapFrame::OnEditCsgIntersect(wxCommandEvent& event) { 790 if (IsBeingDeleted()) return; 791 792 if (canDoCsgIntersect()) 793 m_document->csgIntersect(); 794 } 795 OnEditToggleTextureLock(wxCommandEvent & event)796 void MapFrame::OnEditToggleTextureLock(wxCommandEvent& event) { 797 if (IsBeingDeleted()) return; 798 799 m_document->setTextureLock(!m_document->textureLock()); 800 GetToolBar()->SetToolNormalBitmap(CommandIds::Menu::EditToggleTextureLock, textureLockBitmap()); 801 } 802 textureLockBitmap()803 wxBitmap MapFrame::textureLockBitmap() { 804 if (m_document->textureLock()) 805 return IO::loadImageResource("TextureLockOn.png"); 806 return IO::loadImageResource("TextureLockOff.png"); 807 } 808 OnEditSnapVerticesToInteger(wxCommandEvent & event)809 void MapFrame::OnEditSnapVerticesToInteger(wxCommandEvent& event) { 810 if (IsBeingDeleted()) return; 811 812 if (canSnapVertices()) 813 m_document->snapVertices(1u); 814 } 815 OnEditSnapVerticesToGrid(wxCommandEvent & event)816 void MapFrame::OnEditSnapVerticesToGrid(wxCommandEvent& event) { 817 if (IsBeingDeleted()) return; 818 819 if (canSnapVertices()) 820 m_document->snapVertices(m_document->grid().actualSize()); 821 } 822 OnViewToggleShowGrid(wxCommandEvent & event)823 void MapFrame::OnViewToggleShowGrid(wxCommandEvent& event) { 824 if (IsBeingDeleted()) return; 825 826 m_document->grid().toggleVisible(); 827 } 828 OnViewToggleSnapToGrid(wxCommandEvent & event)829 void MapFrame::OnViewToggleSnapToGrid(wxCommandEvent& event) { 830 if (IsBeingDeleted()) return; 831 832 m_document->grid().toggleSnap(); 833 } 834 OnViewIncGridSize(wxCommandEvent & event)835 void MapFrame::OnViewIncGridSize(wxCommandEvent& event) { 836 if (IsBeingDeleted()) return; 837 838 if (canIncGridSize()) 839 m_document->grid().incSize(); 840 } 841 OnViewDecGridSize(wxCommandEvent & event)842 void MapFrame::OnViewDecGridSize(wxCommandEvent& event) { 843 if (IsBeingDeleted()) return; 844 845 if (canDecGridSize()) 846 m_document->grid().decSize(); 847 } 848 OnViewSetGridSize(wxCommandEvent & event)849 void MapFrame::OnViewSetGridSize(wxCommandEvent& event) { 850 if (IsBeingDeleted()) return; 851 852 const size_t size = static_cast<size_t>(event.GetId() - CommandIds::Menu::ViewSetGridSize1); 853 assert(size < Grid::MaxSize); 854 m_document->grid().setSize(size); 855 } 856 OnViewMoveCameraToNextPoint(wxCommandEvent & event)857 void MapFrame::OnViewMoveCameraToNextPoint(wxCommandEvent& event) { 858 if (IsBeingDeleted()) return; 859 860 if (canMoveCameraToNextPoint()) 861 m_mapView->moveCameraToNextTracePoint(); 862 } 863 OnViewMoveCameraToPreviousPoint(wxCommandEvent & event)864 void MapFrame::OnViewMoveCameraToPreviousPoint(wxCommandEvent& event) { 865 if (IsBeingDeleted()) return; 866 867 if (canMoveCameraToPreviousPoint()) 868 m_mapView->moveCameraToPreviousTracePoint(); 869 } 870 OnViewFocusCameraOnSelection(wxCommandEvent & event)871 void MapFrame::OnViewFocusCameraOnSelection(wxCommandEvent& event) { 872 if (IsBeingDeleted()) return; 873 874 if (canFocusCamera()) 875 m_mapView->focusCameraOnSelection(true); 876 } 877 OnViewMoveCameraToPosition(wxCommandEvent & event)878 void MapFrame::OnViewMoveCameraToPosition(wxCommandEvent& event) { 879 if (IsBeingDeleted()) return; 880 881 wxTextEntryDialog dialog(this, "Enter a position (x y z) for the camera.", "Move Camera", "0.0 0.0 0.0"); 882 if (dialog.ShowModal() == wxID_OK) { 883 const wxString str = dialog.GetValue(); 884 const Vec3 position = Vec3::parse(str.ToStdString()); 885 m_mapView->moveCameraToPosition(position, true); 886 } 887 } 888 OnViewHideSelectedObjects(wxCommandEvent & event)889 void MapFrame::OnViewHideSelectedObjects(wxCommandEvent& event) { 890 if (IsBeingDeleted()) return; 891 892 if (canHide()) 893 m_document->hideSelection(); 894 } 895 OnViewIsolateSelectedObjects(wxCommandEvent & event)896 void MapFrame::OnViewIsolateSelectedObjects(wxCommandEvent& event) { 897 if (IsBeingDeleted()) return; 898 899 if (canIsolate()) 900 m_document->isolate(m_document->selectedNodes().nodes()); 901 } 902 OnViewShowHiddenObjects(wxCommandEvent & event)903 void MapFrame::OnViewShowHiddenObjects(wxCommandEvent& event) { 904 if (IsBeingDeleted()) return; 905 906 m_document->showAll(); 907 } 908 OnViewSwitchToMapInspector(wxCommandEvent & event)909 void MapFrame::OnViewSwitchToMapInspector(wxCommandEvent& event) { 910 if (IsBeingDeleted()) return; 911 912 m_inspector->switchToPage(Inspector::InspectorPage_Map); 913 } 914 OnViewSwitchToEntityInspector(wxCommandEvent & event)915 void MapFrame::OnViewSwitchToEntityInspector(wxCommandEvent& event) { 916 if (IsBeingDeleted()) return; 917 918 m_inspector->switchToPage(Inspector::InspectorPage_Entity); 919 } 920 OnViewSwitchToFaceInspector(wxCommandEvent & event)921 void MapFrame::OnViewSwitchToFaceInspector(wxCommandEvent& event) { 922 if (IsBeingDeleted()) return; 923 924 m_inspector->switchToPage(Inspector::InspectorPage_Face); 925 } 926 OnViewToggleMaximizeCurrentView(wxCommandEvent & event)927 void MapFrame::OnViewToggleMaximizeCurrentView(wxCommandEvent& event) { 928 if (IsBeingDeleted()) return; 929 930 m_mapView->toggleMaximizeCurrentView(); 931 } 932 OnViewToggleInfoPanel(wxCommandEvent & event)933 void MapFrame::OnViewToggleInfoPanel(wxCommandEvent& event) { 934 if (IsBeingDeleted()) return; 935 936 if (m_vSplitter->isMaximized(m_mapView)) 937 m_vSplitter->restore(); 938 else 939 m_vSplitter->maximize(m_mapView); 940 } 941 OnViewToggleInspector(wxCommandEvent & event)942 void MapFrame::OnViewToggleInspector(wxCommandEvent& event) { 943 if (IsBeingDeleted()) return; 944 945 if (m_hSplitter->isMaximized(m_vSplitter)) 946 m_hSplitter->restore(); 947 else 948 m_hSplitter->maximize(m_vSplitter); 949 } 950 OnDebugPrintVertices(wxCommandEvent & event)951 void MapFrame::OnDebugPrintVertices(wxCommandEvent& event) { 952 if (IsBeingDeleted()) return; 953 954 m_document->printVertices(); 955 } 956 OnDebugCreateBrush(wxCommandEvent & event)957 void MapFrame::OnDebugCreateBrush(wxCommandEvent& event) { 958 if (IsBeingDeleted()) return; 959 960 wxTextEntryDialog dialog(this, "Enter a list of at least 4 points (x y z) (x y z) ...", "Create Brush", ""); 961 if (dialog.ShowModal() == wxID_OK) { 962 const wxString str = dialog.GetValue(); 963 const Vec3::List positions = Vec3::parseList(str.ToStdString()); 964 m_document->createBrush(positions); 965 } 966 } 967 OnDebugCopyJSShortcutMap(wxCommandEvent & event)968 void MapFrame::OnDebugCopyJSShortcutMap(wxCommandEvent& event) { 969 if (IsBeingDeleted()) return; 970 971 OpenClipboard openClipboard; 972 if (wxTheClipboard->IsOpened()) { 973 const String str = ActionManager::instance().getJSTable(); 974 wxTheClipboard->SetData(new wxTextDataObject(str)); 975 } 976 977 } 978 OnFlipObjectsHorizontally(wxCommandEvent & event)979 void MapFrame::OnFlipObjectsHorizontally(wxCommandEvent& event) { 980 if (IsBeingDeleted()) return; 981 m_mapView->flipObjects(Math::Direction_Left); 982 } 983 OnFlipObjectsVertically(wxCommandEvent & event)984 void MapFrame::OnFlipObjectsVertically(wxCommandEvent& event) { 985 if (IsBeingDeleted()) return; 986 m_mapView->flipObjects(Math::Direction_Up); 987 } 988 OnUpdateUI(wxUpdateUIEvent & event)989 void MapFrame::OnUpdateUI(wxUpdateUIEvent& event) { 990 if (IsBeingDeleted()) return; 991 992 const ActionManager& actionManager = ActionManager::instance(); 993 994 switch (event.GetId()) { 995 case wxID_OPEN: 996 case wxID_SAVE: 997 case wxID_SAVEAS: 998 case wxID_CLOSE: 999 case CommandIds::Menu::FileOpenRecent: 1000 event.Enable(true); 1001 break; 1002 case CommandIds::Menu::FileLoadPointFile: 1003 event.Enable(canLoadPointFile()); 1004 break; 1005 case CommandIds::Menu::FileUnloadPointFile: 1006 event.Enable(canUnloadPointFile()); 1007 break; 1008 case wxID_UNDO: { 1009 const ActionMenuItem* item = actionManager.findMenuItem(wxID_UNDO); 1010 assert(item != NULL); 1011 if (canUndo()) { 1012 event.Enable(true); 1013 event.SetText(item->menuString(m_document->lastCommandName(), m_mapView->viewportHasFocus())); 1014 } else { 1015 event.Enable(false); 1016 event.SetText(item->menuString("", m_mapView->viewportHasFocus())); 1017 } 1018 break; 1019 } 1020 case wxID_REDO: { 1021 const ActionMenuItem* item = actionManager.findMenuItem(wxID_REDO); 1022 if (canRedo()) { 1023 event.Enable(true); 1024 event.SetText(item->menuString(m_document->nextCommandName(), m_mapView->viewportHasFocus())); 1025 } else { 1026 event.Enable(false); 1027 event.SetText(item->menuString("", m_mapView->viewportHasFocus())); 1028 } 1029 break; 1030 } 1031 case CommandIds::Menu::EditRepeat: 1032 case CommandIds::Menu::EditClearRepeat: 1033 event.Enable(true); 1034 break; 1035 case wxID_CUT: 1036 event.Enable(canCut()); 1037 break; 1038 case wxID_COPY: 1039 event.Enable(canCopy()); 1040 break; 1041 case wxID_PASTE: 1042 case CommandIds::Menu::EditPasteAtOriginalPosition: 1043 event.Enable(canPaste()); 1044 break; 1045 case wxID_DUPLICATE: 1046 event.Enable(canDuplicate()); 1047 break; 1048 case wxID_DELETE: 1049 event.Enable(canDelete()); 1050 break; 1051 case CommandIds::Menu::EditSelectAll: 1052 event.Enable(canSelect()); 1053 break; 1054 case CommandIds::Menu::EditSelectSiblings: 1055 event.Enable(canSelectSiblings()); 1056 break; 1057 case CommandIds::Menu::EditSelectTouching: 1058 case CommandIds::Menu::EditSelectInside: 1059 event.Enable(canSelectByBrush()); 1060 break; 1061 case CommandIds::Menu::EditSelectTall: 1062 event.Enable(canSelectTall()); 1063 break; 1064 case CommandIds::Menu::EditSelectByFilePosition: 1065 event.Enable(canSelect()); 1066 break; 1067 case CommandIds::Menu::EditSelectNone: 1068 event.Enable(canDeselect()); 1069 break; 1070 case CommandIds::Menu::EditGroupSelection: 1071 event.Enable(canGroup()); 1072 break; 1073 case CommandIds::Menu::EditUngroupSelection: 1074 event.Enable(canUngroup()); 1075 break; 1076 case CommandIds::Menu::EditDeactivateTool: 1077 event.Check(!m_mapView->anyToolActive()); 1078 event.Enable(true); 1079 break; 1080 case CommandIds::Menu::EditToggleCreateComplexBrushTool: 1081 event.Check(m_mapView->createComplexBrushToolActive()); 1082 event.Enable(m_mapView->canToggleCreateComplexBrushTool()); 1083 break; 1084 case CommandIds::Menu::EditToggleClipTool: 1085 event.Check(m_mapView->clipToolActive()); 1086 event.Enable(m_mapView->canToggleClipTool()); 1087 break; 1088 case CommandIds::Menu::EditToggleRotateObjectsTool: 1089 event.Check(m_mapView->rotateObjectsToolActive()); 1090 event.Enable(m_mapView->canToggleRotateObjectsTool()); 1091 break; 1092 case CommandIds::Menu::EditToggleVertexTool: 1093 event.Check(m_mapView->vertexToolActive()); 1094 event.Enable(m_mapView->canToggleVertexTool()); 1095 break; 1096 case CommandIds::Menu::EditCsgConvexMerge: 1097 event.Enable(canDoCsgConvexMerge()); 1098 break; 1099 case CommandIds::Menu::EditCsgSubtract: 1100 event.Enable(canDoCsgSubtract()); 1101 break; 1102 case CommandIds::Menu::EditCsgIntersect: 1103 event.Enable(canDoCsgIntersect()); 1104 break; 1105 case CommandIds::Menu::EditSnapVerticesToInteger: 1106 case CommandIds::Menu::EditSnapVerticesToGrid: 1107 event.Enable(canSnapVertices()); 1108 break; 1109 case CommandIds::Menu::EditReplaceTexture: 1110 event.Enable(true); 1111 break; 1112 case CommandIds::Menu::EditToggleTextureLock: 1113 event.Enable(true); 1114 event.Check(m_document->textureLock()); 1115 break; 1116 case CommandIds::Menu::ViewToggleShowGrid: 1117 event.Enable(true); 1118 event.Check(m_document->grid().visible()); 1119 break; 1120 case CommandIds::Menu::ViewToggleSnapToGrid: 1121 event.Enable(true); 1122 event.Check(m_document->grid().snap()); 1123 break; 1124 case CommandIds::Menu::ViewIncGridSize: 1125 event.Enable(canIncGridSize()); 1126 break; 1127 case CommandIds::Menu::ViewDecGridSize: 1128 event.Enable(canDecGridSize()); 1129 break; 1130 case CommandIds::Menu::ViewSetGridSize1: 1131 event.Enable(true); 1132 event.Check(m_document->grid().size() == 0); 1133 break; 1134 case CommandIds::Menu::ViewSetGridSize2: 1135 event.Enable(true); 1136 event.Check(m_document->grid().size() == 1); 1137 break; 1138 case CommandIds::Menu::ViewSetGridSize4: 1139 event.Enable(true); 1140 event.Check(m_document->grid().size() == 2); 1141 break; 1142 case CommandIds::Menu::ViewSetGridSize8: 1143 event.Enable(true); 1144 event.Check(m_document->grid().size() == 3); 1145 break; 1146 case CommandIds::Menu::ViewSetGridSize16: 1147 event.Enable(true); 1148 event.Check(m_document->grid().size() == 4); 1149 break; 1150 case CommandIds::Menu::ViewSetGridSize32: 1151 event.Enable(true); 1152 event.Check(m_document->grid().size() == 5); 1153 break; 1154 case CommandIds::Menu::ViewSetGridSize64: 1155 event.Enable(true); 1156 event.Check(m_document->grid().size() == 6); 1157 break; 1158 case CommandIds::Menu::ViewSetGridSize128: 1159 event.Enable(true); 1160 event.Check(m_document->grid().size() == 7); 1161 break; 1162 case CommandIds::Menu::ViewSetGridSize256: 1163 event.Enable(true); 1164 event.Check(m_document->grid().size() == 8); 1165 break; 1166 case CommandIds::Menu::ViewMoveCameraToNextPoint: 1167 event.Enable(canMoveCameraToNextPoint()); 1168 break; 1169 case CommandIds::Menu::ViewMoveCameraToPreviousPoint: 1170 event.Enable(canMoveCameraToPreviousPoint()); 1171 break; 1172 case CommandIds::Menu::ViewFocusCameraOnSelection: 1173 event.Enable(canFocusCamera()); 1174 break; 1175 case CommandIds::Menu::ViewMoveCameraToPosition: 1176 event.Enable(true); 1177 break; 1178 case CommandIds::Menu::ViewHideSelection: 1179 event.Enable(canHide()); 1180 break; 1181 case CommandIds::Menu::ViewIsolateSelection: 1182 event.Enable(canIsolate()); 1183 break; 1184 case CommandIds::Menu::ViewUnhideAll: 1185 event.Enable(true); 1186 break; 1187 case CommandIds::Menu::ViewSwitchToMapInspector: 1188 case CommandIds::Menu::ViewSwitchToEntityInspector: 1189 case CommandIds::Menu::ViewSwitchToFaceInspector: 1190 event.Enable(true); 1191 break; 1192 case CommandIds::Menu::ViewToggleMaximizeCurrentView: 1193 event.Enable(m_mapView->canMaximizeCurrentView()); 1194 event.Check(m_mapView->currentViewMaximized()); 1195 break; 1196 case CommandIds::Menu::ViewToggleInfoPanel: 1197 event.Enable(true); 1198 event.Check(m_vSplitter->isMaximized(m_mapView)); 1199 break; 1200 case CommandIds::Menu::ViewToggleInspector: 1201 event.Enable(true); 1202 event.Check(m_hSplitter->isMaximized(m_vSplitter)); 1203 break; 1204 case CommandIds::Menu::DebugPrintVertices: 1205 case CommandIds::Menu::DebugCreateBrush: 1206 case CommandIds::Menu::DebugCopyJSShortcuts: 1207 event.Enable(true); 1208 break; 1209 case CommandIds::Actions::FlipObjectsHorizontally: 1210 case CommandIds::Actions::FlipObjectsVertically: 1211 event.Enable(m_mapView->canFlipObjects()); 1212 break; 1213 default: 1214 if (event.GetId() >= CommandIds::Menu::FileRecentDocuments && 1215 event.GetId() < CommandIds::Menu::FileRecentDocuments + 10) 1216 event.Enable(true); 1217 else 1218 event.Enable(false); 1219 break; 1220 } 1221 } 1222 OnToolBarSetGridSize(wxCommandEvent & event)1223 void MapFrame::OnToolBarSetGridSize(wxCommandEvent& event) { 1224 if (IsBeingDeleted()) return; 1225 1226 const size_t size = static_cast<size_t>(event.GetSelection()); 1227 assert(size < Grid::MaxSize); 1228 m_document->grid().setSize(size); 1229 } 1230 canLoadPointFile() const1231 bool MapFrame::canLoadPointFile() const { 1232 return m_document->canLoadPointFile(); 1233 } 1234 canUnloadPointFile() const1235 bool MapFrame::canUnloadPointFile() const { 1236 return m_document->isPointFileLoaded(); 1237 } 1238 canUndo() const1239 bool MapFrame::canUndo() const { 1240 return m_document->canUndoLastCommand(); 1241 } 1242 canRedo() const1243 bool MapFrame::canRedo() const { 1244 return m_document->canRedoNextCommand(); 1245 } 1246 canCut() const1247 bool MapFrame::canCut() const { 1248 return canDelete(); 1249 } 1250 canCopy() const1251 bool MapFrame::canCopy() const { 1252 return m_document->hasSelectedNodes() || m_document->hasSelectedBrushFaces(); 1253 } 1254 canPaste() const1255 bool MapFrame::canPaste() const { 1256 OpenClipboard openClipboard; 1257 return wxTheClipboard->IsOpened() && wxTheClipboard->IsSupported(wxDF_TEXT); 1258 } 1259 canDelete() const1260 bool MapFrame::canDelete() const { 1261 return m_document->hasSelectedNodes() && !m_mapView->anyToolActive(); 1262 } 1263 canDuplicate() const1264 bool MapFrame::canDuplicate() const { 1265 return m_document->hasSelectedNodes() && !m_mapView->clipToolActive() && !m_mapView->vertexToolActive(); 1266 } 1267 canSelectSiblings() const1268 bool MapFrame::canSelectSiblings() const { 1269 return canChangeSelection() && m_document->hasSelectedNodes(); 1270 } 1271 canSelectByBrush() const1272 bool MapFrame::canSelectByBrush() const { 1273 return canChangeSelection() && m_document->selectedNodes().hasOnlyBrushes(); 1274 } 1275 canSelectTall() const1276 bool MapFrame::canSelectTall() const { 1277 return canChangeSelection() && m_document->selectedNodes().hasOnlyBrushes() && m_mapView->canSelectTall(); 1278 } 1279 canSelect() const1280 bool MapFrame::canSelect() const { 1281 return canChangeSelection(); 1282 } 1283 canDeselect() const1284 bool MapFrame::canDeselect() const { 1285 return canChangeSelection() && m_document->hasSelectedNodes(); 1286 } 1287 canChangeSelection() const1288 bool MapFrame::canChangeSelection() const { 1289 return m_document->editorContext().canChangeSelection(); 1290 } 1291 canGroup() const1292 bool MapFrame::canGroup() const { 1293 return m_document->hasSelectedNodes(); 1294 } 1295 canUngroup() const1296 bool MapFrame::canUngroup() const { 1297 return m_document->selectedNodes().hasOnlyGroups(); 1298 } 1299 canHide() const1300 bool MapFrame::canHide() const { 1301 return m_document->hasSelectedNodes(); 1302 } 1303 canIsolate() const1304 bool MapFrame::canIsolate() const { 1305 return m_document->hasSelectedNodes(); 1306 } 1307 canDoCsgConvexMerge() const1308 bool MapFrame::canDoCsgConvexMerge() const { 1309 return (m_document->hasSelectedBrushFaces() && m_document->selectedBrushFaces().size() > 1) || 1310 (m_document->selectedNodes().hasOnlyBrushes() && m_document->selectedNodes().brushCount() > 1); 1311 } 1312 canDoCsgSubtract() const1313 bool MapFrame::canDoCsgSubtract() const { 1314 return m_document->selectedNodes().hasOnlyBrushes() && m_document->selectedNodes().brushCount() > 1; 1315 } 1316 canDoCsgIntersect() const1317 bool MapFrame::canDoCsgIntersect() const { 1318 return m_document->selectedNodes().hasOnlyBrushes() && m_document->selectedNodes().brushCount() > 1; 1319 } 1320 canSnapVertices() const1321 bool MapFrame::canSnapVertices() const { 1322 return m_document->selectedNodes().hasOnlyBrushes(); 1323 } 1324 canDecGridSize() const1325 bool MapFrame::canDecGridSize() const { 1326 return m_document->grid().size() > 0; 1327 } 1328 canIncGridSize() const1329 bool MapFrame::canIncGridSize() const { 1330 return m_document->grid().size() < Grid::MaxSize; 1331 } 1332 canMoveCameraToNextPoint() const1333 bool MapFrame::canMoveCameraToNextPoint() const { 1334 return m_mapView->canMoveCameraToNextTracePoint(); 1335 } 1336 canMoveCameraToPreviousPoint() const1337 bool MapFrame::canMoveCameraToPreviousPoint() const { 1338 return m_mapView->canMoveCameraToPreviousTracePoint(); 1339 } 1340 canFocusCamera() const1341 bool MapFrame::canFocusCamera() const { 1342 return m_document->hasSelectedNodes(); 1343 } 1344 OnClose(wxCloseEvent & event)1345 void MapFrame::OnClose(wxCloseEvent& event) { 1346 if (IsBeingDeleted()) return; 1347 1348 if (!IsBeingDeleted()) { 1349 assert(m_frameManager != NULL); 1350 if (event.CanVeto() && !confirmOrDiscardChanges()) 1351 event.Veto(); 1352 else 1353 m_frameManager->removeAndDestroyFrame(this); 1354 } 1355 } 1356 OnAutosaveTimer(wxTimerEvent & event)1357 void MapFrame::OnAutosaveTimer(wxTimerEvent& event) { 1358 if (IsBeingDeleted()) return; 1359 1360 m_autosaver->triggerAutosave(logger()); 1361 } 1362 } 1363 } 1364