2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
25 // Leonardo Zide (leo@lokigames.com)
28 #include "preferences.h"
29 #include "globaldefs.h"
32 #include "environment.h"
34 #include "debugging/debugging.h"
36 #include "generic/callback.h"
37 #include "math/vector.h"
38 #include "string/string.h"
39 #include "stream/stringstream.h"
43 #include "gtkutil/filechooser.h"
44 #include "gtkutil/messagebox.h"
50 #include "mainframe.h"
56 void Global_constructPreferences( PreferencesPage& page ){
57 page.appendCheckBox( "Console", "Enable Logging", g_Console_enableLogging );
60 void Interface_constructPreferences( PreferencesPage& page ){
62 page.appendCheckBox( "", "Default Text Editor", g_TextEditor_useWin32Editor );
65 ui::CheckButton use_custom = page.appendCheckBox( "Text Editor", "Custom", g_TextEditor_useCustomEditor );
66 ui::Widget custom_editor = page.appendPathEntry( "Text Editor Command", g_TextEditor_editorCommand, true );
67 Widget_connectToggleDependency( custom_editor, use_custom );
72 void Mouse_constructPreferences( PreferencesPage& page ){
74 const char* buttons[] = { "2 button", "3 button", };
75 page.appendRadio( "Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE( buttons ) );
77 page.appendCheckBox( "Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick );
79 void Mouse_constructPage( PreferenceGroup& group ){
80 PreferencesPage page( group.createPage( "Mouse", "Mouse Preferences" ) );
81 Mouse_constructPreferences( page );
83 void Mouse_registerPreferencesPage(){
84 PreferencesDialog_addInterfacePage( makeCallbackF(Mouse_constructPage) );
89 =========================================================
90 Games selection dialog
91 =========================================================
95 #include <uilib/uilib.h>
97 inline const char* xmlAttr_getName( xmlAttrPtr attr ){
98 return reinterpret_cast<const char*>( attr->name );
101 inline const char* xmlAttr_getValue( xmlAttrPtr attr ){
102 return reinterpret_cast<const char*>( attr->children->content );
105 CGameDescription::CGameDescription( xmlDocPtr pDoc, const CopiedString& gameFile ){
106 // read the user-friendly game name
107 xmlNodePtr pNode = pDoc->children;
109 while ( strcmp( (const char*)pNode->name, "game" ) && pNode != 0 )
114 Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL );
117 for ( xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next )
119 m_gameDescription.insert( GameDescription::value_type( xmlAttr_getName( attr ), xmlAttr_getValue( attr ) ) );
123 StringOutputStream path( 256 );
124 path << AppPath_get() << gameFile.c_str() << "/";
125 mGameToolsPath = path.c_str();
128 ASSERT_MESSAGE( file_exists( mGameToolsPath.c_str() ), "game directory not found: " << makeQuoted( mGameToolsPath.c_str() ) );
130 mGameFile = gameFile;
133 GameDescription::iterator i = m_gameDescription.find( "type" );
134 if ( i == m_gameDescription.end() ) {
135 globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>( pDoc->URL ) << "'\n";
141 mGameType = ( *i ).second.c_str();
146 void CGameDescription::Dump(){
147 globalOutputStream() << "game description file: " << makeQuoted( mGameFile.c_str() ) << "\n";
148 for ( GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i )
150 globalOutputStream() << ( *i ).first.c_str() << " = " << makeQuoted( ( *i ).second.c_str() ) << "\n";
154 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
157 #include "warnings.h"
158 #include "stream/textfilestream.h"
159 #include "container/array.h"
160 #include "xml/ixml.h"
161 #include "xml/xmlparser.h"
162 #include "xml/xmlwriter.h"
164 #include "preferencedictionary.h"
165 #include "stringio.h"
167 const char* const PREFERENCES_VERSION = "1.0";
169 bool Preferences_Load( PreferenceDictionary& preferences, const char* filename, const char *cmdline_prefix ){
171 TextFileInputStream file( filename );
172 if ( !file.failed() ) {
173 XMLStreamParser parser( file );
174 XMLPreferenceDictionaryImporter importer( preferences, PREFERENCES_VERSION );
175 parser.exportXML( importer );
179 int l = strlen( cmdline_prefix );
180 for ( int i = 1; i < g_argc - 1; ++i )
182 if ( g_argv[i][0] == '-' ) {
183 if ( !strncmp( g_argv[i] + 1, cmdline_prefix, l ) ) {
184 if ( g_argv[i][l + 1] == '-' ) {
185 preferences.importPref( g_argv[i] + l + 2, g_argv[i + 1] );
195 bool Preferences_Save( PreferenceDictionary& preferences, const char* filename ){
196 TextFileOutputStream file( filename );
197 if ( !file.failed() ) {
198 XMLStreamWriter writer( file );
199 XMLPreferenceDictionaryExporter exporter( preferences, PREFERENCES_VERSION );
200 exporter.exportXML( writer );
206 bool Preferences_Save_Safe( PreferenceDictionary& preferences, const char* filename ){
207 Array<char> tmpName( filename, filename + strlen( filename ) + 1 + 3 );
208 *( tmpName.end() - 4 ) = 'T';
209 *( tmpName.end() - 3 ) = 'M';
210 *( tmpName.end() - 2 ) = 'P';
211 *( tmpName.end() - 1 ) = '\0';
213 return Preferences_Save( preferences, tmpName.data() )
214 && ( !file_exists( filename ) || file_remove( filename ) )
215 && file_move( tmpName.data(), filename );
220 static void Export(const Callback<void(bool)> &returnz) {
221 returnz(g_Console_enableLogging);
224 static void Import(bool value) {
225 g_Console_enableLogging = value;
226 Sys_LogFile(g_Console_enableLogging);
231 void RegisterGlobalPreferences( PreferenceSystem& preferences ){
232 preferences.registerPreference( "gamefile", make_property_string( g_GamesDialog.m_sGameFile ) );
233 preferences.registerPreference( "gamePrompt", make_property_string( g_GamesDialog.m_bGamePrompt ) );
234 preferences.registerPreference( "log console", make_property_string<LogConsole>() );
238 PreferenceDictionary g_global_preferences;
240 void GlobalPreferences_Init(){
241 RegisterGlobalPreferences( g_global_preferences );
244 void CGameDialog::LoadPrefs(){
245 // load global .pref file
246 StringOutputStream strGlobalPref( 256 );
247 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
249 globalOutputStream() << "loading global preferences from " << makeQuoted( strGlobalPref.c_str() ) << "\n";
251 if ( !Preferences_Load( g_global_preferences, strGlobalPref.c_str(), "global" ) ) {
252 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
256 void CGameDialog::SavePrefs(){
257 StringOutputStream strGlobalPref( 256 );
258 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
260 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
262 if ( !Preferences_Save_Safe( g_global_preferences, strGlobalPref.c_str() ) ) {
263 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
267 void CGameDialog::DoGameDialog(){
271 // we save the prefs file
275 void CGameDialog::GameFileImport( int value ){
276 m_nComboSelect = value;
277 // use value to set m_sGameFile
278 std::list<CGameDescription *>::iterator iGame = mGames.begin();
280 for ( i = 0; i < value; i++ )
284 m_sGameFile = ( *iGame )->mGameFile;
287 void CGameDialog::GameFileExport( const Callback<void(int)> & importCallback ) const {
288 // use m_sGameFile to set value
289 std::list<CGameDescription *>::const_iterator iGame;
291 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
293 if ( ( *iGame )->mGameFile == m_sGameFile ) {
299 importCallback( m_nComboSelect );
302 struct CGameDialog_GameFile {
303 static void Export(const CGameDialog &self, const Callback<void(int)> &returnz) {
304 self.GameFileExport(returnz);
307 static void Import(CGameDialog &self, int value) {
308 self.GameFileImport(value);
312 void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){
313 std::vector<const char*> games;
314 games.reserve( mGames.size() );
315 for ( std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i )
317 games.push_back( ( *i )->getRequiredKeyValue( "name" ) );
321 StringArrayRange( &( *games.begin() ), &( *games.end() ) ),
322 make_property<CGameDialog_GameFile>(*this)
324 page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt );
327 ui::Window CGameDialog::BuildDialog(){
328 auto frame = create_dialog_frame( "Game settings", ui::Shadow::ETCHED_IN );
330 auto vbox2 = create_dialog_vbox( 0, 4 );
334 PreferencesPage preferencesPage( *this, vbox2 );
335 Global_constructPreferences( preferencesPage );
336 CreateGlobalFrame( preferencesPage );
339 return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame );
342 void CGameDialog::ScanForGames(){
343 StringOutputStream strGamesPath( 256 );
344 strGamesPath << AppPath_get() << "games/";
345 const char *path = strGamesPath.c_str();
347 globalOutputStream() << "Scanning for game description files: " << path << '\n';
351 do we put game description files below AppPath, or in ~/.radiant
352 i.e. read only or read/write?
353 my guess .. readonly cause it's an install
354 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
355 (if that's really needed)
358 Directory_forEach(path, [&](const char *name) {
359 if (!extension_equal(path_get_extension(name), "game")) {
362 StringOutputStream strPath(256);
363 strPath << path << name;
364 globalOutputStream() << strPath.c_str() << '\n';
366 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
368 mGames.push_front(new CGameDescription(pDoc, name));
371 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
376 CGameDescription* CGameDialog::GameDescriptionForComboItem(){
377 std::list<CGameDescription *>::iterator iGame;
379 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame,i++ )
381 if ( i == m_nComboSelect ) {
385 return 0; // not found
388 void CGameDialog::InitGlobalPrefPath(){
389 g_Preferences.m_global_rc_path = g_string_new( SettingsPath_get() );
392 void CGameDialog::Reset(){
393 if ( !g_Preferences.m_global_rc_path ) {
394 InitGlobalPrefPath();
396 StringOutputStream strGlobalPref( 256 );
397 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
398 file_remove( strGlobalPref.c_str() );
401 void CGameDialog::Init(){
402 InitGlobalPrefPath();
405 if ( mGames.empty() ) {
406 Error( "Didn't find any valid game file descriptions, aborting\n" );
410 std::list<CGameDescription *>::iterator iGame, iPrevGame;
411 for ( iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame )
413 if ( iPrevGame != mGames.end() ) {
414 if ( strcmp( ( *iGame )->getRequiredKeyValue( "name" ), ( *iPrevGame )->getRequiredKeyValue( "name" ) ) < 0 ) {
415 CGameDescription *h = *iGame;
423 CGameDescription* currentGameDescription = 0;
425 if ( !m_bGamePrompt ) {
426 // search by .game name
427 std::list<CGameDescription *>::iterator iGame;
428 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
430 if ( ( *iGame )->mGameFile == m_sGameFile ) {
431 currentGameDescription = ( *iGame );
436 if ( m_bGamePrompt || !currentGameDescription ) {
439 // use m_nComboSelect to identify the game to run as and set the globals
440 currentGameDescription = GameDescriptionForComboItem();
441 ASSERT_NOTNULL( currentGameDescription );
443 g_pGameDescription = currentGameDescription;
445 g_pGameDescription->Dump();
448 CGameDialog::~CGameDialog(){
449 // free all the game descriptions
450 std::list<CGameDescription *>::iterator iGame;
451 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
461 inline const char* GameDescription_getIdentifier( const CGameDescription& gameDescription ){
462 const char* identifier = gameDescription.getKeyValue( "index" );
463 if ( string_empty( identifier ) ) {
470 CGameDialog g_GamesDialog;
473 // =============================================================================
474 // Widget callbacks for PrefsDlg
476 static void OnButtonClean( ui::Widget widget, gpointer data ){
477 // make sure this is what the user wants
478 if ( ui::alert( g_Preferences.GetWidget(), "This will close Radiant and clean the corresponding registry entries.\n"
479 "Next time you start Radiant it will be good as new. Do you wish to continue?",
480 "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) {
481 PrefsDlg *dlg = (PrefsDlg*)data;
482 dlg->EndModal( eIDCANCEL );
484 g_preferences_globals.disable_ini = true;
490 // =============================================================================
496 very first prefs init deals with selecting the game and the game tools path
497 then we can load .ini stuff
499 using prefs / ini settings:
502 look in ~/.radiant/<version>/gamename
506 const char *PREFS_LOCAL_FILENAME = "local.pref";
508 void PrefsDlg::Init(){
509 // m_global_rc_path has been set above
510 // m_rc_path is for game specific preferences
511 // takes the form: global-pref-path/gamename/prefs-file
513 // this is common to win32 and Linux init now
514 m_rc_path = g_string_new( m_global_rc_path->str );
517 g_string_append( m_rc_path, g_pGameDescription->mGameFile.c_str() );
518 g_string_append( m_rc_path, "/" );
519 Q_mkdir( m_rc_path->str );
522 m_inipath = g_string_new( m_rc_path->str );
523 g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
526 void notebook_set_page( ui::Widget notebook, ui::Widget page ){
527 int pagenum = gtk_notebook_page_num( GTK_NOTEBOOK( notebook ), page );
528 if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != pagenum ) {
529 gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook ), pagenum );
533 void PrefsDlg::showPrefPage( ui::Widget prefpage ){
534 notebook_set_page( m_notebook, prefpage );
538 static void treeSelection( ui::TreeSelection selection, gpointer data ){
539 PrefsDlg *dlg = (PrefsDlg*)data;
542 GtkTreeIter selected;
543 if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
544 ui::Widget prefpage{ui::null};
545 gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 );
546 dlg->showPrefPage( prefpage );
550 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
552 inline void PreferenceGroupCallbacks_constructGroup( const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group ){
553 for ( PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
560 inline void PreferenceGroupCallbacks_pushBack( PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback ){
561 callbacks.push_back( callback );
564 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
566 inline void PreferencesPageCallbacks_constructPage( const PreferencesPageCallbacks& callbacks, PreferencesPage& page ){
567 for ( PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
573 inline void PreferencesPageCallbacks_pushBack( PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback ){
574 callbacks.push_back( callback );
577 PreferencesPageCallbacks g_interfacePreferences;
578 void PreferencesDialog_addInterfacePreferences( const PreferencesPageCallback& callback ){
579 PreferencesPageCallbacks_pushBack( g_interfacePreferences, callback );
581 PreferenceGroupCallbacks g_interfaceCallbacks;
582 void PreferencesDialog_addInterfacePage( const PreferenceGroupCallback& callback ){
583 PreferenceGroupCallbacks_pushBack( g_interfaceCallbacks, callback );
586 PreferencesPageCallbacks g_displayPreferences;
587 void PreferencesDialog_addDisplayPreferences( const PreferencesPageCallback& callback ){
588 PreferencesPageCallbacks_pushBack( g_displayPreferences, callback );
590 PreferenceGroupCallbacks g_displayCallbacks;
591 void PreferencesDialog_addDisplayPage( const PreferenceGroupCallback& callback ){
592 PreferenceGroupCallbacks_pushBack( g_displayCallbacks, callback );
595 PreferencesPageCallbacks g_settingsPreferences;
596 void PreferencesDialog_addSettingsPreferences( const PreferencesPageCallback& callback ){
597 PreferencesPageCallbacks_pushBack( g_settingsPreferences, callback );
599 PreferenceGroupCallbacks g_settingsCallbacks;
600 void PreferencesDialog_addSettingsPage( const PreferenceGroupCallback& callback ){
601 PreferenceGroupCallbacks_pushBack( g_settingsCallbacks, callback );
604 void Widget_updateDependency( ui::Widget self, ui::Widget toggleButton ){
605 gtk_widget_set_sensitive( self, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggleButton ) ) && gtk_widget_is_sensitive( toggleButton ) );
608 void ToggleButton_toggled_Widget_updateDependency( ui::Widget toggleButton, ui::Widget self ){
609 Widget_updateDependency( self, toggleButton );
612 void ToggleButton_state_changed_Widget_updateDependency( ui::Widget toggleButton, GtkStateType state, ui::Widget self ){
613 if ( state == GTK_STATE_INSENSITIVE ) {
614 Widget_updateDependency( self, toggleButton );
618 void Widget_connectToggleDependency( ui::Widget self, ui::Widget toggleButton ){
619 toggleButton.connect( "state_changed", G_CALLBACK( ToggleButton_state_changed_Widget_updateDependency ), self );
620 toggleButton.connect( "toggled", G_CALLBACK( ToggleButton_toggled_Widget_updateDependency ), self );
621 Widget_updateDependency( self, toggleButton );
625 inline ui::VBox getVBox( ui::Bin page ){
626 return ui::VBox::from(gtk_bin_get_child(page));
629 GtkTreeIter PreferenceTree_appendPage( ui::TreeStore store, GtkTreeIter* parent, const char* name, ui::Widget page ){
631 gtk_tree_store_append( store, &group, parent );
632 gtk_tree_store_set( store, &group, 0, name, 1, page, -1 );
636 ui::Bin PreferencePages_addPage( ui::Widget notebook, const char* name ){
637 ui::Widget preflabel = ui::Label( name );
640 auto pageframe = ui::Frame( name );
641 gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 4 );
644 ui::Widget vbox = ui::VBox( FALSE, 4 );
646 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 4 );
649 // Add the page to the notebook
650 gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
655 class PreferenceTreeGroup : public PreferenceGroup
658 ui::Widget m_notebook;
659 ui::TreeStore m_store;
662 PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group ) :
664 m_notebook( notebook ),
668 PreferencesPage createPage( const char* treeName, const char* frameName ){
669 auto page = PreferencePages_addPage( m_notebook, frameName );
670 PreferenceTree_appendPage( m_store, &m_group, treeName, page );
671 return PreferencesPage( m_dialog, getVBox( page ) );
675 ui::Window PrefsDlg::BuildDialog(){
676 PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) );
677 Mouse_registerPreferencesPage();
679 ui::Window dialog = ui::Window(create_floating_window( "NetRadiant Preferences", m_parent ));
682 auto mainvbox = ui::VBox( FALSE, 5 );
683 dialog.add(mainvbox);
684 gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 );
688 auto hbox = ui::HBox( FALSE, 5 );
690 mainvbox.pack_end(hbox, FALSE, TRUE, 0);
693 auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &m_modal );
694 hbox.pack_end(button, FALSE, FALSE, 0);
697 auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &m_modal );
698 hbox.pack_end(button, FALSE, FALSE, 0);
701 auto button = create_dialog_button( "Clean", G_CALLBACK( OnButtonClean ), this );
702 hbox.pack_end(button, FALSE, FALSE, 0);
707 auto hbox = ui::HBox( FALSE, 5 );
708 mainvbox.pack_start( hbox, TRUE, TRUE, 0 );
712 auto sc_win = ui::ScrolledWindow(ui::New);
713 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_win ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
714 hbox.pack_start( sc_win, FALSE, FALSE, 0 );
716 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN );
718 // prefs pages notebook
719 m_notebook = ui::Widget::from(gtk_notebook_new());
720 // hide the notebook tabs since its not supposed to look like a notebook
721 gtk_notebook_set_show_tabs( GTK_NOTEBOOK( m_notebook ), FALSE );
722 hbox.pack_start( m_notebook, TRUE, TRUE, 0 );
727 auto store = ui::TreeStore::from(gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER ));
729 auto view = ui::TreeView(ui::TreeModel::from(store._handle));
730 gtk_tree_view_set_headers_visible(view, FALSE );
733 auto renderer = ui::CellRendererText(ui::New);
734 auto column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} );
735 gtk_tree_view_append_column(view, column );
739 auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view));
740 selection.connect( "changed", G_CALLBACK( treeSelection ), this );
748 /********************************************************************/
749 /* Add preference tree options */
750 /********************************************************************/
753 PreferencePages_addPage( m_notebook, "Front Page" );
756 auto global = PreferencePages_addPage( m_notebook, "Global Preferences" );
758 PreferencesPage preferencesPage( *this, getVBox( global ) );
759 Global_constructPreferences( preferencesPage );
761 auto group = PreferenceTree_appendPage( store, 0, "Global", global );
763 auto game = PreferencePages_addPage( m_notebook, "Game" );
764 PreferencesPage preferencesPage( *this, getVBox( game ) );
765 g_GamesDialog.CreateGlobalFrame( preferencesPage );
767 PreferenceTree_appendPage( store, &group, "Game", game );
772 auto interfacePage = PreferencePages_addPage( m_notebook, "Interface Preferences" );
774 PreferencesPage preferencesPage( *this, getVBox( interfacePage ) );
775 PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage );
778 auto group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage );
779 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
781 PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup );
785 auto display = PreferencePages_addPage( m_notebook, "Display Preferences" );
787 PreferencesPage preferencesPage( *this, getVBox( display ) );
788 PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage );
790 auto group = PreferenceTree_appendPage( store, 0, "Display", display );
791 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
793 PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup );
797 auto settings = PreferencePages_addPage( m_notebook, "General Settings" );
799 PreferencesPage preferencesPage( *this, getVBox( settings ) );
800 PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage );
803 auto group = PreferenceTree_appendPage( store, 0, "Settings", settings );
804 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
806 PreferenceGroupCallbacks_constructGroup( g_settingsCallbacks, preferenceGroup );
810 gtk_tree_view_expand_all(view );
812 g_object_unref( G_OBJECT( store ) );
818 gtk_notebook_set_current_page( GTK_NOTEBOOK( m_notebook ), 0 );
823 preferences_globals_t g_preferences_globals;
825 PrefsDlg g_Preferences; // global prefs instance
828 void PreferencesDialog_constructWindow( ui::Window main_window ){
829 g_Preferences.m_parent = main_window;
830 g_Preferences.Create();
832 void PreferencesDialog_destroyWindow(){
833 g_Preferences.Destroy();
837 PreferenceDictionary g_preferences;
839 PreferenceSystem& GetPreferenceSystem(){
840 return g_preferences;
843 class PreferenceSystemAPI
845 PreferenceSystem* m_preferencesystem;
847 typedef PreferenceSystem Type;
848 STRING_CONSTANT( Name, "*" );
850 PreferenceSystemAPI(){
851 m_preferencesystem = &GetPreferenceSystem();
853 PreferenceSystem* getTable(){
854 return m_preferencesystem;
858 #include "modulesystem/singletonmodule.h"
859 #include "modulesystem/moduleregistry.h"
861 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
862 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
863 StaticRegisterModule staticRegisterPreferenceSystem( StaticPreferenceSystemModule::instance() );
865 void Preferences_Load(){
866 g_GamesDialog.LoadPrefs();
868 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
870 if ( !Preferences_Load( g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str() ) ) {
871 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
875 void Preferences_Save(){
876 if ( g_preferences_globals.disable_ini ) {
880 g_GamesDialog.SavePrefs();
882 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
884 if ( !Preferences_Save_Safe( g_preferences, g_Preferences.m_inipath->str ) ) {
885 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
889 void Preferences_Reset(){
890 file_remove( g_Preferences.m_inipath->str );
894 void PrefsDlg::PostModal( EMessageBoxReturn code ){
895 if ( code == eIDOK ) {
901 std::vector<const char*> g_restart_required;
903 void PreferencesDialog_restartRequired( const char* staticName ){
904 g_restart_required.push_back( staticName );
907 void PreferencesDialog_showDialog(){
908 if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) {
909 if ( !g_restart_required.empty() ) {
910 StringOutputStream message( 256 );
911 message << "Preference changes require a restart:\n";
912 for ( std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i )
914 message << ( *i ) << '\n';
916 ui::alert( MainFrame_getWindow(), message.c_str() );
917 g_restart_required.clear();
923 static void Export(const Callback<void(const char *)> &returnz) {
924 returnz(gamename_get());
927 static void Import(const char *value) {
933 static void Export(const Callback<void(const char *)> &returnz) {
934 returnz(gamemode_get());
937 static void Import(const char *value) {
942 void RegisterPreferences( PreferenceSystem& preferences ){
944 preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) );
946 preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useCustomEditor ) );
947 preferences.registerPreference( "CustomShaderEditorCommand", make_property_string( g_TextEditor_editorCommand ) );
950 preferences.registerPreference( "GameName", make_property<GameName>() );
951 preferences.registerPreference( "GameMode", make_property<GameMode>() );
954 void Preferences_Init(){
955 RegisterPreferences( GetPreferenceSystem() );