(C++) FileSaveDialog patch [v0.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.
Post Reply
Rambus
Posts: 96
Joined: Thu Nov 24, 2005 4:56 pm
Location: Canada
Contact:

(C++) FileSaveDialog patch [v0.1]

Post by Rambus »

FileSaveDialog is a GUI object much like FileOpenDialog that allows a user to specify an output path for a file. A user can check if the file selected/entered exists and decide if the location is valid. It looks *almost* identical to FileOpenDialog.

The full version includes
-compiled irrlicht.dll (dx9,dx8,openGl)
-pre-compiled example usage (Examples/05.UserInterface)
-Full source code, ready to build visual studio 05 project file.
-New, updated version of ChatQueue 0.3.2 built into the irrlicht.dll and included in the full source code.

The latest version of the code is available at:
www.g0dsoft.com/irrlicht/FileSaveDialog/v01/full.zip

And for just the changes to the irrlicht source: (Much smaller)
www.g0dsoft.com/irrlicht/FileSaveDialog/v01/src.zip

Image

(ChatQueue) Updated for 0.3.2
-Fixed a uncommon bug with word wrapping.

ToDo:
-Allow a user to define what output file types are acceptable.
-Filter directory list by acceptable file types.

Note: The code was built off of an irrlicht widget and as such may still be covered under the irrlicht liscense. The FileSaveWidget is proposed as a patch, rather then a user widget.

See 05.UserInterface/main.cpp for example usage.

IGUIFileSaveQueue.h

Code: Select all

/*
FileSaveDialog is a unofficial modification/addition to the Irrlicht Source code.
Version: 0.1
Code by: Mark Laprairie
Contact: webmaster@g0dsoft.com
Url: www.g0dsoft.com
*/

#ifndef __I_GUI_FILE_SAVE_DIALOG_H_INCLUDED__
#define __I_GUI_FILE_SAVE_DIALOG_H_INCLUDED__

#include "IGUIElement.h"

namespace irr
{
namespace gui
{

	//! Standard file chooser dialog.
	class IGUIFileSaveDialog : public IGUIElement
	{
	public:

		//! constructor
		IGUIFileSaveDialog(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
			: IGUIElement(EGUIET_FILE_SAVE_DIALOG, environment, parent, id, rectangle) {}

		//! destructor
		virtual ~IGUIFileSaveDialog() {}

		//! Returns the filename of the selected file. Returns NULL, if no file was selected.
		virtual const wchar_t* getFileName() const = 0;
	};


} // end namespace gui
} // end namespace irr

#endif
CGUIFileSaveQueue.h

Code: Select all

/*
FileSaveDialog is a unofficial modification/addition to the Irrlicht Source code.
For conditions of distribution and use, see copyright notice in irrlicht.h
Version: 0.1
Code by: Mark Laprairie
Contact: webmaster@g0dsoft.com
Url: www.g0dsoft.com
*/

#ifndef __C_GUI_FILE_SAVE_DIALOG_H_INCLUDED__
#define __C_GUI_FILE_SAVE_DIALOG_H_INCLUDED__

#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_

#include "IGUIFileSaveDialog.h"
#include "IGUIButton.h"
#include "IGUIListBox.h"
#include "IGUIEditBox.h"
#include "IFileSystem.h"

namespace irr
{
namespace gui
{

	class CGUIFileSaveDialog : public IGUIFileSaveDialog
	{
	public:

		//! constructor
		CGUIFileSaveDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id);

		//! destructor
		virtual ~CGUIFileSaveDialog();

		//! returns the filename of the selected file. Returns NULL, if no file was selected.
		virtual const wchar_t* getFileName() const;

		//! called if an event happened.
		virtual bool OnEvent(const SEvent& event);

		//! draws the element and its children
		virtual void draw();

	protected:

		//! fills the listbox with files.
		void fillListBox();

		//! sends the event that the file has been selected.
		void sendSelectedEvent();

		//! sends the event that the file choose process has been canceld
		void sendCancelEvent();

		core::position2d<s32> DragStart;
		core::stringw FileName;
		bool Dragging;
		IGUIButton* CloseButton;
		IGUIButton* OKButton;
		IGUIButton* CancelButton;
		IGUIListBox* FileBox;
		IGUIElement* FileNameText;
		IGUIElement* EventParent;
		io::IFileSystem* FileSystem;

		io::IFileList* FileList;
	};


} // end namespace gui
} // end namespace irr

#endif // _IRR_COMPILE_WITH_GUI_

#endif // __C_GUI_FILE_Save_DIALOG_H_INCLUDED__
CGUIFileSaveQueue.cpp

Code: Select all

/*
FileSaveDialog is a unofficial modification/addition to the Irrlicht Source code.
For conditions of distribution and use, see copyright notice in irrlicht.h
Version: 0.1
Code by: Mark Laprairie
Contact: webmaster@g0dsoft.com
Url: www.g0dsoft.com
*/

#include "CGUIFileSaveDialog.h"
#ifdef _IRR_COMPILE_WITH_GUI_

#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIFont.h"
#include "IGUIFontBitmap.h"
#include "IFileList.h"
#include "os.h"

namespace irr
{
namespace gui
{

const s32 FOD_WIDTH = 350;
const s32 FOD_HEIGHT = 250;


//! constructor
CGUIFileSaveDialog::CGUIFileSaveDialog(const wchar_t* title,
		IGUIEnvironment* environment, IGUIElement* parent, s32 id)
: IGUIFileSaveDialog(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)
{
	#ifdef _DEBUG
	IGUIElement::setDebugName("CGUIFileSaveDialog");
	#endif

	Text = title;
	FileName = L"";

	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"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close");
	CloseButton->setSubElement(true);
	CloseButton->setTabStop(false);
	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, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK");
	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, 55, RelativeRect.getWidth()-90, 230), this, -1,true);
	FileBox->setSubElement(true);
	FileBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
	FileBox->grab();

	FileNameText = Environment->addEditBox(L"",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->grab();

	FileSystem = Environment->getFileSystem();

	if (FileSystem)
		FileSystem->grab();

	setTabGroup(true);

	fillListBox();
}


//! destructor
CGUIFileSaveDialog::~CGUIFileSaveDialog()
{
	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();
}


//! returns the filename of the selected file. Returns NULL, if no file was selected.
const wchar_t* CGUIFileSaveDialog::getFileName() const
{
	return FileName.c_str();
}


//! called if an event happened.
bool CGUIFileSaveDialog::OnEvent(const SEvent& event)
{
	switch(event.EventType)
	{
	case EET_GUI_EVENT:
		switch(event.GUIEvent.EventType)
		{
			case EGET_ELEMENT_FOCUS_LOST:
				Dragging = false;
				break;
			case EGET_EDITBOX_ENTER:
				if(event.GUIEvent.Caller != FileNameText)
					break;
			case EGET_BUTTON_CLICKED:
				if (event.GUIEvent.Caller == CloseButton ||
					event.GUIEvent.Caller == CancelButton)
				{
					sendCancelEvent();
					remove();
					return true;
				}
				else
				{
					if (event.GUIEvent.Caller == OKButton || event.GUIEvent.Caller == FileNameText) 
					{
						if((core::stringw)FileNameText->getText() != L"")
						{
							core::stringw s;
							s = FileSystem->getWorkingDirectory();
							if(s.findLast('\\',-1) != s.findFirst('\\'))
								s.append('\\');
							s.append(FileNameText->getText());
							FileName = s.c_str();
							os::Printer::log(s.c_str());
							sendSelectedEvent();
							remove();
							return true;
						}
					}
				}
				break;

			case EGET_LISTBOX_CHANGED:
				{
					s32 selected = FileBox->getSelected();
					if (FileList && FileSystem && !(FileList->isDirectory(selected)) )
					{
							core::stringw s;
							s = FileList->getFileName(selected);
							FileNameText->setText(s.c_str());
							return true;
					}
				}
				break;
			case EGET_LISTBOX_SELECTED_AGAIN:
				{
					const s32 selected = FileBox->getSelected();
					if (FileList && FileSystem)
					{
						if (FileList->isDirectory(selected))
						{
							FileSystem->changeWorkingDirectoryTo(FileList->getFileName(selected));
							fillListBox();
						}
						else
						{
							core::stringw s;
							s = FileList->getFileName(selected);
							FileNameText->setText(s.c_str());
							return true;
						}
					}
				}
				break;
			default: //For GCC compatibility
				break;
		}
		break;
	case EET_MOUSE_INPUT_EVENT:
		switch(event.MouseInput.Event)
		{
		case EMIE_MOUSE_WHEEL:
			return FileBox->OnEvent(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;
			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;
		default:
			break;
		}
	default:
		break;
	}

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


//! draws the element and its children
void CGUIFileSaveDialog::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();
}


//! fills the listbox with files.
void CGUIFileSaveDialog::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);
		FileBox->addItem(s.c_str(), skin->getIcon(FileList->isDirectory(i) ? EGDI_DIRECTORY : EGDI_FILE));
	}
}


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


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

} // end namespace gui
} // end namespace irr

#endif // _IRR_COMPILE_WITH_GUI_
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

Hi, That's very nice.

I've done a version with filetypes icons but the code is looking very bad. (Right now it seem to compile only on DEVC++, and failed for some on Linux and other (Perhaps because of the iconbank)

I think it will take some time before we're able to mimic our OS's dialogs. (Path, drive selection, "favorites", filetypes, etc)

Do you plan to do other versions in the future?
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

two things I have always wanted and will hack into these.

1) dont change directories when selecting a file, or at least change back to the original when the file is selected

2) Filter directory list by acceptable file types if this means something like *.dat and only .dat files show up.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Seven wrote:two things I have always wanted and will hack into these.

1) dont change directories when selecting a file, or at least change back to the original when the file is selected
Easily done by having the dialog cache the working directory and restore it.
Seven wrote: 2) Filter directory list by acceptable file types if this means something like *.dat and only .dat files show up.
Code for doing that with the original file dialog is here...
Last edited by vitek on Thu Jul 31, 2008 5:04 pm, edited 1 time in total.
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

Simple file type selector:

Code: Select all

s = FileList->getFileName(i);
if (FileList->isDirectory(i) || (s.find(".irr")> -1))
   FileBox->addItem(s.c_str(), skin->getIcon(FileList->isDirectory(i) ? EGDI_DIRECTORY : EGDI_FILE)); 
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

I've done a simple upgrade of irrlicht's filedialog which doesn't affect the working directory (using the method vitek mentions basically) and also allows a file filter to be specified.

I also made it standard for open/save type uses which i think is probably a better idea, rather than having one type for opening and one type for saving, seems to be the commonly used approach.

Another thing i 'solved' was to allow drive switching which the standard irrlicht filedialog doesn't allow, you can only navigate the drive that the working directory is on. But i didn't solve this nicely, i just put an edit box to put the requested drive letter in and then a button to make the change... not very elegant but it gets the job done :lol:

anyway, this looks good and thanks for sharing it. If anyone's interested in mine then it's available via IrrAI and is in the IrrAI Editor source folder.
Image Image Image
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

You don't have link to irrAI in your signature?
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

Clearly not :lol:
Image Image Image
CarlS
Posts: 86
Joined: Wed May 09, 2007 1:21 am
Contact:

Post by CarlS »

Thanks for making this available :)

--Carl
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

JP wrote: and also allows a file filter to be specified.
JP,
Could you make it so that you can specify multiple file types. For example, when allowing the user to select an animation file, something like this might be nice. "*.X,*.md2,*.MD3" or for sound ""*.mp3,*.ogg"

Seven
Post Reply