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 "TextureCollectionEditor.h"
21 
22 #include "PreferenceManager.h"
23 #include "Assets/TextureManager.h"
24 #include "Assets/TextureCollection.h"
25 #include "View/ChoosePathTypeDialog.h"
26 #include "View/MapDocument.h"
27 #include "View/ViewConstants.h"
28 #include "View/ViewUtils.h"
29 #include "View/wxUtils.h"
30 
31 #include <wx/bmpbuttn.h>
32 #include <wx/filedlg.h>
33 #include <wx/listbox.h>
34 #include <wx/panel.h>
35 #include <wx/sizer.h>
36 
37 namespace TrenchBroom {
38     namespace View {
TextureCollectionEditor(wxWindow * parent,MapDocumentWPtr document)39         TextureCollectionEditor::TextureCollectionEditor(wxWindow* parent, MapDocumentWPtr document) :
40         wxPanel(parent),
41         m_document(document) {
42             createGui();
43             bindObservers();
44         }
45 
~TextureCollectionEditor()46         TextureCollectionEditor::~TextureCollectionEditor() {
47             unbindObservers();
48         }
49 
OnAddTextureCollectionsClicked(wxCommandEvent & event)50         void TextureCollectionEditor::OnAddTextureCollectionsClicked(wxCommandEvent& event) {
51             if (IsBeingDeleted()) return;
52 
53             const wxString pathWxStr = ::wxFileSelector("Load Texture Collection", wxEmptyString, wxEmptyString, wxEmptyString, "", wxFD_OPEN);
54             if (pathWxStr.empty())
55                 return;
56 
57             loadTextureCollection(m_document, this, pathWxStr);
58         }
59 
OnRemoveTextureCollectionsClicked(wxCommandEvent & event)60         void TextureCollectionEditor::OnRemoveTextureCollectionsClicked(wxCommandEvent& event) {
61             if (IsBeingDeleted()) return;
62 
63             wxArrayInt selections;
64             m_collections->GetSelections(selections);
65             assert(!selections.empty());
66 
67             MapDocumentSPtr document = lock(m_document);
68 
69             const StringList names = document->externalTextureCollectionNames();
70             StringList removeNames;
71 
72             for (size_t i = 0; i < selections.size(); ++i) {
73                 const size_t index = static_cast<size_t>(selections[i]);
74                 assert(index < names.size());
75                 removeNames.push_back(names[index]);
76             }
77 
78             document->removeTextureCollections(removeNames);
79         }
80 
OnMoveTextureCollectionUpClicked(wxCommandEvent & event)81         void TextureCollectionEditor::OnMoveTextureCollectionUpClicked(wxCommandEvent& event) {
82             if (IsBeingDeleted()) return;
83 
84             wxArrayInt selections;
85             m_collections->GetSelections(selections);
86             assert(selections.size() == 1);
87 
88             MapDocumentSPtr document = lock(m_document);
89 
90             const StringList names = document->externalTextureCollectionNames();
91 
92             const size_t index = static_cast<size_t>(selections.front());
93             assert(index > 0 && index < names.size());
94 
95             document->moveTextureCollectionUp(names[index]);
96             m_collections->SetSelection(static_cast<int>(index - 1));
97         }
98 
OnMoveTextureCollectionDownClicked(wxCommandEvent & event)99         void TextureCollectionEditor::OnMoveTextureCollectionDownClicked(wxCommandEvent& event) {
100             if (IsBeingDeleted()) return;
101 
102             wxArrayInt selections;
103             m_collections->GetSelections(selections);
104             assert(selections.size() == 1);
105 
106             MapDocumentSPtr document = lock(m_document);
107 
108             const StringList names = document->externalTextureCollectionNames();
109 
110             const size_t index = static_cast<size_t>(selections.front());
111             assert(index < names.size() - 1);
112 
113             document->moveTextureCollectionDown(names[index]);
114             m_collections->SetSelection(static_cast<int>(index + 1));
115         }
116 
OnUpdateRemoveButtonUI(wxUpdateUIEvent & event)117         void TextureCollectionEditor::OnUpdateRemoveButtonUI(wxUpdateUIEvent& event) {
118             if (IsBeingDeleted()) return;
119 
120                 wxArrayInt selections;
121                 event.Enable(m_collections->GetSelections(selections) > 0);
122         }
123 
OnUpdateMoveUpButtonUI(wxUpdateUIEvent & event)124         void TextureCollectionEditor::OnUpdateMoveUpButtonUI(wxUpdateUIEvent& event) {
125             if (IsBeingDeleted()) return;
126 
127             wxArrayInt selections;
128             event.Enable(m_collections->GetSelections(selections) == 1 && selections.front() > 0);
129         }
130 
OnUpdateMoveDownButtonUI(wxUpdateUIEvent & event)131         void TextureCollectionEditor::OnUpdateMoveDownButtonUI(wxUpdateUIEvent& event) {
132             if (IsBeingDeleted()) return;
133 
134             const int collectionCount = static_cast<int>(m_collections->GetCount());
135             wxArrayInt selections;
136             event.Enable(m_collections->GetSelections(selections) == 1 && selections.front() < collectionCount - 1);
137         }
138 
createGui()139         void TextureCollectionEditor::createGui() {
140             static const int ListBoxMargin =
141 #ifdef __APPLE__
142             0;
143 #else
144             LayoutConstants::NarrowHMargin;
145 #endif
146 
147             m_collections = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE | wxBORDER_NONE);
148 
149             wxWindow* addTextureCollectionsButton = createBitmapButton(this, "Add.png", "Add texture collections from the file system");
150             wxWindow* removeTextureCollectionsButton = createBitmapButton(this, "Remove.png", "Remove the selected texture collections");
151             wxWindow* moveTextureCollectionUpButton = createBitmapButton(this, "Up.png", "Move the selected texture collection up");
152             wxWindow* moveTextureCollectionDownButton = createBitmapButton(this, "Down.png", "Move the selected texture collection down");
153 
154             addTextureCollectionsButton->Bind(wxEVT_BUTTON, &TextureCollectionEditor::OnAddTextureCollectionsClicked, this);
155             removeTextureCollectionsButton->Bind(wxEVT_BUTTON, &TextureCollectionEditor::OnRemoveTextureCollectionsClicked, this);
156             moveTextureCollectionUpButton->Bind(wxEVT_BUTTON, &TextureCollectionEditor::OnMoveTextureCollectionUpClicked, this);
157             moveTextureCollectionDownButton->Bind(wxEVT_BUTTON, &TextureCollectionEditor::OnMoveTextureCollectionDownClicked, this);
158             removeTextureCollectionsButton->Bind(wxEVT_UPDATE_UI, &TextureCollectionEditor::OnUpdateRemoveButtonUI, this);
159             moveTextureCollectionUpButton->Bind(wxEVT_UPDATE_UI, &TextureCollectionEditor::OnUpdateMoveUpButtonUI, this);
160             moveTextureCollectionDownButton->Bind(wxEVT_UPDATE_UI, &TextureCollectionEditor::OnUpdateMoveDownButtonUI, this);
161 
162             wxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
163             buttonSizer->Add(addTextureCollectionsButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
164             buttonSizer->Add(removeTextureCollectionsButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
165             buttonSizer->AddSpacer(LayoutConstants::WideHMargin);
166             buttonSizer->Add(moveTextureCollectionUpButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
167             buttonSizer->Add(moveTextureCollectionDownButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
168             buttonSizer->AddStretchSpacer();
169 
170             wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
171             sizer->Add(m_collections, 1, wxEXPAND | wxLEFT | wxRIGHT, ListBoxMargin);
172             sizer->Add(buttonSizer, 0, wxEXPAND | wxLEFT | wxRIGHT, LayoutConstants::NarrowHMargin);
173             sizer->SetItemMinSize(m_collections, 100, 70);
174 
175             SetBackgroundColour(*wxWHITE);
176             SetSizerAndFit(sizer);
177         }
178 
bindObservers()179         void TextureCollectionEditor::bindObservers() {
180             MapDocumentSPtr document = lock(m_document);
181             document->documentWasNewedNotifier.addObserver(this, &TextureCollectionEditor::documentWasNewed);
182             document->documentWasLoadedNotifier.addObserver(this, &TextureCollectionEditor::documentWasLoaded);
183             document->textureCollectionsDidChangeNotifier.addObserver(this, &TextureCollectionEditor::textureCollectionsDidChange);
184 
185             PreferenceManager& prefs = PreferenceManager::instance();
186             prefs.preferenceDidChangeNotifier.addObserver(this, &TextureCollectionEditor::preferenceDidChange);
187         }
188 
unbindObservers()189         void TextureCollectionEditor::unbindObservers() {
190             if (!expired(m_document)) {
191                 MapDocumentSPtr document = lock(m_document);
192                 document->documentWasNewedNotifier.removeObserver(this, &TextureCollectionEditor::documentWasNewed);
193                 document->documentWasLoadedNotifier.removeObserver(this, &TextureCollectionEditor::documentWasLoaded);
194                 document->textureCollectionsDidChangeNotifier.removeObserver(this, &TextureCollectionEditor::textureCollectionsDidChange);
195             }
196 
197             PreferenceManager& prefs = PreferenceManager::instance();
198             prefs.preferenceDidChangeNotifier.removeObserver(this, &TextureCollectionEditor::preferenceDidChange);
199         }
200 
documentWasNewed(MapDocument * document)201         void TextureCollectionEditor::documentWasNewed(MapDocument* document) {
202             updateControls();
203         }
204 
documentWasLoaded(MapDocument * document)205         void TextureCollectionEditor::documentWasLoaded(MapDocument* document) {
206             updateControls();
207         }
208 
textureCollectionsDidChange()209         void TextureCollectionEditor::textureCollectionsDidChange() {
210             updateControls();
211         }
212 
preferenceDidChange(const IO::Path & path)213         void TextureCollectionEditor::preferenceDidChange(const IO::Path& path) {
214             MapDocumentSPtr document = lock(m_document);
215             if (document->isGamePathPreference(path))
216                 updateControls();
217         }
218 
updateControls()219         void TextureCollectionEditor::updateControls() {
220             m_collections->Clear();
221 
222             MapDocumentSPtr document = lock(m_document);
223             const StringList names = document->externalTextureCollectionNames();
224             StringList::const_iterator it, end;
225             for (it = names.begin(), end = names.end(); it != end; ++it) {
226                 const String& name = *it;
227                 m_collections->Append(name);
228             }
229         }
230     }
231 }
232