(C++) File Selector/Dialog v1.1

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

It can ;)

I don't think i demo'd that in the above application but in the new editor for IrrAI (unreleased as of yet) you can select directories, so it should be available in this snippet i think...
Image Image Image
fabietto
Posts: 93
Joined: Wed Sep 24, 2008 4:38 pm
Location: Plymouth, UK
Contact:

Post by fabietto »

JP wrote:It can ;)

I don't think i demo'd that in the above application but in the new editor for IrrAI (unreleased as of yet) you can select directories, so it should be available in this snippet i think...
Nice to know. I'll give it a try right now... :)
fabietto
Posts: 93
Joined: Wed Sep 24, 2008 4:38 pm
Location: Plymouth, UK
Contact:

Post by fabietto »

I've played a bit with this class and it looks well coded. I'd just highlight two points:

1) the dialog doesn't close when I select a file/directory (I've seen that this has already been pointed before);

2) it would be nice to have a dialog which automatically makes the application waiting for the user response (basically a loop which ends only when the user has done something, both selected a file/directory or pressed the cancel button). Maybe passing a Boolean flag to the constructor?

My two cents... :)
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

Yeah i've not got round to making it close when you double click a file or directory... not sure that i will.. the button works fine ;) heh

Your other suggestion is sort of an ok suggestion in a way.. would be useful for sure, but it wouldn't be ideal for an element to hold up rendering i don't think... it kinda breaks the design of irrlicht.. if that were added in i'm sure it wouldn't be accepted into irrlicht itself by the devs.

It's not particularly hard to wait for the dialog to be dealt with.. When you create it raise a flag saying it's open and then listen out for the element closed event and lower the flag when that's done. Whilst the flag is up don't do anything else with the app.
Image Image Image
fabietto
Posts: 93
Joined: Wed Sep 24, 2008 4:38 pm
Location: Plymouth, UK
Contact:

Post by fabietto »

JP wrote:Yeah i've not got round to making it close when you double click a file or directory... not sure that i will.. the button works fine ;) heh

Your other suggestion is sort of an ok suggestion in a way.. would be useful for sure, but it wouldn't be ideal for an element to hold up rendering i don't think... it kinda breaks the design of irrlicht.. if that were added in i'm sure it wouldn't be accepted into irrlicht itself by the devs.

It's not particularly hard to wait for the dialog to be dealt with.. When you create it raise a flag saying it's open and then listen out for the element closed event and lower the flag when that's done. Whilst the flag is up don't do anything else with the app.
Well, to be honest on my Mac the dialog didn't close in both ways... :)

I can agree with your second point if you speak in terms of Irrlicht's way of coding (or maybe 3D-engines way of coding in general), but typically a dialog box has to do exactly that. It has to stop the application until the user does something (ie, select a file). Maybe it could be possible to stop just the scene manager rendering. Furthermore I can't see any reasons, in a real application, for doing rendering when the user is selecting a file/directory (which are typically used for loading/saving stuff).

It's true that it's possible to use flags for controlling the opening/closing of the dialog, but it becomes really weird, particularly if you need to use more than one dialog and you want to perform checks on the selected files/directories as well.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

You could make the file selector modal if it were part of the engine (probably if it wasn't part of the engine too i guess but i didn't look into that much) which would mean you couldn't click on another GUI element until you'd dealt with the file dialog, i guess that's what you mean?

So you have no way of closing the dialog in the sample app at all? You can't click on a file to select it and then press Open? That doesn't get rid of it? Does the console output say anything strange?
Image Image Image
fabietto
Posts: 93
Joined: Wed Sep 24, 2008 4:38 pm
Location: Plymouth, UK
Contact:

Post by fabietto »

JP wrote:You could make the file selector modal if it were part of the engine (probably if it wasn't part of the engine too i guess but i didn't look into that much) which would mean you couldn't click on another GUI element until you'd dealt with the file dialog, i guess that's what you mean?
Well, it doesn't really matter if I can click on others GUI elements while the dialog is still open (of course, it would be better if I couldn't). What I'd like to have is a dialog that blocks my application until the user has taken his decision (ie, selected a file/directory). In my application, for example, I first display the GUI elements. Then, when the user press a certain button, I'd like to have the dialog appearing (asking the user where he wants to store the data generated by the application) and, when it has been closed selecting a file/directory, the application can start sure that the data directory has already been selected. Of course I could do that using some flags, but it's not a clean solution. And it becomes a bit complicated to manage if I want to use more than one dialog, one next to each other, to ask various things to the user.
JP wrote:So you have no way of closing the dialog in the sample app at all? You can't click on a file to select it and then press Open? That doesn't get rid of it? Does the console output say anything strange?
Exactly. I haven't checked that carefully, since I've decided to switch to the Qt's QFileDialog. Unfortunately, I've removed the class from my application now, but I could add it again if you want to do some testing.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

It's strange it doesn't work at all as no one else has complained about it... And it's always worked fine for me... Maybe it's a mac thing...

I would suggest that if you want the file selector to block your app then you implement that yourself in some way. I guess you could create the file selector and then sit in a loop directly after just calling the render function of the file selector.. that may work... also calling device->run() in the loop would be a good idea to keep the timer updated and events dispatching.
Image Image Image
fabietto
Posts: 93
Joined: Wed Sep 24, 2008 4:38 pm
Location: Plymouth, UK
Contact:

Post by fabietto »

JP wrote:It's strange it doesn't work at all as no one else has complained about it... And it's always worked fine for me... Maybe it's a mac thing...
Ok, I'll test it deeply this evening and I'll let you know. Please, send me a reminder if you won't hear anything from me soon... ;)
JP wrote:I would suggest that if you want the file selector to block your app then you implement that yourself in some way. I guess you could create the file selector and then sit in a loop directly after just calling the render function of the file selector.. that may work... also calling device->run() in the loop would be a good idea to keep the timer updated and events dispatching.
Yeah, it sounds good in principle. Anyway, I've seen that using Qt stuff (my application already relies on Qt, so I can use its functions without any hassle) I'm able to obtain the effect I was looking for, so I'm fine now. I was just giving you my humble advice, since I think that in any real applications there's no reason to continue the rendering (and so progressing the application) while the user has to take a decision (which is typically time-dependent).
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

I'm not actually using Qt.. never used it ever :lol: What makes you think i was?

One reason you might want to keep rendering whilst the dialog is open is if the user moves the dialog around the screen then you'll get some nasty effects going on in the space where it used to be as the render isn't being updated.
Image Image Image
fabietto
Posts: 93
Joined: Wed Sep 24, 2008 4:38 pm
Location: Plymouth, UK
Contact:

Post by fabietto »

JP wrote:I'm not actually using Qt.. never used it ever :lol: What makes you think i was?
Uhm, no... I was just saying that, in *my application*, *I* can use Qt instead that the Irrlicht's file selector... :p
JP wrote:One reason you might want to keep rendering whilst the dialog is open is if the user moves the dialog around the screen then you'll get some nasty effects going on in the space where it used to be as the render isn't being updated.
So, it should be enough to keep the GUI rendered, but I still can't see any reason for rendering the entire graphics scene... :)
Dorth
Posts: 931
Joined: Sat May 26, 2007 11:03 pm

Post by Dorth »

Because if not, you'll smear your gui on the background, which is ugly.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

Aye that's what i was saying, moving around the file selector, which is perfectly allowable, will smear a great mess over anything that you've stopped rendering.

Yeah sorry, misread your post, thought you said i see you're using Qt :lol:
Image Image Image
thespecial1
Posts: 135
Joined: Thu Oct 30, 2008 11:56 am
Location: UK
Contact:

Post by thespecial1 »

Hi all

I would like to submit a modification to the outstanding file selector class that (for windows) adds a drive letter selection box, had to involve the win32Api so not sure what this will do on 64/vista but it works even if it involves a dirty hack, I needed this badly for my project.

CGUIFileSelector.h

Code: Select all

#ifndef INC_CGUIFILESELECTOR_H
#define INC_CGUIFILESELECTOR_H

#include <irrlicht.h>
#ifdef _IRR_WINDOWS_
	#include <windows.h>
	#include <iostream>
#endif

using namespace irr;
using namespace gui;

/** Class for opening/saving files. */
class CGUIFileSelector : public IGUIFileOpenDialog {
      
	public:
        /** Enum to specify the usage of the instance of the class */   
        enum E_FILESELECTOR_TYPE {
          EFST_OPEN_DIALOG, //<! For opening files
          EFST_SAVE_DIALOG, //<! For saving files
          EFST_NUM_TYPES    //<! Not used, just specifies how many possible types there are
        };
                  
        /** 
		\brief Constructor
		\param title - The title of the dialog
		\pararm environment - The GUI environment to be used
		\param parent - The parent of the dialog
		\param id - The ID of the dialog
		\param type - The type of dialog
		*/
		CGUIFileSelector(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id, E_FILESELECTOR_TYPE type);

		/**
        \brief Destructor
        */
		virtual ~CGUIFileSelector();
		
		/**
        \brief Returns the filename of the selected file. Returns NULL, if no file was selected.
        \return a const wchar_t*
        */
		virtual const wchar_t* getFileName() const;

		/**
        \brief called if an event happened.
        \param even - the event that happened
        \return a bool
        */
		virtual bool OnEvent(const SEvent& event);

		/**
		\brief Render function
		*/
		virtual void draw();
		
		/**
		\brief Returns the current file filter selected or "All Files" if no filter is applied
		\return a stringw
		*/
		inline core::stringw getFileFilter() const {
               if (FilterComboBox->getSelected() >= FileFilters.size()) return core::stringw("All Files"); 
               else return FileFilters[FilterComboBox->getSelected()].FileExtension;
        }
        
        /**
        \brief Returns the type of the dialog
        \return a E_FILESELECTOR_TYPE
        */
        inline E_FILESELECTOR_TYPE getDialogType() { return DialogType; }
        
        /**
        \brief Add a file filter
        \param name - The description of the file type
        \param ext - The file's extension
        \param texture - The icon texture
        */
        void addFileFilter(wchar_t* name, wchar_t* ext, video::ITexture* texture);
        
        /**
        \brief Set an icon to use to display unknown files
        \param texture - the 16x16 icon to use
        */
        inline void setCustomFileIcon(video::ITexture* texture) {
          if (texture) FileIconIdx = addIcon(texture);
          else FileIconIdx = -1;
          fillListBox();
        }
        /**
        \brief Set an icon to use to display directories
        \param texture - the 16x16 icon to use
        */
        inline void setCustomDirectoryIcon(video::ITexture* texture) {
          if (texture) DirectoryIconIdx = addIcon(texture);
          else DirectoryIconIdx = -1;
          fillListBox();
        }
        
        /**
        \brief Sets whether directories can be chosen as the 'file' to open
        \param choosable - Whether the directory can be chosen
        */
        inline void setDirectoryChoosable(bool choosable) { IsDirectoryChoosable = choosable; }

	protected:

        /**
        \brief Returns true if the file extension is one of the registered filters
        \param s - the string to be checked
        \return a bool
        */
        bool matchesFileFilter(core::stringw s);
        /**
        \brief Returns true if the file extension matches the specified filter
        \param s - the string to be checked
        \param f - the filter to check for
        \return a bool
        */
        bool matchesFileFilter(core::stringw s, core::stringw f);
        
		/**
        \brief Fills the listbox with files.
        */
		void fillListBox();

		/**
        \brief Sends the event that the file has been selected.
        */
		void sendSelectedEvent();

		/**
        \brief Sends the event that the file choose process has been canceld
        */
		void sendCancelEvent();
		
		u32 addIcon(video::ITexture* texture);
				
		/** Struct to describe file filters to use when displaying files in directories */
        struct SFileFilter {
          /*
          \brief Constructor
          \param name - The name/description of the filter
          \param filter - The file extension required
          \param texture - The texture to use as an icon for the file type
          */
          SFileFilter(wchar_t* name, wchar_t* filter, video::ITexture* texture) {
            FilterName = name;
            FileExtension = filter;
            FileIcon = texture;
            FileIconIdx = 0;
          }
          void operator=(const SFileFilter& other) {
            FilterName = other.FilterName;
            FileExtension = other.FileExtension;
            FileIcon = other.FileIcon;
            FileIconIdx = other.FileIconIdx;
          }
          core::stringw FilterName;
          core::stringw FileExtension;     
          video::ITexture* FileIcon;
          u32 FileIconIdx;
        };

		core::position2d<s32> DragStart;
		bool Dragging;
		bool IsDirectoryChoosable;
		s32 FileIconIdx;
		s32 DirectoryIconIdx;
		IGUIButton* CloseButton;
		IGUIButton* OKButton;
		IGUIButton* CancelButton;
		IGUIEditBox* FileNameText;
		IGUIListBox* FileBox;
		IGUIComboBox* DriveBox;
		IGUIComboBox* FilterComboBox;
		IGUIElement* EventParent;
		IGUISpriteBank* SpriteBank;
		io::IFileSystem* FileSystem;
		io::IFileList* FileList;
		core::array<SFileFilter> FileFilters;
		E_FILESELECTOR_TYPE DialogType;
		core::stringc prev_working_dir;
		
		static s32 numFileSelectors;
			
};

#endif /* INC_CGUIFILESELECTOR_H */

CGUIFileSelector.cpp

Code: Select all

#include <CGUIFileSelector.h>


const s32 FOD_WIDTH = 350;
const s32 FOD_HEIGHT = 265;

s32 CGUIFileSelector::numFileSelectors = 0;

wchar_t *returnMultiByte_FromString(std::string sIn) {  // return a multibyte from a string
	wchar_t *tempBuff = new wchar_t[sIn.length() + 1];
	mbstowcs(tempBuff,sIn.c_str(),sIn.length() + 1);
	return tempBuff;
}

//! constructor
CGUIFileSelector::CGUIFileSelector(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id, E_FILESELECTOR_TYPE type)
: IGUIFileOpenDialog(environment, parent, id,
 core::rect<s32>((parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2,
					(parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2,	
					(parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2+FOD_WIDTH,
					(parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2+FOD_HEIGHT)),	
  Dragging(false), FileNameText(0), FileList(0), DialogType(type) {   
    #ifdef _DEBUG
	  IGUIElement::setDebugName("CGUIFileSelector");
	#endif    
    
    Text = title;
    IsDirectoryChoosable = false;
    
	IGUISkin* skin = Environment->getSkin();
	IGUISpriteBank* sprites = 0;
	video::SColor color(255,255,255,255);
	if (skin) {
		sprites = skin->getSpriteBank();
		color = skin->getColor(EGDC_WINDOW_SYMBOL);
	}

	s32 buttonw = Environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH);
	s32 posx = RelativeRect.getWidth() - buttonw - 4;

	CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1, 
		L"", L"Close");
	CloseButton->setSubElement(true);
	if (sprites) {
		CloseButton->setSpriteBank(sprites);
		CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), color);
		CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), color);
	}
	CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	CloseButton->grab();

	OKButton = Environment->addButton(
		core::rect<s32>(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50), 
		this, -1, (DialogType==EFST_OPEN_DIALOG?L"Open":L"Save"));
	OKButton->setSubElement(true);
	OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	OKButton->grab();

	CancelButton = Environment->addButton(
		core::rect<s32>(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75), 
		this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel");
	CancelButton->setSubElement(true);
	CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	CancelButton->grab();

	FileBox = Environment->addListBox(core::rect<s32>(10, 80, RelativeRect.getWidth()-90, 230), this, -1, true);
	FileBox->setSubElement(true);
	FileBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
	FileBox->grab();

	DriveBox = Environment->addComboBox(core::rect<s32>(10, 55, RelativeRect.getWidth()-90, 75), this, -1);
	DriveBox->setSubElement(true);
	DriveBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	DriveBox->grab();	

	FileNameText = Environment->addEditBox(0, core::rect<s32>(10, 30, RelativeRect.getWidth()-90, 50), true, this, -1);
	FileNameText->setSubElement(true);
	FileNameText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	FileNameText->setTextAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	FileNameText->grab();
	
	FilterComboBox = Environment->addComboBox(core::rect<s32>(10, RelativeRect.getHeight()-30, RelativeRect.getWidth()-90, RelativeRect.getHeight()-10), this, -1);
	FilterComboBox->setSubElement(true);
	FilterComboBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
	FilterComboBox->grab();
    FilterComboBox->addItem(L"All Files");
   
    core::stringc str = "FileSelectorIcons";
    str += numFileSelectors++;
    SpriteBank = Environment->addEmptySpriteBank(str.c_str());
    if (SpriteBank) {
      SpriteBank->grab();
      FileBox->setSpriteBank(SpriteBank);
    }
    DirectoryIconIdx = -1;
    FileIconIdx = -1;
	
	FileSystem = Environment->getFileSystem();
	
	if (FileSystem) {
		FileSystem->grab();
	    prev_working_dir = FileSystem->getWorkingDirectory();
		//printf("working directory saved: %s\n", prev_working_dir.c_str());
	}

	fillListBox();


#ifdef _IRR_WINDOWS_
	enum { SZ = 1024, GB = 1024*1024*1024 } ;
	char drives[SZ] ;

	if (GetLogicalDriveStrings( SZ, drives ) < SZ) {
		char* p = drives;
		while( *p ) { // two null chars; end of list    
			DriveBox->addItem(returnMultiByte_FromString(p));

			while( *p ) ++p ; // get to next null char
			++p ; // and then skip over it
		}
	}
#endif
#ifndef _IRR_WINDOWS_
	
#endif

}



//! destructor
CGUIFileSelector::~CGUIFileSelector() {
	if (CloseButton)
		CloseButton->drop();

	if (OKButton)
		OKButton->drop();

	if (CancelButton)
		CancelButton->drop();

	if (FileBox)
		FileBox->drop();

	if (FileNameText)
		FileNameText->drop();

	if (FileSystem)
		FileSystem->drop();

	if (FileList)
		FileList->drop();
		
	if (FilterComboBox)
	    FilterComboBox->drop();
	    
    if (SpriteBank)
        SpriteBank->drop();
	    
}


//! returns the filename of the selected file. Returns NULL, if no file was selected.
const wchar_t* CGUIFileSelector::getFileName() const {
	return FileNameText->getText();
}



//! called if an event happened.
bool CGUIFileSelector::OnEvent(const SEvent& event) {
	switch(event.EventType) {
    case EET_KEY_INPUT_EVENT:
         switch (event.KeyInput.Key) {
           case KEY_RETURN:
             if (FileSystem) {
			   FileSystem->changeWorkingDirectoryTo(core::stringc(FileNameText->getText()).c_str());
			   fillListBox();
			   FileNameText->setText(core::stringw(FileSystem->getWorkingDirectory()).c_str());
	         }
             return true;
         }
         break;
	case EET_GUI_EVENT:
		switch(event.GUIEvent.EventType) {
        case EGET_COMBO_BOX_CHANGED:
			if (event.GUIEvent.Caller == FilterComboBox) {
				fillListBox();
			} else {  // change drive
				if (FileSystem) {		
					FileSystem->changeWorkingDirectoryTo(core::stringc(DriveBox->getText()).c_str());
					fillListBox();
				}
			}
			break;
		case EGET_ELEMENT_FOCUS_LOST:
			Dragging = false;
			break;
		case EGET_BUTTON_CLICKED:
			if (event.GUIEvent.Caller == CloseButton ||
				event.GUIEvent.Caller == CancelButton) {
                if (FileSystem) {
				  FileSystem->changeWorkingDirectoryTo(prev_working_dir.c_str());
				  //printf("working directory reset to: %s\n", prev_working_dir.c_str());
				}
				sendCancelEvent();
				remove();
				return true;
			}
			else
			if (event.GUIEvent.Caller == OKButton && (IsDirectoryChoosable || matchesFileFilter(FileNameText->getText()))) {
				if (FileSystem) {
				  FileSystem->changeWorkingDirectoryTo(prev_working_dir.c_str());
				  //printf("working directory reset to: %s\n", prev_working_dir.c_str());
				}
				sendSelectedEvent();
				remove();
				return true;
			}
			break;

		case EGET_LISTBOX_CHANGED:
			{
				s32 selected = FileBox->getSelected();
				if (FileList && FileSystem)
				{
					core::stringw strw;
					strw = FileSystem->getWorkingDirectory();
					if (strw[strw.size()-1] != '\\')
					  strw += "\\";
					strw += FileBox->getListItem(selected);
					FileNameText->setText(strw.c_str());
				}
			}
			break;
		case EGET_LISTBOX_SELECTED_AGAIN: 
			{			
				s32 selected = FileBox->getSelected();
				if (FileList && FileSystem) {
					if (FileList->isDirectory(selected)) {
						FileSystem->changeWorkingDirectoryTo(FileList->getFileName(selected));
						fillListBox();
						FileNameText->setText(core::stringw(FileSystem->getWorkingDirectory()).c_str());
					}
					else
					{
						core::stringw strw;
						strw = FileSystem->getWorkingDirectory();
			    		if (strw[strw.size()-1] != '\\')
						  strw += "\\";
						strw += FileBox->getListItem(selected);
						FileNameText->setText(strw.c_str());
						return true;
					}
				}
			}
			break;
		}
		break;
	case EET_MOUSE_INPUT_EVENT:
		switch(event.MouseInput.Event) {
		case EMIE_LMOUSE_PRESSED_DOWN:
			DragStart.X = event.MouseInput.X;
			DragStart.Y = event.MouseInput.Y;
			Dragging = true;
			Environment->setFocus(this);
			return true;
		case EMIE_LMOUSE_LEFT_UP:
			Dragging = false;
			Environment->removeFocus(this);
			return true;
		case EMIE_MOUSE_MOVED:
			if (Dragging) {
				// gui window should not be dragged outside its parent
				if (Parent)
					if (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 ||
						event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 ||
						event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 ||
						event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1)

						return true;

				move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
				DragStart.X = event.MouseInput.X;
				DragStart.Y = event.MouseInput.Y;
				return true;
			}
			break;
		}
	}

	return Parent ? Parent->OnEvent(event) : false;
}


//! draws the element and its children
void CGUIFileSelector::draw() {
	if (!IsVisible)
		return;

	IGUISkin* skin = Environment->getSkin();

	core::rect<s32> rect = AbsoluteRect;

	rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), 
		rect, &AbsoluteClippingRect);

	if (Text.size()) {
		rect.UpperLeftCorner.X += 2;
		rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5;

		IGUIFont* font = skin->getFont(EGDF_WINDOW);
		if (font)
			font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true, 
			&AbsoluteClippingRect);
	}

	IGUIElement::draw();
}

//bool CGUIFileSelector::matchesFileFilter(core::stringw s) {
//  if (FilterComboBox->getSelected() >= FileFilters.size()) return true; // 'All Files' selectable
//  else {
//    s32 pos = s.findLast('.'); // Find the last '.' so we can check the file extension
//    return FileFilters[FilterComboBox->getSelected()].FileExtension.equals_ignore_case(core::stringw(&s.c_str()[pos+1])); 
//  }
//}

bool CGUIFileSelector::matchesFileFilter(core::stringw s) { 
   if (FileFilters.size() > 1) {
      s32 selected = FilterComboBox->getSelected();
      if (selected == 0) {
         for (s32 i = 0; i < FileFilters.size(); i++) {
            s32 pos = s.findLast('.'); // Find the last '.' so we can check the file extension
            if (FileFilters[i].FileExtension.equals_ignore_case(core::stringw(&s.c_str()[pos+1])))
               return true;
         }
         return false;
      }
      selected--;
      if (selected >= FileFilters.size()) return true; // 'All Files' selectable
      else {
         s32 pos = s.findLast('.'); // Find the last '.' so we can check the file extension
         return FileFilters[selected].FileExtension.equals_ignore_case(core::stringw(&s.c_str()[pos+1]));
      }
   }
   if (FilterComboBox->getSelected() >= FileFilters.size()) return true; // 'All Files' selectable
   else {
      s32 pos = s.findLast('.'); // Find the last '.' so we can check the file extension
      return FileFilters[FilterComboBox->getSelected()].FileExtension.equals_ignore_case(core::stringw(&s.c_str()[pos+1]));
   }
} 

bool CGUIFileSelector::matchesFileFilter(core::stringw s, core::stringw f) {
  s32 pos = s.findLast('.'); // Find the last '.' so we can check the file extension
  return f.equals_ignore_case(core::stringw(&s.c_str()[pos+1])); 
}

//! fills the listbox with files.
void CGUIFileSelector::fillListBox() {
	IGUISkin *skin = Environment->getSkin();

	if (!FileSystem || !FileBox || !skin)
		return;

	if (FileList)
		FileList->drop();

	FileBox->clear();

	FileList = FileSystem->createFileList();
	core::stringw s;

	for (u32 i=0; i<FileList->getFileCount(); ++i) {
		s = FileList->getFileName(i);
		// We just want a list of directories and those matching the file filter
		if (FileList->isDirectory(i))
          if (DirectoryIconIdx != -1) FileBox->addItem(s.c_str(), DirectoryIconIdx);
          else                        FileBox->addItem(s.c_str());
		else if (matchesFileFilter(s))
		  if (FilterComboBox->getSelected() >= FileFilters.size())
            if (FileIconIdx != -1) {
              s32 iconIdx = FileIconIdx;
              for (u32 i = 0 ; i < FileFilters.size() ; i++) 
                if (matchesFileFilter(s, FileFilters[i].FileExtension))
                  iconIdx = FileFilters[i].FileIconIdx;
              FileBox->addItem(s.c_str(), iconIdx);
            } else  FileBox->addItem(s.c_str());
		  else FileBox->addItem(s.c_str(), FileFilters[FilterComboBox->getSelected()].FileIconIdx);        

	}

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


//! sends the event that the file has been selected.
void CGUIFileSelector::sendSelectedEvent() {
	SEvent event;
	event.EventType = EET_GUI_EVENT;
	event.GUIEvent.Caller = this;
	event.GUIEvent.EventType = EGET_FILE_SELECTED;
	Parent->OnEvent(event);
}

//! sends the event that the file choose process has been canceld
void CGUIFileSelector::sendCancelEvent() {
	SEvent event;
	event.EventType = EET_GUI_EVENT;
	event.GUIEvent.Caller = this;
	event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED;
	Parent->OnEvent(event);
}

//void CGUIFileSelector::addFileFilter(wchar_t* name, wchar_t* ext, video::ITexture* texture) {
//  SFileFilter filter(name, ext, texture);
//  
//  filter.FileIconIdx = addIcon(texture);
//  
//  FileFilters.push_back(filter);  
//  
//  FilterComboBox->clear();
//  core::stringw strw;
//  for (u32 i = 0 ; i < FileFilters.size() ; i++) {
//    strw = FileFilters[i].FilterName;
//    strw += " (*.";
//    strw += FileFilters[i].FileExtension;
//    strw += ")";
//    FilterComboBox->addItem(strw.c_str());
//  }
//  FilterComboBox->addItem(L"All Files");
//  
//  fillListBox();
//}
void CGUIFileSelector::addFileFilter(wchar_t* name, wchar_t* ext, video::ITexture* texture) {
  SFileFilter filter(name, ext, texture);
 
  filter.FileIconIdx = addIcon(texture);
 
  FileFilters.push_back(filter);
 
  FilterComboBox->clear();
  core::stringw strw;

  if (FileFilters.size() > 1) {
     strw = "Supported ";
     for (u32 i = 0 ; i < FileFilters.size() ; i++) {
      strw += ".";
      strw += FileFilters[i].FileExtension;
      strw += " ";
     }
     FilterComboBox->addItem(strw.c_str());
  }
 
  for (u32 i = 0 ; i < FileFilters.size() ; i++) {
    strw = FileFilters[i].FilterName;
    strw += " (*.";
    strw += FileFilters[i].FileExtension;
    strw += ")";
    FilterComboBox->addItem(strw.c_str());
  }
  FilterComboBox->addItem(L"All Files");
 
  fillListBox();
} 

u32 CGUIFileSelector::addIcon(video::ITexture* texture) {
	if (!SpriteBank || !texture) return 0;
    
	// load and add the texture to the bank     
	SpriteBank->addTexture(texture); 
	u32 textureIndex = SpriteBank->getTextureCount() - 1; 
	// now lets get the sprite bank's rectangles and add some for our animation 
	core::array<core::rect<s32> >& rectangles = SpriteBank->getPositions(); 
	u32 firstRect = rectangles.size(); 
	// remember that rectangles are not in pixels, they enclose pixels! 
	// to draw a rectangle around the pixel at 0,0, it would rect<s32>(0,0, 1,1) 
	rectangles.push_back(core::rect<s32>(0,0, 16,16)); 


	// now we make a sprite.. 
	SGUISprite sprite; 
	sprite.frameTime = 30; 
	// add some frames of animation. 
	SGUISpriteFrame frame; 
	frame.rectNumber = firstRect; 
	frame.textureNumber = textureIndex; 

	// add this frame 
	sprite.Frames.push_back(frame); 
	// add the sprite 
	u32 spriteIndex = SpriteBank->getSprites().size(); 
	SpriteBank->getSprites().push_back(sprite);  

	return textureIndex;
}

not sure how to fill this for linux, a list of /dev maybe??
U238
Posts: 14
Joined: Mon Aug 17, 2009 1:01 pm
Location: Taganrog, Russia

Post by U238 »

Thank you very much, JP for the code, I exactly looked for file save dialog :)
Will using and testing :)
Post Reply