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 ){
61 page.appendPathEntry( "Shader Editor Command", g_TextEditor_editorCommand, false );
64 void Mouse_constructPreferences( PreferencesPage& page ){
66 // const char* buttons[] = { "2 button", "3 button", };
67 // page.appendRadio( "Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE( buttons ) );
69 // page.appendCheckBox( "Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick );
70 page.appendCheckBox( "", "Zoom to mouse pointer", g_xywindow_globals.m_bZoomInToPointer );
72 void Mouse_constructPage( PreferenceGroup& group ){
73 PreferencesPage page( group.createPage( "Mouse", "Mouse Preferences" ) );
74 Mouse_constructPreferences( page );
76 void Mouse_registerPreferencesPage(){
77 PreferencesDialog_addInterfacePage( makeCallbackF(Mouse_constructPage) );
82 =========================================================
83 Games selection dialog
84 =========================================================
88 #include <uilib/uilib.h>
90 inline const char* xmlAttr_getName( xmlAttrPtr attr ){
91 return reinterpret_cast<const char*>( attr->name );
94 inline const char* xmlAttr_getValue( xmlAttrPtr attr ){
95 return reinterpret_cast<const char*>( attr->children->content );
98 CGameDescription::CGameDescription( xmlDocPtr pDoc, const CopiedString& gameFile ){
99 // read the user-friendly game name
100 xmlNodePtr pNode = pDoc->children;
102 while ( pNode != 0 && strcmp( (const char*)pNode->name, "game" ) )
107 Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL );
110 for ( xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next )
112 m_gameDescription.insert( GameDescription::value_type( xmlAttr_getName( attr ), xmlAttr_getValue( attr ) ) );
116 StringOutputStream path( 256 );
117 path << AppPath_get() << gameFile.c_str() << "/";
118 mGameToolsPath = path.c_str();
121 ASSERT_MESSAGE( file_exists( mGameToolsPath.c_str() ), "game directory not found: " << makeQuoted( mGameToolsPath.c_str() ) );
123 mGameFile = gameFile;
126 GameDescription::iterator i = m_gameDescription.find( "type" );
127 if ( i == m_gameDescription.end() ) {
128 globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>( pDoc->URL ) << "'\n";
134 mGameType = ( *i ).second.c_str();
139 void CGameDescription::Dump(){
140 globalOutputStream() << "game description file: " << makeQuoted( mGameFile.c_str() ) << "\n";
141 for ( GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i )
143 globalOutputStream() << ( *i ).first.c_str() << " = " << makeQuoted( ( *i ).second.c_str() ) << "\n";
147 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
150 #include "warnings.h"
151 #include "stream/textfilestream.h"
152 #include "container/array.h"
153 #include "xml/ixml.h"
154 #include "xml/xmlparser.h"
155 #include "xml/xmlwriter.h"
157 #include "preferencedictionary.h"
158 #include "stringio.h"
160 const char* const PREFERENCES_VERSION = "1.0";
162 bool Preferences_Load( PreferenceDictionary& preferences, const char* filename, const char *cmdline_prefix ){
164 TextFileInputStream file( filename );
165 if ( !file.failed() ) {
166 XMLStreamParser parser( file );
167 XMLPreferenceDictionaryImporter importer( preferences, PREFERENCES_VERSION );
168 parser.exportXML( importer );
172 int l = strlen( cmdline_prefix );
173 for ( int i = 1; i < g_argc - 1; ++i )
175 if ( g_argv[i][0] == '-' ) {
176 if ( !strncmp( g_argv[i] + 1, cmdline_prefix, l ) ) {
177 if ( g_argv[i][l + 1] == '-' ) {
178 preferences.importPref( g_argv[i] + l + 2, g_argv[i + 1] );
188 bool Preferences_Save( PreferenceDictionary& preferences, const char* filename ){
189 TextFileOutputStream file( filename );
190 if ( !file.failed() ) {
191 XMLStreamWriter writer( file );
192 XMLPreferenceDictionaryExporter exporter( preferences, PREFERENCES_VERSION );
193 exporter.exportXML( writer );
199 bool Preferences_Save_Safe( PreferenceDictionary& preferences, const char* filename ){
200 Array<char> tmpName( filename, filename + strlen( filename ) + 1 + 3 );
201 *( tmpName.end() - 4 ) = 'T';
202 *( tmpName.end() - 3 ) = 'M';
203 *( tmpName.end() - 2 ) = 'P';
204 *( tmpName.end() - 1 ) = '\0';
206 return Preferences_Save( preferences, tmpName.data() )
207 && ( !file_exists( filename ) || file_remove( filename ) )
208 && file_move( tmpName.data(), filename );
213 static void Export(const Callback<void(bool)> &returnz) {
214 returnz(g_Console_enableLogging);
217 static void Import(bool value) {
218 g_Console_enableLogging = value;
219 Sys_LogFile(g_Console_enableLogging);
224 void RegisterGlobalPreferences( PreferenceSystem& preferences ){
225 preferences.registerPreference( "gamefile", make_property_string( g_GamesDialog.m_sGameFile ) );
226 preferences.registerPreference( "gamePrompt", make_property_string( g_GamesDialog.m_bGamePrompt ) );
227 preferences.registerPreference( "log console", make_property_string<LogConsole>() );
231 PreferenceDictionary g_global_preferences;
233 void GlobalPreferences_Init(){
234 RegisterGlobalPreferences( g_global_preferences );
237 void CGameDialog::LoadPrefs(){
238 // load global .pref file
239 StringOutputStream strGlobalPref( 256 );
240 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
242 globalOutputStream() << "loading global preferences from " << makeQuoted( strGlobalPref.c_str() ) << "\n";
244 if ( !Preferences_Load( g_global_preferences, strGlobalPref.c_str(), "global" ) ) {
245 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
249 void CGameDialog::SavePrefs(){
250 StringOutputStream strGlobalPref( 256 );
251 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
253 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
255 if ( !Preferences_Save_Safe( g_global_preferences, strGlobalPref.c_str() ) ) {
256 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
260 void CGameDialog::DoGameDialog(){
264 // we save the prefs file
268 void CGameDialog::GameFileImport( int value ){
269 m_nComboSelect = value;
270 // use value to set m_sGameFile
271 std::list<CGameDescription *>::iterator iGame = mGames.begin();
273 for ( i = 0; i < value; i++ )
277 m_sGameFile = ( *iGame )->mGameFile;
280 void CGameDialog::GameFileExport( const Callback<void(int)> & importCallback ) const {
281 // use m_sGameFile to set value
282 std::list<CGameDescription *>::const_iterator iGame;
284 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
286 if ( ( *iGame )->mGameFile == m_sGameFile ) {
292 importCallback( m_nComboSelect );
295 struct CGameDialog_GameFile {
296 static void Export(const CGameDialog &self, const Callback<void(int)> &returnz) {
297 self.GameFileExport(returnz);
300 static void Import(CGameDialog &self, int value) {
301 self.GameFileImport(value);
305 void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){
306 std::vector<const char*> games;
307 games.reserve( mGames.size() );
308 for ( std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i )
310 games.push_back( ( *i )->getRequiredKeyValue( "name" ) );
314 StringArrayRange( &( *games.begin() ), &( *games.end() ) ),
315 make_property<CGameDialog_GameFile>(*this)
317 page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt );
320 ui::Window CGameDialog::BuildDialog(){
321 auto frame = create_dialog_frame( "Game settings", ui::Shadow::ETCHED_IN );
323 auto vbox2 = create_dialog_vbox( 0, 4 );
327 PreferencesPage preferencesPage( *this, vbox2 );
328 Global_constructPreferences( preferencesPage );
329 CreateGlobalFrame( preferencesPage );
332 return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame );
335 void CGameDialog::ScanForGames(){
336 StringOutputStream strGamesPath( 256 );
337 strGamesPath << AppPath_get() << "games/";
338 const char *path = strGamesPath.c_str();
340 globalOutputStream() << "Scanning for game description files: " << path << '\n';
344 do we put game description files below AppPath, or in ~/.radiant
345 i.e. read only or read/write?
346 my guess .. readonly cause it's an install
347 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
348 (if that's really needed)
351 Directory_forEach(path, [&](const char *name) {
352 if (!extension_equal(path_get_extension(name), "game")) {
355 StringOutputStream strPath(256);
356 strPath << path << name;
357 globalOutputStream() << strPath.c_str() << '\n';
359 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
361 mGames.push_front(new CGameDescription(pDoc, name));
364 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
369 CGameDescription* CGameDialog::GameDescriptionForComboItem(){
370 std::list<CGameDescription *>::iterator iGame;
372 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame,i++ )
374 if ( i == m_nComboSelect ) {
378 return 0; // not found
381 void CGameDialog::InitGlobalPrefPath(){
382 g_Preferences.m_global_rc_path = g_string_new( SettingsPath_get() );
385 void CGameDialog::Reset(){
386 if ( !g_Preferences.m_global_rc_path ) {
387 InitGlobalPrefPath();
389 StringOutputStream strGlobalPref( 256 );
390 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
391 file_remove( strGlobalPref.c_str() );
394 void CGameDialog::Init(){
395 InitGlobalPrefPath();
398 if ( mGames.empty() ) {
399 Error( "Didn't find any valid game file descriptions, aborting\n" );
403 std::list<CGameDescription *>::iterator iGame, iPrevGame;
404 for ( iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame )
406 if ( iPrevGame != mGames.end() ) {
407 if ( strcmp( ( *iGame )->getRequiredKeyValue( "name" ), ( *iPrevGame )->getRequiredKeyValue( "name" ) ) < 0 ) {
408 CGameDescription *h = *iGame;
416 CGameDescription* currentGameDescription = 0;
418 if ( !m_bGamePrompt ) {
419 // search by .game name
420 std::list<CGameDescription *>::iterator iGame;
421 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
423 if ( ( *iGame )->mGameFile == m_sGameFile ) {
424 currentGameDescription = ( *iGame );
429 if ( m_bGamePrompt || !currentGameDescription ) {
432 // use m_nComboSelect to identify the game to run as and set the globals
433 currentGameDescription = GameDescriptionForComboItem();
434 ASSERT_NOTNULL( currentGameDescription );
436 g_pGameDescription = currentGameDescription;
438 g_pGameDescription->Dump();
441 CGameDialog::~CGameDialog(){
442 // free all the game descriptions
443 std::list<CGameDescription *>::iterator iGame;
444 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
454 inline const char* GameDescription_getIdentifier( const CGameDescription& gameDescription ){
455 const char* identifier = gameDescription.getKeyValue( "index" );
456 if ( string_empty( identifier ) ) {
463 CGameDialog g_GamesDialog;
466 // =============================================================================
467 // Widget callbacks for PrefsDlg
469 static void OnButtonClean( ui::Widget widget, gpointer data ){
470 // make sure this is what the user wants
471 if ( ui::alert( g_Preferences.GetWidget(), "This will close Radiant and clean the corresponding registry entries.\n"
472 "Next time you start Radiant it will be good as new. Do you wish to continue?",
473 "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) {
474 PrefsDlg *dlg = (PrefsDlg*)data;
475 dlg->EndModal( eIDCANCEL );
477 g_preferences_globals.disable_ini = true;
483 // =============================================================================
489 very first prefs init deals with selecting the game and the game tools path
490 then we can load .ini stuff
492 using prefs / ini settings:
495 look in ~/.radiant/<version>/gamename
499 const char *PREFS_LOCAL_FILENAME = "local.pref";
501 void PrefsDlg::Init(){
502 // m_global_rc_path has been set above
503 // m_rc_path is for game specific preferences
504 // takes the form: global-pref-path/gamename/prefs-file
506 // this is common to win32 and Linux init now
507 m_rc_path = g_string_new( m_global_rc_path->str );
510 g_string_append( m_rc_path, g_pGameDescription->mGameFile.c_str() );
511 g_string_append( m_rc_path, "/" );
512 Q_mkdir( m_rc_path->str );
515 m_inipath = g_string_new( m_rc_path->str );
516 g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
519 void notebook_set_page( ui::Widget notebook, ui::Widget page ){
520 int pagenum = gtk_notebook_page_num( GTK_NOTEBOOK( notebook ), page );
521 if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != pagenum ) {
522 gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook ), pagenum );
526 void PrefsDlg::showPrefPage( ui::Widget prefpage ){
527 notebook_set_page( m_notebook, prefpage );
531 static void treeSelection( ui::TreeSelection selection, gpointer data ){
532 PrefsDlg *dlg = (PrefsDlg*)data;
535 GtkTreeIter selected;
536 if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
537 ui::Widget prefpage{ui::null};
538 gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 );
539 dlg->showPrefPage( prefpage );
543 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
545 inline void PreferenceGroupCallbacks_constructGroup( const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group ){
546 for ( PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
553 inline void PreferenceGroupCallbacks_pushBack( PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback ){
554 callbacks.push_back( callback );
557 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
559 inline void PreferencesPageCallbacks_constructPage( const PreferencesPageCallbacks& callbacks, PreferencesPage& page ){
560 for ( PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
566 inline void PreferencesPageCallbacks_pushBack( PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback ){
567 callbacks.push_back( callback );
570 PreferencesPageCallbacks g_interfacePreferences;
571 void PreferencesDialog_addInterfacePreferences( const PreferencesPageCallback& callback ){
572 PreferencesPageCallbacks_pushBack( g_interfacePreferences, callback );
574 PreferenceGroupCallbacks g_interfaceCallbacks;
575 void PreferencesDialog_addInterfacePage( const PreferenceGroupCallback& callback ){
576 PreferenceGroupCallbacks_pushBack( g_interfaceCallbacks, callback );
579 PreferencesPageCallbacks g_displayPreferences;
580 void PreferencesDialog_addDisplayPreferences( const PreferencesPageCallback& callback ){
581 PreferencesPageCallbacks_pushBack( g_displayPreferences, callback );
583 PreferenceGroupCallbacks g_displayCallbacks;
584 void PreferencesDialog_addDisplayPage( const PreferenceGroupCallback& callback ){
585 PreferenceGroupCallbacks_pushBack( g_displayCallbacks, callback );
588 PreferencesPageCallbacks g_settingsPreferences;
589 void PreferencesDialog_addSettingsPreferences( const PreferencesPageCallback& callback ){
590 PreferencesPageCallbacks_pushBack( g_settingsPreferences, callback );
592 PreferenceGroupCallbacks g_settingsCallbacks;
593 void PreferencesDialog_addSettingsPage( const PreferenceGroupCallback& callback ){
594 PreferenceGroupCallbacks_pushBack( g_settingsCallbacks, callback );
597 void Widget_updateDependency( ui::Widget self, ui::Widget toggleButton ){
598 gtk_widget_set_sensitive( self, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggleButton ) ) && gtk_widget_is_sensitive( toggleButton ) );
601 void ToggleButton_toggled_Widget_updateDependency( ui::Widget toggleButton, ui::Widget self ){
602 Widget_updateDependency( self, toggleButton );
605 void ToggleButton_state_changed_Widget_updateDependency( ui::Widget toggleButton, GtkStateType state, ui::Widget self ){
606 if ( state == GTK_STATE_INSENSITIVE ) {
607 Widget_updateDependency( self, toggleButton );
611 void Widget_connectToggleDependency( ui::Widget self, ui::Widget toggleButton ){
612 toggleButton.connect( "state_changed", G_CALLBACK( ToggleButton_state_changed_Widget_updateDependency ), self );
613 toggleButton.connect( "toggled", G_CALLBACK( ToggleButton_toggled_Widget_updateDependency ), self );
614 Widget_updateDependency( self, toggleButton );
618 inline ui::VBox getVBox( ui::Bin page ){
619 return ui::VBox::from(gtk_bin_get_child(page));
622 GtkTreeIter PreferenceTree_appendPage( ui::TreeStore store, GtkTreeIter* parent, const char* name, ui::Widget page ){
624 gtk_tree_store_append( store, &group, parent );
625 gtk_tree_store_set( store, &group, 0, name, 1, page, -1 );
629 ui::Bin PreferencePages_addPage( ui::Widget notebook, const char* name ){
630 ui::Widget preflabel = ui::Label( name );
633 auto pageframe = ui::Frame( name );
634 gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 4 );
637 ui::Widget vbox = ui::VBox( FALSE, 4 );
639 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 4 );
642 // Add the page to the notebook
643 gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
648 class PreferenceTreeGroup : public PreferenceGroup
651 ui::Widget m_notebook;
652 ui::TreeStore m_store;
655 PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group ) :
657 m_notebook( notebook ),
661 PreferencesPage createPage( const char* treeName, const char* frameName ){
662 auto page = PreferencePages_addPage( m_notebook, frameName );
663 PreferenceTree_appendPage( m_store, &m_group, treeName, page );
664 return PreferencesPage( m_dialog, getVBox( page ) );
668 ui::Window PrefsDlg::BuildDialog(){
669 PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) );
670 //Mouse_registerPreferencesPage();
672 ui::Window dialog = ui::Window(create_floating_window( "NetRadiant Preferences", m_parent ));
675 auto mainvbox = ui::VBox( FALSE, 5 );
676 dialog.add(mainvbox);
677 gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 );
681 auto hbox = ui::HBox( FALSE, 5 );
683 mainvbox.pack_end(hbox, FALSE, TRUE, 0);
686 auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &m_modal );
687 hbox.pack_end(button, FALSE, FALSE, 0);
690 auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &m_modal );
691 hbox.pack_end(button, FALSE, FALSE, 0);
694 auto button = create_dialog_button( "Clean", G_CALLBACK( OnButtonClean ), this );
695 hbox.pack_end(button, FALSE, FALSE, 0);
700 auto hbox = ui::HBox( FALSE, 5 );
701 mainvbox.pack_start( hbox, TRUE, TRUE, 0 );
705 auto sc_win = ui::ScrolledWindow(ui::New);
706 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_win ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
707 hbox.pack_start( sc_win, FALSE, FALSE, 0 );
709 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN );
711 // prefs pages notebook
712 m_notebook = ui::Widget::from(gtk_notebook_new());
713 // hide the notebook tabs since its not supposed to look like a notebook
714 gtk_notebook_set_show_tabs( GTK_NOTEBOOK( m_notebook ), FALSE );
715 hbox.pack_start( m_notebook, TRUE, TRUE, 0 );
720 auto store = ui::TreeStore::from(gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER ));
722 auto view = ui::TreeView(ui::TreeModel::from(store._handle));
723 gtk_tree_view_set_headers_visible(view, FALSE );
726 auto renderer = ui::CellRendererText(ui::New);
727 auto column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} );
728 gtk_tree_view_append_column(view, column );
732 auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view));
733 selection.connect( "changed", G_CALLBACK( treeSelection ), this );
741 /********************************************************************/
742 /* Add preference tree options */
743 /********************************************************************/
746 PreferencePages_addPage( m_notebook, "Front Page" );
749 auto global = PreferencePages_addPage( m_notebook, "Global Preferences" );
751 PreferencesPage preferencesPage( *this, getVBox( global ) );
752 Global_constructPreferences( preferencesPage );
754 auto group = PreferenceTree_appendPage( store, 0, "Global", global );
756 auto game = PreferencePages_addPage( m_notebook, "Game" );
757 PreferencesPage preferencesPage( *this, getVBox( game ) );
758 g_GamesDialog.CreateGlobalFrame( preferencesPage );
760 PreferenceTree_appendPage( store, &group, "Game", game );
765 auto interfacePage = PreferencePages_addPage( m_notebook, "Interface Preferences" );
767 PreferencesPage preferencesPage( *this, getVBox( interfacePage ) );
768 PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage );
771 auto group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage );
772 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
774 PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup );
778 auto display = PreferencePages_addPage( m_notebook, "Display Preferences" );
780 PreferencesPage preferencesPage( *this, getVBox( display ) );
781 PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage );
783 auto group = PreferenceTree_appendPage( store, 0, "Display", display );
784 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
786 PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup );
790 auto settings = PreferencePages_addPage( m_notebook, "General Settings" );
792 PreferencesPage preferencesPage( *this, getVBox( settings ) );
793 PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage );
796 auto group = PreferenceTree_appendPage( store, 0, "Settings", settings );
797 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
799 PreferenceGroupCallbacks_constructGroup( g_settingsCallbacks, preferenceGroup );
803 gtk_tree_view_expand_all(view );
805 g_object_unref( G_OBJECT( store ) );
811 gtk_notebook_set_current_page( GTK_NOTEBOOK( m_notebook ), 0 );
816 preferences_globals_t g_preferences_globals;
818 PrefsDlg g_Preferences; // global prefs instance
821 void PreferencesDialog_constructWindow( ui::Window main_window ){
822 g_Preferences.m_parent = main_window;
823 g_Preferences.Create();
825 void PreferencesDialog_destroyWindow(){
826 g_Preferences.Destroy();
830 PreferenceDictionary g_preferences;
832 PreferenceSystem& GetPreferenceSystem(){
833 return g_preferences;
836 class PreferenceSystemAPI
838 PreferenceSystem* m_preferencesystem;
840 typedef PreferenceSystem Type;
841 STRING_CONSTANT( Name, "*" );
843 PreferenceSystemAPI(){
844 m_preferencesystem = &GetPreferenceSystem();
846 PreferenceSystem* getTable(){
847 return m_preferencesystem;
851 #include "modulesystem/singletonmodule.h"
852 #include "modulesystem/moduleregistry.h"
854 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
855 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
856 StaticRegisterModule staticRegisterPreferenceSystem( StaticPreferenceSystemModule::instance() );
858 void Preferences_Load(){
859 g_GamesDialog.LoadPrefs();
861 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
863 if ( !Preferences_Load( g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str() ) ) {
864 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
868 void Preferences_Save(){
869 if ( g_preferences_globals.disable_ini ) {
873 g_GamesDialog.SavePrefs();
875 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
877 if ( !Preferences_Save_Safe( g_preferences, g_Preferences.m_inipath->str ) ) {
878 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
882 void Preferences_Reset(){
883 file_remove( g_Preferences.m_inipath->str );
887 void PrefsDlg::PostModal( EMessageBoxReturn code ){
888 if ( code == eIDOK ) {
894 std::vector<const char*> g_restart_required;
896 void PreferencesDialog_restartRequired( const char* staticName ){
897 g_restart_required.push_back( staticName );
900 void PreferencesDialog_showDialog(){
901 //if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) {
902 if ( g_Preferences.DoModal() == eIDOK ) {
903 if ( !g_restart_required.empty() ) {
904 StringOutputStream message( 256 );
905 message << "Preference changes require a restart:\n";
906 for ( std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i )
908 message << ( *i ) << '\n';
910 ui::alert( MainFrame_getWindow(), message.c_str() );
911 g_restart_required.clear();
917 static void Export(const Callback<void(const char *)> &returnz) {
918 returnz(gamename_get());
921 static void Import(const char *value) {
927 static void Export(const Callback<void(const char *)> &returnz) {
928 returnz(gamemode_get());
931 static void Import(const char *value) {
936 void RegisterPreferences( PreferenceSystem& preferences ){
937 preferences.registerPreference( "CustomShaderEditorCommand", make_property_string( g_TextEditor_editorCommand ) );
939 preferences.registerPreference( "GameName", make_property<GameName>() );
940 preferences.registerPreference( "GameMode", make_property<GameMode>() );
943 void Preferences_Init(){
944 RegisterPreferences( GetPreferenceSystem() );