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