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 void LogConsole_importString( const char* string ){
221 g_Console_enableLogging = string_equal( string, "true" );
222 Sys_LogFile( g_Console_enableLogging );
224 typedef FreeCaller<void(const char*), LogConsole_importString> LogConsoleImportStringCaller;
227 void RegisterGlobalPreferences( PreferenceSystem& preferences ){
228 preferences.registerPreference( "gamefile", CopiedStringImportStringCaller( g_GamesDialog.m_sGameFile ), CopiedStringExportStringCaller( g_GamesDialog.m_sGameFile ) );
229 preferences.registerPreference( "gamePrompt", BoolImportStringCaller( g_GamesDialog.m_bGamePrompt ), BoolExportStringCaller( g_GamesDialog.m_bGamePrompt ) );
230 preferences.registerPreference( "log console", LogConsoleImportStringCaller(), BoolExportStringCaller( g_Console_enableLogging ) );
234 PreferenceDictionary g_global_preferences;
236 void GlobalPreferences_Init(){
237 RegisterGlobalPreferences( g_global_preferences );
240 void CGameDialog::LoadPrefs(){
241 // load global .pref file
242 StringOutputStream strGlobalPref( 256 );
243 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
245 globalOutputStream() << "loading global preferences from " << makeQuoted( strGlobalPref.c_str() ) << "\n";
247 if ( !Preferences_Load( g_global_preferences, strGlobalPref.c_str(), "global" ) ) {
248 globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
252 void CGameDialog::SavePrefs(){
253 StringOutputStream strGlobalPref( 256 );
254 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
256 globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
258 if ( !Preferences_Save_Safe( g_global_preferences, strGlobalPref.c_str() ) ) {
259 globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
263 void CGameDialog::DoGameDialog(){
267 // we save the prefs file
271 void CGameDialog::GameFileImport( int value ){
272 m_nComboSelect = value;
273 // use value to set m_sGameFile
274 std::list<CGameDescription *>::iterator iGame = mGames.begin();
276 for ( i = 0; i < value; i++ )
280 m_sGameFile = ( *iGame )->mGameFile;
283 void CGameDialog::GameFileExport( const IntImportCallback& importCallback ) const {
284 // use m_sGameFile to set value
285 std::list<CGameDescription *>::const_iterator iGame;
287 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
289 if ( ( *iGame )->mGameFile == m_sGameFile ) {
295 importCallback( m_nComboSelect );
298 void CGameDialog_GameFileImport( CGameDialog& self, int value ){
299 self.GameFileImport( value );
302 void CGameDialog_GameFileExport( CGameDialog& self, const IntImportCallback& importCallback ){
303 self.GameFileExport( importCallback );
306 void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){
307 std::vector<const char*> games;
308 games.reserve( mGames.size() );
309 for ( std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i )
311 games.push_back( ( *i )->getRequiredKeyValue( "name" ) );
315 StringArrayRange( &( *games.begin() ), &( *games.end() ) ),
316 ReferenceCaller<CGameDialog, void(int), CGameDialog_GameFileImport>( *this ),
317 ReferenceCaller<CGameDialog, void(const IntImportCallback&), CGameDialog_GameFileExport>( *this )
319 page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt );
322 ui::Window CGameDialog::BuildDialog(){
323 auto frame = create_dialog_frame( "Game settings", ui::Shadow::ETCHED_IN );
325 auto vbox2 = create_dialog_vbox( 0, 4 );
329 PreferencesPage preferencesPage( *this, vbox2 );
330 Global_constructPreferences( preferencesPage );
331 CreateGlobalFrame( preferencesPage );
334 return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame );
337 void CGameDialog::ScanForGames(){
338 StringOutputStream strGamesPath( 256 );
339 strGamesPath << AppPath_get() << "games/";
340 const char *path = strGamesPath.c_str();
342 globalOutputStream() << "Scanning for game description files: " << path << '\n';
346 do we put game description files below AppPath, or in ~/.radiant
347 i.e. read only or read/write?
348 my guess .. readonly cause it's an install
349 we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
350 (if that's really needed)
353 Directory_forEach(path, [&](const char *name) {
354 if (!extension_equal(path_get_extension(name), "game")) {
357 StringOutputStream strPath(256);
358 strPath << path << name;
359 globalOutputStream() << strPath.c_str() << '\n';
361 xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
363 mGames.push_front(new CGameDescription(pDoc, name));
366 globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
371 CGameDescription* CGameDialog::GameDescriptionForComboItem(){
372 std::list<CGameDescription *>::iterator iGame;
374 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame,i++ )
376 if ( i == m_nComboSelect ) {
380 return 0; // not found
383 void CGameDialog::InitGlobalPrefPath(){
384 g_Preferences.m_global_rc_path = g_string_new( SettingsPath_get() );
387 void CGameDialog::Reset(){
388 if ( !g_Preferences.m_global_rc_path ) {
389 InitGlobalPrefPath();
391 StringOutputStream strGlobalPref( 256 );
392 strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
393 file_remove( strGlobalPref.c_str() );
396 void CGameDialog::Init(){
397 InitGlobalPrefPath();
400 if ( mGames.empty() ) {
401 Error( "Didn't find any valid game file descriptions, aborting\n" );
405 std::list<CGameDescription *>::iterator iGame, iPrevGame;
406 for ( iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame )
408 if ( iPrevGame != mGames.end() ) {
409 if ( strcmp( ( *iGame )->getRequiredKeyValue( "name" ), ( *iPrevGame )->getRequiredKeyValue( "name" ) ) < 0 ) {
410 CGameDescription *h = *iGame;
418 CGameDescription* currentGameDescription = 0;
420 if ( !m_bGamePrompt ) {
421 // search by .game name
422 std::list<CGameDescription *>::iterator iGame;
423 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
425 if ( ( *iGame )->mGameFile == m_sGameFile ) {
426 currentGameDescription = ( *iGame );
431 if ( m_bGamePrompt || !currentGameDescription ) {
434 // use m_nComboSelect to identify the game to run as and set the globals
435 currentGameDescription = GameDescriptionForComboItem();
436 ASSERT_NOTNULL( currentGameDescription );
438 g_pGameDescription = currentGameDescription;
440 g_pGameDescription->Dump();
443 CGameDialog::~CGameDialog(){
444 // free all the game descriptions
445 std::list<CGameDescription *>::iterator iGame;
446 for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
456 inline const char* GameDescription_getIdentifier( const CGameDescription& gameDescription ){
457 const char* identifier = gameDescription.getKeyValue( "index" );
458 if ( string_empty( identifier ) ) {
465 CGameDialog g_GamesDialog;
468 // =============================================================================
469 // Widget callbacks for PrefsDlg
471 static void OnButtonClean( ui::Widget widget, gpointer data ){
472 // make sure this is what the user wants
473 if ( g_Preferences.GetWidget().alert( "This will close Radiant and clean the corresponding registry entries.\n"
474 "Next time you start Radiant it will be good as new. Do you wish to continue?",
475 "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) {
476 PrefsDlg *dlg = (PrefsDlg*)data;
477 dlg->EndModal( eIDCANCEL );
479 g_preferences_globals.disable_ini = true;
485 // =============================================================================
491 very first prefs init deals with selecting the game and the game tools path
492 then we can load .ini stuff
494 using prefs / ini settings:
497 look in ~/.radiant/<version>/gamename
501 const char *PREFS_LOCAL_FILENAME = "local.pref";
503 void PrefsDlg::Init(){
504 // m_global_rc_path has been set above
505 // m_rc_path is for game specific preferences
506 // takes the form: global-pref-path/gamename/prefs-file
508 // this is common to win32 and Linux init now
509 m_rc_path = g_string_new( m_global_rc_path->str );
512 g_string_append( m_rc_path, g_pGameDescription->mGameFile.c_str() );
513 g_string_append( m_rc_path, "/" );
514 Q_mkdir( m_rc_path->str );
517 m_inipath = g_string_new( m_rc_path->str );
518 g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
521 void notebook_set_page( ui::Widget notebook, ui::Widget page ){
522 int pagenum = gtk_notebook_page_num( GTK_NOTEBOOK( notebook ), page );
523 if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != pagenum ) {
524 gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook ), pagenum );
528 void PrefsDlg::showPrefPage( ui::Widget prefpage ){
529 notebook_set_page( m_notebook, prefpage );
533 static void treeSelection( ui::TreeSelection selection, gpointer data ){
534 PrefsDlg *dlg = (PrefsDlg*)data;
537 GtkTreeIter selected;
538 if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
539 ui::Widget prefpage{ui::null};
540 gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 );
541 dlg->showPrefPage( prefpage );
545 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
547 inline void PreferenceGroupCallbacks_constructGroup( const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group ){
548 for ( PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
555 inline void PreferenceGroupCallbacks_pushBack( PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback ){
556 callbacks.push_back( callback );
559 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
561 inline void PreferencesPageCallbacks_constructPage( const PreferencesPageCallbacks& callbacks, PreferencesPage& page ){
562 for ( PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
568 inline void PreferencesPageCallbacks_pushBack( PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback ){
569 callbacks.push_back( callback );
572 PreferencesPageCallbacks g_interfacePreferences;
573 void PreferencesDialog_addInterfacePreferences( const PreferencesPageCallback& callback ){
574 PreferencesPageCallbacks_pushBack( g_interfacePreferences, callback );
576 PreferenceGroupCallbacks g_interfaceCallbacks;
577 void PreferencesDialog_addInterfacePage( const PreferenceGroupCallback& callback ){
578 PreferenceGroupCallbacks_pushBack( g_interfaceCallbacks, callback );
581 PreferencesPageCallbacks g_displayPreferences;
582 void PreferencesDialog_addDisplayPreferences( const PreferencesPageCallback& callback ){
583 PreferencesPageCallbacks_pushBack( g_displayPreferences, callback );
585 PreferenceGroupCallbacks g_displayCallbacks;
586 void PreferencesDialog_addDisplayPage( const PreferenceGroupCallback& callback ){
587 PreferenceGroupCallbacks_pushBack( g_displayCallbacks, callback );
590 PreferencesPageCallbacks g_settingsPreferences;
591 void PreferencesDialog_addSettingsPreferences( const PreferencesPageCallback& callback ){
592 PreferencesPageCallbacks_pushBack( g_settingsPreferences, callback );
594 PreferenceGroupCallbacks g_settingsCallbacks;
595 void PreferencesDialog_addSettingsPage( const PreferenceGroupCallback& callback ){
596 PreferenceGroupCallbacks_pushBack( g_settingsCallbacks, callback );
599 void Widget_updateDependency( ui::Widget self, ui::Widget toggleButton ){
600 gtk_widget_set_sensitive( self, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggleButton ) ) && gtk_widget_is_sensitive( toggleButton ) );
603 void ToggleButton_toggled_Widget_updateDependency( ui::Widget toggleButton, ui::Widget self ){
604 Widget_updateDependency( self, toggleButton );
607 void ToggleButton_state_changed_Widget_updateDependency( ui::Widget toggleButton, GtkStateType state, ui::Widget self ){
608 if ( state == GTK_STATE_INSENSITIVE ) {
609 Widget_updateDependency( self, toggleButton );
613 void Widget_connectToggleDependency( ui::Widget self, ui::Widget toggleButton ){
614 toggleButton.connect( "state_changed", G_CALLBACK( ToggleButton_state_changed_Widget_updateDependency ), self );
615 toggleButton.connect( "toggled", G_CALLBACK( ToggleButton_toggled_Widget_updateDependency ), self );
616 Widget_updateDependency( self, toggleButton );
620 inline ui::VBox getVBox( ui::Bin page ){
621 return ui::VBox::from(gtk_bin_get_child(page));
624 GtkTreeIter PreferenceTree_appendPage( ui::TreeStore store, GtkTreeIter* parent, const char* name, ui::Widget page ){
626 gtk_tree_store_append( store, &group, parent );
627 gtk_tree_store_set( store, &group, 0, name, 1, page, -1 );
631 ui::Bin PreferencePages_addPage( ui::Widget notebook, const char* name ){
632 ui::Widget preflabel = ui::Label( name );
635 auto pageframe = ui::Frame( name );
636 gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 4 );
639 ui::Widget vbox = ui::VBox( FALSE, 4 );
641 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 4 );
644 // Add the page to the notebook
645 gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
650 class PreferenceTreeGroup : public PreferenceGroup
653 ui::Widget m_notebook;
654 ui::TreeStore m_store;
657 PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group ) :
659 m_notebook( notebook ),
663 PreferencesPage createPage( const char* treeName, const char* frameName ){
664 auto page = PreferencePages_addPage( m_notebook, frameName );
665 PreferenceTree_appendPage( m_store, &m_group, treeName, page );
666 return PreferencesPage( m_dialog, getVBox( page ) );
670 ui::Window PrefsDlg::BuildDialog(){
671 PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) );
672 Mouse_registerPreferencesPage();
674 ui::Window dialog = ui::Window(create_floating_window( "NetRadiant Preferences", m_parent ));
677 auto mainvbox = ui::VBox( FALSE, 5 );
678 dialog.add(mainvbox);
679 gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 );
683 auto hbox = ui::HBox( FALSE, 5 );
685 mainvbox.pack_end(hbox, FALSE, TRUE, 0);
688 auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &m_modal );
689 hbox.pack_end(button, FALSE, FALSE, 0);
692 auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &m_modal );
693 hbox.pack_end(button, FALSE, FALSE, 0);
696 auto button = create_dialog_button( "Clean", G_CALLBACK( OnButtonClean ), this );
697 hbox.pack_end(button, FALSE, FALSE, 0);
702 auto hbox = ui::HBox( FALSE, 5 );
703 mainvbox.pack_start( hbox, TRUE, TRUE, 0 );
707 auto sc_win = ui::ScrolledWindow(ui::New);
708 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_win ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
709 hbox.pack_start( sc_win, FALSE, FALSE, 0 );
711 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN );
713 // prefs pages notebook
714 m_notebook = ui::Widget(gtk_notebook_new());
715 // hide the notebook tabs since its not supposed to look like a notebook
716 gtk_notebook_set_show_tabs( GTK_NOTEBOOK( m_notebook ), FALSE );
717 hbox.pack_start( m_notebook, TRUE, TRUE, 0 );
722 auto store = ui::TreeStore(gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER ));
724 auto view = ui::TreeView(ui::TreeModel(store));
725 gtk_tree_view_set_headers_visible(view, FALSE );
728 auto renderer = ui::CellRendererText(ui::New);
729 auto column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} );
730 gtk_tree_view_append_column(view, column );
734 auto selection = ui::TreeSelection(gtk_tree_view_get_selection(view ));
735 selection.connect( "changed", G_CALLBACK( treeSelection ), this );
743 /********************************************************************/
744 /* Add preference tree options */
745 /********************************************************************/
748 PreferencePages_addPage( m_notebook, "Front Page" );
751 auto global = PreferencePages_addPage( m_notebook, "Global Preferences" );
753 PreferencesPage preferencesPage( *this, getVBox( global ) );
754 Global_constructPreferences( preferencesPage );
756 auto group = PreferenceTree_appendPage( store, 0, "Global", global );
758 auto game = PreferencePages_addPage( m_notebook, "Game" );
759 PreferencesPage preferencesPage( *this, getVBox( game ) );
760 g_GamesDialog.CreateGlobalFrame( preferencesPage );
762 PreferenceTree_appendPage( store, &group, "Game", game );
767 auto interfacePage = PreferencePages_addPage( m_notebook, "Interface Preferences" );
769 PreferencesPage preferencesPage( *this, getVBox( interfacePage ) );
770 PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage );
773 auto group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage );
774 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
776 PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup );
780 auto display = PreferencePages_addPage( m_notebook, "Display Preferences" );
782 PreferencesPage preferencesPage( *this, getVBox( display ) );
783 PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage );
785 auto group = PreferenceTree_appendPage( store, 0, "Display", display );
786 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
788 PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup );
792 auto settings = PreferencePages_addPage( m_notebook, "General Settings" );
794 PreferencesPage preferencesPage( *this, getVBox( settings ) );
795 PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage );
798 auto group = PreferenceTree_appendPage( store, 0, "Settings", settings );
799 PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
801 PreferenceGroupCallbacks_constructGroup( g_settingsCallbacks, preferenceGroup );
805 gtk_tree_view_expand_all(view );
807 g_object_unref( G_OBJECT( store ) );
813 gtk_notebook_set_current_page( GTK_NOTEBOOK( m_notebook ), 0 );
818 preferences_globals_t g_preferences_globals;
820 PrefsDlg g_Preferences; // global prefs instance
823 void PreferencesDialog_constructWindow( ui::Window main_window ){
824 g_Preferences.m_parent = main_window;
825 g_Preferences.Create();
827 void PreferencesDialog_destroyWindow(){
828 g_Preferences.Destroy();
832 PreferenceDictionary g_preferences;
834 PreferenceSystem& GetPreferenceSystem(){
835 return g_preferences;
838 class PreferenceSystemAPI
840 PreferenceSystem* m_preferencesystem;
842 typedef PreferenceSystem Type;
843 STRING_CONSTANT( Name, "*" );
845 PreferenceSystemAPI(){
846 m_preferencesystem = &GetPreferenceSystem();
848 PreferenceSystem* getTable(){
849 return m_preferencesystem;
853 #include "modulesystem/singletonmodule.h"
854 #include "modulesystem/moduleregistry.h"
856 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
857 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
858 StaticRegisterModule staticRegisterPreferenceSystem( StaticPreferenceSystemModule::instance() );
860 void Preferences_Load(){
861 g_GamesDialog.LoadPrefs();
863 globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
865 if ( !Preferences_Load( g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str() ) ) {
866 globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
870 void Preferences_Save(){
871 if ( g_preferences_globals.disable_ini ) {
875 g_GamesDialog.SavePrefs();
877 globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
879 if ( !Preferences_Save_Safe( g_preferences, g_Preferences.m_inipath->str ) ) {
880 globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
884 void Preferences_Reset(){
885 file_remove( g_Preferences.m_inipath->str );
889 void PrefsDlg::PostModal( EMessageBoxReturn code ){
890 if ( code == eIDOK ) {
896 std::vector<const char*> g_restart_required;
898 void PreferencesDialog_restartRequired( const char* staticName ){
899 g_restart_required.push_back( staticName );
902 void PreferencesDialog_showDialog(){
903 if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) {
904 if ( !g_restart_required.empty() ) {
905 StringOutputStream message( 256 );
906 message << "Preference changes require a restart:\n";
907 for ( std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i )
909 message << ( *i ) << '\n';
911 MainFrame_getWindow().alert( message.c_str() );
912 g_restart_required.clear();
921 void GameName_importString( const char* value ){
922 gamename_set( value );
924 typedef FreeCaller<void(const char*), GameName_importString> GameNameImportStringCaller;
925 void GameName_exportString( const StringImportCallback& importer ){
926 importer( gamename_get() );
928 typedef FreeCaller<void(const StringImportCallback&), GameName_exportString> GameNameExportStringCaller;
930 void GameMode_importString( const char* value ){
931 gamemode_set( value );
933 typedef FreeCaller<void(const char*), GameMode_importString> GameModeImportStringCaller;
934 void GameMode_exportString( const StringImportCallback& importer ){
935 importer( gamemode_get() );
937 typedef FreeCaller<void(const StringImportCallback&), GameMode_exportString> GameModeExportStringCaller;
940 void RegisterPreferences( PreferenceSystem& preferences ){
942 preferences.registerPreference( "UseCustomShaderEditor", BoolImportStringCaller( g_TextEditor_useWin32Editor ), BoolExportStringCaller( g_TextEditor_useWin32Editor ) );
944 preferences.registerPreference( "UseCustomShaderEditor", BoolImportStringCaller( g_TextEditor_useCustomEditor ), BoolExportStringCaller( g_TextEditor_useCustomEditor ) );
945 preferences.registerPreference( "CustomShaderEditorCommand", CopiedStringImportStringCaller( g_TextEditor_editorCommand ), CopiedStringExportStringCaller( g_TextEditor_editorCommand ) );
948 preferences.registerPreference( "GameName", GameNameImportStringCaller(), GameNameExportStringCaller() );
949 preferences.registerPreference( "GameMode", GameModeImportStringCaller(), GameModeExportStringCaller() );
952 void Preferences_Init(){
953 RegisterPreferences( GetPreferenceSystem() );