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