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 "UVEditor.h"
21 #include "Model/ChangeBrushFaceAttributesRequest.h"
22 #include "View/MapDocument.h"
23 #include "View/UVView.h"
24 #include "View/ViewConstants.h"
25 #include "View/wxUtils.h"
26 
27 #include <wx/bmpbuttn.h>
28 #include <wx/sizer.h>
29 #include <wx/spinctrl.h>
30 #include <wx/stattext.h>
31 
32 namespace TrenchBroom {
33     namespace View {
UVEditor(wxWindow * parent,MapDocumentWPtr document,GLContextManager & contextManager)34         UVEditor::UVEditor(wxWindow* parent, MapDocumentWPtr document, GLContextManager& contextManager) :
35         wxPanel(parent),
36         m_document(document),
37         m_uvView(NULL),
38         m_xSubDivisionEditor(NULL),
39         m_ySubDivisionEditor(NULL) {
40             createGui(contextManager);
41         }
42 
OnResetTexture(wxCommandEvent & event)43         void UVEditor::OnResetTexture(wxCommandEvent& event) {
44             if (IsBeingDeleted()) return;
45 
46             Model::ChangeBrushFaceAttributesRequest request;
47             request.resetTextureAxes();
48             request.setOffset(Vec2f::Null);
49             request.setRotation(0.0f);
50             request.setScale(Vec2f::One);
51 
52             MapDocumentSPtr document = lock(m_document);
53             document->setFaceAttributes(request);
54         }
55 
OnFlipTextureH(wxCommandEvent & event)56         void UVEditor::OnFlipTextureH(wxCommandEvent& event) {
57             if (IsBeingDeleted()) return;
58 
59             Model::ChangeBrushFaceAttributesRequest request;
60             request.mulXScale(-1.0f);
61 
62             MapDocumentSPtr document = lock(m_document);
63             document->setFaceAttributes(request);
64         }
65 
OnFlipTextureV(wxCommandEvent & event)66         void UVEditor::OnFlipTextureV(wxCommandEvent& event) {
67             if (IsBeingDeleted()) return;
68 
69             Model::ChangeBrushFaceAttributesRequest request;
70             request.mulYScale(-1.0f);
71 
72             MapDocumentSPtr document = lock(m_document);
73             document->setFaceAttributes(request);
74         }
75 
OnRotateTextureCCW(wxCommandEvent & event)76         void UVEditor::OnRotateTextureCCW(wxCommandEvent& event) {
77             if (IsBeingDeleted()) return;
78 
79             Model::ChangeBrushFaceAttributesRequest request;
80             request.addRotation(90.0f);
81 
82             MapDocumentSPtr document = lock(m_document);
83             document->setFaceAttributes(request);
84         }
85 
OnRotateTextureCW(wxCommandEvent & event)86         void UVEditor::OnRotateTextureCW(wxCommandEvent& event) {
87             if (IsBeingDeleted()) return;
88 
89             Model::ChangeBrushFaceAttributesRequest request;
90             request.addRotation(-90.0f);
91 
92             MapDocumentSPtr document = lock(m_document);
93             document->setFaceAttributes(request);
94         }
95 
OnUpdateButtonUI(wxUpdateUIEvent & event)96         void UVEditor::OnUpdateButtonUI(wxUpdateUIEvent& event) {
97             if (IsBeingDeleted()) return;
98 
99             MapDocumentSPtr document = lock(m_document);
100             event.Enable(!document->allSelectedBrushFaces().empty());
101         }
102 
OnSubDivisionChanged(wxSpinEvent & event)103         void UVEditor::OnSubDivisionChanged(wxSpinEvent& event) {
104             if (IsBeingDeleted()) return;
105 
106             const int x = m_xSubDivisionEditor->GetValue();
107             const int y = m_ySubDivisionEditor->GetValue();
108             m_uvView->setSubDivisions(Vec2i(x, y));
109         }
110 
createGui(GLContextManager & contextManager)111         void UVEditor::createGui(GLContextManager& contextManager) {
112             m_uvView = new UVView(this, m_document, contextManager);
113 
114             wxWindow* resetTextureButton = createBitmapButton(this, "ResetTexture.png", "Reset texture alignment");
115             wxWindow* flipTextureHButton = createBitmapButton(this, "FlipTextureH.png", "Flip texture X axis");
116             wxWindow* flipTextureVButton = createBitmapButton(this, "FlipTextureV.png", "Flip texture Y axis");
117             wxWindow* rotateTextureCCWButton = createBitmapButton(this, "RotateTextureCCW.png", "Rotate texture 90° counter-clockwise");
118             wxWindow* rotateTextureCWButton = createBitmapButton(this, "RotateTextureCW.png", "Rotate texture 90° clockwise");
119 
120             resetTextureButton->Bind(wxEVT_BUTTON, &UVEditor::OnResetTexture, this);
121             resetTextureButton->Bind(wxEVT_UPDATE_UI, &UVEditor::OnUpdateButtonUI, this);
122             flipTextureHButton->Bind(wxEVT_BUTTON, &UVEditor::OnFlipTextureH, this);
123             flipTextureHButton->Bind(wxEVT_UPDATE_UI, &UVEditor::OnUpdateButtonUI, this);
124             flipTextureVButton->Bind(wxEVT_BUTTON, &UVEditor::OnFlipTextureV, this);
125             flipTextureVButton->Bind(wxEVT_UPDATE_UI, &UVEditor::OnUpdateButtonUI, this);
126             rotateTextureCCWButton->Bind(wxEVT_BUTTON, &UVEditor::OnRotateTextureCCW, this);
127             rotateTextureCCWButton->Bind(wxEVT_UPDATE_UI, &UVEditor::OnUpdateButtonUI, this);
128             rotateTextureCWButton->Bind(wxEVT_BUTTON, &UVEditor::OnRotateTextureCW, this);
129             rotateTextureCWButton->Bind(wxEVT_UPDATE_UI, &UVEditor::OnUpdateButtonUI, this);
130 
131             wxStaticText* gridLabel = new wxStaticText(this, wxID_ANY, "Grid ");
132             gridLabel->SetFont(gridLabel->GetFont().Bold());
133             m_xSubDivisionEditor = new wxSpinCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER | wxALIGN_RIGHT);
134             m_xSubDivisionEditor->SetRange(1, 16);
135 
136             m_ySubDivisionEditor = new wxSpinCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER | wxALIGN_RIGHT);
137             m_ySubDivisionEditor->SetRange(1, 16);
138 
139             m_xSubDivisionEditor->Bind(wxEVT_SPINCTRL, &UVEditor::OnSubDivisionChanged, this);
140             m_ySubDivisionEditor->Bind(wxEVT_SPINCTRL, &UVEditor::OnSubDivisionChanged, this);
141 
142             wxSizer* bottomSizer = new wxBoxSizer(wxHORIZONTAL);
143             bottomSizer->Add(resetTextureButton,                   0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
144             bottomSizer->Add(flipTextureHButton,                   0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
145             bottomSizer->Add(flipTextureVButton,                   0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
146             bottomSizer->Add(rotateTextureCCWButton,               0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
147             bottomSizer->Add(rotateTextureCWButton,                0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
148             bottomSizer->AddStretchSpacer();
149             bottomSizer->Add(gridLabel,                              0, wxALIGN_CENTER_VERTICAL);
150             bottomSizer->Add(new wxStaticText(this, wxID_ANY, "X:"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
151             bottomSizer->Add(m_xSubDivisionEditor,                   0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::MediumHMargin);
152             bottomSizer->Add(new wxStaticText(this, wxID_ANY, "Y:"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, LayoutConstants::NarrowHMargin);
153             bottomSizer->Add(m_ySubDivisionEditor,                   0, wxALIGN_CENTER_VERTICAL);
154             bottomSizer->SetItemMinSize(m_xSubDivisionEditor, 50, m_xSubDivisionEditor->GetSize().y);
155             bottomSizer->SetItemMinSize(m_ySubDivisionEditor, 50, m_ySubDivisionEditor->GetSize().y);
156 
157             wxSizer* outerSizer = new wxBoxSizer(wxVERTICAL);
158             outerSizer->Add(m_uvView, 1, wxEXPAND);
159             outerSizer->AddSpacer(LayoutConstants::NarrowVMargin);
160             outerSizer->Add(bottomSizer, 0, wxLEFT | wxRIGHT | wxEXPAND, LayoutConstants::MediumHMargin);
161             outerSizer->AddSpacer(LayoutConstants::NarrowVMargin);
162 
163             SetBackgroundColour(*wxWHITE);
164             SetSizer(outerSizer);
165         }
166     }
167 }
168