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 "LayerEditor.h" 21 22 #include "Model/Brush.h" 23 #include "Model/CollectSelectableNodesVisitor.h" 24 #include "Model/Entity.h" 25 #include "Model/FindGroupVisitor.h" 26 #include "Model/FindLayerVisitor.h" 27 #include "Model/Group.h" 28 #include "Model/Layer.h" 29 #include "Model/World.h" 30 #include "View/LayerListView.h" 31 #include "View/MapDocument.h" 32 #include "View/ViewConstants.h" 33 #include "View/wxUtils.h" 34 35 #include <wx/bmpbuttn.h> 36 #include <wx/menu.h> 37 #include <wx/msgdlg.h> 38 #include <wx/sizer.h> 39 #include <wx/textdlg.h> 40 41 #include <set> 42 43 namespace TrenchBroom { 44 namespace View { LayerEditor(wxWindow * parent,MapDocumentWPtr document)45 LayerEditor::LayerEditor(wxWindow* parent, MapDocumentWPtr document) : 46 wxPanel(parent), 47 m_document(document), 48 m_layerList(NULL) { 49 createGui(); 50 } 51 OnSetCurrentLayer(LayerCommand & event)52 void LayerEditor::OnSetCurrentLayer(LayerCommand& event) { 53 if (IsBeingDeleted()) return; 54 55 Model::Layer* layer = event.layer(); 56 MapDocumentSPtr document = lock(m_document); 57 if (layer->locked()) 58 document->resetLock(Model::NodeList(1, layer)); 59 if (layer->hidden()) 60 document->resetVisibility(Model::NodeList(1, layer)); 61 document->setCurrentLayer(event.layer()); 62 } 63 OnLayerRightClick(LayerCommand & event)64 void LayerEditor::OnLayerRightClick(LayerCommand& event) { 65 if (IsBeingDeleted()) return; 66 67 const Model::Layer* layer = event.layer(); 68 69 wxMenu popupMenu; 70 popupMenu.Append(MoveSelectionToLayerCommandId, "Move selection to layer"); 71 popupMenu.Append(SelectAllInLayerCommandId, "Select all in layer"); 72 popupMenu.AppendSeparator(); 73 popupMenu.Append(ToggleLayerVisibleCommandId, layer->hidden() ? "Show layer" : "Hide layer"); 74 popupMenu.Append(ToggleLayerLockedCommandId, layer->locked() ? "Unlock layer" : "Lock layer"); 75 popupMenu.AppendSeparator(); 76 popupMenu.Append(RemoveLayerCommandId, "Remove layer"); 77 78 popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnMoveSelectionToLayer, this, MoveSelectionToLayerCommandId); 79 popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateMoveSelectionToLayerUI, this, MoveSelectionToLayerCommandId); 80 popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnSelectAllInLayer, this, SelectAllInLayerCommandId); 81 popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnToggleLayerVisibleFromMenu, this, ToggleLayerVisibleCommandId); 82 popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateToggleLayerVisibleUI, this, ToggleLayerVisibleCommandId); 83 popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnToggleLayerLockedFromMenu, this, ToggleLayerLockedCommandId); 84 popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateToggleLayerLockedUI, this, ToggleLayerLockedCommandId); 85 popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnRemoveLayer, this, RemoveLayerCommandId); 86 popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateRemoveLayerUI, this, RemoveLayerCommandId); 87 88 PopupMenu(&popupMenu); 89 } 90 OnToggleLayerVisibleFromMenu(wxCommandEvent & event)91 void LayerEditor::OnToggleLayerVisibleFromMenu(wxCommandEvent& event) { 92 if (IsBeingDeleted()) return; 93 94 toggleLayerVisible(m_layerList->selectedLayer()); 95 } 96 OnToggleLayerVisibleFromList(LayerCommand & event)97 void LayerEditor::OnToggleLayerVisibleFromList(LayerCommand& event) { 98 if (IsBeingDeleted()) return; 99 100 toggleLayerVisible(event.layer()); 101 } 102 OnUpdateToggleLayerVisibleUI(wxUpdateUIEvent & event)103 void LayerEditor::OnUpdateToggleLayerVisibleUI(wxUpdateUIEvent& event) { 104 Model::Layer* layer = m_layerList->selectedLayer(); 105 if (layer == NULL) { 106 event.Enable(false); 107 return; 108 } 109 110 MapDocumentSPtr document = lock(m_document); 111 if (!layer->hidden() && layer == document->currentLayer()) { 112 event.Enable(false); 113 return; 114 } 115 116 event.Enable(true); 117 } 118 toggleLayerVisible(Model::Layer * layer)119 void LayerEditor::toggleLayerVisible(Model::Layer* layer) { 120 assert(layer != NULL); 121 MapDocumentSPtr document = lock(m_document); 122 if (!layer->hidden()) 123 document->hide(Model::NodeList(1, layer)); 124 else 125 document->resetVisibility(Model::NodeList(1, layer)); 126 } 127 OnToggleLayerLockedFromMenu(wxCommandEvent & event)128 void LayerEditor::OnToggleLayerLockedFromMenu(wxCommandEvent& event) { 129 if (IsBeingDeleted()) return; 130 131 toggleLayerLocked(m_layerList->selectedLayer()); 132 } 133 OnToggleLayerLockedFromList(LayerCommand & event)134 void LayerEditor::OnToggleLayerLockedFromList(LayerCommand& event) { 135 if (IsBeingDeleted()) return; 136 137 toggleLayerLocked(event.layer()); 138 } 139 OnUpdateToggleLayerLockedUI(wxUpdateUIEvent & event)140 void LayerEditor::OnUpdateToggleLayerLockedUI(wxUpdateUIEvent& event) { 141 Model::Layer* layer = m_layerList->selectedLayer(); 142 if (layer == NULL) { 143 event.Enable(false); 144 return; 145 } 146 147 MapDocumentSPtr document = lock(m_document); 148 if (!layer->locked() && layer == document->currentLayer()) { 149 event.Enable(false); 150 return; 151 } 152 153 event.Enable(true); 154 } 155 toggleLayerLocked(Model::Layer * layer)156 void LayerEditor::toggleLayerLocked(Model::Layer* layer) { 157 assert(layer != NULL); 158 MapDocumentSPtr document = lock(m_document); 159 if (!layer->locked()) 160 document->lock(Model::NodeList(1, layer)); 161 else 162 document->resetLock(Model::NodeList(1, layer)); 163 } 164 165 class LayerEditor::CollectMoveableNodes : public Model::NodeVisitor { 166 private: 167 Model::World* m_world; 168 Model::NodeSet m_selectNodes; 169 Model::NodeSet m_moveNodes; 170 public: CollectMoveableNodes(Model::World * world)171 CollectMoveableNodes(Model::World* world) : m_world(world) {} 172 selectNodes() const173 const Model::NodeList selectNodes() const { 174 return Model::NodeList(m_selectNodes.begin(), m_selectNodes.end()); 175 } 176 moveNodes() const177 const Model::NodeList moveNodes() const { 178 return Model::NodeList(m_moveNodes.begin(), m_moveNodes.end()); 179 } 180 private: doVisit(Model::World * world)181 void doVisit(Model::World* world) {} doVisit(Model::Layer * layer)182 void doVisit(Model::Layer* layer) {} 183 doVisit(Model::Group * group)184 void doVisit(Model::Group* group) { 185 assert(group->selected()); 186 187 if (group->group() == NULL) { 188 m_moveNodes.insert(group); 189 m_selectNodes.insert(group); 190 } 191 } 192 doVisit(Model::Entity * entity)193 void doVisit(Model::Entity* entity) { 194 assert(entity->selected()); 195 196 if (entity->group() == NULL) { 197 m_moveNodes.insert(entity); 198 m_selectNodes.insert(entity); 199 } 200 } 201 doVisit(Model::Brush * brush)202 void doVisit(Model::Brush* brush) { 203 assert(brush->selected()); 204 if (brush->group() == NULL) { 205 Model::AttributableNode* entity = brush->entity(); 206 if (entity == m_world) { 207 m_moveNodes.insert(brush); 208 m_selectNodes.insert(brush); 209 } else { 210 if (m_moveNodes.insert(entity).second) { 211 const Model::NodeList& siblings = entity->children(); 212 m_selectNodes.insert(siblings.begin(), siblings.end()); 213 } 214 } 215 } 216 } 217 }; 218 OnMoveSelectionToLayer(wxCommandEvent & event)219 void LayerEditor::OnMoveSelectionToLayer(wxCommandEvent& event) { 220 if (IsBeingDeleted()) return; 221 222 Model::Layer* layer = m_layerList->selectedLayer(); 223 assert(layer != NULL); 224 225 MapDocumentSPtr document = lock(m_document); 226 Transaction transaction(document, "Move Nodes to " + layer->name()); 227 moveSelectedNodesToLayer(document, layer); 228 } 229 OnUpdateMoveSelectionToLayerUI(wxUpdateUIEvent & event)230 void LayerEditor::OnUpdateMoveSelectionToLayerUI(wxUpdateUIEvent& event) { 231 if (IsBeingDeleted()) return; 232 233 const Model::Layer* layer = m_layerList->selectedLayer(); 234 if (layer == NULL) { 235 event.Enable(false); 236 return; 237 } 238 239 MapDocumentSPtr document = lock(m_document); 240 const Model::NodeList& nodes = document->selectedNodes().nodes(); 241 if (nodes.empty()) { 242 event.Enable(false); 243 return; 244 } 245 246 Model::NodeList::const_iterator it, end; 247 for (it = nodes.begin(), end = nodes.end(); it != end; ++it) { 248 Model::Node* node = *it; 249 Model::Group* nodeGroup = Model::findGroup(node); 250 if (nodeGroup != NULL) { 251 event.Enable(false); 252 return; 253 } 254 } 255 256 for (it = nodes.begin(), end = nodes.end(); it != end; ++it) { 257 Model::Node* node = *it; 258 Model::Layer* nodeLayer = Model::findLayer(node); 259 if (nodeLayer != layer) { 260 event.Enable(true); 261 return; 262 } 263 } 264 265 event.Enable(false); 266 } 267 OnSelectAllInLayer(wxCommandEvent & event)268 void LayerEditor::OnSelectAllInLayer(wxCommandEvent& event) { 269 if (IsBeingDeleted()) return; 270 271 Model::Layer* layer = m_layerList->selectedLayer(); 272 assert(layer != NULL); 273 274 MapDocumentSPtr document = lock(m_document); 275 276 Model::CollectSelectableNodesVisitor visitor(document->editorContext()); 277 layer->recurse(visitor); 278 279 const Model::NodeList& nodes = visitor.nodes(); 280 document->deselectAll(); 281 document->select(nodes); 282 } 283 OnAddLayer(wxCommandEvent & event)284 void LayerEditor::OnAddLayer(wxCommandEvent& event) { 285 if (IsBeingDeleted()) return; 286 287 const String name = queryLayerName(); 288 if (!name.empty()) { 289 MapDocumentSPtr document = lock(m_document); 290 Model::World* world = document->world(); 291 Model::Layer* layer = world->createLayer(name, document->worldBounds()); 292 293 Transaction transaction(document, "Create Layer " + layer->name()); 294 document->addNode(layer, world); 295 document->setCurrentLayer(layer); 296 m_layerList->setSelectedLayer(layer); 297 } 298 } 299 queryLayerName()300 String LayerEditor::queryLayerName() { 301 while (true) { 302 wxTextEntryDialog dialog(this, "Enter a name", "Layer Name", "Unnamed"); 303 dialog.CentreOnParent(); 304 if (dialog.ShowModal() != wxID_OK) 305 return ""; 306 307 const String name = dialog.GetValue().ToStdString(); 308 if (StringUtils::isBlank(name)) { 309 if (wxMessageBox("Layer names cannot be blank.", "Error", wxOK | wxCANCEL | wxCENTRE, this) != wxOK) 310 return ""; 311 } else if (StringUtils::containsCaseInsensitive(name, "\"")) { 312 if (wxMessageBox("Layer names cannot contain double quotes.", "Error", wxOK | wxCANCEL | wxCENTRE, this) != wxOK) 313 return ""; 314 } else { 315 return name; 316 } 317 } 318 } 319 OnRemoveLayer(wxCommandEvent & event)320 void LayerEditor::OnRemoveLayer(wxCommandEvent& event) { 321 if (IsBeingDeleted()) return; 322 323 Model::Layer* layer = m_layerList->selectedLayer(); 324 assert(layer != NULL); 325 326 Model::Layer* newCurrentLayer = findVisibleAndUnlockedLayer(layer); 327 assert(newCurrentLayer != NULL); 328 329 MapDocumentSPtr document = lock(m_document); 330 Model::Layer* defaultLayer = document->world()->defaultLayer(); 331 332 Model::CollectSelectableNodesVisitor collectSelectableNodes(document->editorContext()); 333 layer->recurse(collectSelectableNodes); 334 335 Transaction transaction(document, "Remove Layer " + layer->name()); 336 document->deselectAll(); 337 document->select(collectSelectableNodes.nodes()); 338 if (layer->hasChildren()) 339 document->reparentNodes(defaultLayer, layer->children()); 340 if (document->currentLayer() == layer) 341 document->setCurrentLayer(newCurrentLayer); 342 document->removeNode(layer); 343 } 344 OnUpdateRemoveLayerUI(wxUpdateUIEvent & event)345 void LayerEditor::OnUpdateRemoveLayerUI(wxUpdateUIEvent& event) { 346 if (IsBeingDeleted()) return; 347 348 const Model::Layer* layer = m_layerList->selectedLayer(); 349 if (layer == NULL) { 350 event.Enable(false); 351 return; 352 } 353 354 if (findVisibleAndUnlockedLayer(layer) == NULL) { 355 event.Enable(false); 356 return; 357 } 358 359 MapDocumentSPtr document = lock(m_document); 360 event.Enable(layer != document->world()->defaultLayer()); 361 } 362 OnShowAllLayers(wxCommandEvent & event)363 void LayerEditor::OnShowAllLayers(wxCommandEvent& event) { 364 if (IsBeingDeleted()) return; 365 366 MapDocumentSPtr document = lock(m_document); 367 const Model::LayerList& layers = document->world()->allLayers(); 368 document->resetVisibility(Model::NodeList(layers.begin(), layers.end())); 369 } 370 findVisibleAndUnlockedLayer(const Model::Layer * except) const371 Model::Layer* LayerEditor::findVisibleAndUnlockedLayer(const Model::Layer* except) const { 372 MapDocumentSPtr document = lock(m_document); 373 if (!document->world()->defaultLayer()->locked() && !document->world()->defaultLayer()->hidden()) 374 return document->world()->defaultLayer(); 375 376 const Model::LayerList& layers = document->world()->customLayers(); 377 Model::LayerList::const_iterator it, end; 378 for (it = layers.begin(), end = layers.end(); it != end; ++it) { 379 Model::Layer* layer = *it; 380 if (layer != except && !layer->locked() && !layer->hidden()) 381 return layer; 382 } 383 384 return NULL; 385 } 386 moveSelectedNodesToLayer(MapDocumentSPtr document,Model::Layer * layer)387 void LayerEditor::moveSelectedNodesToLayer(MapDocumentSPtr document, Model::Layer* layer) { 388 const Model::NodeList& selectedNodes = document->selectedNodes().nodes(); 389 390 CollectMoveableNodes visitor(document->world()); 391 Model::Node::accept(selectedNodes.begin(), selectedNodes.end(), visitor); 392 393 const Model::NodeList moveNodes = visitor.moveNodes(); 394 if (!moveNodes.empty()) { 395 const Model::NodeList selectNodes = visitor.selectNodes(); 396 document->deselectAll(); 397 document->reparentNodes(layer, visitor.moveNodes()); 398 if (!layer->hidden() && !layer->locked()) 399 document->select(visitor.selectNodes()); 400 } 401 } 402 createGui()403 void LayerEditor::createGui() { 404 SetBackgroundColour(*wxWHITE); 405 406 m_layerList = new LayerListView(this, m_document); 407 m_layerList->Bind(LAYER_SET_CURRENT_EVENT, &LayerEditor::OnSetCurrentLayer, this); 408 m_layerList->Bind(LAYER_RIGHT_CLICK_EVENT, &LayerEditor::OnLayerRightClick, this); 409 m_layerList->Bind(LAYER_TOGGLE_VISIBLE_EVENT, &LayerEditor::OnToggleLayerVisibleFromList, this); 410 m_layerList->Bind(LAYER_TOGGLE_LOCKED_EVENT, &LayerEditor::OnToggleLayerLockedFromList, this); 411 412 wxWindow* addLayerButton = createBitmapButton(this, "Add.png", "Add a new layer from the current selection"); 413 wxWindow* removeLayerButton = createBitmapButton(this, "Remove.png", "Remove the selected layer and move its objects to the default layer"); 414 wxWindow* showAllLayersButton = createBitmapButton(this, "Visible.png", "Show all layers"); 415 416 addLayerButton->Bind(wxEVT_BUTTON, &LayerEditor::OnAddLayer, this); 417 removeLayerButton->Bind(wxEVT_BUTTON, &LayerEditor::OnRemoveLayer, this); 418 removeLayerButton->Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateRemoveLayerUI, this); 419 showAllLayersButton->Bind(wxEVT_BUTTON, &LayerEditor::OnShowAllLayers, this); 420 421 wxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL); 422 buttonSizer->Add(addLayerButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin); 423 buttonSizer->Add(removeLayerButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin); 424 buttonSizer->Add(showAllLayersButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin); 425 buttonSizer->AddStretchSpacer(); 426 427 wxSizer* sizer = new wxBoxSizer(wxVERTICAL); 428 sizer->Add(m_layerList, 1, wxEXPAND); 429 sizer->Add(buttonSizer, 0, wxEXPAND); 430 SetSizer(sizer); 431 } 432 } 433 } 434