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