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 "PreferenceDialog.h" 21 22 #include "PreferenceManager.h" 23 #include "Preferences.h" 24 #include "IO/Path.h" 25 #include "IO/ResourceUtils.h" 26 #include "View/BorderLine.h" 27 #include "View/GamesPreferencePane.h" 28 #include "View/KeyboardPreferencePane.h" 29 #include "View/MousePreferencePane.h" 30 #include "View/ViewPreferencePane.h" 31 #include "View/ViewConstants.h" 32 #include "View/PreferencePane.h" 33 #include "View/wxUtils.h" 34 35 #include <wx/button.h> 36 #include <wx/panel.h> 37 #include <wx/sizer.h> 38 #include <wx/simplebook.h> 39 #include <wx/stdpaths.h> 40 #include <wx/toolbar.h> 41 42 namespace TrenchBroom { 43 namespace View { IMPLEMENT_DYNAMIC_CLASS(PreferenceDialog,wxDialog)44 IMPLEMENT_DYNAMIC_CLASS(PreferenceDialog, wxDialog) 45 46 PreferenceDialog::PreferenceDialog() : 47 m_toolBar(NULL), 48 m_book(NULL) { 49 Create(); 50 } 51 Create()52 bool PreferenceDialog::Create() { 53 if (!wxDialog::Create(NULL, wxID_ANY, "Preferences")) 54 return false; 55 56 createGui(); 57 bindEvents(); 58 switchToPane(PrefPane_First); 59 currentPane()->updateControls(); 60 SetClientSize(currentPane()->GetMinSize()); 61 62 return true; 63 } 64 OnToolClicked(wxCommandEvent & event)65 void PreferenceDialog::OnToolClicked(wxCommandEvent& event) { 66 if (IsBeingDeleted()) return; 67 68 const PrefPane newPane = static_cast<PrefPane>(event.GetId()); 69 switchToPane(newPane); 70 } 71 OnOKClicked(wxCommandEvent & event)72 void PreferenceDialog::OnOKClicked(wxCommandEvent& event) { 73 if (IsBeingDeleted()) return; 74 75 if (!currentPane()->validate()) 76 return; 77 78 PreferenceManager& prefs = PreferenceManager::instance(); 79 if (!prefs.saveInstantly()) 80 prefs.saveChanges(); 81 EndModal(wxID_OK); 82 } 83 OnApplyClicked(wxCommandEvent & event)84 void PreferenceDialog::OnApplyClicked(wxCommandEvent& event) { 85 if (IsBeingDeleted()) return; 86 87 if (!currentPane()->validate()) 88 return; 89 90 PreferenceManager& prefs = PreferenceManager::instance(); 91 if (!prefs.saveInstantly()) 92 prefs.saveChanges(); 93 } 94 OnCancelClicked(wxCommandEvent & event)95 void PreferenceDialog::OnCancelClicked(wxCommandEvent& event) { 96 if (IsBeingDeleted()) return; 97 98 PreferenceManager& prefs = PreferenceManager::instance(); 99 if (!prefs.saveInstantly()) 100 prefs.discardChanges(); 101 EndModal(wxID_CANCEL); 102 } 103 OnClose(wxCloseEvent & event)104 void PreferenceDialog::OnClose(wxCloseEvent& event) { 105 if (IsBeingDeleted()) return; 106 107 if (!currentPane()->validate() && event.CanVeto()) { 108 event.Veto(); 109 return; 110 } 111 112 PreferenceManager& prefs = PreferenceManager::instance(); 113 if (!prefs.saveInstantly()) { 114 switch (event.GetId()) { 115 case wxID_OK: 116 prefs.saveChanges(); 117 break; 118 default: 119 prefs.discardChanges(); 120 break; 121 122 } 123 } 124 } 125 OnFileClose(wxCommandEvent & event)126 void PreferenceDialog::OnFileClose(wxCommandEvent& event) { 127 if (IsBeingDeleted()) return; 128 129 if (!currentPane()->validate()) { 130 event.Skip(); 131 return; 132 } 133 134 PreferenceManager& prefs = PreferenceManager::instance(); 135 prefs.discardChanges(); // does nothing if the preferences save changes instantly 136 Close(); 137 } 138 OnResetClicked(wxCommandEvent & event)139 void PreferenceDialog::OnResetClicked(wxCommandEvent& event) { 140 if (IsBeingDeleted()) return; 141 142 assert(currentPane()->canResetToDefaults()); 143 currentPane()->resetToDefaults(); 144 } 145 OnUpdateReset(wxUpdateUIEvent & event)146 void PreferenceDialog::OnUpdateReset(wxUpdateUIEvent& event) { 147 if (IsBeingDeleted()) return; 148 149 event.Enable(currentPane()->canResetToDefaults()); 150 } 151 createGui()152 void PreferenceDialog::createGui() { 153 SetIcon(wxIcon(wxStandardPaths::Get().GetInstallPrefix() + "/share/icons/hicolor/128x128/apps/trenchbroom.png", wxBITMAP_TYPE_PNG)); 154 155 const wxBitmap gamesImage = IO::loadImageResource("GeneralPreferences.png"); 156 const wxBitmap generalImage = IO::loadImageResource("GeneralPreferences.png"); 157 const wxBitmap mouseImage = IO::loadImageResource("MousePreferences.png"); 158 const wxBitmap keyboardImage = IO::loadImageResource("KeyboardPreferences.png"); 159 160 m_toolBar = new wxToolBar(this, wxID_ANY); 161 m_toolBar->AddCheckTool(PrefPane_Games, "Games", gamesImage, wxNullBitmap); 162 m_toolBar->AddCheckTool(PrefPane_View, "View", generalImage, wxNullBitmap); 163 m_toolBar->AddCheckTool(PrefPane_Mouse, "Mouse", mouseImage, wxNullBitmap); 164 m_toolBar->AddCheckTool(PrefPane_Keyboard, "Keyboard", keyboardImage, wxNullBitmap); 165 m_toolBar->Realize(); 166 167 m_book = new wxSimplebook(this); 168 m_book->AddPage(new GamesPreferencePane(m_book), "Games"); 169 m_book->AddPage(new ViewPreferencePane(m_book), "View"); 170 m_book->AddPage(new MousePreferencePane(m_book), "Mouse"); 171 m_book->AddPage(new KeyboardPreferencePane(m_book), "Keyboard"); 172 173 wxButton* resetButton = new wxButton(this, wxID_ANY, "Reset to defaults"); 174 resetButton->Bind(wxEVT_BUTTON, &PreferenceDialog::OnResetClicked, this); 175 resetButton->Bind(wxEVT_UPDATE_UI, &PreferenceDialog::OnUpdateReset, this); 176 177 wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); 178 sizer->Add(m_toolBar, 0, wxEXPAND); 179 #if !defined __APPLE__ 180 wxWindow* line = new BorderLine(this, BorderLine::Direction_Horizontal); 181 sizer->Add(line, 0, wxEXPAND); 182 sizer->SetItemMinSize(line, wxSize(wxDefaultCoord, 1)); 183 #endif 184 sizer->Add(m_book, 1, wxEXPAND); 185 186 wxSizer* bottomSizer = new wxBoxSizer(wxHORIZONTAL); 187 #if !defined __APPLE__ 188 bottomSizer->Add(resetButton, 0, wxALIGN_CENTER_VERTICAL); 189 bottomSizer->AddStretchSpacer(); 190 bottomSizer->Add(CreateButtonSizer(wxOK | wxAPPLY | wxCANCEL)); 191 #else 192 bottomSizer->Add(resetButton, 0, wxALL, LayoutConstants::DialogOuterMargin); 193 bottomSizer->AddStretchSpacer(); 194 #endif 195 196 sizer->Add(wrapDialogButtonSizer(bottomSizer, this), 0, wxEXPAND); 197 198 SetSizer(sizer); 199 } 200 bindEvents()201 void PreferenceDialog::bindEvents() { 202 Bind(wxEVT_MENU, &PreferenceDialog::OnFileClose, this, wxID_CLOSE); 203 Bind(wxEVT_BUTTON, &PreferenceDialog::OnOKClicked, this, wxID_OK); 204 Bind(wxEVT_BUTTON, &PreferenceDialog::OnApplyClicked, this, wxID_APPLY); 205 Bind(wxEVT_BUTTON, &PreferenceDialog::OnCancelClicked, this, wxID_CANCEL); 206 Bind(wxEVT_TOOL, &PreferenceDialog::OnToolClicked, this, PrefPane_First, PrefPane_Last); 207 } 208 switchToPane(const PrefPane pane)209 void PreferenceDialog::switchToPane(const PrefPane pane) { 210 if (currentPaneId() == pane && currentPane() != NULL) { 211 toggleTools(currentPaneId()); 212 return; 213 } 214 215 if (currentPane() != NULL && !currentPane()->validate()) { 216 toggleTools(currentPaneId()); 217 return; 218 } 219 220 toggleTools(pane); 221 m_book->SetSelection(static_cast<size_t>(pane)); 222 currentPane()->updateControls(); 223 224 GetSizer()->SetItemMinSize(m_book, currentPane()->GetMinSize()); 225 Fit(); 226 #if defined __APPLE__ 227 updateAcceleratorTable(pane); 228 #endif 229 } 230 toggleTools(const PrefPane pane)231 void PreferenceDialog::toggleTools(const PrefPane pane) { 232 for (int i = PrefPane_First; i <= PrefPane_Last; ++i) 233 m_toolBar->ToggleTool(i, pane == i); 234 } 235 currentPane() const236 PreferencePane* PreferenceDialog::currentPane() const { 237 return static_cast<PreferencePane*>(m_book->GetCurrentPage()); 238 } 239 currentPaneId() const240 PreferenceDialog::PrefPane PreferenceDialog::currentPaneId() const { 241 return static_cast<PrefPane>(m_book->GetSelection()); 242 } 243 updateAcceleratorTable(const PrefPane pane)244 void PreferenceDialog::updateAcceleratorTable(const PrefPane pane) { 245 // allow the dialog to be closed using CMD+W 246 // but only if the keyboard preference pane is not active 247 if (pane != PrefPane_Keyboard) { 248 wxAcceleratorEntry acceleratorEntries[1]; 249 acceleratorEntries[0].Set(wxACCEL_CMD, static_cast<int>('W'), wxID_CLOSE); 250 wxAcceleratorTable accceleratorTable(1, acceleratorEntries); 251 SetAcceleratorTable(accceleratorTable); 252 } else { 253 wxAcceleratorTable accceleratorTable(0, NULL); 254 SetAcceleratorTable(accceleratorTable); 255 } 256 } 257 } 258 } 259