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 "FlagsEditor.h" 21 22 #include "View/FlagChangedCommand.h" 23 #include "View/ViewConstants.h" 24 25 #include <cassert> 26 #include <wx/checkbox.h> 27 #include <wx/sizer.h> 28 29 namespace TrenchBroom { 30 namespace View { FlagsEditor(wxWindow * parent,const size_t numCols)31 FlagsEditor::FlagsEditor(wxWindow* parent, const size_t numCols) : 32 wxPanel(parent), 33 m_numCols(numCols) { 34 assert(m_numCols > 0); 35 } 36 setFlags(const wxArrayString & labels,const wxArrayString & tooltips)37 void FlagsEditor::setFlags(const wxArrayString& labels, const wxArrayString& tooltips) { 38 wxArrayInt values(labels.size()); 39 for (size_t i = 0; i < labels.size(); ++i) 40 values[i] = (1 << i); 41 setFlags(values, labels, tooltips); 42 } 43 setFlags(const wxArrayInt & values,const wxArrayString & labels,const wxArrayString & tooltips)44 void FlagsEditor::setFlags(const wxArrayInt& values, const wxArrayString& labels, const wxArrayString& tooltips) { 45 const size_t count = values.size(); 46 setCheckBoxCount(count); 47 48 const size_t numRows = count / m_numCols; 49 wxFlexGridSizer* sizer = new wxFlexGridSizer(static_cast<int>(numRows), 50 static_cast<int>(m_numCols), 51 0, LayoutConstants::WideHMargin); 52 53 for (size_t row = 0; row < numRows; ++row) { 54 for (size_t col = 0; col < m_numCols; ++col) { 55 const size_t index = col * numRows + row; 56 if (index < count) { 57 m_checkBoxes[index]->SetLabel(index < labels.size() ? labels[index] : wxString() << (1 << index)); 58 m_checkBoxes[index]->SetToolTip(index < tooltips.size() ? tooltips[index] : ""); 59 m_values[index] = values[index]; 60 sizer->Add(m_checkBoxes[index]); 61 } 62 } 63 } 64 65 SetSizerAndFit(sizer); 66 } 67 setFlagValue(const int on,const int mixed)68 void FlagsEditor::setFlagValue(const int on, const int mixed) { 69 for (size_t i = 0; i < m_checkBoxes.size(); ++i) { 70 wxCheckBox* checkBox = m_checkBoxes[i]; 71 const int value = m_values[i]; 72 const bool isMixed = (mixed & value) != 0; 73 const bool isChecked = (on & value) != 0; 74 if (isMixed) 75 checkBox->Set3StateValue(wxCHK_UNDETERMINED); 76 else if (isChecked) 77 checkBox->Set3StateValue(wxCHK_CHECKED); 78 else 79 checkBox->Set3StateValue(wxCHK_UNCHECKED); 80 } 81 } 82 getNumFlags() const83 size_t FlagsEditor::getNumFlags() const { 84 return m_checkBoxes.size(); 85 } 86 isFlagSet(const size_t index) const87 bool FlagsEditor::isFlagSet(const size_t index) const { 88 assert(index < m_checkBoxes.size()); 89 return m_checkBoxes[index]->Get3StateValue() == wxCHK_CHECKED; 90 } 91 isFlagMixed(const size_t index) const92 bool FlagsEditor::isFlagMixed(const size_t index) const { 93 assert(index < m_checkBoxes.size()); 94 return m_checkBoxes[index]->Get3StateValue() == wxCHK_UNDETERMINED; 95 } 96 getSetFlagValue() const97 int FlagsEditor::getSetFlagValue() const { 98 int value = 0; 99 for (size_t i = 0; i < m_checkBoxes.size(); ++i) { 100 if (isFlagSet(i)) 101 value |= m_values[i]; 102 } 103 return value; 104 } 105 getMixedFlagValue() const106 int FlagsEditor::getMixedFlagValue() const { 107 int value = 0; 108 for (size_t i = 0; i < m_checkBoxes.size(); ++i) { 109 if (isFlagMixed(i)) 110 value |= m_values[i]; 111 } 112 return value; 113 } 114 getFlagLabel(const size_t index) const115 wxString FlagsEditor::getFlagLabel(const size_t index) const { 116 assert(index < m_checkBoxes.size()); 117 return m_checkBoxes[index]->GetLabel(); 118 } 119 lineHeight() const120 int FlagsEditor::lineHeight() const { 121 assert(!m_checkBoxes.empty()); 122 return m_checkBoxes.front()->GetSize().y; 123 } 124 OnCheckBoxClicked(wxCommandEvent & event)125 void FlagsEditor::OnCheckBoxClicked(wxCommandEvent& event) { 126 if (IsBeingDeleted()) return; 127 128 const size_t index = getIndexFromEvent(event); 129 assert(index < m_checkBoxes.size()); 130 131 FlagChangedCommand command; 132 command.setValues(index, getSetFlagValue(), getMixedFlagValue()); 133 command.SetEventObject(this); 134 command.SetId(GetId()); 135 ProcessEvent(command); 136 } 137 setCheckBoxCount(const size_t count)138 void FlagsEditor::setCheckBoxCount(const size_t count) { 139 while (count > m_checkBoxes.size()) { 140 wxCheckBox* checkBox = new wxCheckBox(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxCHK_3STATE); 141 checkBox->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &FlagsEditor::OnCheckBoxClicked, this); 142 m_checkBoxes.push_back(checkBox); 143 } 144 while (count < m_checkBoxes.size()) 145 delete m_checkBoxes.back(), m_checkBoxes.pop_back(); 146 m_values.resize(count); 147 } 148 getIndexFromEvent(const wxCommandEvent & event) const149 size_t FlagsEditor::getIndexFromEvent(const wxCommandEvent& event) const { 150 for (size_t i = 0; i < m_checkBoxes.size(); ++i) 151 if (event.GetEventObject() == m_checkBoxes[i]) 152 return i; 153 return m_checkBoxes.size(); 154 } 155 } 156 } 157