]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/preferences.cpp
Check if games folder exists, and copy shaderlist for Q3 if missing
[xonotic/netradiant.git] / radiant / preferences.cpp
1 /*
2    Copyright (C) 1999-2007 id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 //
23 // User preferences
24 //
25 // Leonardo Zide (leo@lokigames.com)
26 //
27
28 #include "stdafx.h"
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <assert.h>
32 #if defined ( __linux__ ) || defined ( __APPLE__ )
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #endif
39 #include "missing.h"
40 #include "gtkmisc.h"
41
42 #ifdef _WIN32
43 #include <io.h>
44 #define X_OK 0
45 #include <sys/stat.h>
46 #endif
47
48 #define PREF_SECTION            "Prefs"
49 #define INTERNAL_SECTION        "Internals"
50 #define MOUSE_KEY               "MouseButtons"
51 #define WINDOW_KEY              "QE4StyleWindows"
52 #define LAYOUT_KEY              "WindowLayout"
53 #define RUNQ2_KEY               "RunQuake2Run"
54 #define TLOCK_KEY               "TextureLock"
55 #define RLOCK_KEY               "RotateLock"
56 #define LOADLAST_KEY            "LoadLast"
57 #define LOADLASTMAP_KEY         "LoadLastMap"
58 #define LASTPROJ_KEY            "LastProject"
59 #define LASTPROJVER_KEY         "LastProjectKey"
60 #define LASTMAP_KEY             "LastMap"
61 #define FACE_KEY                "NewFaceGrab"
62 #define BSP_KEY                 "InternalBSP"
63 #define RCLICK_KEY              "NewRightClick"
64 #define VERTEX_KEY              "NewVertex"
65 #define AUTOSAVE_KEY            "Autosave"
66 #define AUTOSAVETIME_KEY        "AutosaveMinutes"
67 #define PAK_KEY                 "UsePAK"
68 #define NEWAPPLY_KEY            "ApplyDismissesSurface"
69 #define HACK_KEY                "Gatewayescapehack"
70 #define TEXTURE_KEY             "NewTextureWindowStuff"
71 #define TINYBRUSH_KEY           "CleanTinyBrushes"
72 #define TINYSIZE_KEY            "CleanTinyBrusheSize"
73 #define SNAPSHOT_KEY            "Snapshots"
74 #define MOVESPEED_KEY           "MoveSpeed"
75 #define ANGLESPEED_KEY          "AngleSpeed"
76 #define SETGAME_KEY             "UseSetGame"
77 #define CAMXYUPDATE_KEY         "CamXYUpdate"
78 #define CAMDRAGMULTISELECT_KEY  "CamDragMultiSelect"
79 #define CAMFREELOOK_KEY         "CamFreeLook"
80 #define CAMINVERSEMOUSE_KEY     "CamInverseMouse"
81 #define CAMDISCRETE_KEY         "CamDiscrete"
82 #define LIGHTDRAW_KEY           "NewLightStyle"
83 #define WHATGAME_KEY            "WhichGame"
84 #define CUBICCLIP_KEY           "CubicClipping"
85 #define CUBICSCALE_KEY          "CubicScale"
86 #define ALTEDGE_KEY             "ALTEdgeDrag"
87 #define FACECOLORS_KEY          "FaceColors"
88 #define SNAPT_KEY               "SnapT"
89 #define XZVIS_KEY               "XZVIS"
90 #define YZVIS_KEY               "YZVIS"
91 #define ZVIS_KEY                "ZVIS"
92 #define SIZEPAINT_KEY           "SizePainting"
93 #define DLLENTITIES_KEY         "DLLEntities"
94 #define DETACHABLEMENUS_KEY     "DetachableMenus"
95 #define PATCHTOOLBAR_KEY        "PatchToolBar"
96 #define WIDETOOLBAR_KEY         "WideToolBar"
97 #define PLUGINTOOLBAR_KEY "PluginToolBar"
98 #define NOCLAMP_KEY             "NoClamp"
99 #define SNAP_KEY                "Snap"
100 #define PREFAB_KEY              "PrefabPath"
101 #define USERINI_KEY             "UserINIPath"
102 #define ROTATION_KEY            "Rotation"
103 #define BUGGYICD_KEY            "BuggyICD"
104 #define CHASEMOUSE_KEY          "ChaseMouse"
105 #define ENTITYSHOW_KEY          "EntityShow"
106 #define TEXTURESCALE_KEY        "TextureScale"
107 #define TEXTURESCROLLBAR_KEY    "TextureScrollbar"
108 #define DISPLAYLISTS_KEY        "UseDisplayLists"
109 #define ANTIALIASEDLINES_KEY    "UseAntialiasedPointsAndLines" // Fishman - Add antialiazed points and lines support. 09/03/00
110 #define NORMALIZECOLORS_KEY     "NormalizeColors"
111 #define SHADERS_KEY             "UseShaders"
112 #define SWITCHCLIP_KEY          "SwitchClipKey"
113 #define SELWHOLEENTS_KEY            "SelectWholeEntitiesKey"
114 #define TEXTURESUBSET_KEY         "UseTextureSubsetLoading"
115 #define TEXTUREQUALITY_KEY      "TextureQuality"
116 #define SHOWSHADERS_KEY           "ShowShaders"
117 #define SHADERTEST_KEY          "ShaderTest"
118 #define GLLIGHTING_KEY          "UseGLLighting"
119 #define LOADSHADERS_KEY         "LoadShaders"
120 #define NOSTIPPLE_KEY           "NoStipple"
121 #define UNDOLEVELS_KEY          "UndoLevels"
122 #define VERTEXMODE_KEY          "VertexSplit"
123 #define ENGINEPATH_KEY          "EnginePath"
124 #define ENGINE_KEY              "Engine"
125 #define LOGCONSOLE_KEY          "LogConsole"
126 #define SELECTCURVES_KEY        "SelectCurves"
127 #define SELECTMODELS_KEY        "SelectModels"
128 #define SHADERLISTONLY_KEY      "ShowShaderlistOnly"
129 #define WATCHBSP_KEY            "WatchBSP"
130 #define LEAKSTOP_KEY            "LeakStop"
131 #define DOSLEEP_KEY             "SleepMode"
132 #define SUBDIVISIONS_KEY        "Subdivisions"
133 #define DEFAULTTEXURESCALE_KEY  "DefaultTextureScale"
134 #define CLIPCAULK_KEY           "ClipCaulk"
135 #define PATCHSHOWBOUNDS_KEY     "PatchShowBounds"
136 #define NATIVEGUI_KEY           "NativeGUI"
137 #define STARTONPRIMMON_KEY      "StartOnPrimMon"
138 #define NOSYSMENUPOPUPS_KEY     "NoSysMenuPopups"
139 #define SNAPTTOGRID_KEY         "SnapTToGrid"
140 #define FLOATINGZ_KEY           "FloatingZ"
141 #define TARGETFIX_KEY           "TargetFix"
142 #define GLPOINTWORKAROUND_KEY   "GlPointWorkaround"     // Gef: Workaround for broken Kyro * gl driver 25-aug-2001
143 #define WHEELINC_KEY            "WheelMouseInc"
144 #define PATCHBBOXSEL_KEY        "PatchBBoxSel"
145 #define LASTLIGHTINTENSITY_KEY  "LastLightIntensity"
146 #define CUSTOMSHADEREDITOR_KEY        "UseCustomShaderEditor"
147 #define CUSTOMSHADEREDITORCOMMAND_KEY "CustomShaderEditorCommand"
148 #define TEXTURECOMPRESSIONFORMAT_KEY "TextureCompressionFormat"
149 #define LIGHTRADIUS_KEY "LightRadiuses"
150 #define Q3MAP2TEX_KEY "Q3Map2Tex"
151
152 #ifdef ATIHACK_812
153 #define ATIHACK_KEY "ATIHack"
154 #endif
155
156 #ifdef NVIDIA_AERO_HACK
157 #define NVAEROHACK_KEY "NvidiaAeroHack"
158 #endif
159
160 // window stuff
161 #define ENTITYSPLIT1_KEY  "EntitySplit1"
162 #define ENTITYSPLIT2_KEY  "EntitySplit2"
163 #define POSITIONX_KEY     "PositionX"
164 #define POSITIONY_KEY     "PositionY"
165 #define ENTITYWND_KEY     "EntityWnd"
166 #define MAPINFOWND_KEY    "MapInfoDlg"
167 #define CAMWND_KEY        "CamWnd"
168 #define ZWND_KEY          "ZWnd"
169 #define XYWND_KEY         "XYWnd"
170 #define XZWND_KEY         "XZWnd"
171 #define YZWND_KEY         "YZWnd"
172 #define PATCHWND_KEY      "PatchWnd"
173 #define SURFACEWND_KEY    "SurfaceWnd"
174 #define ENTITYINFOWND_KEY "EntityInfoDlg"
175 #define WIDTH_KEY         "Width"
176 #define HEIGHT_KEY        "Height"
177 #define ZWIDTH_KEY        "ZWidth"
178 #define XYHEIGHT_KEY      "XYHeight"
179 #define XYWIDTH_KEY       "XYWidth"
180 #define CAMWIDTH_KEY      "CamWidth"
181 #define CAMHEIGHT_KEY     "CamHeight"
182 #define ZFLOATWIDTH_KEY   "ZWidthFloating"
183 #define STATE_KEY         "State"
184
185 // menu stuff
186 #define COUNT_KEY         "Count"
187 #define FILE_KEY          "File"
188
189 //saved info
190 #define SI_TEXMENU_KEY          "SI_TexMenu"
191 #define SI_GAMMA_KEY            "SI_Gamma"
192 #define SI_COLORS_KEY           "SI_Colors"
193 #define SI_EXCLUDE_KEY          "SI_Exclude"
194 #define SI_INCLUDE_KEY          "SI_Include"
195 #define SI_SURFACE_TEXDEF_KEY   "SI_SurfaceTexdef"
196 #define SI_PATCH_TEXDEF_KEY     "SI_PatchTexdef"
197 #define SI_AXISCOLORS_KEY       "SI_AxisColors"
198 #define SI_SHOWNAMES_KEY        "SI_ShowNames"
199 #define SI_SHOWCOORDS_KEY       "SI_ShowCoords"
200 #define SI_SHOWANGLES_KEY       "SI_ShowAngles"
201 #define SI_SHOWOUTLINES_KEY     "SI_ShowOutlines"
202 #define SI_SHOWAXIS_KEY         "SI_ShowAxis"
203 #define SI_NOSELOUTLINES_KEY    "SI_NoSelectedOutlines"
204 #define SI_OUTLINESTYLE_KEY "SI_OutLineStyle"
205
206 //for texdefs
207 #define TD_SCALE1_KEY           "_Scale1"
208 #define TD_SCALE2_KEY           "_Scale2"
209 #define TD_SHIFT1_KEY           "_Shift1"
210 #define TD_SHIFT2_KEY           "_Shift2"
211 #define TD_ROTATE_KEY           "_Rotate"
212
213 #define MOUSE_DEF 1
214 #define WINDOW_DEF 0
215 #define RUNQ2_DEF 0
216 #define WATCHBSP_DEF 1
217 #define TLOCK_DEF 1
218 #define LOADLAST_DEF 1
219 #define RUN_DEF 0
220 #define SUBDIVISIONS_DEF 4
221
222 void WindowPosition_Parse( window_position_t& m_value, const CString& value ){
223         if ( sscanf( value.GetBuffer(), "%d %d %d %d", &m_value.x, &m_value.y, &m_value.w, &m_value.h ) != 4 ) {
224                 m_value.x = m_value.y = m_value.w = m_value.h = -1;
225         }
226 }
227
228 void WindowPosition_Write( const window_position_t& m_value, CString& value ){
229         char buffer[64];
230         sprintf( buffer, "%d %d %d %d", m_value.x, m_value.y, m_value.w, m_value.h );
231         value = buffer;
232 }
233
234
235 CXMLPropertyBag::CXMLPropertyBag() {
236         mStrFilename = "";
237         mpDoc = NULL;
238         mbEmpty = false;
239 }
240
241 // generic preference functions
242
243 void CXMLPropertyBag::PushAssignment( const char *name, PrefTypes_t type, void *pV ){
244         list<CPrefAssignment>::iterator iAssign;
245         for ( iAssign = mPrefAssignments.begin(); iAssign != mPrefAssignments.end(); iAssign++ )
246         {
247                 if ( ( *iAssign ).mName == name ) {
248                         // we have it already, check anyway
249                         if ( pV != ( *iAssign ).mVal ) {
250                                 Sys_FPrintf( SYS_ERR, "PushAssignment, '%s' has different mVal\n", name );
251                                 return;
252                         }
253                 }
254         }
255         // ok, it's not in our list yet
256         mPrefAssignments.push_front( CPrefAssignment( name, type, pV ) );
257 }
258
259 xmlNodePtr CXMLPropertyBag::EpairForName( const char *name ){
260         xmlNodePtr ret = NULL;
261
262         xmlNodePtr pNode = mpDocNode->children;
263         while ( pNode != NULL )
264         {
265                 if ( pNode->type == XML_ELEMENT_NODE ) {
266                         xmlAttrPtr tmp_attr_ptr = xmlHasProp( pNode, (xmlChar *)"name" );
267                         if ( tmp_attr_ptr != NULL && !strcmp( name, (char *)tmp_attr_ptr->children->content ) ) {
268                                 if ( ret ) {
269                                         Sys_FPrintf( SYS_WRN, "WARNING: dupe property in CXMLPropertyBag::EpairForName '%s'\n", name );
270                                 }
271                                 else {
272                                         ret = pNode;
273                                 }
274                         }
275                 }
276                 pNode = pNode->next;
277         }
278         return ret;
279 }
280
281 void CXMLPropertyBag::GetPref( const char *name, Str *pV, const char *V ){
282         xmlNodePtr pNode = EpairForName( name );
283         if ( pNode ) {
284                 if ( pNode->children && pNode->children->content ) {
285                         *pV = pNode->children->content;
286                 }
287                 else {
288                         // means the pref exists, and that the value is ""
289                         *pV = "";
290                 }
291         }
292         else
293         {
294                 pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)V );
295                 xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name );
296         }
297         // push the pref assignment if needed
298         PushAssignment( name, PREF_STR, pV );
299 }
300
301 void CXMLPropertyBag::GetPref( const char *name, int *pV, int V ){
302         xmlNodePtr pNode;
303         if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) {
304                 *pV = atoi( (char *)pNode->children->content );
305         }
306         else
307         {
308                 char s[10];
309                 sprintf( s, "%d", V );
310                 pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s );
311                 xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name );
312                 *pV = V;
313         }
314         // push the pref assignment if needed
315         PushAssignment( name, PREF_INT, pV );
316 }
317
318 void CXMLPropertyBag::GetPref( const char *name, bool *pV, bool V ){
319         xmlNodePtr pNode;
320         if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) {
321                 if ( !strcmp( (char *)pNode->children->content, "true" ) ) {
322                         *pV = true;
323                 }
324                 else
325                 {
326                         *pV = false;
327                 }
328         }
329         else
330         {
331                 char s[10];
332                 V ? strcpy( s, "true" ) : strcpy( s, "false" );
333                 pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s );
334                 xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name );
335                 *pV = V;
336         }
337         // push the pref assignment
338         PushAssignment( name, PREF_BOOL, pV );
339 }
340
341 void CXMLPropertyBag::GetPref( const char *name, float *pV, float V ){
342         xmlNodePtr pNode;
343         if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) {
344                 *pV = atof( (char *)pNode->children->content );
345         }
346         else
347         {
348                 char s[10];
349                 sprintf( s, "%f", V );
350                 pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s );
351                 xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name );
352                 *pV = V;
353         }
354         // push the pref assignment if needed
355         PushAssignment( name, PREF_FLOAT, pV );
356 }
357
358 void CXMLPropertyBag::GetPref( const char *name, float* pV, float* V ){
359         xmlNodePtr pNode;
360         if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) {
361                 sscanf( (char *)pNode->children->content, "%f %f %f", &pV[0], &pV[1], &pV[2] );
362         }
363         else
364         {
365                 char s[128];
366                 sprintf( s, "%f %f %f", V[0], V[1], V[2] );
367                 pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s );
368                 xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name );
369                 pV[0] = V[0];
370                 pV[1] = V[1];
371                 pV[2] = V[2];
372         }
373         // push the pref assignment if needed
374         PushAssignment( name, PREF_VEC3, pV );
375 }
376
377 void CXMLPropertyBag::GetPref( const char *name, window_position_t* pV, window_position_t V ){
378         xmlNodePtr pNode;
379         if ( ( pNode = EpairForName( name ) ) && pNode->children && pNode->children->content ) {
380                 WindowPosition_Parse( *pV, CString( (xmlChar *)pNode->children->content ) );
381         }
382         else
383         {
384                 CString str;
385                 WindowPosition_Write( V, str );
386                 pNode = xmlNewChild( mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)str.GetBuffer() );
387                 xmlSetProp( pNode, (xmlChar *)"name", (xmlChar *)name );
388                 *pV = V;
389         }
390         // push the pref assignment if needed
391         PushAssignment( name, PREF_WNDPOS, pV );
392 }
393
394 void CXMLPropertyBag::UpdatePrefTree(){
395         // read the assignments and update the tree
396         list<CPrefAssignment>::iterator iPref;
397         for ( iPref = mPrefAssignments.begin(); iPref != mPrefAssignments.end(); iPref++ )
398         {
399                 CPrefAssignment *pPref = &( *iPref );
400                 // look for the node
401                 xmlNodePtr pNode;
402                 char s[64];
403
404                 pNode = EpairForName( pPref->mName.GetBuffer() );
405                 // we never expect that the node could not be found, because this is supposed to happen
406                 // after the tree was built with GetPref calls, never on a blank tree
407                 if ( !pNode ) {
408                         Sys_FPrintf( SYS_ERR, "Unexpected EpairForName '%s' not found in UpdatePrefTree\n", pPref->mName.GetBuffer() );
409                         return;
410                 }
411                 switch ( ( *iPref ).mType )
412                 {
413                 case PREF_STR:
414                         xmlNodeSetContent( pNode, (const xmlChar *)( (Str *)pPref->mVal )->GetBuffer() );
415                         break;
416                 case PREF_INT:
417                         sprintf( s, "%d", *(int *)pPref->mVal );
418                         xmlNodeSetContent( pNode, (xmlChar *)s );
419                         break;
420                 case PREF_FLOAT:
421                         sprintf( s, "%f", *(float *)pPref->mVal );
422                         xmlNodeSetContent( pNode, (xmlChar *)s );
423                         break;
424                 case PREF_BOOL:
425                         *(bool *)pPref->mVal ? strcpy( s, "true" ) : strcpy( s, "false" );
426                         xmlNodeSetContent( pNode, (xmlChar *)s );
427                         break;
428                 case PREF_VEC3:
429                 {
430                         float* v = (float*)pPref->mVal;
431                         sprintf( s, "%f %f %f", v[0], v[1], v[2] );
432                         xmlNodeSetContent( pNode, (xmlChar *)s );
433                 }
434                 break;
435                 case PREF_WNDPOS:
436                 {
437                         CString str;
438                         WindowPosition_Write( *(window_position_t*)pPref->mVal, str );
439                         xmlNodeSetContent( pNode, (xmlChar*)str.GetBuffer() );
440                 }
441                 break;
442                 }
443         }
444 }
445
446 void CXMLPropertyBag::Clear(){
447         if ( !InUse() ) {
448                 return;
449         }
450
451         xmlFreeDoc( mpDoc );
452         mpDoc = NULL;
453         mpDocNode = NULL;
454         mbEmpty = false;
455 }
456
457 void CXMLPropertyBag::ReadXMLFile( const char* pFilename ){
458         mpDoc = xmlParseFile( pFilename );
459
460         // basic checks
461         if ( mpDoc ) {
462                 mpDocNode = mpDoc->children;
463                 xmlAttrPtr tmp_attr_ptr = xmlHasProp( mpDocNode, (xmlChar *)"version" );
464                 if ( strcmp( (char *)mpDocNode->name, "qpref" ) ) {
465                         Sys_FPrintf( SYS_ERR, "Unrecognized node '%s' in '%s'\n", mpDocNode->name, mpDoc->URL );
466                         xmlFreeDoc( mpDoc );
467                         mpDoc = NULL;
468                 }
469                 else if ( tmp_attr_ptr != NULL && strcmp( (char*)tmp_attr_ptr->children->content, "1" ) ) {
470                         Sys_FPrintf( SYS_ERR, "Wrong version '%s' in <qpref> node for '%s'\n", (char*)tmp_attr_ptr->children->content, mpDoc->URL );
471                         xmlFreeDoc( mpDoc );
472                         mpDoc = NULL;
473                 }
474                 Sys_Printf( "Opened XML property file: '%s'\n", pFilename );
475         }
476
477         if ( !mpDoc ) {
478                 mbEmpty = true;
479                 // no document, create one
480                 mpDoc = xmlNewDoc( (xmlChar *)"1.0" );
481                 mpDocNode = xmlNewDocNode( mpDoc, NULL, (xmlChar *)"qpref", NULL );
482                 xmlDocSetRootElement( mpDoc, mpDocNode );
483                 xmlSetProp( mpDocNode, (xmlChar *)"version", (xmlChar *)"1" );
484                 Sys_Printf( "XML property file '%s' invalid/not found, creating blank properties tree\n", pFilename );
485         }
486 }
487
488 qboolean CXMLPropertyBag::WriteXMLFile( const char* pFilename ){
489         int res = xmlSaveFormatFile( pFilename, mpDoc, 1 );
490
491         if ( res == -1 ) {
492                 return false;
493         }
494
495         Sys_Printf( "Wrote XML property file '%s'\n", pFilename );
496         return true;
497 }
498
499 // =============================================================================
500 // Widget callbacks for PrefsDlg
501
502 #if !defined( WIN32 )
503 // browse for custom editor executable
504 static void OnBtnBrowseEditor( GtkWidget *widget, gpointer data ){
505         PrefsDlg *dlg = (PrefsDlg*)data;
506
507         const char *filename = file_dialog( g_PrefsDlg.GetWidget(), TRUE, _( "Executable for Custom Editor" ) );
508
509         if ( filename != NULL ) {
510                 dlg->m_strEditorCommand = filename;
511                 dlg->UpdateData( FALSE );
512         }
513 }
514 #endif
515
516 static void OnBtnBrowseprefab( GtkWidget *widget, gpointer data ){
517         PrefsDlg *dlg = (PrefsDlg*)data;
518         char *path = dlg->m_strPrefabPath;
519         if ( strlen( path ) == 0 ) {
520                 path = g_strGameToolsPath;
521         }
522         char *dir = dir_dialog( g_PrefsDlg.GetWidget(), _( "Set prefab path" ), path );
523         dlg->UpdateData( TRUE );
524
525         if ( dir != NULL ) {
526                 CString strPath;
527                 strPath = dir;
528                 AddSlash( strPath );
529                 dlg->m_strPrefabPath = strPath;
530                 dlg->UpdateData( FALSE );
531                 free( dir );
532         }
533 }
534
535 static void OnBtnBrowseuserini( GtkWidget *widget, gpointer data ){
536         PrefsDlg *dlg = (PrefsDlg*)data;
537         char *path = dlg->m_strUserPath;
538         if ( strlen( path ) == 0 ) {
539                 path = g_strGameToolsPath;
540         }
541         // TODO: INI filter?
542         const char *filename = file_dialog( g_PrefsDlg.GetWidget(), TRUE, _( "Find INI file" ), path );
543
544         if ( filename != NULL ) {
545                 dlg->UpdateData( TRUE );
546                 dlg->m_strUserPath = filename;
547                 dlg->UpdateData( FALSE );
548         }
549 }
550
551 static void OnButtonClean( GtkWidget *widget, gpointer data ){
552         // make sure this is what the user wants
553         if ( gtk_MessageBox( g_PrefsDlg.GetWidget(), _( "This will close Radiant and clean the corresponding registry entries.\n"
554                                                                                                         "Next time you start Radiant it will be good as new. Do you wish to continue?" ),
555                                                  _( "Reset Registry" ), MB_YESNO ) == IDYES ) {
556                 PrefsDlg *dlg = (PrefsDlg*)data;
557                 dlg->EndModal( IDCANCEL );
558
559                 g_qeglobals.disable_ini = true;
560                 remove( dlg->m_inipath->str );
561                 char buf[PATH_MAX];
562                 sprintf( buf, "%sSavedInfo.bin", dlg->m_rc_path->str );
563                 remove( buf );
564                 HandleCommand( NULL, GINT_TO_POINTER( ID_FILE_EXIT ) );
565                 _exit( 0 );
566         }
567 }
568
569 // =============================================================================
570 // PrefsDlg class
571
572 // IMPORTANT NOTE: the values here don't matter very much
573 // the actual intialization if you start with an empty .ini is done when loading the prefs for the first time
574 // profile_load_int takes an argument to use if the value is not found
575 PrefsDlg::PrefsDlg (){
576         m_bWarn = TRUE;
577         m_nMouse = 1;
578         m_nView = MainFrame::eRegular;
579         m_bLoadLast = FALSE;
580         m_bInternalBSP = FALSE;
581         m_bRightClick = FALSE;
582         m_bSetGame = FALSE;
583         m_bAutoSave = TRUE;
584         m_nAutoSave = 5;
585         m_bLoadLastMap = FALSE;
586         m_bTextureWindow = FALSE;
587         m_bSnapShots = FALSE;
588         m_fTinySize = 0.5;
589         m_bCleanTiny = FALSE;
590         m_bCamXYUpdate = TRUE;
591         m_bCamDragMultiSelect = FALSE;
592         m_bCamFreeLook = TRUE;
593         m_bCamFreeLookStrafe = FALSE;
594         m_bCamInverseMouse = FALSE;
595         m_bCamDiscrete = TRUE;
596         m_bNewLightDraw = FALSE;
597         m_strPrefabPath = "";
598         m_nWhatGame = 0;
599         m_bALTEdge = FALSE;
600         m_bFaceColors = FALSE;
601         m_bXZVis = FALSE;
602         m_bYZVis = FALSE;
603         m_bZVis = FALSE;
604         m_bSizePaint = FALSE;
605         m_bDLLEntities = FALSE;
606 #ifdef _WIN32
607         m_bDetachableMenus = FALSE; // Most win32 users will find detachable menus annoying
608 #else
609         m_bDetachableMenus = TRUE;  // Linux/Apple users are used to them...
610 #endif
611         m_bPatchToolbar = TRUE;
612         m_bWideToolbar = TRUE;
613         m_bPluginToolbar = TRUE;
614         m_bNoClamp = FALSE;
615         m_bSnap = TRUE;
616         m_strUserPath = "";
617         m_nRotation = 0;
618         m_bChaseMouse = FALSE;
619         m_bTextureScrollbar = TRUE;
620         m_bDisplayLists = TRUE;
621         m_bAntialiasedPointsAndLines = FALSE; // Fishman - Add antialiazed points and lines support. 09/03/00
622         m_bShowShaders = FALSE;
623         m_nShader = -1;
624         m_bNoStipple = FALSE;
625         m_bVertexSplit = FALSE;
626         m_bSelectCurves = TRUE;
627         m_bSelectModels = TRUE;
628         m_nEntityShowState = ENTITY_SKINNED_BOXED;
629         m_nTextureScale = 2;
630         m_bSwitchClip = FALSE;
631         m_bSelectWholeEntities = TRUE;
632         m_nTextureQuality = 3;
633         m_bShowShaders = TRUE;
634         m_bGLLighting = FALSE;
635         m_nShader = 0;
636         m_nUndoLevels = 30;
637         m_bTexturesShaderlistOnly = FALSE;
638         // paths to ini files
639         m_rc_path = NULL;
640         m_inipath = NULL;
641         m_bWatchBSP = TRUE;
642         m_bLeakStop = TRUE;
643         m_iTimeout = 15;
644         m_bRunQuake = TRUE;
645         m_bDoSleep = FALSE;
646         m_nSubdivisions = 4;
647         // not prefs
648         m_bFloatingZ = FALSE;
649         m_bGlPtWorkaround = FALSE;  // Gef: Kyro/GL_POINTS workaround 25-aug-2001
650 #ifdef _WIN32
651         m_bNativeGUI = FALSE;
652         m_bStartOnPrimMon = FALSE;
653 #endif
654         m_global_rc_path = NULL;
655 #ifdef _WIN32
656         m_bUseWin32Editor = TRUE;
657 #else
658         // custom shader editor options
659         m_bUseCustomEditor = FALSE;
660         m_strEditorCommand = "";
661 #endif
662         m_nLightRadiuses = 1;
663         m_bQ3Map2Texturing = TRUE;
664 #ifdef ATIHACK_812
665         m_bGlATIHack = FALSE;
666 #endif
667 #ifdef NVIDIA_AERO_HACK
668         m_bGlNvidiaAeroHack = TRUE;
669         m_bGlNvidiaAeroHackPrevState = -1; // -1 is uninitialized, 0 is FALSE, 1 is TRUE
670 #endif
671 }
672
673 /*!
674    =========================================================
675    Games selection dialog
676    =========================================================
677  */
678
679 #if defined( WIN32 )
680 #define TOOLS_ATTRIBUTE "gametools_win32"
681 #define ENGINE_ATTRIBUTE "engine_win32"
682 #define ENGINEPATH_ATTRIBUTE "enginepath_win32"
683 #define MP_ENGINE_ATTRIBUTE "mp_engine_win32"
684 #elif defined( __linux__ ) || defined ( __FreeBSD__ )
685 #define TOOLS_ATTRIBUTE "gametools_linux"
686 #define ENGINE_ATTRIBUTE "engine_linux"
687 #define ENGINEPATH_ATTRIBUTE "enginepath_linux"
688 #define MP_ENGINE_ATTRIBUTE "mp_engine_linux"
689 #elif defined( __APPLE__ )
690 #define TOOLS_ATTRIBUTE "gametools_macos"
691 #define ENGINE_ATTRIBUTE "engine_macos"
692 #define ENGINEPATH_ATTRIBUTE "enginepath_macos"
693 #define MP_ENGINE_ATTRIBUTE "mp_engine_macos"
694 #else
695 #error "unsupported platform"
696 #endif
697
698 CGameDescription::CGameDescription( xmlDocPtr pDoc, const Str &GameFile ){
699         char *p, *prop;
700         mpDoc = pDoc;
701         // read the user-friendly game name
702         xmlNodePtr pNode = mpDoc->children;
703
704         while ( strcmp( (const char*)pNode->name, "game" ) && pNode != NULL ) pNode = pNode->next;
705         if ( !pNode ) {
706                 ///< \todo add the file name (this node and gametools should all be part of CGameDescription anyway)
707                 Error( "Didn't find 'game' node in the game description file '%s'\n", pDoc->URL );
708         }
709         // on win32, game tools path can now be specified relative to the exe's cwd
710         prop = (char*)xmlGetProp( pNode, (xmlChar*)TOOLS_ATTRIBUTE );
711         if ( prop == NULL ) {
712                 Error( "Didn't find '"TOOLS_ATTRIBUTE "' node in the game description file '%s'\n", pDoc->URL );
713         }
714         {
715                 char full[PATH_MAX];
716 #ifdef _WIN32
717                 _fullpath( full, prop, PATH_MAX );
718 #else
719                 strncpy( full, prop, PATH_MAX );
720 #endif
721                 xmlFree( prop );
722                 prop = NULL;
723                 for ( p = full; *p != '\0'; p++ ) {
724                         if ( *p == '\\' ) {
725                                 *p = '/';
726                         }
727                         mGameToolsPath = full;
728                         if ( p != full && *( p - 1 ) != '/' ) {
729                                 mGameToolsPath += "/";
730                         }
731                 }
732         }
733
734         prop = (char*)xmlGetProp( pNode, (xmlChar*)"name" );
735         if ( prop == NULL ) {
736                 Sys_FPrintf( SYS_WRN, "Warning, 'name' attribute not found in '%s'\n", pDoc->URL );
737                 mGameName = pDoc->URL;
738         }
739         else
740         {
741                 mGameName = prop;
742                 xmlFree( prop );
743         }
744
745         mGameFile = GameFile;
746
747         prop = (char*)xmlGetProp( pNode, (xmlChar*)"quake2" );
748         if ( prop == NULL ) {
749                 // default
750                 quake2 = false;
751         }
752         else
753         {
754                 quake2 = true;
755                 xmlFree( prop );
756         }
757
758         // if this is set, the open maps dialoge will open the engine path not the
759         // home dir for map loading and saving
760         prop = (char*)xmlGetProp( pNode, (xmlChar*)"no_maps_in_home" );
761         if ( prop == NULL ) {
762                 // default
763                 noMapsInHome = false;
764         }
765         else
766         {
767                 noMapsInHome = true;
768                 xmlFree( prop );
769         }
770
771         prop = (char*)xmlGetProp( pNode, (xmlChar*)"basegame" );
772         if ( prop == NULL ) {
773                 // default
774                 mBaseGame = "baseq3";
775         }
776         else
777         {
778                 mBaseGame = prop;
779                 xmlFree( prop );
780         }
781
782
783         prop = (char*)xmlGetProp( pNode, (const xmlChar*)ENGINE_ATTRIBUTE );
784         if ( prop == NULL ) {
785 #ifdef _WIN32
786                 mEngine = "quake3.exe";
787 #elif __linux__
788                 mEngine = "quake3";
789 #elif __APPLE__
790                 mEngine = "Quake3.app";
791 #endif
792         }
793         else
794         {
795                 mEngine = prop;
796                 xmlFree( prop );
797         }
798
799         prop = (char*)xmlGetProp( pNode, (const xmlChar*)MP_ENGINE_ATTRIBUTE );
800         if ( prop == NULL ) {
801 #ifdef _WIN32
802                 mMultiplayerEngine = "quake3.exe";
803 #elif __linux__
804                 mMultiplayerEngine = "quake3";
805 #elif __APPLE__
806                 mMultiplayerEngine = "Quake3.app";
807 #endif
808         }
809         else
810         {
811                 mMultiplayerEngine = prop;
812                 xmlFree( prop );
813         }
814
815         {
816                 // on win32, engine path can now be specified relative to the exe's cwd
817                 prop = (char*)xmlGetProp( pNode, (const xmlChar *)ENGINEPATH_ATTRIBUTE );
818                 if ( prop != NULL ) {
819                         char full[PATH_MAX];
820                 #ifdef _WIN32
821                         _fullpath( full, prop, PATH_MAX );
822                 #else
823                         strncpy( full, prop, PATH_MAX );
824                 #endif
825                         xmlFree( prop );
826                         prop = NULL;
827                         // process seperators
828                         for ( p = full; *p != '\0'; p++ ) {
829                                 if ( *p == '\\' ) {
830                                         *p = '/';
831                                 }
832                         }
833                         mEnginePath = full;
834                         if ( p != full && *( p - 1 ) != '/' ) {
835                                 mEnginePath += "/";
836                         }
837                 }
838                 else
839                 {
840                         // if engine path was not specified in the .game, it implies we can guess it from the gametools path
841                         // on win32, and for most game package, the gametools are installed with the game
842                         char aux_path[PATH_MAX]; // aux
843                         strcpy( aux_path, mGameToolsPath.GetBuffer() );
844                         if ( ( aux_path[ strlen( aux_path ) - 1 ] == '/' ) || ( aux_path[ strlen( aux_path ) - 1 ] == '\\' ) ) {
845                                 aux_path[strlen( aux_path ) - 1] = '\0'; // strip ending '/' if any
846                         }
847                         char up_path[PATH_MAX]; // up one level
848                         ExtractFilePath( aux_path, up_path );
849                         mEnginePath = up_path;
850                 }
851         }
852
853 #if defined ( __linux__ ) || defined ( __APPLE__ )
854         // *nix specific
855         prop = (char*)xmlGetProp( pNode, (const xmlChar *)"prefix" );
856         if ( prop != NULL ) {
857                 mUserPathPrefix = prop;
858                 xmlFree( prop );
859         }
860 #endif
861         mShaderPath = xmlGetProp( pNode, (const xmlChar *)"shaderpath" );
862         if ( !mShaderPath.GetLength() ) {
863                 mShaderPath = "scripts/";
864                 mShaderlist = "scripts/shaderlist.txt";
865         }
866         else
867         {
868                 AddSlash( mShaderPath );
869                 mShaderlist = mShaderPath;
870                 mShaderlist += "shaderlist.txt";
871         }
872         xmlChar* default_scale = xmlGetProp( pNode, (const xmlChar *)"default_scale" );
873         if ( default_scale ) {
874                 mTextureDefaultScale = atof( (const char *)default_scale );
875                 xmlFree( default_scale );
876         }
877         else{
878                 mTextureDefaultScale = 0.5f;
879         }
880         xmlChar* eclass_singleload = xmlGetProp( pNode, (const xmlChar*)"eclass_singleload" );
881         if ( eclass_singleload ) {
882                 mEClassSingleLoad = true;
883                 xmlFree( eclass_singleload );
884         }
885         else{
886                 mEClassSingleLoad = false;
887         }
888         xmlChar* no_patch = xmlGetProp( pNode, (const xmlChar *)"no_patch" );
889         if ( no_patch ) {
890                 mNoPatch = true;
891                 xmlFree( no_patch );
892         }
893         else{
894                 mNoPatch = false;
895         }
896         xmlChar* caulk_shader = xmlGetProp( pNode, (const xmlChar *)"caulk_shader" );
897         if ( caulk_shader ) {
898                 mCaulkShader = caulk_shader;
899                 xmlFree( caulk_shader );
900         }
901         else{
902                 mCaulkShader = "textures/common/caulk";
903         }
904 }
905
906 void CGameDescription::Dump(){
907 #ifdef _WIN32
908         if ( CGameDialog::GetNetrun() ) {
909                 Sys_Printf( "Running in network mode, prefs path set to '%s'\n", g_strTempPath.GetBuffer() );
910         }
911 #endif
912         Sys_Printf( "game name            : '%s'\n", mGameName.GetBuffer() );
913         Sys_Printf( "game file            : '%s'\n", mGameFile.GetBuffer() );
914         Sys_Printf( "game path            : '%s'\n", mGameToolsPath.GetBuffer() );
915         Sys_Printf( "base game            : '%s'\n", mBaseGame.GetBuffer() );
916         Sys_Printf( "engine path          : '%s'\n", mEnginePath.GetBuffer() );
917         Sys_Printf( "engine               : '%s'\n", mEngine.GetBuffer() );
918         Sys_Printf( "shaderlist           : '%s'\n", mShaderlist.GetBuffer() );
919         Sys_Printf( "caulk shader: '%s'\n", mCaulkShader.GetBuffer() );
920 #if defined ( __linux__ ) || defined ( __APPLE__ )
921         Sys_Printf( "prefix               : '%s'\n", mUserPathPrefix.GetBuffer() );
922 #endif
923         Sys_Printf( "default texture scale: %g\n", mTextureDefaultScale );
924         Sys_Printf( "single eclass load   : %s\n", mEClassSingleLoad ? "Yes" : "No" );
925         Sys_Printf( "patches supported    : %s\n", mNoPatch ? "No" : "Yes" );
926 }
927
928 CPrefAssignment& CPrefAssignment::operator =( const CPrefAssignment& ass ){
929         if ( &ass != this ) {
930                 mName = ass.mName;
931                 mType = ass.mType;
932                 mVal = ass.mVal;
933         }
934         return *this;
935 }
936
937 CPrefAssignment::CPrefAssignment( const CPrefAssignment& ass ){
938         *this = ass;
939 }
940
941 void CGameDialog::LoadPrefs(){
942         // if we already have a document loaded, we will free and reload from file
943         if ( mGlobalPrefs.InUse() ) {
944                 Sys_Printf( "Reloading global prefs from file\n" );
945                 mGlobalPrefs.Clear();
946         }
947
948         // load global .pref file
949         CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str;
950         strGlobalPref += "global.pref";
951
952         mGlobalPrefs.ReadXMLFile( strGlobalPref.GetBuffer() );
953
954         mGlobalPrefs.GetPref( "gamefile", &m_sGameFile, "" ); // NOTE: there's no default, user HAS to select something
955         mGlobalPrefs.GetPref( "autoload", &m_bAutoLoadGame, false );
956         mGlobalPrefs.GetPref( "log console", &m_bLogConsole, false );
957         // in a very particular post-.pid startup
958         // we may have the console turned on and want to keep it that way
959         // so we use a latching system
960         if ( m_bForceLogConsole ) {
961                 m_bLogConsole = true;
962                 Sys_Printf( "console logging has been latched on, saving prefs\n" );
963                 SavePrefs();
964                 m_bForceLogConsole = false;
965         }
966
967         // console logging: call Sys_LogConsole to check console logging status
968         // it is important that we would log console as early as possible to make it useful
969         Sys_LogFile();
970
971         if ( mGlobalPrefs.mbEmpty ) {
972                 Sys_Printf( "Saving global.pref with default pref values\n" );
973                 SavePrefs();
974         }
975 }
976
977 void CGameDialog::SavePrefs(){
978         // update the tree and save it
979         mGlobalPrefs.UpdatePrefTree();
980
981         CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str;
982         strGlobalPref += "global.pref";
983
984         if ( !mGlobalPrefs.WriteXMLFile( strGlobalPref.GetBuffer() ) ) {
985                 Sys_FPrintf( SYS_ERR, "Error occured while saving global prefs file '%s'\n", strGlobalPref.GetBuffer() );
986         }
987 }
988
989 void CGameDialog::DoGameInstall() {
990         // make sure console logging is on whenever we enter the installation loop
991         g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
992         Sys_LogFile();
993         mGameInstall.Run();
994 }
995
996 void CGameDialog::DoGameDialog() {
997         // allow looping the game selection dialog with calls to the game configure dialog in between
998         while ( m_bDoGameInstall ) {
999
1000                 m_bDoGameInstall = false;
1001
1002                 if ( DoModal() == IDCANCEL ) {
1003                         Error( "game selection dialog canceled, cannot continue" );
1004                         return;
1005                 }
1006
1007                 if ( m_bDoGameInstall ) {
1008                         DoGameInstall();
1009                         ScanForGames();
1010                         // and we will loop to do another DoModal dialog
1011                 }
1012         }
1013
1014         // unhook so we can use in other places
1015         // we manually incref'ed it when creating, it won't be freed (destructor)
1016         gtk_container_remove( GTK_CONTAINER( mTopBox ), GetGlobalFrame() );
1017
1018         // we save the prefs file
1019         SavePrefs();
1020 }
1021
1022 GtkWidget* CGameDialog::GetGlobalFrame(){
1023         GtkWidget *vbox, *text, *combo, *check;
1024
1025         if ( mFrame != NULL ) {
1026                 return mFrame;
1027         }
1028
1029         mFrame = gtk_frame_new( NULL );
1030         gtk_container_set_border_width( GTK_CONTAINER( mFrame ), 5 );
1031         gtk_widget_show( mFrame );
1032
1033         vbox = gtk_vbox_new( FALSE, 6 );
1034         gtk_widget_show( vbox );
1035         gtk_container_add( GTK_CONTAINER( mFrame ), vbox );
1036         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1037
1038         text = gtk_label_new( _( "Select the game:" ) );
1039         gtk_widget_show( text );
1040         gtk_box_pack_start( GTK_BOX( vbox ), text, FALSE, FALSE, 0 );
1041
1042         combo = gtk_combo_box_new_text();
1043         gtk_widget_show( combo );
1044         gtk_box_pack_start( GTK_BOX( vbox ), combo, FALSE, FALSE, 0 );
1045         AddDialogData( combo, &m_nComboSelect, DLG_COMBO_BOX_INT );
1046         mGameCombo = GTK_COMBO_BOX( combo );
1047
1048         UpdateGameCombo();
1049
1050         check = gtk_check_button_new_with_label( _( "Auto load selected game on startup" ) );
1051         gtk_widget_show( check );
1052         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1053         AddDialogData( check, &m_bAutoLoadGame, DLG_CHECK_BOOL );
1054
1055         text = gtk_label_new( _( "(this frame is available in the prefs menu if you set auto-select)" ) );
1056         gtk_widget_show( text );
1057         gtk_box_pack_start( GTK_BOX( vbox ), text, FALSE, FALSE, 0 );
1058
1059 #ifdef _WIN32
1060         check = gtk_check_button_new_with_label( _( "Networked install - per-user settings" ) );
1061         gtk_widget_show( check );
1062         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1063         AddDialogData( check, &m_bNetRun, DLG_CHECK_BOOL );
1064 #endif
1065
1066         check = gtk_check_button_new_with_label( _( "Log the console to radiant.log" ) );
1067         gtk_widget_show( check );
1068         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1069         AddDialogData( check, &m_bLogConsole, DLG_CHECK_BOOL );
1070
1071         // incref it so we can pass it around
1072         gtk_widget_ref( GTK_WIDGET( mFrame ) );
1073
1074         return mFrame;
1075 }
1076
1077 void CGameDialog::UpdateData( bool retrieve ) {
1078         if ( !retrieve ) {
1079                 // use m_sGameFile to set m_nComboSelect
1080                 list<CGameDescription *>::iterator iGame;
1081                 int i = 0;
1082                 for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ )
1083                 {
1084                         if ( ( *iGame )->mGameFile == m_sGameFile ) {
1085                                 m_nComboSelect = i;
1086                                 break;
1087                         }
1088                         i++;
1089                 }
1090 #ifdef _WIN32
1091                 UpdateNetrun( false );
1092 #endif
1093         }
1094         Dialog::UpdateData( retrieve );
1095         if ( retrieve ) {
1096                 // use m_nComboSelect to set m_sGameFile
1097                 list<CGameDescription *>::iterator iGame = mGames.begin();
1098                 int i;
1099                 for ( i = 0; i < m_nComboSelect; i++ )
1100                 {
1101                         iGame++;
1102                 }
1103                 m_sGameFile = ( *iGame )->mGameFile;
1104 #ifdef _WIN32
1105                 UpdateNetrun( true );
1106 #endif
1107         }
1108 }
1109
1110 void CGameDialog::SInstallCallback( GtkWidget *widget, gpointer data ) {
1111         CGameDialog *d = static_cast< CGameDialog* >( data );
1112         d->m_bDoGameInstall = true;
1113         d->EndModal( 0 );
1114 }
1115
1116 void CGameDialog::BuildDialog() {
1117         GtkWidget *dlg, *vbox1, *button, *setup_button;
1118
1119         dlg = m_pWidget;
1120         gtk_window_set_title( GTK_WINDOW( dlg ), _( "Select Game" ) );
1121
1122         vbox1 = gtk_vbox_new( FALSE, 0 );
1123         gtk_widget_show( vbox1 );
1124         gtk_container_add( GTK_CONTAINER( dlg ), vbox1 );
1125
1126         gtk_container_add( GTK_CONTAINER( vbox1 ), GetGlobalFrame() );
1127         mTopBox = vbox1;
1128
1129         setup_button = gtk_button_new_with_label( _( "Configure more games" ) );
1130         gtk_widget_show( setup_button );
1131         gtk_box_pack_start( GTK_BOX( vbox1 ), setup_button, FALSE, FALSE, 0 );
1132         gtk_signal_connect( GTK_OBJECT( setup_button ), "clicked",
1133                                                 GTK_SIGNAL_FUNC( SInstallCallback ), this );
1134
1135         button = gtk_button_new_with_label( _( "OK" ) );
1136         gtk_widget_show( button );
1137         gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
1138         AddModalButton( button, IDOK );
1139
1140         button = gtk_button_new_with_label( _( "Cancel" ) );
1141         gtk_widget_show( button );
1142         gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
1143         AddModalButton( button, IDCANCEL );
1144
1145         gtk_widget_set_usize( button, 60, -2 );
1146 }
1147
1148 void CGameDialog::UpdateGameCombo() {
1149         // fill in with the game descriptions
1150         list<CGameDescription *>::iterator iGame;
1151
1152         if ( mGameCombo == NULL ) {
1153                 Sys_Printf( "mGameCombo == NULL\n" );
1154                 return;
1155         }
1156
1157         // clear whatever is in - wtf no way to know how many text entries?
1158         // use set/get active to track
1159         gtk_combo_box_set_active( mGameCombo, 0 );
1160         while ( gtk_combo_box_get_active( mGameCombo ) == 0 ) {
1161                 gtk_combo_box_remove_text( mGameCombo, 0 );
1162                 gtk_combo_box_set_active( mGameCombo, 0 );
1163         }
1164
1165         for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) {
1166                 gtk_combo_box_append_text( mGameCombo, ( *iGame )->mGameName.GetBuffer() );
1167         }
1168         gtk_combo_box_set_active( mGameCombo, 0 );
1169 }
1170
1171 void CGameDialog::ScanForGames(){
1172         CString strPath;
1173         char *dirlist;
1174         GDir *dir;
1175         CString strGamesPath = g_strAppPath.GetBuffer();
1176         strGamesPath += "games";
1177         const char *path = strGamesPath.GetBuffer();
1178
1179         if ( !mGames.empty() ) {
1180                 Sys_Printf( "Clearing game list\n" );
1181                 list<CGameDescription*>::iterator iGame;
1182                 for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ ) {
1183                         delete ( *iGame );
1184                 }
1185                 mGames.clear();
1186         }
1187
1188         Sys_Printf( "Scanning for game description files: %s\n", path );
1189
1190         /*!
1191            \todo FIXME LINUX:
1192            do we put game description files below g_strAppPath, or in ~/.radiant
1193            i.e. read only or read/write?
1194            my guess .. readonly cause it's an install
1195            we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
1196            (if that's really needed)
1197          */
1198
1199         // FIXME need to catch the 'no game description' situation and exit with a clean error
1200
1201         dir = g_dir_open( path, 0, NULL );
1202
1203         if ( dir != NULL ) {
1204                 while ( 1 )
1205                 {
1206                         const gchar* name = g_dir_read_name( dir );
1207                         if ( name == NULL ) {
1208                                 break;
1209                         }
1210
1211                         dirlist = g_strdup( name );
1212 #ifdef _WIN32
1213                         strlwr( dirlist );
1214 #endif
1215                         char *ext = strrchr( dirlist, '.' );
1216                         if ( ( ext == NULL ) || ( strcmp( ext, ".game" ) != 0 ) ) {
1217                                 continue;
1218                         }
1219                         strPath.Format( "%s/%s", path, dirlist );
1220                         Sys_Printf( "%s\n", strPath.GetBuffer() );
1221                         // got one, load it
1222                         xmlDocPtr pDoc = xmlParseFile( strPath.GetBuffer() );
1223                         if ( pDoc ) {
1224                                 mGames.push_front( new CGameDescription( pDoc, dirlist ) );
1225                         }
1226                         else
1227                         {
1228                                 Sys_FPrintf( SYS_ERR, "XML parser failed on '%s'\n", strPath.GetBuffer() );
1229                         }
1230
1231                         g_free( dirlist );
1232                 }
1233                 g_dir_close( dir );
1234         }
1235
1236         // entries in the combo need to be updated
1237         UpdateGameCombo();
1238 }
1239
1240 CGameDescription* CGameDialog::GameDescriptionForComboItem(){
1241         list<CGameDescription *>::iterator iGame;
1242         int i = 0;
1243         for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++,i++ ) {
1244                 if ( i == m_nComboSelect ) {
1245                         return ( *iGame );
1246                 }
1247         }
1248         return NULL; // not found
1249 }
1250
1251 void CGameDialog::InitGlobalPrefPath(){
1252         GString *global_rc_path;
1253         // configure m_global_rc_path
1254         // this is the g_strTempPath, and it has already been mkdir'ed
1255         global_rc_path = g_string_new( g_strTempPath.GetBuffer() );
1256         g_PrefsDlg.m_global_rc_path = global_rc_path;
1257 }
1258
1259 void CGameDialog::Reset(){
1260         if ( !g_PrefsDlg.m_global_rc_path ) {
1261                 InitGlobalPrefPath();
1262         }
1263         CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str;
1264         strGlobalPref += "global.pref";
1265         remove( strGlobalPref.GetBuffer() );
1266 }
1267
1268 void CGameDialog::Init(){
1269         InitGlobalPrefPath();
1270         ScanForGames();
1271         if ( mGames.empty() ) {
1272                 DoGameInstall();
1273                 ScanForGames();
1274                 if ( mGames.empty() ) {
1275                         Error( "No games setup, aborting\n" );
1276                 }
1277         }
1278         LoadPrefs();
1279         if ( m_bAutoLoadGame ) {
1280                 // search by .game name
1281                 list<CGameDescription *>::iterator iGame;
1282                 for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ )
1283                 {
1284                         if ( ( *iGame )->mGameFile == m_sGameFile ) {
1285                                 m_pCurrentGameDescription = ( *iGame );
1286                                 break;
1287                         }
1288                 }
1289         }
1290         if ( !m_bAutoLoadGame || !m_pCurrentGameDescription ) {
1291                 DoGameDialog();
1292                 // use m_nComboSelect to identify the game to run as and set the globals
1293                 m_pCurrentGameDescription = GameDescriptionForComboItem();
1294                 if ( !m_pCurrentGameDescription ) {
1295                         Error( "Lookup of game description object failed, can't continue\n" );
1296                 }
1297         }
1298         g_pGameDescription = m_pCurrentGameDescription;
1299
1300         g_strGameToolsPath = g_pGameDescription->mGameToolsPath;
1301
1302         // NOTE TTimo: this is moved from QE_LoadProject in 1.2
1303         // (probably broken)
1304         // NOTE Hydra: was broken for win32, we don't use m_strHomeGame or m_strFSBasePath
1305 #if defined ( __linux__ ) || defined ( __APPLE__ )
1306         g_qeglobals.m_strHomeGame = g_get_home_dir();
1307         g_qeglobals.m_strHomeGame += "/";
1308         g_qeglobals.m_strHomeGame += m_pCurrentGameDescription->mUserPathPrefix.GetBuffer();
1309         g_qeglobals.m_strHomeGame += "/";
1310 #else
1311         g_qeglobals.m_strHomeGame = g_pGameDescription->mEnginePath.GetBuffer();
1312 #endif
1313
1314         g_pGameDescription->Dump();
1315 }
1316
1317 CGameDialog::~CGameDialog(){
1318         if ( mFrame ) {
1319                 // NOTE I'm not too sure how reliable this is
1320                 gtk_widget_unref( GTK_WIDGET( mFrame ) );
1321         }
1322         // free all the game descriptions
1323         list<CGameDescription *>::iterator iGame;
1324         for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ )
1325         {
1326                 delete ( *iGame );
1327                 *iGame = NULL;
1328         }
1329 }
1330
1331 void CGameDialog::AddPacksURL( Str &URL ){
1332         // add the URLs for the list of game packs installed
1333         // FIXME: this is kinda hardcoded for now..
1334         list<CGameDescription *>::iterator iGame;
1335         for ( iGame = mGames.begin(); iGame != mGames.end(); iGame++ )
1336         {
1337                 if ( ( *iGame )->mGameFile == "q3.game" ) {
1338                         URL += "&Games_dlup%5B%5D=1";
1339                 }
1340                 else if ( ( *iGame )->mGameFile == "wolf.game" ) {
1341                         URL += "&Games_dlup%5B%5D=2";
1342                 }
1343                 // FIXME: double entry
1344                 else if ( ( *iGame )->mGameFile == "wolf.game" ) {
1345                         URL += "&Games_dlup%5B%5D=3";
1346                 }
1347                 else if ( ( *iGame )->mGameFile == "jk2.game" ) {
1348                         URL += "&Games_dlup%5B%5D=4";
1349                 }
1350                 else if ( ( *iGame )->mGameFile == "stvef.game" ) {
1351                         URL += "&Games_dlup%5B%5D=5";
1352                 }
1353                 else if ( ( *iGame )->mGameFile == "sof2.game" ) {
1354                         URL += "&Games_dlup%5B%5D=6";
1355                 }
1356                 else if ( ( *iGame )->mGameFile == "ja.game" ) {
1357                         URL += "&Games_dlup%5B%5D=7";
1358                 }
1359         }
1360 }
1361
1362 #ifdef _WIN32
1363
1364 #define NETRUN_FILENAME "netrun.conf"
1365
1366 bool CGameDialog::m_bNetRun;
1367
1368 void CGameDialog::UpdateNetrun( bool retrieve ){
1369         FILE *f_netrun;
1370         CString strNetrun;
1371         strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME;
1372         if ( !retrieve ) {
1373                 // now check if we are running from a network installation
1374                 // use a dummy file as the flag
1375                 f_netrun = fopen( strNetrun.GetBuffer(), "r" );
1376                 if ( f_netrun ) {
1377                         fclose( f_netrun );
1378                         m_bNetRun = true;
1379                 }
1380                 else{
1381                         m_bNetRun = false;
1382                 }
1383         }
1384         else
1385         {
1386                 if ( m_bNetRun ) {
1387                         f_netrun = fopen( strNetrun.GetBuffer(), "w" );
1388                         if ( !f_netrun ) {
1389                                 Sys_FPrintf( SYS_ERR, "ERROR: Failed to create netrun file '%s'\n", strNetrun.GetBuffer() );
1390                                 m_bNetRun = false;
1391                         }
1392                         else
1393                         {
1394                                 fclose( f_netrun );
1395                                 Sys_Printf( "Created/Checked '%s'\n", strNetrun.GetBuffer() );
1396                         }
1397                 }
1398                 else
1399                 {
1400                         if ( remove( strNetrun.GetBuffer() ) == -1 ) {
1401                                 if ( errno != ENOENT ) {
1402                                         Sys_FPrintf( SYS_ERR, "Failed to remove netrun file '%s'\n", strNetrun.GetBuffer() );
1403                                 }
1404                                 m_bNetRun = true;
1405                         }
1406                         else
1407                         {
1408                                 Sys_Printf( "Netrun mode is disabled\n" );
1409                         }
1410                 }
1411         }
1412 }
1413
1414 bool CGameDialog::GetNetrun(){
1415         return m_bNetRun;
1416 }
1417 #endif
1418
1419 /*
1420    ========
1421
1422    very first prefs init deals with selecting the game and the game tools path
1423    then we can load .ini stuff
1424
1425    using prefs / ini settings:
1426    those are per-game
1427
1428    win32:
1429    look in g_strGameToolsPath for .ini
1430
1431    linux:
1432    look in ~/.radiant/<version>/gamename
1433    ========
1434  */
1435
1436 #define PREFS_LOCAL_FILENAME "local.pref"
1437
1438 void PrefsDlg::Init(){
1439         mGamesDialog.Init();
1440
1441         // m_global_rc_path has been set above, do m_rc_path with game specific stuff now
1442         // the win32 and linux versions have been unified for network mode
1443 #ifdef _WIN32
1444         if ( !CGameDialog::GetNetrun() ) {
1445                 // legacy prefs settings, this goes where the game pack is installed
1446                 m_rc_path = g_string_new( g_strGameToolsPath.GetBuffer() );
1447                 m_inipath = g_string_new( m_rc_path->str );
1448                 g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
1449                 return;
1450         }
1451 #endif
1452         // this is common to win32 and Linux init now
1453         m_rc_path = g_string_new( m_global_rc_path->str );
1454
1455         // game sub-dir
1456         g_string_append( m_rc_path, g_pGameDescription->mGameFile.GetBuffer() );
1457         g_string_append( m_rc_path, "/" );
1458         Q_mkdir( m_rc_path->str, 0775 );
1459
1460         // then the ini file
1461         m_inipath = g_string_new( m_rc_path->str );
1462         g_string_append( m_inipath, PREFS_LOCAL_FILENAME );
1463
1464 }
1465
1466 void PrefsDlg::UpdateData( bool retrieve ){
1467         // leo: the "changed" signal confuses the update function
1468         if ( m_pWidget == NULL ) {
1469                 return;
1470         }
1471         mGamesDialog.UpdateData( retrieve );
1472         Dialog::UpdateData( retrieve );
1473 }
1474
1475 #ifdef _WIN32
1476 #define PREFSHSPACE 5
1477 #else
1478 #define PREFSHSPACE 0
1479 #endif
1480
1481 static void UpdateSensitivity( GtkWidget *widget, gpointer data ){
1482         PrefsDlg *dlg = (PrefsDlg*)data;
1483         dlg->DoSensitivity();
1484 }
1485
1486 static void UpdateEditorSensitivity( GtkWidget *widget, gpointer data ){
1487         PrefsDlg *dlg = (PrefsDlg*)data;
1488         dlg->DoEditorSensitivity();
1489 }
1490
1491 // start new prefs dialog
1492
1493 /*! Utility function for swapping notebook pages for tree list selections */
1494 void PrefsDlg::showPrefPage( int prefpage ){
1495         if ( gtk_notebook_get_current_page( GTK_NOTEBOOK( notebook ) ) != prefpage ) {
1496                 gtk_notebook_set_page( GTK_NOTEBOOK( notebook ), prefpage );
1497         }
1498
1499         return;
1500 }
1501
1502 static void treeSelection( GtkTreeSelection* selection, gpointer data ){
1503         PrefsDlg *dlg = (PrefsDlg*)data;
1504
1505         GtkTreeModel* model;
1506         GtkTreeIter selected;
1507         if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
1508                 int prefpage;
1509                 gtk_tree_model_get( model, &selected, 1, (gpointer*)&prefpage, -1 );
1510                 dlg->showPrefPage( prefpage );
1511         }
1512 }
1513
1514 void PrefsDlg::BuildDialog(){
1515         // Main Preferences dialog
1516         GtkWidget *dialog, *mainvbox, *hbox, *sc_win, *preflabel;
1517
1518         // Widgets on notebook pages
1519         GtkWidget *check, *label, *scale, *hbox2, *combo,
1520         *table, *spin,  *entry, *pixmap,
1521         *radio, *button, *pageframe, *vbox;
1522
1523         GList *combo_list = (GList*)NULL;
1524
1525         GtkObject *adj;
1526
1527         dialog = m_pWidget;
1528         gtk_window_set_title( GTK_WINDOW( dialog ), _( "GtkRadiant Preferences" ) );
1529         gtk_widget_realize( dialog );
1530
1531         mainvbox = gtk_vbox_new( FALSE, 5 );
1532         gtk_container_add( GTK_CONTAINER( dialog ), mainvbox );
1533         gtk_container_set_border_width( GTK_CONTAINER( mainvbox ), 5 );
1534         gtk_widget_show( mainvbox );
1535
1536         hbox = gtk_hbox_new( FALSE, 5 );
1537         gtk_widget_show( hbox );
1538         gtk_box_pack_end( GTK_BOX( mainvbox ), hbox, FALSE, TRUE, 0 );
1539
1540         button = gtk_button_new_with_label( _( "OK" ) );
1541         gtk_widget_show( button );
1542         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
1543         gtk_widget_set_usize( button, 60, -2 );
1544         AddModalButton( button, IDOK );
1545
1546         button = gtk_button_new_with_label( _( "Cancel" ) );
1547         gtk_widget_show( button );
1548         gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
1549         gtk_widget_set_usize( button, 60, -2 );
1550         AddModalButton( button, IDCANCEL );
1551
1552         button = gtk_button_new_with_label( _( "Clean" ) );
1553         gtk_widget_show( button );
1554         gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnButtonClean ), this );
1555         gtk_box_pack_start( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
1556         gtk_widget_set_usize( button, 60, -2 );
1557
1558         hbox = gtk_hbox_new( FALSE, 5 );
1559         gtk_box_pack_start( GTK_BOX( mainvbox ), hbox, TRUE, TRUE, 0 );
1560         gtk_widget_show( hbox );
1561
1562         sc_win = gtk_scrolled_window_new( NULL, NULL );
1563         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_win ), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
1564         gtk_box_pack_start( GTK_BOX( hbox ), sc_win, FALSE, FALSE, 0 );
1565         gtk_widget_show( sc_win );
1566
1567         // prefs pages notebook
1568         notebook = gtk_notebook_new();
1569         // hide the notebook tabs since its not supposed to look like a notebook
1570         gtk_notebook_set_show_tabs( GTK_NOTEBOOK( notebook ), FALSE );
1571         gtk_box_pack_start( GTK_BOX( hbox ), notebook, TRUE, TRUE, 0 );
1572         gtk_widget_show( notebook );
1573
1574         gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_win ), GTK_SHADOW_IN );
1575
1576         {
1577                 GtkTreeStore* store = gtk_tree_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER );
1578
1579                 GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) );
1580                 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE );
1581
1582                 {
1583                         GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
1584                         GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( _( "Preferences" ), renderer, "text", 0, NULL );
1585                         gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
1586                 }
1587
1588                 {
1589                         GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
1590                         g_signal_connect( G_OBJECT( selection ), "changed", G_CALLBACK( treeSelection ), this );
1591                 }
1592
1593                 gtk_widget_show( view );
1594
1595                 gtk_container_add( GTK_CONTAINER( sc_win ), view );
1596
1597                 {
1598                         /********************************************************************/
1599                         /* Add preference tree options                                      */
1600                         /********************************************************************/
1601                         {
1602                                 GtkTreeIter group;
1603                                 gtk_tree_store_append( store, &group, NULL );
1604                                 gtk_tree_store_set( store, &group, 0, _( "Globals" ), 1, PTAB_FRONT, -1 );
1605                                 {
1606                                         GtkTreeIter tab;
1607                                         gtk_tree_store_append( store, &tab, &group );
1608                                         gtk_tree_store_set( store, &tab, 0, _( "Game settings" ), 1, (gpointer)PTAB_GAME_SETTINGS, -1 );
1609                                 }
1610                         }
1611
1612                         {
1613                                 GtkTreeIter group;
1614                                 gtk_tree_store_append( store, &group, NULL );
1615                                 gtk_tree_store_set( store, &group, 0, _( "Display" ), 1, PTAB_FRONT, -1 );
1616                                 {
1617                                         GtkTreeIter tab;
1618                                         gtk_tree_store_append( store, &tab, &group );
1619                                         gtk_tree_store_set( store, &tab, 0, _( "2D Display/Rendering" ), 1, (gpointer)PTAB_2D, -1 );
1620                                 }
1621                                 {
1622                                         GtkTreeIter tab;
1623                                         gtk_tree_store_append( store, &tab, &group );
1624                                         gtk_tree_store_set( store, &tab, 0, _( "3D View" ), 1, (gpointer)PTAB_CAMERA, -1 );
1625                                 }
1626                                 {
1627                                         GtkTreeIter tab;
1628                                         gtk_tree_store_append( store, &tab, &group );
1629                                         gtk_tree_store_set( store, &tab, 0, _( "Texture Settings" ), 1, (gpointer)PTAB_TEXTURE, -1 );
1630                                 }
1631                         }
1632
1633                         {
1634                                 GtkTreeIter group;
1635                                 gtk_tree_store_append( store, &group, NULL );
1636                                 gtk_tree_store_set( store, &group, 0, _( "Interface" ), 1, PTAB_FRONT, -1 );
1637                                 {
1638                                         GtkTreeIter tab;
1639                                         gtk_tree_store_append( store, &tab, &group );
1640                                         gtk_tree_store_set( store, &tab, 0, _( "Layout" ), 1, (gpointer)PTAB_LAYOUT, -1 );
1641                                 }
1642                                 {
1643                                         GtkTreeIter tab;
1644                                         gtk_tree_store_append( store, &tab, &group );
1645                                         gtk_tree_store_set( store, &tab, 0, _( "Mouse" ), 1, (gpointer)PTAB_MOUSE, -1 );
1646                                 }
1647                                 {
1648                                         GtkTreeIter tab;
1649                                         gtk_tree_store_append( store, &tab, &group );
1650                                         gtk_tree_store_set( store, &tab, 0, _( "Editing" ), 1, (gpointer)PTAB_EDITING, -1 );
1651                                 }
1652                         }
1653
1654                         {
1655                                 GtkTreeIter group;
1656                                 gtk_tree_store_append( store, &group, NULL );
1657                                 gtk_tree_store_set( store, &group, 0, _( "Other" ), 1, PTAB_FRONT, -1 );
1658                                 {
1659                                         GtkTreeIter tab;
1660                                         gtk_tree_store_append( store, &tab, &group );
1661                                         gtk_tree_store_set( store, &tab, 0, _( "Startup/Auto save" ), 1, (gpointer)PTAB_STARTUP, -1 );
1662                                 }
1663                                 {
1664                                         GtkTreeIter tab;
1665                                         gtk_tree_store_append( store, &tab, &group );
1666                                         gtk_tree_store_set( store, &tab, 0, _( "Paths" ), 1, (gpointer)PTAB_PATHS, -1 );
1667                                 }
1668                                 {
1669                                         GtkTreeIter tab;
1670                                         gtk_tree_store_append( store, &tab, &group );
1671                                         gtk_tree_store_set( store, &tab, 0, _( "Brush" ), 1, (gpointer)PTAB_BRUSH, -1 );
1672                                 }
1673                                 {
1674                                         GtkTreeIter tab;
1675                                         gtk_tree_store_append( store, &tab, &group );
1676                                         gtk_tree_store_set( store, &tab, 0, _( "Misc" ), 1, (gpointer)PTAB_MISC, -1 );
1677                                 }
1678                                 if ( !g_qeglobals.bBSPFrontendPlugin ) {
1679                                         GtkTreeIter tab;
1680                                         gtk_tree_store_append( store, &tab, &group );
1681                                         gtk_tree_store_set( store, &tab, 0, _( "BSP Monitoring" ), 1, (gpointer)PTAB_BSPMONITOR, -1 );
1682                                 }
1683                         }
1684                 }
1685
1686                 gtk_tree_view_expand_all( GTK_TREE_VIEW( view ) );
1687
1688                 g_object_unref( G_OBJECT( store ) );
1689         }
1690
1691         /**********************************************************************/
1692         /* build the prefs pages                                              */
1693         /**********************************************************************/
1694
1695         // Front page...
1696         // todo : add something interesting here
1697         // NOTE TTimo: tip of the day? or a logo?
1698         preflabel = gtk_label_new( _( "Front Page" ) );
1699         gtk_widget_show( preflabel );
1700         pageframe = gtk_frame_new( NULL );
1701         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
1702         gtk_widget_show( pageframe );
1703         vbox = gtk_vbox_new( FALSE, 5 );
1704         gtk_widget_show( vbox );
1705         gtk_widget_set_usize( GTK_WIDGET( vbox ), 350, -2 );
1706         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1707         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
1708
1709         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
1710
1711         /******** global preferences group ****************************/
1712         preflabel = gtk_label_new( _( "Globals" ) );
1713         gtk_widget_show( preflabel );
1714
1715         pageframe = mGamesDialog.GetGlobalFrame();
1716         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
1717
1718         /******** 2D prefs group (xy views/rendering options) *********/
1719         preflabel = gtk_label_new( _( "2D Display" ) );
1720         gtk_widget_show( preflabel );
1721         pageframe = gtk_frame_new( _( "2D Display" ) );
1722         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
1723         gtk_widget_show( pageframe );
1724         vbox = gtk_vbox_new( FALSE, 5 );
1725         gtk_widget_show( vbox );
1726         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1727         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
1728
1729         // OpenGL Display Lists
1730         check = gtk_check_button_new_with_label( _( "OpenGL Display Lists" ) );
1731         gtk_widget_show( check );
1732         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1733         AddDialogData( check, &m_bDisplayLists, DLG_CHECK_BOOL );
1734
1735         // Antialiased points & lines
1736         // Fishman - Add antialiazed points and lines support. 09/03/00
1737         check = gtk_check_button_new_with_label( _( "OpenGL antialiased points and lines" ) );
1738         gtk_widget_show( check );
1739         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1740         AddDialogData( check, &m_bAntialiasedPointsAndLines, DLG_CHECK_BOOL );
1741
1742         // Solid selection boxes
1743         check = gtk_check_button_new_with_label( _( "Solid selection boxes" ) );
1744         gtk_widget_show( check );
1745         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1746         AddDialogData( check, &m_bNoStipple, DLG_CHECK_BOOL );
1747
1748         // Display size info
1749         check = gtk_check_button_new_with_label( _( "Display size info" ) );
1750         gtk_widget_show( check );
1751         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1752         AddDialogData( check, &m_bSizePaint, DLG_CHECK_BOOL );
1753
1754         // Alternate vertex/edge handles
1755         // Gef: Kyro GL_POINT work around 25-aug-2001
1756         check = gtk_check_button_new_with_label( _( "Alternate vertex/edge handles" ) );
1757         gtk_widget_show( check );
1758         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1759         AddDialogData( check, &m_bGlPtWorkaround, DLG_CHECK_BOOL );
1760
1761         g_list_free( combo_list );
1762
1763 #ifdef ATIHACK_812
1764         // ATI bugs
1765         check = gtk_check_button_new_with_label( _( "ATI and Intel cards w/ buggy drivers (disappearing polygons)" ) );
1766         gtk_widget_show( check );
1767         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1768         AddDialogData( check, &m_bGlATIHack, DLG_CHECK_BOOL );
1769 #endif
1770
1771 #ifdef NVIDIA_AERO_HACK
1772         check = gtk_check_button_new_with_label( _( "NVIDIA/Aero bug - disable Windows composition" ) );
1773         gtk_widget_show( check );
1774         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1775         AddDialogData( check, &m_bGlNvidiaAeroHack, DLG_CHECK_BOOL );
1776 #endif
1777
1778         // Add the page to the notebook
1779         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
1780
1781         /******** 3D Camera view group *********/
1782         preflabel = gtk_label_new( _( "3D View" ) );
1783         gtk_widget_show( preflabel );
1784         pageframe = gtk_frame_new( _( "3D View" ) );
1785         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
1786         gtk_widget_show( pageframe );
1787         vbox = gtk_vbox_new( FALSE, 5 );
1788         gtk_widget_show( vbox );
1789         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1790         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
1791
1792         // Directional velocity (Movement Velocity)
1793         // label container
1794         hbox2 = gtk_hbox_new( FALSE, 0 );
1795         gtk_widget_show( hbox2 );
1796         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
1797
1798         // label
1799         label = gtk_label_new( _( "Movement Velocity" ) );
1800         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
1801         gtk_widget_show( label );
1802         gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
1803
1804         // adjustment
1805         adj = gtk_adjustment_new( 100, 50, 300, 1, 10, 10 );
1806         AddDialogData( adj, &m_nMoveSpeed, DLG_ADJ_INT );
1807
1808         // scale
1809         scale = gtk_hscale_new( GTK_ADJUSTMENT( adj ) );
1810         gtk_widget_show( scale );
1811         gtk_box_pack_start( GTK_BOX( vbox ), scale, FALSE, TRUE, 2 );
1812
1813         gtk_scale_set_draw_value( GTK_SCALE( scale ), TRUE );
1814
1815         // Angular velocity (Rotational Velocity)
1816         // label container
1817         hbox2 = gtk_hbox_new( FALSE, 0 );
1818         gtk_widget_show( hbox2 );
1819         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
1820
1821         // label
1822         label = gtk_label_new( _( "Rotational Velocity" ) );
1823         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
1824         gtk_widget_show( label );
1825         gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
1826
1827         // adjustment
1828         adj = gtk_adjustment_new( 3, 1, 180, 1, 10, 10 ); // value, low, high, step, page_step, page_size
1829         AddDialogData( adj, &m_nAngleSpeed, DLG_ADJ_INT );
1830
1831         // scale
1832         scale = gtk_hscale_new( GTK_ADJUSTMENT( adj ) );
1833         gtk_widget_show( scale );
1834         gtk_box_pack_start( GTK_BOX( vbox ), scale, FALSE, TRUE, 2 );
1835         gtk_scale_set_draw_value( GTK_SCALE( scale ), TRUE );
1836
1837         // Text under the velocity sliders
1838         // container
1839         hbox2 = gtk_hbox_new( FALSE, 0 );
1840         gtk_widget_show( hbox2 );
1841         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
1842
1843         // label
1844         label = gtk_label_new( _( "slow" ) );
1845         gtk_widget_show( label );
1846         gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
1847
1848         // label
1849         label = gtk_label_new( _( "fast" ) );
1850         gtk_widget_show( label );
1851         gtk_box_pack_end( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
1852
1853         // Allow drag to select multiple faces/brushes
1854         // container
1855         table = gtk_table_new( 2, 1, FALSE );
1856         gtk_widget_show( table );
1857         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
1858         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
1859         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
1860
1861         label = gtk_label_new( _( "Use paint-select in camera view:" ) );
1862         gtk_widget_show( label );
1863         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
1864         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
1865                                           (GtkAttachOptions) ( 0 ),
1866                                           (GtkAttachOptions) ( 0 ), 0, 0 );
1867
1868         combo_list = NULL;
1869         combo_list = g_list_append( combo_list, (void *)_( "No" ) );
1870         combo_list = g_list_append( combo_list, (void *)_( "Yes" ) );
1871         combo_list = g_list_append( combo_list, (void *)_( "Yes (Classic Key Setup)" ) );
1872
1873         combo = gtk_combo_new();
1874         gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list );
1875         gtk_widget_show( combo );
1876         gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1,
1877                                           (GtkAttachOptions) ( GTK_FILL ),
1878                                           (GtkAttachOptions) ( 0 ), 0, 0 );
1879         gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE );
1880         AddDialogData( combo, &m_nCamDragMultiSelect, DLG_COMBO_INT );
1881
1882         // Freelook in Camera view
1883         check = gtk_check_button_new_with_label( _( "Freelook in Camera view" ) );
1884         gtk_widget_show( check );
1885         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1886         gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT );
1887         AddDialogData( check, &m_bCamFreeLook, DLG_CHECK_BOOL );
1888
1889         // Freelook in Camera view w/ forward & back strafing instead of up and down looking
1890         check = gtk_check_button_new_with_label( _( "Freelook strafes Forward and Back" ) );
1891         gtk_widget_show( check );
1892         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1893         gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT );
1894         AddDialogData( check, &m_bCamFreeLookStrafe, DLG_CHECK_BOOL );
1895
1896         // Invert mouse in freelook
1897         check = gtk_check_button_new_with_label( _( "Invert mouse in freelook" ) );
1898         gtk_widget_show( check );
1899         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1900         gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT );
1901         AddDialogData( check, &m_bCamInverseMouse, DLG_CHECK_BOOL );
1902
1903         // Discrete movement
1904         check = gtk_check_button_new_with_label( _( "Discrete movement" ) );
1905         gtk_widget_show( check );
1906         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1907         gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT );
1908         AddDialogData( check, &m_bCamDiscrete, DLG_CHECK_BOOL );
1909
1910         // Update XY views on camera move
1911         check = gtk_check_button_new_with_label( _( "Update XY views on camera move" ) );
1912         gtk_widget_show( check );
1913         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1914         gtk_label_set_justify( GTK_LABEL( GTK_BIN( check )->child ), GTK_JUSTIFY_LEFT );
1915         AddDialogData( check, &m_bCamXYUpdate, DLG_CHECK_BOOL );
1916
1917         // Add the page to the notebook
1918         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
1919
1920         /******** Texture group *********/
1921         preflabel = gtk_label_new( _( "Textures" ) );
1922         gtk_widget_show( preflabel );
1923         pageframe = gtk_frame_new( _( "Textures" ) );
1924         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
1925         gtk_widget_show( pageframe );
1926         vbox = gtk_vbox_new( FALSE, 6 );
1927         gtk_widget_show( vbox );
1928         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
1929         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
1930
1931         // Texture quality slider
1932         // label
1933         label = gtk_label_new( _( "Texture quality" ) );
1934         gtk_widget_show( label );
1935         gtk_box_pack_start( GTK_BOX( vbox ), label, FALSE, FALSE, 0 );
1936         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
1937         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
1938
1939         // adjustment
1940         adj = gtk_adjustment_new( 0, 0, 4, 1, 1, 1 );
1941         AddDialogData( adj, &m_nLatchedTextureQuality, DLG_ADJ_INT );
1942
1943         // scale
1944         scale = gtk_hscale_new( GTK_ADJUSTMENT( adj ) );
1945         gtk_widget_show( scale );
1946         gtk_box_pack_start( GTK_BOX( vbox ), scale, FALSE, FALSE, 0 );
1947         gtk_scale_set_draw_value( GTK_SCALE( scale ), FALSE );
1948
1949         // text under the texture slider
1950         hbox2 = gtk_hbox_new( FALSE, 0 );
1951         gtk_widget_show( hbox2 );
1952         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
1953         label = gtk_label_new( _( "low" ) );
1954         gtk_widget_show( label );
1955         gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
1956         label = gtk_label_new( _( "high" ) );
1957         gtk_widget_show( label );
1958         gtk_box_pack_end( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
1959
1960         // texture subsets
1961         check = gtk_check_button_new_with_label( _( "Texture subsets" ) );
1962         gtk_widget_show( check );
1963         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1964         AddDialogData( check, &m_bTextureWindow, DLG_CHECK_BOOL );
1965
1966         // texture scrollbar
1967         check = gtk_check_button_new_with_label( _( "Texture scrollbar" ) );
1968         gtk_widget_show( check );
1969         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1970         AddDialogData( check, &m_bTextureScrollbar, DLG_CHECK_BOOL );
1971
1972         // texture increment matches grid
1973         check = gtk_check_button_new_with_label( _( "Tex increment matches grid" ) );
1974         gtk_widget_show( check );
1975         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
1976         AddDialogData( check, &m_bSnapTToGrid, DLG_CHECK_BOOL );
1977
1978         // RIANT
1979         // Texture compression choice label
1980         // container
1981         table = gtk_table_new( 2, 1, FALSE );
1982         gtk_widget_show( table );
1983         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
1984         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
1985         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
1986
1987         label = gtk_label_new( _( "Texture Compression (if available):" ) );
1988         gtk_widget_show( label );
1989         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
1990         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
1991                                           (GtkAttachOptions) ( 0 ),
1992                                           (GtkAttachOptions) ( 0 ), 0, 0 );
1993         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
1994
1995         // Texture compression choice label
1996         combo_list = NULL;
1997         // NONE will always be in pos 0
1998         combo_list = g_list_append( combo_list, (void *)_( "None" ) );
1999
2000         // if OpenGL compression is enabled it will always be
2001         // in pos 1
2002         if ( g_qeglobals.m_bOpenGLCompressionSupported ) {
2003                 combo_list = g_list_append( combo_list, (void *)_( "OpenGL ARB" ) );
2004         }
2005
2006         // If S3 is enabled offer all 3 valid compression schemes in RGBA
2007         if ( g_qeglobals.m_bS3CompressionSupported ) {
2008                 combo_list = g_list_append( combo_list, (void *)_( "S3TC DXT1" ) );
2009                 combo_list = g_list_append( combo_list, (void *)_( "S3TC DXT3" ) );
2010                 combo_list = g_list_append( combo_list, (void *)_( "S3TC DXT5" ) );
2011         }
2012
2013         combo = gtk_combo_new();
2014         gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list );
2015         gtk_widget_show( combo );
2016         gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1,
2017                                           (GtkAttachOptions) ( GTK_FILL ),
2018                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2019         gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE );
2020         AddDialogData( combo, &m_nTextureCompressionFormat, DLG_COMBO_INT );
2021         g_list_free( combo_list );
2022
2023         // container
2024         table = gtk_table_new( 2, 1, FALSE );
2025         gtk_widget_show( table );
2026         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2027         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2028         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2029
2030         // Startup shaders
2031         // label
2032         label = gtk_label_new( _( "Startup Shaders:" ) );
2033         gtk_widget_show( label );
2034         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
2035         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
2036                                           (GtkAttachOptions) ( 0 ),
2037                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2038         gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
2039
2040         // combo list
2041         combo_list = NULL;
2042         combo_list = g_list_append( combo_list, (void *)_( "None" ) );
2043         if ( g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game" ) {
2044                 combo_list = g_list_append( combo_list, (void *)_( "System" ) );
2045         }
2046         else if ( g_pGameDescription->mGameFile == "sof2.game" ) {
2047                 combo_list = g_list_append( combo_list, (void *)( "Tools" ) );
2048         }
2049         else{
2050                 combo_list = g_list_append( combo_list, (void *)_( "Common" ) );
2051         }
2052         combo_list = g_list_append( combo_list, (void *)_( "All" ) );
2053         combo = gtk_combo_new();
2054         gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list );
2055         gtk_widget_show( combo );
2056         gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1,
2057                                           (GtkAttachOptions) ( GTK_FILL ),
2058                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2059         gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE );
2060         AddDialogData( combo, &m_nLatchedShader, DLG_COMBO_INT );
2061         g_list_free( combo_list );
2062
2063         // Add the page to the notebook
2064         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2065
2066         /******** Layout group *********/
2067         preflabel = gtk_label_new( _( "Layout" ) );
2068         gtk_widget_show( preflabel );
2069         pageframe = gtk_frame_new( _( "Layout" ) );
2070         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2071         gtk_widget_show( pageframe );
2072         vbox = gtk_vbox_new( FALSE, 5 );
2073         gtk_widget_show( vbox );
2074         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2075         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2076
2077         // View types
2078         // table
2079         table = gtk_table_new( 2, 4, FALSE );
2080         gtk_widget_show( table );
2081         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2082         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2083         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2084
2085         // view type 1
2086         pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window1.bmp" );
2087         gtk_widget_show( pixmap );
2088         gtk_table_attach( GTK_TABLE( table ), pixmap, 0, 1, 0, 1,
2089                                           (GtkAttachOptions) ( 0 ),
2090                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2091
2092         // view type 2
2093         pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window2.bmp" );
2094         gtk_widget_show( pixmap );
2095         gtk_table_attach( GTK_TABLE( table ), pixmap, 1, 2, 0, 1,
2096                                           (GtkAttachOptions) ( 0 ),
2097                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2098
2099         // view type 3
2100         pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window3.bmp" );
2101         gtk_widget_show( pixmap );
2102         gtk_table_attach( GTK_TABLE( table ), pixmap, 2, 3, 0, 1,
2103                                           (GtkAttachOptions) ( 0 ),
2104                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2105
2106         // view type 4
2107         pixmap = new_pixmap( g_pParentWnd->m_pWidget, "window4.bmp" );
2108         gtk_widget_show( pixmap );
2109         gtk_table_attach( GTK_TABLE( table ), pixmap, 3, 4, 0, 1,
2110                                           (GtkAttachOptions) ( 0 ),
2111                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2112
2113         // view type 1 selector
2114         radio = gtk_radio_button_new( NULL );
2115         gtk_widget_show( radio );
2116         gtk_table_attach( GTK_TABLE( table ), radio, 0, 1, 1, 2,
2117                                           (GtkAttachOptions) ( 0 ),
2118                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2119
2120         // view type 2 selector
2121         radio = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON( radio ) );
2122         gtk_widget_show( radio );
2123         gtk_table_attach( GTK_TABLE( table ), radio, 1, 2, 1, 2,
2124                                           (GtkAttachOptions) ( 0 ),
2125                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2126
2127         // view type 3 selector
2128         radio = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON( radio ) );
2129         gtk_widget_show( radio );
2130         gtk_table_attach( GTK_TABLE( table ), radio, 2, 3, 1, 2,
2131                                           (GtkAttachOptions) ( 0 ),
2132                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2133
2134         // view type 4 selector
2135         radio = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON( radio ) );
2136         gtk_widget_show( radio );
2137         gtk_table_attach( GTK_TABLE( table ), radio, 3, 4, 1, 2,
2138                                           (GtkAttachOptions) ( 0 ),
2139                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2140         AddDialogData( radio, &m_nLatchedView, DLG_RADIO_INT );
2141
2142         // Floating Z window
2143         check = gtk_check_button_new_with_label( _( "Floating Z Window" ) );
2144         gtk_widget_show( check );
2145         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2146         AddDialogData( check, &m_bLatchedFloatingZ, DLG_CHECK_BOOL );
2147
2148         // show menu tear-off seperators
2149         check = gtk_check_button_new_with_label( _( "Detachable Menus" ) );
2150         gtk_widget_show( check );
2151         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2152         AddDialogData( check, &m_bLatchedDetachableMenus, DLG_CHECK_BOOL );
2153
2154         if ( !g_pGameDescription->mNoPatch ) {
2155                 // show patch toolbar
2156                 check = gtk_check_button_new_with_label( _( "Patch Toolbar" ) );
2157                 gtk_widget_show( check );
2158                 gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2159                 g_object_set_data( G_OBJECT( dialog ), "check_patchtoolbar", check ); // Allow to be disabled for Q1/Q2
2160                 AddDialogData( check, &m_bLatchedPatchToolbar, DLG_CHECK_BOOL );
2161         }
2162
2163         // use wide toolbar
2164         check = gtk_check_button_new_with_label( _( "Wide Toolbar" ) );
2165         gtk_widget_show( check );
2166         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2167         AddDialogData( check, &m_bLatchedWideToolbar, DLG_CHECK_BOOL );
2168
2169         // use plugin toolbar
2170         check = gtk_check_button_new_with_label( _( "Plugin Toolbar" ) );
2171         gtk_widget_show( check );
2172         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2173         AddDialogData( check, &m_bLatchedPluginToolbar, DLG_CHECK_BOOL );
2174
2175 #ifdef _WIN32
2176         // win32 file dialog
2177         check = gtk_check_button_new_with_label( _( "Use win32 file dialog (hacky)" ) );
2178         gtk_widget_show( check );
2179         // gtk_container_add (GTK_CONTAINER (vbox), check);
2180         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2181         AddDialogData( check, &m_bNativeGUI, DLG_CHECK_BOOL );
2182
2183         // position on primary monitor
2184         check = gtk_check_button_new_with_label( _( "Start on Primary Monitor" ) );
2185         gtk_widget_show( check );
2186         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2187         g_object_set_data( G_OBJECT( dialog ), "check_startonprimary", check );
2188         gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateSensitivity ), this );
2189         AddDialogData( check, &m_bStartOnPrimMon, DLG_CHECK_BOOL );
2190 #endif
2191
2192         // Add the page to the notebook
2193         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2194
2195         /******** Mouse group *********/
2196         preflabel = gtk_label_new( _( "Mouse" ) );
2197         gtk_widget_show( preflabel );
2198         pageframe = gtk_frame_new( _( "Mouse" ) );
2199         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2200         gtk_widget_show( pageframe );
2201         vbox = gtk_vbox_new( FALSE, 5 );
2202         gtk_widget_show( vbox );
2203         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2204         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2205
2206         // Buttons
2207         // container
2208         hbox2 = gtk_hbox_new( FALSE, 5 );
2209         gtk_widget_show( hbox2 );
2210         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
2211
2212         // 2 button radio
2213         radio = gtk_radio_button_new_with_label( NULL, _( "2 button" ) );
2214         gtk_widget_show( radio );
2215         gtk_box_pack_start( GTK_BOX( hbox2 ), radio, FALSE, FALSE, 0 );
2216
2217         // 3 button radio
2218         radio = gtk_radio_button_new_with_label_from_widget( GTK_RADIO_BUTTON( radio ), _( "3 button" ) );
2219         gtk_widget_show( radio );
2220         gtk_box_pack_start( GTK_BOX( hbox2 ), radio, FALSE, FALSE, 0 );
2221         AddDialogData( radio, &m_nMouse, DLG_RADIO_INT );
2222
2223         // right click to drop entity
2224         check = gtk_check_button_new_with_label( _( "Right click to drop entities" ) );
2225         gtk_widget_show( check );
2226         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2227         AddDialogData( check, &m_bRightClick, DLG_CHECK_BOOL );
2228
2229         // Mouse chaser (and this does what?)
2230         check = gtk_check_button_new_with_label( _( "Mouse chaser" ) );
2231         gtk_widget_show( check );
2232         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2233         AddDialogData( check, &m_bChaseMouse, DLG_CHECK_BOOL );
2234
2235         // Alt + multi-drag
2236         check = gtk_check_button_new_with_label( _( "ALT + multi-drag" ) );
2237         gtk_widget_show( check );
2238         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2239         AddDialogData( check, &m_bALTEdge, DLG_CHECK_BOOL );
2240
2241         // Mouse wheel increments
2242         // container
2243         hbox2 = gtk_hbox_new( FALSE, 5 );
2244         gtk_widget_show( hbox2 );
2245         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
2246
2247         // label
2248         label = gtk_label_new( _( "Wheel Mouse inc:" ) );
2249         gtk_widget_show( label );
2250         gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
2251
2252         // entry
2253         entry = gtk_entry_new();
2254         gtk_widget_show( entry );
2255         gtk_widget_set_usize( entry, 40, -2 );
2256         gtk_box_pack_start( GTK_BOX( hbox2 ), entry, FALSE, FALSE, 0 );
2257         AddDialogData( entry, &m_nWheelInc, DLG_ENTRY_INT );
2258
2259         // Add the page to the notebook
2260         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2261
2262         /******** Editing group *********/
2263         preflabel = gtk_label_new( _( "Editing" ) );
2264         gtk_widget_show( preflabel );
2265         pageframe = gtk_frame_new( _( "Editing" ) );
2266         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2267         gtk_widget_show( pageframe );
2268         vbox = gtk_vbox_new( FALSE, 5 );
2269         gtk_widget_show( vbox );
2270         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2271         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2272
2273         // Vertex editing splits faces
2274         check = gtk_check_button_new_with_label( _( "Vertex editing splits face" ) );
2275         gtk_widget_show( check );
2276         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2277         AddDialogData( check, &m_bVertexSplit, DLG_CHECK_BOOL );
2278
2279         // Fix target/targetname collisions
2280         check = gtk_check_button_new_with_label( _( "Fix target/targetname collisions" ) );
2281         gtk_widget_show( check );
2282         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2283         AddDialogData( check, &m_bDoTargetFix, DLG_CHECK_BOOL );
2284
2285         // Clipper tool uses caulk
2286         check = gtk_check_button_new_with_label( _( "Clipper tool uses caulk" ) );
2287         gtk_widget_show( check );
2288         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2289         AddDialogData( check, &m_bClipCaulk, DLG_CHECK_BOOL );
2290
2291         // Don't clamp plane points
2292         check = gtk_check_button_new_with_label( _( "Don't clamp plane points" ) );
2293         gtk_widget_show( check );
2294         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2295         AddDialogData( check, &m_bNoClamp, DLG_CHECK_BOOL );
2296
2297         // Snap to grid
2298         check = gtk_check_button_new_with_label( _( "Snap to grid" ) );
2299         gtk_widget_show( check );
2300         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2301         AddDialogData( check, &m_bSnap, DLG_CHECK_BOOL );
2302
2303         // Select patch by bounding box
2304         check = gtk_check_button_new_with_label( _( "Select patches by bounding box" ) );
2305         gtk_widget_show( check );
2306         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2307         AddDialogData( check, &m_bPatchBBoxSelect, DLG_CHECK_BOOL );
2308
2309         // Rotation increment
2310         // container
2311         table = gtk_table_new( 2, 3, FALSE );
2312         gtk_widget_show( table );
2313         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2314         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2315         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2316
2317         // label
2318         label = gtk_label_new( _( "Rotation increment:" ) );
2319         gtk_widget_show( label );
2320         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
2321                                           (GtkAttachOptions) ( 0 ),
2322                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2323
2324         // entry
2325         entry = gtk_entry_new();
2326         gtk_widget_show( entry );
2327         gtk_widget_set_usize( entry, 60, -2 );
2328         gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1,
2329                                           (GtkAttachOptions) ( GTK_FILL ),
2330                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2331         AddDialogData( entry, &m_nRotation, DLG_ENTRY_INT );
2332
2333         // Undo levels
2334         // label
2335         label = gtk_label_new( _( "Undo Levels:" ) );
2336         gtk_widget_show( label );
2337         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2,
2338                                           (GtkAttachOptions) ( 0 ),
2339                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2340
2341         // spinner (allows undo levels to be set to zero)
2342         spin = gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 1, 0, 64, 1, 10, 10 ) ), 1, 0 );
2343         gtk_widget_show( spin );
2344         gtk_table_attach( GTK_TABLE( table ), spin, 1, 2, 1, 2,
2345                                           (GtkAttachOptions) ( GTK_FILL ),
2346                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2347         gtk_widget_set_usize( spin, 60, -2 );
2348         AddDialogData( spin, &m_nUndoLevels, DLG_SPIN_INT );
2349
2350         // Patch subdivisions
2351         // label
2352         label = gtk_label_new( _( "Patch subdivisions:" ) );
2353         gtk_widget_show( label );
2354         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 2, 3,
2355                                           (GtkAttachOptions) ( 0 ),
2356                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2357
2358         // entry (spinner perhaps? [2-16])
2359         entry = gtk_entry_new();
2360         gtk_widget_show( entry );
2361         gtk_widget_set_usize( entry, 60, -2 );
2362         gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 2, 3,
2363                                           (GtkAttachOptions) ( GTK_FILL ),
2364                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2365         AddDialogData( entry, &m_nSubdivisions, DLG_ENTRY_INT );
2366
2367         // Add the page to the notebook
2368         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2369
2370         /******** Save/Load group *********/
2371         preflabel = gtk_label_new( _( "Startup/Auto save" ) );
2372         gtk_widget_show( preflabel );
2373         pageframe = gtk_frame_new( _( "Startup/Auto save" ) );
2374         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2375         gtk_widget_show( pageframe );
2376         vbox = gtk_vbox_new( FALSE, 5 );
2377         gtk_widget_show( vbox );
2378         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2379         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2380
2381         // Snapshots
2382         check = gtk_check_button_new_with_label( _( "Snapshots" ) );
2383         gtk_widget_show( check );
2384         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2385         AddDialogData( check, &m_bSnapShots, DLG_CHECK_BOOL );
2386
2387         // load last project on open
2388         check = gtk_check_button_new_with_label( _( "Load last project on open" ) );
2389         gtk_widget_show( check );
2390         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2391         AddDialogData( check, &m_bLoadLast, DLG_CHECK_BOOL );
2392
2393         // load last map on open
2394         check = gtk_check_button_new_with_label( _( "Load last map on open" ) );
2395         gtk_widget_show( check );
2396         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2397         AddDialogData( check, &m_bLoadLastMap, DLG_CHECK_BOOL );
2398
2399         // Auto save..
2400         // container
2401         hbox2 = gtk_hbox_new( FALSE, 5 );
2402         gtk_widget_show( hbox2 );
2403         gtk_box_pack_start( GTK_BOX( vbox ), hbox2, FALSE, FALSE, 0 );
2404         gtk_container_set_border_width( GTK_CONTAINER( hbox2 ), 0 );
2405
2406         // label
2407         check = gtk_check_button_new_with_label( _( "Auto save every" ) );
2408         gtk_widget_show( check );
2409         gtk_box_pack_start( GTK_BOX( hbox2 ), check, FALSE, FALSE, 0 );
2410         AddDialogData( check, &m_bAutoSave, DLG_CHECK_BOOL );
2411
2412         // spinner
2413         spin = gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 1, 1, 60, 1, 10, 10 ) ), 1, 0 );
2414         gtk_widget_show( spin );
2415         gtk_box_pack_start( GTK_BOX( hbox2 ), spin, FALSE, FALSE, 0 );
2416         gtk_widget_set_usize( spin, 60, -2 );
2417         AddDialogData( spin, &m_nAutoSave, DLG_SPIN_INT );
2418
2419         // label
2420         label = gtk_label_new( _( "minutes" ) );
2421         gtk_widget_show( label );
2422         gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, FALSE, 0 );
2423
2424         // Add the page to the notebook
2425         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2426
2427         /******** Paths group *********/
2428         preflabel = gtk_label_new( _( "Paths" ) );
2429         gtk_widget_show( preflabel );
2430         pageframe = gtk_frame_new( _( "Paths" ) );
2431         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2432         gtk_widget_show( pageframe );
2433         vbox = gtk_vbox_new( FALSE, 5 );
2434         gtk_widget_show( vbox );
2435         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2436         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2437
2438         // prefab path
2439         // table
2440         table = gtk_table_new( 3, 3, FALSE );
2441         gtk_widget_show( table );
2442         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2443         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2444         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2445
2446         // label
2447         label = gtk_label_new( _( "Prefab path:" ) );
2448         gtk_widget_show( label );
2449         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
2450                                           (GtkAttachOptions) ( 0 ),
2451                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2452         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
2453
2454         // path entry
2455         entry = gtk_entry_new();
2456         gtk_widget_show( entry );
2457         gtk_widget_set_usize( GTK_WIDGET( entry ), 240, -2 );
2458         gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1,
2459                                           (GtkAttachOptions) ( GTK_FILL ),
2460                                           (GtkAttachOptions) ( 0 ), 1, 0 );
2461         AddDialogData( entry, &m_strPrefabPath, DLG_ENTRY_TEXT );
2462
2463 #if 0
2464         // browse button
2465         button = gtk_button_new_with_label( "..." );
2466         gtk_widget_show( button );
2467         gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseprefab ), this );
2468         gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1,
2469                                           (GtkAttachOptions) ( 0 ),
2470                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2471 #endif
2472
2473         // User ini path
2474         // label
2475         label = gtk_label_new( _( "User INI path:" ) );
2476         gtk_widget_show( label );
2477         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2,
2478                                           (GtkAttachOptions) ( 0 ),
2479                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2480         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
2481
2482         // user ini path entry
2483         entry = gtk_entry_new();
2484         gtk_widget_show( entry );
2485         gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 1, 2,
2486                                           (GtkAttachOptions) ( GTK_FILL ),
2487                                           (GtkAttachOptions) ( 0 ), 1, 0 );
2488         AddDialogData( entry, &m_strUserPath, DLG_ENTRY_TEXT );
2489
2490         // user ini browse button
2491         button = gtk_button_new_with_label( "..." );
2492         gtk_widget_show( button );
2493         gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseuserini ), this );
2494         gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 1, 2,
2495                                           (GtkAttachOptions) ( 0 ),
2496                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2497
2498         // Add the page to the notebook
2499         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2500
2501         /******** Brush group ********/
2502         preflabel = gtk_label_new( _( "Brush" ) );
2503         gtk_widget_show( preflabel );
2504         pageframe = gtk_frame_new( _( "Brush" ) );
2505         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2506         gtk_widget_show( pageframe );
2507         vbox = gtk_vbox_new( FALSE, 5 );
2508         gtk_widget_show( vbox );
2509         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2510         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2511
2512         // default texture scale
2513         // table
2514         table = gtk_table_new( 2, 1, FALSE ); // I believe that the 2 and 1 are switched here, and this is
2515                                               // intentional to be consistent with other calls to gtk_table_new()
2516                                               // [that are probably also switched].
2517         gtk_widget_show( table );
2518         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2519         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2520         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2521
2522         // label
2523         label = gtk_label_new( _( "Default texture scale:" ) );
2524         gtk_widget_show( label );
2525         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
2526         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
2527                                           (GtkAttachOptions) ( 0 ),
2528                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2529
2530         // scale entry
2531         entry = gtk_entry_new();
2532         gtk_widget_show( entry );
2533         gtk_widget_set_usize( GTK_WIDGET( entry ), 60, -2 );
2534         gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1,
2535                                           (GtkAttachOptions) ( GTK_FILL ),
2536                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2537         AddDialogData( entry, &m_fDefTextureScale, DLG_ENTRY_FLOAT );
2538
2539         // Add the page to the notebook
2540         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2541
2542         /******** Misc group *********/
2543         preflabel = gtk_label_new( _( "Misc" ) );
2544         gtk_widget_show( preflabel );
2545         pageframe = gtk_frame_new( _( "Misc" ) );
2546         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2547         gtk_widget_show( pageframe );
2548         vbox = gtk_vbox_new( FALSE, 5 );
2549         gtk_widget_show( vbox );
2550         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2551         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2552
2553         // Light drawing
2554         check = gtk_check_button_new_with_label( _( "Light drawing" ) );
2555         gtk_widget_show( check );
2556         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2557         AddDialogData( check, &m_bNewLightDraw, DLG_CHECK_BOOL );
2558
2559         // Light radiuses
2560         // container
2561         table = gtk_table_new( 2, 1, FALSE );
2562         gtk_widget_show( table );
2563         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2564         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2565         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2566
2567         label = gtk_label_new( _( "Light radiuses:" ) );
2568         gtk_widget_show( label );
2569         gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT );
2570         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
2571                                           (GtkAttachOptions) ( 0 ),
2572                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2573
2574         combo_list = NULL;
2575         combo_list = g_list_append( combo_list, (void *)_( "Disabled" ) );
2576         combo_list = g_list_append( combo_list, (void *)_( "True Q3Map2 Style" ) );
2577         combo_list = g_list_append( combo_list, (void *)_( "Classic Style" ) );
2578
2579         combo = gtk_combo_new();
2580         gtk_combo_set_popdown_strings( GTK_COMBO( combo ), combo_list );
2581         gtk_widget_show( combo );
2582         gtk_table_attach( GTK_TABLE( table ), combo, 1, 2, 0, 1,
2583                                           (GtkAttachOptions) ( GTK_FILL ),
2584                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2585         gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO( combo )->entry ), FALSE );
2586         AddDialogData( combo, &m_nLightRadiuses, DLG_COMBO_INT );
2587
2588 #ifdef _WIN32
2589         check = gtk_check_button_new_with_label( _( "Use win32 file associations to open text files instead of builtin editor" ) );
2590         gtk_widget_show( check );
2591         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2592         AddDialogData( check, &g_PrefsDlg.m_bUseWin32Editor, DLG_CHECK_BOOL );
2593 #else
2594         // use custom shader editor
2595         check = gtk_check_button_new_with_label( _( "Use Custom Shader Editor" ) );
2596         gtk_widget_show( check );
2597         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2598         gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateEditorSensitivity ), this );
2599         g_object_set_data( G_OBJECT( dialog ), "check_customeditor", check );
2600         AddDialogData( check, &g_PrefsDlg.m_bUseCustomEditor, DLG_CHECK_BOOL );
2601
2602         // custom shader editor executable
2603         // table
2604         table = gtk_table_new( 3, 1, FALSE );
2605         gtk_widget_show( table );
2606         gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
2607         gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
2608         gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
2609
2610         // label
2611         label = gtk_label_new( _( "Custom Editor Command" ) );
2612         gtk_widget_show( label );
2613         gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
2614                                           (GtkAttachOptions) ( 0 ),
2615                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2616         gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
2617         g_object_set_data( G_OBJECT( dialog ), "label_customeditor", label );
2618         gtk_widget_set_sensitive( label, g_PrefsDlg.m_bUseCustomEditor );
2619
2620         // custom editor command entry
2621         entry = gtk_entry_new();
2622         gtk_widget_show( entry );
2623         gtk_widget_set_usize( GTK_WIDGET( entry ), 240, -2 );
2624         gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1,
2625                                           (GtkAttachOptions) ( GTK_FILL ),
2626                                           (GtkAttachOptions) ( 0 ), 1, 0 );
2627         AddDialogData( entry, &m_strEditorCommand, DLG_ENTRY_TEXT );
2628         gtk_widget_set_sensitive( entry, g_PrefsDlg.m_bUseCustomEditor );
2629         g_object_set_data( G_OBJECT( dialog ), "entry_customeditor", entry );
2630
2631         // browse button
2632         button = gtk_button_new_with_label( _( "..." ) );
2633         gtk_widget_show( button );
2634         gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseEditor ), this );
2635         gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1,
2636                                           (GtkAttachOptions) ( 0 ),
2637                                           (GtkAttachOptions) ( 0 ), 0, 0 );
2638         g_object_set_data( G_OBJECT( dialog ), "button_customeditor", button );
2639         gtk_widget_set_sensitive( button, g_PrefsDlg.m_bUseCustomEditor );
2640 #endif
2641
2642         // Add the page to the notebook
2643         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2644
2645         /******** BSP Monitoring group *********/
2646         // this is never displayed if the plugin isn't available
2647         preflabel = gtk_label_new( _( "BSP Monitoring" ) );
2648         gtk_widget_show( preflabel );
2649         pageframe = gtk_frame_new( _( "BSP Monitoring" ) );
2650         gtk_container_set_border_width( GTK_CONTAINER( pageframe ), 5 );
2651         gtk_widget_show( pageframe );
2652         vbox = gtk_vbox_new( FALSE, 5 );
2653         gtk_widget_show( vbox );
2654         gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
2655         gtk_container_add( GTK_CONTAINER( pageframe ), vbox );
2656
2657         // Enable BSP process monitoring
2658         check = gtk_check_button_new_with_label( _( "Enable BSP process monitoring" ) );
2659         gtk_widget_show( check );
2660         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2661         g_object_set_data( G_OBJECT( dialog ), "check_monitorbsp", check );
2662         gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateSensitivity ), this );
2663         AddDialogData( check, &g_PrefsDlg.m_bWatchBSP, DLG_CHECK_BOOL );
2664
2665         // Stop on leak
2666         check = gtk_check_button_new_with_label( _( "Stop compilation on leak" ) );
2667         gtk_widget_show( check );
2668         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2669         g_object_set_data( G_OBJECT( dialog ), "check_leakstop", check );
2670         AddDialogData( check, &g_PrefsDlg.m_bLeakStop, DLG_CHECK_BOOL );
2671
2672         // engine after compile
2673         check = gtk_check_button_new_with_label( _( "Run engine after compile" ) );
2674         gtk_widget_show( check );
2675         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2676         g_object_set_data( G_OBJECT( dialog ), "check_runengine", check );
2677         gtk_signal_connect( GTK_OBJECT( check ), "clicked", GTK_SIGNAL_FUNC( UpdateSensitivity ), this );
2678         AddDialogData( check, &g_PrefsDlg.m_bRunQuake, DLG_CHECK_BOOL );
2679
2680         // sleep mode when running engine
2681         check = gtk_check_button_new_with_label( _( "Activate sleep mode when running the engine" ) );
2682         gtk_widget_show( check );
2683         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2684         g_object_set_data( G_OBJECT( dialog ), "check_sleep", check );
2685         AddDialogData( check, &g_PrefsDlg.m_bDoSleep, DLG_CHECK_BOOL );
2686
2687         // use q3map2's texture projection
2688         check = gtk_check_button_new_with_label( _( "Texturing compatible with q3map2" ) );
2689         gtk_widget_show( check );
2690         gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 );
2691         g_object_set_data( G_OBJECT( dialog ), "check_q3map2", check );
2692         AddDialogData( check, &g_PrefsDlg.m_bQ3Map2Texturing, DLG_CHECK_BOOL );
2693
2694         // Add the page to the notebook
2695         gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), pageframe, preflabel );
2696
2697         gtk_notebook_set_page( GTK_NOTEBOOK( notebook ), PTAB_FRONT );
2698
2699         return;
2700 }
2701
2702 // end new prefs dialog
2703
2704 void PrefsDlg::LoadTexdefPref( texdef_t* pTexdef, char* pName ){
2705         char buffer[256];
2706
2707         memset( pTexdef, 0, sizeof( texdef_t ) );
2708
2709         sprintf( buffer, "%s%s", pName, TD_SCALE1_KEY );
2710         mLocalPrefs.GetPref( buffer, &pTexdef->scale[0],   0.5f );
2711
2712         sprintf( buffer, "%s%s", pName, TD_SCALE2_KEY );
2713         mLocalPrefs.GetPref( buffer, &pTexdef->scale[1],   0.5f );
2714
2715         sprintf( buffer, "%s%s", pName, TD_SHIFT1_KEY );
2716         mLocalPrefs.GetPref( buffer, &pTexdef->shift[0],   8.f );
2717
2718         sprintf( buffer, "%s%s", pName, TD_SHIFT2_KEY );
2719         mLocalPrefs.GetPref( buffer, &pTexdef->shift[1],   8.f );
2720
2721         sprintf( buffer, "%s%s", pName, TD_ROTATE_KEY );
2722         mLocalPrefs.GetPref( buffer, &pTexdef->rotate,     45 );
2723 }
2724
2725 void PrefsDlg::UpdateTextureCompression(){
2726         // if OpenGL is not ready yet, don't do anything
2727         if ( !g_qeglobals.m_bOpenGLReady ) {
2728                 Sys_Printf( "OpenGL not ready - postpone texture compression capability check\n" );
2729                 return;
2730         }
2731
2732         if ( g_qeglobals.bTextureCompressionSupported ) {
2733                 if ( m_nTextureCompressionFormat >= 2 && !g_qeglobals.m_bS3CompressionSupported ) {
2734                         Sys_Printf( "Inconsistant pref setting for texture compression (%d), rolling back\n", m_nTextureCompressionFormat );
2735                         m_nTextureCompressionFormat = 1; // if this is not supported either, see below
2736                 }
2737                 if ( m_nTextureCompressionFormat == 1 && !g_qeglobals.m_bOpenGLCompressionSupported ) {
2738                         Sys_Printf( "Inconsistant pref setting for texture compression (GL_COMPRESSED_RGBA), rolling back\n" );
2739                         m_nTextureCompressionFormat = 0;
2740                 }
2741                 switch ( m_nTextureCompressionFormat )
2742                 {
2743                 case ( 0 ):
2744                 {
2745                         g_qeglobals.texture_components = GL_RGBA;
2746                         Sys_Printf( "texture compression disabled by preferences settings\n" );
2747                         break;
2748                 }
2749                 case ( 1 ):
2750                 {
2751                         g_qeglobals.texture_components = GL_COMPRESSED_RGBA;
2752                         Sys_Printf( "OpenGL texture compression enabled\n" );
2753                         break;
2754                 }
2755                 case ( 2 ):
2756                 {
2757                         g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
2758                         Sys_Printf( "S3TC DXT1 texture compression enabled\n" );
2759                         break;
2760                 }
2761                 case ( 3 ):
2762                 {
2763                         g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
2764                         Sys_Printf( "S3TC DXT3 texture compression enabled\n" );
2765                         break;
2766                 }
2767                 case ( 4 ):
2768                 {
2769                         g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
2770                         Sys_Printf( "S3TC DXT5 texture compression enabled\n" );
2771                         break;
2772                 }
2773                 }
2774         }
2775         else
2776         {
2777                 Sys_Printf( "texture compression is not supported by your current graphic card/drivers\n" );
2778                 g_qeglobals.texture_components = GL_RGBA;
2779                 m_nTextureCompressionFormat = 0;
2780         }
2781 }
2782
2783 #ifdef ATIHACK_812
2784 void PrefsDlg::UpdateATIHack() {
2785         // if OpenGL is not ready yet, don't do anything
2786         if ( !g_qeglobals.m_bOpenGLReady ) {
2787                 Sys_Printf( "OpenGL not ready - postpone ATI bug workaround setup\n" );
2788                 return;
2789         }
2790
2791         if ( m_bGlATIHack ) {
2792                 qglCullFace = &qglCullFace_ATIHack;
2793                 qglDisable = &qglDisable_ATIHack;
2794                 qglEnable = &qglEnable_ATIHack;
2795                 qglPolygonMode = &qglPolygonMode_ATIHack;
2796                 Sys_Printf( "ATI bug workaround enabled\n" );
2797         }
2798         else {
2799                 qglCullFace = qglCullFace_real;
2800                 qglDisable = qglDisable_real;
2801                 qglEnable = qglEnable_real;
2802                 qglPolygonMode = qglPolygonMode_real;
2803                 Sys_Printf( "ATI bug workaround disabled\n" );
2804         }
2805 }
2806 #endif
2807
2808 #ifdef NVIDIA_AERO_HACK
2809 void PrefsDlg::UpdateNvidiaAeroHack() {
2810         if ( m_bGlNvidiaAeroHack && m_bGlNvidiaAeroHackPrevState == 1 ) {
2811                 return;
2812         }
2813         if ( ( !m_bGlNvidiaAeroHack ) && m_bGlNvidiaAeroHackPrevState == 0 ) {
2814                 return;
2815         }
2816         if ( ( !m_bGlNvidiaAeroHack ) && m_bGlNvidiaAeroHackPrevState < 0 ) {
2817                 // The hack state is uninitialized, meaning that this is the first call
2818                 // to this function.  I prefer not to explicitly enable composition because
2819                 // the user may have set the application to disable it, and I don't want to
2820                 // override that.  Leave the state of composition as-is if the hack checkbox
2821                 // isn't checked.
2822                 m_bGlNvidiaAeroHackPrevState = 0;
2823                 return;
2824         }
2825         HMODULE lib = LoadLibrary( "dwmapi.dll" );
2826         if ( lib ) {
2827                 void ( WINAPI *qDwmEnableComposition )( bool bEnable ) =
2828                         ( void (WINAPI *) ( bool bEnable ) )GetProcAddress( lib, "DwmEnableComposition" );
2829                 if ( qDwmEnableComposition ) {
2830                         if ( m_bGlNvidiaAeroHack ) {
2831                                 Sys_Printf( "Disabling Windows composition\n" );
2832                                 qDwmEnableComposition( 0 );
2833                                 m_bGlNvidiaAeroHackPrevState = 1;
2834                         }
2835                         else {
2836                                 Sys_Printf( "Enabling Windows composition\n" );
2837                                 qDwmEnableComposition( 1 );
2838                                 m_bGlNvidiaAeroHackPrevState = 0;
2839                         }
2840                 }
2841                 FreeLibrary( lib );
2842         }
2843 }
2844 #endif
2845
2846 // TTimo: m_strEnginePath has a special status, if not found in registry we need to
2847 // initiliaze it for sure. It is not totally failsafe but we can use the same
2848 // code than in q3map, expecting to find some "quake" above us. If not, we prompt
2849 // for the engine executable path
2850 void PrefsDlg::LoadPrefs(){
2851         int i;
2852
2853         // first things first, load prefs from global prefs
2854         mGamesDialog.LoadPrefs();
2855
2856         // if we already have a document loaded, we will free and reload from file
2857         if ( mLocalPrefs.InUse() ) {
2858                 mLocalPrefs.Clear();
2859         }
2860
2861         // load local.pref file
2862         mLocalPrefs.ReadXMLFile( m_inipath->str );
2863
2864         mLocalPrefs.GetPref( PATCHSHOWBOUNDS_KEY,  &g_bPatchShowBounds,  FALSE );
2865         mLocalPrefs.GetPref( MOUSE_KEY,            &m_nMouse,            MOUSE_DEF );
2866         m_nMouseButtons = m_nMouse ? 3 : 2;
2867
2868         // project file
2869         // if it's not found here, mainframe.cpp will take care of finding one
2870         mLocalPrefs.GetPref( LASTPROJ_KEY, &m_strLastProject, "" );
2871         mLocalPrefs.GetPref( LASTPROJVER_KEY, &m_nLastProjectVer, -1 );
2872
2873         // prefab path
2874         // NOTE TTimo: I'm not sure why this is in prefs
2875         // should probably be a project setting
2876         // and I'm not sure that we really have a way to set this reliably either
2877         CString strPrefab;
2878         strPrefab = g_qeglobals.m_strHomeGame.GetBuffer();
2879         strPrefab += g_pGameDescription->mBaseGame.GetBuffer();
2880         strPrefab += "/prefabs/";
2881         mLocalPrefs.GetPref( PREFAB_KEY, &m_strPrefabPath, strPrefab );
2882
2883         mLocalPrefs.GetPref( LASTLIGHTINTENSITY_KEY, &m_iLastLightIntensity, 300 );
2884         mLocalPrefs.GetPref( TLOCK_KEY,              &m_bTextureLock,        TLOCK_DEF );
2885         mLocalPrefs.GetPref( RLOCK_KEY,              &m_bRotateLock,         TLOCK_DEF );
2886         mLocalPrefs.GetPref( LASTMAP_KEY,            &m_strLastMap,          "" );
2887         mLocalPrefs.GetPref( LOADLAST_KEY,           &m_bLoadLast,           LOADLAST_DEF );
2888         mLocalPrefs.GetPref( BSP_KEY,                &m_bInternalBSP,        FALSE );
2889         mLocalPrefs.GetPref( RCLICK_KEY,             &m_bRightClick,         TRUE );
2890         mLocalPrefs.GetPref( AUTOSAVE_KEY,           &m_bAutoSave,           TRUE );
2891         mLocalPrefs.GetPref( LOADLASTMAP_KEY,        &m_bLoadLastMap,        FALSE );
2892         mLocalPrefs.GetPref( TINYBRUSH_KEY,          &m_bCleanTiny,          FALSE );
2893         mLocalPrefs.GetPref( TINYSIZE_KEY,           &m_fTinySize,           0.5f );
2894         mLocalPrefs.GetPref( AUTOSAVETIME_KEY,       &m_nAutoSave,           5 );
2895         mLocalPrefs.GetPref( SNAPSHOT_KEY,           &m_bSnapShots,          FALSE );
2896         mLocalPrefs.GetPref( MOVESPEED_KEY,          &m_nMoveSpeed,          100 );
2897         mLocalPrefs.GetPref( ANGLESPEED_KEY,         &m_nAngleSpeed,         3 );
2898         mLocalPrefs.GetPref( SETGAME_KEY,            &m_bSetGame,            FALSE );
2899         mLocalPrefs.GetPref( CAMXYUPDATE_KEY,        &m_bCamXYUpdate,        TRUE );
2900         mLocalPrefs.GetPref( CAMDRAGMULTISELECT_KEY, &m_nCamDragMultiSelect, TRUE );
2901         mLocalPrefs.GetPref( CAMFREELOOK_KEY,        &m_bCamFreeLook,        TRUE );
2902         mLocalPrefs.GetPref( CAMINVERSEMOUSE_KEY,    &m_bCamInverseMouse,    FALSE );
2903         mLocalPrefs.GetPref( CAMDISCRETE_KEY,        &m_bCamDiscrete,        TRUE );
2904         mLocalPrefs.GetPref( LIGHTDRAW_KEY,          &m_bNewLightDraw,       TRUE );
2905         mLocalPrefs.GetPref( CUBICCLIP_KEY,          &m_bCubicClipping,      TRUE );
2906         mLocalPrefs.GetPref( CUBICSCALE_KEY,         &m_nCubicScale,         13 );
2907         mLocalPrefs.GetPref( ALTEDGE_KEY,            &m_bALTEdge,            FALSE );
2908         mLocalPrefs.GetPref( FACECOLORS_KEY,         &m_bFaceColors,         FALSE );
2909         mLocalPrefs.GetPref( XZVIS_KEY,              &m_bXZVis,              FALSE );
2910         mLocalPrefs.GetPref( YZVIS_KEY,              &m_bYZVis,              FALSE );
2911         mLocalPrefs.GetPref( ZVIS_KEY,               &m_bZVis,               FALSE );
2912         mLocalPrefs.GetPref( SIZEPAINT_KEY,          &m_bSizePaint,                  FALSE );
2913         mLocalPrefs.GetPref( DLLENTITIES_KEY,        &m_bDLLEntities,                FALSE );
2914
2915         mLocalPrefs.GetPref( DETACHABLEMENUS_KEY,    &m_bLatchedDetachableMenus,            TRUE );
2916         m_bDetachableMenus = m_bLatchedDetachableMenus;
2917
2918         if ( g_pGameDescription->mNoPatch ) {
2919                 m_bPatchToolbar = false;
2920         }
2921         else
2922         {
2923                 mLocalPrefs.GetPref( PATCHTOOLBAR_KEY,       &m_bLatchedPatchToolbar,               TRUE );
2924                 m_bPatchToolbar = m_bLatchedPatchToolbar;
2925         }
2926
2927         mLocalPrefs.GetPref( WIDETOOLBAR_KEY,        &m_bLatchedWideToolbar,                TRUE );
2928         m_bWideToolbar = m_bLatchedWideToolbar;
2929
2930         mLocalPrefs.GetPref( PLUGINTOOLBAR_KEY, &m_bLatchedPluginToolbar, TRUE );
2931         m_bPluginToolbar = m_bLatchedPluginToolbar;
2932
2933         mLocalPrefs.GetPref( WINDOW_KEY,             (int*)&m_nLatchedView,  WINDOW_DEF );
2934         m_nView = m_nLatchedView;
2935
2936         mLocalPrefs.GetPref( FLOATINGZ_KEY,          &m_bLatchedFloatingZ,           FALSE );
2937         m_bFloatingZ = m_bLatchedFloatingZ;
2938
2939         mLocalPrefs.GetPref( TEXTUREQUALITY_KEY,     &m_nLatchedTextureQuality,             3 );
2940         m_nTextureQuality = m_nLatchedTextureQuality;
2941
2942         mLocalPrefs.GetPref( LOADSHADERS_KEY,        &m_nLatchedShader,                     0 );
2943         m_nShader = m_nLatchedShader;
2944
2945         mLocalPrefs.GetPref( NOCLAMP_KEY,            &m_bNoClamp,                    FALSE );
2946         mLocalPrefs.GetPref( SNAP_KEY,               &m_bSnap,                       TRUE );
2947         mLocalPrefs.GetPref( USERINI_KEY,            &m_strUserPath,                 "" );
2948         mLocalPrefs.GetPref( ROTATION_KEY,           &m_nRotation,                   45 );
2949         mLocalPrefs.GetPref( CHASEMOUSE_KEY,         &m_bChaseMouse,                 TRUE );
2950         mLocalPrefs.GetPref( ENTITYSHOW_KEY,         &m_nEntityShowState,            ENTITY_SKINNED_BOXED );
2951
2952         // this will probably need to be 75 or 100 for Q1.
2953         mLocalPrefs.GetPref( TEXTURESCALE_KEY,       &m_nTextureScale,               50 );
2954
2955         // FIXME: Hydra - actually, this stuff is Q1,Q2 and HL specific.
2956         if ( ( g_pGameDescription->mGameFile == "hl.game" ) ) {
2957                 // No BSP monitoring in the default compiler tools for Half-life (yet)
2958                 mLocalPrefs.GetPref( WATCHBSP_KEY,           &m_bWatchBSP,                   FALSE );
2959
2960                 // Texture subset on by default (HL specific really, because of halflife.wad's size)
2961                 mLocalPrefs.GetPref( TEXTURE_KEY,            &m_bTextureWindow,              TRUE );
2962         }
2963         else if ( g_pGameDescription->quake2 ) {
2964                 // BSP monitoring is implemented in Quake2 and Heretic2 tools
2965                 mLocalPrefs.GetPref( WATCHBSP_KEY,           &m_bWatchBSP,                   TRUE );
2966
2967                 // Texture subset on by default (HL specific really, because of halflife.wad's size)
2968                 mLocalPrefs.GetPref( TEXTURE_KEY,            &m_bTextureWindow,              TRUE );
2969         }
2970         else
2971         {
2972                 mLocalPrefs.GetPref( WATCHBSP_KEY,           &m_bWatchBSP,                   WATCHBSP_DEF );
2973                 mLocalPrefs.GetPref( TEXTURE_KEY,            &m_bTextureWindow,              FALSE );
2974         }
2975
2976
2977         mLocalPrefs.GetPref( TEXTURESCROLLBAR_KEY,   &m_bTextureScrollbar,           TRUE );
2978         mLocalPrefs.GetPref( DISPLAYLISTS_KEY,       &m_bDisplayLists,               TRUE );
2979         mLocalPrefs.GetPref( ANTIALIASEDLINES_KEY,   &m_bAntialiasedPointsAndLines,  FALSE );
2980         mLocalPrefs.GetPref( SWITCHCLIP_KEY,         &m_bSwitchClip,                 TRUE );
2981         mLocalPrefs.GetPref( SELWHOLEENTS_KEY,       &m_bSelectWholeEntities,        TRUE );
2982         mLocalPrefs.GetPref( SHOWSHADERS_KEY,        &m_bShowShaders,                TRUE );
2983         mLocalPrefs.GetPref( GLLIGHTING_KEY,         &m_bGLLighting,                 FALSE );
2984         mLocalPrefs.GetPref( NOSTIPPLE_KEY,          &m_bNoStipple,                  FALSE );
2985         mLocalPrefs.GetPref( UNDOLEVELS_KEY,         &m_nUndoLevels,                 30 );
2986         mLocalPrefs.GetPref( VERTEXMODE_KEY,         &m_bVertexSplit,                TRUE );
2987         mLocalPrefs.GetPref( RUNQ2_KEY,              &m_bRunQuake,                   RUNQ2_DEF );
2988         mLocalPrefs.GetPref( LEAKSTOP_KEY,           &m_bLeakStop,                   TRUE );
2989         mLocalPrefs.GetPref( DOSLEEP_KEY,            &m_bDoSleep,                    FALSE );
2990         mLocalPrefs.GetPref( SELECTCURVES_KEY,       &m_bSelectCurves,               TRUE );
2991         mLocalPrefs.GetPref( SELECTMODELS_KEY,       &m_bSelectModels,               TRUE );
2992         mLocalPrefs.GetPref( SHADERLISTONLY_KEY,     &m_bTexturesShaderlistOnly,     FALSE );
2993         mLocalPrefs.GetPref( DEFAULTTEXURESCALE_KEY, &m_fDefTextureScale,            g_pGameDescription->mTextureDefaultScale );
2994         mLocalPrefs.GetPref( SUBDIVISIONS_KEY,       &m_nSubdivisions,               SUBDIVISIONS_DEF );
2995         mLocalPrefs.GetPref( CLIPCAULK_KEY,          &m_bClipCaulk,                  FALSE );
2996         mLocalPrefs.GetPref( SNAPTTOGRID_KEY,        &m_bSnapTToGrid,                FALSE );
2997         mLocalPrefs.GetPref( TARGETFIX_KEY,          &m_bDoTargetFix,                TRUE );
2998         mLocalPrefs.GetPref( WHEELINC_KEY,           &m_nWheelInc,                   64 );
2999         mLocalPrefs.GetPref( PATCHBBOXSEL_KEY,       &m_bPatchBBoxSelect,            FALSE );
3000
3001         // Gef: Kyro GL_POINT workaround
3002         mLocalPrefs.GetPref( GLPOINTWORKAROUND_KEY,  &m_bGlPtWorkaround,             FALSE );
3003
3004         // window positioning
3005         mLocalPrefs.GetPref( ENTITYSPLIT1_KEY,       &mWindowInfo.nEntitySplit1,     -1 );
3006         mLocalPrefs.GetPref( ENTITYSPLIT2_KEY,       &mWindowInfo.nEntitySplit2,     -1 );
3007
3008         mLocalPrefs.GetPref( POSITIONX_KEY,          &mWindowInfo.position.x,        -1 );
3009         mLocalPrefs.GetPref( POSITIONY_KEY,          &mWindowInfo.position.y,        -1 );
3010         mLocalPrefs.GetPref( WIDTH_KEY,              &mWindowInfo.position.w,        -1 );
3011         mLocalPrefs.GetPref( HEIGHT_KEY,             &mWindowInfo.position.h,        450 );
3012
3013         const window_position_t default_window_pos = { 0, 0, 200, 200, };
3014
3015         mLocalPrefs.GetPref( ENTITYWND_KEY,          &mWindowInfo.posEntityWnd,      default_window_pos );
3016         mLocalPrefs.GetPref( MAPINFOWND_KEY,         &mWindowInfo.posMapInfoWnd,     default_window_pos );
3017         mLocalPrefs.GetPref( CAMWND_KEY,             &mWindowInfo.posCamWnd,         default_window_pos );
3018         mLocalPrefs.GetPref( ZWND_KEY,               &mWindowInfo.posZWnd,           default_window_pos );
3019         mLocalPrefs.GetPref( XYWND_KEY,              &mWindowInfo.posXYWnd,          default_window_pos );
3020         mLocalPrefs.GetPref( YZWND_KEY,              &mWindowInfo.posYZWnd,          default_window_pos );
3021         mLocalPrefs.GetPref( XZWND_KEY,              &mWindowInfo.posXZWnd,          default_window_pos );
3022         mLocalPrefs.GetPref( PATCHWND_KEY,           &mWindowInfo.posPatchWnd,       default_window_pos );
3023         mLocalPrefs.GetPref( SURFACEWND_KEY,         &mWindowInfo.posSurfaceWnd,     default_window_pos );
3024         mLocalPrefs.GetPref( ENTITYINFOWND_KEY,      &mWindowInfo.posEntityInfoWnd,  default_window_pos );
3025
3026         mLocalPrefs.GetPref( ZWIDTH_KEY,             &mWindowInfo.nZWidth,           30 );
3027         mLocalPrefs.GetPref( XYHEIGHT_KEY,           &mWindowInfo.nXYHeight,         300 );
3028         mLocalPrefs.GetPref( XYWIDTH_KEY,            &mWindowInfo.nXYWidth,          300 );
3029         mLocalPrefs.GetPref( CAMWIDTH_KEY,           &mWindowInfo.nCamWidth,         200 );
3030         mLocalPrefs.GetPref( CAMHEIGHT_KEY,          &mWindowInfo.nCamHeight,        200 );
3031         mLocalPrefs.GetPref( ZFLOATWIDTH_KEY,        &mWindowInfo.nZFloatWidth,      300 );
3032 #ifdef _WIN32
3033         mLocalPrefs.GetPref( STATE_KEY,              &mWindowInfo.nState,            SW_SHOW );
3034 #endif
3035
3036         // menu stuff
3037         mLocalPrefs.GetPref( COUNT_KEY,              &m_nMRUCount,                   0 );
3038         for ( i = 0; i < 4; i++ )
3039         {
3040                 char buf[64];
3041                 sprintf( buf, "%s%d", FILE_KEY, i );
3042                 mLocalPrefs.GetPref( buf,                  &m_strMRUFiles[i],              "" );
3043         }
3044
3045         // some platform specific prefs
3046 #ifdef _WIN32
3047         mLocalPrefs.GetPref( NATIVEGUI_KEY,          &m_bNativeGUI,                  TRUE );
3048         mLocalPrefs.GetPref( STARTONPRIMMON_KEY,     &m_bStartOnPrimMon,             FALSE );
3049 #endif
3050
3051         mLocalPrefs.GetPref( SI_TEXMENU_KEY,         &g_qeglobals.d_savedinfo.iTexMenu,                ID_VIEW_BILINEARMIPMAP );
3052         mLocalPrefs.GetPref( SI_GAMMA_KEY,           &g_qeglobals.d_savedinfo.fGamma,                  1.0f );
3053         mLocalPrefs.GetPref( SI_EXCLUDE_KEY,         &g_qeglobals.d_savedinfo.exclude,                 0 ); // nothing filtered by default
3054         mLocalPrefs.GetPref( SI_INCLUDE_KEY,         &g_qeglobals.d_savedinfo.include,                 INCLUDE_NAMES | INCLUDE_COORDS | INCLUDE_ANGLES | INCLUDE_CAMERATINT );
3055         mLocalPrefs.GetPref( SI_SHOWNAMES_KEY,       &g_qeglobals.d_savedinfo.show_names,              FALSE );
3056         mLocalPrefs.GetPref( SI_SHOWCOORDS_KEY,      &g_qeglobals.d_savedinfo.show_coordinates,        TRUE );
3057         mLocalPrefs.GetPref( SI_SHOWANGLES_KEY,      &g_qeglobals.d_savedinfo.show_angles,             TRUE );
3058         mLocalPrefs.GetPref( SI_SHOWOUTLINES_KEY,    &g_qeglobals.d_savedinfo.show_outline,            FALSE );
3059         mLocalPrefs.GetPref( SI_SHOWAXIS_KEY,        &g_qeglobals.d_savedinfo.show_axis,               TRUE );
3060         mLocalPrefs.GetPref( SI_NOSELOUTLINES_KEY,   &g_qeglobals.d_savedinfo.bNoSelectedOutlines,     FALSE );
3061
3062         mLocalPrefs.GetPref( SI_OUTLINESTYLE_KEY,   &g_qeglobals.d_savedinfo.iSelectedOutlinesStyle,  OUTLINE_ZBUF | OUTLINE_BSEL );
3063
3064         LoadTexdefPref( &g_qeglobals.d_savedinfo.m_SIIncrement, SI_SURFACE_TEXDEF_KEY );
3065         LoadTexdefPref( &g_qeglobals.d_savedinfo.m_PIIncrement, SI_PATCH_TEXDEF_KEY );
3066
3067         // text editor binding
3068 #ifdef _WIN32
3069         mLocalPrefs.GetPref( CUSTOMSHADEREDITOR_KEY, &m_bUseWin32Editor, TRUE );
3070 #else
3071         mLocalPrefs.GetPref( CUSTOMSHADEREDITOR_KEY, &m_bUseCustomEditor, FALSE );
3072         mLocalPrefs.GetPref( CUSTOMSHADEREDITORCOMMAND_KEY, &m_strEditorCommand, "" );
3073 #endif
3074
3075
3076         vec3_t vDefaultAxisColours[3] = {
3077                 {0.f, 0.5f, 0.f},
3078                 {0.f, 0.f, 1.f},
3079                 {1.f, 0.f, 0.f},
3080         };
3081
3082         for ( i = 0; i < 3; i++ ) {
3083                 char buf[64];
3084                 sprintf( buf, "%s%d", SI_AXISCOLORS_KEY, i );
3085                 mLocalPrefs.GetPref( buf,   g_qeglobals.d_savedinfo.AxisColors[i], vDefaultAxisColours[i] );
3086         }
3087
3088         vec3_t vDefaultColours[COLOR_LAST] = {
3089                 {0.25f, 0.25f,  0.25f},
3090                 {1.f,   1.f,    1.f},
3091                 {0.75f, 0.75f,  0.75f},
3092                 {0.5f,  0.5f,   0.5f},
3093                 {0.25f, 0.25f,  0.25f},
3094                 {0.0f,  0.0f,   0.0f},
3095                 {0.f,   0.f,    1.f},
3096                 {0.f,   0.f,    0.f},
3097                 {0.f,   0.f,    0.f},
3098                 {1.f,   0.f,    0.f},
3099                 {0.f,   0.f,    1.f},
3100                 {0.5f,  0.f,    0.75f},
3101                 {1.0f,  0.f,    0.f},
3102                 {0.f,   0.f,    0.f},
3103                 {0.f,   0.f,    0.f},
3104         };
3105
3106         for ( i = 0; i < COLOR_LAST; i++ ) {
3107                 char buf[64];
3108                 sprintf( buf, "%s%d", SI_COLORS_KEY, i );
3109                 mLocalPrefs.GetPref( buf,   g_qeglobals.d_savedinfo.colors[i], vDefaultColours[i] );
3110         }
3111
3112         mLocalPrefs.GetPref( TEXTURECOMPRESSIONFORMAT_KEY, &m_nTextureCompressionFormat, 1 );
3113
3114         mLocalPrefs.GetPref( LIGHTRADIUS_KEY, &m_nLightRadiuses, TRUE );
3115
3116         mLocalPrefs.GetPref( Q3MAP2TEX_KEY, &m_bQ3Map2Texturing, TRUE );
3117
3118 #ifdef ATIHACK_812
3119         mLocalPrefs.GetPref( ATIHACK_KEY, &m_bGlATIHack, FALSE );
3120 #endif
3121
3122 #ifdef NVIDIA_AERO_HACK
3123         mLocalPrefs.GetPref( NVAEROHACK_KEY, &m_bGlNvidiaAeroHack, TRUE );
3124 #endif
3125
3126         Undo_SetMaxSize( m_nUndoLevels ); // set it internally as well / FIXME: why not just have one global value?
3127
3128         UpdateTextureCompression();
3129
3130 #ifdef ATIHACK_812
3131         UpdateATIHack();
3132 #endif
3133
3134 #ifdef NVIDIA_AERO_HACK
3135         UpdateNvidiaAeroHack();
3136 #endif
3137
3138         if ( mLocalPrefs.mbEmpty ) {
3139                 mLocalPrefs.mbEmpty = false;
3140                 Sys_Printf( "Saving local.pref with default pref values\n" );
3141                 SavePrefs();
3142         }
3143 }
3144
3145 void PrefsDlg::SavePrefs(){
3146         if ( g_qeglobals.disable_ini ) {
3147                 return;
3148         }
3149
3150 #ifdef _DEBUG
3151         Sys_Printf( "PrefsDlg::SavePrefs\n" );
3152 #endif
3153
3154         // this will take care of copying back from the dialog to the variables
3155         // NOTE: it may be overkill to call systematically before a SavePrefs, but it's safer
3156         // this will also cause an UpdateData for the mGamesDialog
3157         UpdateData( TRUE );
3158
3159         mGamesDialog.SavePrefs();
3160
3161         // update the tree and save it
3162         mLocalPrefs.UpdatePrefTree();
3163         if ( !mLocalPrefs.WriteXMLFile( m_inipath->str ) ) {
3164                 Sys_FPrintf( SYS_ERR, "Error occured while saving local prefs file '%s'\n", m_inipath->str );
3165         }
3166
3167         if ( m_nMouse == 0 ) {
3168                 m_nMouseButtons = 2;
3169         }
3170         else {
3171                 m_nMouseButtons = 3;
3172         }
3173
3174 }
3175
3176 void PrefsDlg::PostModal( int code ){
3177         if ( code == IDOK ) {
3178                 SavePrefs();
3179                 // make sure the logfile is ok
3180                 Sys_LogFile();
3181 #ifdef ATIHACK_812
3182                 UpdateATIHack();
3183 #endif
3184 #ifdef NVIDIA_AERO_HACK
3185                 UpdateNvidiaAeroHack();
3186 #endif
3187                 if ( g_pParentWnd ) {
3188                         g_pParentWnd->SetGridStatus();
3189                 }
3190                 Sys_UpdateWindows( W_ALL );
3191                 if ( m_nUndoLevels != 0 ) {
3192                         Undo_SetMaxSize( m_nUndoLevels );
3193                 }
3194         }
3195 }
3196
3197 void PrefsDlg::DoEditorSensitivity(){
3198         if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( m_pWidget ), "check_customeditor" ) ) ) ) {
3199                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "label_customeditor" ) ), TRUE );
3200                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "entry_customeditor" ) ), TRUE );
3201                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "button_customeditor" ) ), TRUE );
3202         }
3203         else
3204         {
3205                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "label_customeditor" ) ), FALSE );
3206                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "entry_customeditor" ) ), FALSE );
3207                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "button_customeditor" ) ), FALSE );
3208         }
3209 }
3210
3211 void PrefsDlg::DoSensitivity(){
3212 #if 0
3213         // first, look at the project file version ... will monitoring work?
3214         // project files now XML, guaranteed to be at least version 2
3215         if ( 0 ) { //IntForKey( g_qeglobals.d_project_entity, "version" ) < 2)
3216                 if ( m_bWarn ) {
3217                         Str Msg;
3218                         Msg = "The current project file (";
3219                         Msg += g_PrefsDlg.m_strLastProject;
3220                         Msg += ") is not at least version 2.\nI need version 2 or above to setup BSP monitoring correctly.";
3221                         gtk_MessageBox( m_pWidget, Msg.GetBuffer(), MB_OK );
3222
3223                         m_bWarn = false;
3224                 }
3225
3226                 // go ahead, disable everybuddy
3227                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_leakstop" ) ), FALSE );
3228                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_monitorbsp" ) ), FALSE );
3229                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ), FALSE );
3230                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), FALSE );
3231         }
3232         else
3233         {
3234 #endif
3235 //    m_bWarn = true;
3236
3237         gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_leakstop" ) ), TRUE );
3238         gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_monitorbsp" ) ), TRUE );
3239         gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ), TRUE );
3240         gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), TRUE );
3241
3242         if ( !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( m_pWidget ), "check_monitorbsp" ) ) ) ) {
3243                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_leakstop" ) ), FALSE );
3244                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ), FALSE );
3245                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), FALSE );
3246         }
3247         else if ( !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( m_pWidget ), "check_runengine" ) ) ) ) {
3248                 gtk_widget_set_sensitive( GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "check_sleep" ) ), FALSE );
3249         }
3250 }
3251
3252 /*
3253    ============================================================
3254    CGameInstall
3255    ============================================================
3256  */
3257
3258 CGameInstall::CGameInstall() {
3259         memset( m_availGames, 0, sizeof( m_availGames ) );
3260 }
3261
3262 void CGameInstall::OnBtnBrowseEngine( GtkWidget *widget, gpointer data ) {
3263         Sys_Printf( "OnBtnBrowseEngine\n" );
3264
3265         CGameInstall* i = static_cast<CGameInstall*>( data );
3266         char *dir = dir_dialog( i->m_pWidget, _( "Select game directory" ), NULL );
3267
3268         i->UpdateData( TRUE );
3269
3270         if ( dir != NULL ) {
3271                 i->m_strEngine = dir;
3272                 i->UpdateData( FALSE );
3273                 g_free( dir );
3274         }
3275 }
3276
3277 void CGameInstall::OnGameSelectChanged( GtkWidget *widget, gpointer data ) {
3278         Sys_Printf( "OnGameSelectChanged\n" );
3279
3280         CGameInstall* i = static_cast<CGameInstall*>( data );
3281         i->UpdateData( TRUE );
3282         i->m_strName = gtk_combo_box_get_active_text( GTK_COMBO_BOX( widget ) );
3283         i->UpdateData( FALSE );
3284 }
3285
3286 void CGameInstall::BuildDialog() {
3287         GtkWidget *dlg, *vbox1, *button, *text, *combo, *entry, *hbox;
3288
3289         dlg = m_pWidget;
3290         gtk_window_set_title( GTK_WINDOW( dlg ), _( "Configure games" ) );
3291
3292         vbox1 = gtk_vbox_new( FALSE, 0 );
3293         gtk_widget_show( vbox1 );
3294         gtk_container_add( GTK_CONTAINER( dlg ), vbox1 );
3295
3296         text = gtk_label_new( _( "Select the game to configure" ) );
3297         gtk_widget_show( text );
3298         gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 );
3299
3300         combo = gtk_combo_box_new_text();
3301         gtk_widget_show( combo );
3302         gtk_box_pack_start( GTK_BOX( vbox1 ), combo, FALSE, FALSE, 0 );
3303
3304         //      GList *combo_list = NULL;
3305         int iGame = 0;
3306         while ( m_availGames[ iGame ] != GAME_NONE ) {
3307                 switch ( m_availGames[ iGame ] ) {
3308                 case GAME_Q2:
3309                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Quake II" ) );
3310                         break;
3311                 case GAME_Q3:
3312                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Quake III Arena and mods" ) );
3313                         break;
3314                 case GAME_URT:
3315                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Urban Terror (standalone)" ) );
3316                         break;
3317                 case GAME_UFOAI:
3318                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "UFO: Alien Invasion" ) );
3319                         break;
3320                 case GAME_Q2W:
3321                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Quake2World" ) );
3322                         break;
3323                 case GAME_WARSOW:
3324                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Warsow" ) );
3325                         break;
3326                 case GAME_NEXUIZ:
3327                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Nexuiz" ) );
3328                         break;
3329                 case GAME_TREMULOUS:
3330                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Tremulous" ) );
3331                         break;
3332                 case GAME_JA:
3333                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Jedi Academy and mods" ) );
3334                         break;
3335                 case GAME_REACTION:
3336                         gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Reaction Quake 3" ) );
3337                         break;
3338                 }
3339                 iGame++;
3340         }
3341         AddDialogData( combo, &m_nComboSelect, DLG_COMBO_BOX_INT );
3342         gtk_signal_connect( GTK_OBJECT( combo ), "changed", G_CALLBACK( OnGameSelectChanged ), this );
3343         gtk_combo_box_set_active( GTK_COMBO_BOX( combo ), 0 );  // NOTE: will trigger signal
3344
3345         text = gtk_label_new( _( "Name:" ) );
3346         gtk_widget_show( text );
3347         gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 );
3348
3349         entry = gtk_entry_new();
3350         gtk_widget_show( entry );
3351         gtk_box_pack_start( GTK_BOX( vbox1 ), entry, FALSE, FALSE, 0 );
3352         AddDialogData( entry, &m_strName, DLG_ENTRY_TEXT );
3353
3354         text = gtk_label_new( _( "Engine directory:" ) );
3355         gtk_widget_show( text );
3356         gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 );
3357
3358         hbox = gtk_hbox_new( FALSE, 0 );
3359         gtk_widget_show( hbox );
3360         gtk_box_pack_start( GTK_BOX( vbox1 ), hbox, FALSE, FALSE, 0 );
3361
3362         entry = gtk_entry_new();
3363         gtk_widget_show( entry );
3364         gtk_box_pack_start( GTK_BOX( hbox ), entry, FALSE, FALSE, 0 );
3365         AddDialogData( entry, &m_strEngine, DLG_ENTRY_TEXT );
3366
3367         button = gtk_button_new_with_label( _( "..." ) );
3368         gtk_widget_show( button );
3369         gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( OnBtnBrowseEngine ), this );
3370         gtk_box_pack_start( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
3371
3372         // this gets done in the project stuff atm
3373 #if 0
3374         text = gtk_label_new( _( "Mod subdirectory:" ) );
3375         gtk_widget_show( text );
3376         gtk_box_pack_start( GTK_BOX( vbox1 ), text, FALSE, FALSE, 0 );
3377
3378         entry = gtk_entry_new();
3379         gtk_widget_show( entry );
3380         gtk_box_pack_start( GTK_BOX( vbox1 ), entry, FALSE, FALSE, 0 );
3381         AddDialogData( entry, &m_strMod, DLG_ENTRY_TEXT );
3382 #endif
3383
3384         button = gtk_button_new_with_label( _( "OK" ) );
3385         gtk_widget_show( button );
3386         gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
3387         AddModalButton( button, IDOK );
3388
3389         button = gtk_button_new_with_label( _( "Cancel" ) );
3390         gtk_widget_show( button );
3391         gtk_box_pack_start( GTK_BOX( vbox1 ), button, FALSE, FALSE, 0 );
3392         AddModalButton( button, IDCANCEL );
3393
3394         gtk_widget_set_usize( button, 60, -2 );
3395 }
3396
3397 void CGameInstall::Run() {
3398         ScanGames();
3399         if ( m_availGames[0] == GAME_NONE ) {
3400                 return;
3401         }
3402         if ( DoModal() == IDCANCEL ) {
3403                 Sys_Printf( "game dialog cancelled\n" );
3404                 return;
3405         }
3406         Sys_Printf( "combo: %d name: %s engine: %s mod: %s\n", m_nComboSelect, m_strName.GetBuffer(), m_strEngine.GetBuffer(), m_strMod.GetBuffer() );
3407
3408         // write out the game file
3409         Str gameFilePath = g_strAppPath.GetBuffer();
3410         gameFilePath += "games/";
3411         if(CheckFile(gameFilePath) != PATH_DIRECTORY) {
3412                 radCreateDirectory(gameFilePath);
3413         }
3414         gameFilePath += m_strName.GetBuffer();
3415         gameFilePath += ".game";
3416         Sys_Printf( "game file: %s\n", gameFilePath.GetBuffer() );
3417
3418         FILE * fg = fopen( gameFilePath.GetBuffer(), "w" );
3419         if ( fg == NULL ) {
3420                 Error( "Failed to open %s for writing\n", gameFilePath.GetBuffer() );
3421         }
3422         fprintf( fg, "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"yes\"?>\n<game\n" );
3423         fprintf( fg, "  name=\"%s\"\n", m_strName.GetBuffer() );
3424         fprintf( fg, "  "ENGINEPATH_ATTRIBUTE "=\"%s\"\n", m_strEngine.GetBuffer() );
3425         switch ( m_availGames[ m_nComboSelect ] ) {
3426         case GAME_Q2: {
3427                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/Quake2Pack/game\"\n", g_strAppPath.GetBuffer() );
3428                 fprintf( fg, "  prefix=\".quake2\"\n" );
3429                 Str source = g_strAppPath.GetBuffer();
3430                 source += "installs/";
3431                 source += Q2_PACK;
3432                 source += "/install/";
3433                 Str dest = m_strEngine.GetBuffer();
3434                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3435                 fprintf( fg, "  basegame=\"baseq2\"\n" );
3436                 break;
3437         }
3438         case GAME_Q3: {
3439                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/Q3Pack/game\"\n", g_strAppPath.GetBuffer() );
3440                 fprintf( fg, "  prefix=\".q3a\"\n" );
3441                 Str source = g_strAppPath.GetBuffer();
3442                 source += "installs/";
3443                 source += Q3_PACK;
3444                 source += "/install/";
3445                 Str dest = m_strEngine.GetBuffer();
3446                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3447                 // Hardcoded fix for "missing" shaderlist in gamepack
3448                 dest += "/baseq3/scripts/shaderlist.txt";
3449                 if(CheckFile(dest.GetBuffer()) != PATH_FILE) {
3450                         source += "baseq3/scripts/default_shaderlist.txt";
3451                         radCopyFile(source.GetBuffer(),dest.GetBuffer());
3452                 }
3453                 fprintf( fg, "  basegame=\"baseq3\"\n" );
3454                 break;
3455         }
3456         case GAME_URT: {
3457                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/UrTPack/game\"\n", g_strAppPath.GetBuffer() );
3458                 fprintf( fg, "  prefix=\".q3a\"\n" );
3459                 Str source = g_strAppPath.GetBuffer();
3460                 source += "installs/";
3461                 source += URT_PACK;
3462                 source += "/install/";
3463                 Str dest = m_strEngine.GetBuffer();
3464                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3465                 fprintf( fg, "  basegame=\"q3ut4\"\n" );
3466                 break;
3467         }
3468         case GAME_UFOAI: {
3469                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/UFOAIPack/game\"\n", g_strAppPath.GetBuffer() );
3470                 fprintf( fg, "  prefix=\".ufoai\"\n" );
3471                 Str source = g_strAppPath.GetBuffer();
3472                 source += "installs/";
3473                 source += UFOAI_PACK;
3474                 source += "/install/";
3475                 Str dest = m_strEngine.GetBuffer();
3476                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3477                 fprintf( fg, "  basegame=\"base\"\n" );
3478                 break;
3479         }
3480         case GAME_Q2W: {
3481                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/Q2WPack/game\"\n", g_strAppPath.GetBuffer() );
3482                 fprintf( fg, "  prefix=\".quake2world\"\n" );
3483                 Str source = g_strAppPath.GetBuffer();
3484                 source += "installs/";
3485                 source += Q2W_PACK;
3486                 source += "/install/";
3487                 Str dest = m_strEngine.GetBuffer();
3488                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3489                 fprintf( fg, "  basegame=\"default\"\n" );
3490                 break;
3491         }
3492         case GAME_WARSOW: {
3493                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/WarsowPack/game\"\n", g_strAppPath.GetBuffer() );
3494                 fprintf( fg, "  prefix=\".warsow\"\n" );
3495                 Str source = g_strAppPath.GetBuffer();
3496                 source += "installs/";
3497                 source += WARSOW_PACK;
3498                 source += "/install/";
3499                 Str dest = m_strEngine.GetBuffer();
3500                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3501                 fprintf( fg, "  basegame=\"basewsw\"\n" );
3502                 break;
3503         }
3504         case GAME_NEXUIZ: {
3505                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/NexuizPack/game\"\n", g_strAppPath.GetBuffer() );
3506                 fprintf( fg, "  prefix=\".nexuiz\"\n" );
3507                 Str source = g_strAppPath.GetBuffer();
3508                 source += "installs/";
3509                 source += NEXUIZ_PACK;
3510                 source += "/install/";
3511                 Str dest = m_strEngine.GetBuffer();
3512                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3513                 fprintf( fg, "  basegame=\"data\"\n" );
3514                 break;
3515         }
3516         case GAME_TREMULOUS: {
3517                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/TremulousPack/game\"\n", g_strAppPath.GetBuffer() );
3518                 fprintf( fg, "  prefix=\".tremulous\"\n" );
3519                 Str source = g_strAppPath.GetBuffer();
3520                 source += "installs/";
3521                 source += TREMULOUS_PACK;
3522                 source += "/install/";
3523                 Str dest = m_strEngine.GetBuffer();
3524                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3525                 fprintf( fg, "  basegame=\"base\"\n" );
3526                 break;
3527         }
3528         case GAME_JA: {
3529                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/JAPack/game\"\n", g_strAppPath.GetBuffer() );
3530                 fprintf( fg, "  prefix=\".ja\"\n" );
3531                 Str source = g_strAppPath.GetBuffer();
3532                 source += "installs/";
3533                 source += JA_PACK;
3534                 source += "/install/";
3535                 Str dest = m_strEngine.GetBuffer();
3536                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3537                 fprintf( fg, "  basegame=\"base\"\n" );
3538                 break;
3539         }
3540         case GAME_REACTION: {
3541                 fprintf( fg, "  "TOOLS_ATTRIBUTE "=\"%sinstalls/"REACTION_PACK "/game\"\n", g_strAppPath.GetBuffer() );
3542                 fprintf( fg, "  prefix=\".Reaction\"\n" );
3543                 Str source = g_strAppPath.GetBuffer();
3544                 source += "installs/";
3545                 source += REACTION_PACK;
3546                 source += "/install/";
3547                 Str dest = m_strEngine.GetBuffer();
3548                 CopyTree( source.GetBuffer(), dest.GetBuffer() );
3549                 fprintf( fg, "  basegame=\"Boomstick\"\n" );
3550                 fprintf( fg, "  default_scale=\"0.5\"\n" ); // Superfluous because the default is already 0.5,
3551                 // but demonstrates how to set the default texture scale
3552                 // for a specific game.
3553                 break;
3554         }
3555         }
3556         fprintf( fg, "/>\n" );
3557         fclose( fg );
3558 }
3559
3560 /*
3561    ===============
3562    CGameInstall::ScanGames
3563    scan for active games that can be installed, based on the presence
3564    ===============
3565  */
3566 void CGameInstall::ScanGames() {
3567         Str pakPaths = g_strAppPath.GetBuffer();
3568         int iGame = 0;
3569         const char      *dirname;
3570
3571         pakPaths += "installs/";
3572         FindFiles fileScan( pakPaths.GetBuffer() );
3573         while ( ( dirname = fileScan.NextFile() ) != NULL ) {
3574                 if ( stricmp( dirname, Q3_PACK ) == 0 ) {
3575                         m_availGames[ iGame++ ] = GAME_Q3;
3576                 }
3577                 if ( stricmp( dirname, URT_PACK ) == 0 ) {
3578                         m_availGames[ iGame++ ] = GAME_URT;
3579                 }
3580                 if ( stricmp( dirname, UFOAI_PACK ) == 0 ) {
3581                         m_availGames[ iGame++ ] = GAME_UFOAI;
3582                 }
3583                 if ( stricmp( dirname, Q2W_PACK ) == 0 ) {
3584                         m_availGames[ iGame++ ] = GAME_Q2W;
3585                 }
3586                 if ( stricmp( dirname, WARSOW_PACK ) == 0 ) {
3587                         m_availGames[ iGame++ ] = GAME_WARSOW;
3588                 }
3589                 if ( stricmp( dirname, NEXUIZ_PACK ) == 0 ) {
3590                         m_availGames[ iGame++ ] = GAME_NEXUIZ;
3591                 }
3592                 if ( stricmp( dirname, Q2_PACK ) == 0 ) {
3593                         m_availGames[ iGame++ ] = GAME_Q2;
3594                 }
3595                 if ( stricmp( dirname, TREMULOUS_PACK ) == 0 ) {
3596                         m_availGames[ iGame++ ] = GAME_TREMULOUS;
3597                 }
3598                 if ( stricmp( dirname, JA_PACK ) == 0 ) {
3599                         m_availGames[ iGame++ ] = GAME_JA;
3600                 }
3601                 if ( stricmp( dirname, REACTION_PACK ) == 0 ) {
3602                         m_availGames[ iGame++ ] = GAME_REACTION;
3603                 }
3604         }
3605         Sys_Printf( "No installable games found in: %s\n",
3606                                 pakPaths.GetBuffer() );
3607 }