]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/preferences.cpp
GTK: wrap gtk_box_pack_start
[xonotic/netradiant.git] / radiant / preferences.cpp
index 2fd078830b64584f2cec84ab7faae9dac4bb7bc8..9a3e826c19a46f0d51b982c710e527ac3d59c62b 100644 (file)
@@ -1,23 +1,23 @@
 /*
-Copyright (C) 1999-2006 Id Software, Inc. and contributors.
-For a list of contributors, see the accompanying CONTRIBUTORS file.
+   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
 
-This file is part of GtkRadiant.
+   This file is part of GtkRadiant.
 
-GtkRadiant is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-GtkRadiant is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GtkRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GtkRadiant; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 //
 // User preferences
@@ -26,23 +26,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
 #include "preferences.h"
+#include "globaldefs.h"
 
-#include "debugging/debugging.h"
+#include <gtk/gtk.h>
+#include "environment.h"
 
-#include <gtk/gtkmain.h>
-#include <gtk/gtkvbox.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtkframe.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkscrolledwindow.h>
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtktreestore.h>
-#include <gtk/gtktreeselection.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtknotebook.h>
+#include "debugging/debugging.h"
 
 #include "generic/callback.h"
 #include "math/vector.h"
@@ -64,112 +53,102 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 
 
-void Global_constructPreferences(PreferencesPage& page)
-{
-  page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
+void Global_constructPreferences( PreferencesPage& page ){
+       page.appendCheckBox( "Console", "Enable Logging", g_Console_enableLogging );
 }
 
-void Interface_constructPreferences(PreferencesPage& page)
-{
-#ifdef WIN32
-  page.appendCheckBox("", "Default Text Editor", g_TextEditor_useWin32Editor);
+void Interface_constructPreferences( PreferencesPage& page ){
+#if GDEF_OS_WINDOWS
+       page.appendCheckBox( "", "Default Text Editor", g_TextEditor_useWin32Editor );
 #else
-  {
-    GtkWidget* use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
-    GtkWidget* custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
-    Widget_connectToggleDependency(custom_editor, use_custom);
-  }
+       {
+               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
 }
 
-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);
+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 );
 }
-void Mouse_constructPage(PreferenceGroup& group)
-{
-  PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
-  Mouse_constructPreferences(page);
+void Mouse_constructPage( PreferenceGroup& group ){
+       PreferencesPage page( group.createPage( "Mouse", "Mouse Preferences" ) );
+       Mouse_constructPreferences( page );
 }
-void Mouse_registerPreferencesPage()
-{
-  PreferencesDialog_addInterfacePage(FreeCaller1<PreferenceGroup&, Mouse_constructPage>());
+void Mouse_registerPreferencesPage(){
+       PreferencesDialog_addInterfacePage( FreeCaller1<PreferenceGroup&, Mouse_constructPage>() );
 }
 
 
 /*!
-=========================================================
-Games selection dialog
-=========================================================
-*/
+   =========================================================
+   Games selection dialog
+   =========================================================
+ */
 
 #include <map>
+#include <uilib/uilib.h>
 
-inline const char* xmlAttr_getName(xmlAttrPtr attr)
-{
-  return reinterpret_cast<const char*>(attr->name);
+inline const char* xmlAttr_getName( xmlAttrPtr attr ){
+       return reinterpret_cast<const char*>( attr->name );
 }
 
-inline const char* xmlAttr_getValue(xmlAttrPtr attr)
-{
-  return reinterpret_cast<const char*>(attr->children->content);
+inline const char* xmlAttr_getValue( xmlAttrPtr attr ){
+       return reinterpret_cast<const char*>( attr->children->content );
 }
 
-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)
-  {
-    pNode=pNode->next;
-  }
-  if (!pNode)
-  {
-    Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
-  }
-
-  for(xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next)
-  {
-    m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
-  }
-
-  {
-    StringOutputStream path(256);
-    path << AppPath_get() << gameFile.c_str() << "/";
-    mGameToolsPath = path.c_str();
-  }
-
-  ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()), "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
-
-  mGameFile = gameFile;
-  {
-    GameDescription::iterator i = m_gameDescription.find("type");
-    if(i == m_gameDescription.end())
-    {
-      globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>(pDoc->URL) << "'\n";
-      // default
-      mGameType = "q3";
-    }
-    else
-    {
-      mGameType = (*i).second.c_str();
-    }
-  }
-}
-
-void CGameDescription::Dump()
-{
-  globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
-  for(GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i)
-  {
-    globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
-  }
+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 )
+       {
+               pNode = pNode->next;
+       }
+       if ( !pNode ) {
+               Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL );
+       }
+
+       for ( xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next )
+       {
+               m_gameDescription.insert( GameDescription::value_type( xmlAttr_getName( attr ), xmlAttr_getValue( attr ) ) );
+       }
+
+       {
+               StringOutputStream path( 256 );
+               path << AppPath_get() << gameFile.c_str() << "/";
+               mGameToolsPath = path.c_str();
+       }
+
+       ASSERT_MESSAGE( file_exists( mGameToolsPath.c_str() ), "game directory not found: " << makeQuoted( mGameToolsPath.c_str() ) );
+
+       mGameFile = gameFile;
+
+       {
+               GameDescription::iterator i = m_gameDescription.find( "type" );
+               if ( i == m_gameDescription.end() ) {
+                       globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>( pDoc->URL ) << "'\n";
+                       // default
+                       mGameType = "q3";
+               }
+               else
+               {
+                       mGameType = ( *i ).second.c_str();
+               }
+       }
+}
+
+void CGameDescription::Dump(){
+       globalOutputStream() << "game description file: " << makeQuoted( mGameFile.c_str() ) << "\n";
+       for ( GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i )
+       {
+               globalOutputStream() << ( *i ).first.c_str() << " = " << makeQuoted( ( *i ).second.c_str() ) << "\n";
+       }
 }
 
 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
@@ -187,331 +166,313 @@ CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentD
 
 const char* const PREFERENCES_VERSION = "1.0";
 
-bool Preferences_Load(PreferenceDictionary& preferences, const char* filename)
-{
-  TextFileInputStream file(filename);
-  if(!file.failed())
-  {
-    XMLStreamParser parser(file);
-    XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
-    parser.exportXML(importer);
-    return true;
-  }
-  return false;
-}
-
-bool Preferences_Save(PreferenceDictionary& preferences, const char* filename)
-{
-  TextFileOutputStream file(filename);
-  if(!file.failed())
-  {
-    XMLStreamWriter writer(file);
-    XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
-    exporter.exportXML(writer);
-    return true;
-  }
-  return false;
-}
-
-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';
-
-  return Preferences_Save(preferences, tmpName.data())
-    && (!file_exists(filename) || file_remove(filename))
-    && file_move(tmpName.data(), filename);
-}
-
-
-
-void LogConsole_importString(const char* string)
-{
-  g_Console_enableLogging = string_equal(string, "true");
-  Sys_LogFile(g_Console_enableLogging);
+bool Preferences_Load( PreferenceDictionary& preferences, const char* filename, const char *cmdline_prefix ){
+       bool ret = false;
+       TextFileInputStream file( filename );
+       if ( !file.failed() ) {
+               XMLStreamParser parser( file );
+               XMLPreferenceDictionaryImporter importer( preferences, PREFERENCES_VERSION );
+               parser.exportXML( importer );
+               ret = true;
+       }
+
+       int l = strlen( cmdline_prefix );
+       for ( int i = 1; i < g_argc - 1; ++i )
+       {
+               if ( g_argv[i][0] == '-' ) {
+                       if ( !strncmp( g_argv[i] + 1, cmdline_prefix, l ) ) {
+                               if ( g_argv[i][l + 1] == '-' ) {
+                                       preferences.importPref( g_argv[i] + l + 2, g_argv[i + 1] );
+                               }
+                       }
+                       ++i;
+               }
+       }
+
+       return ret;
+}
+
+bool Preferences_Save( PreferenceDictionary& preferences, const char* filename ){
+       TextFileOutputStream file( filename );
+       if ( !file.failed() ) {
+               XMLStreamWriter writer( file );
+               XMLPreferenceDictionaryExporter exporter( preferences, PREFERENCES_VERSION );
+               exporter.exportXML( writer );
+               return true;
+       }
+       return false;
+}
+
+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';
+
+       return Preferences_Save( preferences, tmpName.data() )
+                  && ( !file_exists( filename ) || file_remove( filename ) )
+                  && file_move( tmpName.data(), filename );
+}
+
+
+
+void LogConsole_importString( const char* string ){
+       g_Console_enableLogging = string_equal( string, "true" );
+       Sys_LogFile( g_Console_enableLogging );
 }
 typedef FreeCaller1<const char*, LogConsole_importString> LogConsoleImportStringCaller;
 
 
-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));
+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 ) );
 }
 
 
 PreferenceDictionary g_global_preferences;
 
-void GlobalPreferences_Init()
-{
-  RegisterGlobalPreferences(g_global_preferences);
+void GlobalPreferences_Init(){
+       RegisterGlobalPreferences( g_global_preferences );
 }
 
-void CGameDialog::LoadPrefs()
-{
-  // load global .pref file
-  StringOutputStream strGlobalPref(256);
-  strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
+void CGameDialog::LoadPrefs(){
+       // load global .pref file
+       StringOutputStream strGlobalPref( 256 );
+       strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
 
-  globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
+       globalOutputStream() << "loading global preferences from " << makeQuoted( strGlobalPref.c_str() ) << "\n";
 
-  if(!Preferences_Load(g_global_preferences, strGlobalPref.c_str()))
-  {
-    globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
-  }
+       if ( !Preferences_Load( g_global_preferences, strGlobalPref.c_str(), "global" ) ) {
+               globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
+       }
 }
 
-void CGameDialog::SavePrefs()
-{
-  StringOutputStream strGlobalPref(256);
-  strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
+void CGameDialog::SavePrefs(){
+       StringOutputStream strGlobalPref( 256 );
+       strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
 
-  globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
+       globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
 
-  if(!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str()))
-  {
-    globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
-  }
+       if ( !Preferences_Save_Safe( g_global_preferences, strGlobalPref.c_str() ) ) {
+               globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
+       }
 }
 
-void CGameDialog::DoGameDialog()
-{
-  // show the UI
-  DoModal();
+void CGameDialog::DoGameDialog(){
+       // show the UI
+       DoModal();
 
-  // we save the prefs file
-  SavePrefs();
+       // we save the prefs file
+       SavePrefs();
 }
 
-void CGameDialog::GameFileImport(int value)
-{
-  m_nComboSelect = value;
-  // use value to set m_sGameFile
-  std::list<CGameDescription *>::iterator iGame = mGames.begin();
-  int i;
-  for(i=0; i<value; i++)
-  {
-    ++iGame;
-  }
-  m_sGameFile = (*iGame)->mGameFile;
-}
-
-void CGameDialog::GameFileExport(const IntImportCallback& importCallback) const
-{
-  // use m_sGameFile to set value
-  std::list<CGameDescription *>::const_iterator iGame;
-  int i = 0;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-  {
-    if ((*iGame)->mGameFile == m_sGameFile)
-    {
-      m_nComboSelect = i;
-      break;
-    }
-    i++;
-  }
-  importCallback(m_nComboSelect);
-}
-
-void CGameDialog_GameFileImport(CGameDialog& self, int value)
-{
-  self.GameFileImport(value);
+void CGameDialog::GameFileImport( int value ){
+       m_nComboSelect = value;
+       // use value to set m_sGameFile
+       std::list<CGameDescription *>::iterator iGame = mGames.begin();
+       int i;
+       for ( i = 0; i < value; i++ )
+       {
+               ++iGame;
+       }
+       m_sGameFile = ( *iGame )->mGameFile;
 }
 
-void CGameDialog_GameFileExport(CGameDialog& self, const IntImportCallback& importCallback)
-{
-  self.GameFileExport(importCallback);
+void CGameDialog::GameFileExport( const IntImportCallback& importCallback ) const {
+       // use m_sGameFile to set value
+       std::list<CGameDescription *>::const_iterator iGame;
+       int i = 0;
+       for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
+       {
+               if ( ( *iGame )->mGameFile == m_sGameFile ) {
+                       m_nComboSelect = i;
+                       break;
+               }
+               i++;
+       }
+       importCallback( m_nComboSelect );
 }
 
-void CGameDialog::CreateGlobalFrame(PreferencesPage& page)
-{
-  std::vector<const char*> games;
-  games.reserve(mGames.size());
-  for(std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i)
-  {
-    games.push_back((*i)->getRequiredKeyValue("name"));
-  }
-  page.appendCombo(
-    "Select the game",
-    StringArrayRange(&(*games.begin()), &(*games.end())),
-    ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>(*this),
-    ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>(*this)
-  );
-  page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
-}
-
-GtkWindow* CGameDialog::BuildDialog()
-{
-  GtkFrame* frame = create_dialog_frame("Game settings", GTK_SHADOW_ETCHED_IN);
-
-  GtkVBox* vbox2 = create_dialog_vbox(0, 4);
-  gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox2));
-
-  {
-    PreferencesPage preferencesPage(*this, GTK_WIDGET(vbox2));
-    Global_constructPreferences(preferencesPage);
-    CreateGlobalFrame(preferencesPage);
-  }
-
-  return create_simple_modal_dialog_window("Global Preferences", m_modal, GTK_WIDGET(frame));
+void CGameDialog_GameFileImport( CGameDialog& self, int value ){
+       self.GameFileImport( value );
 }
 
-class LoadGameFile
-{
-  std::list<CGameDescription*>& mGames;
-  const char* mPath;
-public:
-  LoadGameFile(std::list<CGameDescription*>& 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_GameFileExport( CGameDialog& self, const IntImportCallback& importCallback ){
+       self.GameFileExport( importCallback );
+}
 
-void CGameDialog::ScanForGames()
-{
-  StringOutputStream strGamesPath(256);
-  strGamesPath << AppPath_get() << "games/";
-  const char *path = strGamesPath.c_str();
+void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){
+       std::vector<const char*> games;
+       games.reserve( mGames.size() );
+       for ( std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i )
+       {
+               games.push_back( ( *i )->getRequiredKeyValue( "name" ) );
+       }
+       page.appendCombo(
+               "Select the game",
+               StringArrayRange( &( *games.begin() ), &( *games.end() ) ),
+               ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>( *this ),
+               ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>( *this )
+               );
+       page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt );
+}
 
-  globalOutputStream() << "Scanning for game description files: " << path << '\n';
+ui::Window CGameDialog::BuildDialog(){
+       auto frame = create_dialog_frame( "Game settings", ui::Shadow::ETCHED_IN );
 
-  /*!
-  \todo FIXME LINUX:
-  do we put game description files below AppPath, or in ~/.radiant
-  i.e. read only or read/write?
-  my guess .. readonly cause it's an install
-  we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
-  (if that's really needed)
-  */
+       auto vbox2 = create_dialog_vbox( 0, 4 );
+       frame.add(vbox2);
 
-  Directory_forEach(path, LoadGameFile(mGames, path));
-}
+       {
+               PreferencesPage preferencesPage( *this, ui::Widget(GTK_WIDGET( vbox2 )) );
+               Global_constructPreferences( preferencesPage );
+               CreateGlobalFrame( preferencesPage );
+       }
 
-CGameDescription* CGameDialog::GameDescriptionForComboItem()
-{
-  std::list<CGameDescription *>::iterator iGame;
-  int i=0;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame,i++)
-  {
-    if (i == m_nComboSelect)
-    {
-      return (*iGame);
-    }
-  }
-  return 0; // not found
-}
-
-void CGameDialog::InitGlobalPrefPath()
-{
-  g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
+       return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame );
 }
 
-void CGameDialog::Reset()
+class LoadGameFile
 {
-  if (!g_Preferences.m_global_rc_path)
-    InitGlobalPrefPath();
-  StringOutputStream strGlobalPref(256);
-  strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
-  file_remove(strGlobalPref.c_str());
+std::list<CGameDescription*>& mGames;
+const char* mPath;
+public:
+LoadGameFile( std::list<CGameDescription*>& 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::Init()
-{
-  InitGlobalPrefPath();
-  LoadPrefs();
-  ScanForGames();
-  if (mGames.empty())
-  {
-    Error("Didn't find any valid game file descriptions, aborting\n");
-  }
-  CGameDescription* currentGameDescription = 0;
-
-  if (!m_bGamePrompt)
-  {
-    // search by .game name
-    std::list<CGameDescription *>::iterator iGame;
-    for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-    {
-      if ((*iGame)->mGameFile == m_sGameFile)
-      {
-        currentGameDescription = (*iGame);
-        break;
-      }
-    }
-  }
-  if (m_bGamePrompt || !currentGameDescription)
-  {
-    Create();
-    DoGameDialog();
-    // use m_nComboSelect to identify the game to run as and set the globals
-    currentGameDescription = GameDescriptionForComboItem();
-    ASSERT_NOTNULL(currentGameDescription);
-  }
-  g_pGameDescription = currentGameDescription;
-
-  g_pGameDescription->Dump();
-}
-
-CGameDialog::~CGameDialog()
-{
-  // free all the game descriptions
-  std::list<CGameDescription *>::iterator iGame;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-  {
-    delete (*iGame);
-    *iGame = 0;
-  }
-  if(GetWidget() != 0)
-  {
-    Destroy();
-  }
-}
-
-inline const char* GameDescription_getIdentifier(const CGameDescription& gameDescription)
-{
-  const char* identifier = gameDescription.getKeyValue("index");
-  if(string_empty(identifier))
-  {
-    identifier = "1";
-  }
-  return identifier;
+void CGameDialog::ScanForGames(){
+       StringOutputStream strGamesPath( 256 );
+       strGamesPath << AppPath_get() << "games/";
+       const char *path = strGamesPath.c_str();
+
+       globalOutputStream() << "Scanning for game description files: " << path << '\n';
+
+       /*!
+          \todo FIXME LINUX:
+          do we put game description files below AppPath, or in ~/.radiant
+          i.e. read only or read/write?
+          my guess .. readonly cause it's an install
+          we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
+          (if that's really needed)
+        */
+
+       Directory_forEach( path, LoadGameFile( mGames, path ) );
+}
+
+CGameDescription* CGameDialog::GameDescriptionForComboItem(){
+       std::list<CGameDescription *>::iterator iGame;
+       int i = 0;
+       for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame,i++ )
+       {
+               if ( i == m_nComboSelect ) {
+                       return ( *iGame );
+               }
+       }
+       return 0; // not found
+}
+
+void CGameDialog::InitGlobalPrefPath(){
+       g_Preferences.m_global_rc_path = g_string_new( SettingsPath_get() );
+}
+
+void CGameDialog::Reset(){
+       if ( !g_Preferences.m_global_rc_path ) {
+               InitGlobalPrefPath();
+       }
+       StringOutputStream strGlobalPref( 256 );
+       strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
+       file_remove( strGlobalPref.c_str() );
+}
+
+void CGameDialog::Init(){
+       InitGlobalPrefPath();
+       LoadPrefs();
+       ScanForGames();
+       if ( mGames.empty() ) {
+               Error( "Didn't find any valid game file descriptions, aborting\n" );
+       }
+       else
+       {
+               std::list<CGameDescription *>::iterator iGame, iPrevGame;
+               for ( iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame )
+               {
+                       if ( iPrevGame != mGames.end() ) {
+                               if ( strcmp( ( *iGame )->getRequiredKeyValue( "name" ), ( *iPrevGame )->getRequiredKeyValue( "name" ) ) < 0 ) {
+                                       CGameDescription *h = *iGame;
+                                       *iGame = *iPrevGame;
+                                       *iPrevGame = h;
+                               }
+                       }
+               }
+       }
+
+       CGameDescription* currentGameDescription = 0;
+
+       if ( !m_bGamePrompt ) {
+               // search by .game name
+               std::list<CGameDescription *>::iterator iGame;
+               for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
+               {
+                       if ( ( *iGame )->mGameFile == m_sGameFile ) {
+                               currentGameDescription = ( *iGame );
+                               break;
+                       }
+               }
+       }
+       if ( m_bGamePrompt || !currentGameDescription ) {
+               Create();
+               DoGameDialog();
+               // use m_nComboSelect to identify the game to run as and set the globals
+               currentGameDescription = GameDescriptionForComboItem();
+               ASSERT_NOTNULL( currentGameDescription );
+       }
+       g_pGameDescription = currentGameDescription;
+
+       g_pGameDescription->Dump();
+}
+
+CGameDialog::~CGameDialog(){
+       // free all the game descriptions
+       std::list<CGameDescription *>::iterator iGame;
+       for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame )
+       {
+               delete ( *iGame );
+               *iGame = 0;
+       }
+       if ( GetWidget() ) {
+               Destroy();
+       }
+}
+
+inline const char* GameDescription_getIdentifier( const CGameDescription& gameDescription ){
+       const char* identifier = gameDescription.getKeyValue( "index" );
+       if ( string_empty( identifier ) ) {
+               identifier = "1";
+       }
+       return identifier;
 }
 
-void CGameDialog::AddPacksURL(StringOutputStream &URL)
-{
-  // add the URLs for the list of game packs installed
-  // FIXME: this is kinda hardcoded for now..
-  std::list<CGameDescription *>::iterator iGame;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-  {
-    URL << "&Games_dlup%5B%5D=" << GameDescription_getIdentifier(*(*iGame));
-  }
-}
 
 CGameDialog g_GamesDialog;
 
@@ -519,380 +480,351 @@ CGameDialog g_GamesDialog;
 // =============================================================================
 // Widget callbacks for PrefsDlg
 
-static void OnButtonClean (GtkWidget *widget, gpointer data) 
-{
-  // make sure this is what the user wants
-  if (gtk_MessageBox(GTK_WIDGET(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?",
-      "Reset Registry", eMB_YESNO, eMB_ICONASTERISK) == eIDYES)
-  {
-    PrefsDlg *dlg = (PrefsDlg*)data;
-    dlg->EndModal (eIDCANCEL);
+static void OnButtonClean( ui::Widget widget, gpointer data ){
+       // make sure this is what the user wants
+       if ( ui::Widget(GTK_WIDGET( 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?",
+                                                "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) {
+               PrefsDlg *dlg = (PrefsDlg*)data;
+               dlg->EndModal( eIDCANCEL );
 
-    g_preferences_globals.disable_ini = true;
-    Preferences_Reset();
-    gtk_main_quit();
-  }
+               g_preferences_globals.disable_ini = true;
+               Preferences_Reset();
+               gtk_main_quit();
+       }
 }
 
 // =============================================================================
 // PrefsDlg class
 
 /*
-========
+   ========
 
-very first prefs init deals with selecting the game and the game tools path
-then we can load .ini stuff
+   very first prefs init deals with selecting the game and the game tools path
+   then we can load .ini stuff
 
-using prefs / ini settings:
-those are per-game
+   using prefs / ini settings:
+   those are per-game
 
-look in ~/.radiant/<version>/gamename
-========
-*/
+   look in ~/.radiant/<version>/gamename
+   ========
+ */
 
-#define PREFS_LOCAL_FILENAME "local.pref"
+const char *PREFS_LOCAL_FILENAME = "local.pref";
 
-void PrefsDlg::Init()
-{
-  // m_global_rc_path has been set above
-  // m_rc_path is for game specific preferences
-  // takes the form: global-pref-path/gamename/prefs-file
-
-  // this is common to win32 and Linux init now
-  m_rc_path = g_string_new (m_global_rc_path->str);
-  
-  // game sub-dir
-  g_string_append (m_rc_path, g_pGameDescription->mGameFile.c_str());
-  g_string_append (m_rc_path, "/");
-  Q_mkdir (m_rc_path->str);
-  
-  // then the ini file
-  m_inipath = g_string_new (m_rc_path->str);
-  g_string_append (m_inipath, PREFS_LOCAL_FILENAME);
-}
-
-void notebook_set_page(GtkWidget* notebook, GtkWidget* page)
-{
-  int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
-  if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum)
-  {
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
-  }
+void PrefsDlg::Init(){
+       // m_global_rc_path has been set above
+       // m_rc_path is for game specific preferences
+       // takes the form: global-pref-path/gamename/prefs-file
+
+       // this is common to win32 and Linux init now
+       m_rc_path = g_string_new( m_global_rc_path->str );
+
+       // game sub-dir
+       g_string_append( m_rc_path, g_pGameDescription->mGameFile.c_str() );
+       g_string_append( m_rc_path, "/" );
+       Q_mkdir( m_rc_path->str );
+
+       // then the ini file
+       m_inipath = g_string_new( m_rc_path->str );
+       g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
 }
 
-void PrefsDlg::showPrefPage(GtkWidget* prefpage)
-{
-  notebook_set_page(m_notebook, prefpage);
-  return;
+void notebook_set_page( ui::Widget notebook, ui::Widget page ){
+       int pagenum = gtk_notebook_page_num( GTK_NOTEBOOK( notebook ), page );
+       if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != pagenum ) {
+               gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook ), pagenum );
+       }
 }
 
-static void treeSelection(GtkTreeSelection* selection, gpointer data)
-{
-  PrefsDlg *dlg = (PrefsDlg*)data;
+void PrefsDlg::showPrefPage( ui::Widget prefpage ){
+       notebook_set_page( m_notebook, prefpage );
+       return;
+}
+
+static void treeSelection( GtkTreeSelection* selection, gpointer data ){
+       PrefsDlg *dlg = (PrefsDlg*)data;
 
-  GtkTreeModel* model;
-  GtkTreeIter selected;
-  if(gtk_tree_selection_get_selected(selection, &model, &selected))
-  {
-    GtkWidget* prefpage;
-    gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1);
-    dlg->showPrefPage(prefpage);
-  }
+       GtkTreeModel* model;
+       GtkTreeIter selected;
+       if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
+               ui::Widget prefpage{ui::null};
+               gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 );
+               dlg->showPrefPage( prefpage );
+       }
 }
 
 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
 
-inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group)
-{
-  for(PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
-  {
-    (*i)(group);
-  }
+inline void PreferenceGroupCallbacks_constructGroup( const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group ){
+       for ( PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
+       {
+               ( *i )( group );
+       }
 }
 
 
-inline void PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback)
-{
-  callbacks.push_back(callback);
+inline void PreferenceGroupCallbacks_pushBack( PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback ){
+       callbacks.push_back( callback );
 }
 
 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
 
-inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks& callbacks, PreferencesPage& page)
-{
-  for(PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
-  {
-    (*i)(page);
-  }
+inline void PreferencesPageCallbacks_constructPage( const PreferencesPageCallbacks& callbacks, PreferencesPage& page ){
+       for ( PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i )
+       {
+               ( *i )( page );
+       }
 }
 
-inline void PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback)
-{
-  callbacks.push_back(callback);
+inline void PreferencesPageCallbacks_pushBack( PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback ){
+       callbacks.push_back( callback );
 }
 
 PreferencesPageCallbacks g_interfacePreferences;
-void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback& callback)
-{
-  PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
+void PreferencesDialog_addInterfacePreferences( const PreferencesPageCallback& callback ){
+       PreferencesPageCallbacks_pushBack( g_interfacePreferences, callback );
 }
 PreferenceGroupCallbacks g_interfaceCallbacks;
-void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback& callback)
-{
-  PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
+void PreferencesDialog_addInterfacePage( const PreferenceGroupCallback& callback ){
+       PreferenceGroupCallbacks_pushBack( g_interfaceCallbacks, callback );
 }
 
 PreferencesPageCallbacks g_displayPreferences;
-void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback& callback)
-{
-  PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
+void PreferencesDialog_addDisplayPreferences( const PreferencesPageCallback& callback ){
+       PreferencesPageCallbacks_pushBack( g_displayPreferences, callback );
 }
 PreferenceGroupCallbacks g_displayCallbacks;
-void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback& callback)
-{
-  PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
+void PreferencesDialog_addDisplayPage( const PreferenceGroupCallback& callback ){
+       PreferenceGroupCallbacks_pushBack( g_displayCallbacks, callback );
 }
 
 PreferencesPageCallbacks g_settingsPreferences;
-void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback& callback)
-{
-  PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
+void PreferencesDialog_addSettingsPreferences( const PreferencesPageCallback& callback ){
+       PreferencesPageCallbacks_pushBack( g_settingsPreferences, callback );
 }
 PreferenceGroupCallbacks g_settingsCallbacks;
-void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback& callback)
-{
-  PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
+void PreferencesDialog_addSettingsPage( const PreferenceGroupCallback& callback ){
+       PreferenceGroupCallbacks_pushBack( g_settingsCallbacks, callback );
 }
 
-void Widget_updateDependency(GtkWidget* self, GtkWidget* toggleButton)
-{
-  gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) && GTK_WIDGET_IS_SENSITIVE(toggleButton));
+void Widget_updateDependency( ui::Widget self, ui::Widget toggleButton ){
+       gtk_widget_set_sensitive( self, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( toggleButton ) ) && gtk_widget_is_sensitive( toggleButton ) );
 }
 
-void ToggleButton_toggled_Widget_updateDependency(GtkWidget *toggleButton, GtkWidget* self)
-{
-  Widget_updateDependency(self, toggleButton);
+void ToggleButton_toggled_Widget_updateDependency( ui::Widget toggleButton, ui::Widget self ){
+       Widget_updateDependency( self, toggleButton );
 }
 
-void ToggleButton_state_changed_Widget_updateDependency(GtkWidget* toggleButton, GtkStateType state, GtkWidget* self)
-{
-  if(state == GTK_STATE_INSENSITIVE)
-  {
-    Widget_updateDependency(self, toggleButton);
-  }
+void ToggleButton_state_changed_Widget_updateDependency( ui::Widget toggleButton, GtkStateType state, ui::Widget self ){
+       if ( state == GTK_STATE_INSENSITIVE ) {
+               Widget_updateDependency( self, toggleButton );
+       }
 }
 
-void Widget_connectToggleDependency(GtkWidget* self, GtkWidget* toggleButton)
-{
-  g_signal_connect(G_OBJECT(toggleButton), "state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
-  g_signal_connect(G_OBJECT(toggleButton), "toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
-  Widget_updateDependency(self, toggleButton);
+void Widget_connectToggleDependency( ui::Widget self, ui::Widget toggleButton ){
+       toggleButton.connect( "state_changed", G_CALLBACK( ToggleButton_state_changed_Widget_updateDependency ), self );
+       toggleButton.connect( "toggled", G_CALLBACK( ToggleButton_toggled_Widget_updateDependency ), self );
+       Widget_updateDependency( self, toggleButton );
 }
 
 
-inline GtkWidget* getVBox(GtkWidget* page)
-{
-  return gtk_bin_get_child(GTK_BIN(page));
+inline ui::Widget getVBox( ui::Widget page ){
+       return ui::Widget(gtk_bin_get_child( GTK_BIN( page ) ));
 }
 
-GtkTreeIter PreferenceTree_appendPage(GtkTreeStore* store, GtkTreeIter* parent, const char* name, GtkWidget* page)
-{
-  GtkTreeIter group;
-  gtk_tree_store_append(store, &group, parent);
-  gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
-  return group;
+GtkTreeIter PreferenceTree_appendPage( GtkTreeStore* 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 );
+       return group;
 }
 
-GtkWidget* PreferencePages_addPage(GtkWidget* notebook, const char* name)
-{
-  GtkWidget* preflabel = gtk_label_new(name);
-  gtk_widget_show(preflabel);
+ui::Widget PreferencePages_addPage( ui::Widget notebook, const char* name ){
+       ui::Widget preflabel = ui::Label( name );
+       preflabel.show();
 
-  GtkWidget* pageframe = gtk_frame_new(name);
-  gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
-  gtk_widget_show(pageframe);
+       auto pageframe = ui::Frame( name );
+       gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 4 );
+       pageframe.show();
 
-  GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
-  gtk_widget_show(vbox);
-  gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
-  gtk_container_add(GTK_CONTAINER(pageframe), vbox);
+       ui::Widget vbox = ui::VBox( FALSE, 4 );
+       vbox.show();
+       gtk_container_set_border_width( GTK_CONTAINER( vbox ), 4 );
+       pageframe.add(vbox);
 
-  // Add the page to the notebook
-  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
+       // Add the page to the notebook
+       gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
 
-  return pageframe;
+       return pageframe;
 }
 
 class PreferenceTreeGroup : public PreferenceGroup
 {
-  Dialog& m_dialog;
-  GtkWidget* m_notebook;
-  GtkTreeStore* m_store;
-  GtkTreeIter m_group;
+Dialog& m_dialog;
+ui::Widget m_notebook;
+GtkTreeStore* m_store;
+GtkTreeIter m_group;
 public:
-  PreferenceTreeGroup(Dialog& dialog, GtkWidget* notebook, GtkTreeStore* store, GtkTreeIter group) :
-    m_dialog(dialog),
-    m_notebook(notebook),
-    m_store(store),
-    m_group(group)
-  {
-  }
-  PreferencesPage createPage(const char* treeName, const char* frameName)
-  {
-    GtkWidget* page = PreferencePages_addPage(m_notebook, frameName);
-    PreferenceTree_appendPage(m_store, &m_group, treeName, page);
-    return PreferencesPage(m_dialog, getVBox(page));
-  }
+PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, GtkTreeStore* store, GtkTreeIter group ) :
+       m_dialog( dialog ),
+       m_notebook( notebook ),
+       m_store( store ),
+       m_group( group ){
+}
+PreferencesPage createPage( const char* treeName, const char* frameName ){
+       ui::Widget page = PreferencePages_addPage( m_notebook, frameName );
+       PreferenceTree_appendPage( m_store, &m_group, treeName, page );
+       return PreferencesPage( m_dialog, getVBox( page ) );
+}
 };
 
-GtkWindow* PrefsDlg::BuildDialog()
-{
-  PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, Interface_constructPreferences>());
-  Mouse_registerPreferencesPage();
-
-  GtkWindow* dialog = create_floating_window("NetRadiant Preferences", m_parent);
-
-  {
-    GtkWidget* mainvbox = gtk_vbox_new(FALSE, 5);
-    gtk_container_add(GTK_CONTAINER(dialog), mainvbox);
-    gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
-    gtk_widget_show(mainvbox);
-  
-    {
-      GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
-      gtk_widget_show(hbox);
-      gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0);
-
-      {
-        GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
-        gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
-        gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
-        gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
-    }
-  
-    {
-      GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
-      gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
-      gtk_widget_show(hbox);
-  
-      {
-        GtkWidget* sc_win = gtk_scrolled_window_new(0, 0);
-        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-        gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0);
-        gtk_widget_show(sc_win);
-        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
-
-        // prefs pages notebook
-        m_notebook = 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);
-        gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 0);
-        gtk_widget_show(m_notebook);
-
-
-        {
-          GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
-
-          GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
-          gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
-
-          {
-            GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
-            GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, 0);
-            gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
-          }
-
-          {
-            GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-            g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this);
-          }
-
-          gtk_widget_show(view);
-
-          gtk_container_add(GTK_CONTAINER (sc_win), view);
-
-          {
-            /********************************************************************/
-            /* Add preference tree options                                      */
-            /********************************************************************/
-            // Front page... 
-            //GtkWidget* front =
-            PreferencePages_addPage(m_notebook, "Front Page");
-
-            {
-              GtkWidget* global = PreferencePages_addPage(m_notebook, "Global Preferences");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(global));
-                Global_constructPreferences(preferencesPage);
-              }
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Global", global);
-              {
-                GtkWidget* game = PreferencePages_addPage(m_notebook, "Game");
-                PreferencesPage preferencesPage(*this, getVBox(game));
-                g_GamesDialog.CreateGlobalFrame(preferencesPage);
-
-                PreferenceTree_appendPage(store, &group, "Game", game);
-              }
-            }
-
-            {
-              GtkWidget* interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(interfacePage));
-                PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
-              }
-
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
-              PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
-
-              PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
-            }
-
-            {
-              GtkWidget* display = PreferencePages_addPage(m_notebook, "Display Preferences");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(display));
-                PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
-              }
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Display", display);
-              PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
-
-              PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
-            }
-
-            {
-              GtkWidget* settings = PreferencePages_addPage(m_notebook, "General Settings");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(settings));
-                PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
-              }
-
-              GtkTreeIter 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));
-    
-          g_object_unref(G_OBJECT(store));
-        }
-      }
-    }
-  }
-
-  gtk_notebook_set_page(GTK_NOTEBOOK(m_notebook), 0);
-
-  return dialog;
+ui::Window PrefsDlg::BuildDialog(){
+       PreferencesDialog_addInterfacePreferences( FreeCaller1<PreferencesPage&, Interface_constructPreferences>() );
+       Mouse_registerPreferencesPage();
+
+       ui::Window dialog = ui::Window(create_floating_window( "NetRadiant Preferences", m_parent ));
+
+       {
+               auto mainvbox = ui::VBox( FALSE, 5 );
+               dialog.add(mainvbox);
+               gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 );
+               mainvbox.show();
+
+               {
+                       auto hbox = ui::HBox( FALSE, 5 );
+                       hbox.show();
+                       mainvbox.pack_end(hbox, FALSE, TRUE, 0);
+
+                       {
+                               auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &m_modal );
+                               hbox.pack_end(button, FALSE, FALSE, 0);
+                       }
+                       {
+                               auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &m_modal );
+                               hbox.pack_end(button, FALSE, FALSE, 0);
+                       }
+                       {
+                               auto button = create_dialog_button( "Clean", G_CALLBACK( OnButtonClean ), this );
+                               hbox.pack_end(button, FALSE, FALSE, 0);
+                       }
+               }
+
+               {
+                       auto hbox = ui::HBox( FALSE, 5 );
+                       mainvbox.pack_start( hbox, TRUE, TRUE, 0 );
+                       hbox.show();
+
+                       {
+                               auto sc_win = ui::ScrolledWindow(ui::New);
+                               gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_win ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
+                               hbox.pack_start( sc_win, FALSE, FALSE, 0 );
+                               sc_win.show();
+                               gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN );
+
+                               // prefs pages notebook
+                               m_notebook = ui::Widget(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 );
+                               m_notebook.show();
+
+
+                               {
+                                       auto store = 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 renderer = ui::CellRendererText(ui::New);
+                                               GtkTreeViewColumn* column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} );
+                                               gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
+                                       }
+
+                                       {
+                                               auto selection = ui::TreeSelection(gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) ));
+                                               selection.connect( "changed", G_CALLBACK( treeSelection ), this );
+                                       }
+
+                                       view.show();
+
+                                       sc_win.add(view);
+
+                                       {
+                                               /********************************************************************/
+                                               /* Add preference tree options                                      */
+                                               /********************************************************************/
+                                               // Front page...
+                                               //GtkWidget* front =
+                                               PreferencePages_addPage( m_notebook, "Front Page" );
+
+                                               {
+                                                       ui::Widget global = PreferencePages_addPage( m_notebook, "Global Preferences" );
+                                                       {
+                                                               PreferencesPage preferencesPage( *this, getVBox( global ) );
+                                                               Global_constructPreferences( preferencesPage );
+                                                       }
+                                                       GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Global", global );
+                                                       {
+                                                               ui::Widget game = PreferencePages_addPage( m_notebook, "Game" );
+                                                               PreferencesPage preferencesPage( *this, getVBox( game ) );
+                                                               g_GamesDialog.CreateGlobalFrame( preferencesPage );
+
+                                                               PreferenceTree_appendPage( store, &group, "Game", game );
+                                                       }
+                                               }
+
+                                               {
+                                                       ui::Widget interfacePage = PreferencePages_addPage( m_notebook, "Interface Preferences" );
+                                                       {
+                                                               PreferencesPage preferencesPage( *this, getVBox( interfacePage ) );
+                                                               PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage );
+                                                       }
+
+                                                       GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage );
+                                                       PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
+
+                                                       PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup );
+                                               }
+
+                                               {
+                                                       ui::Widget display = PreferencePages_addPage( m_notebook, "Display Preferences" );
+                                                       {
+                                                               PreferencesPage preferencesPage( *this, getVBox( display ) );
+                                                               PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage );
+                                                       }
+                                                       GtkTreeIter group = PreferenceTree_appendPage( store, 0, "Display", display );
+                                                       PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group );
+
+                                                       PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup );
+                                               }
+
+                                               {
+                                                       ui::Widget settings = PreferencePages_addPage( m_notebook, "General Settings" );
+                                                       {
+                                                               PreferencesPage preferencesPage( *this, getVBox( settings ) );
+                                                               PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage );
+                                                       }
+
+                                                       GtkTreeIter 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 ) );
+
+                                       g_object_unref( G_OBJECT( store ) );
+                               }
+                       }
+               }
+       }
+
+       gtk_notebook_set_current_page( GTK_NOTEBOOK( m_notebook ), 0 );
+
+       return dialog;
 }
 
 preferences_globals_t g_preferences_globals;
@@ -900,39 +832,34 @@ preferences_globals_t g_preferences_globals;
 PrefsDlg g_Preferences;               // global prefs instance
 
 
-void PreferencesDialog_constructWindow(GtkWindow* main_window)
-{
-  g_Preferences.m_parent = main_window;
-  g_Preferences.Create();
+void PreferencesDialog_constructWindow( ui::Window main_window ){
+       g_Preferences.m_parent = main_window;
+       g_Preferences.Create();
 }
-void PreferencesDialog_destroyWindow()
-{
-  g_Preferences.Destroy();
+void PreferencesDialog_destroyWindow(){
+       g_Preferences.Destroy();
 }
 
 
 PreferenceDictionary g_preferences;
 
-PreferenceSystem& GetPreferenceSystem()
-{
-  return g_preferences;
+PreferenceSystem& GetPreferenceSystem(){
+       return g_preferences;
 }
 
 class PreferenceSystemAPI
 {
-  PreferenceSystem* m_preferencesystem;
+PreferenceSystem* m_preferencesystem;
 public:
-  typedef PreferenceSystem Type;
-  STRING_CONSTANT(Name, "*");
-
-  PreferenceSystemAPI()
-  {
-    m_preferencesystem = &GetPreferenceSystem();
-  }
-  PreferenceSystem* getTable()
-  {
-    return m_preferencesystem;
-  }
+typedef PreferenceSystem Type;
+STRING_CONSTANT( Name, "*" );
+
+PreferenceSystemAPI(){
+       m_preferencesystem = &GetPreferenceSystem();
+}
+PreferenceSystem* getTable(){
+       return m_preferencesystem;
+}
 };
 
 #include "modulesystem/singletonmodule.h"
@@ -940,116 +867,100 @@ public:
 
 typedef SingletonModule<PreferenceSystemAPI> PreferenceSystemModule;
 typedef Static<PreferenceSystemModule> StaticPreferenceSystemModule;
-StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule::instance());
+StaticRegisterModule staticRegisterPreferenceSystem( StaticPreferenceSystemModule::instance() );
 
-void Preferences_Load()
-{
-  g_GamesDialog.LoadPrefs();
+void Preferences_Load(){
+       g_GamesDialog.LoadPrefs();
 
-  globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
+       globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
 
-  if(!Preferences_Load(g_preferences, g_Preferences.m_inipath->str))
-  {
-    globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
-  }
+       if ( !Preferences_Load( g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str() ) ) {
+               globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
+       }
 }
 
-void Preferences_Save()
-{
-  if (g_preferences_globals.disable_ini)
-    return;
+void Preferences_Save(){
+       if ( g_preferences_globals.disable_ini ) {
+               return;
+       }
 
-  g_GamesDialog.SavePrefs();
+       g_GamesDialog.SavePrefs();
 
-  globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
+       globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
 
-  if(!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str))
-  {
-    globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
-  }
+       if ( !Preferences_Save_Safe( g_preferences, g_Preferences.m_inipath->str ) ) {
+               globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
+       }
 }
 
-void Preferences_Reset()
-{
-  file_remove(g_Preferences.m_inipath->str);
+void Preferences_Reset(){
+       file_remove( g_Preferences.m_inipath->str );
 }
 
 
-void PrefsDlg::PostModal (EMessageBoxReturn code)
-{
-  if (code == eIDOK)
-  {
-    Preferences_Save();
-    UpdateAllWindows();
-  }
+void PrefsDlg::PostModal( EMessageBoxReturn code ){
+       if ( code == eIDOK ) {
+               Preferences_Save();
+               UpdateAllWindows();
+       }
 }
 
 std::vector<const char*> g_restart_required;
 
-void PreferencesDialog_restartRequired(const char* staticName)
-{
-  g_restart_required.push_back(staticName);
+void PreferencesDialog_restartRequired( const char* staticName ){
+       g_restart_required.push_back( staticName );
 }
 
-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";
-      for(std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i)
-      {
-        message << (*i) << '\n';
-      }
-      gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), message.c_str());
-      g_restart_required.clear();
-    }
-  }
+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";
+                       for ( std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i )
+                       {
+                               message << ( *i ) << '\n';
+                       }
+                       MainFrame_getWindow().alert( message.c_str() );
+                       g_restart_required.clear();
+               }
+       }
 }
 
 
 
 
 
-void GameName_importString(const char* value)
-{
-  gamename_set(value);
+void GameName_importString( const char* value ){
+       gamename_set( value );
 }
 typedef FreeCaller1<const char*, GameName_importString> GameNameImportStringCaller;
-void GameName_exportString(const StringImportCallback& importer)
-{
-  importer(gamename_get());
+void GameName_exportString( const StringImportCallback& importer ){
+       importer( gamename_get() );
 }
 typedef FreeCaller1<const StringImportCallback&, GameName_exportString> GameNameExportStringCaller;
 
-void GameMode_importString(const char* value)
-{
-  gamemode_set(value);
+void GameMode_importString( const char* value ){
+       gamemode_set( value );
 }
 typedef FreeCaller1<const char*, GameMode_importString> GameModeImportStringCaller;
-void GameMode_exportString(const StringImportCallback& importer)
-{
-  importer(gamemode_get());
+void GameMode_exportString( const StringImportCallback& importer ){
+       importer( gamemode_get() );
 }
 typedef FreeCaller1<const StringImportCallback&, GameMode_exportString> GameModeExportStringCaller;
 
 
-void RegisterPreferences(PreferenceSystem& preferences)
-{
-#ifdef WIN32
-  preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useWin32Editor), BoolExportStringCaller(g_TextEditor_useWin32Editor));
+void RegisterPreferences( PreferenceSystem& preferences ){
+#if GDEF_OS_WINDOWS
+       preferences.registerPreference( "UseCustomShaderEditor", BoolImportStringCaller( g_TextEditor_useWin32Editor ), BoolExportStringCaller( 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", BoolImportStringCaller( g_TextEditor_useCustomEditor ), BoolExportStringCaller( g_TextEditor_useCustomEditor ) );
+       preferences.registerPreference( "CustomShaderEditorCommand", CopiedStringImportStringCaller( g_TextEditor_editorCommand ), CopiedStringExportStringCaller( g_TextEditor_editorCommand ) );
 #endif
 
-  preferences.registerPreference("GameName", GameNameImportStringCaller(), GameNameExportStringCaller());
-  preferences.registerPreference("GameMode", GameModeImportStringCaller(), GameModeExportStringCaller());
+       preferences.registerPreference( "GameName", GameNameImportStringCaller(), GameNameExportStringCaller() );
+       preferences.registerPreference( "GameMode", GameModeImportStringCaller(), GameModeExportStringCaller() );
 }
 
-void Preferences_Init()
-{
-  RegisterPreferences(GetPreferenceSystem());
+void Preferences_Init(){
+       RegisterPreferences( GetPreferenceSystem() );
 }