balance_wheel/IrrExtensions/gui/GUIFileSelectPanel.cpp

433 lines
12 KiB
C++

// (c) 2015-2019 Nicolaus Anderson
#ifndef GUI_FILE_SELECT_PANEL_CPP
#define GUI_MATERIAL_PANEL_CPP
#include "GUIFileSelectPanel.h"
#include <irrArray.h>
#include <IGUIEnvironment.h>
#include <IFileSystem.h>
#include <IFileList.h>
#include <locale.h>
//#include <os.h> // needed for locale
#include <IGUIButton.h>
#include <IGUIListBox.h>
#include <IGUIEditBox.h>
namespace irr {
namespace gui {
using core::string;
using core::vector2di;
using core::dimension2di;
GUIFileSelectPanel::GUIFileSelectPanel(
IGUIEnvironment* pEnvironment,
IGUIElement* pParent,
recti pRect,
io::path pStartDirectory,
s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, fileSystem(0)
, fileList(0)
, filesIndex()
, selectButton(0)
, cancelButton(0)
, fileListBox(0)
, fileNameEditBox(0)
, isFileSelectedFromList(false)
, lastFileSelectPanelEvent(EGFSPE_NONE)
, notifyWhenEditBoxChanges(false)
, restoreDirWhenDone(true)
, restoreDirWhenCancelled(true)
, initialWorkingDir()
, currentWorkingDir()
, drawBack(true)
{
fileSystem = Environment->getFileSystem();
fileSystem->grab();
recti selectButtonRect( vector2di(pRect.getWidth()-130, pRect.getHeight()-25), dimension2di(60,20) );
selectButton = Environment->addButton( selectButtonRect, this, -1, L"Select", L"Confirm file name" );
selectButton->setAlignment( EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT );
selectButton->setSubElement(true);
selectButton->grab();
recti cancelButtonRect( vector2di(pRect.getWidth()-65, pRect.getHeight()-25), dimension2di(60,20) );
cancelButton = Environment->addButton( cancelButtonRect, this, -1, L"Cancel" );
cancelButton->setAlignment( EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT );
cancelButton->setSubElement(true);
cancelButton->grab();
recti fileListRect( 5, 5, pRect.getWidth()-5, pRect.getHeight()-55 );
fileListBox = Environment->addListBox( fileListRect, this, -1, true );
fileListBox->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
fileListBox->setSubElement(true);
fileListBox->grab();
recti fileNameEditRect( 5, pRect.getHeight()-50, pRect.getWidth()-5, pRect.getHeight()-30 );
fileNameEditBox = Environment->addEditBox( L"", fileNameEditRect, true, this, -1 );
fileNameEditBox->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT );
fileNameEditBox->setSubElement(true);
fileNameEditBox->grab();
initialWorkingDir = fileSystem->getAbsolutePath( fileSystem->getWorkingDirectory() );
if ( pStartDirectory.size() )
{
fileSystem->changeWorkingDirectoryTo( pStartDirectory );
currentWorkingDir = pStartDirectory;
} else {
currentWorkingDir = initialWorkingDir;
}
fillFileList();
}
GUIFileSelectPanel::~GUIFileSelectPanel()
{
//if ( restoreDirWhenDone )
// fileSystem->changeWorkingDirectoryTo( initialWorkingDir );
if ( selectButton )
selectButton->drop();
if ( cancelButton )
cancelButton->drop();
if ( fileListBox )
fileListBox->drop();
if ( fileNameEditBox )
fileNameEditBox->drop();
fileSystem->drop();
}
IGUIButton* GUIFileSelectPanel::getSelectButton()
{
return selectButton;
}
IGUIButton* GUIFileSelectPanel::getCancelButton()
{
return cancelButton;
}
bool GUIFileSelectPanel::OnEvent( const SEvent& event )
{
if ( event.EventType != EET_GUI_EVENT )
return false;
/*
How this should work:
Typing in an edit-box filters the list to show only matches unless
the editbox value is "", in which case, everything is shown.
The file selected is set to the file name.
isSelectedFileReal() indicates if the selected file is taken from the list.
*/
/*
DO NOT RESTORE THE DIRECTORY AFTER SELECTION.
It doesn't make sense to restore the directory before the file path has been obtained by the user.
EDIT:
I can change this if I use getFullFileName() from the fileList, which saves the directory.
*/
switch ( event.GUIEvent.EventType )
{
case EGET_BUTTON_CLICKED:
if ( event.GUIEvent.Caller == selectButton )
{
lastFileSelectPanelEvent = EGFSPE_FILE_CONFIRMED;
sendGUIEvent( EGET_FILE_SELECTED );
if ( restoreDirWhenDone )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
}
else if ( event.GUIEvent.Caller == cancelButton )
{
lastFileSelectPanelEvent = EGFSPE_CANCEL;
sendGUIEvent( EGET_FILE_CHOOSE_DIALOG_CANCELLED );
if ( restoreDirWhenCancelled )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
}
break;
case EGET_EDITBOX_CHANGED:
if ( event.GUIEvent.Caller == fileNameEditBox )
{
isFileSelectedFromList = false;
fillFileList();
if ( notifyWhenEditBoxChanges )
sendGUIEvent( EGET_EDITBOX_CHANGED, fileNameEditBox );
return true;
}
break;
case EGET_EDITBOX_ENTER: // another means of selection
if ( event.GUIEvent.Caller == fileNameEditBox )
{
// confirm file selection
lastFileSelectPanelEvent = EGFSPE_FILE_CONFIRMED;
//sendGUIEvent( EGET_EDITBOX_ENTER, fileNameEditBox ); // Doesn't allow file_selected filtering in parent OnEvent
sendGUIEvent( EGET_FILE_SELECTED );
if ( restoreDirWhenDone )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
}
break;
case EGET_LISTBOX_CHANGED:
if ( event.GUIEvent.Caller == fileListBox )
{
isFileSelectedFromList = true;
lastFileSelectPanelEvent = EGFSPE_REAL_FILE_SELECTED;
//sendGUIEvent( EGET_LISTBOX_CHANGED, fileListBox ); // Doesn't allow file_selected filtering in parent OnEvent
sendGUIEvent( EGET_FILE_SELECTED );
return true;
}
break;
case EGET_LISTBOX_SELECTED_AGAIN:
if ( event.GUIEvent.Caller == fileListBox )
{
// confirm file selection
lastFileSelectPanelEvent = EGFSPE_FILE_CONFIRMED;
if ( isSelectedFileReal() )
{
//sendGUIEvent( EGET_LISTBOX_SELECTED_AGAIN, fileListBox ); // Doesn't allow file_selected filtering in parent OnEvent
sendGUIEvent( EGET_FILE_SELECTED );
if ( restoreDirWhenDone )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
} else {
// Selected is real (since it's in the list), but it is a directory
openSelectedDirectory();
}
}
break;
default: break;
}
return false;
}
EGUIFileSelectPanelEvent GUIFileSelectPanel::getLastEvent()
{
return lastFileSelectPanelEvent;
}
void GUIFileSelectPanel::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
if ( Parent )
Parent->OnEvent(event);
}
void GUIFileSelectPanel::setNotifyWhenEditBoxChanges(bool yes)
{
notifyWhenEditBoxChanges = yes;
}
io::path GUIFileSelectPanel::getCurrentWorkingDirectory()
{
fileSystem->flattenFilename(currentWorkingDir);
return currentWorkingDir;
}
bool GUIFileSelectPanel::isSelectedReal()
{
return isFileSelectedFromList;
}
bool GUIFileSelectPanel::isSelectedFileReal()
{
// Must be selected from list and not be a directory
if ( isFileSelectedFromList )
{
for ( u32 i=0; i < fileList->getFileCount(); i++ )
{
if ( fileList->getFileName(i) == fileListBox->getListItem( fileListBox->getSelected() ) )
{
return ! ( fileList->isDirectory(i) );
}
}
}
return false;
}
io::path GUIFileSelectPanel::getSelectedFile()
{
if ( isFileSelectedFromList )
{
return fileList->getFileName( getSelectedFileIndex() );
}
io::path filename = fileNameEditBox->getText();
fileSystem->flattenFilename( filename );
return filename;
}
io::path GUIFileSelectPanel::getSelectedFilePath()
{
if ( isFileSelectedFromList )
{
return fileList->getFullFileName( getSelectedFileIndex() );
}
return fileSystem->getAbsolutePath( getSelectedFile() );
}
io::path GUIFileSelectPanel::getSelectedFileRelativePath()
{
return fileSystem->getRelativeFilename( getSelectedFilePath(), initialWorkingDir );
}
//! Restore the working directory to the initial directory when a file is selected
void GUIFileSelectPanel::setRestoreDirectoryWhenDone(bool yes)
{
restoreDirWhenDone = yes;
}
//! Restore the working directory to the initial directory when cancelling
void GUIFileSelectPanel::setRestoreDirectoryWhenCancelled(bool yes)
{
restoreDirWhenCancelled = yes;
}
void GUIFileSelectPanel::reactivate()
{
fileSystem->changeWorkingDirectoryTo( currentWorkingDir );
}
void GUIFileSelectPanel::deactivate()
{
fileSystem->changeWorkingDirectoryTo( initialWorkingDir );
}
s32 GUIFileSelectPanel::getSelectedFileIndex()
{
return filesIndex[ fileListBox->getSelected() ];
}
void GUIFileSelectPanel::openSelectedDirectory()
{
if ( ! fileList )
return;
//const io::path entry = fileList->getFullFileName( getSelectedFileIndex() );
const io::path entry = fileList->getFileName( getSelectedFileIndex() );
if ( entry.size() > 0 )
{
fileSystem->changeWorkingDirectoryTo( entry );
currentWorkingDir = fileSystem->getWorkingDirectory();
fillFileList();
}
}
void GUIFileSelectPanel::pathToStringW(irr::core::stringw& result, const irr::io::path& p)
{
// Taken from Irrlicht trunk 5823, probably added by CuteAlien.
#ifndef _IRR_WCHAR_FILESYSTEM
char* oldLocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE,""); // multibyteToWString is affected by LC_CTYPE. Filenames seem to need the system-locale.
core::multibyteToWString(result, p);
setlocale(LC_CTYPE, oldLocale);
#else
result = p.c_str();
#endif
}
void GUIFileSelectPanel::fillFileList()
{
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
setlocale(LC_ALL,"");
#endif
if ( fileList ) {
fileList->drop();
fileList = 0;
}
fileList = fileSystem->createFileList();
if ( !fileList ) // FIXME: Should throw, but this should also never happen
return;
filesIndex.clear();
fileListBox->clear();
s32 folderIcon = Environment->getSkin()->getIcon(EGDI_DIRECTORY);
s32 fileIcon = Environment->getSkin()->getIcon(EGDI_FILE);
stringw filterText(fileNameEditBox->getText());
stringw fileNameTemp;
for ( u32 i=0; i < fileList->getFileCount(); i++ )
{
pathToStringW(fileNameTemp, fileList->getFileName(i));
if ( filterText.size() == 0
|| ( filterText.size() > 0 && fileNameTemp.subString(0,filterText.size()) == filterText )
)
{
fileListBox->addItem(
fileNameTemp.c_str(),
(fileList->isDirectory(i)?folderIcon:0)
);
filesIndex.push_back(i);
}
}
}
void GUIFileSelectPanel::draw()
{
if ( drawBack )
{
Environment->getSkin()->draw3DSunkenPane(this,
Environment->getSkin()->getColor(EGDC_3D_FACE), true, true,
AbsoluteRect, &AbsoluteClippingRect );
}
IGUIElement::draw();
}
void
GUIFileSelectPanel::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
){
out->addBool("RestoreStartDirectoryWhenDone", restoreDirWhenDone);
out->addBool("RestoreStartDirectoryWhenCancelled", restoreDirWhenCancelled);
#ifndef _IRR_WCHAR_FILESYSTEM
out->addString("InitialWorkingDirectory", initialWorkingDir.c_str());
#else
out->addStringW("InitialWorkingDirectory", initialWorkingDir.c_str());
#endif
out->addBool("DrawBack", drawBack);
}
void
GUIFileSelectPanel::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
){
restoreDirWhenDone = in->getAttributeAsBool("RestoreStartDirectoryWhenDone", restoreDirWhenDone);
restoreDirWhenCancelled = in->getAttributeAsBool("RestoreStartDirectoryWhenCancelled", restoreDirWhenCancelled);
if ( in->existsAttribute("InitialWorkingDirectory") ) {
#ifndef _IRR_WCHAR_FILESYSTEM
initialWorkingDir = in->getAttributeAsString("InitialWorkingDirectory", initialWorkingDir.c_str());
#else
initialWorkingDir = in->getAttributeAsStringW("InitialWorkingDirectory", initialWorkingDir.c_str());
#endif
}
drawBack = in->getAttributeAsBool("DrawBack", drawBack);
}
}}
#endif