X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=radiant%2Fpreferences.cpp;h=8aaa30b59e720646f00aadfeda890eacb33e402c;hp=08ff05c4e549d185a4ca37de97fcff2fa505ff27;hb=f100a82117cc13e8a646e39349865cd35d54b891;hpb=9b5ba1fe10d7eba4db1588c2a4926829c465dc76 diff --git a/radiant/preferences.cpp b/radiant/preferences.cpp index 08ff05c4..8aaa30b5 100644 --- a/radiant/preferences.cpp +++ b/radiant/preferences.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2007 id Software, Inc. and contributors. + 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. @@ -25,3647 +25,980 @@ // Leonardo Zide (leo@lokigames.com) // -#include "stdafx.h" -#include -#include -#include -#if defined ( __linux__ ) || defined ( __APPLE__ ) -#include -#include -#include -#include -#include -#endif -#include "missing.h" -#include "gtkmisc.h" +#include "preferences.h" +#include "globaldefs.h" -#ifdef _WIN32 -#include -#define X_OK 0 -#include -#endif +#include +#include "environment.h" -#define PREF_SECTION "Prefs" -#define INTERNAL_SECTION "Internals" -#define MOUSE_KEY "MouseButtons" -#define WINDOW_KEY "QE4StyleWindows" -#define LAYOUT_KEY "WindowLayout" -#define RUNQ2_KEY "RunQuake2Run" -#define TLOCK_KEY "TextureLock" -#define RLOCK_KEY "RotateLock" -#define LOADLAST_KEY "LoadLast" -#define LOADLASTMAP_KEY "LoadLastMap" -#define LASTPROJ_KEY "LastProject" -#define LASTPROJVER_KEY "LastProjectKey" -#define LASTMAP_KEY "LastMap" -#define FACE_KEY "NewFaceGrab" -#define BSP_KEY "InternalBSP" -#define RCLICK_KEY "NewRightClick" -#define VERTEX_KEY "NewVertex" -#define AUTOSAVE_KEY "Autosave" -#define AUTOSAVETIME_KEY "AutosaveMinutes" -#define PAK_KEY "UsePAK" -#define NEWAPPLY_KEY "ApplyDismissesSurface" -#define HACK_KEY "Gatewayescapehack" -#define TEXTURE_KEY "NewTextureWindowStuff" -#define TINYBRUSH_KEY "CleanTinyBrushes" -#define TINYSIZE_KEY "CleanTinyBrusheSize" -#define SNAPSHOT_KEY "Snapshots" -#define MOVESPEED_KEY "MoveSpeed" -#define ANGLESPEED_KEY "AngleSpeed" -#define SETGAME_KEY "UseSetGame" -#define CAMXYUPDATE_KEY "CamXYUpdate" -#define CAMDRAGMULTISELECT_KEY "CamDragMultiSelect" -#define CAMFREELOOK_KEY "CamFreeLook" -#define CAMINVERSEMOUSE_KEY "CamInverseMouse" -#define CAMDISCRETE_KEY "CamDiscrete" -#define LIGHTDRAW_KEY "NewLightStyle" -#define WHATGAME_KEY "WhichGame" -#define CUBICCLIP_KEY "CubicClipping" -#define CUBICSCALE_KEY "CubicScale" -#define ALTEDGE_KEY "ALTEdgeDrag" -#define FACECOLORS_KEY "FaceColors" -#define SNAPT_KEY "SnapT" -#define XZVIS_KEY "XZVIS" -#define YZVIS_KEY "YZVIS" -#define ZVIS_KEY "ZVIS" -#define SIZEPAINT_KEY "SizePainting" -#define DLLENTITIES_KEY "DLLEntities" -#define DETACHABLEMENUS_KEY "DetachableMenus" -#define PATCHTOOLBAR_KEY "PatchToolBar" -#define WIDETOOLBAR_KEY "WideToolBar" -#define PLUGINTOOLBAR_KEY "PluginToolBar" -#define NOCLAMP_KEY "NoClamp" -#define SNAP_KEY "Snap" -#define PREFAB_KEY "PrefabPath" -#define USERINI_KEY "UserINIPath" -#define ROTATION_KEY "Rotation" -#define BUGGYICD_KEY "BuggyICD" -#define CHASEMOUSE_KEY "ChaseMouse" -#define ENTITYSHOW_KEY "EntityShow" -#define TEXTURESCALE_KEY "TextureScale" -#define TEXTURESCROLLBAR_KEY "TextureScrollbar" -#define DISPLAYLISTS_KEY "UseDisplayLists" -#define ANTIALIASEDLINES_KEY "UseAntialiasedPointsAndLines" // Fishman - Add antialiazed points and lines support. 09/03/00 -#define NORMALIZECOLORS_KEY "NormalizeColors" -#define SHADERS_KEY "UseShaders" -#define SWITCHCLIP_KEY "SwitchClipKey" -#define SELWHOLEENTS_KEY "SelectWholeEntitiesKey" -#define TEXTURESUBSET_KEY "UseTextureSubsetLoading" -#define TEXTUREQUALITY_KEY "TextureQuality" -#define SHOWSHADERS_KEY "ShowShaders" -#define SHADERTEST_KEY "ShaderTest" -#define GLLIGHTING_KEY "UseGLLighting" -#define LOADSHADERS_KEY "LoadShaders" -#define NOSTIPPLE_KEY "NoStipple" -#define UNDOLEVELS_KEY "UndoLevels" -#define VERTEXMODE_KEY "VertexSplit" -#define ENGINEPATH_KEY "EnginePath" -#define ENGINE_KEY "Engine" -#define LOGCONSOLE_KEY "LogConsole" -#define SELECTCURVES_KEY "SelectCurves" -#define SELECTMODELS_KEY "SelectModels" -#define SHADERLISTONLY_KEY "ShowShaderlistOnly" -#define WATCHBSP_KEY "WatchBSP" -#define LEAKSTOP_KEY "LeakStop" -#define DOSLEEP_KEY "SleepMode" -#define SUBDIVISIONS_KEY "Subdivisions" -#define DEFAULTTEXURESCALE_KEY "DefaultTextureScale" -#define CLIPCAULK_KEY "ClipCaulk" -#define PATCHSHOWBOUNDS_KEY "PatchShowBounds" -#define NATIVEGUI_KEY "NativeGUI" -#define STARTONPRIMMON_KEY "StartOnPrimMon" -#define NOSYSMENUPOPUPS_KEY "NoSysMenuPopups" -#define SNAPTTOGRID_KEY "SnapTToGrid" -#define FLOATINGZ_KEY "FloatingZ" -#define TARGETFIX_KEY "TargetFix" -#define GLPOINTWORKAROUND_KEY "GlPointWorkaround" // Gef: Workaround for broken Kyro * gl driver 25-aug-2001 -#define WHEELINC_KEY "WheelMouseInc" -#define PATCHBBOXSEL_KEY "PatchBBoxSel" -#define LASTLIGHTINTENSITY_KEY "LastLightIntensity" -#define CUSTOMSHADEREDITOR_KEY "UseCustomShaderEditor" -#define CUSTOMSHADEREDITORCOMMAND_KEY "CustomShaderEditorCommand" -#define TEXTURECOMPRESSIONFORMAT_KEY "TextureCompressionFormat" -#define LIGHTRADIUS_KEY "LightRadiuses" -#define Q3MAP2TEX_KEY "Q3Map2Tex" - -#ifdef ATIHACK_812 -#define ATIHACK_KEY "ATIHack" -#endif +#include "debugging/debugging.h" -#ifdef NVIDIA_AERO_HACK -#define NVAEROHACK_KEY "NvidiaAeroHack" -#endif +#include "generic/callback.h" +#include "math/vector.h" +#include "string/string.h" +#include "stream/stringstream.h" +#include "os/file.h" +#include "os/path.h" +#include "os/dir.h" +#include "gtkutil/filechooser.h" +#include "gtkutil/messagebox.h" +#include "cmdlib.h" -// window stuff -#define ENTITYSPLIT1_KEY "EntitySplit1" -#define ENTITYSPLIT2_KEY "EntitySplit2" -#define POSITIONX_KEY "PositionX" -#define POSITIONY_KEY "PositionY" -#define ENTITYWND_KEY "EntityWnd" -#define MAPINFOWND_KEY "MapInfoDlg" -#define CAMWND_KEY "CamWnd" -#define ZWND_KEY "ZWnd" -#define XYWND_KEY "XYWnd" -#define XZWND_KEY "XZWnd" -#define YZWND_KEY "YZWnd" -#define PATCHWND_KEY "PatchWnd" -#define SURFACEWND_KEY "SurfaceWnd" -#define ENTITYINFOWND_KEY "EntityInfoDlg" -#define WIDTH_KEY "Width" -#define HEIGHT_KEY "Height" -#define ZWIDTH_KEY "ZWidth" -#define XYHEIGHT_KEY "XYHeight" -#define XYWIDTH_KEY "XYWidth" -#define CAMWIDTH_KEY "CamWidth" -#define CAMHEIGHT_KEY "CamHeight" -#define ZFLOATWIDTH_KEY "ZWidthFloating" -#define STATE_KEY "State" - -// menu stuff -#define COUNT_KEY "Count" -#define FILE_KEY "File" - -//saved info -#define SI_TEXMENU_KEY "SI_TexMenu" -#define SI_GAMMA_KEY "SI_Gamma" -#define SI_COLORS_KEY "SI_Colors" -#define SI_EXCLUDE_KEY "SI_Exclude" -#define SI_INCLUDE_KEY "SI_Include" -#define SI_SURFACE_TEXDEF_KEY "SI_SurfaceTexdef" -#define SI_PATCH_TEXDEF_KEY "SI_PatchTexdef" -#define SI_AXISCOLORS_KEY "SI_AxisColors" -#define SI_SHOWNAMES_KEY "SI_ShowNames" -#define SI_SHOWCOORDS_KEY "SI_ShowCoords" -#define SI_SHOWANGLES_KEY "SI_ShowAngles" -#define SI_SHOWOUTLINES_KEY "SI_ShowOutlines" -#define SI_SHOWAXIS_KEY "SI_ShowAxis" -#define SI_NOSELOUTLINES_KEY "SI_NoSelectedOutlines" -#define SI_OUTLINESTYLE_KEY "SI_OutLineStyle" - -//for texdefs -#define TD_SCALE1_KEY "_Scale1" -#define TD_SCALE2_KEY "_Scale2" -#define TD_SHIFT1_KEY "_Shift1" -#define TD_SHIFT2_KEY "_Shift2" -#define TD_ROTATE_KEY "_Rotate" - -#define MOUSE_DEF 1 -#define WINDOW_DEF 0 -#define RUNQ2_DEF 0 -#define WATCHBSP_DEF 1 -#define TLOCK_DEF 1 -#define LOADLAST_DEF 1 -#define RUN_DEF 0 -#define SUBDIVISIONS_DEF 4 - -void WindowPosition_Parse( window_position_t& m_value, const CString& value ){ - if ( sscanf( value.GetBuffer(), "%d %d %d %d", &m_value.x, &m_value.y, &m_value.w, &m_value.h ) != 4 ) { - m_value.x = m_value.y = m_value.w = m_value.h = -1; - } -} +#include "error.h" +#include "console.h" +#include "xywindow.h" +#include "mainframe.h" +#include "qe3.h" +#include "gtkdlgs.h" -void WindowPosition_Write( const window_position_t& m_value, CString& value ){ - char buffer[64]; - sprintf( buffer, "%d %d %d %d", m_value.x, m_value.y, m_value.w, m_value.h ); - value = buffer; -} -CXMLPropertyBag::CXMLPropertyBag() { - mStrFilename = ""; - mpDoc = NULL; - mbEmpty = false; +void Global_constructPreferences( PreferencesPage& page ){ + page.appendCheckBox( "Console", "Enable Logging", g_Console_enableLogging ); } -// generic preference functions - -void CXMLPropertyBag::PushAssignment( const char *name, PrefTypes_t type, void *pV ){ - list::iterator iAssign; - for ( iAssign = mPrefAssignments.begin(); iAssign != mPrefAssignments.end(); iAssign++ ) +void Interface_constructPreferences( PreferencesPage& page ){ +#if GDEF_OS_WINDOWS + page.appendCheckBox( "", "Default Text Editor", g_TextEditor_useWin32Editor ); +#else { - if ( ( *iAssign ).mName == name ) { - // we have it already, check anyway - if ( pV != ( *iAssign ).mVal ) { - Sys_FPrintf( SYS_ERR, "PushAssignment, '%s' has different mVal\n", name ); - return; - } - } + 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 ); } - // ok, it's not in our list yet - mPrefAssignments.push_front( CPrefAssignment( name, type, pV ) ); +#endif } -xmlNodePtr CXMLPropertyBag::EpairForName( const char *name ){ - xmlNodePtr ret = NULL; - - xmlNodePtr pNode = mpDocNode->children; - while ( pNode != NULL ) +void Mouse_constructPreferences( PreferencesPage& page ){ { - if ( pNode->type == XML_ELEMENT_NODE ) { - xmlAttrPtr tmp_attr_ptr = xmlHasProp( pNode, (xmlChar *)"name" ); - if ( tmp_attr_ptr != NULL && !strcmp( name, (char *)tmp_attr_ptr->children->content ) ) { - if ( ret ) { - Sys_FPrintf( SYS_WRN, "WARNING: dupe property in CXMLPropertyBag::EpairForName '%s'\n", name ); - } - else { - ret = pNode; - } - } - } - pNode = pNode->next; + const char* buttons[] = { "2 button", "3 button", }; + page.appendRadio( "Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE( buttons ) ); } - return ret; + page.appendCheckBox( "Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick ); } - -void CXMLPropertyBag::GetPref( const char *name, Str *pV, const char *V ){ - xmlNodePtr pNode = EpairForName( name ); - if ( pNode ) { - if ( pNode->children && pNode->children->content ) { - *pV = pNode->children->content; - } - else { - // means the pref exists, and that the value is "" - *pV = ""; - } - } - else - { - pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)V ); - xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name ); - } - // push the pref assignment if needed - PushAssignment( name, PREF_STR, pV ); +void Mouse_constructPage( PreferenceGroup& group ){ + PreferencesPage page( group.createPage( "Mouse", "Mouse Preferences" ) ); + Mouse_constructPreferences( page ); } - -void CXMLPropertyBag::GetPref( const char *name, int *pV, int V ){ - xmlNodePtr pNode; - if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) { - *pV = atoi( (char *)pNode->children->content ); - } - else - { - char s[10]; - sprintf( s, "%d", V ); - pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s ); - xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name ); - *pV = V; - } - // push the pref assignment if needed - PushAssignment( name, PREF_INT, pV ); +void Mouse_registerPreferencesPage(){ + PreferencesDialog_addInterfacePage( makeCallbackF(Mouse_constructPage) ); } -void CXMLPropertyBag::GetPref( const char *name, bool *pV, bool V ){ - xmlNodePtr pNode; - if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) { - if ( !strcmp( (char *)pNode->children->content, "true" ) ) { - *pV = true; - } - else - { - *pV = false; - } - } - else - { - char s[10]; - V ? strcpy( s, "true" ) : strcpy( s, "false" ); - pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s ); - xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name ); - *pV = V; - } - // push the pref assignment - PushAssignment( name, PREF_BOOL, pV ); -} -void CXMLPropertyBag::GetPref( const char *name, float *pV, float V ){ - xmlNodePtr pNode; - if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) { - *pV = atof( (char *)pNode->children->content ); - } - else - { - char s[10]; - sprintf( s, "%f", V ); - pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s ); - xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name ); - *pV = V; - } - // push the pref assignment if needed - PushAssignment( name, PREF_FLOAT, pV ); +/*! + ========================================================= + Games selection dialog + ========================================================= + */ + +#include +#include + +inline const char* xmlAttr_getName( xmlAttrPtr attr ){ + return reinterpret_cast( attr->name ); } -void CXMLPropertyBag::GetPref( const char *name, float* pV, float* V ){ - xmlNodePtr pNode; - if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) { - sscanf( (char *)pNode->children->content, "%f %f %f", &pV[0], &pV[1], &pV[2] ); - } - else - { - char s[128]; - sprintf( s, "%f %f %f", V[0], V[1], V[2] ); - pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s ); - xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name ); - pV[0] = V[0]; - pV[1] = V[1]; - pV[2] = V[2]; - } - // push the pref assignment if needed - PushAssignment( name, PREF_VEC3, pV ); +inline const char* xmlAttr_getValue( xmlAttrPtr attr ){ + return reinterpret_cast( attr->children->content ); } -void CXMLPropertyBag::GetPref( const char *name, window_position_t* pV, window_position_t V ){ - xmlNodePtr pNode; - if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) { - WindowPosition_Parse( *pV, CString( (xmlChar *)pNode->children->content ) ); - } - else +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 ) { - CString str; - WindowPosition_Write( V, str ); - pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)str.GetBuffer() ); - xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name ); - *pV = V; + pNode = pNode->next; + } + if ( !pNode ) { + Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL ); } - // push the pref assignment if needed - PushAssignment( name, PREF_WNDPOS, pV ); -} -void CXMLPropertyBag::UpdatePrefTree(){ - // read the assignments and update the tree - list::iterator iPref; - for ( iPref = mPrefAssignments.begin(); iPref != mPrefAssignments.end(); iPref++ ) + for ( xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next ) { - CPrefAssignment *pPref = &( *iPref ); - // look for the node - xmlNodePtr pNode; - char s[64]; - - pNode = EpairForName( pPref->mName.GetBuffer() ); - // we never expect that the node could not be found, because this is supposed to happen - // after the tree was built with GetPref calls, never on a blank tree - if ( !pNode ) { - Sys_FPrintf( SYS_ERR, "Unexpected EpairForName '%s' not found in UpdatePrefTree\n", pPref->mName.GetBuffer() ); - return; - } - switch ( ( *iPref ).mType ) - { - case PREF_STR: - xmlNodeSetContent( pNode, (const xmlChar *)( (Str *)pPref->mVal )->GetBuffer() ); - break; - case PREF_INT: - sprintf( s, "%d", *(int *)pPref->mVal ); - xmlNodeSetContent( pNode, (xmlChar *)s ); - break; - case PREF_FLOAT: - sprintf( s, "%f", *(float *)pPref->mVal ); - xmlNodeSetContent( pNode, (xmlChar *)s ); - break; - case PREF_BOOL: - *(bool *)pPref->mVal ? strcpy( s, "true" ) : strcpy( s, "false" ); - xmlNodeSetContent( pNode, (xmlChar *)s ); - break; - case PREF_VEC3: - { - float* v = (float*)pPref->mVal; - sprintf( s, "%f %f %f", v[0], v[1], v[2] ); - xmlNodeSetContent( pNode, (xmlChar *)s ); - } - break; - case PREF_WNDPOS: - { - CString str; - WindowPosition_Write( *(window_position_t*)pPref->mVal, str ); - xmlNodeSetContent( pNode, (xmlChar*)str.GetBuffer() ); - } - break; - } + m_gameDescription.insert( GameDescription::value_type( xmlAttr_getName( attr ), xmlAttr_getValue( attr ) ) ); } -} -void CXMLPropertyBag::Clear(){ - if ( !InUse() ) { - return; + { + StringOutputStream path( 256 ); + path << DataPath_get() << "gamepacks/" << gameFile.c_str() << "/"; + mGameToolsPath = path.c_str(); } - xmlFreeDoc( mpDoc ); - mpDoc = NULL; - mpDocNode = NULL; - mbEmpty = false; -} + ASSERT_MESSAGE( file_exists( mGameToolsPath.c_str() ), "game directory not found: " << makeQuoted( mGameToolsPath.c_str() ) ); -void CXMLPropertyBag::ReadXMLFile( const char* pFilename ){ - mpDoc = xmlParseFile( pFilename ); + mGameFile = gameFile; - // basic checks - if ( mpDoc ) { - mpDocNode = mpDoc->children; - xmlAttrPtr tmp_attr_ptr = xmlHasProp( mpDocNode, (xmlChar *)"version" ); - if ( strcmp( (char *)mpDocNode->name, "qpref" ) ) { - Sys_FPrintf( SYS_ERR, "Unrecognized node '%s' in '%s'\n", mpDocNode->name, mpDoc->URL ); - xmlFreeDoc( mpDoc ); - mpDoc = NULL; + { + GameDescription::iterator i = m_gameDescription.find( "type" ); + if ( i == m_gameDescription.end() ) { + globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast( pDoc->URL ) << "'\n"; + // default + mGameType = "q3"; } - else if ( tmp_attr_ptr != NULL && strcmp( (char*)tmp_attr_ptr->children->content, "1" ) ) { - Sys_FPrintf( SYS_ERR, "Wrong version '%s' in node for '%s'\n", (char*)tmp_attr_ptr->children->content, mpDoc->URL ); - xmlFreeDoc( mpDoc ); - mpDoc = NULL; + else + { + mGameType = ( *i ).second.c_str(); } - Sys_Printf( "Opened XML property file: '%s'\n", pFilename ); - } - - if ( !mpDoc ) { - mbEmpty = true; - // no document, create one - mpDoc = xmlNewDoc( (xmlChar *)"1.0" ); - mpDocNode = xmlNewDocNode( mpDoc, NULL, (xmlChar *)"qpref", NULL ); - xmlDocSetRootElement( mpDoc, mpDocNode ); - xmlSetProp( mpDocNode, (xmlChar *)"version", (xmlChar *)"1" ); - Sys_Printf( "XML property file '%s' invalid/not found, creating blank properties tree\n", pFilename ); } } -qboolean CXMLPropertyBag::WriteXMLFile( const char* pFilename ){ - int res = xmlSaveFormatFile( pFilename, mpDoc, 1 ); - - if ( res == -1 ) { - return false; +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"; } - - Sys_Printf( "Wrote XML property file '%s'\n", pFilename ); - return true; } -// ============================================================================= -// Widget callbacks for PrefsDlg +CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription -#if !defined( WIN32 ) -// browse for custom editor executable -static void OnBtnBrowseEditor( GtkWidget *widget, gpointer data ){ - PrefsDlg *dlg = (PrefsDlg*)data; - const char *filename = file_dialog( g_PrefsDlg.GetWidget(), TRUE, _( "Executable for Custom Editor" ) ); +#include "warnings.h" +#include "stream/textfilestream.h" +#include "container/array.h" +#include "xml/ixml.h" +#include "xml/xmlparser.h" +#include "xml/xmlwriter.h" - if ( filename != NULL ) { - dlg->m_strEditorCommand = filename; - dlg->UpdateData( FALSE ); - } -} -#endif +#include "preferencedictionary.h" +#include "stringio.h" -static void OnBtnBrowseprefab( GtkWidget *widget, gpointer data ){ - PrefsDlg *dlg = (PrefsDlg*)data; - char *path = dlg->m_strPrefabPath; - if ( strlen( path ) == 0 ) { - path = g_strGameToolsPath; - } - char *dir = dir_dialog( g_PrefsDlg.GetWidget(), _( "Set prefab path" ), path ); - dlg->UpdateData( TRUE ); - - if ( dir != NULL ) { - CString strPath; - strPath = dir; - AddSlash( strPath ); - dlg->m_strPrefabPath = strPath; - dlg->UpdateData( FALSE ); - free( dir ); - } -} +const char* const PREFERENCES_VERSION = "1.0"; -static void OnBtnBrowseuserini( GtkWidget *widget, gpointer data ){ - PrefsDlg *dlg = (PrefsDlg*)data; - char *path = dlg->m_strUserPath; - if ( strlen( path ) == 0 ) { - path = g_strGameToolsPath; +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; } - // TODO: INI filter? - const char *filename = file_dialog( g_PrefsDlg.GetWidget(), TRUE, _( "Find INI file" ), path ); - - if ( filename != NULL ) { - dlg->UpdateData( TRUE ); - dlg->m_strUserPath = filename; - dlg->UpdateData( FALSE ); - } -} - -static void OnButtonClean( GtkWidget *widget, gpointer data ){ - // make sure this is what the user wants - if ( gtk_MessageBox( g_PrefsDlg.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" ), MB_YESNO ) == IDYES ) { - PrefsDlg *dlg = (PrefsDlg*)data; - dlg->EndModal( IDCANCEL ); - - g_qeglobals.disable_ini = true; - remove( dlg->m_inipath->str ); - char buf[PATH_MAX]; - sprintf( buf, "%sSavedInfo.bin", dlg->m_rc_path->str ); - remove( buf ); - HandleCommand( NULL, GINT_TO_POINTER( ID_FILE_EXIT ) ); - _exit( 0 ); - } -} - -// ============================================================================= -// PrefsDlg class - -// IMPORTANT NOTE: the values here don't matter very much -// the actual intialization if you start with an empty .ini is done when loading the prefs for the first time -// profile_load_int takes an argument to use if the value is not found -PrefsDlg::PrefsDlg (){ - m_bWarn = TRUE; - m_nMouse = 1; - m_nView = MainFrame::eRegular; - m_bLoadLast = FALSE; - m_bInternalBSP = FALSE; - m_bRightClick = FALSE; - m_bSetGame = FALSE; - m_bAutoSave = TRUE; - m_nAutoSave = 5; - m_bLoadLastMap = FALSE; - m_bTextureWindow = FALSE; - m_bSnapShots = FALSE; - m_fTinySize = 0.5; - m_bCleanTiny = FALSE; - m_bCamXYUpdate = TRUE; - m_bCamDragMultiSelect = FALSE; - m_bCamFreeLook = TRUE; - m_bCamFreeLookStrafe = FALSE; - m_bCamInverseMouse = FALSE; - m_bCamDiscrete = TRUE; - m_bNewLightDraw = FALSE; - m_strPrefabPath = ""; - m_nWhatGame = 0; - m_bALTEdge = FALSE; - m_bFaceColors = FALSE; - m_bXZVis = FALSE; - m_bYZVis = FALSE; - m_bZVis = FALSE; - m_bSizePaint = FALSE; - m_bDLLEntities = FALSE; -#ifdef _WIN32 - m_bDetachableMenus = FALSE; // Most win32 users will find detachable menus annoying -#else - m_bDetachableMenus = TRUE; // Linux/Apple users are used to them... -#endif - m_bPatchToolbar = TRUE; - m_bWideToolbar = TRUE; - m_bPluginToolbar = TRUE; - m_bNoClamp = FALSE; - m_bSnap = TRUE; - m_strUserPath = ""; - m_nRotation = 0; - m_bChaseMouse = FALSE; - m_bTextureScrollbar = TRUE; - m_bDisplayLists = TRUE; - m_bAntialiasedPointsAndLines = FALSE; // Fishman - Add antialiazed points and lines support. 09/03/00 - m_bShowShaders = FALSE; - m_nShader = -1; - m_bNoStipple = FALSE; - m_bVertexSplit = FALSE; - m_bSelectCurves = TRUE; - m_bSelectModels = TRUE; - m_nEntityShowState = ENTITY_SKINNED_BOXED; - m_nTextureScale = 2; - m_bSwitchClip = FALSE; - m_bSelectWholeEntities = TRUE; - m_nTextureQuality = 3; - m_bShowShaders = TRUE; - m_bGLLighting = FALSE; - m_nShader = 0; - m_nUndoLevels = 30; - m_bTexturesShaderlistOnly = FALSE; - // paths to ini files - m_rc_path = NULL; - m_inipath = NULL; - m_bWatchBSP = TRUE; - m_bLeakStop = TRUE; - m_iTimeout = 15; - m_bRunQuake = TRUE; - m_bDoSleep = FALSE; - m_nSubdivisions = 4; - // not prefs - m_bFloatingZ = FALSE; - m_bGlPtWorkaround = FALSE; // Gef: Kyro/GL_POINTS workaround 25-aug-2001 -#ifdef _WIN32 - m_bNativeGUI = FALSE; - m_bStartOnPrimMon = FALSE; -#endif - m_global_rc_path = NULL; -#ifdef _WIN32 - m_bUseWin32Editor = TRUE; -#else - // custom shader editor options - m_bUseCustomEditor = FALSE; - m_strEditorCommand = ""; -#endif - m_nLightRadiuses = 1; - m_bQ3Map2Texturing = TRUE; -#ifdef ATIHACK_812 - m_bGlATIHack = FALSE; -#endif -#ifdef NVIDIA_AERO_HACK - m_bGlNvidiaAeroHack = TRUE; - m_bGlNvidiaAeroHackPrevState = -1; // -1 is uninitialized, 0 is FALSE, 1 is TRUE -#endif -} -/*! - ========================================================= - Games selection dialog - ========================================================= - */ - -#if defined( WIN32 ) -#define TOOLS_ATTRIBUTE "gametools_win32" -#define ENGINE_ATTRIBUTE "engine_win32" -#define ENGINEPATH_ATTRIBUTE "enginepath_win32" -#define MP_ENGINE_ATTRIBUTE "mp_engine_win32" -#elif defined( __linux__ ) || defined ( __FreeBSD__ ) -#define TOOLS_ATTRIBUTE "gametools_linux" -#define ENGINE_ATTRIBUTE "engine_linux" -#define ENGINEPATH_ATTRIBUTE "enginepath_linux" -#define MP_ENGINE_ATTRIBUTE "mp_engine_linux" -#elif defined( __APPLE__ ) -#define TOOLS_ATTRIBUTE "gametools_macos" -#define ENGINE_ATTRIBUTE "engine_macos" -#define ENGINEPATH_ATTRIBUTE "enginepath_macos" -#define MP_ENGINE_ATTRIBUTE "mp_engine_macos" -#else -#error "unsupported platform" -#endif - -CGameDescription::CGameDescription( xmlDocPtr pDoc, const Str &GameFile ){ - char *p, *prop; - mpDoc = pDoc; - // read the user-friendly game name - xmlNodePtr pNode = mpDoc->children; - - while ( strcmp( (const char*)pNode->name, "game" ) && pNode != NULL ) pNode = pNode->next; - if ( !pNode ) { - ///< \todo add the file name (this node and gametools should all be part of CGameDescription anyway) - Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL ); - } - // on win32, game tools path can now be specified relative to the exe's cwd - prop = (char*)xmlGetProp( pNode, (xmlChar*)TOOLS_ATTRIBUTE ); - if ( prop == NULL ) { - Error( "Didn't find '"TOOLS_ATTRIBUTE "' node in the game description file '%s'\n", pDoc->URL ); - } + int l = strlen( cmdline_prefix ); + for ( int i = 1; i < g_argc - 1; ++i ) { - char full[PATH_MAX]; -#ifdef _WIN32 - _fullpath( full, prop, PATH_MAX ); -#else - strncpy( full, prop, PATH_MAX ); -#endif - xmlFree( prop ); - prop = NULL; - for ( p = full; *p != '\0'; p++ ) { - if ( *p == '\\' ) { - *p = '/'; - } - mGameToolsPath = full; - if ( p != full && *( p - 1 ) != '/' ) { - mGameToolsPath += "/"; + 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; } } - prop = (char*)xmlGetProp( pNode, (xmlChar*)"name" ); - if ( prop == NULL ) { - Sys_FPrintf( SYS_WRN, "Warning, 'name' attribute not found in '%s'\n", pDoc->URL ); - mGameName = pDoc->URL; - } - else - { - mGameName = prop; - xmlFree( prop ); - } - - mGameFile = GameFile; + return ret; +} - prop = (char*)xmlGetProp( pNode, (xmlChar*)"quake2" ); - if ( prop == NULL ) { - // default - quake2 = false; - } - else - { - quake2 = true; - xmlFree( prop ); +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; +} - // if this is set, the open maps dialoge will open the engine path not the - // home dir for map loading and saving - prop = (char*)xmlGetProp( pNode, (xmlChar*)"no_maps_in_home" ); - if ( prop == NULL ) { - // default - noMapsInHome = false; - } - else - { - noMapsInHome = true; - xmlFree( prop ); - } +bool Preferences_Save_Safe( PreferenceDictionary& preferences, const char* filename ){ + std::string tmpName( filename ); + tmpName += "TMP"; - prop = (char*)xmlGetProp( pNode, (xmlChar*)"basegame" ); - if ( prop == NULL ) { - // default - mBaseGame = "baseq3"; - } - else - { - mBaseGame = prop; - xmlFree( prop ); - } + return Preferences_Save( preferences, tmpName.c_str() ) + && ( !file_exists( filename ) || file_remove( filename ) ) + && file_move( tmpName.data(), filename ); +} - prop = (char*)xmlGetProp( pNode, (const xmlChar*)ENGINE_ATTRIBUTE ); - if ( prop == NULL ) { -#ifdef _WIN32 - mEngine = "quake3.exe"; -#elif __linux__ - mEngine = "quake3"; -#elif __APPLE__ - mEngine = "Quake3.app"; -#endif - } - else - { - mEngine = prop; - xmlFree( prop ); +struct LogConsole { + static void Export(const Callback &returnz) { + returnz(g_Console_enableLogging); } - prop = (char*)xmlGetProp( pNode, (const xmlChar*)MP_ENGINE_ATTRIBUTE ); - if ( prop == NULL ) { -#ifdef _WIN32 - mMultiplayerEngine = "quake3.exe"; -#elif __linux__ - mMultiplayerEngine = "quake3"; -#elif __APPLE__ - mMultiplayerEngine = "Quake3.app"; -#endif - } - else - { - mMultiplayerEngine = prop; - xmlFree( prop ); + static void Import(bool value) { + g_Console_enableLogging = value; + Sys_EnableLogFile(g_Console_enableLogging); } +}; - { - // on win32, engine path can now be specified relative to the exe's cwd - prop = (char*)xmlGetProp( pNode, (const xmlChar *)ENGINEPATH_ATTRIBUTE ); - if ( prop != NULL ) { - char full[PATH_MAX]; - #ifdef _WIN32 - _fullpath( full, prop, PATH_MAX ); - #else - strncpy( full, prop, PATH_MAX ); - #endif - xmlFree( prop ); - prop = NULL; - // process seperators - for ( p = full; *p != '\0'; p++ ) { - if ( *p == '\\' ) { - *p = '/'; - } - } - mEnginePath = full; - if ( p != full && *( p - 1 ) != '/' ) { - mEnginePath += "/"; - } - } - else - { - // if engine path was not specified in the .game, it implies we can guess it from the gametools path - // on win32, and for most game package, the gametools are installed with the game - char aux_path[PATH_MAX]; // aux - strcpy( aux_path, mGameToolsPath.GetBuffer() ); - if ( ( aux_path[ strlen( aux_path ) - 1 ] == '/' ) || ( aux_path[ strlen( aux_path ) - 1 ] == '\\' ) ) { - aux_path[strlen( aux_path ) - 1] = '\0'; // strip ending '/' if any - } - char up_path[PATH_MAX]; // up one level - ExtractFilePath( aux_path, up_path ); - mEnginePath = up_path; - } - } -#if defined ( __linux__ ) || defined ( __APPLE__ ) - // *nix specific - prop = (char*)xmlGetProp( pNode, (const xmlChar *)"prefix" ); - if ( prop != NULL ) { - mUserPathPrefix = prop; - xmlFree( prop ); - } -#endif - mShaderPath = xmlGetProp( pNode, (const xmlChar *)"shaderpath" ); - if ( !mShaderPath.GetLength() ) { - mShaderPath = "scripts/"; - mShaderlist = "scripts/shaderlist.txt"; - } - else - { - AddSlash( mShaderPath ); - mShaderlist = mShaderPath; - mShaderlist += "shaderlist.txt"; - } - xmlChar* default_scale = xmlGetProp( pNode, (const xmlChar *)"default_scale" ); - if ( default_scale ) { - mTextureDefaultScale = atof( (const char *)default_scale ); - xmlFree( default_scale ); - } - else{ - mTextureDefaultScale = 0.5f; - } - xmlChar* eclass_singleload = xmlGetProp( pNode, (const xmlChar*)"eclass_singleload" ); - if ( eclass_singleload ) { - mEClassSingleLoad = true; - xmlFree( eclass_singleload ); - } - else{ - mEClassSingleLoad = false; - } - xmlChar* no_patch = xmlGetProp( pNode, (const xmlChar *)"no_patch" ); - if ( no_patch ) { - mNoPatch = true; - xmlFree( no_patch ); - } - else{ - mNoPatch = false; - } - xmlChar* caulk_shader = xmlGetProp( pNode, (const xmlChar *)"caulk_shader" ); - if ( caulk_shader ) { - mCaulkShader = caulk_shader; - xmlFree( caulk_shader ); - } - else{ - mCaulkShader = "textures/common/caulk"; - } +void RegisterGlobalPreferences( PreferenceSystem& preferences ){ + preferences.registerPreference( "gamefile", make_property_string( g_GamesDialog.m_sGameFile ) ); + preferences.registerPreference( "gamePrompt", make_property_string( g_GamesDialog.m_bGamePrompt ) ); + preferences.registerPreference( "skipGamePromptOnce", make_property_string( g_GamesDialog.m_bSkipGamePromptOnce ) ); + preferences.registerPreference( "log console", make_property_string() ); } -void CGameDescription::Dump(){ -#ifdef _WIN32 - if ( CGameDialog::GetNetrun() ) { - Sys_Printf( "Running in network mode, prefs path set to '%s'\n", g_strTempPath.GetBuffer() ); - } -#endif - Sys_Printf( "game name : '%s'\n", mGameName.GetBuffer() ); - Sys_Printf( "game file : '%s'\n", mGameFile.GetBuffer() ); - Sys_Printf( "game path : '%s'\n", mGameToolsPath.GetBuffer() ); - Sys_Printf( "base game : '%s'\n", mBaseGame.GetBuffer() ); - Sys_Printf( "engine path : '%s'\n", mEnginePath.GetBuffer() ); - Sys_Printf( "engine : '%s'\n", mEngine.GetBuffer() ); - Sys_Printf( "shaderlist : '%s'\n", mShaderlist.GetBuffer() ); - Sys_Printf( "caulk shader: '%s'\n", mCaulkShader.GetBuffer() ); -#if defined ( __linux__ ) || defined ( __APPLE__ ) - Sys_Printf( "prefix : '%s'\n", mUserPathPrefix.GetBuffer() ); -#endif - Sys_Printf( "default texture scale: %g\n", mTextureDefaultScale ); - Sys_Printf( "single eclass load : %s\n", mEClassSingleLoad ? "Yes" : "No" ); - Sys_Printf( "patches supported : %s\n", mNoPatch ? "No" : "Yes" ); -} -CPrefAssignment& CPrefAssignment::operator =( const CPrefAssignment& ass ){ - if ( &ass != this ) { - mName = ass.mName; - mType = ass.mType; - mVal = ass.mVal; - } - return *this; -} +PreferenceDictionary g_global_preferences; -CPrefAssignment::CPrefAssignment( const CPrefAssignment& ass ){ - *this = ass; +void GlobalPreferences_Init(){ + RegisterGlobalPreferences( g_global_preferences ); } void CGameDialog::LoadPrefs(){ - // if we already have a document loaded, we will free and reload from file - if ( mGlobalPrefs.InUse() ) { - Sys_Printf( "Reloading global prefs from file\n" ); - mGlobalPrefs.Clear(); - } - // load global .pref file - CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; - strGlobalPref += "global.pref"; - - mGlobalPrefs.ReadXMLFile( strGlobalPref.GetBuffer() ); - - mGlobalPrefs.GetPref( "gamefile", &m_sGameFile, "" ); // NOTE: there's no default, user HAS to select something - mGlobalPrefs.GetPref( "autoload", &m_bAutoLoadGame, false ); - mGlobalPrefs.GetPref( "log console", &m_bLogConsole, false ); - // in a very particular post-.pid startup - // we may have the console turned on and want to keep it that way - // so we use a latching system - if ( m_bForceLogConsole ) { - m_bLogConsole = true; - Sys_Printf( "console logging has been latched on, saving prefs\n" ); - SavePrefs(); - m_bForceLogConsole = false; - } + StringOutputStream strGlobalPref( 256 ); + strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref"; - // console logging: call Sys_LogConsole to check console logging status - // it is important that we would log console as early as possible to make it useful - Sys_LogFile(); + globalOutputStream() << "loading global preferences from " << makeQuoted( strGlobalPref.c_str() ) << "\n"; - if ( mGlobalPrefs.mbEmpty ) { - Sys_Printf( "Saving global.pref with default pref values\n" ); - SavePrefs(); + if ( !Preferences_Load( g_global_preferences, strGlobalPref.c_str(), "global" ) ) { + globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n"; } } void CGameDialog::SavePrefs(){ - // update the tree and save it - mGlobalPrefs.UpdatePrefTree(); + StringOutputStream strGlobalPref( 256 ); + strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref"; - CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; - strGlobalPref += "global.pref"; + globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n"; - if ( !mGlobalPrefs.WriteXMLFile( strGlobalPref.GetBuffer() ) ) { - Sys_FPrintf( SYS_ERR, "Error occured while saving global prefs file '%s'\n", strGlobalPref.GetBuffer() ); + if ( !Preferences_Save_Safe( g_global_preferences, strGlobalPref.c_str() ) ) { + globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n"; } } -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(); -} - -void CGameDialog::DoGameDialog() { - // allow looping the game selection dialog with calls to the game configure dialog in between - while ( m_bDoGameInstall ) { - - m_bDoGameInstall = false; - - if ( DoModal() == IDCANCEL ) { - Error( "game selection dialog canceled, cannot continue" ); - return; - } - - if ( m_bDoGameInstall ) { - DoGameInstall(); - ScanForGames(); - // and we will loop to do another DoModal dialog - } - } - - // unhook so we can use in other places - // we manually incref'ed it when creating, it won't be freed (destructor) - gtk_container_remove( GTK_CONTAINER( mTopBox ), GetGlobalFrame() ); +void CGameDialog::DoGameDialog(){ + // show the UI + DoModal(); // we save the prefs file SavePrefs(); } -GtkWidget* CGameDialog::GetGlobalFrame(){ - GtkWidget *vbox, *text, *combo, *check; - - if ( mFrame != NULL ) { - return mFrame; +void CGameDialog::GameFileImport( int value ){ + m_nComboSelect = value; + // use value to set m_sGameFile + std::list::iterator iGame = mGames.begin(); + int i; + for ( i = 0; i < value; i++ ) + { + ++iGame; } - mFrame = gtk_frame_new( NULL ); - gtk_container_set_border_width( GTK_CONTAINER( mFrame ), 5 ); - gtk_widget_show( mFrame ); - - vbox = gtk_vbox_new( FALSE, 6 ); - gtk_widget_show( vbox ); - gtk_container_add( GTK_CONTAINER( mFrame ), vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - - text = gtk_label_new( _( "Select the game:" ) ); - gtk_widget_show( text ); - gtk_box_pack_start( GTK_BOX( vbox ), text, FALSE, FALSE, 0 ); - - 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 ); - - UpdateGameCombo(); - - check = gtk_check_button_new_with_label( _( "Auto load selected game on startup" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bAutoLoadGame, DLG_CHECK_BOOL ); - - text = gtk_label_new( _( "(this frame is available in the prefs menu if you set auto-select)" ) ); - gtk_widget_show( text ); - gtk_box_pack_start( GTK_BOX( vbox ), text, FALSE, FALSE, 0 ); - -#ifdef _WIN32 - check = gtk_check_button_new_with_label( _( "Networked install - per-user settings" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bNetRun, DLG_CHECK_BOOL ); -#endif - - check = gtk_check_button_new_with_label( _( "Log the console to radiant.log" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLogConsole, DLG_CHECK_BOOL ); + if ( ( *iGame )->mGameFile != m_sGameFile ) { + m_sGameFile = ( *iGame )->mGameFile; - // incref it so we can pass it around - gtk_widget_ref( GTK_WIDGET( mFrame ) ); + // do not trigger radiant restart when switching game on startup using Global Preferences dialog + if ( !onStartup ) { + PreferencesDialog_restartRequired( "Selected Game" ); + } + } - return mFrame; + // onStartup can only be true once, when Global Preferences are displayed at startup + onStartup = false; } -void CGameDialog::UpdateData( bool retrieve ) { - if ( !retrieve ) { - // use m_sGameFile to set m_nComboSelect - list::iterator iGame; - int i = 0; - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) - { - if ( ( *iGame )->mGameFile == m_sGameFile ) { - m_nComboSelect = i; - break; - } - i++; - } -#ifdef _WIN32 - UpdateNetrun( false ); -#endif - } - Dialog::UpdateData( retrieve ); - if ( retrieve ) { - // use m_nComboSelect to set m_sGameFile - list::iterator iGame = mGames.begin(); - int i; - for ( i = 0; i < m_nComboSelect; i++ ) - { - iGame++; +void CGameDialog::GameFileExport( const Callback & importCallback ) const { + // use m_sGameFile to set value + std::list::const_iterator iGame; + int i = 0; + for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame ) + { + if ( ( *iGame )->mGameFile == m_sGameFile ) { + m_nComboSelect = i; + break; } - m_sGameFile = ( *iGame )->mGameFile; -#ifdef _WIN32 - UpdateNetrun( true ); -#endif + i++; } + importCallback( m_nComboSelect ); } -void CGameDialog::SInstallCallback( GtkWidget *widget, gpointer data ) { - CGameDialog *d = static_cast< CGameDialog* >( data ); - d->m_bDoGameInstall = true; - d->EndModal( 0 ); -} - -void CGameDialog::BuildDialog() { - GtkWidget *dlg, *vbox1, *button, *setup_button; - - dlg = m_pWidget; - gtk_window_set_title( GTK_WINDOW( dlg ), _( "Select Game" ) ); - - vbox1 = gtk_vbox_new( FALSE, 0 ); - gtk_widget_show( vbox1 ); - gtk_container_add( GTK_CONTAINER( dlg ), vbox1 ); - - gtk_container_add( GTK_CONTAINER( vbox1 ), GetGlobalFrame() ); - mTopBox = vbox1; - - setup_button = gtk_button_new_with_label( _( "Configure more games" ) ); - gtk_widget_show( setup_button ); - gtk_box_pack_start( GTK_BOX( vbox1 ), setup_button, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( setup_button ), "clicked", - GTK_SIGNAL_FUNC( SInstallCallback ), this ); - - button = gtk_button_new_with_label( _( "OK" ) ); - gtk_widget_show( button ); - gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 ); - AddModalButton( button, IDOK ); +struct CGameDialog_GameFile { + static void Export(const CGameDialog &self, const Callback &returnz) { + self.GameFileExport(returnz); + } - 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 ); + static void Import(CGameDialog &self, int value) { + self.GameFileImport(value); + } +}; - gtk_widget_set_usize( button, 60, -2 ); +void CGameDialog::CreateGlobalFrame( PreferencesPage& page ){ + std::vector games; + games.reserve( mGames.size() ); + for ( std::list::iterator i = mGames.begin(); i != mGames.end(); ++i ) + { + games.push_back( ( *i )->getRequiredKeyValue( "name" ) ); + } + page.appendCombo( + "Select the game", + StringArrayRange( &( *games.begin() ), &( *games.end() ) ), + make_property(*this) + ); + page.appendCheckBox( "Startup", "Show Global Preferences", m_bGamePrompt ); } -void CGameDialog::UpdateGameCombo() { - // fill in with the game descriptions - list::iterator iGame; +ui::Window CGameDialog::BuildDialog(){ + auto frame = create_dialog_frame( "Game settings", ui::Shadow::ETCHED_IN ); - if ( mGameCombo == NULL ) { - Sys_Printf( "mGameCombo == NULL\n" ); - return; - } + auto vbox2 = create_dialog_vbox( 0, 4 ); + frame.add(vbox2); - // 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 ); + { + PreferencesPage preferencesPage( *this, vbox2 ); + Global_constructPreferences( preferencesPage ); + CreateGlobalFrame( preferencesPage ); } - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) { - gtk_combo_box_append_text( mGameCombo, ( *iGame )->mGameName.GetBuffer() ); - } - gtk_combo_box_set_active( mGameCombo, 0 ); + return create_simple_modal_dialog_window( "Global Preferences", m_modal, frame ); } void CGameDialog::ScanForGames(){ - CString strPath; - char *dirlist; - GDir *dir; - CString strGamesPath = g_strAppPath.GetBuffer(); - strGamesPath += "games"; - const char *path = strGamesPath.GetBuffer(); - - if ( !mGames.empty() ) { - Sys_Printf( "Clearing game list\n" ); - list::iterator iGame; - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) { - delete ( *iGame ); - } - mGames.clear(); - } + StringOutputStream strGamesPath( 256 ); + strGamesPath << DataPath_get() << "gamepacks/games/"; + const char *path = strGamesPath.c_str(); - Sys_Printf( "Scanning for game description files: %s\n", path ); + globalOutputStream() << "Scanning for game description files: " << path << '\n'; /*! \todo FIXME LINUX: - do we put game description files below g_strAppPath, or in ~/.radiant + 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//games/ scanning on top of that for developers (if that's really needed) */ - // FIXME need to catch the 'no game description' situation and exit with a clean error - - dir = g_dir_open( path, 0, NULL ); - - if ( dir != NULL ) { - while ( 1 ) - { - const gchar* name = g_dir_read_name( dir ); - if ( name == NULL ) { - break; - } - - dirlist = g_strdup( name ); -#ifdef _WIN32 - strlwr( dirlist ); -#endif - char *ext = strrchr( dirlist, '.' ); - if ( ( ext == NULL ) || ( strcmp( ext, ".game" ) != 0 ) ) { - continue; - } - strPath.Format( "%s/%s", path, dirlist ); - Sys_Printf( "%s\n", strPath.GetBuffer() ); - // got one, load it - xmlDocPtr pDoc = xmlParseFile( strPath.GetBuffer() ); - if ( pDoc ) { - mGames.push_front( new CGameDescription( pDoc, dirlist ) ); - } - else - { - Sys_FPrintf( SYS_ERR, "XML parser failed on '%s'\n", strPath.GetBuffer() ); - } - - g_free( dirlist ); + Directory_forEach(path, [&](const char *name) { + if (!extension_equal(path_get_extension(name), "game")) { + return; } - g_dir_close( dir ); - } + StringOutputStream strPath(256); + strPath << path << name; + globalOutputStream() << strPath.c_str() << '\n'; - // entries in the combo need to be updated - UpdateGameCombo(); + xmlDocPtr pDoc = xmlParseFile(strPath.c_str()); + if (pDoc) { + mGames.push_front(new CGameDescription(pDoc, name)); + xmlFreeDoc(pDoc); + } else { + globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n"; + } + }); } CGameDescription* CGameDialog::GameDescriptionForComboItem(){ - list::iterator iGame; + std::list::iterator iGame; int i = 0; - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++,i++ ) { + for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame,i++ ) + { if ( i == m_nComboSelect ) { return ( *iGame ); } } - return NULL; // not found + return 0; // not found } void CGameDialog::InitGlobalPrefPath(){ - GString *global_rc_path; - // configure m_global_rc_path - // this is the g_strTempPath, and it has already been mkdir'ed - global_rc_path = g_string_new( g_strTempPath.GetBuffer() ); - g_PrefsDlg.m_global_rc_path = global_rc_path; + g_Preferences.m_global_rc_path = g_string_new( SettingsPath_get() ); } void CGameDialog::Reset(){ - if ( !g_PrefsDlg.m_global_rc_path ) { + if ( !g_Preferences.m_global_rc_path ) { InitGlobalPrefPath(); } - CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; - strGlobalPref += "global.pref"; - remove( strGlobalPref.GetBuffer() ); + StringOutputStream strGlobalPref( 256 ); + strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref"; + file_remove( strGlobalPref.c_str() ); } void CGameDialog::Init(){ + bool gamePrompt = false; + InitGlobalPrefPath(); - ScanForGames(); - if ( mGames.empty() ) { - DoGameInstall(); - ScanForGames(); - if ( mGames.empty() ) { - Error( "No games setup, aborting\n" ); - } - } LoadPrefs(); - if ( m_bAutoLoadGame ) { - // search by .game name - list::iterator iGame; - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) - { - if ( ( *iGame )->mGameFile == m_sGameFile ) { - m_pCurrentGameDescription = ( *iGame ); - break; - } - } - } - if ( !m_bAutoLoadGame || !m_pCurrentGameDescription ) { - DoGameDialog(); - // use m_nComboSelect to identify the game to run as and set the globals - m_pCurrentGameDescription = GameDescriptionForComboItem(); - if ( !m_pCurrentGameDescription ) { - Error( "Lookup of game description object failed, can't continue\n" ); - } - } - g_pGameDescription = m_pCurrentGameDescription; - - g_strGameToolsPath = g_pGameDescription->mGameToolsPath; - - // NOTE TTimo: this is moved from QE_LoadProject in 1.2 - // (probably broken) - // NOTE Hydra: was broken for win32, we don't use m_strHomeGame or m_strFSBasePath -#if defined ( __linux__ ) || defined ( __APPLE__ ) - g_qeglobals.m_strHomeGame = g_get_home_dir(); - g_qeglobals.m_strHomeGame += "/"; - g_qeglobals.m_strHomeGame += m_pCurrentGameDescription->mUserPathPrefix.GetBuffer(); - g_qeglobals.m_strHomeGame += "/"; -#else - g_qeglobals.m_strHomeGame = g_pGameDescription->mEnginePath.GetBuffer(); -#endif - - g_pGameDescription->Dump(); -} - -CGameDialog::~CGameDialog(){ - if ( mFrame ) { - // NOTE I'm not too sure how reliable this is - gtk_widget_unref( GTK_WIDGET( mFrame ) ); - } - // free all the game descriptions - list::iterator iGame; - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) - { - delete ( *iGame ); - *iGame = NULL; - } -} - -void CGameDialog::AddPacksURL( Str &URL ){ - // add the URLs for the list of game packs installed - // FIXME: this is kinda hardcoded for now.. - list::iterator iGame; - for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) - { - if ( ( *iGame )->mGameFile == "q3.game" ) { - URL += "&Games_dlup%5B%5D=1"; - } - else if ( ( *iGame )->mGameFile == "wolf.game" ) { - URL += "&Games_dlup%5B%5D=2"; - } - // FIXME: double entry - else if ( ( *iGame )->mGameFile == "wolf.game" ) { - URL += "&Games_dlup%5B%5D=3"; - } - else if ( ( *iGame )->mGameFile == "jk2.game" ) { - URL += "&Games_dlup%5B%5D=4"; - } - else if ( ( *iGame )->mGameFile == "stvef.game" ) { - URL += "&Games_dlup%5B%5D=5"; - } - else if ( ( *iGame )->mGameFile == "sof2.game" ) { - URL += "&Games_dlup%5B%5D=6"; - } - else if ( ( *iGame )->mGameFile == "ja.game" ) { - URL += "&Games_dlup%5B%5D=7"; - } - } -} - -#ifdef _WIN32 - -#define NETRUN_FILENAME "netrun.conf" - -bool CGameDialog::m_bNetRun; + ScanForGames(); -void CGameDialog::UpdateNetrun( bool retrieve ){ - FILE *f_netrun; - CString strNetrun; - strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; - if ( !retrieve ) { - // now check if we are running from a network installation - // use a dummy file as the flag - f_netrun = fopen( strNetrun.GetBuffer(), "r" ); - if ( f_netrun ) { - fclose( f_netrun ); - m_bNetRun = true; - } - else{ - m_bNetRun = false; - } + if ( mGames.empty() ) { + Error( "Didn't find any valid game file descriptions, aborting\n" ); } else { - if ( m_bNetRun ) { - f_netrun = fopen( strNetrun.GetBuffer(), "w" ); - if ( !f_netrun ) { - Sys_FPrintf( SYS_ERR, "ERROR: Failed to create netrun file '%s'\n", strNetrun.GetBuffer() ); - m_bNetRun = false; - } - else - { - fclose( f_netrun ); - Sys_Printf( "Created/Checked '%s'\n", strNetrun.GetBuffer() ); - } - } - else + std::list::iterator iGame, iPrevGame; + for ( iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame ) { - if ( remove( strNetrun.GetBuffer() ) == -1 ) { - if ( errno != ENOENT ) { - Sys_FPrintf( SYS_ERR, "Failed to remove netrun file '%s'\n", strNetrun.GetBuffer() ); + if ( iPrevGame != mGames.end() ) { + if ( strcmp( ( *iGame )->getRequiredKeyValue( "name" ), ( *iPrevGame )->getRequiredKeyValue( "name" ) ) < 0 ) { + CGameDescription *h = *iGame; + *iGame = *iPrevGame; + *iPrevGame = h; } - m_bNetRun = true; - } - else - { - Sys_Printf( "Netrun mode is disabled\n" ); } } } -} - -bool CGameDialog::GetNetrun(){ - return m_bNetRun; -} -#endif - -/* - ======== - - 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 - - win32: - look in g_strGameToolsPath for .ini - - linux: - look in ~/.radiant//gamename - ======== - */ -#define PREFS_LOCAL_FILENAME "local.pref" + CGameDescription* currentGameDescription = 0; -void PrefsDlg::Init(){ - mGamesDialog.Init(); - - // m_global_rc_path has been set above, do m_rc_path with game specific stuff now - // the win32 and linux versions have been unified for network mode -#ifdef _WIN32 - if ( !CGameDialog::GetNetrun() ) { - // legacy prefs settings, this goes where the game pack is installed - m_rc_path = g_string_new( g_strGameToolsPath.GetBuffer() ); - m_inipath = g_string_new( m_rc_path->str ); - g_string_append( m_inipath, PREFS_LOCAL_FILENAME ); - return; + // m_bSkipGamePromptOnce is used to not prompt for game on restart, only on fresh startup + if ( m_bGamePrompt && !m_bSkipGamePromptOnce ) { + gamePrompt = true; } -#endif - // 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.GetBuffer() ); - g_string_append( m_rc_path, "/" ); - Q_mkdir( m_rc_path->str, 0775 ); - // then the ini file - m_inipath = g_string_new( m_rc_path->str ); - g_string_append( m_inipath, PREFS_LOCAL_FILENAME ); - -} - -void PrefsDlg::UpdateData( bool retrieve ){ - // leo: the "changed" signal confuses the update function - if ( m_pWidget == NULL ) { - return; - } - mGamesDialog.UpdateData( retrieve ); - Dialog::UpdateData( retrieve ); -} - -#ifdef _WIN32 -#define PREFSHSPACE 5 -#else -#define PREFSHSPACE 0 -#endif - -static void UpdateSensitivity( GtkWidget *widget, gpointer data ){ - PrefsDlg *dlg = (PrefsDlg*)data; - dlg->DoSensitivity(); -} - -static void UpdateEditorSensitivity( GtkWidget *widget, gpointer data ){ - PrefsDlg *dlg = (PrefsDlg*)data; - dlg->DoEditorSensitivity(); -} - -// start new prefs dialog - -/*! Utility function for swapping notebook pages for tree list selections */ -void PrefsDlg::showPrefPage( int prefpage ){ - if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != prefpage ) { - gtk_notebook_set_page( GTK_NOTEBOOK( 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 ) ) { - int prefpage; - gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 ); - dlg->showPrefPage( prefpage ); - } -} - -void PrefsDlg::BuildDialog(){ - // Main Preferences dialog - GtkWidget *dialog, *mainvbox, *hbox, *sc_win, *preflabel; - - // Widgets on notebook pages - GtkWidget *check, *label, *scale, *hbox2, *combo, - *table, *spin, *entry, *pixmap, - *radio, *button, *pageframe, *vbox; - - GList *combo_list = (GList*)NULL; - - GtkObject *adj; - - dialog = m_pWidget; - gtk_window_set_title( GTK_WINDOW( dialog ), _( "GtkRadiant Preferences" ) ); - gtk_widget_realize( dialog ); - - 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 ); - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_widget_show( hbox ); - gtk_box_pack_end( GTK_BOX( mainvbox ), hbox, FALSE, TRUE, 0 ); - - button = gtk_button_new_with_label( _( "OK" ) ); - gtk_widget_show( button ); - gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 ); - gtk_widget_set_usize( button, 60, -2 ); - AddModalButton( button, IDOK ); - - button = gtk_button_new_with_label( _( "Cancel" ) ); - gtk_widget_show( button ); - gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 ); - gtk_widget_set_usize( button, 60, -2 ); - AddModalButton( button, IDCANCEL ); - - button = gtk_button_new_with_label( _( "Clean" ) ); - gtk_widget_show( button ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnButtonClean ), this ); - gtk_box_pack_start( GTK_BOX( hbox ), button, FALSE, FALSE, 0 ); - gtk_widget_set_usize( button, 60, -2 ); - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( mainvbox ), hbox, TRUE, TRUE, 0 ); - gtk_widget_show( hbox ); - - sc_win = gtk_scrolled_window_new( NULL, NULL ); - 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 ); - - // prefs pages notebook - notebook = gtk_notebook_new(); - // hide the notebook tabs since its not supposed to look like a notebook - gtk_notebook_set_show_tabs( GTK_NOTEBOOK( notebook ), FALSE ); - gtk_box_pack_start( GTK_BOX( hbox ), notebook, TRUE, TRUE, 0 ); - gtk_widget_show( notebook ); - - gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN ); - - { - 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, NULL ); - 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 ); + m_bSkipGamePromptOnce = false; + g_GamesDialog.SavePrefs(); + if ( !gamePrompt ) { + // search by .game name + std::list::iterator iGame; + for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame ) { - /********************************************************************/ - /* Add preference tree options */ - /********************************************************************/ - { - GtkTreeIter group; - gtk_tree_store_append( store, &group, NULL ); - gtk_tree_store_set( store, &group, 0, _( "Globals" ), 1, PTAB_FRONT, -1 ); - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Game settings" ), 1, (gpointer)PTAB_GAME_SETTINGS, -1 ); - } - } - - { - GtkTreeIter group; - gtk_tree_store_append( store, &group, NULL ); - gtk_tree_store_set( store, &group, 0, _( "Display" ), 1, PTAB_FRONT, -1 ); - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "2D Display/Rendering" ), 1, (gpointer)PTAB_2D, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "3D View" ), 1, (gpointer)PTAB_CAMERA, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Texture Settings" ), 1, (gpointer)PTAB_TEXTURE, -1 ); - } - } - - { - GtkTreeIter group; - gtk_tree_store_append( store, &group, NULL ); - gtk_tree_store_set( store, &group, 0, _( "Interface" ), 1, PTAB_FRONT, -1 ); - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Layout" ), 1, (gpointer)PTAB_LAYOUT, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Mouse" ), 1, (gpointer)PTAB_MOUSE, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Editing" ), 1, (gpointer)PTAB_EDITING, -1 ); - } - } - - { - GtkTreeIter group; - gtk_tree_store_append( store, &group, NULL ); - gtk_tree_store_set( store, &group, 0, _( "Other" ), 1, PTAB_FRONT, -1 ); - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Startup/Auto save" ), 1, (gpointer)PTAB_STARTUP, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Paths" ), 1, (gpointer)PTAB_PATHS, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Brush" ), 1, (gpointer)PTAB_BRUSH, -1 ); - } - { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "Misc" ), 1, (gpointer)PTAB_MISC, -1 ); - } - if ( !g_qeglobals.bBSPFrontendPlugin ) { - GtkTreeIter tab; - gtk_tree_store_append( store, &tab, &group ); - gtk_tree_store_set( store, &tab, 0, _( "BSP Monitoring" ), 1, (gpointer)PTAB_BSPMONITOR, -1 ); - } + if ( ( *iGame )->mGameFile == m_sGameFile ) { + currentGameDescription = ( *iGame ); + break; } } - - gtk_tree_view_expand_all( GTK_TREE_VIEW( view ) ); - - g_object_unref( G_OBJECT( store ) ); } - /**********************************************************************/ - /* build the prefs pages */ - /**********************************************************************/ - - // Front page... - // todo : add something interesting here - // NOTE TTimo: tip of the day? or a logo? - preflabel = gtk_label_new( _( "Front Page" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( NULL ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_widget_set_usize( GTK_WIDGET( vbox ), 350, -2 ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - - /******** global preferences group ****************************/ - preflabel = gtk_label_new( _( "Globals" ) ); - gtk_widget_show( preflabel ); - - pageframe = mGamesDialog.GetGlobalFrame(); - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - - /******** 2D prefs group (xy views/rendering options) *********/ - preflabel = gtk_label_new( _( "2D Display" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "2D Display" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // OpenGL Display Lists - check = gtk_check_button_new_with_label( _( "OpenGL Display Lists" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bDisplayLists, DLG_CHECK_BOOL ); - - // Antialiased points & lines - // Fishman - Add antialiazed points and lines support. 09/03/00 - check = gtk_check_button_new_with_label( _( "OpenGL antialiased points and lines" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bAntialiasedPointsAndLines, DLG_CHECK_BOOL ); - - // Solid selection boxes - check = gtk_check_button_new_with_label( _( "Solid selection boxes" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bNoStipple, DLG_CHECK_BOOL ); - - // Display size info - check = gtk_check_button_new_with_label( _( "Display size info" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bSizePaint, DLG_CHECK_BOOL ); - - // Alternate vertex/edge handles - // Gef: Kyro GL_POINT work around 25-aug-2001 - check = gtk_check_button_new_with_label( _( "Alternate vertex/edge handles" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bGlPtWorkaround, DLG_CHECK_BOOL ); - - g_list_free( combo_list ); - -#ifdef ATIHACK_812 - // ATI bugs - check = gtk_check_button_new_with_label( _( "ATI and Intel cards w/ buggy drivers (disappearing polygons)" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bGlATIHack, DLG_CHECK_BOOL ); -#endif - -#ifdef NVIDIA_AERO_HACK - check = gtk_check_button_new_with_label( _( "NVIDIA/Aero bug - disable Windows composition" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bGlNvidiaAeroHack, DLG_CHECK_BOOL ); -#endif - - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - - /******** 3D Camera view group *********/ - preflabel = gtk_label_new( _( "3D View" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "3D View" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Directional velocity (Movement Velocity) - // label container - hbox2 = gtk_hbox_new( FALSE, 0 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - - // label - label = gtk_label_new( _( "Movement Velocity" ) ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - - // adjustment - adj = gtk_adjustment_new( 100, 50, 300, 1, 10, 10 ); - AddDialogData( adj, &m_nMoveSpeed, DLG_ADJ_INT ); - - // scale - scale = gtk_hscale_new( GTK_ADJUSTMENT( adj ) ); - gtk_widget_show( scale ); - gtk_box_pack_start( GTK_BOX( vbox ), scale, FALSE, TRUE, 2 ); - - gtk_scale_set_draw_value( GTK_SCALE( scale ), TRUE ); - - // Angular velocity (Rotational Velocity) - // label container - hbox2 = gtk_hbox_new( FALSE, 0 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - - // label - label = gtk_label_new( _( "Rotational Velocity" ) ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - - // adjustment - adj = gtk_adjustment_new( 3, 1, 180, 1, 10, 10 ); // value, low, high, step, page_step, page_size - AddDialogData( adj, &m_nAngleSpeed, DLG_ADJ_INT ); - - // scale - scale = gtk_hscale_new( GTK_ADJUSTMENT( adj ) ); - gtk_widget_show( scale ); - gtk_box_pack_start( GTK_BOX( vbox ), scale, FALSE, TRUE, 2 ); - gtk_scale_set_draw_value( GTK_SCALE( scale ), TRUE ); - - // Text under the velocity sliders - // container - hbox2 = gtk_hbox_new( FALSE, 0 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - - // label - label = gtk_label_new( _( "slow" ) ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - - // label - label = gtk_label_new( _( "fast" ) ); - gtk_widget_show( label ); - gtk_box_pack_end( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - - // Allow drag to select multiple faces/brushes - // container - table = gtk_table_new( 2, 1, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - label = gtk_label_new( _( "Use paint-select in camera view:" ) ); - gtk_widget_show( label ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - combo_list = NULL; - combo_list = g_list_append( combo_list, (void *)_( "No" ) ); - combo_list = g_list_append( combo_list, (void *)_( "Yes" ) ); - combo_list = g_list_append( combo_list, (void *)_( "Yes (Classic Key Setup)" ) ); - - combo = gtk_combo_new(); - gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list ); - gtk_widget_show( combo ); - gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE ); - AddDialogData( combo, &m_nCamDragMultiSelect, DLG_COMBO_INT ); - - // Freelook in Camera view - check = gtk_check_button_new_with_label( _( "Freelook in Camera view" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT ); - AddDialogData( check, &m_bCamFreeLook, DLG_CHECK_BOOL ); - - // Freelook in Camera view w/ forward & back strafing instead of up and down looking - check = gtk_check_button_new_with_label( _( "Freelook strafes Forward and Back" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT ); - AddDialogData( check, &m_bCamFreeLookStrafe, DLG_CHECK_BOOL ); - - // Invert mouse in freelook - check = gtk_check_button_new_with_label( _( "Invert mouse in freelook" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT ); - AddDialogData( check, &m_bCamInverseMouse, DLG_CHECK_BOOL ); - - // Discrete movement - check = gtk_check_button_new_with_label( _( "Discrete movement" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT ); - AddDialogData( check, &m_bCamDiscrete, DLG_CHECK_BOOL ); - - // Update XY views on camera move - check = gtk_check_button_new_with_label( _( "Update XY views on camera move" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT ); - AddDialogData( check, &m_bCamXYUpdate, DLG_CHECK_BOOL ); - - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - - /******** Texture group *********/ - preflabel = gtk_label_new( _( "Textures" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Textures" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 6 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Texture quality slider - // label - label = gtk_label_new( _( "Texture quality" ) ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( vbox ), label, FALSE, FALSE, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - - // adjustment - adj = gtk_adjustment_new( 0, 0, 4, 1, 1, 1 ); - AddDialogData( adj, &m_nLatchedTextureQuality, DLG_ADJ_INT ); - - // scale - scale = gtk_hscale_new( GTK_ADJUSTMENT( adj ) ); - gtk_widget_show( scale ); - gtk_box_pack_start( GTK_BOX( vbox ), scale, FALSE, FALSE, 0 ); - gtk_scale_set_draw_value( GTK_SCALE( scale ), FALSE ); - - // text under the texture slider - hbox2 = gtk_hbox_new( FALSE, 0 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - label = gtk_label_new( _( "low" ) ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - label = gtk_label_new( _( "high" ) ); - gtk_widget_show( label ); - gtk_box_pack_end( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - - // texture subsets - check = gtk_check_button_new_with_label( _( "Texture subsets" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bTextureWindow, DLG_CHECK_BOOL ); - - // texture scrollbar - check = gtk_check_button_new_with_label( _( "Texture scrollbar" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bTextureScrollbar, DLG_CHECK_BOOL ); - - // texture increment matches grid - check = gtk_check_button_new_with_label( _( "Tex increment matches grid" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bSnapTToGrid, DLG_CHECK_BOOL ); - - // RIANT - // Texture compression choice label - // container - table = gtk_table_new( 2, 1, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - label = gtk_label_new( _( "Texture Compression (if available):" ) ); - gtk_widget_show( label ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); - - // Texture compression choice label - combo_list = NULL; - // NONE will always be in pos 0 - combo_list = g_list_append( combo_list, (void *)_( "None" ) ); - - // if OpenGL compression is enabled it will always be - // in pos 1 - if ( g_qeglobals.m_bOpenGLCompressionSupported ) { - combo_list = g_list_append( combo_list, (void *)_( "OpenGL ARB" ) ); + if ( gamePrompt || !currentGameDescription ) { + onStartup = true; + Create(); + DoGameDialog(); + // use m_nComboSelect to identify the game to run as and set the globals + currentGameDescription = GameDescriptionForComboItem(); + ASSERT_NOTNULL( currentGameDescription ); } - - // If S3 is enabled offer all 3 valid compression schemes in RGBA - if ( g_qeglobals.m_bS3CompressionSupported ) { - combo_list = g_list_append( combo_list, (void *)_( "S3TC DXT1" ) ); - combo_list = g_list_append( combo_list, (void *)_( "S3TC DXT3" ) ); - combo_list = g_list_append( combo_list, (void *)_( "S3TC DXT5" ) ); + else { + onStartup = false; } - combo = gtk_combo_new(); - gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list ); - gtk_widget_show( combo ); - gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE ); - AddDialogData( combo, &m_nTextureCompressionFormat, DLG_COMBO_INT ); - g_list_free( combo_list ); - - // container - table = gtk_table_new( 2, 1, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // Startup shaders - // label - label = gtk_label_new( _( "Startup Shaders:" ) ); - gtk_widget_show( label ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); - - // combo list - combo_list = NULL; - combo_list = g_list_append( combo_list, (void *)_( "None" ) ); - if ( g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game" ) { - combo_list = g_list_append( combo_list, (void *)_( "System" ) ); - } - else if ( g_pGameDescription->mGameFile == "sof2.game" ) { - combo_list = g_list_append( combo_list, (void *)( "Tools" ) ); + g_pGameDescription = currentGameDescription; + + g_pGameDescription->Dump(); +} + +CGameDialog::~CGameDialog(){ + // free all the game descriptions + std::list::iterator iGame; + for ( iGame = mGames.begin(); iGame != mGames.end(); ++iGame ) + { + delete ( *iGame ); + *iGame = 0; } - else{ - combo_list = g_list_append( combo_list, (void *)_( "Common" ) ); + if ( GetWidget() ) { + Destroy(); } - combo_list = g_list_append( combo_list, (void *)_( "All" ) ); - combo = gtk_combo_new(); - gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list ); - gtk_widget_show( combo ); - gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE ); - AddDialogData( combo, &m_nLatchedShader, DLG_COMBO_INT ); - g_list_free( combo_list ); - - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); +} - /******** Layout group *********/ - preflabel = gtk_label_new( _( "Layout" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Layout" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // View types - // table - table = gtk_table_new( 2, 4, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // view type 1 - pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window1.bmp" ); - gtk_widget_show( pixmap ); - gtk_table_attach( GTK_TABLE( table ), pixmap, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 2 - pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window2.bmp" ); - gtk_widget_show( pixmap ); - gtk_table_attach( GTK_TABLE( table ), pixmap, 1, 2, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 3 - pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window3.bmp" ); - gtk_widget_show( pixmap ); - gtk_table_attach( GTK_TABLE( table ), pixmap, 2, 3, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 4 - pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window4.bmp" ); - gtk_widget_show( pixmap ); - gtk_table_attach( GTK_TABLE( table ), pixmap, 3, 4, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 1 selector - radio = gtk_radio_button_new( NULL ); - gtk_widget_show( radio ); - gtk_table_attach( GTK_TABLE( table ), radio, 0, 1, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 2 selector - radio = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON( radio ) ); - gtk_widget_show( radio ); - gtk_table_attach( GTK_TABLE( table ), radio, 1, 2, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 3 selector - radio = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON( radio ) ); - gtk_widget_show( radio ); - gtk_table_attach( GTK_TABLE( table ), radio, 2, 3, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // view type 4 selector - radio = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON( radio ) ); - gtk_widget_show( radio ); - gtk_table_attach( GTK_TABLE( table ), radio, 3, 4, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - AddDialogData( radio, &m_nLatchedView, DLG_RADIO_INT ); - - // Floating Z window - check = gtk_check_button_new_with_label( _( "Floating Z Window" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLatchedFloatingZ, DLG_CHECK_BOOL ); - - // show menu tear-off seperators - check = gtk_check_button_new_with_label( _( "Detachable Menus" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLatchedDetachableMenus, DLG_CHECK_BOOL ); - - if ( !g_pGameDescription->mNoPatch ) { - // show patch toolbar - check = gtk_check_button_new_with_label( _( "Patch Toolbar" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_patchtoolbar", check ); // Allow to be disabled for Q1/Q2 - AddDialogData( check, &m_bLatchedPatchToolbar, DLG_CHECK_BOOL ); +inline const char* GameDescription_getIdentifier( const CGameDescription& gameDescription ){ + const char* identifier = gameDescription.getKeyValue( "index" ); + if ( string_empty( identifier ) ) { + identifier = "1"; } + return identifier; +} - // use wide toolbar - check = gtk_check_button_new_with_label( _( "Wide Toolbar" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLatchedWideToolbar, DLG_CHECK_BOOL ); - - // use plugin toolbar - check = gtk_check_button_new_with_label( _( "Plugin Toolbar" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLatchedPluginToolbar, DLG_CHECK_BOOL ); - -#ifdef _WIN32 - // win32 file dialog - check = gtk_check_button_new_with_label( _( "Use win32 file dialog (hacky)" ) ); - gtk_widget_show( check ); - // gtk_container_add (GTK_CONTAINER (vbox), check); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bNativeGUI, DLG_CHECK_BOOL ); - - // position on primary monitor - check = gtk_check_button_new_with_label( _( "Start on Primary Monitor" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_startonprimary", check ); - gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateSensitivity ), this ); - AddDialogData( check, &m_bStartOnPrimMon, DLG_CHECK_BOOL ); -#endif - - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - /******** Mouse group *********/ - preflabel = gtk_label_new( _( "Mouse" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Mouse" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Buttons - // container - hbox2 = gtk_hbox_new( FALSE, 5 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - - // 2 button radio - radio = gtk_radio_button_new_with_label( NULL, _( "2 button" ) ); - gtk_widget_show( radio ); - gtk_box_pack_start( GTK_BOX( hbox2 ), radio, FALSE, FALSE, 0 ); - - // 3 button radio - radio = gtk_radio_button_new_with_label_from_widget( GTK_RADIO_BUTTON( radio ), _( "3 button" ) ); - gtk_widget_show( radio ); - gtk_box_pack_start( GTK_BOX( hbox2 ), radio, FALSE, FALSE, 0 ); - AddDialogData( radio, &m_nMouse, DLG_RADIO_INT ); - - // right click to drop entity - check = gtk_check_button_new_with_label( _( "Right click to drop entities" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bRightClick, DLG_CHECK_BOOL ); - - // Mouse chaser (and this does what?) - check = gtk_check_button_new_with_label( _( "Mouse chaser" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bChaseMouse, DLG_CHECK_BOOL ); - - // Alt + multi-drag - check = gtk_check_button_new_with_label( _( "ALT + multi-drag" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bALTEdge, DLG_CHECK_BOOL ); - - // Mouse wheel increments - // container - hbox2 = gtk_hbox_new( FALSE, 5 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - - // label - label = gtk_label_new( _( "Wheel Mouse inc:" ) ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); - - // entry - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_widget_set_usize( entry, 40, -2 ); - gtk_box_pack_start( GTK_BOX( hbox2 ), entry, FALSE, FALSE, 0 ); - AddDialogData( entry, &m_nWheelInc, DLG_ENTRY_INT ); +CGameDialog g_GamesDialog; - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - /******** Editing group *********/ - preflabel = gtk_label_new( _( "Editing" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Editing" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Vertex editing splits faces - check = gtk_check_button_new_with_label( _( "Vertex editing splits face" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bVertexSplit, DLG_CHECK_BOOL ); - - // Fix target/targetname collisions - check = gtk_check_button_new_with_label( _( "Fix target/targetname collisions" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bDoTargetFix, DLG_CHECK_BOOL ); - - // Clipper tool uses caulk - check = gtk_check_button_new_with_label( _( "Clipper tool uses caulk" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bClipCaulk, DLG_CHECK_BOOL ); - - // Don't clamp plane points - check = gtk_check_button_new_with_label( _( "Don't clamp plane points" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bNoClamp, DLG_CHECK_BOOL ); - - // Snap to grid - check = gtk_check_button_new_with_label( _( "Snap to grid" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bSnap, DLG_CHECK_BOOL ); - - // Select patch by bounding box - check = gtk_check_button_new_with_label( _( "Select patches by bounding box" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bPatchBBoxSelect, DLG_CHECK_BOOL ); - - // Rotation increment - // container - table = gtk_table_new( 2, 3, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // label - label = gtk_label_new( _( "Rotation increment:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // entry - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_widget_set_usize( entry, 60, -2 ); - gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - AddDialogData( entry, &m_nRotation, DLG_ENTRY_INT ); - - // Undo levels - // label - label = gtk_label_new( _( "Undo Levels:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // spinner (allows undo levels to be set to zero) - spin = gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 1, 0, 64, 1, 10, 10 ) ), 1, 0 ); - gtk_widget_show( spin ); - gtk_table_attach( GTK_TABLE( table ), spin, 1, 2, 1, 2, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_widget_set_usize( spin, 60, -2 ); - AddDialogData( spin, &m_nUndoLevels, DLG_SPIN_INT ); - - // Patch subdivisions - // label - label = gtk_label_new( _( "Patch subdivisions:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 2, 3, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // entry (spinner perhaps? [2-16]) - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_widget_set_usize( entry, 60, -2 ); - gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 2, 3, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - AddDialogData( entry, &m_nSubdivisions, DLG_ENTRY_INT ); +// ============================================================================= +// Widget callbacks for PrefsDlg - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); +static void OnButtonClean( ui::Widget widget, gpointer data ){ + // make sure this is what the user wants + if ( ui::alert( g_Preferences.GetWidget(), "This will close " RADIANT_NAME " and clean the corresponding registry entries.\n" + "Next time you start " RADIANT_NAME " it will be good as new. Do you wish to continue?", + "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk ) == ui::alert_response::YES ) { + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->EndModal( eIDCANCEL ); - /******** Save/Load group *********/ - preflabel = gtk_label_new( _( "Startup/Auto save" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Startup/Auto save" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Snapshots - check = gtk_check_button_new_with_label( _( "Snapshots" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bSnapShots, DLG_CHECK_BOOL ); - - // load last project on open - check = gtk_check_button_new_with_label( _( "Load last project on open" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLoadLast, DLG_CHECK_BOOL ); - - // load last map on open - check = gtk_check_button_new_with_label( _( "Load last map on open" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bLoadLastMap, DLG_CHECK_BOOL ); - - // Auto save.. - // container - hbox2 = gtk_hbox_new( FALSE, 5 ); - gtk_widget_show( hbox2 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 ); - gtk_container_set_border_width( GTK_CONTAINER( hbox2 ), 0 ); - - // label - check = gtk_check_button_new_with_label( _( "Auto save every" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( hbox2 ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bAutoSave, DLG_CHECK_BOOL ); - - // spinner - spin = gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 1, 1, 60, 1, 10, 10 ) ), 1, 0 ); - gtk_widget_show( spin ); - gtk_box_pack_start( GTK_BOX( hbox2 ), spin, FALSE, FALSE, 0 ); - gtk_widget_set_usize( spin, 60, -2 ); - AddDialogData( spin, &m_nAutoSave, DLG_SPIN_INT ); - - // label - label = gtk_label_new( _( "minutes" ) ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 ); + g_preferences_globals.disable_ini = true; + Preferences_Reset(); + gtk_main_quit(); + } +} - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); +// ============================================================================= +// PrefsDlg class - /******** Paths group *********/ - preflabel = gtk_label_new( _( "Paths" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Paths" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // prefab path - // table - table = gtk_table_new( 3, 3, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // label - label = gtk_label_new( _( "Prefab path:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 ); - - // path entry - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_widget_set_usize( GTK_WIDGET( entry ), 240, -2 ); - gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 1, 0 ); - AddDialogData( entry, &m_strPrefabPath, DLG_ENTRY_TEXT ); - -#if 0 - // browse button - button = gtk_button_new_with_label( "..." ); - gtk_widget_show( button ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseprefab ), this ); - gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); -#endif +/* + ======== - // User ini path - // label - label = gtk_label_new( _( "User INI path:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 ); - - // user ini path entry - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 1, 2, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 1, 0 ); - AddDialogData( entry, &m_strUserPath, DLG_ENTRY_TEXT ); - - // user ini browse button - button = gtk_button_new_with_label( "..." ); - gtk_widget_show( button ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseuserini ), this ); - gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); + very first prefs init deals with selecting the game and the game tools path + then we can load .ini stuff - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); + using prefs / ini settings: + those are per-game - /******** Brush group ********/ - preflabel = gtk_label_new( _( "Brush" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Brush" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // default texture scale - // table - table = gtk_table_new( 2, 1, FALSE ); // I believe that the 2 and 1 are switched here, and this is - // intentional to be consistent with other calls to gtk_table_new() - // [that are probably also switched]. - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // label - label = gtk_label_new( _( "Default texture scale:" ) ); - gtk_widget_show( label ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - // scale entry - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_widget_set_usize( GTK_WIDGET( entry ), 60, -2 ); - gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - AddDialogData( entry, &m_fDefTextureScale, DLG_ENTRY_FLOAT ); + look in ~/.radiant//gamename + ======== + */ - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); +const char *PREFS_LOCAL_FILENAME = "local.pref"; - /******** Misc group *********/ - preflabel = gtk_label_new( _( "Misc" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "Misc" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Light drawing - check = gtk_check_button_new_with_label( _( "Light drawing" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &m_bNewLightDraw, DLG_CHECK_BOOL ); - - // Light radiuses - // container - table = gtk_table_new( 2, 1, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - label = gtk_label_new( _( "Light radiuses:" ) ); - gtk_widget_show( label ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - - combo_list = NULL; - combo_list = g_list_append( combo_list, (void *)_( "Disabled" ) ); - combo_list = g_list_append( combo_list, (void *)_( "True Q3Map2 Style" ) ); - combo_list = g_list_append( combo_list, (void *)_( "Classic Style" ) ); - - combo = gtk_combo_new(); - gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list ); - gtk_widget_show( combo ); - gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE ); - AddDialogData( combo, &m_nLightRadiuses, DLG_COMBO_INT ); - -#ifdef _WIN32 - check = gtk_check_button_new_with_label( _( "Use win32 file associations to open text files instead of builtin editor" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - AddDialogData( check, &g_PrefsDlg.m_bUseWin32Editor, DLG_CHECK_BOOL ); -#else - // use custom shader editor - check = gtk_check_button_new_with_label( _( "Use Custom Shader Editor" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateEditorSensitivity ), this ); - g_object_set_data( G_OBJECT( dialog ), "check_customeditor", check ); - AddDialogData( check, &g_PrefsDlg.m_bUseCustomEditor, DLG_CHECK_BOOL ); - - // custom shader editor executable - // table - table = gtk_table_new( 3, 1, FALSE ); - gtk_widget_show( table ); - gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // label - label = gtk_label_new( _( "Custom Editor Command" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 ); - g_object_set_data( G_OBJECT( dialog ), "label_customeditor", label ); - gtk_widget_set_sensitive( label, g_PrefsDlg.m_bUseCustomEditor ); - - // custom editor command entry - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_widget_set_usize( GTK_WIDGET( entry ), 240, -2 ); - gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 1, 0 ); - AddDialogData( entry, &m_strEditorCommand, DLG_ENTRY_TEXT ); - gtk_widget_set_sensitive( entry, g_PrefsDlg.m_bUseCustomEditor ); - g_object_set_data( G_OBJECT( dialog ), "entry_customeditor", entry ); - - // browse button - button = gtk_button_new_with_label( _( "..." ) ); - gtk_widget_show( button ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseEditor ), this ); - gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - g_object_set_data( G_OBJECT( dialog ), "button_customeditor", button ); - gtk_widget_set_sensitive( button, g_PrefsDlg.m_bUseCustomEditor ); -#endif +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 - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); + // this is common to win32 and Linux init now + m_rc_path = g_string_new( m_global_rc_path->str ); - /******** BSP Monitoring group *********/ - // this is never displayed if the plugin isn't available - preflabel = gtk_label_new( _( "BSP Monitoring" ) ); - gtk_widget_show( preflabel ); - pageframe = gtk_frame_new( _( "BSP Monitoring" ) ); - gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 ); - gtk_widget_show( pageframe ); - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); - gtk_container_add( GTK_CONTAINER( pageframe ), vbox ); - - // Enable BSP process monitoring - check = gtk_check_button_new_with_label( _( "Enable BSP process monitoring" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_monitorbsp", check ); - gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateSensitivity ), this ); - AddDialogData( check, &g_PrefsDlg.m_bWatchBSP, DLG_CHECK_BOOL ); - - // Stop on leak - check = gtk_check_button_new_with_label( _( "Stop compilation on leak" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_leakstop", check ); - AddDialogData( check, &g_PrefsDlg.m_bLeakStop, DLG_CHECK_BOOL ); - - // engine after compile - check = gtk_check_button_new_with_label( _( "Run engine after compile" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_runengine", check ); - gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateSensitivity ), this ); - AddDialogData( check, &g_PrefsDlg.m_bRunQuake, DLG_CHECK_BOOL ); - - // sleep mode when running engine - check = gtk_check_button_new_with_label( _( "Activate sleep mode when running the engine" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_sleep", check ); - AddDialogData( check, &g_PrefsDlg.m_bDoSleep, DLG_CHECK_BOOL ); - - // use q3map2's texture projection - check = gtk_check_button_new_with_label( _( "Texturing compatible with q3map2" ) ); - gtk_widget_show( check ); - gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); - g_object_set_data( G_OBJECT( dialog ), "check_q3map2", check ); - AddDialogData( check, &g_PrefsDlg.m_bQ3Map2Texturing, DLG_CHECK_BOOL ); + // 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 ); - // Add the page to the notebook - gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); + // then the ini file + m_inipath = g_string_new( m_rc_path->str ); + g_string_append( m_inipath, PREFS_LOCAL_FILENAME ); +} - gtk_notebook_set_page( GTK_NOTEBOOK( notebook ), PTAB_FRONT ); +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 ); + } +} +void PrefsDlg::showPrefPage( ui::Widget prefpage ){ + notebook_set_page( m_notebook, prefpage ); return; } -// end new prefs dialog - -void PrefsDlg::LoadTexdefPref( texdef_t* pTexdef, const char* pName ){ - char buffer[256]; - - memset( pTexdef, 0, sizeof( texdef_t ) ); +static void treeSelection( ui::TreeSelection selection, gpointer data ){ + PrefsDlg *dlg = (PrefsDlg*)data; - sprintf( buffer, "%s%s", pName, TD_SCALE1_KEY ); - mLocalPrefs.GetPref( buffer, &pTexdef->scale[0], 0.5f ); + 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 ); + } +} - sprintf( buffer, "%s%s", pName, TD_SCALE2_KEY ); - mLocalPrefs.GetPref( buffer, &pTexdef->scale[1], 0.5f ); +typedef std::list PreferenceGroupCallbacks; - sprintf( buffer, "%s%s", pName, TD_SHIFT1_KEY ); - mLocalPrefs.GetPref( buffer, &pTexdef->shift[0], 8.f ); +inline void PreferenceGroupCallbacks_constructGroup( const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group ){ + for ( PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i ) + { + ( *i )( group ); + } +} - sprintf( buffer, "%s%s", pName, TD_SHIFT2_KEY ); - mLocalPrefs.GetPref( buffer, &pTexdef->shift[1], 8.f ); - sprintf( buffer, "%s%s", pName, TD_ROTATE_KEY ); - mLocalPrefs.GetPref( buffer, &pTexdef->rotate, 45 ); +inline void PreferenceGroupCallbacks_pushBack( PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback ){ + callbacks.push_back( callback ); } -void PrefsDlg::UpdateTextureCompression(){ - // if OpenGL is not ready yet, don't do anything - if ( !g_qeglobals.m_bOpenGLReady ) { - Sys_Printf( "OpenGL not ready - postpone texture compression capability check\n" ); - return; - } +typedef std::list PreferencesPageCallbacks; - if ( g_qeglobals.bTextureCompressionSupported ) { - if ( m_nTextureCompressionFormat >= 2 && !g_qeglobals.m_bS3CompressionSupported ) { - Sys_Printf( "Inconsistant pref setting for texture compression (%d), rolling back\n", m_nTextureCompressionFormat ); - m_nTextureCompressionFormat = 1; // if this is not supported either, see below - } - if ( m_nTextureCompressionFormat == 1 && !g_qeglobals.m_bOpenGLCompressionSupported ) { - Sys_Printf( "Inconsistant pref setting for texture compression (GL_COMPRESSED_RGBA), rolling back\n" ); - m_nTextureCompressionFormat = 0; - } - switch ( m_nTextureCompressionFormat ) - { - case ( 0 ): - { - g_qeglobals.texture_components = GL_RGBA; - Sys_Printf( "texture compression disabled by preferences settings\n" ); - break; - } - case ( 1 ): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA; - Sys_Printf( "OpenGL texture compression enabled\n" ); - break; - } - case ( 2 ): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - Sys_Printf( "S3TC DXT1 texture compression enabled\n" ); - break; - } - case ( 3 ): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - Sys_Printf( "S3TC DXT3 texture compression enabled\n" ); - break; - } - case ( 4 ): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - Sys_Printf( "S3TC DXT5 texture compression enabled\n" ); - break; - } - } - } - else +inline void PreferencesPageCallbacks_constructPage( const PreferencesPageCallbacks& callbacks, PreferencesPage& page ){ + for ( PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i ) { - Sys_Printf( "texture compression is not supported by your current graphic card/drivers\n" ); - g_qeglobals.texture_components = GL_RGBA; - m_nTextureCompressionFormat = 0; + ( *i )( page ); } } -#ifdef ATIHACK_812 -void PrefsDlg::UpdateATIHack() { - // if OpenGL is not ready yet, don't do anything - if ( !g_qeglobals.m_bOpenGLReady ) { - Sys_Printf( "OpenGL not ready - postpone ATI bug workaround setup\n" ); - return; - } +inline void PreferencesPageCallbacks_pushBack( PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback ){ + callbacks.push_back( callback ); +} - if ( m_bGlATIHack ) { - qglCullFace = &qglCullFace_ATIHack; - qglDisable = &qglDisable_ATIHack; - qglEnable = &qglEnable_ATIHack; - qglPolygonMode = &qglPolygonMode_ATIHack; - Sys_Printf( "ATI bug workaround enabled\n" ); - } - else { - qglCullFace = qglCullFace_real; - qglDisable = qglDisable_real; - qglEnable = qglEnable_real; - qglPolygonMode = qglPolygonMode_real; - Sys_Printf( "ATI bug workaround disabled\n" ); - } +PreferencesPageCallbacks g_interfacePreferences; +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 ); } -#endif -#ifdef NVIDIA_AERO_HACK -void PrefsDlg::UpdateNvidiaAeroHack() { - if ( m_bGlNvidiaAeroHack && m_bGlNvidiaAeroHackPrevState == 1 ) { - return; - } - if ( ( !m_bGlNvidiaAeroHack ) && m_bGlNvidiaAeroHackPrevState == 0 ) { - return; - } - if ( ( !m_bGlNvidiaAeroHack ) && m_bGlNvidiaAeroHackPrevState < 0 ) { - // The hack state is uninitialized, meaning that this is the first call - // to this function. I prefer not to explicitly enable composition because - // the user may have set the application to disable it, and I don't want to - // override that. Leave the state of composition as-is if the hack checkbox - // isn't checked. - m_bGlNvidiaAeroHackPrevState = 0; - return; - } - HMODULE lib = LoadLibrary( "dwmapi.dll" ); - if ( lib ) { - void ( WINAPI *qDwmEnableComposition )( bool bEnable ) = - ( void (WINAPI *) ( bool bEnable ) )GetProcAddress( lib, "DwmEnableComposition" ); - if ( qDwmEnableComposition ) { - if ( m_bGlNvidiaAeroHack ) { - Sys_Printf( "Disabling Windows composition\n" ); - qDwmEnableComposition( 0 ); - m_bGlNvidiaAeroHackPrevState = 1; - } - else { - Sys_Printf( "Enabling Windows composition\n" ); - qDwmEnableComposition( 1 ); - m_bGlNvidiaAeroHackPrevState = 0; - } - } - FreeLibrary( lib ); - } +PreferencesPageCallbacks g_displayPreferences; +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 ); } -#endif -// TTimo: m_strEnginePath has a special status, if not found in registry we need to -// initiliaze it for sure. It is not totally failsafe but we can use the same -// code than in q3map, expecting to find some "quake" above us. If not, we prompt -// for the engine executable path -void PrefsDlg::LoadPrefs(){ - int i; +PreferencesPageCallbacks g_settingsPreferences; +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 ); +} - // first things first, load prefs from global prefs - mGamesDialog.LoadPrefs(); +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 ) ); +} - // if we already have a document loaded, we will free and reload from file - if ( mLocalPrefs.InUse() ) { - mLocalPrefs.Clear(); - } +void ToggleButton_toggled_Widget_updateDependency( ui::Widget toggleButton, ui::Widget self ){ + Widget_updateDependency( self, toggleButton ); +} - // load local.pref file - mLocalPrefs.ReadXMLFile( m_inipath->str ); - - mLocalPrefs.GetPref( PATCHSHOWBOUNDS_KEY, &g_bPatchShowBounds, FALSE ); - mLocalPrefs.GetPref( MOUSE_KEY, &m_nMouse, MOUSE_DEF ); - m_nMouseButtons = m_nMouse ? 3 : 2; - - // project file - // if it's not found here, mainframe.cpp will take care of finding one - mLocalPrefs.GetPref( LASTPROJ_KEY, &m_strLastProject, "" ); - mLocalPrefs.GetPref( LASTPROJVER_KEY, &m_nLastProjectVer, -1 ); - - // prefab path - // NOTE TTimo: I'm not sure why this is in prefs - // should probably be a project setting - // and I'm not sure that we really have a way to set this reliably either - CString strPrefab; - strPrefab = g_qeglobals.m_strHomeGame.GetBuffer(); - strPrefab += g_pGameDescription->mBaseGame.GetBuffer(); - strPrefab += "/prefabs/"; - mLocalPrefs.GetPref( PREFAB_KEY, &m_strPrefabPath, strPrefab ); - - mLocalPrefs.GetPref( LASTLIGHTINTENSITY_KEY, &m_iLastLightIntensity, 300 ); - mLocalPrefs.GetPref( TLOCK_KEY, &m_bTextureLock, TLOCK_DEF ); - mLocalPrefs.GetPref( RLOCK_KEY, &m_bRotateLock, TLOCK_DEF ); - mLocalPrefs.GetPref( LASTMAP_KEY, &m_strLastMap, "" ); - mLocalPrefs.GetPref( LOADLAST_KEY, &m_bLoadLast, LOADLAST_DEF ); - mLocalPrefs.GetPref( BSP_KEY, &m_bInternalBSP, FALSE ); - mLocalPrefs.GetPref( RCLICK_KEY, &m_bRightClick, TRUE ); - mLocalPrefs.GetPref( AUTOSAVE_KEY, &m_bAutoSave, TRUE ); - mLocalPrefs.GetPref( LOADLASTMAP_KEY, &m_bLoadLastMap, FALSE ); - mLocalPrefs.GetPref( TINYBRUSH_KEY, &m_bCleanTiny, FALSE ); - mLocalPrefs.GetPref( TINYSIZE_KEY, &m_fTinySize, 0.5f ); - mLocalPrefs.GetPref( AUTOSAVETIME_KEY, &m_nAutoSave, 5 ); - mLocalPrefs.GetPref( SNAPSHOT_KEY, &m_bSnapShots, FALSE ); - mLocalPrefs.GetPref( MOVESPEED_KEY, &m_nMoveSpeed, 100 ); - mLocalPrefs.GetPref( ANGLESPEED_KEY, &m_nAngleSpeed, 3 ); - mLocalPrefs.GetPref( SETGAME_KEY, &m_bSetGame, FALSE ); - mLocalPrefs.GetPref( CAMXYUPDATE_KEY, &m_bCamXYUpdate, TRUE ); - mLocalPrefs.GetPref( CAMDRAGMULTISELECT_KEY, &m_nCamDragMultiSelect, TRUE ); - mLocalPrefs.GetPref( CAMFREELOOK_KEY, &m_bCamFreeLook, TRUE ); - mLocalPrefs.GetPref( CAMINVERSEMOUSE_KEY, &m_bCamInverseMouse, FALSE ); - mLocalPrefs.GetPref( CAMDISCRETE_KEY, &m_bCamDiscrete, TRUE ); - mLocalPrefs.GetPref( LIGHTDRAW_KEY, &m_bNewLightDraw, TRUE ); - mLocalPrefs.GetPref( CUBICCLIP_KEY, &m_bCubicClipping, TRUE ); - mLocalPrefs.GetPref( CUBICSCALE_KEY, &m_nCubicScale, 13 ); - mLocalPrefs.GetPref( ALTEDGE_KEY, &m_bALTEdge, FALSE ); - mLocalPrefs.GetPref( FACECOLORS_KEY, &m_bFaceColors, FALSE ); - mLocalPrefs.GetPref( XZVIS_KEY, &m_bXZVis, FALSE ); - mLocalPrefs.GetPref( YZVIS_KEY, &m_bYZVis, FALSE ); - mLocalPrefs.GetPref( ZVIS_KEY, &m_bZVis, FALSE ); - mLocalPrefs.GetPref( SIZEPAINT_KEY, &m_bSizePaint, FALSE ); - mLocalPrefs.GetPref( DLLENTITIES_KEY, &m_bDLLEntities, FALSE ); - - mLocalPrefs.GetPref( DETACHABLEMENUS_KEY, &m_bLatchedDetachableMenus, TRUE ); - m_bDetachableMenus = m_bLatchedDetachableMenus; - - if ( g_pGameDescription->mNoPatch ) { - m_bPatchToolbar = false; - } - else - { - mLocalPrefs.GetPref( PATCHTOOLBAR_KEY, &m_bLatchedPatchToolbar, TRUE ); - m_bPatchToolbar = m_bLatchedPatchToolbar; +void ToggleButton_state_changed_Widget_updateDependency( ui::Widget toggleButton, GtkStateType state, ui::Widget self ){ + if ( state == GTK_STATE_INSENSITIVE ) { + Widget_updateDependency( self, toggleButton ); } +} - mLocalPrefs.GetPref( WIDETOOLBAR_KEY, &m_bLatchedWideToolbar, TRUE ); - m_bWideToolbar = m_bLatchedWideToolbar; +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 ); +} - mLocalPrefs.GetPref( PLUGINTOOLBAR_KEY, &m_bLatchedPluginToolbar, TRUE ); - m_bPluginToolbar = m_bLatchedPluginToolbar; - mLocalPrefs.GetPref( WINDOW_KEY, (int*)&m_nLatchedView, WINDOW_DEF ); - m_nView = m_nLatchedView; +inline ui::VBox getVBox( ui::Bin page ){ + return ui::VBox::from(gtk_bin_get_child(page)); +} - mLocalPrefs.GetPref( FLOATINGZ_KEY, &m_bLatchedFloatingZ, FALSE ); - m_bFloatingZ = m_bLatchedFloatingZ; +GtkTreeIter PreferenceTree_appendPage( ui::TreeStore store, GtkTreeIter* parent, const char* name, ui::Widget page ){ + GtkTreeIter group; + gtk_tree_store_append( store, &group, parent ); + gtk_tree_store_set( store, &group, 0, name, 1, page, -1 ); + return group; +} - mLocalPrefs.GetPref( TEXTUREQUALITY_KEY, &m_nLatchedTextureQuality, 3 ); - m_nTextureQuality = m_nLatchedTextureQuality; +ui::Bin PreferencePages_addPage( ui::Widget notebook, const char* name ){ + ui::Widget preflabel = ui::Label( name ); + preflabel.show(); - mLocalPrefs.GetPref( LOADSHADERS_KEY, &m_nLatchedShader, 0 ); - m_nShader = m_nLatchedShader; + auto pageframe = ui::Frame( name ); + gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 4 ); + pageframe.show(); - mLocalPrefs.GetPref( NOCLAMP_KEY, &m_bNoClamp, FALSE ); - mLocalPrefs.GetPref( SNAP_KEY, &m_bSnap, TRUE ); - mLocalPrefs.GetPref( USERINI_KEY, &m_strUserPath, "" ); - mLocalPrefs.GetPref( ROTATION_KEY, &m_nRotation, 45 ); - mLocalPrefs.GetPref( CHASEMOUSE_KEY, &m_bChaseMouse, TRUE ); - mLocalPrefs.GetPref( ENTITYSHOW_KEY, &m_nEntityShowState, ENTITY_SKINNED_BOXED ); + ui::Widget vbox = ui::VBox( FALSE, 4 ); + vbox.show(); + gtk_container_set_border_width( GTK_CONTAINER( vbox ), 4 ); + pageframe.add(vbox); - // this will probably need to be 75 or 100 for Q1. - mLocalPrefs.GetPref( TEXTURESCALE_KEY, &m_nTextureScale, 50 ); + // Add the page to the notebook + gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel ); - // FIXME: Hydra - actually, this stuff is Q1,Q2 and HL specific. - if ( ( g_pGameDescription->mGameFile == "hl.game" ) ) { - // No BSP monitoring in the default compiler tools for Half-life (yet) - mLocalPrefs.GetPref( WATCHBSP_KEY, &m_bWatchBSP, FALSE ); + return pageframe; +} - // Texture subset on by default (HL specific really, because of halflife.wad's size) - mLocalPrefs.GetPref( TEXTURE_KEY, &m_bTextureWindow, TRUE ); - } - else if ( g_pGameDescription->quake2 ) { - // BSP monitoring is implemented in Quake2 and Heretic2 tools - mLocalPrefs.GetPref( WATCHBSP_KEY, &m_bWatchBSP, TRUE ); +class PreferenceTreeGroup : public PreferenceGroup +{ +Dialog& m_dialog; +ui::Widget m_notebook; +ui::TreeStore m_store; +GtkTreeIter m_group; +public: +PreferenceTreeGroup( Dialog& dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group ) : + m_dialog( dialog ), + m_notebook( notebook ), + m_store( store ), + m_group( group ){ +} +PreferencesPage createPage( const char* treeName, const char* frameName ){ + auto page = PreferencePages_addPage( m_notebook, frameName ); + PreferenceTree_appendPage( m_store, &m_group, treeName, page ); + return PreferencesPage( m_dialog, getVBox( page ) ); +} +}; - // Texture subset on by default (HL specific really, because of halflife.wad's size) - mLocalPrefs.GetPref( TEXTURE_KEY, &m_bTextureWindow, TRUE ); - } - else - { - mLocalPrefs.GetPref( WATCHBSP_KEY, &m_bWatchBSP, WATCHBSP_DEF ); - mLocalPrefs.GetPref( TEXTURE_KEY, &m_bTextureWindow, FALSE ); - } +ui::Window PrefsDlg::BuildDialog(){ + PreferencesDialog_addInterfacePreferences( makeCallbackF(Interface_constructPreferences) ); + Mouse_registerPreferencesPage(); + ui::Window dialog = ui::Window(create_floating_window( RADIANT_NAME " Preferences", m_parent )); - mLocalPrefs.GetPref( TEXTURESCROLLBAR_KEY, &m_bTextureScrollbar, TRUE ); - mLocalPrefs.GetPref( DISPLAYLISTS_KEY, &m_bDisplayLists, TRUE ); - mLocalPrefs.GetPref( ANTIALIASEDLINES_KEY, &m_bAntialiasedPointsAndLines, FALSE ); - mLocalPrefs.GetPref( SWITCHCLIP_KEY, &m_bSwitchClip, TRUE ); - mLocalPrefs.GetPref( SELWHOLEENTS_KEY, &m_bSelectWholeEntities, TRUE ); - mLocalPrefs.GetPref( SHOWSHADERS_KEY, &m_bShowShaders, TRUE ); - mLocalPrefs.GetPref( GLLIGHTING_KEY, &m_bGLLighting, FALSE ); - mLocalPrefs.GetPref( NOSTIPPLE_KEY, &m_bNoStipple, FALSE ); - mLocalPrefs.GetPref( UNDOLEVELS_KEY, &m_nUndoLevels, 30 ); - mLocalPrefs.GetPref( VERTEXMODE_KEY, &m_bVertexSplit, TRUE ); - mLocalPrefs.GetPref( RUNQ2_KEY, &m_bRunQuake, RUNQ2_DEF ); - mLocalPrefs.GetPref( LEAKSTOP_KEY, &m_bLeakStop, TRUE ); - mLocalPrefs.GetPref( DOSLEEP_KEY, &m_bDoSleep, FALSE ); - mLocalPrefs.GetPref( SELECTCURVES_KEY, &m_bSelectCurves, TRUE ); - mLocalPrefs.GetPref( SELECTMODELS_KEY, &m_bSelectModels, TRUE ); - mLocalPrefs.GetPref( SHADERLISTONLY_KEY, &m_bTexturesShaderlistOnly, FALSE ); - mLocalPrefs.GetPref( DEFAULTTEXURESCALE_KEY, &m_fDefTextureScale, g_pGameDescription->mTextureDefaultScale ); - mLocalPrefs.GetPref( SUBDIVISIONS_KEY, &m_nSubdivisions, SUBDIVISIONS_DEF ); - mLocalPrefs.GetPref( CLIPCAULK_KEY, &m_bClipCaulk, FALSE ); - mLocalPrefs.GetPref( SNAPTTOGRID_KEY, &m_bSnapTToGrid, FALSE ); - mLocalPrefs.GetPref( TARGETFIX_KEY, &m_bDoTargetFix, TRUE ); - mLocalPrefs.GetPref( WHEELINC_KEY, &m_nWheelInc, 64 ); - mLocalPrefs.GetPref( PATCHBBOXSEL_KEY, &m_bPatchBBoxSelect, FALSE ); - - // Gef: Kyro GL_POINT workaround - mLocalPrefs.GetPref( GLPOINTWORKAROUND_KEY, &m_bGlPtWorkaround, FALSE ); - - // window positioning - mLocalPrefs.GetPref( ENTITYSPLIT1_KEY, &mWindowInfo.nEntitySplit1, -1 ); - mLocalPrefs.GetPref( ENTITYSPLIT2_KEY, &mWindowInfo.nEntitySplit2, -1 ); - - mLocalPrefs.GetPref( POSITIONX_KEY, &mWindowInfo.position.x, -1 ); - mLocalPrefs.GetPref( POSITIONY_KEY, &mWindowInfo.position.y, -1 ); - mLocalPrefs.GetPref( WIDTH_KEY, &mWindowInfo.position.w, -1 ); - mLocalPrefs.GetPref( HEIGHT_KEY, &mWindowInfo.position.h, 450 ); - - const window_position_t default_window_pos = { 0, 0, 200, 200, }; - - mLocalPrefs.GetPref( ENTITYWND_KEY, &mWindowInfo.posEntityWnd, default_window_pos ); - mLocalPrefs.GetPref( MAPINFOWND_KEY, &mWindowInfo.posMapInfoWnd, default_window_pos ); - mLocalPrefs.GetPref( CAMWND_KEY, &mWindowInfo.posCamWnd, default_window_pos ); - mLocalPrefs.GetPref( ZWND_KEY, &mWindowInfo.posZWnd, default_window_pos ); - mLocalPrefs.GetPref( XYWND_KEY, &mWindowInfo.posXYWnd, default_window_pos ); - mLocalPrefs.GetPref( YZWND_KEY, &mWindowInfo.posYZWnd, default_window_pos ); - mLocalPrefs.GetPref( XZWND_KEY, &mWindowInfo.posXZWnd, default_window_pos ); - mLocalPrefs.GetPref( PATCHWND_KEY, &mWindowInfo.posPatchWnd, default_window_pos ); - mLocalPrefs.GetPref( SURFACEWND_KEY, &mWindowInfo.posSurfaceWnd, default_window_pos ); - mLocalPrefs.GetPref( ENTITYINFOWND_KEY, &mWindowInfo.posEntityInfoWnd, default_window_pos ); - - mLocalPrefs.GetPref( ZWIDTH_KEY, &mWindowInfo.nZWidth, 30 ); - mLocalPrefs.GetPref( XYHEIGHT_KEY, &mWindowInfo.nXYHeight, 300 ); - mLocalPrefs.GetPref( XYWIDTH_KEY, &mWindowInfo.nXYWidth, 300 ); - mLocalPrefs.GetPref( CAMWIDTH_KEY, &mWindowInfo.nCamWidth, 200 ); - mLocalPrefs.GetPref( CAMHEIGHT_KEY, &mWindowInfo.nCamHeight, 200 ); - mLocalPrefs.GetPref( ZFLOATWIDTH_KEY, &mWindowInfo.nZFloatWidth, 300 ); -#ifdef _WIN32 - mLocalPrefs.GetPref( STATE_KEY, &mWindowInfo.nState, SW_SHOW ); -#endif + gtk_window_set_transient_for( dialog, m_parent ); + gtk_window_set_position( dialog, GTK_WIN_POS_CENTER_ON_PARENT ); - // menu stuff - mLocalPrefs.GetPref( COUNT_KEY, &m_nMRUCount, 0 ); - for ( i = 0; i < 4; i++ ) { - char buf[64]; - sprintf( buf, "%s%d", FILE_KEY, i ); - mLocalPrefs.GetPref( buf, &m_strMRUFiles[i], "" ); - } + auto mainvbox = ui::VBox( FALSE, 5 ); + dialog.add(mainvbox); + gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 ); + mainvbox.show(); - // some platform specific prefs -#ifdef _WIN32 - mLocalPrefs.GetPref( NATIVEGUI_KEY, &m_bNativeGUI, TRUE ); - mLocalPrefs.GetPref( STARTONPRIMMON_KEY, &m_bStartOnPrimMon, FALSE ); -#endif + { + auto hbox = ui::HBox( FALSE, 5 ); + hbox.show(); + mainvbox.pack_end(hbox, FALSE, TRUE, 0); - mLocalPrefs.GetPref( SI_TEXMENU_KEY, &g_qeglobals.d_savedinfo.iTexMenu, ID_VIEW_BILINEARMIPMAP ); - mLocalPrefs.GetPref( SI_GAMMA_KEY, &g_qeglobals.d_savedinfo.fGamma, 1.0f ); - mLocalPrefs.GetPref( SI_EXCLUDE_KEY, &g_qeglobals.d_savedinfo.exclude, 0 ); // nothing filtered by default - mLocalPrefs.GetPref( SI_INCLUDE_KEY, &g_qeglobals.d_savedinfo.include, INCLUDE_NAMES | INCLUDE_COORDS | INCLUDE_ANGLES | INCLUDE_CAMERATINT ); - mLocalPrefs.GetPref( SI_SHOWNAMES_KEY, &g_qeglobals.d_savedinfo.show_names, FALSE ); - mLocalPrefs.GetPref( SI_SHOWCOORDS_KEY, &g_qeglobals.d_savedinfo.show_coordinates, TRUE ); - mLocalPrefs.GetPref( SI_SHOWANGLES_KEY, &g_qeglobals.d_savedinfo.show_angles, TRUE ); - mLocalPrefs.GetPref( SI_SHOWOUTLINES_KEY, &g_qeglobals.d_savedinfo.show_outline, FALSE ); - mLocalPrefs.GetPref( SI_SHOWAXIS_KEY, &g_qeglobals.d_savedinfo.show_axis, TRUE ); - mLocalPrefs.GetPref( SI_NOSELOUTLINES_KEY, &g_qeglobals.d_savedinfo.bNoSelectedOutlines, FALSE ); - - mLocalPrefs.GetPref( SI_OUTLINESTYLE_KEY, &g_qeglobals.d_savedinfo.iSelectedOutlinesStyle, OUTLINE_ZBUF | OUTLINE_BSEL ); - - LoadTexdefPref( &g_qeglobals.d_savedinfo.m_SIIncrement, SI_SURFACE_TEXDEF_KEY ); - LoadTexdefPref( &g_qeglobals.d_savedinfo.m_PIIncrement, SI_PATCH_TEXDEF_KEY ); - - // text editor binding -#ifdef _WIN32 - mLocalPrefs.GetPref( CUSTOMSHADEREDITOR_KEY, &m_bUseWin32Editor, TRUE ); -#else - mLocalPrefs.GetPref( CUSTOMSHADEREDITOR_KEY, &m_bUseCustomEditor, FALSE ); - mLocalPrefs.GetPref( CUSTOMSHADEREDITORCOMMAND_KEY, &m_strEditorCommand, "" ); -#endif + { + 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 ); - vec3_t vDefaultAxisColours[3] = { - {0.f, 0.5f, 0.f}, - {0.f, 0.f, 1.f}, - {1.f, 0.f, 0.f}, - }; + // prefs pages notebook + m_notebook = ui::Widget::from(gtk_notebook_new()); + // hide the notebook tabs since its not supposed to look like a notebook + gtk_notebook_set_show_tabs( GTK_NOTEBOOK( m_notebook ), FALSE ); + hbox.pack_start( m_notebook, TRUE, TRUE, 0 ); + m_notebook.show(); - for ( i = 0; i < 3; i++ ) { - char buf[64]; - sprintf( buf, "%s%d", SI_AXISCOLORS_KEY, i ); - mLocalPrefs.GetPref( buf, g_qeglobals.d_savedinfo.AxisColors[i], vDefaultAxisColours[i] ); - } - vec3_t vDefaultColours[COLOR_LAST] = { - {0.25f, 0.25f, 0.25f}, - {1.f, 1.f, 1.f}, - {0.75f, 0.75f, 0.75f}, - {0.5f, 0.5f, 0.5f}, - {0.25f, 0.25f, 0.25f}, - {0.0f, 0.0f, 0.0f}, - {0.f, 0.f, 1.f}, - {0.f, 0.f, 0.f}, - {0.f, 0.f, 0.f}, - {1.f, 0.f, 0.f}, - {0.f, 0.f, 1.f}, - {0.5f, 0.f, 0.75f}, - {1.0f, 0.f, 0.f}, - {0.f, 0.f, 0.f}, - {0.f, 0.f, 0.f}, - }; - - for ( i = 0; i < COLOR_LAST; i++ ) { - char buf[64]; - sprintf( buf, "%s%d", SI_COLORS_KEY, i ); - mLocalPrefs.GetPref( buf, g_qeglobals.d_savedinfo.colors[i], vDefaultColours[i] ); + { + auto store = ui::TreeStore::from(gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER )); + + auto view = ui::TreeView(ui::TreeModel::from(store._handle)); + gtk_tree_view_set_headers_visible(view, FALSE ); + + { + auto renderer = ui::CellRendererText(ui::New); + auto column = ui::TreeViewColumn( "Preferences", renderer, {{"text", 0}} ); + gtk_tree_view_append_column(view, column ); + } + + { + auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(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" ); + + { + auto global = PreferencePages_addPage( m_notebook, "Global Preferences" ); + { + PreferencesPage preferencesPage( *this, getVBox( global ) ); + Global_constructPreferences( preferencesPage ); + } + auto group = PreferenceTree_appendPage( store, 0, "Global", global ); + { + auto game = PreferencePages_addPage( m_notebook, "Game" ); + PreferencesPage preferencesPage( *this, getVBox( game ) ); + g_GamesDialog.CreateGlobalFrame( preferencesPage ); + + PreferenceTree_appendPage( store, &group, "Game", game ); + } + } + + { + auto interfacePage = PreferencePages_addPage( m_notebook, "Interface Preferences" ); + { + PreferencesPage preferencesPage( *this, getVBox( interfacePage ) ); + PreferencesPageCallbacks_constructPage( g_interfacePreferences, preferencesPage ); + } + + auto group = PreferenceTree_appendPage( store, 0, "Interface", interfacePage ); + PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group ); + + PreferenceGroupCallbacks_constructGroup( g_interfaceCallbacks, preferenceGroup ); + } + + { + auto display = PreferencePages_addPage( m_notebook, "Display Preferences" ); + { + PreferencesPage preferencesPage( *this, getVBox( display ) ); + PreferencesPageCallbacks_constructPage( g_displayPreferences, preferencesPage ); + } + auto group = PreferenceTree_appendPage( store, 0, "Display", display ); + PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group ); + + PreferenceGroupCallbacks_constructGroup( g_displayCallbacks, preferenceGroup ); + } + + { + auto settings = PreferencePages_addPage( m_notebook, "General Settings" ); + { + PreferencesPage preferencesPage( *this, getVBox( settings ) ); + PreferencesPageCallbacks_constructPage( g_settingsPreferences, preferencesPage ); + } + + auto group = PreferenceTree_appendPage( store, 0, "Settings", settings ); + PreferenceTreeGroup preferenceGroup( *this, m_notebook, store, group ); + + PreferenceGroupCallbacks_constructGroup( g_settingsCallbacks, preferenceGroup ); + } + } + + gtk_tree_view_expand_all(view ); + + g_object_unref( G_OBJECT( store ) ); + } + } + } } - mLocalPrefs.GetPref( TEXTURECOMPRESSIONFORMAT_KEY, &m_nTextureCompressionFormat, 1 ); - - mLocalPrefs.GetPref( LIGHTRADIUS_KEY, &m_nLightRadiuses, TRUE ); + gtk_notebook_set_current_page( GTK_NOTEBOOK( m_notebook ), 0 ); - mLocalPrefs.GetPref( Q3MAP2TEX_KEY, &m_bQ3Map2Texturing, TRUE ); + return dialog; +} -#ifdef ATIHACK_812 - mLocalPrefs.GetPref( ATIHACK_KEY, &m_bGlATIHack, FALSE ); -#endif +preferences_globals_t g_preferences_globals; -#ifdef NVIDIA_AERO_HACK - mLocalPrefs.GetPref( NVAEROHACK_KEY, &m_bGlNvidiaAeroHack, TRUE ); -#endif +PrefsDlg g_Preferences; // global prefs instance - Undo_SetMaxSize( m_nUndoLevels ); // set it internally as well / FIXME: why not just have one global value? - UpdateTextureCompression(); +void PreferencesDialog_constructWindow( ui::Window main_window ){ + g_Preferences.m_parent = main_window; + g_Preferences.Create(); +} +void PreferencesDialog_destroyWindow(){ + g_Preferences.Destroy(); +} -#ifdef ATIHACK_812 - UpdateATIHack(); -#endif -#ifdef NVIDIA_AERO_HACK - UpdateNvidiaAeroHack(); -#endif +PreferenceDictionary g_preferences; - if ( mLocalPrefs.mbEmpty ) { - mLocalPrefs.mbEmpty = false; - Sys_Printf( "Saving local.pref with default pref values\n" ); - SavePrefs(); - } +PreferenceSystem& GetPreferenceSystem(){ + return g_preferences; } -void PrefsDlg::SavePrefs(){ - if ( g_qeglobals.disable_ini ) { - return; - } - -#ifdef _DEBUG - Sys_Printf( "PrefsDlg::SavePrefs\n" ); -#endif +class PreferenceSystemAPI +{ +PreferenceSystem* m_preferencesystem; +public: +typedef PreferenceSystem Type; +STRING_CONSTANT( Name, "*" ); - // this will take care of copying back from the dialog to the variables - // NOTE: it may be overkill to call systematically before a SavePrefs, but it's safer - // this will also cause an UpdateData for the mGamesDialog - UpdateData( TRUE ); +PreferenceSystemAPI(){ + m_preferencesystem = &GetPreferenceSystem(); +} +PreferenceSystem* getTable(){ + return m_preferencesystem; +} +}; - mGamesDialog.SavePrefs(); +#include "modulesystem/singletonmodule.h" +#include "modulesystem/moduleregistry.h" - // update the tree and save it - mLocalPrefs.UpdatePrefTree(); - if ( !mLocalPrefs.WriteXMLFile( m_inipath->str ) ) { - Sys_FPrintf( SYS_ERR, "Error occured while saving local prefs file '%s'\n", m_inipath->str ); - } +typedef SingletonModule PreferenceSystemModule; +typedef Static StaticPreferenceSystemModule; +StaticRegisterModule staticRegisterPreferenceSystem( StaticPreferenceSystemModule::instance() ); - if ( m_nMouse == 0 ) { - m_nMouseButtons = 2; - } - else { - m_nMouseButtons = 3; - } +void Preferences_Load(){ + g_GamesDialog.LoadPrefs(); -} + globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n"; -void PrefsDlg::PostModal( int code ){ - if ( code == IDOK ) { - SavePrefs(); - // make sure the logfile is ok - Sys_LogFile(); -#ifdef ATIHACK_812 - UpdateATIHack(); -#endif -#ifdef NVIDIA_AERO_HACK - UpdateNvidiaAeroHack(); -#endif - if ( g_pParentWnd ) { - g_pParentWnd->SetGridStatus(); - } - Sys_UpdateWindows( W_ALL ); - if ( m_nUndoLevels != 0 ) { - Undo_SetMaxSize( m_nUndoLevels ); - } + 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 PrefsDlg::DoEditorSensitivity(){ - if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( m_pWidget ), "check_customeditor" ) ) ) ) { - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "label_customeditor" ) ), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "entry_customeditor" ) ), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "button_customeditor" ) ), TRUE ); - } - else - { - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "label_customeditor" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "entry_customeditor" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "button_customeditor" ) ), FALSE ); +void Preferences_Save(){ + if ( g_preferences_globals.disable_ini ) { + return; } -} -void PrefsDlg::DoSensitivity(){ -#if 0 - // first, look at the project file version ... will monitoring work? - // project files now XML, guaranteed to be at least version 2 - if ( 0 ) { //IntForKey( g_qeglobals.d_project_entity, "version" ) < 2) - if ( m_bWarn ) { - Str Msg; - Msg = "The current project file ("; - Msg += g_PrefsDlg.m_strLastProject; - Msg += ") is not at least version 2.\nI need version 2 or above to setup BSP monitoring correctly."; - gtk_MessageBox( m_pWidget, Msg.GetBuffer(), MB_OK ); - - m_bWarn = false; - } - - // go ahead, disable everybuddy - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_leakstop" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_monitorbsp" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), FALSE ); - } - else - { -#endif -// m_bWarn = true; + // save global preferences + g_GamesDialog.SavePrefs(); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_leakstop" ) ), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_monitorbsp" ) ), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), TRUE ); + globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n"; - if ( !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( m_pWidget ), "check_monitorbsp" ) ) ) ) { - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_leakstop" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), FALSE ); - } - else if ( !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ) ) ) { - gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), FALSE ); + if ( !Preferences_Save_Safe( g_preferences, g_Preferences.m_inipath->str ) ) { + globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n"; } } -/* - ============================================================ - CGameInstall - ============================================================ - */ - -CGameInstall::CGameInstall() { - memset( m_availGames, 0, sizeof( m_availGames ) ); +void Preferences_Reset(){ + file_remove( g_Preferences.m_inipath->str ); } -void CGameInstall::OnBtnBrowseEngine( GtkWidget *widget, gpointer data ) { - Sys_Printf( "OnBtnBrowseEngine\n" ); - - CGameInstall* i = static_cast( data ); - char *dir = dir_dialog( i->m_pWidget, _( "Select game directory" ), NULL ); - i->UpdateData( TRUE ); - - if ( dir != NULL ) { - i->m_strEngine = dir; - i->UpdateData( FALSE ); - g_free( dir ); +void PrefsDlg::PostModal( EMessageBoxReturn code ){ + if ( code == eIDOK ) { + Preferences_Save(); + UpdateAllWindows(); } } -void CGameInstall::OnGameSelectChanged( GtkWidget *widget, gpointer data ) { - Sys_Printf( "OnGameSelectChanged\n" ); +std::vector g_restart_required; - CGameInstall* i = static_cast( data ); - i->UpdateData( TRUE ); - i->m_strName = gtk_combo_box_get_active_text( GTK_COMBO_BOX( widget ) ); - i->UpdateData( FALSE ); +void PreferencesDialog_restartRequired( const char* staticName ){ + g_restart_required.push_back( staticName ); } -void CGameInstall::BuildDialog() { - GtkWidget *dlg, *vbox1, *button, *text, *combo, *entry, *hbox; +bool PreferencesDialog_isRestartRequired(){ + return !g_restart_required.empty(); +} - dlg = m_pWidget; - gtk_window_set_title( GTK_WINDOW( dlg ), _( "Configure games" ) ); +void PreferencesDialog_restartIfRequired(){ + if ( !g_restart_required.empty() ) { + StringOutputStream message( 256 ); + message << "Preference changes require a restart:\n\n"; - vbox1 = gtk_vbox_new( FALSE, 0 ); - gtk_widget_show( vbox1 ); - gtk_container_add( GTK_CONTAINER( dlg ), vbox1 ); + for ( std::vector::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i ) + { + message << ( *i ) << '\n'; + } - text = gtk_label_new( _( "Select the game to configure" ) ); - gtk_widget_show( text ); - gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 ); + message << "\nRestart now?"; - combo = gtk_combo_box_new_text(); - gtk_widget_show( combo ); - gtk_box_pack_start( GTK_BOX( vbox1 ), combo, FALSE, FALSE, 0 ); + auto ret = ui::alert( MainFrame_getWindow(), message.c_str(), "Restart " RADIANT_NAME "?", ui::alert_type::YESNO, ui::alert_icon::Question ); - // GList *combo_list = NULL; - int iGame = 0; - while ( m_availGames[ iGame ] != GAME_NONE ) { - switch ( m_availGames[ iGame ] ) { - case GAME_Q2: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Quake II" ) ); - break; - case GAME_Q3: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Quake III Arena and mods" ) ); - break; - case GAME_URT: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Urban Terror (standalone)" ) ); - break; - case GAME_UFOAI: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "UFO: Alien Invasion" ) ); - break; - case GAME_Q2W: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Quake2World" ) ); - break; - case GAME_WARSOW: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Warsow" ) ); - break; - case GAME_NEXUIZ: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Nexuiz" ) ); - break; - case GAME_TREMULOUS: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Tremulous" ) ); - break; - case GAME_JA: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Jedi Academy and mods" ) ); - break; - case GAME_REACTION: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Reaction Quake 3" ) ); - break; - case GAME_ET: - gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Wolfenstein: Enemy Territory" ) ); - break; + g_restart_required.clear(); + + if ( ret == ui::alert_response::YES ) { + g_GamesDialog.m_bSkipGamePromptOnce = true; + Radiant_Restart(); } - iGame++; } - 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 ); - gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 ); - - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_box_pack_start( GTK_BOX( vbox1 ), entry, FALSE, FALSE, 0 ); - AddDialogData( entry, &m_strName, DLG_ENTRY_TEXT ); - - 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( 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:" ) ); - gtk_widget_show( text ); - gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 ); - - entry = gtk_entry_new(); - gtk_widget_show( entry ); - gtk_box_pack_start( GTK_BOX( vbox1 ), entry, FALSE, FALSE, 0 ); - AddDialogData( entry, &m_strMod, DLG_ENTRY_TEXT ); -#endif - - button = gtk_button_new_with_label( _( "OK" ) ); - 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 CGameInstall::Run() { - ScanGames(); - if ( m_availGames[0] == GAME_NONE ) { - return; - } - if ( DoModal() == IDCANCEL ) { - Sys_Printf( "game dialog cancelled\n" ); - return; +void PreferencesDialog_showDialog(){ + if ( ConfirmModified( "Edit Preferences" ) && g_Preferences.DoModal() == eIDOK ) { + PreferencesDialog_restartIfRequired(); } - 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 - Str gameFilePath = g_strAppPath.GetBuffer(); - gameFilePath += "games/"; - if ( CheckFile( gameFilePath ) != PATH_DIRECTORY ) { - radCreateDirectory( gameFilePath ); +struct GameName { + static void Export(const Callback &returnz) { + returnz(gamename_get()); } - switch ( m_availGames[ m_nComboSelect ] ) { - case GAME_Q2: - gameFilePath += "q2.game"; - break; - case GAME_Q3: - gameFilePath += "q3.game"; - break; - case GAME_URT: - gameFilePath += "urt.game"; - break; - case GAME_UFOAI: - gameFilePath += "ufoai.game"; - break; - case GAME_Q2W: - gameFilePath += "q2w.game"; - break; - case GAME_WARSOW: - gameFilePath += "warsow.game"; - break; - case GAME_NEXUIZ: - gameFilePath += "nexuiz.game"; - break; - case GAME_TREMULOUS: - gameFilePath += "tremulous.game"; - break; - case GAME_JA: - gameFilePath += "ja.game"; - break; - case GAME_REACTION: - gameFilePath += "reaction.game"; - break; - case GAME_ET: - gameFilePath += "et.game"; - break; + static void Import(const char *value) { + gamename_set(value); } +}; - Sys_Printf( "game file: %s\n", gameFilePath.GetBuffer() ); - - FILE * fg = fopen( gameFilePath.GetBuffer(), "w" ); - if ( fg == NULL ) { - Error( "Failed to open %s for writing\n", gameFilePath.GetBuffer() ); - } - fprintf( fg, "\n &returnz) { + returnz(gamemode_get()); } - case GAME_NEXUIZ: { - fprintf( fg, " "TOOLS_ATTRIBUTE "=\"%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(); - radCopyTree( source.GetBuffer(), dest.GetBuffer() ); - fprintf( fg, " basegame=\"data\"\n" ); - break; - } - case GAME_TREMULOUS: { - fprintf( fg, " "TOOLS_ATTRIBUTE "=\"%sinstalls/TremulousPack/game\"\n", g_strAppPath.GetBuffer() ); - fprintf( fg, " prefix=\".tremulous\"\n" ); - Str source = g_strAppPath.GetBuffer(); - source += "installs/"; - source += TREMULOUS_PACK; - source += "/install/"; - Str dest = m_strEngine.GetBuffer(); - radCopyTree( source.GetBuffer(), dest.GetBuffer() ); - fprintf( fg, " basegame=\"base\"\n" ); - break; - } - case GAME_JA: { - fprintf( fg, " "TOOLS_ATTRIBUTE "=\"%sinstalls/JAPack/game\"\n", g_strAppPath.GetBuffer() ); - fprintf( fg, " prefix=\".ja\"\n" ); - Str source = g_strAppPath.GetBuffer(); - source += "installs/"; - source += JA_PACK; - source += "/install/"; - Str dest = m_strEngine.GetBuffer(); - radCopyTree( source.GetBuffer(), dest.GetBuffer() ); - fprintf( fg, " basegame=\"base\"\n" ); - break; - } - case GAME_REACTION: { - fprintf( fg, " "TOOLS_ATTRIBUTE "=\"%sinstalls/"REACTION_PACK "/game\"\n", g_strAppPath.GetBuffer() ); - fprintf( fg, " prefix=\".Reaction\"\n" ); - Str source = g_strAppPath.GetBuffer(); - source += "installs/"; - source += REACTION_PACK; - source += "/install/"; - Str dest = m_strEngine.GetBuffer(); - radCopyTree( source.GetBuffer(), dest.GetBuffer() ); - fprintf( fg, " basegame=\"Boomstick\"\n" ); - fprintf( fg, " default_scale=\"0.5\"\n" ); // Superfluous because the default is already 0.5, - // but demonstrates how to set the default texture scale - // for a specific game. - break; + + static void Import(const char *value) { + gamemode_set(value); } - case GAME_ET: { -#ifdef _WIN32 - fprintf( fg, " "ENGINE_ATTRIBUTE "=\"ET.exe\"\n"); -#elif __linux__ - fprintf( fg, " "ENGINE_ATTRIBUTE "=\"et\"\n" ); +}; + +void RegisterPreferences( PreferenceSystem& preferences ){ +#if GDEF_OS_WINDOWS + preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) ); +#else + preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useCustomEditor ) ); + preferences.registerPreference( "CustomShaderEditorCommand", make_property_string( g_TextEditor_editorCommand ) ); #endif - fprintf( fg, " "TOOLS_ATTRIBUTE "=\"%sinstalls/"ET_PACK "/game\"\n", g_strAppPath.GetBuffer() ); - fprintf( fg, " prefix=\".etwolf\"\n" ); - Str source = g_strAppPath.GetBuffer(); - source += "installs/"; - source += ET_PACK; - source += "/install/"; - Str dest = m_strEngine.GetBuffer(); - radCopyTree( source.GetBuffer(), dest.GetBuffer() ); - // Hardcoded fix for "missing" shaderlist in gamepack - dest += "/etmain/scripts/shaderlist.txt"; - if(CheckFile(dest.GetBuffer()) != PATH_FILE) { - source += "etmain/scripts/default_shaderlist.txt"; - radCopyFile(source.GetBuffer(),dest.GetBuffer()); - } - fprintf( fg, " basegame=\"etmain\"\n" ); - break; - } - } - fprintf( fg, "/>\n" ); - fclose( fg ); + + preferences.registerPreference( "GameName", make_property() ); + preferences.registerPreference( "GameMode", make_property() ); } -/* - =============== - CGameInstall::ScanGames - scan for active games that can be installed, based on the presence - =============== - */ -void CGameInstall::ScanGames() { - Str pakPaths = g_strAppPath.GetBuffer(); - int iGame = 0; - const char *dirname; - - pakPaths += "installs/"; - FindFiles fileScan( pakPaths.GetBuffer() ); - while ( ( dirname = fileScan.NextFile() ) != NULL ) { - if ( stricmp( dirname, Q3_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_Q3; - } - if ( stricmp( dirname, URT_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_URT; - } - if ( stricmp( dirname, UFOAI_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_UFOAI; - } - if ( stricmp( dirname, Q2W_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_Q2W; - } - if ( stricmp( dirname, WARSOW_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_WARSOW; - } - if ( stricmp( dirname, NEXUIZ_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_NEXUIZ; - } - if ( stricmp( dirname, Q2_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_Q2; - } - if ( stricmp( dirname, TREMULOUS_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_TREMULOUS; - } - if ( stricmp( dirname, JA_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_JA; - } - if ( stricmp( dirname, REACTION_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_REACTION; - } - if ( stricmp( dirname, ET_PACK ) == 0 ) { - m_availGames[ iGame++ ] = GAME_ET; - } - } - Sys_Printf( "No installable games found in: %s\n", - pakPaths.GetBuffer() ); +void Preferences_Init(){ + RegisterPreferences( GetPreferenceSystem() ); }