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