[Gtkradiant] r4795 - in GtkRadiant/trunk: docs/developer include radiant

svn-noreply at zerowing.idsoftware.com svn-noreply at zerowing.idsoftware.com
Wed Sep 22 05:28:14 CDT 2004


Author: spog
Date: 2004-09-21 18:00:19 -0500 (Tue, 21 Sep 2004)
New Revision: 4795

Modified:
   GtkRadiant/trunk/docs/developer/CHANGES
   GtkRadiant/trunk/docs/developer/TODO
   GtkRadiant/trunk/include/ifiletypes.h
   GtkRadiant/trunk/radiant/gtkmisc.cpp
Log:
file-choosers changed to use GtkFileChooser

Modified: GtkRadiant/trunk/docs/developer/CHANGES
===================================================================
--- GtkRadiant/trunk/docs/developer/CHANGES	2004-09-21 20:49:06 UTC (rev 4794)
+++ GtkRadiant/trunk/docs/developer/CHANGES	2004-09-21 23:00:19 UTC (rev 4795)
@@ -2,6 +2,10 @@
 that we distribute with the binaries. (see changelog)
 
 20/09/2004
+Michael Schlueter
+- Changed file-chooser dialogs to use GtkFileChooser.
+
+20/09/2004
 SPoG
 - Added basic rendering for 'curve_CatmullRomSpline' on doom3 entities.
 

Modified: GtkRadiant/trunk/docs/developer/TODO
===================================================================
--- GtkRadiant/trunk/docs/developer/TODO	2004-09-21 20:49:06 UTC (rev 4794)
+++ GtkRadiant/trunk/docs/developer/TODO	2004-09-21 23:00:19 UTC (rev 4795)
@@ -18,7 +18,6 @@
 HIGH priority features
 
 Brush: make edge/vertex/face dragging with QE tool select equal points
-UI: change file-choosers to use GtkFileChooser on linux
 Model: add support for doom3 md5anim format
 Model: support doom3 .skin files
 VFS: add ability to browse VFS from file-open dialogs.

Modified: GtkRadiant/trunk/include/ifiletypes.h
===================================================================
--- GtkRadiant/trunk/include/ifiletypes.h	2004-09-21 20:49:06 UTC (rev 4794)
+++ GtkRadiant/trunk/include/ifiletypes.h	2004-09-21 23:00:19 UTC (rev 4795)
@@ -7,10 +7,12 @@
 public:
   filetype_t()
     : name(""), pattern("")
-  {}
+  {
+  }
   filetype_t(const char* _name, const char* _pattern)
     : name(_name), pattern(_pattern)
-  {}
+  {
+  }
   const char* name;
   const char* pattern;
 };

Modified: GtkRadiant/trunk/radiant/gtkmisc.cpp
===================================================================
--- GtkRadiant/trunk/radiant/gtkmisc.cpp	2004-09-21 20:49:06 UTC (rev 4794)
+++ GtkRadiant/trunk/radiant/gtkmisc.cpp	2004-09-21 23:00:19 UTC (rev 4795)
@@ -36,6 +36,7 @@
 
 #include <stdlib.h>
 #include <set>
+#include <vector>
 #include <gtk/gtkframe.h>
 #include <gtk/gtkvbox.h>
 #include <gtk/gtkhbox.h>
@@ -66,6 +67,8 @@
 #include "math/vector.h"
 #include "pathlib.h"
 #include "str.h"
+#include "auto_array.h"
+#include "stringstream.h"
 
 #include "error.h"
 #include "filetypes.h"
@@ -1502,40 +1505,8 @@
 // =============================================================================
 // File dialog
 
-// fenris #3078 WHENHELLISFROZENOVER
-
-//#define FILEDLG_DBG
-
-static void file_sel_callback (GtkWidget *widget, gpointer data)
-{
-  GtkWidget *parent;
-  int *loop;
-  bool *success;
-
-  parent = gtk_widget_get_toplevel (widget);
-  loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");
-  success = (bool*)g_object_get_data (G_OBJECT (parent), "success");
-  
-  if ((EMessageBoxReturn)gpointer_to_int(data) == eIDOK)
-    *success = true;
-  
-  *loop = 0;
-}
-
-gint file_sel_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)
-{
-  int *loop;
-
-  gtk_widget_hide (widget);
-  loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");
-  *loop = 0;
-
-  return TRUE;
-}
-
 char* dir_dialog(GtkWidget* parent, const char* title, const char* path)
 {
-#if 0
   GtkWidget* dialog = gtk_file_chooser_dialog_new(title,
 				        GTK_WINDOW(parent),
 				        GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
@@ -1557,47 +1528,6 @@
   gtk_widget_destroy(dialog);
 
   return filename;
-#else
-
-  GtkWidget* file_sel;
-  char* filename = 0;
-  int loop = 1;
-  bool success = false;
-
-  file_sel = gtk_file_selection_new (title);
-  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",
-                      GTK_SIGNAL_FUNC (file_sel_callback), gint_to_pointer (eIDOK));
-  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",
-                      GTK_SIGNAL_FUNC (file_sel_callback), gint_to_pointer (eIDCANCEL));
-  gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",
-                      GTK_SIGNAL_FUNC (file_sel_delete_callback), 0);
-  gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));
-
-  if (parent != 0)
-    gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));
-
-  gtk_widget_hide (GTK_FILE_SELECTION (file_sel)->file_list->parent);
-
-  g_object_set_data (G_OBJECT (file_sel), "loop", &loop);
-  g_object_set_data (G_OBJECT (file_sel), "filename", &filename);
-  g_object_set_data (G_OBJECT (file_sel), "success", &success);
-
-  if (path != 0)
-    gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), path);
-
-  gtk_grab_add (file_sel);
-  gtk_widget_show (file_sel);
-
-  while (loop)
-    gtk_main_iteration ();
-
-  filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));
-
-  gtk_grab_remove (file_sel);
-  gtk_widget_destroy (file_sel);
-
-  return filename;
-#endif
 }
 
 bool color_dialog (GtkWidget *parent, Vector3& color, const char* title)
@@ -1838,178 +1768,133 @@
   gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 0);
 }
 
-
-class CFileType : public IFileTypeList
+struct filetype_pair_t
 {
-  struct filetype_pair_t
+  filetype_pair_t()
+    : m_minor("")
   {
-    filetype_pair_t()
-      : m_minor(""), m_type(filetype_t())
-    {}
-    filetype_pair_t(const char* minor, filetype_t type)
-      : m_minor(minor), m_type(type)
-    {}
-    const char* m_minor;
-    filetype_t m_type;
-  };
+  }
+  filetype_pair_t(const char* minor, filetype_t type)
+    : m_minor(minor), m_type(type)
+  {
+  }
+  const char* m_minor;
+  filetype_t m_type;
+};
 
+class FileTypeList : public IFileTypeList
+{
   struct filetype_copy_t
   {
-    void operator=(const filetype_pair_t& other)
+    filetype_copy_t(const filetype_pair_t& other)
+      : m_minor(other.m_minor), m_name(other.m_type.name), m_pattern(other.m_type.pattern)
     {
-      m_minor = other.m_minor;
-      m_name = other.m_type.name;
-      m_pattern = other.m_type.pattern;
     }
     string_t m_minor;
     string_t m_name;
     string_t m_pattern;
   };
+
+  typedef std::list<filetype_copy_t> Types;
+  Types m_types;
 public:
-  CFileType()
+
+  typedef Types::const_iterator const_iterator;
+  const_iterator begin() const
   {
-    m_nTypes = 0;
-    m_pTypes = 0;
-    m_strWin32Filters = 0;
-    m_pstrGTKMasks = 0;
+    return m_types.begin();
   }
-
-  ~CFileType()
+  const_iterator end() const
   {
-    delete[] m_pTypes;
-    DestroyWin32Filters();
-    DestroyGTKMasks();
+    return m_types.end();
   }
 
-  void addType(const char* minor, filetype_t type)
+  std::size_t size() const
   {
-    filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes+1];
-    if(m_nTypes > 0)
-    {
-      for(int i=0; i<m_nTypes; i++)
-        newTypes[i] = m_pTypes[i];
-      delete[] m_pTypes;
-    }
-    m_pTypes = newTypes;
-    m_pTypes[m_nTypes] = filetype_pair_t(minor, type);
-    m_nTypes++;
-    ConstructGTKMasks();
-    ConstructWin32Filters();
+    return m_types.size();
   }
- 
-  filetype_pair_t GetTypeForWin32Filter(const char *filter) const
-  {
-    for(int i=0; i<m_nTypes; i++)
-      if(strcmp(m_pTypes[i].m_pattern.c_str(), filter)==0)
-        return filetype_pair_t(m_pTypes[i].m_minor.c_str(), filetype_t(m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str()));
-    return filetype_pair_t();
-  }
 
-  filetype_pair_t GetTypeForGTKMask(const char *mask) const
+  void addType(const char* minor, filetype_t type)
   {
-    for(int i=0; i<m_nTypes; i++)
-      if(strcmp(m_pstrGTKMasks[i],mask)==0)
-        return filetype_pair_t(m_pTypes[i].m_minor.c_str(), filetype_t(m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str()));
-    return filetype_pair_t();
+    m_types.push_back(filetype_pair_t(minor, type));
   }
+};
 
-  char *m_strWin32Filters;
-  char **m_pstrGTKMasks;
-private:
-  int m_nTypes;
-  filetype_copy_t *m_pTypes;
+#ifdef WIN32
 
-  void DestroyWin32Filters()
+class Win32Filters
+{
+  const FileTypeList& m_types;
+  auto_array<char> m_filters;
+public:
+  Win32Filters(const FileTypeList& typeList) : m_types(typeList)
   {
-    delete[] m_strWin32Filters;
-  }
-
-  void ConstructWin32Filters()
-  {
-    DestroyWin32Filters();
     std::size_t len = 0;
-    for(int i=0; i<m_nTypes; i++)
-      len = len + strlen(m_pTypes[i].m_name.c_str()) + strlen(m_pTypes[i].m_pattern.c_str())*2 + 5;
-    m_strWin32Filters = new char[len+1]; // length + null char
-    char *w = m_strWin32Filters;
-    for(int i=0; i<m_nTypes; i++)
+    for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
     {
-      for(const char *r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)
+      len = len + strlen((*i).m_name.c_str()) + strlen((*i).m_pattern.c_str()) * 2 + 5;
+    }
+    m_filters.allocate(len + 1); // length + null char
+    char *w = m_filters.data();
+    for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
+    {
+      for(const char *r = (*i).m_name.c_str(); *r!='\0'; r++, w++)
+      {
         *w = *r;
+      }
       *w++ = ' ';
       *w++ = '(';
-      for(const char *r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
+      for(const char *r = (*i).m_pattern.c_str(); *r!='\0'; r++, w++)
+      {
         *w = *r;
+      }
       *w++ = ')';
       *w++ = '\0';
-      for(const char *r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
+      for(const char *r = (*i).m_pattern.c_str(); *r!='\0'; r++, w++)
+      {
         *w = (*r == ',') ? ';' : *r;
+      }
       *w++ = '\0';
     }
-    m_strWin32Filters[len] = '\0';
+    m_filters[len] = '\0';
   }
-
-  void DestroyGTKMasks()
+  filetype_pair_t getType(const char *filter) const
   {
-    if(m_pstrGTKMasks != 0)
-      for(char **p = m_pstrGTKMasks; *p != 0; p++)
-        delete[] *p;
-    delete[] m_pstrGTKMasks;
-  }
-  
-  void ConstructGTKMasks()
-  {
-    DestroyGTKMasks();
-    m_pstrGTKMasks = new char*[m_nTypes+1];
-    for(int i=0; i<m_nTypes; i++)
+    for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
     {
-      std::size_t len = strlen(m_pTypes[i].m_name.c_str()) + strlen(m_pTypes[i].m_pattern.c_str()) + 3;
-      m_pstrGTKMasks[i] = new char[len+1]; // length + null char
-      char *w = m_pstrGTKMasks[i];
-      for(const char *r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)
-        *w = *r;
-      *w++ = ' ';
-      *w++ = '<';
-      for(const char *r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
-        *w = *r;
-      *w++ = '>';
-      *w++ = '\0';
+      if(string_equal((*i).m_pattern.c_str(), filter))
+      {
+        return filetype_pair_t((*i).m_minor.c_str(), filetype_t((*i).m_name.c_str(), (*i).m_pattern.c_str()));
+      }
     }
-    m_pstrGTKMasks[m_nTypes] = 0;
+    return filetype_pair_t();
   }
-
+  const char* getFilters() const
+  {
+    return m_filters.data();
+  }
 };
 
-#ifdef WIN32
-
 #define WIN32_LEAN_AND_MEAN
 #include <gdk/gdkwin32.h>
 #include <commdlg.h>
 
-static OPENFILENAME ofn;       /* common dialog box structure   */ 
-static char szDirName[MAX_PATH];    /* directory string              */ 
-static char szFile[MAX_PATH];       /* filename string               */ 
-static char szFileTitle[MAX_PATH];  /* file title string             */ 
-static int i, cbString;        /* integer count variables       */ 
-static HANDLE hf;              /* file handle                   */ 
-#else
-static char szFile[1024];
-#endif
+static char szFile[MAX_PATH];       /* filename string */
 
+
 #define FILEDLG_CUSTOM_FILTER_LENGTH 64
 // to be used with the advanced file selector
 
-const char* file_dialog_show(GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
+const char* file_dialog_show_win32(GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
 {
   // Gtk dialog
-  GtkWidget* file_sel;
   int loop = 1;
   char *new_path = 0;
 
   const char* r;
   char* w;
   filetype_t type;
-  CFileType typelist;
+  FileTypeList typelist;
 
   if(pattern == 0)
   {
@@ -2018,193 +1903,289 @@
 
   GetFileTypeRegistry()->getTypeList(pattern, &typelist);
 
-#ifdef WIN32
+  Win32Filters filters(typelist);
+
   // win32 dialog stores the selected "save as type" extension in the second null-terminated string
   char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH];
 
-  if (g_layout_globals.m_bNativeGUI)
+  static OPENFILENAME ofn;       /* common dialog box structure   */ 
+  static char szDirName[MAX_PATH];    /* directory string              */ 
+  static char szFile[MAX_PATH];       /* filename string               */ 
+  static char szFileTitle[MAX_PATH];  /* file title string             */ 
+  static int i, cbString;        /* integer count variables       */ 
+  static HANDLE hf;              /* file handle                   */ 
+
+  // do that the native way
+  /* Place the terminating null character in the szFile. */  
+  szFile[0] = '\0';
+  customfilter[0] = customfilter[1] = customfilter[2] = '\0';
+  
+  /* Set the members of the OPENFILENAME structure. */     
+  ofn.lStructSize = sizeof(OPENFILENAME); 
+  ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window);
+  ofn.nFilterIndex = 0;
+  ofn.lpstrFilter = filters.getFilters();
+  ofn.lpstrCustomFilter = customfilter;
+  ofn.nMaxCustFilter = sizeof(customfilter);
+  ofn.lpstrFile = szFile;
+  ofn.nMaxFile = sizeof(szFile); 
+  ofn.lpstrFileTitle = 0; // we don't need to get the name of the file
+  if(path)
   {
-    // do that the native way
-    /* Place the terminating null character in the szFile. */  
-    szFile[0] = '\0';
-    customfilter[0] = customfilter[1] = customfilter[2] = '\0';
-    
-    /* Set the members of the OPENFILENAME structure. */     
-    ofn.lStructSize = sizeof(OPENFILENAME); 
-    ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window);
-    ofn.nFilterIndex = 0;
-    ofn.lpstrFilter = typelist.m_strWin32Filters;
-    ofn.lpstrCustomFilter = customfilter;
-    ofn.nMaxCustFilter = sizeof(customfilter);
-    ofn.lpstrFile = szFile;
-    ofn.nMaxFile = sizeof(szFile); 
-    ofn.lpstrFileTitle = 0; // we don't need to get the name of the file
-    if(path)
+    // szDirName: Radiant uses unix convention for paths internally
+    //   Win32 (of course) and Gtk (who would have thought) expect the '\\' convention
+    // copy path, replacing dir separators as appropriate
+    for(r=path, w=szDirName; *r!='\0'; r++)
+      *w++ = (*r=='/') ? '\\' : *r;
+    // terminate string
+    *w = '\0';
+    ofn.lpstrInitialDir = szDirName;
+  }
+  else ofn.lpstrInitialDir = 0;
+  ofn.lpstrTitle = title;
+  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 
+
+  /* Display the Open dialog box. */
+  // it's open or close depending on 'open' parameter
+  if (open)
+  {
+    if (!GetOpenFileName(&ofn))
+      return 0; // canceled
+  }
+  else
+  {
+    if (!GetSaveFileName(&ofn))
+      return 0; // canceled
+  }
+
+  if(!string_equal(pattern, "*"))
+  {
+    type = filters.getType(customfilter+1).m_type;
+  }
+
+  // don't return an empty filename
+  if(szFile[0] == '\0') return 0;
+
+  // convert back to unix format
+  for(w=szFile; *w!='\0'; w++)
+  {
+    if(*w=='\\')
     {
-      // szDirName: Radiant uses unix convention for paths internally
-      //   Win32 (of course) and Gtk (who would have thought) expect the '\\' convention
-      // copy path, replacing dir separators as appropriate
-      for(r=path, w=szDirName; *r!='\0'; r++)
-        *w++ = (*r=='/') ? '\\' : *r;
-      // terminate string
-      *w = '\0';
-      ofn.lpstrInitialDir = szDirName;
+      *w = '/';
     }
-    else ofn.lpstrInitialDir = 0;
-    ofn.lpstrTitle = title;
-    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 
-
-    /* Display the Open dialog box. */
-    // it's open or close depending on 'open' parameter
-    if (open)
+  }
+  // when saving, force an extension depending on filetype
+  /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
+  if(!open && !string_equal(pattern, "*"))
+  {
+    // last ext separator
+    const char* extension = path_get_extension(szFile);
+    // no extension
+    if(string_empty(extension))
     {
-      if (!GetOpenFileName(&ofn))
-        return 0; // canceled
+      strcat(szFile, type.pattern+1);
     }
     else
     {
-      if (!GetSaveFileName(&ofn))
-        return 0; // canceled
+      strcpy(szFile + (extension - szFile), type.pattern+2);
     }
-
-    if(!string_equal(pattern, "*"))
-      type = typelist.GetTypeForWin32Filter(customfilter+1).m_type;
-    
   }
-  else
-  {
-#endif
-    // do that the Gtk way
-    if (title == 0)
-      title = open ? "Open File" : "Save File";
-    
-    // we expect an actual path below, if the path is 0 we might crash
-    if (!path || path[0] == '\0')
-    {
-#ifdef WIN32
-      path = "C:\\";
-#elif defined (__linux__) || defined (__APPLE__)
-      path = "/";
-#else
-      path = "/";
-#endif
-    }
 
-    // alloc new path with extra char for dir separator
-    new_path = new char[strlen(path)+1+1];
-    // copy path, replacing dir separators as appropriate
-    for(r=path, w=new_path; *r!='\0'; r++)
-      *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r;
-    // add dir separator to end of path if required
-    if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR;
-    // terminate string
-    *w = '\0';
+  return szFile;
+}
 
-    file_sel = gtk_file_selection_new (title);
-
-#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0
-    // set the masks
-    gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel));
-    gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast<const char**>(typelist.m_pstrGTKMasks));
 #endif
 
-    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",
-      GTK_SIGNAL_FUNC (file_sel_callback), gint_to_pointer (eIDOK));
-    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",
-      GTK_SIGNAL_FUNC (file_sel_callback), gint_to_pointer (eIDCANCEL));
-    gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",
-      GTK_SIGNAL_FUNC (file_sel_delete_callback), 0);
-    gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));
-    
-    if (parent != 0)
+
+class GTKMasks
+{
+  const FileTypeList& m_types;
+public:
+  std::vector<string_t> m_filters;
+  std::vector<string_t> m_masks;
+
+  GTKMasks(const FileTypeList& types) : m_types(types)
+  {
+    m_masks.reserve(m_types.size());
+    for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
     {
-      gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));
+      std::size_t len = strlen((*i).m_name.c_str()) + strlen((*i).m_pattern.c_str()) + 3;
+      StringOutputStream buffer(len + 1); // length + null char
+
+      buffer << (*i).m_name.c_str() << " <" << (*i).m_pattern.c_str() << ">";
+
+      m_masks.push_back(buffer.c_str());
     }
-    
-    bool success = false;
-    g_object_set_data (G_OBJECT (file_sel), "loop", &loop);
-    g_object_set_data (G_OBJECT (file_sel), "success", &success);
-    
-    if (!open)
+
+    m_filters.reserve(m_types.size());
+    for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
     {
-      g_object_set_data (G_OBJECT (file_sel), "overwrite", gint_to_pointer (1));
+      m_filters.push_back((*i).m_pattern);
     }
-    
-    if (new_path != 0)
+  }
+
+  filetype_pair_t GetTypeForGTKMask(const char *mask) const
+  {
+    std::vector<string_t>::const_iterator j = m_masks.begin();
+    for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i, ++j)
     {
-      gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path);
-      delete[] new_path;
+      if(string_equal((*j).c_str(), mask))
+      {
+        return filetype_pair_t((*i).m_minor.c_str(), filetype_t((*i).m_name.c_str(), (*i).m_pattern.c_str()));
+      }
     }
+    return filetype_pair_t();
+  }
 
-    gtk_grab_add (file_sel);
-    gtk_widget_show (file_sel);
+};
 
-    while (loop)
-    {
-      gtk_main_iteration ();
-    }
-    if(success)
-    {
-#if 0 //!\todo Add masks to GtkFileSelection in gtk2
-      if(!string_equal(pattern, "*"))
-        type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask).m_type;
-#endif
-      strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));
-    }
+static char g_file_dialog_file[1024];
+
+const char* file_dialog_show(GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
+{
+  char *new_path = 0;
+
+  const char* r;
+  char* w;
+  filetype_t type;
+
+  if(pattern == 0)
+  {
+    pattern = "*";
+  }
+
+  FileTypeList typelist;
+  GetFileTypeRegistry()->getTypeList(pattern, &typelist);
+
+  GTKMasks masks(typelist);
+
+  if (title == 0)
+    title = open ? "Open File" : "Save File";
     
-    gtk_grab_remove (file_sel);
-    gtk_widget_destroy (file_sel);
+  // we expect an actual path below, if the path is 0 we might crash
+  if (!path || path[0] == '\0')
+  {
 #ifdef WIN32
-  }
+    path = "C:\\";
+#elif defined (__linux__) || defined (__APPLE__)
+    path = "/";
+#else
+    path = "/";
 #endif
+  }
 
-  // don't return an empty filename
-  if(szFile[0] == '\0') return 0;
+  // alloc new path with extra char for dir separator
+  new_path = new char[strlen(path)+1+1];
+  // copy path, replacing dir separators as appropriate
+  for(r=path, w=new_path; *r!='\0'; r++)
+    *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r;
+  // add dir separator to end of path if required
+  if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR;
+  // terminate string
+  *w = '\0';
 
-  // convert back to unix format
-  for(w=szFile; *w!='\0'; w++)
-    if(*w=='\\')
-      *w = '/';
+  GtkWidget* dialog;
+  if (open)
+  {
+    dialog = gtk_file_chooser_dialog_new(title,
+                                        GTK_WINDOW(parent),
+                                        GTK_FILE_CHOOSER_ACTION_OPEN,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                        NULL);
+  }
+  else
+  {
+    dialog = gtk_file_chooser_dialog_new(title,
+                                        GTK_WINDOW(parent),
+                                        GTK_FILE_CHOOSER_ACTION_SAVE,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                        NULL);
+    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "unnamed");
+  }
 
-#if defined(WIN32)
-  if (g_layout_globals.m_bNativeGUI) // filetype mask not supported in gtk dialog yet
+  gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+  gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+
+  if (new_path != 0)
   {
-    // when saving, force an extension depending on filetype
-    /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
-    if(!open && !string_equal(pattern, "*"))
+    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), new_path);
+    delete[] new_path;
+  }
+
+  // we should add all important paths as shortcut folder...
+  // gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), "/tmp/", NULL);
+
+  
+  for(std::size_t i = 0; i < masks.m_filters.size(); ++i)
+  {
+    GtkFileFilter* filter = gtk_file_filter_new ();
+    gtk_file_filter_add_pattern(filter, masks.m_filters[i].c_str());
+    gtk_file_filter_set_name(filter, masks.m_masks[i].c_str());
+    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+  }
+
+  if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
+  {
+    strcpy(g_file_dialog_file, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
+
+    if(!string_equal(pattern, "*"))
     {
+      GtkFileFilter* filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
+      type = masks.GetTypeForGTKMask(gtk_file_filter_get_name(filter)).m_type;
       // last ext separator
-      const char* extension = path_get_extension(szFile);
+      const char* extension = path_get_extension(g_file_dialog_file);
       // no extension
       if(string_empty(extension))
       {
-        strcat(szFile, type.pattern+1);
+        strcat(g_file_dialog_file, type.pattern+1);
       }
       else
       {
-        strcpy(szFile + (extension - szFile), type.pattern+2);
+        strcpy(g_file_dialog_file + (extension - g_file_dialog_file), type.pattern+2);
       }
     }
+
+    // convert back to unix format
+    for(w=g_file_dialog_file; *w!='\0'; w++)
+    {
+      if(*w=='\\') 
+      {
+        *w = '/';
+      }
+    }
   }
-#endif
+  else
+  {
+    g_file_dialog_file[0] = '\0';
+  }
 
-  return szFile;
+  gtk_widget_destroy(dialog);
+
+  // don't return an empty filename
+  if(g_file_dialog_file[0] == '\0') return NULL;
+
+  return g_file_dialog_file;
 }
 
 const char* file_dialog (GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
 {
   for(;;)
   {
-    const char* file = file_dialog_show(parent, open, title, path, pattern);
+    const char* file = g_layout_globals.m_bNativeGUI
+      ? file_dialog_show_win32(parent, open, title, path, pattern)
+      : file_dialog_show(parent, open, title, path, pattern);
+
     if(open
-      || !file_exists(szFile)
+      || !file_exists(file)
       || gtk_MessageBox(parent, "File already exists.\nOverwrite?", "GtkRadiant", eMB_NOYES) == eIDYES)
     {
       return file;
     }
   }
 
-  return 0;
+  return NULL;
 }
 
 #ifdef WIN32




More information about the Gtkradiant mailing list