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