8d7f93aeb32b6b5f4d0c17918023382848dd1ebf
[xonotic/netradiant.git] / radiant / preferences.h
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 /*
23    The following source code is licensed by Id Software and subject to the terms of
24    its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with
25    GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT,
26    please contact Id Software immediately at info@idsoftware.com.
27  */
28
29 #if !defined( INCLUDED_PREFERENCES_H )
30 #define INCLUDED_PREFERENCES_H
31
32 #include "libxml/parser.h"
33 #include "dialog.h"
34 #include <list>
35 #include <map>
36
37 void Widget_connectToggleDependency( ui::Widget self, ui::Widget toggleButton );
38
39 class PreferencesPage
40 {
41 Dialog& m_dialog;
42 ui::VBox m_vbox;
43 public:
44 PreferencesPage( Dialog& dialog, ui::VBox vbox ) : m_dialog( dialog ), m_vbox( vbox ){
45 }
46 ui::CheckButton appendCheckBox( const char* name, const char* flag, bool& data ){
47         return m_dialog.addCheckBox( m_vbox, name, flag, data );
48 }
49 ui::CheckButton appendCheckBox( const char* name, const char* flag, ImportExportCallback<bool> const &cb ){
50         return m_dialog.addCheckBox( m_vbox, name, flag, cb );
51 }
52 void appendCombo( const char* name, StringArrayRange values, ImportExportCallback<int> const &cb ){
53         m_dialog.addCombo( m_vbox, name, values, cb );
54 }
55 void appendCombo( const char* name, int& data, StringArrayRange values ){
56         m_dialog.addCombo( m_vbox, name, data, values );
57 }
58 void appendSlider( const char* name, int& data, gboolean draw_value, const char* low, const char* high, double value, double lower, double upper, double step_increment, double page_increment ){
59         m_dialog.addSlider( m_vbox, name, data, draw_value, low, high, value, lower, upper, step_increment, page_increment );
60 }
61 void appendRadio( const char* name, StringArrayRange names, ImportExportCallback<int> const &cb ){
62         m_dialog.addRadio( m_vbox, name, names, cb );
63 }
64 void appendRadio( const char* name, int& data, StringArrayRange names ){
65         m_dialog.addRadio( m_vbox, name, data, names );
66 }
67 void appendRadioIcons( const char* name, StringArrayRange icons, ImportExportCallback<int> const &cb ){
68         m_dialog.addRadioIcons( m_vbox, name, icons, cb );
69 }
70 void appendRadioIcons( const char* name, int& data, StringArrayRange icons ){
71         m_dialog.addRadioIcons( m_vbox, name, data, icons );
72 }
73 ui::Widget appendEntry( const char* name, ImportExportCallback<int> const &cb ){
74         return m_dialog.addIntEntry( m_vbox, name, cb );
75 }
76 ui::Widget appendEntry( const char* name, int& data ){
77         return m_dialog.addEntry( m_vbox, name, data );
78 }
79 ui::Widget appendEntry( const char* name, ImportExportCallback<std::size_t> const &cb){
80         return m_dialog.addSizeEntry( m_vbox, name, cb );
81 }
82 ui::Widget appendEntry( const char* name, std::size_t& data ){
83         return m_dialog.addEntry( m_vbox, name, data );
84 }
85 ui::Widget appendEntry( const char* name, ImportExportCallback<float> const &cb ){
86         return m_dialog.addFloatEntry( m_vbox, name, cb );
87 }
88 ui::Widget appendEntry( const char* name, float& data ){
89         return m_dialog.addEntry( m_vbox, name, data );
90 }
91 ui::Widget appendPathEntry( const char* name, bool browse_directory, ImportExportCallback<const char *> const &cb ){
92         return m_dialog.addPathEntry( m_vbox, name, browse_directory, cb );
93 }
94 ui::Widget appendPathEntry( const char* name, CopiedString& data, bool directory ){
95         return m_dialog.addPathEntry( m_vbox, name, data, directory );
96 }
97 ui::SpinButton appendSpinner( const char* name, int& data, double value, double lower, double upper ){
98         return m_dialog.addSpinner( m_vbox, name, data, value, lower, upper );
99 }
100 ui::SpinButton appendSpinner( const char* name, double value, double lower, double upper, ImportExportCallback<int> const &cb ){
101         return m_dialog.addSpinner( m_vbox, name, value, lower, upper, cb );
102 }
103 ui::SpinButton appendSpinner( const char* name, double value, double lower, double upper, ImportExportCallback<float> const &cb ){
104         return m_dialog.addSpinner( m_vbox, name, value, lower, upper, cb );
105 }
106 };
107
108 typedef Callback<void(PreferencesPage&)> PreferencesPageCallback;
109
110 class PreferenceGroup
111 {
112 public:
113 virtual PreferencesPage createPage( const char* treeName, const char* frameName ) = 0;
114 };
115
116 typedef Callback<void(PreferenceGroup&)> PreferenceGroupCallback;
117
118 void PreferencesDialog_addInterfacePreferences( const PreferencesPageCallback& callback );
119 void PreferencesDialog_addInterfacePage( const PreferenceGroupCallback& callback );
120 void PreferencesDialog_addDisplayPreferences( const PreferencesPageCallback& callback );
121 void PreferencesDialog_addDisplayPage( const PreferenceGroupCallback& callback );
122 void PreferencesDialog_addSettingsPreferences( const PreferencesPageCallback& callback );
123 void PreferencesDialog_addSettingsPage( const PreferenceGroupCallback& callback );
124
125 void PreferencesDialog_restartRequired( const char* staticName );
126
127 template<typename Value>
128 class LatchedValue {
129 public:
130     Value m_value;
131     Value m_latched;
132     const char *m_description;
133
134     LatchedValue(Value value, const char *description) : m_latched(value), m_description(description) {
135     }
136
137     void useLatched() {
138         m_value = m_latched;
139     }
140
141     void import(Value value) {
142         m_latched = value;
143         if (m_latched != m_value) {
144             PreferencesDialog_restartRequired(m_description);
145         }
146     }
147 };
148
149 template<class Self, class T = Self>
150 ImportExportCallback<T> mkImportExportCallback(LatchedValue<Self> &self) {
151         return {
152                         MemberCaller<LatchedValue<Self>, void(T), &LatchedValue<Self>::import>(self),
153                         ReferenceCaller<Self, void(const Callback<void(T)> &), impexp<Self, T>::Export>(self.m_latched)
154         };
155 }
156
157 /*!
158    holds information for a given game
159    I'm a bit unclear on that still
160    it holds game specific configuration stuff
161    such as base names, engine names, some game specific features to activate in the various modules
162    it is not strictly a prefs thing since the user is not supposed to edit that (unless he is hacking
163    support for a new game)
164
165    what we do now is fully generate the information for this during the setup. We might want to
166    generate a piece that just says "the game pack is there", but put the rest of the config somwhere
167    else (i.e. not generated, copied over during setup .. for instance in the game tools directory)
168  */
169 class CGameDescription
170 {
171 typedef std::map<CopiedString, CopiedString> GameDescription;
172
173 public:
174 CopiedString mGameFile;   ///< the .game file that describes this game
175 GameDescription m_gameDescription;
176
177 CopiedString mGameToolsPath;   ///< the explicit path to the game-dependent modules
178 CopiedString mGameType;   ///< the type of the engine
179
180 const char* getKeyValue( const char* key ) const {
181         GameDescription::const_iterator i = m_gameDescription.find( key );
182         if ( i != m_gameDescription.end() ) {
183                 return ( *i ).second.c_str();
184         }
185         return "";
186 }
187 const char* getRequiredKeyValue( const char* key ) const {
188         GameDescription::const_iterator i = m_gameDescription.find( key );
189         if ( i != m_gameDescription.end() ) {
190                 return ( *i ).second.c_str();
191         }
192         ERROR_MESSAGE( "game attribute " << makeQuoted( key ) << " not found in " << makeQuoted( mGameFile.c_str() ) );
193         return "";
194 }
195
196 CGameDescription( xmlDocPtr pDoc, const CopiedString &GameFile );
197
198 void Dump();
199 };
200
201 extern CGameDescription *g_pGameDescription;
202
203 class PrefsDlg;
204
205 class PreferencesPage;
206
207 class StringOutputStream;
208
209 /*!
210    standalone dialog for games selection, and more generally global settings
211  */
212 class CGameDialog : public Dialog
213 {
214 protected:
215
216 mutable int m_nComboSelect;   ///< intermediate int value for combo in dialog box
217
218 public:
219
220 /*!
221    those settings are saved in the global prefs file
222    I'm too lazy to wrap behind protected access, not sure this needs to be public
223    NOTE: those are preference settings. if you change them it is likely that you would
224    have to restart the editor for them to take effect
225  */
226 /*@{*/
227 /*!
228    what game has been selected
229    this is the name of the .game file
230  */
231 CopiedString m_sGameFile;
232 /*!
233    prompt which game to load on startup
234  */
235 bool m_bGamePrompt;
236 /*!
237    log console to radiant.log
238    m_bForceLogConsole is an obscure forced latching situation
239  */
240 bool m_bForceLogConsole;
241 /*@}*/
242
243 /*!
244    the list of game descriptions we scanned from the game/ dir
245  */
246 std::list<CGameDescription*> mGames;
247
248 CGameDialog() :
249         m_sGameFile( "" ),
250         m_bGamePrompt( true ),
251         m_bForceLogConsole( false ){
252 }
253 virtual ~CGameDialog();
254
255 /*!
256    intialize the game dialog, called at CPrefsDlg::Init
257    will scan for games, load prefs, and do game selection dialog if needed
258  */
259 void Init();
260
261 /*!
262    reset the global settings by removing the file
263  */
264 void Reset();
265
266 /*!
267    run the dialog UI for the list of games
268  */
269 void DoGameDialog();
270
271 /*!
272    Dialog API
273    this is only called when the dialog is built at startup for main engine select
274  */
275 ui::Window BuildDialog();
276
277 void GameFileImport( int value );
278 void GameFileExport( const ImportExportCallback<int>::Import_t& importCallback ) const;
279
280 /*!
281    construction of the dialog frame
282    this is the part to be re-used in prefs dialog
283    for the standalone dialog, we include this in a modal box
284    for prefs, we hook the frame in the main notebook
285    build the frame on-demand (only once)
286  */
287 void CreateGlobalFrame( PreferencesPage& page );
288
289 /*!
290    global preferences subsystem
291    XML-based this time, hopefully this will generalize to other prefs
292    LoadPrefs has hardcoded defaults
293    NOTE: it may not be strictly 'CGameDialog' to put the global prefs here
294    could have named the class differently I guess
295  */
296 /*@{*/
297 void LoadPrefs();   ///< load from file into variables
298 void SavePrefs();   ///< save pref variables to file
299 /*@}*/
300
301 private:
302 /*!
303    scan for .game files, load them
304  */
305 void ScanForGames();
306
307 /*!
308    inits g_Preferences.m_global_rc_path
309  */
310 void InitGlobalPrefPath();
311
312 /*!
313    uses m_nComboItem to find the right mGames
314  */
315 CGameDescription *GameDescriptionForComboItem();
316 };
317
318 /*!
319    this holds global level preferences
320  */
321 extern CGameDialog g_GamesDialog;
322
323
324 class texdef_t;
325
326 class PrefsDlg : public Dialog
327 {
328 public:
329 protected:
330 std::list<CGameDescription *> mGames;
331
332 public:
333
334 ui::Widget m_notebook{ui::null};
335
336 virtual ~PrefsDlg(){
337         g_string_free( m_rc_path, true );
338         g_string_free( m_inipath, true );
339 }
340
341 /*!
342    path for global settings
343    win32: AppPath
344    linux: ~/.radiant/[version]/
345  */
346 GString *m_global_rc_path;
347
348 /*!
349    path to per-game settings
350    used for various game dependant storage
351    win32: GameToolsPath
352    linux: ~/.radiant/[version]/[gamename]/
353  */
354 GString *m_rc_path;
355
356 /*!
357    holds per-game settings
358    m_rc_path+"local.pref"
359    \todo FIXME at some point this should become XML property bag code too
360  */
361 GString *m_inipath;
362
363 // initialize the above paths
364 void Init();
365
366 /*! Utility function for swapping notebook pages for tree list selections */
367 void showPrefPage( ui::Widget prefpage );
368
369 protected:
370
371 /*! Dialog API */
372 ui::Window BuildDialog();
373 void PostModal( EMessageBoxReturn code );
374 };
375
376 extern PrefsDlg g_Preferences;
377
378 struct preferences_globals_t
379 {
380         // disabled all INI / registry read write .. used when shutting down after registry cleanup
381         bool disable_ini;
382         preferences_globals_t() : disable_ini( false ){
383         }
384 };
385 extern preferences_globals_t g_preferences_globals;
386
387 void PreferencesDialog_constructWindow( ui::Window main_window );
388 void PreferencesDialog_destroyWindow();
389
390 void PreferencesDialog_showDialog();
391
392 void GlobalPreferences_Init();
393 void Preferences_Init();
394
395 void Preferences_Load();
396 void Preferences_Save();
397
398 void Preferences_Reset();
399
400
401 #endif