]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/mainframe.cpp
improve path finding logic
[xonotic/netradiant.git] / radiant / mainframe.cpp
index 031f2b473cc1520684eeb49f9193061ee9e2d5c5..bddb333ef9acb01e4381cc573b700cca9569309c 100644 (file)
@@ -184,22 +184,86 @@ void VFS_Destroy()
 
 // Home Paths
 
+#ifdef WIN32
+#include <shlobj.h>
+const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}};
+#define qREFKNOWNFOLDERID GUID
+#define qKF_FLAG_CREATE 0x8000
+#define qKF_FLAG_NO_ALIAS 0x1000
+static HRESULT (WINAPI *qSHGetKnownFolderPath) (qREFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
+#endif
 void HomePaths_Realise()
 {
-#if defined(POSIX)
-  const char* prefix = g_pGameDescription->getKeyValue("prefix");
-  if(!string_empty(prefix))
+  do
   {
-    StringOutputStream path(256);
-    path << DirectoryCleaned(g_get_home_dir()) << prefix << "/";
-    g_qeglobals.m_userEnginePath = path.c_str();
-    Q_mkdir(g_qeglobals.m_userEnginePath.c_str());
-  }
-  else
+    const char* prefix = g_pGameDescription->getKeyValue("prefix");
+    if(!string_empty(prefix))
+    {
+      StringOutputStream path(256);
+
+#if defined(__APPLE__)
+      path.clear();
+      path << DirectoryCleaned(g_get_home_dir()) << "Library/Application Support" << (prefix+1) << "/";
+      if(file_is_directory(path.c_str()))
+      {
+        g_qeglobals.m_userEnginePath = path.c_str();
+        break;
+      }
 #endif
-  {
+
+#if defined(WIN32)
+      TCHAR mydocsdir[MAX_PATH + 1];
+      wchar_t *mydocsdirw;
+      HMODULE shfolder = LoadLibrary("shfolder.dll");
+      if(shfolder)
+        qSHGetKnownFolderPath = GetProcAddress("SHGetFolderPathA");
+      else
+        qSHGetKnownFolderPath = NULL;
+      CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+      if(qSHGetKnownFolderPath && qSHGetKnownFolderPath(qFOLDERID_SavedGames, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &mydocsdirw) == S_OK)
+      {
+        memset(mydocsdir, 0, sizeof(mydocsdir));
+        wctombs(mydocsdir, mydocsdirw, sizeof(mydocsdir)-1);
+        CoTaskMemFree(mydocsdirw);
+        path.clear();
+        path << DirectoryCleaned(mydocsdir) << (prefix+1) << "/";
+        if(file_is_directory(path.c_str()))
+        {
+          g_qeglobals.m_userEnginePath = path.c_str();
+          CoUninitialize();
+          FreeLibrary(shfolder);
+          break;
+        }
+      }
+      CoUninitialize();
+      if(shfolder)
+        FreeLibrary(shfolder);
+      if(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir))
+      {
+        path.clear();
+        path << DirectoryCleaned(mydocsdir) << "My Games/" << (prefix+1) << "/";
+        // win32: only add it if it already exists
+        if(file_is_directory(path.c_str()))
+        {
+          g_qeglobals.m_userEnginePath = path.c_str();
+          break;
+        }
+      }
+#endif
+
+#if defined(POSIX)
+      path.clear();
+      path << DirectoryCleaned(g_get_home_dir()) << prefix << "/";
+      g_qeglobals.m_userEnginePath = path.c_str();
+      break;
+#endif
+    }
+
     g_qeglobals.m_userEnginePath = EnginePath_get();
   }
+  while(0);
+
+  Q_mkdir(g_qeglobals.m_userEnginePath.c_str());
 
   {
     StringOutputStream path(256);
@@ -718,7 +782,7 @@ void PasteToCamera()
   // Work out the delta
   Vector3 mid;
   Select_GetMid(mid);
-  Vector3 delta = vector3_subtracted(vector3_snapped(Camera_getOrigin(camwnd), GetGridSize()), mid);
+  Vector3 delta = vector3_subtracted(vector3_snapped(Camera_getOrigin(camwnd), GetSnapGridSize()), mid);
 
   // Move to camera
   GlobalSelectionSystem().translateSelected(delta);
@@ -976,11 +1040,13 @@ void OpenUpdateURL()
 {
   // build the URL
   StringOutputStream URL(256);
-  URL << "http://www.qeradiant.com/index.php?data=dlupdate&query_dlup=1";
+  URL << "http://www.icculus.org/netradiant/?cmd=update&data=dlupdate&query_dlup=1";
 #ifdef WIN32
   URL << "&OS_dlup=1";
-#else
+#elif defined(__APPLE__)
   URL << "&OS_dlup=2";
+#else
+  URL << "&OS_dlup=3";
 #endif
   URL << "&Version_dlup=" RADIANT_VERSION;
   g_GamesDialog.AddPacksURL(URL);
@@ -990,15 +1056,15 @@ void OpenUpdateURL()
 // open the Q3Rad manual
 void OpenHelpURL()
 {
-  // at least on win32, AppPath + "Q3Rad_Manual/index.htm"
+  // at least on win32, AppPath + "docs/index.html"
   StringOutputStream help(256);
-  help << AppPath_get() << "Q3Rad_Manual/index.htm";
+  help << AppPath_get() << "docs/index.html";
   OpenURL(help.c_str());
 }
 
 void OpenBugReportURL()
 {
-  OpenURL("http://www.qeradiant.com/?data=bugreport");
+  OpenURL("http://www.icculus.org/netradiant/?cmd=bugs");
 }
 
 
@@ -1186,12 +1252,22 @@ void SelectFaceMode()
 
 class CloneSelected : public scene::Graph::Walker
 {
+  bool doMakeUnique;
+  NodeSmartReference worldspawn;
 public:
+  CloneSelected(bool d): doMakeUnique(d), worldspawn(Map_FindOrInsertWorldspawn(g_map))
+  {
+  }
   bool pre(const scene::Path& path, scene::Instance& instance) const
   {
     if(path.size() == 1)
       return true;
 
+    // ignore worldspawn, but keep checking children
+    NodeSmartReference me(path.top().get());
+    if(me == worldspawn)
+           return true;
+
     if(!path.top().get().isRoot())
     {
       Selectable* selectable = Instance_getSelectable(instance);
@@ -1209,6 +1285,11 @@ public:
     if(path.size() == 1)
       return;
 
+    // ignore worldspawn, but keep checking children
+    NodeSmartReference me(path.top().get());
+    if(me == worldspawn)
+           return;
+
     if(!path.top().get().isRoot())
     {
       Selectable* selectable = Instance_getSelectable(instance);
@@ -1216,16 +1297,17 @@ public:
         && selectable->isSelected())
       {
         NodeSmartReference clone(Node_Clone(path.top()));
-        Map_gatherNamespaced(clone);
+               if(doMakeUnique)
+                       Map_gatherNamespaced(clone);
         Node_getTraversable(path.parent().get())->insert(clone);
       }
     }
   }
 };
 
-void Scene_Clone_Selected(scene::Graph& graph)
+void Scene_Clone_Selected(scene::Graph& graph, bool doMakeUnique)
 {
-  graph.traverse(CloneSelected());
+  graph.traverse(CloneSelected(doMakeUnique));
 
   Map_mergeClonedNames();
 }
@@ -1297,7 +1379,20 @@ void Selection_Clone()
   {
     UndoableCommand undo("cloneSelected");
 
-    Scene_Clone_Selected(GlobalSceneGraph());
+    Scene_Clone_Selected(GlobalSceneGraph(), false);
+
+    //NudgeSelection(eNudgeRight, GetGridSize(), GlobalXYWnd_getCurrentViewType());
+    //NudgeSelection(eNudgeDown, GetGridSize(), GlobalXYWnd_getCurrentViewType());
+  }
+}
+
+void Selection_Clone_MakeUnique()
+{
+  if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
+  {
+    UndoableCommand undo("cloneSelectedMakeUnique");
+
+    Scene_Clone_Selected(GlobalSceneGraph(), true);
 
     //NudgeSelection(eNudgeRight, GetGridSize(), GlobalXYWnd_getCurrentViewType());
     //NudgeSelection(eNudgeDown, GetGridSize(), GlobalXYWnd_getCurrentViewType());
@@ -1978,6 +2073,7 @@ GtkMenuItem* create_edit_menu()
   create_menu_item_with_mnemonic(menu, "P_aste To Camera", "PasteToCamera");
   menu_separator(menu);
   create_menu_item_with_mnemonic(menu, "_Duplicate", "CloneSelection");
+  create_menu_item_with_mnemonic(menu, "Duplicate, make uni_que", "CloneSelectionAndMakeUnique");
   create_menu_item_with_mnemonic(menu, "D_elete", "DeleteSelection");
   menu_separator(menu);
   create_menu_item_with_mnemonic(menu, "Pa_rent", "ParentSelection");
@@ -3269,7 +3365,7 @@ void MainFrame::SetGridStatus()
 {
   StringOutputStream status(64);
   const char* lock = (GridStatus_getTextureLockEnabled()) ? "ON" : "OFF";
-  status << "G:" << GridStatus_getGridSize()
+  status << (GetSnapGridSize() > 0 ? "G:" : "g:") << GridStatus_getGridSize()
     << "  R:" << GridStatus_getRotateIncrement()
     << "  C:" << GridStatus_getFarClipDistance()
     << "  L:" << lock;
@@ -3284,13 +3380,10 @@ void GridStatus_onTextureLockEnabledChanged()
   }
 }
 
-namespace
-{
-  GLFont g_font(0, 0);
-}
-
 void GlobalGL_sharedContextCreated()
 {
+  GLFont *g_font = NULL;
+
   // report OpenGL information
   globalOutputStream() << "GL_VENDOR: " << reinterpret_cast<const char*>(glGetString (GL_VENDOR)) << "\n";
   globalOutputStream() << "GL_RENDERER: " << reinterpret_cast<const char*>(glGetString (GL_RENDERER)) << "\n";
@@ -3304,15 +3397,17 @@ void GlobalGL_sharedContextCreated()
   GlobalShaderCache().realise();
   Textures_Realise();
 
-#if defined(WIN32)
-  g_font = glfont_create("courier new 8");
-#elif defined(__linux__)
-  g_font = glfont_create("fixed 8");
+#ifdef WIN32
+  /* win32 is dodgy here, just use courier new then */
+  g_font = glfont_create("arial 9");
 #else
-  g_font = glfont_create("courier 8");
+  GtkSettings *settings = gtk_settings_get_default();
+  gchar *fontname;
+  g_object_get(settings, "gtk-font-name", &fontname, NULL);
+  g_font = glfont_create(fontname);
 #endif
-  GlobalOpenGL().m_font = g_font.getDisplayList();
-  GlobalOpenGL().m_fontHeight = g_font.getPixelHeight();
+
+  GlobalOpenGL().m_font = g_font;
 }
 
 void GlobalGL_sharedContextDestroyed()
@@ -3393,6 +3488,7 @@ void MainFrame_Construct()
   GlobalCommands_insert("Paste", FreeCaller<Paste>(), Accelerator('V', (GdkModifierType)GDK_CONTROL_MASK));
   GlobalCommands_insert("PasteToCamera", FreeCaller<PasteToCamera>(), Accelerator('V', (GdkModifierType)GDK_MOD1_MASK));
   GlobalCommands_insert("CloneSelection", FreeCaller<Selection_Clone>(), Accelerator(GDK_space));
+  GlobalCommands_insert("CloneSelectionAndMakeUnique", FreeCaller<Selection_Clone_MakeUnique>(), Accelerator(GDK_space, (GdkModifierType)GDK_SHIFT_MASK));
   GlobalCommands_insert("DeleteSelection", FreeCaller<deleteSelection>(), Accelerator(GDK_BackSpace));
   GlobalCommands_insert("ParentSelection", FreeCaller<Scene_parentSelected>());
   GlobalCommands_insert("UnSelectSelection", FreeCaller<Selection_Deselect>(), Accelerator(GDK_Escape));