]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/preferences.cpp
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / radiant / preferences.cpp
index 091a88f36324bb884e4c203bebe28b374995a009..53e3fa80c1f0d35a429d5e32f972cdd5f7de43e5 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
    For a list of contributors, see the accompanying CONTRIBUTORS file.
 
@@ -58,23 +58,16 @@ void Global_constructPreferences( PreferencesPage& page ){
 }
 
 void Interface_constructPreferences( PreferencesPage& page ){
-#if GDEF_OS_WINDOWS
-       page.appendCheckBox( "", "Default Text Editor", g_TextEditor_useWin32Editor );
-#else
-       {
-               ui::CheckButton use_custom = page.appendCheckBox( "Text Editor", "Custom", g_TextEditor_useCustomEditor );
-               ui::Widget custom_editor = page.appendPathEntry( "Text Editor Command", g_TextEditor_editorCommand, true );
-               Widget_connectToggleDependency( custom_editor, use_custom );
-       }
-#endif
+       page.appendPathEntry( "Shader Editor Command", g_TextEditor_editorCommand, false );
 }
 
 void Mouse_constructPreferences( PreferencesPage& page ){
-       {
-               const char* buttons[] = { "2 button", "3 button", };
-               page.appendRadio( "Mouse Type",  g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE( buttons ) );
-       }
-       page.appendCheckBox( "Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick );
+//     {
+//             const char* buttons[] = { "2 button", "3 button", };
+//             page.appendRadio( "Mouse Type",  g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE( buttons ) );
+//     }
+//     page.appendCheckBox( "Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick );
+       page.appendCheckBox( "", "Zoom to mouse pointer", g_xywindow_globals.m_bZoomInToPointer );
 }
 void Mouse_constructPage( PreferenceGroup& group ){
        PreferencesPage page( group.createPage( "Mouse", "Mouse Preferences" ) );
@@ -106,7 +99,7 @@ CGameDescription::CGameDescription( xmlDocPtr pDoc, const CopiedString& gameFile
        // read the user-friendly game name
        xmlNodePtr pNode = pDoc->children;
 
-       while ( strcmp( (const char*)pNode->name, "game" ) && pNode != 0 )
+       while ( pNode != 0 && strcmp( (const char*)pNode->name, "game" ) )
        {
                pNode = pNode->next;
        }
@@ -121,7 +114,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,13 +197,10 @@ bool Preferences_Save( PreferenceDictionary& preferences, const char* filename )
 }
 
 bool Preferences_Save_Safe( PreferenceDictionary& preferences, const char* filename ){
-       Array<char> 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 );
 }
@@ -223,7 +213,7 @@ struct LogConsole {
 
        static void Import(bool value) {
                g_Console_enableLogging = value;
-               Sys_LogFile(g_Console_enableLogging);
+               Sys_EnableLogFile(g_Console_enableLogging);
        }
 };
 
@@ -231,6 +221,7 @@ struct LogConsole {
 void RegisterGlobalPreferences( PreferenceSystem& preferences ){
        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<LogConsole>() );
 }
 
@@ -281,7 +272,18 @@ void CGameDialog::GameFileImport( int value ){
        {
                ++iGame;
        }
+
+       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 Callback<void(int)> & importCallback ) const {
@@ -339,9 +341,33 @@ ui::Window CGameDialog::BuildDialog(){
        return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame );
 }
 
+static void StringReplace( std::string& input, const std::string& first, const std::string& second )
+{
+       size_t found = 0;
+       while ( ( found = input.find(first, found) ) != std::string::npos )
+       {
+               input.replace( found, first.length(), second );
+       }
+}
+
+// FIXME, for some unknown reason it sorts “Quake 3” after “Quake 4”.
+static bool CompareGameName( CGameDescription *first, CGameDescription *second )
+{
+       std::string string1( first->getRequiredKeyValue( "name" ) );
+       std::string string2( second->getRequiredKeyValue( "name" ) );
+
+       // HACK: Replace some roman numerals.
+       StringReplace( string1, " III", " 3" );
+       StringReplace( string2, " III", " 3" );
+       StringReplace( string1, " II", " 2" );
+       StringReplace( string2, " II", " 2" );
+
+       return string1 < string2;
+}
+
 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';
@@ -370,6 +396,8 @@ void CGameDialog::ScanForGames(){
                } else {
                        globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
                }
+
+               mGames.sort(CompareGameName);
        });
 }
 
@@ -399,9 +427,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" );
        }
@@ -422,7 +453,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<CGameDescription *>::iterator iGame;
                for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
@@ -433,13 +472,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();
@@ -475,8 +520,8 @@ CGameDialog g_GamesDialog;
 
 static void OnButtonClean( ui::Widget widget, gpointer data ){
        // make sure this is what the user wants
-       if ( ui::alert( g_Preferences.GetWidget(), "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 );
@@ -674,9 +719,12 @@ PreferencesPage createPage( const char* treeName, const char* frameName ){
 
 ui::Window PrefsDlg::BuildDialog(){
        PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) );
-       Mouse_registerPreferencesPage();
+       //Mouse_registerPreferencesPage();
+
+       ui::Window dialog = ui::Window(create_floating_window( RADIANT_NAME " Preferences", m_parent ));
 
-       ui::Window dialog = ui::Window(create_floating_window( "NetRadiant 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 );
@@ -877,6 +925,7 @@ void Preferences_Save(){
                return;
        }
 
+       // save global preferences
        g_GamesDialog.SavePrefs();
 
        globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
@@ -904,21 +953,39 @@ void PreferencesDialog_restartRequired( const char* staticName ){
        g_restart_required.push_back( staticName );
 }
 
-void PreferencesDialog_showDialog(){
-       if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) {
+bool PreferencesDialog_isRestartRequired(){
+       return !g_restart_required.empty();
+}
+
+void PreferencesDialog_restartIfRequired(){
                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<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i )
                        {
                                message << ( *i ) << '\n';
                        }
-                       ui::alert( MainFrame_getWindow(), 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();
                }
        }
 }
 
+void PreferencesDialog_showDialog(){
+       if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) {
+               PreferencesDialog_restartIfRequired();
+       }
+}
+
 struct GameName {
        static void Export(const Callback<void(const char *)> &returnz) {
                returnz(gamename_get());
@@ -940,12 +1007,7 @@ struct GameMode {
 };
 
 void RegisterPreferences( PreferenceSystem& preferences ){
-#if GDEF_OS_WINDOWS
-       preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) );
-#else
-       preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useCustomEditor ) );
        preferences.registerPreference( "CustomShaderEditorCommand", make_property_string( g_TextEditor_editorCommand ) );
-#endif
 
        preferences.registerPreference( "GameName", make_property<GameName>() );
        preferences.registerPreference( "GameMode", make_property<GameMode>() );