From 3e38eae7409f5ff79fb9e6b1b0329aeb3533403d Mon Sep 17 00:00:00 2001
From: TTimo <ttimo@ttimo.net>
Date: Sat, 12 Apr 2008 23:01:39 +0000
Subject: [PATCH] fix and improve the game selection and game configuration
 dialogs - added dir dialog, using GtkComboBox (added support for GtkComboBox
 too)

git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant@248 8a3a26a2-13c4-0310-b231-cf6edde360e5
---
 install/games/q2w/game.xlink        |   8 --
 install/games/q2w/synapse.config    |  59 -----------
 install/games/q3ut4/synapse.config  |  56 ----------
 install/games/quake3/synapse.config |  56 ----------
 install/games/ufoai/game.xlink      |   8 --
 install/games/ufoai/synapse.config  |  59 -----------
 libs/str.h                          |  23 ++--
 radiant/dialog.cpp                  |  18 +++-
 radiant/dialog.h                    |   3 +-
 radiant/preferences.cpp             | 159 +++++++++++++++++++++-------
 radiant/preferences.h               |   7 ++
 11 files changed, 152 insertions(+), 304 deletions(-)
 delete mode 100644 install/games/q2w/game.xlink
 delete mode 100644 install/games/q2w/synapse.config
 delete mode 100644 install/games/q3ut4/synapse.config
 delete mode 100644 install/games/quake3/synapse.config
 delete mode 100644 install/games/ufoai/game.xlink
 delete mode 100644 install/games/ufoai/synapse.config

diff --git a/install/games/q2w/game.xlink b/install/games/q2w/game.xlink
deleted file mode 100644
index 7edec14e..00000000
--- a/install/games/q2w/game.xlink
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
-<!-- generated by Radiant setup, modify at your own risks -->
-<!-- links for the Quake2World game pack -->
-<links>
-<item name="Quake2World Homepage" url="http://quake2world.net"/>
-<item name="MapCenter's GtkRadiant Forum" url="http://www.map-center.com/modules.php?name=Forums&amp;file=viewforum&amp;f=8"/>
-<item name="GtkRadiant Bugzilla - Report Bug" url="http://zerowing.idsoftware.com/bugzilla/index.cgi"/>
-</links>
diff --git a/install/games/q2w/synapse.config b/install/games/q2w/synapse.config
deleted file mode 100644
index f79728a5..00000000
--- a/install/games/q2w/synapse.config
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
-<!-- synapse XML configuration -->
-<synapseconfig>
-  <client name="core">
-    <api name="image">
-      tga jpg
-    </api>
-    <api name="VFS">
-      pak
-    </api>
-    <api name="shaders">
-      ufoai
-    </api>
-    <api name="map">
-      mapq2
-    </api>
-    <api name="eclass">
-      def
-    </api>
-    <api name="surfdialog">
-      ufoai
-    </api>
-    <api name="model">
-      md2 md3
-    </api>
-  </client>
-  <client name="image">
-    <api name="VFS">
-      pak
-    </api>
-  </client>
-  <client name="shaders">
-    <!-- NOTE: this is a SYN_PROVIDE -->
-    <api name="shaders">
-      ufoai
-    </api>
-    <api name="VFS">
-      pak
-    </api>
-  </client>
-  <client name="map">
-    <api name="shaders">
-      ufoai
-    </api>
-  </client>
-  <client name="xmap">
-    <api name="shaders">
-      ufoai
-    </api>
-  </client>
-  <client name="model">
-    <api name="shaders">
-      ufoai
-    </api>
-    <api name="VFS">
-      pak
-    </api>
-  </client>
-</synapseconfig>
diff --git a/install/games/q3ut4/synapse.config b/install/games/q3ut4/synapse.config
deleted file mode 100644
index 58800d49..00000000
--- a/install/games/q3ut4/synapse.config
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
-<!-- synapse XML configuration -->
-<synapseconfig>
-  <client name="core">
-    <api name="image">
-      tga jpg
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-    <api name="shaders">
-      quake3
-    </api>
-    <api name="map">
-      mapq3
-    </api>
-    <api name="eclass">
-      def
-    </api> 
-    <api name="surfdialog">
-      quake3
-    </api>
-  </client>
-  <client name="image">
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-  <client name="shaders">
-    <!-- NOTE: this is a SYN_PROVIDE -->
-    <api name="shaders">
-       quake3
-    </api>
-    <api name="VFS">
-       pk3
-    </api>
-  </client>
-  <client name="map">
-    <api name="shaders">
-      quake3
-    </api>
-  </client>
-  <client name="xmap">
-    <api name="shaders">
-      quake3
-    </api>
-  </client>
-  <client name="model">
-    <api name="shaders">
-      quake3
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-</synapseconfig>
diff --git a/install/games/quake3/synapse.config b/install/games/quake3/synapse.config
deleted file mode 100644
index 58800d49..00000000
--- a/install/games/quake3/synapse.config
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
-<!-- synapse XML configuration -->
-<synapseconfig>
-  <client name="core">
-    <api name="image">
-      tga jpg
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-    <api name="shaders">
-      quake3
-    </api>
-    <api name="map">
-      mapq3
-    </api>
-    <api name="eclass">
-      def
-    </api> 
-    <api name="surfdialog">
-      quake3
-    </api>
-  </client>
-  <client name="image">
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-  <client name="shaders">
-    <!-- NOTE: this is a SYN_PROVIDE -->
-    <api name="shaders">
-       quake3
-    </api>
-    <api name="VFS">
-       pk3
-    </api>
-  </client>
-  <client name="map">
-    <api name="shaders">
-      quake3
-    </api>
-  </client>
-  <client name="xmap">
-    <api name="shaders">
-      quake3
-    </api>
-  </client>
-  <client name="model">
-    <api name="shaders">
-      quake3
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-</synapseconfig>
diff --git a/install/games/ufoai/game.xlink b/install/games/ufoai/game.xlink
deleted file mode 100644
index 963598cc..00000000
--- a/install/games/ufoai/game.xlink
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
-<!-- generated by Radiant setup, modify at your own risks -->
-<links>
-<item name="UFO:AI Community site" url="http://ufoai.sourceforge.net"/>
-<item name="UFO:AI Project site" url="http://www.sourceforge.net/projects/ufoai"/>
-<item name="UFO:AI Tutorials site with mapping tutorials" url="http://ufoai.ninex.info/wiki/index.php/Mapping"/>
-<item name="GtkRadiant Bugzilla - Report Bug" url="http://zerowing.idsoftware.com/bugzilla/index.cgi"/>
-</links>
\ No newline at end of file
diff --git a/install/games/ufoai/synapse.config b/install/games/ufoai/synapse.config
deleted file mode 100644
index 814e51ce..00000000
--- a/install/games/ufoai/synapse.config
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
-<!-- synapse XML configuration -->
-<synapseconfig>
-  <client name="core">
-    <api name="image">
-      tga jpg
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-    <api name="shaders">
-      ufoai
-    </api>
-    <api name="map">
-      mapq2
-    </api>
-    <api name="eclass">
-      def
-    </api>
-    <api name="surfdialog">
-      ufoai
-    </api>
-    <api name="model">
-      md2
-    </api>
-  </client>
-  <client name="image">
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-  <client name="shaders">
-    <!-- NOTE: this is a SYN_PROVIDE -->
-    <api name="shaders">
-      ufoai
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-  <client name="map">
-    <api name="shaders">
-      ufoai
-    </api>
-  </client>
-  <client name="xmap">
-    <api name="shaders">
-      ufoai
-    </api>
-  </client>
-  <client name="model">
-    <api name="shaders">
-      ufoai
-    </api>
-    <api name="VFS">
-      pk3
-    </api>
-  </client>
-</synapseconfig>
diff --git a/libs/str.h b/libs/str.h
index 8cb8a716..bf0cd589 100644
--- a/libs/str.h
+++ b/libs/str.h
@@ -58,20 +58,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #define __StrDup Q_StrDup
 
-inline char* Q_StrDup(char* pStr)
-{
-  if (pStr == NULL)
-    pStr = "";
+inline char* Q_StrDup( char* _pStr ) {
+	const char* pStr = _pStr;
+	if ( pStr == NULL ) {		
+		pStr = "";
+	}
 
-  return strcpy(new char[strlen(pStr)+1], pStr); 
+	return strcpy( new char[ strlen( pStr ) + 1 ], pStr );
 }
 
-inline char* Q_StrDup(const char* pStr)
-{ 
-  if (pStr == NULL)
-    pStr = "";
+inline char* Q_StrDup( const char* pStr ) {
+	if ( pStr == NULL ) {
+		pStr = "";
+	}
 
-  return strcpy(new char[strlen(pStr)+1], pStr); 
+	return strcpy( new char[strlen(pStr)+1], pStr );
 }
 
 #if defined (__linux__) || defined (__APPLE__)
@@ -286,7 +287,6 @@ public:
     }
     else
     {
-      g_pStrWork = "";
       g_pStrWork = new char[1];
       g_pStrWork[0] = '\0';
     }
@@ -327,7 +327,6 @@ public:
     }
     else
     {
-      g_pStrWork = "";
       g_pStrWork = new char[1];
       g_pStrWork[0] = '\0';
     }
diff --git a/radiant/dialog.cpp b/radiant/dialog.cpp
index 4f71d41b..fb1263e4 100644
--- a/radiant/dialog.cpp
+++ b/radiant/dialog.cpp
@@ -196,7 +196,13 @@ void Dialog::UpdateData (bool retrieve)
               }
             i++;
             }
-          }	break;
+          }
+		  break;
+		case DLG_COMBO_BOX_INT: {
+			*(int*)data->buffer = gtk_combo_box_get_active( GTK_COMBO_BOX( data->object ) );
+		}
+			break;
+
         }
       }
     }
@@ -241,8 +247,7 @@ void Dialog::UpdateData (bool retrieve)
         case DLG_ADJ_INT:
           gtk_adjustment_set_value (GTK_ADJUSTMENT (data->object), (*(int*)data->buffer));
           break;
-        case DLG_COMBO_INT:
-          {
+        case DLG_COMBO_INT: {
           GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children;
           char *entry = "";
           
@@ -254,7 +259,12 @@ void Dialog::UpdateData (bool retrieve)
             }
           
           gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (data->object)->entry), entry);
-          }	break;
+          }
+		  break;
+		case DLG_COMBO_BOX_INT: {
+			gtk_combo_box_set_active( GTK_COMBO_BOX( data->object ), *(int*)data->buffer );
+		}
+			break;
         }
       }
     }
diff --git a/radiant/dialog.h b/radiant/dialog.h
index 46ed965a..cd00eff1 100644
--- a/radiant/dialog.h
+++ b/radiant/dialog.h
@@ -36,7 +36,8 @@ typedef enum
   DLG_SPIN_FLOAT,
   DLG_SPIN_INT,
   DLG_ADJ_INT,
-  DLG_COMBO_INT
+  DLG_COMBO_INT,
+  DLG_COMBO_BOX_INT,
 } DLG_DATA_TYPE;
 
 class Dialog
diff --git a/radiant/preferences.cpp b/radiant/preferences.cpp
index 4489205e..29aae8bb 100644
--- a/radiant/preferences.cpp
+++ b/radiant/preferences.cpp
@@ -966,11 +966,15 @@ void CGameDialog::SavePrefs()
   CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str;
   strGlobalPref += "global.pref";
   
-  if (!mGlobalPrefs.WriteXMLFile(strGlobalPref.GetBuffer()))
+  if ( !mGlobalPrefs.WriteXMLFile( strGlobalPref.GetBuffer() ) ) {
     Sys_FPrintf(SYS_ERR, "Error occured while saving global prefs file '%s'\n", strGlobalPref.GetBuffer());
+  }
 }
 
 void CGameDialog::DoGameInstall() {
+	// make sure console logging is on whenever we enter the installation loop
+    g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
+	Sys_LogFile();
 	mGameInstall.Run();
 }
 
@@ -980,7 +984,10 @@ void CGameDialog::DoGameDialog() {
 		
 		m_bDoGameInstall = false;
 
-		DoModal();
+		if ( DoModal() == IDCANCEL ) {
+			Error( "game selection dialog canceled, cannot continue" );
+			return;
+		}
 		
 		if ( m_bDoGameInstall ) {
 			DoGameInstall();
@@ -1018,20 +1025,13 @@ GtkWidget* CGameDialog::GetGlobalFrame()
   gtk_widget_show( text );
   gtk_box_pack_start( GTK_BOX( vbox ), text, FALSE, FALSE, 0 );
 
-  combo = gtk_combo_new();
+  combo = gtk_combo_box_new_text();
   gtk_widget_show( combo );
   gtk_box_pack_start( GTK_BOX( vbox ), combo, FALSE, FALSE, 0 );
+  AddDialogData( combo, &m_nComboSelect, DLG_COMBO_BOX_INT );
+  mGameCombo = GTK_COMBO_BOX( combo );
 
-  // fill in with the game descriptions
-  GList *combo_list = (GList*)NULL;
-  list<CGameDescription *>::iterator iGame;
-  for( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) {
-	  combo_list = g_list_append( combo_list, (void *)(*iGame)->mGameName.GetBuffer() );
-  }
-  gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list );
-  g_list_free( combo_list );
-
-  AddDialogData( combo, &m_nComboSelect, DLG_COMBO_INT );
+  UpdateGameCombo();
 
   check = gtk_check_button_new_with_label( "Auto load selected game on startup" );
   gtk_widget_show(check);
@@ -1125,10 +1125,38 @@ void CGameDialog::BuildDialog() {
 	gtk_widget_show( button );
 	gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
 	AddModalButton( button, IDOK );
+
+	button = gtk_button_new_with_label( "Cancel" );
+	gtk_widget_show( button );
+	gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
+	AddModalButton( button, IDCANCEL );
 	
 	gtk_widget_set_usize( button, 60, -2 );
 }
 
+void CGameDialog::UpdateGameCombo() {
+  // fill in with the game descriptions
+  list<CGameDescription *>::iterator iGame;
+
+  if ( mGameCombo == NULL ) {
+	  Sys_Printf( "mGameCombo == NULL\n" );
+	  return;
+  }
+
+  // clear whatever is in - wtf no way to know how many text entries?
+  // use set/get active to track 
+  gtk_combo_box_set_active( mGameCombo, 0 );
+  while ( gtk_combo_box_get_active( mGameCombo ) == 0 ) {
+	  gtk_combo_box_remove_text( mGameCombo, 0 );
+	  gtk_combo_box_set_active( mGameCombo, 0 );
+  }
+  
+  for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) {
+	  gtk_combo_box_append_text( mGameCombo, (*iGame)->mGameName.GetBuffer() );
+  }
+  gtk_combo_box_set_active( mGameCombo, 0 );
+}
+
 void CGameDialog::ScanForGames()
 {
   CString strPath;
@@ -1190,20 +1218,21 @@ void CGameDialog::ScanForGames()
         Sys_FPrintf(SYS_ERR, "XML parser failed on '%s'\n", strPath.GetBuffer());
       }
 
-      g_free(dirlist);
+      g_free( dirlist );
     }
-    g_dir_close (dir);
+    g_dir_close( dir );
   }
+
+  // entries in the combo need to be updated
+  UpdateGameCombo();
 }
 
 CGameDescription* CGameDialog::GameDescriptionForComboItem()
 {
   list<CGameDescription *>::iterator iGame;
   int i=0;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++,i++)
-  {
-    if (i == m_nComboSelect)
-    {
+  for( iGame = mGames.begin(); iGame != mGames.end(); iGame++,i++ ) {
+    if ( i == m_nComboSelect ) {
       return (*iGame);
     }
   }
@@ -3138,8 +3167,32 @@ CGameInstall::CGameInstall() {
 	memset( m_availGames, 0, sizeof( m_availGames ) );
 }
 
+static void CGameInstall::OnBtnBrowseEngine( GtkWidget *widget, gpointer data ) {
+	Sys_Printf( "OnBtnBrowseEngine\n" );
+
+	CGameInstall* i = static_cast<CGameInstall*>( data );
+	char *dir = dir_dialog( widget, "Select game directory", NULL );
+
+	i->UpdateData( TRUE );
+
+	if ( dir != NULL ) {
+		i->m_strEngine = dir;
+		i->UpdateData( FALSE );
+		free( dir );
+	}
+}
+
+static void CGameInstall::OnGameSelectChanged( GtkWidget *widget, gpointer data ) {
+	Sys_Printf( "OnGameSelectChanged\n" );
+
+	CGameInstall* i = static_cast<CGameInstall*>( data );
+	i->UpdateData( TRUE );	
+	i->m_strName = gtk_combo_box_get_active_text( GTK_COMBO_BOX( widget ) );
+	i->UpdateData( FALSE );
+}
+
 void CGameInstall::BuildDialog() {
-	GtkWidget *dlg, *vbox1, *button, *text, *combo, *entry;
+	GtkWidget *dlg, *vbox1, *button, *text, *combo, *entry, *hbox;
 	
 	dlg = m_pWidget;
 	gtk_window_set_title( GTK_WINDOW( dlg ), "Configure games" );
@@ -3152,41 +3205,41 @@ void CGameInstall::BuildDialog() {
 	gtk_widget_show( text );
 	gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 );
 
-	combo = gtk_combo_new();
+	combo = gtk_combo_box_new_text();
 	gtk_widget_show( combo );
 	gtk_box_pack_start( GTK_BOX( vbox1 ), combo, FALSE, FALSE, 0 );
 
-	GList *combo_list = NULL;
+	//	GList *combo_list = NULL;
 	int iGame = 0;
 	while ( m_availGames[ iGame ] != GAME_NONE ) {
 		switch ( m_availGames[ iGame ] ) {
 		case GAME_Q2:
-			combo_list = g_list_append( combo_list, "Quake II" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "Quake II" );
 			break;
 		case GAME_Q3:
-			combo_list = g_list_append( combo_list, "Quake III Arena (including mods)" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "Quake III Arena and mods" );
 			break;
 		case GAME_URT:
-			combo_list = g_list_append( combo_list, "Urban Terror (standalone)" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "Urban Terror (standalone)" );
 			break;
 		case GAME_UFOAI:
-			combo_list = g_list_append( combo_list, "UFO: Alien Invasion" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "UFO: Alien Invasion" );
 			break;
 		case GAME_Q2W:
-			combo_list = g_list_append( combo_list, "Quake2World" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "Quake2World" );
 			break;
 		case GAME_WARSOW:
-			combo_list = g_list_append( combo_list, "Warsow" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "Warsow" );
 			break;
 		case GAME_NEXUIZ:
-			combo_list = g_list_append( combo_list, "Nexuiz" );
+			gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), "Nexuiz" );
 			break;
 		}
 		iGame++;
 	}
-	gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list );
-	g_list_free( combo_list );
-	AddDialogData( combo, &m_nComboSelect, DLG_COMBO_INT );
+	AddDialogData( combo, &m_nComboSelect, DLG_COMBO_BOX_INT );
+	gtk_signal_connect( GTK_OBJECT( combo ), "changed", G_CALLBACK( OnGameSelectChanged ), this );
+	gtk_combo_box_set_active( GTK_COMBO_BOX( combo ), 0 );	// NOTE: will trigger signal
 
 	text = gtk_label_new( "Name:" );
 	gtk_widget_show( text );
@@ -3200,12 +3253,21 @@ void CGameInstall::BuildDialog() {
 	text = gtk_label_new( "Engine directory:" );
 	gtk_widget_show( text );
 	gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 );
+
+	hbox = gtk_hbox_new( FALSE, 0 );
+	gtk_widget_show( hbox );
+	gtk_box_pack_start( GTK_BOX( vbox1 ), hbox, FALSE, FALSE, 0 );
 	
 	entry = gtk_entry_new();
 	gtk_widget_show( entry );
-	gtk_box_pack_start( GTK_BOX( vbox1 ), entry, FALSE, FALSE, 0 );
+	gtk_box_pack_start( GTK_BOX( hbox ), entry, FALSE, FALSE, 0 );
 	AddDialogData( entry, &m_strEngine, DLG_ENTRY_TEXT );
 
+	button = gtk_button_new_with_label ("...");
+	gtk_widget_show( button );
+	gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseEngine ), this );
+	gtk_box_pack_start( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
+
 	// this gets done in the project stuff atm
 #if 0
 	text = gtk_label_new( "Mod subdirectory:" );
@@ -3223,12 +3285,20 @@ void CGameInstall::BuildDialog() {
 	gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
 	AddModalButton( button, IDOK );
 
+	button = gtk_button_new_with_label( "Cancel" );
+	gtk_widget_show( button );
+	gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
+	AddModalButton( button, IDCANCEL );
+
 	gtk_widget_set_usize( button, 60, -2 );
 }
 
 void CGameInstall::Run() {
 	ScanGames();
-	DoModal();
+	if ( DoModal() == IDCANCEL ) {
+		Sys_Printf( "game dialog cancelled\n" );
+		return;
+	}
 	Sys_Printf( "combo: %d name: %s engine: %s mod: %s\n", m_nComboSelect, m_strName.GetBuffer(), m_strEngine.GetBuffer(), m_strMod.GetBuffer() );
 
 	// write out the game file
@@ -3247,77 +3317,84 @@ void CGameInstall::Run() {
 	fprintf( fg, "  enginepath=\"%s\"\n", m_strEngine.GetBuffer() );
 	switch ( m_availGames[ m_nComboSelect ] ) {
 	case GAME_Q2: {
-		fprintf( fg, "  gametools=\"%sgames/quake2\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%sinstalls/Quake2Pack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".quake2\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += Q2_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"baseq2\"\n" );
 		break;
 	}
 	case GAME_Q3: {
-		fprintf( fg, "  gametools=\"%sgames/quake3\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%sinstalls/Q3Pack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".q3a\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += Q3_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"baseq3\"\n" );
 		break;
 	}
 	case GAME_URT: {
-		fprintf( fg, "  gametools=\"%sgames/q3ut4\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%sinstalls/UrTPack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".q3a\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += URT_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"q3ut4\"\n" );
 		break;
 	}
 	case GAME_UFOAI: {
-		fprintf( fg, "  gametools=\"%sgames/ufoai\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%sinstalls/UFOAIPack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".ufoai\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += UFOAI_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"base\"\n" );
 		break;
 	}
 	case GAME_Q2W: {
-		fprintf( fg, "  gametools=\"%sgames/q2w\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%sinstalls/Q2WPack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".quake2world\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += Q2W_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"default\"\n" );
 		break;
 	}
 	case GAME_WARSOW: {
-		fprintf( fg, "  gametools=\"%sgames/warsow\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%installs/WarsowPack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".warsow\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += WARSOW_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"basewsw\"\n" );
 		break;
 	}
 	case GAME_NEXUIZ: {
-		fprintf( fg, "  gametools=\"%sgames/nexuiz\"\n", g_strAppPath.GetBuffer() );
+		fprintf( fg, "  gametools=\"%sinstalls/NexuizPack/game\"\n", g_strAppPath.GetBuffer() );
 		fprintf( fg, "  prefix=\".nexuiz\"\n" );
 		Str source = g_strAppPath.GetBuffer();
 		source += "installs/";
 		source += NEXUIZ_PACK;
+		source += "/install/";
 		Str dest = m_strEngine.GetBuffer();
 		CopyTree( source.GetBuffer(), dest.GetBuffer() );
 		fprintf( fg, "  basegame=\"data\"\n" );
diff --git a/radiant/preferences.h b/radiant/preferences.h
index 00e2b15d..7042aa1b 100644
--- a/radiant/preferences.h
+++ b/radiant/preferences.h
@@ -213,6 +213,9 @@ public:
 	void Run();
 	void BuildDialog();
 
+	static void OnBtnBrowseEngine( GtkWidget *widget, gpointer data );
+	static void OnGameSelectChanged( GtkWidget *widget, gpointer data );
+
 	enum gameType_e {
 		GAME_NONE = 0,
 		GAME_Q3 = 1,
@@ -243,6 +246,7 @@ class CGameDialog : public Dialog
   GtkWidget *mFrame; ///< this is built on-demand first time it's used
   GtkWidget *mTopBox; ///< top level box used to store the dialog frame, must unhook after modal use
 
+  GtkComboBox	*mGameCombo;	// combo box holds the selection of available game
 
   /*!
   global prefs storage
@@ -310,6 +314,7 @@ public:
 	  m_bLogConsole = false;
 	  m_bForceLogConsole = false;
 	  m_bDoGameInstall = true;	// go through DoModal at least once
+	  mGameCombo = NULL;
   }
   virtual ~CGameDialog(); 
 
@@ -397,6 +402,8 @@ private:
 	callback for the game install button
   */
   static void SInstallCallback( GtkWidget *widget, gpointer data );
+
+  void UpdateGameCombo();
 };
 
 typedef struct {
-- 
2.39.5