IGUIFileOpenDialog and changeWorkingDirectoryTo

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.

IGUIFileOpenDialog and changeWorkingDirectoryTo

Postby monkeycracks » Mon Mar 31, 2008 2:11 am

Well at least this time I searched through the docs...
How do I set file extension limitations on what shows up in the dialog?
If this isn't possible does anyone have any theories on what could be done?

Otherwise, how could I go about using the Windows file open dialog with Irrlicht using the IEventReceiver? (I think this is impossible.)

As for the changeWorking.. etc. etc.

For some reason if the folder that I want to change to is not found, it doesn't seem to return false. It still moves the working directory to that folder. This is kinda irritating as I was using that as the only way I could tell if the directory existed or not.

I'm using the latest SVN and D3D9. The tests were on XP and on Vista. The Documents and Settings folder wasn't on the Vista computer (Two different computers.) yet it still changed the working directory to it.
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA

Re: IGUIFileOpenDialog and changeWorkingDirectoryTo

Postby vitek » Mon Mar 31, 2008 3:23 am

monkeycracks wrote:Well at least this time I searched through the docs...
How do I set file extension limitations on what shows up in the dialog?
If this isn't possible does anyone have any theories on what could be done?

Write a function that tells you if a filename matches a given pattern. I wrote one a long time ago that supports '*' and '?' like windows does. In the unix world there is a POSIX function named fnmatch() that you could use. You could write your own version of it in a hundred lines or so.

moneycracks wrote:Otherwise, how could I go about using the Windows file open dialog with Irrlicht using the IEventReceiver? (I think this is impossible.)

It is possible, but I wouldn't recommend it. I worked on an application that used CFileOpenDialog windows on top of a D3D9 application. There were often problems that would come up. The dialog would disappear, it would cause problems with the application window... It was a mess.

moneycracks wrote:For some reason if the folder that I want to change to is not found, it doesn't seem to return false. It still moves the working directory to that folder. This is kinda irritating as I was using that as the only way I could tell if the directory existed or not.

You can see if a directory exists using the IFileList interface, or you could go down a level and use stat().

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby vitek » Mon Mar 31, 2008 3:29 am

Here is the code that I wrote for file pattern matching. It _should_ work for expressions with * and ?.

Code: Select all
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

bool
simple_filename_match(const char* pat, const char* str)
{
   // may recursively call self to do pattern matching
   while (*pat && *str)
   {
      switch (*pat)
      {
      // match 0 or more characters
      case '*':
         while (*pat == '*')
            ++pat; // additional stars mean nothing
         while ((str = strchr(str, *pat)) != 0)
         {
            if (simple_filename_match(pat, str++))
               return true;
         }

         if (!str)
            return false;
         break;

      // match any one character
      case '?':
         pat += 1;
         str += 1;
         break;

      // match a character
      default:
         if (*pat++ != *str++)
            return false;
         break;
      }
   }
   
   return !(*pat || *str);
}


The documentation for fnmatch() can be found here.

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby monkeycracks » Mon Mar 31, 2008 4:09 am

Lost me a bit with that.. let me see if I get it..

const char* pat would be "*.jpg" and str would be the filepath?
if the filepath is a .jpg file, the bool returns true?


Orrr did I just miss that point completely..

Also, I'm targeting the Windows platform as I'm using some wininet and windows things.

Also, could you expound a bit on the IFileList thing, I understand that I'll want to use isDirectory, but how would I find the index number of said directory
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA

Postby vitek » Mon Mar 31, 2008 9:51 am

monkeycracks wrote:const char* pat would be "*.jpg" and str would be the filepath?if the filepath is a .jpg file, the bool returns true?

Yes. It just tells you if the string str matches the pattern pat. If pat is "*.jpg", and str is "image.jpg", the function would return true. A quick change to the file dialog and its interface and you have file name filtering.

moneycracks wrote:Also, could you expound a bit on the IFileList thing, I understand that I'll want to use isDirectory, but how would I find the index number of said directory

I looked at the implementation of changeWorkingDirectoryTo(), and it uses chdir(). That function is documented to fail if the specified directory does not exist. So, you shouldn't need to do any workarounds. It should just work. Maybe you are running into a special case on Windows?

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby monkeycracks » Mon Mar 31, 2008 10:53 am

Well I can't be too sure on the Vista computer as I can't have a look myself, but the tester said he was pretty sure that he did not have a C:\Documents and Settings.

Thanks for clarifying on that, I'll try to get it implemented sometime later today. Do you think that something like "*.jpg\0 *.bmp\0 *.png" (similar to the windows file open dialog) would be possible or will I need to modify the code for that?

Edit: I just failed at attempting to modify the engine, can't for the life of me figure out what I've done wrong. I added setPattern(char* pattern) and a stringc inside CFileOpenDialog to hold it. I changed the code at Ln 326-336
from
Code: Select all
   for (u32 i=0; i<FileList->getFileCount(); ++i)
   {
      s = FileList->getFileName(i);
      FileBox->addItem(s.c_str(), skin->getIcon(FileList->isDirectory(i) ? EGDI_DIRECTORY : EGDI_FILE));
   }

   if (FileNameText)
   {
      s = FileSystem->getWorkingDirectory();
      FileNameText->setText(s.c_str());
   }

to
Code: Select all
   for (u32 i=0; i<FileList->getFileCount(); ++i)
   {
      s = FileList->getFileName(i);
      if(simple_filename_match(pattern.c_str(), stringc(s.c_str()).c_str()))
      {
         FileBox->addItem(s.c_str(), skin->getIcon(FileList->isDirectory(i) ? EGDI_DIRECTORY : EGDI_FILE));
      }
   }

   if (FileNameText)
   {
      s = FileSystem->getWorkingDirectory();
      FileNameText->setText(s.c_str());
   }


('s' is a stringw)

It throws no compile errors but when I use d->addPattern("*.jpg");, nothing in the file list shows up at all. Not even the . and .. normally located to navigate through dirs.

My theory is that I should be using the addPattern in the constructor and not after its made and fillFileList() (it's in the constructor) is called. I'll look into that when I get home.
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA

Postby vitek » Mon Mar 31, 2008 6:58 pm

monkeycracks wrote:Do you think that something like "*.jpg\0 *.bmp\0 *.png" (similar to the windows file open dialog) would be possible or will I need to modify the code for that?

Yes, this could be done quite easily. You would need to write a short routine to check for matches on each of the patterns. This should do it.

Code: Select all
bool simple_filename_match_many (const char* pat, const char* str)
{
  // it is expected that pat is a null terminated string
  // of null terminated strings. i.e. it ends with two nulls.

  for (/**/; *pat; pat += strlen (pat) + 1)
  {
    if (simple_filename_match (pat, str))
      return true;
  }

  return false;
}


moneycracks wrote:I just failed at attempting to modify the engine, can't for the life of me figure out what I've done wrong...


Uh, well I think you want to filter filenames only. You probably don't want to filter directories.

Code: Select all
for (u32 i=0; i<FileList->getFileCount(); ++i)
{
    const core::stringw s = FileList->getFileName(i);

    if (FileList->isDirectory(i))
    {
      // always include directories
      FileBox->addItem(s.c_str(), skin->getIcon(EGDI_DIRECTORY));
    }
    else if (!pattern.c_str())
    {
      // no pattern string, so show all files
      FileBox->addItem(s.c_str(), skin->getIcon(EGDI_FILE));
    }
    else
    {
      // we have a pattern string, only include file if it matches one
      // of the patterns
      const core::stringc ss (s.c_str());

      if (simple_filename_match_many(pattern.c_str(), ss.c_str()))
      {
        // only include files if they match pattern
        FileBox->addItem(s.c_str(), skin->getIcon(EGDI_FILE));
      }
   }
}



If you want to do this, your setPattern() function has to be smart enough to capture the full null terminated list of null terminated strings, or the caller has to be smart enough to do the right thing to make sure that the embedded nulls are included in the length of the string. I would propose that you write one of the following. Remember that 's' must be double null terminated.

Code: Select all
void CGUIFileOpenDialog::setPattern (const c8* s, u32 n)
{
  pattern = core::stringc (s, n);
  fillListBox(); // refresh file list
}

void CGUIFileOpenDialog::setPattern (const core::stringc& s)
{
  pattern = s;
  fillListBox(); // refresh file list
}


moneycracks wrote:'s' is a stringw

You can easily modify the code I've provided to work with wchar_t so you don't have to do all of that conversion.

moneycracks wrote:My theory is that I should be using the addPattern in the constructor and not after its made and fillFileList() (it's in the constructor) is called. I'll look into that when I get home.

The code I've provided above should not have that problem. If there is no pattern string, then all files are selected. If you set the pattern after the dialog is constructed, then the list box will be refreshed.

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby monkeycracks » Mon Mar 31, 2008 9:10 pm

Thanks vitek. I really appreciate all the help you're giving me on this. Everything works like a charm!

The only question I have remaining is

Also, could you expound a bit on the IFileList thing, I understand that I'll want to use isDirectory, but how would I find the index number of said directory


if anyone cares to answer it.

Thanks much again vitek. Strings always seem to give me troubles.


Edit:: sorry that may have not been clear enough, I want to get the index number based on the name of the directory if possible


Edit:: Sorry for bugging you again vitek, but would it be possible to have more than two patterns? As is I can only do "*.jpg\0*.bmp\0", anything past the second \0 gets ignored by the function and I'm not exactly sure how to make it consider more.
Last edited by monkeycracks on Mon Mar 31, 2008 9:29 pm, edited 1 time in total.
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA

Postby vitek » Mon Mar 31, 2008 9:19 pm

Iterate through each of the entries in the file list. When you find the one that has a matching name, you have the index.

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby monkeycracks » Mon Mar 31, 2008 9:29 pm

Vitek, Thanks again, I edited my post at the bottom right as you posted.
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA

Postby vitek » Tue Apr 01, 2008 12:18 am

moneycracks wrote:I want to get the index number based on the name of the directory if possible

Yes, you do exactly like I said. You iterate through the file list from 0 to fileList->getFileCount(). For every name in the list, you compare it against the name you are looking for. If you find a name that matches, then you know the index of that name.

I've written enough code for you, so I'm not going to write this. It is a simple loop with a counter. It is no more than 5 lines of code.

moneycracks wrote:Sorry for bugging you again vitek, but would it be possible to have more than two patterns? As is I can only do "*.jpg\0*.bmp\0", anything past the second \0 gets ignored by the function and I'm not exactly sure how to make it consider more.

I don't know what you're doing wrong, but the code I posted does not have this problem. If I had to guess, I'd say that the pattern string was cut short because you didn't initialize it in such a way that the embeded nulls are kept.

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby monkeycracks » Tue Apr 01, 2008 12:23 am

I've written enough code for you, so I'm not going to write this. It is a simple loop with a counter. It is no more than 5 lines of code.


Didn't mean that part, sorry ;). I've got that mostly figured out.


As for the initializing it in a way that the null embeds aren't kept : I think c_str(); in the stringc and stringw does it. I'm not for sure but I'll look for a workaround and see if I can't find a way to avoid using them.
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA

Postby monkeycracks » Tue Apr 01, 2008 12:40 am

Yes I found the problem!


const core::stringw s(L"file.png");
const core::stringc ss(s.c_str());

If I change stringw s to stringc s, the embeds aren't lost. I'll have to make the workarounds now. Thanks for the kickoff vitek.
monkeycracks
 
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA


Return to Beginners Help

Who is online

Users browsing this forum: No registered users and 0 guests