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( "", "External Shader 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 );
78 page.appendCheckBox( "", "Improved mousewheel zoom", g_xywindow_globals.m_bImprovedWheelZoom );
80 void Mouse_constructPage( PreferenceGroup& group ){
81 PreferencesPage page( group.createPage( "Mouse", "Mouse Preferences" ) );
82 Mouse_constructPreferences( page );
84 void Mouse_registerPreferencesPage(){
85 PreferencesDialog_addInterfacePage( makeCallbackF(Mouse_constructPage) );
90 =========================================================
91 Games selection dialog
92 =========================================================
96 #include <uilib/uilib.h>
98 inline const char* xmlAttr_getName( xmlAttrPtr attr ){
99 return reinterpret_cast<const char*>( attr->name );
102 inline const char* xmlAttr_getValue( xmlAttrPtr attr ){
103 return reinterpret_cast<const char*>( attr->children->content );
106 CGameDescription::CGameDescription( xmlDocPtr pDoc, const CopiedString& gameFile ){
107 // read the user-friendly game name
108 xmlNodePtr pNode = pDoc->children;
110 while ( pNode != 0 && strcmp( (const char*)pNode->name, "game" ) )
115 Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL );
118 for ( xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next )
120 m_gameDescription.insert( GameDescription::value_type( xmlAttr_getName( attr ), xmlAttr_getValue( attr ) ) );
124 StringOutputStream path( 256 );
125 path << AppPath_get() << gameFile.c_str() << "/";
126 mGameToolsPath = path.c_str();
129 ASSERT_MESSAGE( file_exists( mGameToolsPath.c_str() ), "game directory not found: " << makeQuoted( mGameToolsPath.c_str() ) );
131 mGameFile = gameFile;
134 GameDescription::iterator i = m_gameDescription.find( "type" );
135 if ( i == m_gameDescription.end() ) {
136 globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>( pDoc->URL ) << "'\n";
142 mGameType = ( *i ).second.c_str();
147 void CGameDescription::Dump(){
148 globalOutputStream() << "game description file: " << makeQuoted( mGameFile.c_str() ) << "\n";
149 for ( GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i )
151 globalOutputStream() << ( *i ).first.c_str() << " = " << makeQuoted( ( *i ).second.c_str() ) << "\n";
155 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
158 #include "warnings.h"
159 #include "stream/textfilestream.h"
160 #include "container/array.h"
161 #include "xml/ixml.h"
162 #include "xml/xmlparser.h"
163 #include "xml/xmlwriter.h"
165 #include "preferencedictionary.h"
166 #include "stringio.h"
168 const char* const PREFERENCES_VERSION = "1.0";
170 bool Preferences_Load( PreferenceDictionary& preferences, const char* filename, const char *cmdline_prefix ){
172 TextFileInputStream file( filename );
173 if ( !file.failed() ) {
174 XMLStreamParser parser( file );
175 XMLPreferenceDictionaryImporter importer( preferences, PREFERENCES_VERSION );
176 parser.exportXML( importer );
180 int l = strlen( cmdline_prefix );
181 for ( int i = 1; i < g_argc - 1; ++i )
183 if ( g_argv[i][0] == '-' ) {
184 if ( !strncmp( g_argv[i] + 1, cmdline_prefix, l ) ) {
185 if ( g_argv[i][l + 1] == '-' ) {
186 preferences.importPref( g_argv[i] + l + 2, g_argv[i + 1] );
196 bool Preferences_Save( PreferenceDictionary& preferences, const char* filename ){
197 TextFileOutputStream file( filename );
198 if ( !file.failed() ) {
199 XMLStreamWriter writer( file );
200 XMLPreferenceDictionaryExporter exporter( preferences, PREFERENCES_VERSION );
201 exporter.exportXML( writer );
207 bool Preferences_Save_Safe( PreferenceDictionary& preferences, const char* filename ){
208 Array<char> tmpName( filename, filename + strlen( filename ) + 1 + 3 );
209 *( tmpName.end() - 4 ) = 'T';
210 *( tmpName.end() - 3 ) = 'M';
211 *( tmpName.end() - 2 ) = 'P';
212 *( tmpName.end() - 1 ) = '\0';
214 return Preferences_Save( preferences, tmpName.data() )
215 && ( !file_exists( filename ) || file_remove( filename ) )
216 && file_move( tmpName.data(), filename );
221 static void Export(const Callback<void(bool)> &returnz) {
222 returnz(g_Console_enableLogging);
225 static void Import(bool value) {
226 g_Console_enableLogging = value;
227 Sys_LogFile(g_Console_enableLogging);
232 void RegisterGlobalPreferences( PreferenceSystem& preferences ){
233 preferences.registerPreference( "gamefile", make_property_string( g_GamesDialog.m_sGameFile ) );
234 preferences.registerPreference( "gamePrompt", make_property_string( g_GamesDialog.m_bGamePrompt ) );
235 preferences.registerPreference( "log console", make_property_string<LogConsole>() );
239 PreferenceDictionary g_global_preferences;
241 void GlobalPreferences_Init(){
242 RegisterGlobalPreferences( g_global_preferences );
245 void CGameDialog::LoadPrefs(){
246 // load global .pref file
247 StringOutputStream strGlobalPref( 256 );
248 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
250 globalOutputStream() << "loading global preferences from " << makeQuoted( strGlobalPref.c_str() ) << "\n";
252 if ( !Preferences_Load( g_global_preferences, strGlobalPref.c_str(), "global" ) ) {
253 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
257 void CGameDialog::SavePrefs(){
258 StringOutputStream strGlobalPref( 256 );
259 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
261 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
263 if ( !Preferences_Save_Safe( g_global_preferences, strGlobalPref.c_str() ) ) {
264 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
268 void CGameDialog::DoGameDialog(){
272 // we save the prefs file
276 void CGameDialog::GameFileImport( int value ){
277 m_nComboSelect = value;
278 // use value to set m_sGameFile
279 std::list<CGameDescription *>::iterator iGame = mGames.begin();
281 for ( i = 0; i < value; i++ )
285 m_sGameFile = ( *iGame )->mGameFile;
288 void CGameDialog::GameFileExport( const Callback<void(int)> & importCallback ) const {
289 // use m_sGameFile to set value
290 std::list<CGameDescription *>::const_iterator iGame;
292 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
294 if ( ( *iGame )->mGameFile == m_sGameFile ) {
300 importCallback( m_nComboSelect );
303 struct CGameDialog_GameFile {
304 static void Export(const CGameDialog &self, const Callback<void(int)> &returnz) {
305 self.GameFileExport(returnz);
308 static void Import(CGameDialog &self, int value) {
309 self.GameFileImport(value);
313 void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){
314 std::vector<const char*> games;
315 games.reserve( mGames.size() );
316 for ( std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i )
318 games.push_back( ( *i )->getRequiredKeyValue( "name" ) );
322 StringArrayRange( &( *games.begin() ), &( *games.end() ) ),
323 make_property<CGameDialog_GameFile>(*this)
325 page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt );
328 ui::Window CGameDialog::BuildDialog(){
329 auto frame = create_dialog_frame( "Game settings", ui::Shadow::ETCHED_IN );
331 auto vbox2 = create_dialog_vbox( 0, 4 );
335 PreferencesPage preferencesPage( *this, vbox2 );
336 Global_constructPreferences( preferencesPage );
337 CreateGlobalFrame( preferencesPage );
340 return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame );
343 void CGameDialog::ScanForGames(){
344 StringOutputStream strGamesPath( 256 );
345 strGamesPath << AppPath_get() << "games/";
346 const char *path = strGamesPath.c_str();
348 globalOutputStream() << "Scanning for game description files: " << path << '\n';
352 do we put game description files below AppPath, or in ~/.radiant
353 i.e. read only or read/write?
354 my guess .. readonly cause it's an install
355 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
356 (if that's really needed)
359 Directory_forEach(path, [&](const char *name) {
360 if (!extension_equal(path_get_extension(name), "game")) {
363 StringOutputStream strPath(256);
364 strPath << path << name;
365 globalOutputStream() << strPath.c_str() << '\n';
367 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
369 mGames.push_front(new CGameDescription(pDoc, name));
372 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
377 CGameDescription* CGameDialog::GameDescriptionForComboItem(){
378 std::list<CGameDescription *>::iterator iGame;
380 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame,i++ )
382 if ( i == m_nComboSelect ) {
386 return 0; // not found
389 void CGameDialog::InitGlobalPrefPath(){
390 g_Preferences.m_global_rc_path = g_string_new( SettingsPath_get() );
393 void CGameDialog::Reset(){
394 if ( !g_Preferences.m_global_rc_path ) {
395 InitGlobalPrefPath();
397 StringOutputStream strGlobalPref( 256 );
398 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
399 file_remove( strGlobalPref.c_str() );
402 void CGameDialog::Init(){
403 InitGlobalPrefPath();
406 if ( mGames.empty() ) {
407 Error( "Didn't find any valid game file descriptions, aborting\n" );
411 std::list<CGameDescription *>::iterator iGame, iPrevGame;
412 for ( iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame )
414 if ( iPrevGame != mGames.end() ) {
415 if ( strcmp( ( *iGame )->getRequiredKeyValue( "name" ), ( *iPrevGame )->getRequiredKeyValue( "name" ) ) < 0 ) {
416 CGameDescription *h = *iGame;
424 CGameDescription* currentGameDescription = 0;
426 if ( !m_bGamePrompt ) {
427 // search by .game name
428 std::list<CGameDescription *>::iterator iGame;
429 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
431 if ( ( *iGame )->mGameFile == m_sGameFile ) {
432 currentGameDescription = ( *iGame );
437 if ( m_bGamePrompt || !currentGameDescription ) {
440 // use m_nComboSelect to identify the game to run as and set the globals
441 currentGameDescription = GameDescriptionForComboItem();
442 ASSERT_NOTNULL( currentGameDescription );
444 g_pGameDescription = currentGameDescription;
446 g_pGameDescription->Dump();
449 CGameDialog::~CGameDialog(){
450 // free all the game descriptions
451 std::list<CGameDescription *>::iterator iGame;
452 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
462 inline const char* GameDescription_getIdentifier( const CGameDescription& gameDescription ){
463 const char* identifier = gameDescription.getKeyValue( "index" );
464 if ( string_empty( identifier ) ) {
471 CGameDialog g_GamesDialog;
474 // =============================================================================
475 // Widget callbacks for PrefsDlg
477 static void OnButtonClean( ui::Widget widget, gpointer data ){
478 // make sure this is what the user wants
479 if ( ui::alert( g_Preferences.GetWidget(), "This will close Radiant and clean the corresponding registry entries.\n"
480 "Next time you start Radiant it will be good as new. Do you wish to continue?",
481 "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) {
482 PrefsDlg *dlg = (PrefsDlg*)data;
483 dlg->EndModal( eIDCANCEL );
485 g_preferences_globals.disable_ini = true;
491 // =============================================================================
497 very first prefs init deals with selecting the game and the game tools path
498 then we can load .ini stuff
500 using prefs / ini settings:
503 look in ~/.radiant/<version>/gamename
507 const char *PREFS_LOCAL_FILENAME = "local.pref";
509 void PrefsDlg::Init(){
510 // m_global_rc_path has been set above
511 // m_rc_path is for game specific preferences
512 // takes the form: global-pref-path/gamename/prefs-file
514 // this is common to win32 and Linux init now
515 m_rc_path = g_string_new( m_global_rc_path->str );
518 g_string_append( m_rc_path, g_pGameDescription->mGameFile.c_str() );
519 g_string_append( m_rc_path, "/" );
520 Q_mkdir( m_rc_path->str );
523 m_inipath = g_string_new( m_rc_path->str );
524 g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
527 void notebook_set_page( ui::Widget notebook, ui::Widget page ){
528 int pagenum = gtk_notebook_page_num( GTK_NOTEBOOK( notebook ), page );
529 if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != pagenum ) {
530 gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook ), pagenum );
534 void PrefsDlg::showPrefPage( ui::Widget prefpage ){
535 notebook_set_page( m_notebook, prefpage );
539 static void treeSelection( ui::TreeSelection selection, gpointer data ){
540 PrefsDlg *dlg = (PrefsDlg*)data;
543 GtkTreeIter selected;
544 if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
545 ui::Widget prefpage{ui::null};
546 gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 );
547 dlg->showPrefPage( prefpage );
551 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
553 inline void PreferenceGroupCallbacks_constructGroup( const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group ){
554 for ( PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
561 inline void PreferenceGroupCallbacks_pushBack( PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback ){
562 callbacks.push_back( callback );
565 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
567 inline void PreferencesPageCallbacks_constructPage( const PreferencesPageCallbacks& callbacks, PreferencesPage& page ){
568 for ( PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
574 inline void PreferencesPageCallbacks_pushBack( PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback ){
575 callbacks.push_back( callback );
578 PreferencesPageCallbacks g_interfacePreferences;
579 void PreferencesDialog_addInterfacePreferences( const PreferencesPageCallback& callback ){
580 PreferencesPageCallbacks_pushBack( g_interfacePreferences, callback );
582 PreferenceGroupCallbacks g_interfaceCallbacks;
583 void PreferencesDialog_addInterfacePage( const PreferenceGroupCallback& callback ){
584 PreferenceGroupCallbacks_pushBack( g_interfaceCallbacks, callback );
587 PreferencesPageCallbacks g_displayPreferences;
588 void PreferencesDialog_addDisplayPreferences( const PreferencesPageCallback& callback ){
589 PreferencesPageCallbacks_pushBack( g_displayPreferences, callback );
591 PreferenceGroupCallbacks g_displayCallbacks;
592 void PreferencesDialog_addDisplayPage( const PreferenceGroupCallback& callback ){
593 PreferenceGroupCallbacks_pushBack( g_displayCallbacks, callback );
596 PreferencesPageCallbacks g_settingsPreferences;
597 void PreferencesDialog_addSettingsPreferences( const PreferencesPageCallback& callback ){
598 PreferencesPageCallbacks_pushBack( g_settingsPreferences, callback );
600 PreferenceGroupCallbacks g_settingsCallbacks;
601 void PreferencesDialog_addSettingsPage( const PreferenceGroupCallback& callback ){
602 PreferenceGroupCallbacks_pushBack( g_settingsCallbacks, callback );
605 void Widget_updateDependency( ui::Widget self, ui::Widget toggleButton ){
606 gtk_widget_set_sensitive( self, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggleButton ) ) && gtk_widget_is_sensitive( toggleButton ) );
609 void ToggleButton_toggled_Widget_updateDependency( ui::Widget toggleButton, ui::Widget self ){
610 Widget_updateDependency( self, toggleButton );
613 void ToggleButton_state_changed_Widget_updateDependency( ui::Widget toggleButton, GtkStateType state, ui::Widget self ){
614 if ( state == GTK_STATE_INSENSITIVE ) {
615 Widget_updateDependency( self, toggleButton );
619 void Widget_connectToggleDependency( ui::Widget self, ui::Widget toggleButton ){
620 toggleButton.connect( "state_changed", G_CALLBACK( ToggleButton_state_changed_Widget_updateDependency ), self );
621 toggleButton.connect( "toggled", G_CALLBACK( ToggleButton_toggled_Widget_updateDependency ), self );
622 Widget_updateDependency( self, toggleButton );
626 inline ui::VBox getVBox( ui::Bin page ){
627 return ui::VBox::from(gtk_bin_get_child(page));
630 GtkTreeIter PreferenceTree_appendPage( ui::TreeStore store, GtkTreeIter* parent, const char* name, ui::Widget page ){
632 gtk_tree_store_append( store, &group, parent );
633 gtk_tree_store_set( store, &group, 0, name, 1, page, -1 );
637 ui::Bin PreferencePages_addPage( ui::Widget notebook, const char* name ){
638 ui::Widget preflabel = ui::Label( name );
641 auto pageframe = ui::Frame( name );
642 gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 4 );
645 ui::Widget vbox = ui::VBox( FALSE, 4 );
647 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 4 );
650 // Add the page to the notebook
651 gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
656 class PreferenceTreeGroup : public PreferenceGroup
659 ui::Widget m_notebook;
660 ui::TreeStore m_store;
663 PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group ) :
665 m_notebook( notebook ),
669 PreferencesPage createPage( const char* treeName, const char* frameName ){
670 auto page = PreferencePages_addPage( m_notebook, frameName );
671 PreferenceTree_appendPage( m_store, &m_group, treeName, page );
672 return PreferencesPage( m_dialog, getVBox( page ) );
676 ui::Window PrefsDlg::BuildDialog(){
677 PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) );
678 Mouse_registerPreferencesPage();
680 ui::Window dialog = ui::Window(create_floating_window( "NetRadiant Preferences", m_parent ));
683 auto mainvbox = ui::VBox( FALSE, 5 );
684 dialog.add(mainvbox);
685 gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 );
689 auto hbox = ui::HBox( FALSE, 5 );
691 mainvbox.pack_end(hbox, FALSE, TRUE, 0);
694 auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &m_modal );
695 hbox.pack_end(button, FALSE, FALSE, 0);
698 auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &m_modal );
699 hbox.pack_end(button, FALSE, FALSE, 0);
702 auto button = create_dialog_button( "Clean", G_CALLBACK( OnButtonClean ), this );
703 hbox.pack_end(button, FALSE, FALSE, 0);
708 auto hbox = ui::HBox( FALSE, 5 );
709 mainvbox.pack_start( hbox, TRUE, TRUE, 0 );
713 auto sc_win = ui::ScrolledWindow(ui::New);
714 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_win ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
715 hbox.pack_start( sc_win, FALSE, FALSE, 0 );
717 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN );
719 // prefs pages notebook
720 m_notebook = ui::Widget::from(gtk_notebook_new());
721 // hide the notebook tabs since its not supposed to look like a notebook
722 gtk_notebook_set_show_tabs( GTK_NOTEBOOK( m_notebook ), FALSE );
723 hbox.pack_start( m_notebook, TRUE, TRUE, 0 );
728 auto store = ui::TreeStore::from(gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER ));
730 auto view = ui::TreeView(ui::TreeModel::from(store._handle));
731 gtk_tree_view_set_headers_visible(view, FALSE );
734 auto renderer = ui::CellRendererText(ui::New);
735 auto column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} );
736 gtk_tree_view_append_column(view, column );
740 auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view));
741 selection.connect( "changed", G_CALLBACK( treeSelection ), this );
749 /********************************************************************/
750 /* Add preference tree options */
751 /********************************************************************/
754 PreferencePages_addPage( m_notebook, "Front Page" );
757 auto global = PreferencePages_addPage( m_notebook, "Global Preferences" );
759 PreferencesPage preferencesPage( *this, getVBox( global ) );
760 Global_constructPreferences( preferencesPage );
762 auto group = PreferenceTree_appendPage( store, 0, "Global", global );
764 auto game = PreferencePages_addPage( m_notebook, "Game" );
765 PreferencesPage preferencesPage( *this, getVBox( game ) );
766 g_GamesDialog.CreateGlobalFrame( preferencesPage );
768 PreferenceTree_appendPage( store, &group, "Game", game );
773 auto interfacePage = PreferencePages_addPage( m_notebook, "Interface Preferences" );
775 PreferencesPage preferencesPage( *this, getVBox( interfacePage ) );
776 PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage );
779 auto group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage );
780 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
782 PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup );
786 auto display = PreferencePages_addPage( m_notebook, "Display Preferences" );
788 PreferencesPage preferencesPage( *this, getVBox( display ) );
789 PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage );
791 auto group = PreferenceTree_appendPage( store, 0, "Display", display );
792 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
794 PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup );
798 auto settings = PreferencePages_addPage( m_notebook, "General Settings" );
800 PreferencesPage preferencesPage( *this, getVBox( settings ) );
801 PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage );
804 auto group = PreferenceTree_appendPage( store, 0, "Settings", settings );
805 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
807 PreferenceGroupCallbacks_constructGroup( g_settingsCallbacks, preferenceGroup );
811 gtk_tree_view_expand_all(view );
813 g_object_unref( G_OBJECT( store ) );
819 gtk_notebook_set_current_page( GTK_NOTEBOOK( m_notebook ), 0 );
824 preferences_globals_t g_preferences_globals;
826 PrefsDlg g_Preferences; // global prefs instance
829 void PreferencesDialog_constructWindow( ui::Window main_window ){
830 g_Preferences.m_parent = main_window;
831 g_Preferences.Create();
833 void PreferencesDialog_destroyWindow(){
834 g_Preferences.Destroy();
838 PreferenceDictionary g_preferences;
840 PreferenceSystem& GetPreferenceSystem(){
841 return g_preferences;
844 class PreferenceSystemAPI
846 PreferenceSystem* m_preferencesystem;
848 typedef PreferenceSystem Type;
849 STRING_CONSTANT( Name, "*" );
851 PreferenceSystemAPI(){
852 m_preferencesystem = &GetPreferenceSystem();
854 PreferenceSystem* getTable(){
855 return m_preferencesystem;
859 #include "modulesystem/singletonmodule.h"
860 #include "modulesystem/moduleregistry.h"
862 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
863 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
864 StaticRegisterModule staticRegisterPreferenceSystem( StaticPreferenceSystemModule::instance() );
866 void Preferences_Load(){
867 g_GamesDialog.LoadPrefs();
869 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
871 if ( !Preferences_Load( g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str() ) ) {
872 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
876 void Preferences_Save(){
877 if ( g_preferences_globals.disable_ini ) {
881 g_GamesDialog.SavePrefs();
883 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
885 if ( !Preferences_Save_Safe( g_preferences, g_Preferences.m_inipath->str ) ) {
886 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
890 void Preferences_Reset(){
891 file_remove( g_Preferences.m_inipath->str );
895 void PrefsDlg::PostModal( EMessageBoxReturn code ){
896 if ( code == eIDOK ) {
902 std::vector<const char*> g_restart_required;
904 void PreferencesDialog_restartRequired( const char* staticName ){
905 g_restart_required.push_back( staticName );
908 void PreferencesDialog_showDialog(){
909 //if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) {
910 if ( g_Preferences.DoModal() == eIDOK ) {
911 if ( !g_restart_required.empty() ) {
912 StringOutputStream message( 256 );
913 message << "Preference changes require a restart:\n";
914 for ( std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i )
916 message << ( *i ) << '\n';
918 ui::alert( MainFrame_getWindow(), message.c_str() );
919 g_restart_required.clear();
925 static void Export(const Callback<void(const char *)> &returnz) {
926 returnz(gamename_get());
929 static void Import(const char *value) {
935 static void Export(const Callback<void(const char *)> &returnz) {
936 returnz(gamemode_get());
939 static void Import(const char *value) {
944 void RegisterPreferences( PreferenceSystem& preferences ){
946 preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) );
948 preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useCustomEditor ) );
949 preferences.registerPreference( "CustomShaderEditorCommand", make_property_string( g_TextEditor_editorCommand ) );
952 preferences.registerPreference( "GameName", make_property<GameName>() );
953 preferences.registerPreference( "GameMode", make_property<GameMode>() );
956 void Preferences_Init(){
957 RegisterPreferences( GetPreferenceSystem() );