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 "ReplaceTextureFrame.h"
21 
22 #include "Assets/Texture.h"
23 #include "Model/BrushFace.h"
24 #include "Model/CollectMatchingBrushFacesVisitor.h"
25 #include "Model/World.h"
26 #include "View/BorderLine.h"
27 #include "View/MapDocument.h"
28 #include "View/TextureBrowser.h"
29 #include "View/TitledPanel.h"
30 #include "View/ViewConstants.h"
31 #include "View/wxUtils.h"
32 
33 #include <wx/button.h>
34 #include <wx/msgdlg.h>
35 #include <wx/sizer.h>
36 
37 namespace TrenchBroom {
38     namespace View {
ReplaceTextureFrame(wxWindow * parent,MapDocumentWPtr document,GLContextManager & contextManager)39         ReplaceTextureFrame::ReplaceTextureFrame(wxWindow* parent, MapDocumentWPtr document, GLContextManager& contextManager) :
40         wxFrame(parent, wxID_ANY, "Replace Texture", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT),
41         m_document(document),
42         m_subjectBrowser(NULL),
43         m_replacementBrowser(NULL) {
44             createGui(contextManager);
45         }
46 
OnReplace(wxCommandEvent & event)47         void ReplaceTextureFrame::OnReplace(wxCommandEvent& event) {
48             if (IsBeingDeleted()) return;
49 
50             const Assets::Texture* subject = m_subjectBrowser->selectedTexture();
51             assert(subject != NULL);
52 
53             Assets::Texture* replacement = m_replacementBrowser->selectedTexture();
54             assert(replacement != NULL);
55 
56             MapDocumentSPtr document = lock(m_document);
57             const Model::BrushFaceList faces = getApplicableFaces();
58 
59             if (faces.empty()) {
60                 wxMessageBox("None of the selected faces has the selected texture", "Replace Failed");
61                 return;
62             }
63 
64             Transaction transaction(document, "Replace Textures");
65             document->select(faces);
66             document->setTexture(replacement);
67 
68             StringStream msg;
69             msg << "Replaced texture '" << subject->name() << "' with '" << replacement->name() << "' on " << faces.size() << " faces.";
70             wxMessageBox(msg.str(), "Replace succeeded");
71         }
72 
getApplicableFaces() const73         Model::BrushFaceList ReplaceTextureFrame::getApplicableFaces() const {
74             MapDocumentSPtr document = lock(m_document);
75             Model::BrushFaceList faces = document->allSelectedBrushFaces();
76             if (faces.empty()) {
77                 Model::CollectBrushFacesVisitor collect;
78                 document->world()->acceptAndRecurse(collect);
79                 faces = collect.faces();
80             }
81 
82             const Assets::Texture* subject = m_subjectBrowser->selectedTexture();
83             assert(subject != NULL);
84 
85             Model::BrushFaceList result;
86 
87             Model::BrushFaceList::const_iterator it, end;
88             for (it = faces.begin(), end = faces.end(); it != end; ++it) {
89                 Model::BrushFace* face = *it;
90                 if (face->texture() == subject)
91                     result.push_back(face);
92             }
93             return result;
94         }
95 
OnClose(wxCommandEvent & event)96         void ReplaceTextureFrame::OnClose(wxCommandEvent& event) {
97             if (IsBeingDeleted()) return;
98 
99             Close();
100         }
101 
OnUpdateReplaceButton(wxUpdateUIEvent & event)102         void ReplaceTextureFrame::OnUpdateReplaceButton(wxUpdateUIEvent& event) {
103             if (IsBeingDeleted()) return;
104 
105             const Assets::Texture* subject = m_subjectBrowser->selectedTexture();
106             const Assets::Texture* replacement = m_replacementBrowser->selectedTexture();
107             event.Enable(subject != NULL && replacement != NULL);
108         }
109 
createGui(GLContextManager & contextManager)110         void ReplaceTextureFrame::createGui(GLContextManager& contextManager) {
111             TitledPanel* subjectPanel = new TitledPanel(this, "Find");
112             m_subjectBrowser = new TextureBrowser(subjectPanel->getPanel(), m_document, contextManager);
113             m_subjectBrowser->setHideUnused(true);
114 
115             wxSizer* subjectPanelSizer = new wxBoxSizer(wxVERTICAL);
116             subjectPanelSizer->Add(m_subjectBrowser, 1, wxEXPAND);
117             subjectPanel->getPanel()->SetSizer(subjectPanelSizer);
118 
119             TitledPanel* replacementPanel = new TitledPanel(this, "Replace with");
120             m_replacementBrowser = new TextureBrowser(replacementPanel->getPanel(), m_document, contextManager);
121 
122             wxSizer* replacementPanelSizer = new wxBoxSizer(wxVERTICAL);
123             replacementPanelSizer->Add(m_replacementBrowser, 1, wxEXPAND);
124             replacementPanel->getPanel()->SetSizer(replacementPanelSizer);
125 
126             wxSizer* upperSizer = new wxBoxSizer(wxHORIZONTAL);
127             upperSizer->Add(subjectPanel, 1, wxEXPAND);
128             upperSizer->Add(new BorderLine(this, BorderLine::Direction_Vertical), 0, wxEXPAND);
129             upperSizer->Add(replacementPanel, 1, wxEXPAND);
130 
131             wxButton* replaceButton = new wxButton(this, wxID_OK, "Replace");
132             replaceButton->SetToolTip("Perform replacement on all selected faces");
133             wxButton* closeButton = new wxButton(this, wxID_CLOSE, "Close");
134             closeButton->SetToolTip("Close this window");
135 
136             replaceButton->Bind(wxEVT_BUTTON, &ReplaceTextureFrame::OnReplace, this);
137             closeButton->Bind(wxEVT_BUTTON, &ReplaceTextureFrame::OnClose, this);
138 
139             replaceButton->Bind(wxEVT_UPDATE_UI, &ReplaceTextureFrame::OnUpdateReplaceButton, this);
140 
141             wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
142             buttonSizer->AddButton(replaceButton);
143             buttonSizer->AddButton(closeButton);
144             buttonSizer->Realize();
145 
146             wxSizer* outerSizer = new wxBoxSizer(wxVERTICAL);
147             outerSizer->Add(upperSizer, 1, wxEXPAND);
148             outerSizer->Add(wrapDialogButtonSizer(buttonSizer, this), 0, wxEXPAND);
149             SetSizer(outerSizer);
150 
151             wxAcceleratorEntry entries[] = {
152                 wxAcceleratorEntry(wxACCEL_CTRL, 'W', wxID_CLOSE)
153             };
154             SetAcceleratorTable(wxAcceleratorTable(1, entries));
155             Bind(wxEVT_MENU, &ReplaceTextureFrame::OnClose, this, wxID_CLOSE);
156 
157             SetMinSize(wxSize(650, 450));
158             SetSize(wxSize(650, 450));
159         }
160     }
161 }
162