X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fpreferences.cpp;h=e57380eb1f3a32e071501d901b365762cb4fb417;hb=832101b1611ef0ae21f2b0bc9854ee8481727b89;hp=7d21c16ce6e022cb376b821531ade78728dd76b6;hpb=f0350b355f68497312c517c1bfd1fc216c722992;p=xonotic%2Fnetradiant.git diff --git a/radiant/preferences.cpp b/radiant/preferences.cpp index 7d21c16c..e57380eb 100644 --- a/radiant/preferences.cpp +++ b/radiant/preferences.cpp @@ -81,7 +81,7 @@ void Mouse_constructPage( PreferenceGroup& group ){ Mouse_constructPreferences( page ); } void Mouse_registerPreferencesPage(){ - PreferencesDialog_addInterfacePage( FreeCaller1() ); + PreferencesDialog_addInterfacePage( makeCallbackF(Mouse_constructPage) ); } @@ -121,7 +121,7 @@ CGameDescription::CGameDescription( xmlDocPtr pDoc, const CopiedString& gameFile { StringOutputStream path( 256 ); - path << AppPath_get() << gameFile.c_str() << "/"; + path << DataPath_get() << "gamepacks/" << gameFile.c_str() << "/"; mGameToolsPath = path.c_str(); } @@ -204,30 +204,32 @@ bool Preferences_Save( PreferenceDictionary& preferences, const char* filename ) } bool Preferences_Save_Safe( PreferenceDictionary& preferences, const char* filename ){ - Array tmpName( filename, filename + strlen( filename ) + 1 + 3 ); - *( tmpName.end() - 4 ) = 'T'; - *( tmpName.end() - 3 ) = 'M'; - *( tmpName.end() - 2 ) = 'P'; - *( tmpName.end() - 1 ) = '\0'; + std::string tmpName( filename ); + tmpName += "TMP"; - return Preferences_Save( preferences, tmpName.data() ) + return Preferences_Save( preferences, tmpName.c_str() ) && ( !file_exists( filename ) || file_remove( filename ) ) && file_move( tmpName.data(), filename ); } +struct LogConsole { + static void Export(const Callback &returnz) { + returnz(g_Console_enableLogging); + } -void LogConsole_importString( const char* string ){ - g_Console_enableLogging = string_equal( string, "true" ); - Sys_LogFile( g_Console_enableLogging ); -} -typedef FreeCaller1 LogConsoleImportStringCaller; + static void Import(bool value) { + g_Console_enableLogging = value; + Sys_LogFile(g_Console_enableLogging); + } +}; void RegisterGlobalPreferences( PreferenceSystem& preferences ){ - preferences.registerPreference( "gamefile", CopiedStringImportStringCaller( g_GamesDialog.m_sGameFile ), CopiedStringExportStringCaller( g_GamesDialog.m_sGameFile ) ); - preferences.registerPreference( "gamePrompt", BoolImportStringCaller( g_GamesDialog.m_bGamePrompt ), BoolExportStringCaller( g_GamesDialog.m_bGamePrompt ) ); - preferences.registerPreference( "log console", LogConsoleImportStringCaller(), BoolExportStringCaller( g_Console_enableLogging ) ); + preferences.registerPreference( "gamefile", make_property_string( g_GamesDialog.m_sGameFile ) ); + preferences.registerPreference( "gamePrompt", make_property_string( g_GamesDialog.m_bGamePrompt ) ); + preferences.registerPreference( "skipGamePromptOnce", make_property_string( g_GamesDialog.m_bSkipGamePromptOnce ) ); + preferences.registerPreference( "log console", make_property_string() ); } @@ -277,10 +279,21 @@ void CGameDialog::GameFileImport( int value ){ { ++iGame; } - m_sGameFile = ( *iGame )->mGameFile; + + if ( ( *iGame )->mGameFile != m_sGameFile ) { + m_sGameFile = ( *iGame )->mGameFile; + + // do not trigger radiant restart when switching game on startup using Global Preferences dialog + if ( !onStartup ) { + PreferencesDialog_restartRequired( "Selected Game" ); + } + } + + // onStartup can only be true once, when Global Preferences are displayed at startup + onStartup = false; } -void CGameDialog::GameFileExport( const IntImportCallback& importCallback ) const { +void CGameDialog::GameFileExport( const Callback & importCallback ) const { // use m_sGameFile to set value std::list::const_iterator iGame; int i = 0; @@ -295,13 +308,15 @@ void CGameDialog::GameFileExport( const IntImportCallback& importCallback ) cons importCallback( m_nComboSelect ); } -void CGameDialog_GameFileImport( CGameDialog& self, int value ){ - self.GameFileImport( value ); -} +struct CGameDialog_GameFile { + static void Export(const CGameDialog &self, const Callback &returnz) { + self.GameFileExport(returnz); + } -void CGameDialog_GameFileExport( CGameDialog& self, const IntImportCallback& importCallback ){ - self.GameFileExport( importCallback ); -} + static void Import(CGameDialog &self, int value) { + self.GameFileImport(value); + } +}; void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){ std::vector games; @@ -313,8 +328,7 @@ void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){ page.appendCombo( "Select the game", StringArrayRange( &( *games.begin() ), &( *games.end() ) ), - ReferenceCaller1( *this ), - ReferenceCaller1( *this ) + make_property(*this) ); page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt ); } @@ -334,36 +348,9 @@ ui::Window CGameDialog::BuildDialog(){ return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame ); } -class LoadGameFile -{ -std::list& mGames; -const char* mPath; -public: -LoadGameFile( std::list& games, const char* path ) : mGames( games ), mPath( path ){ -} -void operator()( const char* name ) const { - if ( !extension_equal( path_get_extension( name ), "game" ) ) { - return; - } - StringOutputStream strPath( 256 ); - strPath << mPath << name; - globalOutputStream() << strPath.c_str() << '\n'; - - xmlDocPtr pDoc = xmlParseFile( strPath.c_str() ); - if ( pDoc ) { - mGames.push_front( new CGameDescription( pDoc, name ) ); - xmlFreeDoc( pDoc ); - } - else - { - globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n"; - } -} -}; - void CGameDialog::ScanForGames(){ StringOutputStream strGamesPath( 256 ); - strGamesPath << AppPath_get() << "games/"; + strGamesPath << DataPath_get() << "gamepacks/games/"; const char *path = strGamesPath.c_str(); globalOutputStream() << "Scanning for game description files: " << path << '\n'; @@ -377,7 +364,22 @@ void CGameDialog::ScanForGames(){ (if that's really needed) */ - Directory_forEach( path, LoadGameFile( mGames, path ) ); + Directory_forEach(path, [&](const char *name) { + if (!extension_equal(path_get_extension(name), "game")) { + return; + } + StringOutputStream strPath(256); + strPath << path << name; + globalOutputStream() << strPath.c_str() << '\n'; + + xmlDocPtr pDoc = xmlParseFile(strPath.c_str()); + if (pDoc) { + mGames.push_front(new CGameDescription(pDoc, name)); + xmlFreeDoc(pDoc); + } else { + globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n"; + } + }); } CGameDescription* CGameDialog::GameDescriptionForComboItem(){ @@ -406,9 +408,12 @@ void CGameDialog::Reset(){ } void CGameDialog::Init(){ + bool gamePrompt = false; + InitGlobalPrefPath(); LoadPrefs(); ScanForGames(); + if ( mGames.empty() ) { Error( "Didn't find any valid game file descriptions, aborting\n" ); } @@ -429,7 +434,15 @@ void CGameDialog::Init(){ CGameDescription* currentGameDescription = 0; - if ( !m_bGamePrompt ) { + // m_bSkipGamePromptOnce is used to not prompt for game on restart, only on fresh startup + if ( m_bGamePrompt && !m_bSkipGamePromptOnce ) { + gamePrompt = true; + } + + m_bSkipGamePromptOnce = false; + g_GamesDialog.SavePrefs(); + + if ( !gamePrompt ) { // search by .game name std::list::iterator iGame; for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame ) @@ -440,13 +453,19 @@ void CGameDialog::Init(){ } } } - if ( m_bGamePrompt || !currentGameDescription ) { + + if ( gamePrompt || !currentGameDescription ) { + onStartup = true; Create(); DoGameDialog(); // use m_nComboSelect to identify the game to run as and set the globals currentGameDescription = GameDescriptionForComboItem(); ASSERT_NOTNULL( currentGameDescription ); } + else { + onStartup = false; + } + g_pGameDescription = currentGameDescription; g_pGameDescription->Dump(); @@ -482,8 +501,8 @@ CGameDialog g_GamesDialog; static void OnButtonClean( ui::Widget widget, gpointer data ){ // make sure this is what the user wants - if ( g_Preferences.GetWidget().alert( "This will close Radiant and clean the corresponding registry entries.\n" - "Next time you start Radiant it will be good as new. Do you wish to continue?", + if ( ui::alert( g_Preferences.GetWidget(), "This will close " RADIANT_NAME " and clean the corresponding registry entries.\n" + "Next time you start " RADIANT_NAME " it will be good as new. Do you wish to continue?", "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) { PrefsDlg *dlg = (PrefsDlg*)data; dlg->EndModal( eIDCANCEL ); @@ -542,7 +561,7 @@ void PrefsDlg::showPrefPage( ui::Widget prefpage ){ return; } -static void treeSelection( GtkTreeSelection* selection, gpointer data ){ +static void treeSelection( ui::TreeSelection selection, gpointer data ){ PrefsDlg *dlg = (PrefsDlg*)data; GtkTreeModel* model; @@ -633,7 +652,7 @@ inline ui::VBox getVBox( ui::Bin page ){ return ui::VBox::from(gtk_bin_get_child(page)); } -GtkTreeIter PreferenceTree_appendPage( GtkTreeStore* store, GtkTreeIter* parent, const char* name, ui::Widget page ){ +GtkTreeIter PreferenceTree_appendPage( ui::TreeStore store, GtkTreeIter* parent, const char* name, ui::Widget page ){ GtkTreeIter group; gtk_tree_store_append( store, &group, parent ); gtk_tree_store_set( store, &group, 0, name, 1, page, -1 ); @@ -663,10 +682,10 @@ class PreferenceTreeGroup : public PreferenceGroup { Dialog& m_dialog; ui::Widget m_notebook; -GtkTreeStore* m_store; +ui::TreeStore m_store; GtkTreeIter m_group; public: -PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, GtkTreeStore* store, GtkTreeIter group ) : +PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group ) : m_dialog( dialog ), m_notebook( notebook ), m_store( store ), @@ -680,10 +699,13 @@ PreferencesPage createPage( const char* treeName, const char* frameName ){ }; ui::Window PrefsDlg::BuildDialog(){ - PreferencesDialog_addInterfacePreferences( FreeCaller1() ); + PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) ); Mouse_registerPreferencesPage(); - ui::Window dialog = ui::Window(create_floating_window( "NetRadiant Preferences", m_parent )); + ui::Window dialog = ui::Window(create_floating_window( RADIANT_NAME " Preferences", m_parent )); + + gtk_window_set_transient_for( dialog, m_parent ); + gtk_window_set_position( dialog, GTK_WIN_POS_CENTER_ON_PARENT ); { auto mainvbox = ui::VBox( FALSE, 5 ); @@ -723,7 +745,7 @@ ui::Window PrefsDlg::BuildDialog(){ gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN ); // prefs pages notebook - m_notebook = ui::Widget(gtk_notebook_new()); + m_notebook = ui::Widget::from(gtk_notebook_new()); // hide the notebook tabs since its not supposed to look like a notebook gtk_notebook_set_show_tabs( GTK_NOTEBOOK( m_notebook ), FALSE ); hbox.pack_start( m_notebook, TRUE, TRUE, 0 ); @@ -731,19 +753,19 @@ ui::Window PrefsDlg::BuildDialog(){ { - auto store = gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER ); + auto store = ui::TreeStore::from(gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER )); - ui::Widget view = ui::TreeView(ui::TreeModel( GTK_TREE_MODEL( store ) )); - gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE ); + auto view = ui::TreeView(ui::TreeModel::from(store._handle)); + gtk_tree_view_set_headers_visible(view, FALSE ); { auto renderer = ui::CellRendererText(ui::New); - GtkTreeViewColumn* column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} ); - gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column ); + auto column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} ); + gtk_tree_view_append_column(view, column ); } { - auto selection = ui::TreeSelection(gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) )); + auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view)); selection.connect( "changed", G_CALLBACK( treeSelection ), this ); } @@ -765,7 +787,7 @@ ui::Window PrefsDlg::BuildDialog(){ PreferencesPage preferencesPage( *this, getVBox( global ) ); Global_constructPreferences( preferencesPage ); } - GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Global", global ); + auto group = PreferenceTree_appendPage( store, 0, "Global", global ); { auto game = PreferencePages_addPage( m_notebook, "Game" ); PreferencesPage preferencesPage( *this, getVBox( game ) ); @@ -782,7 +804,7 @@ ui::Window PrefsDlg::BuildDialog(){ PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage ); } - GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage ); + auto group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage ); PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group ); PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup ); @@ -794,7 +816,7 @@ ui::Window PrefsDlg::BuildDialog(){ PreferencesPage preferencesPage( *this, getVBox( display ) ); PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage ); } - GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Display", display ); + auto group = PreferenceTree_appendPage( store, 0, "Display", display ); PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group ); PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup ); @@ -807,14 +829,14 @@ ui::Window PrefsDlg::BuildDialog(){ PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage ); } - GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Settings", settings ); + auto group = PreferenceTree_appendPage( store, 0, "Settings", settings ); PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group ); PreferenceGroupCallbacks_constructGroup( g_settingsCallbacks, preferenceGroup ); } } - gtk_tree_view_expand_all( GTK_TREE_VIEW( view ) ); + gtk_tree_view_expand_all(view ); g_object_unref( G_OBJECT( store ) ); } @@ -884,6 +906,7 @@ void Preferences_Save(){ return; } + // save global preferences g_GamesDialog.SavePrefs(); globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n"; @@ -915,50 +938,57 @@ void PreferencesDialog_showDialog(){ if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) { if ( !g_restart_required.empty() ) { StringOutputStream message( 256 ); - message << "Preference changes require a restart:\n"; + message << "Preference changes require a restart:\n\n"; + for ( std::vector::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i ) { message << ( *i ) << '\n'; } - MainFrame_getWindow().alert( message.c_str() ); + + message << "\nRestart now?"; + + auto ret = ui::alert( MainFrame_getWindow(), message.c_str(), "Restart " RADIANT_NAME "?", ui::alert_type::YESNO, ui::alert_icon::Question ); + g_restart_required.clear(); + + if ( ret == ui::alert_response::YES ) { + g_GamesDialog.m_bSkipGamePromptOnce = true; + Radiant_Restart(); + } } } } +struct GameName { + static void Export(const Callback &returnz) { + returnz(gamename_get()); + } + static void Import(const char *value) { + gamename_set(value); + } +}; +struct GameMode { + static void Export(const Callback &returnz) { + returnz(gamemode_get()); + } - -void GameName_importString( const char* value ){ - gamename_set( value ); -} -typedef FreeCaller1 GameNameImportStringCaller; -void GameName_exportString( const StringImportCallback& importer ){ - importer( gamename_get() ); -} -typedef FreeCaller1 GameNameExportStringCaller; - -void GameMode_importString( const char* value ){ - gamemode_set( value ); -} -typedef FreeCaller1 GameModeImportStringCaller; -void GameMode_exportString( const StringImportCallback& importer ){ - importer( gamemode_get() ); -} -typedef FreeCaller1 GameModeExportStringCaller; - + static void Import(const char *value) { + gamemode_set(value); + } +}; void RegisterPreferences( PreferenceSystem& preferences ){ #if GDEF_OS_WINDOWS - preferences.registerPreference( "UseCustomShaderEditor", BoolImportStringCaller( g_TextEditor_useWin32Editor ), BoolExportStringCaller( g_TextEditor_useWin32Editor ) ); + preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) ); #else - preferences.registerPreference( "UseCustomShaderEditor", BoolImportStringCaller( g_TextEditor_useCustomEditor ), BoolExportStringCaller( g_TextEditor_useCustomEditor ) ); - preferences.registerPreference( "CustomShaderEditorCommand", CopiedStringImportStringCaller( g_TextEditor_editorCommand ), CopiedStringExportStringCaller( g_TextEditor_editorCommand ) ); + preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useCustomEditor ) ); + preferences.registerPreference( "CustomShaderEditorCommand", make_property_string( g_TextEditor_editorCommand ) ); #endif - preferences.registerPreference( "GameName", GameNameImportStringCaller(), GameNameExportStringCaller() ); - preferences.registerPreference( "GameMode", GameModeImportStringCaller(), GameModeExportStringCaller() ); + preferences.registerPreference( "GameName", make_property() ); + preferences.registerPreference( "GameMode", make_property() ); } void Preferences_Init(){