X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=radiant%2Fqe3.cpp;h=809df39ca4107dc7bd607124a8811ce86993bcec;hp=3277bb01bbadad4b46ceb941cadf6946299edada;hb=cfc38f86f878d79656aba515838cb75cf5a371f6;hpb=b1bfb19ecd5ec8355065b2028a6de0c850197b2d diff --git a/radiant/qe3.cpp b/radiant/qe3.cpp index 3277bb01..809df39c 100644 --- a/radiant/qe3.cpp +++ b/radiant/qe3.cpp @@ -1,23 +1,30 @@ /* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. + Copyright (C) 1999-2006 Id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + The following source code is licensed by Id Software and subject to the terms of + its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with + GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT, + please contact Id Software immediately at info@idsoftware.com. + */ // // Linux stuff @@ -25,1773 +32,348 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // Leonardo Zide (leo@lokigames.com) // -#include "stdafx.h" -#include -#include -#include "gtkmisc.h" -#if defined (__linux__) || defined (__APPLE__) -#include -#include -#include -#include -#endif -// for the logging part -#include -#include - -QEGlobals_t g_qeglobals; -QEGlobals_GUI_t g_qeglobals_gui; - -// leo: Track memory allocations for debugging -// NOTE TTimo this was never used and probably not relevant -// there are tools to do that -#ifdef MEM_DEBUG +#include "qe3.h" +#include "globaldefs.h" -static GList *memblocks; +#include -void* debug_malloc (size_t size, const char* file, int line) -{ - void *buf = g_malloc (size + 8); +#include "debugging/debugging.h" - *((const char**)buf) = file; - buf = (char*)buf + 4; - *((int*)buf) = line; - buf = (char*)buf + 4; +#include "ifilesystem.h" +//#include "imap.h" - memblocks = g_list_append (memblocks, buf); +#include - return buf; -} - -void debug_free (void *buf, const char* file, int line) -{ - const char *f; - int l; +#include - if (g_list_find (memblocks, buf)) - { - memblocks = g_list_remove (memblocks, buf); +#include "stream/textfilestream.h" +#include "cmdlib.h" +#include "stream/stringstream.h" +#include "os/path.h" +#include "scenelib.h" - buf = (char*)buf - 4; - l = *((int*)buf); - buf = (char*)buf - 4; - f = *((const char**)buf); +#include "gtkutil/messagebox.h" +#include "error.h" +#include "map.h" +#include "build.h" +#include "points.h" +#include "camwindow.h" +#include "mainframe.h" +#include "preferences.h" +#include "watchbsp.h" +#include "autosave.h" +#include "convert.h" - Sys_FPrintf (SYS_DBG, "free: %s %d", file, line); - Sys_FPrintf (SYS_DBG, " allocated: %s %d\n", f, l); +QEGlobals_t g_qeglobals; - g_free (buf); - } -// else -// free (buf); // from qmalloc, will leak unless we add this same hack to cmdlib -} +#if GDEF_OS_WINDOWS +#define PATH_MAX 260 #endif -vec_t Rad_rint (vec_t in) -{ - if (g_PrefsDlg.m_bNoClamp) - return in; - else - return (float)floor (in + 0.5); -} -void WINAPI QE_CheckOpenGLForErrors(void) -{ - char strMsg[1024]; - int i = qglGetError(); - if (i != GL_NO_ERROR) - { - if (i == GL_OUT_OF_MEMORY) - { - sprintf(strMsg, "OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString((GLenum)i)); - if (gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg, "Radiant Error", MB_YESNO) == IDYES) - { - Map_SaveFile(NULL, false); - } - _exit(1); - } - else - { - Sys_Printf ("Warning: OpenGL Error %s\n", qgluErrorString((GLenum)i)); - } - } -} +void QE_InitVFS(){ + // VFS initialization ----------------------- + // we will call GlobalFileSystem().initDirectory, giving the directories to look in (for files in pk3's and for standalone files) + // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order + // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too + + const char* gamename = gamename_get(); + const char* basegame = basegame_get(); + const char* userRoot = g_qeglobals.m_userEnginePath.c_str(); + const char* globalRoot = EnginePath_get(); + + // if we have a mod dir + if ( !string_equal( gamename, basegame ) ) { + // ~/./ + if ( userRoot && !g_disableHomePath ) { + StringOutputStream userGamePath( 256 ); + userGamePath << userRoot << gamename << '/'; + GlobalFileSystem().initDirectory( userGamePath.c_str() ); + } -// NOTE: don't this function, use VFS instead -char *ExpandReletivePath (char *p) -{ - static char temp[1024]; - const char *base; + // / + if ( !g_disableEnginePath ) { + StringOutputStream globalGamePath( 256 ); + globalGamePath << globalRoot << gamename << '/'; + GlobalFileSystem().initDirectory( globalGamePath.c_str() ); + } + } - if (!p || !p[0]) - return NULL; - if (p[0] == '/' || p[0] == '\\') - return p; + // ~/./ + if ( userRoot && !g_disableHomePath ) { + StringOutputStream userBasePath( 256 ); + userBasePath << userRoot << basegame << '/'; + GlobalFileSystem().initDirectory( userBasePath.c_str() ); + } - base = ValueForKey(g_qeglobals.d_project_entity, "basepath"); - sprintf (temp, "%s/%s", base, p); - return temp; -} + // / + if ( !g_disableEnginePath ) { + StringOutputStream globalBasePath( 256 ); + globalBasePath << globalRoot << basegame << '/'; + GlobalFileSystem().initDirectory( globalBasePath.c_str() ); + } -char *copystring (char *s) -{ - char *b; - b = (char*)malloc(strlen(s)+1); - strcpy (b,s); - return b; + // extra pakpaths + for ( int i = 0; i < g_pakPathCount; i++ ) { + if (g_strcmp0( g_strPakPath[i].c_str(), "")) { + GlobalFileSystem().initDirectory( g_strPakPath[i].c_str() ); + } + } } +int g_numbrushes = 0; +int g_numentities = 0; -bool DoesFileExist(const char* pBuff, long& lSize) -{ - FileStream file; - if (file.Open(pBuff, "r")) - { - lSize += file.GetLength(); - file.Close(); - return true; - } - return false; +void QE_UpdateStatusBar(){ + char buffer[128]; + sprintf( buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); + g_pParentWnd->SetStatusText( g_pParentWnd->m_brushcount_status, buffer ); } +SimpleCounter g_brushCount; -void Map_Snapshot() -{ - CString strMsg; - - // I hope the modified flag is kept correctly up to date - if (!modified) - return; - - // we need to do the following - // 1. make sure the snapshot directory exists (create it if it doesn't) - // 2. find out what the lastest save is based on number - // 3. inc that and save the map - CString strOrgPath, strOrgFile; - ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile); - AddSlash(strOrgPath); - strOrgPath += "snapshots"; - bool bGo = true; - struct stat Stat; - if (stat(strOrgPath, &Stat) == -1) - { -#ifdef _WIN32 - bGo = (_mkdir(strOrgPath) != -1); -#endif - -#if defined (__linux__) || defined (__APPLE__) - bGo = (mkdir(strOrgPath,0755) != -1); -#endif - } - AddSlash(strOrgPath); - if (bGo) - { - int nCount = 0; - long lSize = 0; - CString strNewPath; - strNewPath = strOrgPath; - strNewPath += strOrgFile; - CString strFile; - while (bGo) - { - char buf[PATH_MAX]; - sprintf( buf, "%s.%i", strNewPath.GetBuffer(), nCount ); - strFile = buf; - bGo = DoesFileExist(strFile, lSize); - nCount++; - } - // strFile has the next available slot - Map_SaveFile(strFile, false); - // it is still a modified map (we enter this only if this is a modified map) - Sys_SetTitle (currentmap); - Sys_MarkMapModified(); - if (lSize > 12 * 1024 * 1024) // total size of saves > 4 mb - { - Sys_Printf("The snapshot files in %s total more than 4 megabytes. You might consider cleaning up.", strOrgPath.GetBuffer()); - } - } - else - { - strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetBuffer()); - gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg); - } - strOrgPath = ""; - strOrgFile = ""; +void QE_brushCountChanged(){ + g_numbrushes = int(g_brushCount.get() ); + QE_UpdateStatusBar(); } -/* -=============== -QE_CheckAutoSave - -If five minutes have passed since making a change -and the map hasn't been saved, save it out. -=============== -*/ +SimpleCounter g_entityCount; -void QE_CheckAutoSave( void ) -{ - static time_t s_start; - time_t now; - time (&now); - - if (modified != 1 || !s_start) - { - s_start = now; - return; - } - - if ((now - s_start) > (60 * g_PrefsDlg.m_nAutoSave)) - { - if (g_PrefsDlg.m_bAutoSave) - { - CString strMsg; - strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving..."; - Sys_Printf(strMsg); - Sys_Printf("\n"); - Sys_Status (strMsg,0); - - // only snapshot if not working on a default map - if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0) - { - Map_Snapshot(); - } - else - { - Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false); - } - - Sys_Status ("Autosaving...Saved.", 0 ); - modified = 2; - } - else - { - Sys_Printf ("Autosave skipped...\n"); - Sys_Status ("Autosave skipped...", 0 ); - } - s_start = now; - } +void QE_entityCountChanged(){ + g_numentities = int(g_entityCount.get() ); + QE_UpdateStatusBar(); } +bool ConfirmModified( const char* title ){ + if ( !Map_Modified( g_map ) ) { + return true; + } -// NOTE TTimo we don't like that BuildShortPathName too much -// the VFS provides a vfsCleanFileName which should perform the cleanup tasks -// in the long run I'd like to completely get rid of this - -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 -// used to be disabled, but caused problems - -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 -// can't work with long win32 names until the BSP commands are not working differently -#ifdef _WIN32 -int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) -{ - char *pFile = NULL; - int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); - nResult = GetShortPathName(pPath, pBuffer, nBufferLen); - if (nResult == 0) - strcpy(pBuffer, pPath); // Use long filename - return nResult; + auto result = ui::alert( MainFrame_getWindow(), "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, ui::alert_type::YESNOCANCEL, ui::alert_icon::Question ); + if ( result == ui::alert_response::CANCEL ) { + return false; + } + if ( result == ui::alert_response::YES ) { + if ( Map_Unnamed( g_map ) ) { + return Map_SaveAs(); + } + else + { + return Map_Save(); + } + } + return true; } -#endif -#if defined (__linux__) || defined (__APPLE__) -int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) -{ - // remove /../ from directories - const char *scr = pPath; char *dst = pBuffer; - for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) - { - if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') - { - scr += 3; - while (dst != pBuffer && *(--dst) != '/') - { - i--; - } - } - - *dst = *scr; - - scr++; dst++; - } - *dst = 0; - - return strlen (pBuffer); -} -#endif +void bsp_init(){ + build_set_variable( "RadiantPath", AppPath_get() ); + build_set_variable( "ExecutableType", RADIANT_EXECUTABLE ); + build_set_variable( "EnginePath", EnginePath_get() ); + build_set_variable( "UserEnginePath", g_qeglobals.m_userEnginePath.c_str() ); + build_set_variable( "MonitorAddress", ( g_WatchBSP_Enabled ) ? "127.0.0.1:39000" : "" ); + build_set_variable( "GameName", gamename_get() ); + + StringBuffer ExtraQ3map2Args; + // extra pakpaths + for ( int i = 0; i < g_pakPathCount; i++ ) { + if ( g_strcmp0( g_strPakPath[i].c_str(), "") ) { + ExtraQ3map2Args.push_string( " -fs_pakpath \"" ); + ExtraQ3map2Args.push_string( g_strPakPath[i].c_str() ); + ExtraQ3map2Args.push_string( "\"" ); + } + } -/* -const char *g_pPathFixups[]= -{ - "basepath", - "autosave", -}; + // extra switches + if ( g_disableEnginePath ) { + ExtraQ3map2Args.push_string( " -fs_nobasepath " ); + } -const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*); + if ( g_disableHomePath ) { + ExtraQ3map2Args.push_string( " -fs_nohomepath " ); + } -void QE_CheckProjectEntity() -{ - char *pFile; - char pBuff[PATH_MAX]; - char pNewPath[PATH_MAX]; - for (int i = 0; i < g_nPathFixupCount; i++) - { - char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]); - - strcpy (pNewPath, pPath); - if (pPath[0] != '\\' && pPath[0] != '/') - if (GetFullPathName(pPath, PATH_MAX, pBuff, &pFile)) - strcpy (pNewPath, pBuff); - - BuildShortPathName (pNewPath, pBuff, PATH_MAX); - - // check it's not ending with a filename seperator - if (pBuff[strlen(pBuff)-1] == '/' || pBuff[strlen(pBuff)-1] == '\\') - { - Sys_FPrintf(SYS_WRN, "WARNING: \"%s\" path in the project file has an ending file seperator, fixing.\n", g_pPathFixups[i]); - pBuff[strlen(pBuff)-1]=0; - } - - SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff); - } -} -*/ + build_set_variable( "ExtraQ3map2Args", ExtraQ3map2Args.c_str() ); -void HandleXMLError( void* ctxt, const char* text, ... ) -{ - va_list argptr; - static char buf[32768]; + const char* mapname = Map_Name( g_map ); + StringOutputStream name( 256 ); + name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".bsp"; - va_start (argptr,text); - vsprintf (buf, text, argptr); - Sys_FPrintf (SYS_ERR, "XML %s\n", buf); - va_end (argptr); + build_set_variable( "MapFile", mapname ); + build_set_variable( "BspFile", name.c_str() ); } -#define DTD_BUFFER_LENGTH 1024 -xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false) -{ - xmlDocPtr doc = NULL; - bool wellFormed = false, valid = false; - int res, size = 1024; - char chars[1024]; - xmlParserCtxtPtr ctxt; - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=433 - //if(validate) - // xmlDoValidityCheckingDefaultValue = 1; - //else - xmlDoValidityCheckingDefaultValue = 0; - xmlSetGenericErrorFunc(NULL, HandleXMLError); - - // SPoG - // HACK: use AppPath to resolve DTD location - // do a buffer-safe string copy and concatenate - int i; - char* w; - const char* r; - char buf[DTD_BUFFER_LENGTH]; - - w = buf; - i = 0; - // copy - //assert(g_strAppPath.GetBuffer() != NULL); - for(r = g_strAppPath.GetBuffer(); iRead(chars, 4); - if (res > 0) - { - ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf); - - while ((res = stream->Read(chars, size)) > 0) - { - xmlParseChunk(ctxt, chars, res, 0); - } - xmlParseChunk(ctxt, chars, 0, 1); - doc = ctxt->myDoc; - - wellFormed = (ctxt->wellFormed == 1); - valid = (ctxt->valid == 1); - - xmlFreeParserCtxt(ctxt); - } - - if(wellFormed && (!validate || (validate && valid))) - return doc; - - if(doc != NULL) - xmlFreeDoc(doc); - - return NULL; +void bsp_shutdown(){ + build_clear_variables(); } -xmlDocPtr ParseXMLFile(const char* filename, bool validate = false) +class ArrayCommandListener : public CommandListener { - FileStream stream; - if (stream.Open(filename, "r")) - return ParseXMLStream(&stream, validate); - - Sys_FPrintf(SYS_ERR, "Failed to open file: %s\n",filename); - return NULL; +GPtrArray* m_array; +public: +ArrayCommandListener(){ + m_array = g_ptr_array_new(); } - -// copy a string r to a buffer w -// replace $string as appropriate -void ReplaceTemplates(char* w, const char* r) -{ - const char *p; - const char *__ENGINEPATH = "TEMPLATEenginepath"; - const char *__USERHOMEPATH = "TEMPLATEuserhomepath"; - const char *__TOOLSPATH = "TEMPLATEtoolspath"; - const char *__BASEDIR = "TEMPLATEbasedir"; - const char *__APPPATH = "TEMPLATEapppath"; - - // iterate through string r - while(*r!='\0') - { - // check for special character - if(*r=='$') - { - if(strncmp(r+1, __ENGINEPATH, strlen(__ENGINEPATH)) == 0) - { - r+=strlen(__ENGINEPATH)+1; - p = g_pGameDescription->mEnginePath.GetBuffer(); - } - else if(strncmp(r+1, __USERHOMEPATH, strlen(__USERHOMEPATH)) == 0) - { - r+=strlen(__USERHOMEPATH)+1; - p = g_qeglobals.m_strHomeGame.GetBuffer(); - } - else if(strncmp(r+1, __BASEDIR, strlen(__BASEDIR)) == 0) - { - r+=strlen(__BASEDIR)+1; - p = g_pGameDescription->mBaseGame; - } - else if(strncmp(r+1, __TOOLSPATH, strlen(__TOOLSPATH)) == 0) - { - r+=strlen(__TOOLSPATH)+1; - p = g_strGameToolsPath.GetBuffer(); - } - else if(strncmp(r+1, __APPPATH, strlen(__APPPATH)) == 0) - { - r+=strlen(__APPPATH)+1; - p = g_strAppPath.GetBuffer(); - } - else - { - r++; - p = "$"; - } - - while(*p!='\0') *w++ = *p++; - } - else *w++ = *r++; - } - *w = '\0'; +~ArrayCommandListener(){ + g_ptr_array_free( m_array, TRUE ); } -/* -=========== -QE_LoadProject -TODO TODO TODO (don't think this got fully merged in) -TTimo: added project file "version", version 2 adds '#' chars to the BSP command strings -version 3 was .. I don't remember .. version 4 adds q3map2 commands -TTimo: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk -=========== -*/ -/*\todo decide on a sensible location/name for project files.*/ -bool QE_LoadProject (const char *projectfile) -{ - char buf[1024]; - xmlDocPtr doc; - xmlNodePtr node, project; - - Sys_Printf("Loading project file: \"%s\"\n", projectfile); - doc = ParseXMLFile(projectfile, true); - - if(doc == NULL) return false; - - node=doc->children; - while(node != NULL && node->type != XML_DTD_NODE) node=node->next; - if(node == NULL || strcmp((char*)node->name, "project") != 0) - { - Sys_FPrintf(SYS_ERR, "ERROR: invalid file type\n"); - return false; - } - - while(node->type != XML_ELEMENT_NODE) node=node->next; - // - project = node; - - if(g_qeglobals.d_project_entity != NULL) Entity_Free(g_qeglobals.d_project_entity); - g_qeglobals.d_project_entity = Entity_Alloc(); - - for(node = project->children; node != NULL; node=node->next) - { - if(node->type != XML_ELEMENT_NODE) continue; - - // - ReplaceTemplates(buf, (char*)node->properties->next->children->content); - - SetKeyValue(g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf); - } - - xmlFreeDoc(doc); - - // project file version checking - // add a version checking to avoid people loading later versions of the project file and bitching - int ver = IntForKey( g_qeglobals.d_project_entity, "version" ); - if (ver > PROJECT_VERSION) - { - char strMsg[1024]; - sprintf (strMsg, "This is a version %d project file. This build only supports <=%d project files.\n" - "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION); - gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); - // set the project file to nothing so we are sure we'll ask next time? - g_PrefsDlg.m_strLastProject = ""; - g_PrefsDlg.SavePrefs(); - return false; - } - - // set here some default project settings you need - if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) - { - SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" ); - } - - g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" ); - - g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; - const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); - if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); - g_qeglobals.m_strHomeMaps += str; - g_qeglobals.m_strHomeMaps += '/'; - - // don't forget to create the dirs - Q_mkdir(g_qeglobals.m_strHomeGame.GetBuffer(), 0775); - Q_mkdir(g_qeglobals.m_strHomeMaps.GetBuffer(), 0775); - - // usefull for the log file and debuggin fucked up configurations from users: - // output the basic information of the .qe4 project file - // SPoG - // all these paths should be unix format, with a trailing slash at the end - // if not.. to debug, check that the project file paths are set up correctly - Sys_Printf("basepath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath") ); - Sys_Printf("entitypath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) ); - - - // check whether user_project key exists.. - // if not, save the current project under a new name - if (ValueForKey(g_qeglobals.d_project_entity, "user_project")[0] == '\0') - { - Sys_Printf("Loaded a template project file\n"); - - // create the user_project key - SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 - if (IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION) - { - char strMsg[2048]; - sprintf(strMsg, - "The template project '%s' has version %d. The editor binary is configured for version %d.\n" - "This indicates a problem in your setup. See http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672\n" - "I will keep going with this project till you fix this", - projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION); - gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); - } - - // create the writable project file path - strcpy(buf, g_qeglobals.m_strHomeGame.GetBuffer()); - strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); - strcat(buf, "/scripts/"); - // while the filename is already in use, increment the number we add to the end - int counter = 0; - char pUser[PATH_MAX]; - while (1) - { - sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter ); - counter++; - if (access( pUser, R_OK) != 0) - { - // this is the one - strcpy( buf, pUser ); - break; - } - } - // saving project will cause a save prefs - g_PrefsDlg.m_strLastProject = buf; - g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" ); - QE_SaveProject(buf); - } - else - { - // update preferences::LastProject with path of this successfully-loaded project - // save preferences - Sys_Printf("Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() ); - g_PrefsDlg.m_strLastProject = projectfile; - g_PrefsDlg.SavePrefs(); - } - - return true; +void execute( const char* command ){ + g_ptr_array_add( m_array, g_strdup( command ) ); } -/* -=========== -QE_SaveProject -TTimo: whenever QE_SaveProject is called, prefs are updated and saved with the path to the project -=========== -*/ -qboolean QE_SaveProject (const char* filename) -{ - Sys_Printf("Save project file '%s'\n", filename); - - xmlNodePtr node; - xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0"); - // create DTD node - xmlCreateIntSubset(doc, (xmlChar *)"project", NULL, (xmlChar *)"project.dtd"); - // create project node - doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"project", NULL); - - for(epair_t* epair = g_qeglobals.d_project_entity->epairs; epair != NULL; epair = epair->next) - { - node = xmlNewChild(doc->children->next, NULL, (xmlChar *)"key", NULL); - xmlSetProp(node, (xmlChar*)"name", (xmlChar*)epair->key); - xmlSetProp(node, (xmlChar*)"value", (xmlChar*)epair->value); - } - - CreateDirectoryPath(filename); - if (xmlSaveFormatFile(filename, doc, 1) != -1) - { - xmlFreeDoc(doc); - Sys_Printf("Setting current project in prefs to \"%s\"\n", filename ); - g_PrefsDlg.m_strLastProject = filename; - g_PrefsDlg.SavePrefs(); - return TRUE; - } - else - { - xmlFreeDoc(doc); - Sys_FPrintf(SYS_ERR, "failed to save project file: \"%s\"\n", filename); - return FALSE; - } +GPtrArray* array() const { + return m_array; } +}; - - -/* -=========== -QE_KeyDown -=========== -*/ -#define SPEED_MOVE 32 -#define SPEED_TURN 22.5 - - -/* -=============== -ConnectEntities - -Sets target / targetname on the two entities selected -from the first selected to the secon -=============== -*/ -void ConnectEntities (void) +class BatchCommandListener : public CommandListener { - entity_t *e1, *e2; - const char *target; - char *newtarg = NULL; - - if (g_qeglobals.d_select_count != 2) - { - Sys_Status ("Must have two brushes selected", 0); - Sys_Beep (); - return; - } - - e1 = g_qeglobals.d_select_order[0]->owner; - e2 = g_qeglobals.d_select_order[1]->owner; - - if (e1 == world_entity || e2 == world_entity) - { - Sys_Status ("Can't connect to the world", 0); - Sys_Beep (); - return; - } - - if (e1 == e2) - { - Sys_Status ("Brushes are from same entity", 0); - Sys_Beep (); - return; - } - - target = ValueForKey (e1, "target"); - if (target && target[0]) - newtarg = g_strdup(target); - else - { - target = ValueForKey(e2, "targetname"); - if(target && target[0]) - newtarg = g_strdup(target); - else - Entity_Connect(e1, e2); - } - - if(newtarg != NULL) - { - SetKeyValue(e1, "target", newtarg); - SetKeyValue(e2, "targetname", newtarg); - g_free(newtarg); - } - - Sys_UpdateWindows (W_XY | W_CAMERA); - - Select_Deselect(); - Select_Brush (g_qeglobals.d_select_order[1]); +TextOutputStream& m_file; +std::size_t m_commandCount; +const char* m_outputRedirect; +public: +BatchCommandListener( TextOutputStream& file, const char* outputRedirect ) : m_file( file ), m_commandCount( 0 ), m_outputRedirect( outputRedirect ){ } -qboolean QE_SingleBrush (bool bQuiet) -{ - if ( (selected_brushes.next == &selected_brushes) - || (selected_brushes.next->next != &selected_brushes) ) - { - if (!bQuiet) - { - Sys_Printf ("Error: you must have a single brush selected\n"); - } - return false; +void execute( const char* command ){ + m_file << command; + if ( m_commandCount == 0 ) { + m_file << " > "; } - if (selected_brushes.next->owner->eclass->fixedsize) + else { - if (!bQuiet) - { - Sys_Printf ("Error: you cannot manipulate fixed size entities\n"); - } - return false; + m_file << " >> "; } - - return true; -} - -void QE_InitVFS (void) -{ - // VFS initialization ----------------------- - // we will call vfsInitDirectory, giving the directories to look in (for files in pk3's and for standalone files) - // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order - // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too - Str directory,prefabs; - - // TTimo: let's leave this to HL mode for now - if (g_pGameDescription->mGameFile == "hl.game") - { - // Hydra: we search the "gametools" path first so that we can provide editor - // specific pk3's wads and misc files for use by the editor. - // the relevant map compiler tools will NOT use this directory, so this helps - // to ensure that editor files are not used/required in release versions of maps - // it also helps keep your editor files all in once place, with the editor modules, - // plugins, scripts and config files. - // it also helps when testing maps, as you'll know your files won't/can't be used - // by the game engine itself. - - // - directory = g_pGameDescription->mGameToolsPath; - vfsInitDirectory(directory.GetBuffer()); - } - - // NOTE TTimo about the mymkdir calls .. this is a bit dirty, but a safe thing on *nix - - // if we have a mod dir - if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') - { - -#if defined (__linux__) || defined (__APPLE__) - // ~/./ - directory = g_qeglobals.m_strHomeGame.GetBuffer(); - Q_mkdir (directory.GetBuffer (), 0775); - directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); - Q_mkdir (directory.GetBuffer (), 0775); - vfsInitDirectory(directory.GetBuffer()); - AddSlash (directory); - prefabs = directory; - // also create the maps dir, it will be used as prompt for load/save - directory += "/maps"; - Q_mkdir (directory, 0775); - // and the prefabs dir - prefabs += "/prefabs"; - Q_mkdir (prefabs, 0775); - -#endif - - // / - directory = g_pGameDescription->mEnginePath; - directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); - Q_mkdir (directory.GetBuffer (), 0775); - vfsInitDirectory(directory.GetBuffer()); - AddSlash(directory); - prefabs = directory; - // also create the maps dir, it will be used as prompt for load/save - directory += "/maps"; - Q_mkdir (directory.GetBuffer (), 0775); - // and the prefabs dir - prefabs += "/prefabs"; - Q_mkdir (prefabs, 0775); - } - -#if defined (__linux__) || defined (__APPLE__) - // ~/./ - directory = g_qeglobals.m_strHomeGame.GetBuffer(); - directory += g_pGameDescription->mBaseGame; - vfsInitDirectory (directory.GetBuffer ()); -#endif - - // / - directory = g_pGameDescription->mEnginePath; - directory += g_pGameDescription->mBaseGame; - vfsInitDirectory(directory.GetBuffer()); -} - -void QE_Init (void) -{ - /* - ** initialize variables - */ - g_qeglobals.d_gridsize = 8; - g_qeglobals.d_showgrid = true; - - QE_InitVFS(); - - Eclass_Init(); - FillClassList(); // list in entity window - Map_Init(); - - FillTextureMenu(); - FillBSPMenu(); - - /* - ** other stuff - */ - Z_Init (); -} - -void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ) -{ - while ( *src ) - { - if ( *src == '\\' ) - *dst = '/'; - else - *dst = *src; - dst++; src++; - } - *dst = 0; + m_file << "\"" << m_outputRedirect << "\""; + m_file << "\n"; + ++m_commandCount; } +}; -int g_numbrushes, g_numentities; +bool Region_cameraValid(){ + Vector3 vOrig( vector3_snapped( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ) ) ); -void QE_CountBrushesAndUpdateStatusBar( void ) -{ - static int s_lastbrushcount, s_lastentitycount; - static qboolean s_didonce; - - //entity_t *e; - brush_t *b, *next; - - g_numbrushes = 0; - g_numentities = 0; - - if ( active_brushes.next != NULL ) + for ( int i = 0 ; i < 3 ; i++ ) { - for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) - { - next = b->next; - if (b->brush_faces ) - { - if ( !b->owner->eclass->fixedsize) - g_numbrushes++; - else - g_numentities++; - } + if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) { + return false; } } -/* - if ( entities.next != NULL ) - { - for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) - { - g_numentities++; - } - } -*/ - if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) - { - Sys_UpdateStatusBar(); - - s_lastbrushcount = g_numbrushes; - s_lastentitycount = g_numentities; - s_didonce = true; - } + return true; } -char com_token[1024]; -qboolean com_eof; -/* -================ -I_FloatTime -================ -*/ -double I_FloatTime (void) -{ - time_t t; - - time (&t); - - return t; -#if 0 -// more precise, less portable - struct timeval tp; - struct timezone tzp; - static int secbase; - - gettimeofday(&tp, &tzp); - - if (!secbase) - { - secbase = tp.tv_sec; - return tp.tv_usec/1000000.0; +void RunBSP( const char* name ){ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // make sure we don't attempt to region compile a map with the camera outside the region + if ( region_active && !Region_cameraValid() ) { + globalErrorStream() << "The camera must be in the region to start a region compile.\n"; + return; } - - return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; -#endif -} - -/* -============== -COM_Parse + SaveMap(); -Parse a token out of a string -============== -*/ -char *COM_Parse (char *data) -{ - int c; - int len; - - len = 0; - com_token[0] = 0; - - if (!data) - return NULL; - -// skip whitespace -skipwhite: - while ( (c = *data) <= ' ') - { - if (c == 0) - { - com_eof = true; - return NULL; // end of file; - } - data++; - } - -// skip // comments - if (c=='/' && data[1] == '/') - { - while (*data && *data != '\n') - data++; - goto skipwhite; + if ( Map_Unnamed( g_map ) ) { + globalOutputStream() << "build cancelled\n"; + return; } - -// handle quoted strings specially - if (c == '\"') - { - data++; - do - { - c = *data++; - if (c=='\"') - { - com_token[len] = 0; - return data; - } - com_token[len] = c; - len++; - } while (1); + if ( g_SnapShots_Enabled && !Map_Unnamed( g_map ) && Map_Modified( g_map ) ) { + Map_Snapshot(); } -// parse single characters - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') - { - com_token[len] = c; - len++; - com_token[len] = 0; - return data+1; + if ( region_active ) { + const char* mapname = Map_Name( g_map ); + StringOutputStream name( 256 ); + name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".reg"; + Map_SaveRegion( name.c_str() ); } -// parse a regular word - do - { - com_token[len] = c; - data++; - len++; - c = *data; - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') - break; - } while (c>32); - - com_token[len] = 0; - return data; -} + Pointfile_Delete(); -char* Get_COM_Token() -{ - return com_token; -} + bsp_init(); -/* -============================================================================= - - MISC FUNCTIONS - -============================================================================= -*/ - - -int argc; -char *argv[MAX_NUM_ARGVS]; - -/* -============ -ParseCommandLine -============ -*/ -void ParseCommandLine (char *lpCmdLine) -{ - argc = 1; - argv[0] = "programname"; - - while (*lpCmdLine && (argc < MAX_NUM_ARGVS)) + if ( g_WatchBSP_Enabled ) { + ArrayCommandListener listener; + build_run( name, listener ); + // grab the file name for engine running + const char* fullname = Map_Name( g_map ); + StringOutputStream bspname( 64 ); + bspname << StringRange( path_get_filename_start( fullname ), path_get_filename_base_end( fullname ) ); + BuildMonitor_Run( listener.array(), bspname.c_str() ); + } + else { - while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) - lpCmdLine++; - - if (*lpCmdLine) + char junkpath[PATH_MAX]; + strcpy( junkpath, SettingsPath_get() ); + strcat( junkpath, "junk.txt" ); + + char batpath[PATH_MAX]; +#if GDEF_OS_POSIX + strcpy( batpath, SettingsPath_get() ); + strcat( batpath, "qe3bsp.sh" ); +#elif GDEF_OS_WINDOWS + strcpy( batpath, SettingsPath_get() ); + strcat( batpath, "qe3bsp.bat" ); +#else +#error "unsupported platform" +#endif + bool written = false; { - argv[argc] = lpCmdLine; - argc++; - - while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) - lpCmdLine++; - - if (*lpCmdLine) - { - *lpCmdLine = 0; - lpCmdLine++; + TextFileOutputStream batchFile( batpath ); + if ( !batchFile.failed() ) { +#if GDEF_OS_POSIX + batchFile << "#!/bin/sh \n\n"; +#endif + BatchCommandListener listener( batchFile, junkpath ); + build_run( name, listener ); + written = true; } - + } + if ( written ) { +#if GDEF_OS_POSIX + chmod( batpath, 0744 ); +#endif + globalOutputStream() << "Writing the compile script to '" << batpath << "'\n"; + globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n"; + Q_Exec( batpath, NULL, NULL, true, false ); } } -} - - - -/* -================= -CheckParm - -Checks for the given parameter in the program's command line arguments -Returns the argument number (1 to argc-1) or 0 if not present -================= -*/ -int CheckParm (char *check) -{ - int i; - - for (i = 1;i= '0' && *str <= '9') - num += *str-'0'; - else if (*str >= 'a' && *str <= 'f') - num += 10 + *str-'a'; - else if (*str >= 'A' && *str <= 'F') - num += 10 + *str-'A'; - else - Error ("Bad hex number: %s",hex); - str++; - } - - return num; -} - -int ParseNum (char *str) -{ - if (str[0] == '$') - return ParseHex (str+1); - if (str[0] == '0' && str[1] == 'x') - return ParseHex (str+2); - return atol (str); + bsp_shutdown(); } -// BSP frontend plugin -// global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin -_QERPlugBSPFrontendTable g_BSPFrontendTable; - // ============================================================================= // Sys_ functions -bool Sys_AltDown () -{ -#ifdef _WIN32 - return (GetKeyState(VK_MENU) & 0x8000) != 0; -#endif - -#if defined (__linux__) || defined (__APPLE__) - char keys[32]; - int x; - - XQueryKeymap(GDK_DISPLAY(), keys); - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L); - if (keys[x/8] & (1 << (x % 8))) - return true; - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R); - if (keys[x/8] & (1 << (x % 8))) - return true; - - return false; -#endif -} - -bool Sys_ShiftDown () -{ -#ifdef _WIN32 - return (GetKeyState(VK_SHIFT) & 0x8000) != 0; -#endif - -#if defined (__linux__) || defined (__APPLE__) - char keys[32]; - int x; - - XQueryKeymap(GDK_DISPLAY(), keys); - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_L); - if (keys[x/8] & (1 << (x % 8))) - return true; - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_R); - if (keys[x/8] & (1 << (x % 8))) - return true; - - return false; -#endif -} - -void Sys_MarkMapModified (void) -{ - char title[PATH_MAX]; - - if (modified != 1) - { - modified = true; // mark the map as changed - sprintf (title, "%s *", currentmap); +void Sys_SetTitle( const char *text, bool modified ){ + StringOutputStream title; + title << text; - QE_ConvertDOSToUnixName( title, title ); - Sys_SetTitle (title); - } -} + if ( modified ) { + title << " *"; + } -void Sys_SetTitle (const char *text) -{ - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_main_window), text); + gtk_window_set_title(MainFrame_getWindow(), title.c_str() ); } bool g_bWaitCursor = false; -void WINAPI Sys_BeginWait (void) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); - gdk_cursor_unref (cursor); - g_bWaitCursor = true; -} - -void WINAPI Sys_EndWait (void) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); - gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); - gdk_cursor_unref (cursor); - g_bWaitCursor = false; -} - -void Sys_GetCursorPos (int *x, int *y) -{ - // FIXME: not multihead safe - gdk_window_get_pointer (NULL, x, y, NULL); +void Sys_BeginWait( void ){ + ScreenUpdates_Disable( "Processing...", "Please Wait" ); + GdkCursor *cursor = gdk_cursor_new( GDK_WATCH ); + gdk_window_set_cursor( gtk_widget_get_window(MainFrame_getWindow()), cursor ); + gdk_cursor_unref( cursor ); + g_bWaitCursor = true; } -void Sys_SetCursorPos (int x, int y) -{ - // NOTE: coordinates are in GDK space, not OS space -#ifdef _WIN32 - int sys_x = x - g_pParentWnd->GetGDKOffsetX(); - int sys_y = y - g_pParentWnd->GetGDKOffsetY(); - - SetCursorPos (sys_x, sys_y); -#endif - -#if defined (__linux__) || defined (__APPLE__) - XWarpPointer (GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y); -#endif -} - -void Sys_Beep (void) -{ -#if defined (__linux__) || defined (__APPLE__) - gdk_beep (); -#else - MessageBeep (MB_ICONASTERISK); -#endif -} - -double Sys_DoubleTime (void) -{ - return clock()/ 1000.0; -} - -/* -=============================================================== - - STATUS WINDOW - -=============================================================== -*/ - -void Sys_UpdateStatusBar( void ) -{ - extern int g_numbrushes, g_numentities; - - char numbrushbuffer[100]=""; - - sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); - g_pParentWnd->SetStatusText(2, numbrushbuffer); - //Sys_Status( numbrushbuffer, 2 ); -} - -void Sys_Status(const char *psz, int part ) -{ - g_pParentWnd->SetStatusText (part, psz); -} - -// ============================================================================= -// MRU - -#define MRU_MAX 4 -static GtkWidget *MRU_items[MRU_MAX]; -static int MRU_used; -typedef char MRU_filename_t[PATH_MAX]; -MRU_filename_t MRU_filenames[MRU_MAX]; - -static char* MRU_GetText (int index) -{ - return MRU_filenames[index]; +void Sys_EndWait( void ){ + ScreenUpdates_Enable(); + gdk_window_set_cursor(gtk_widget_get_window(MainFrame_getWindow()), 0 ); + g_bWaitCursor = false; } -void buffer_write_escaped_mnemonic(char* buffer, const char* string) -{ - while(*string != '\0') - { - if(*string == '_') - { - *buffer++ = '_'; - } - - *buffer++ = *string++; - } - *buffer = '\0'; -} - -static void MRU_SetText (int index, const char *filename) -{ - strcpy(MRU_filenames[index], filename); - - char mnemonic[PATH_MAX * 2 + 4]; - mnemonic[0] = '_'; - sprintf(mnemonic+1, "%d", index+1); - mnemonic[2] = '-'; - mnemonic[3] = ' '; - buffer_write_escaped_mnemonic(mnemonic+4, filename); - gtk_label_set_text_with_mnemonic(GTK_LABEL (GTK_BIN (MRU_items[index])->child), mnemonic); -} - -void MRU_Load () -{ - int i = g_PrefsDlg.m_nMRUCount; - - if(i > 4) - i = 4; //FIXME: make this a define - - for (; i > 0; i--) - MRU_AddFile (g_PrefsDlg.m_strMRUFiles[i-1].GetBuffer()); -} - -void MRU_Save () -{ - g_PrefsDlg.m_nMRUCount = MRU_used; - - for (int i = 0; i < MRU_used; i++) - g_PrefsDlg.m_strMRUFiles[i] = MRU_GetText (i); -} - -void MRU_AddWidget (GtkWidget *widget, int pos) -{ - if (pos < MRU_MAX) - MRU_items[pos] = widget; -} - -void MRU_AddFile (const char *str) -{ - int i; - char* text; - - // check if file is already in our list - for (i = 0; i < MRU_used; i++) - { - text = MRU_GetText (i); - - if (strcmp (text, str) == 0) - { - // reorder menu - for (; i > 0; i--) - MRU_SetText (i, MRU_GetText (i-1)); - - MRU_SetText (0, str); - - return; - } - } - - if (MRU_used < MRU_MAX) - MRU_used++; - - // move items down - for (i = MRU_used-1; i > 0; i--) - MRU_SetText (i, MRU_GetText (i-1)); - - MRU_SetText (0, str); - gtk_widget_set_sensitive (MRU_items[0], TRUE); - gtk_widget_show (MRU_items[MRU_used-1]); -} - -void MRU_Activate (int index) -{ - char *text = MRU_GetText (index); - - if (access (text, R_OK) == 0) - { - text = strdup (text); - MRU_AddFile (text); - Map_LoadFile (text); - free (text); - } - else - { - MRU_used--; - - for (int i = index; i < MRU_used; i++) - MRU_SetText (i, MRU_GetText (i+1)); - - if (MRU_used == 0) - { - gtk_label_set_text (GTK_LABEL (GTK_BIN (MRU_items[0])->child), "Recent Files"); - gtk_widget_set_sensitive (MRU_items[0], FALSE); - } - else - { - gtk_widget_hide (MRU_items[MRU_used]); - } - } -} - -/* -====================================================================== - -FILE DIALOGS - -====================================================================== -*/ - -qboolean ConfirmModified () -{ - if (!modified) - return true; - - if (gtk_MessageBox (g_pParentWnd->m_pWidget, "This will lose changes to the map", "warning", MB_OKCANCEL) == IDCANCEL) - return false; - return true; -} - -void ProjectDialog () -{ - const char *filename; - char buffer[NAME_MAX]; - - /* - * Obtain the system directory name and - * store it in buffer. - */ - - strcpy(buffer, g_qeglobals.m_strHomeGame.GetBuffer()); - strcat(buffer, g_pGameDescription->mBaseGame.GetBuffer()); - strcat (buffer, "/scripts/"); - - // Display the Open dialog box - filename = file_dialog (NULL, TRUE, "Open File", buffer, "project"); - - if (filename == NULL) - return; // canceled - - // Open the file. - // NOTE: QE_LoadProject takes care of saving prefs with new path to the project file - if (!QE_LoadProject(filename)) - Sys_Printf ("Failed to load project from file: %s\n", filename); - else - // FIXME TTimo QE_Init is probably broken if you don't call it during startup right now .. - QE_Init(); -} - -/* -======================================================= - -Menu modifications - -======================================================= -*/ - -/* -================== -FillBSPMenu - -================== -*/ -char *bsp_commands[256]; - -void FillBSPMenu () -{ - GtkWidget *item, *menu; // menu points to a GtkMenu (not an item) - epair_t *ep; - GList *lst; - int i; - - menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_bsp")); - - while ((lst = gtk_container_children (GTK_CONTAINER (menu))) != NULL) - gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->data)); - - if (g_PrefsDlg.m_bDetachableMenus) { - item = gtk_tearoff_menu_item_new (); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_set_sensitive (item, TRUE); - gtk_widget_show (item); - } - - if (g_qeglobals.bBSPFrontendPlugin) - { - CString str = g_BSPFrontendTable.m_pfnGetBSPMenu(); - char cTemp[1024]; - strcpy(cTemp, str); - char* token = strtok(cTemp, ",;"); - if (token && *token == ' ') - { - while (*token == ' ') - token++; - } - i = 0; - - // first token is menu name - item = gtk_menu_get_attach_widget (GTK_MENU (menu)); - gtk_label_set_text (GTK_LABEL (GTK_BIN (item)->child), token); - - token = strtok(NULL, ",;"); - while (token != NULL) - { - g_BSPFrontendCommands = g_slist_append (g_BSPFrontendCommands, g_strdup (token)); - item = gtk_menu_item_new_with_label (token); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); - token = strtok(NULL, ",;"); - i++; - } - } - else - { - i = 0; - for (ep = g_qeglobals.d_project_entity->epairs; ep; ep = ep->next) - { - if (strncmp(ep->key, "bsp_", 4)==0) - { - bsp_commands[i] = ep->key; - item = gtk_menu_item_new_with_label (ep->key+4); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); - i++; - } - } - } -} - -//============================================== - -void AddSlash(CString& strPath) -{ - if (strPath.GetLength() > 0) - { - if ((strPath.GetAt(strPath.GetLength()-1) != '/') && - (strPath.GetAt(strPath.GetLength()-1) != '\\')) - strPath += '/'; - } -} - -bool ExtractPath_and_Filename(const char* pPath, CString& strPath, CString& strFilename) -{ - CString strPathName; - strPathName = pPath; - int nSlash = strPathName.ReverseFind('\\'); - if (nSlash == -1) - // TTimo: try forward slash, some are using forward - nSlash = strPathName.ReverseFind('/'); - if (nSlash >= 0) - { - strPath = strPathName.Left(nSlash+1); - strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1); - } - // TTimo: try forward slash, some are using forward - else - strFilename = pPath; - return true; -} - -//=========================================== - -//++timo FIXME: no longer used .. remove! -char *TranslateString (char *buf) -{ - static char buf2[32768]; - int i, l; - char *out; - - l = strlen(buf); - out = buf2; - for (i=0 ; i