/*************************************************************************\
* "$RCSfile: CDlgFileMgr.cpp,v $"                                         *
***************************************************************************
* Information by CVS or VSS:                                              *
*     Last check in on: $Date: 2011/10/20 08:02:47 $                      *
*     by                $Author: schluckebier $
*     Revision        : $Revision: 1.9 $                                 *
\*************************************************************************/
/*! \file CDlgFileMgr.cpp
*	\brief Implementation CDlgFileMgr Class
**************************************************************************/

#include <string.h>
#include <std.h>
#include <mem.h>
#include "VIC_PS.h"
#include "GBit.h"
#include "CLog.hpp"
#include "CRegion.h"
#include "CPSApp.hpp"
#include "CDlg.hpp"
#include "CDlgFileMgr.hpp"
#include "CDlgTools.hpp"
#include "CDlgPassword.hpp"
#include "CImageBrowser.hpp"

CDlgFileMgr *CDlgFileMgr::m_pThis = NULL;	//!< The one and only CDlgFileMgr instance

/*************************************************************************/
CDlgFileMgr::CDlgFileMgr()
/*************************************************************************/
/*! @brief Constructor
**************************************************************************/
{
	m_pApp = CPSApp::GetInstance();
	const int Height = m_pApp->GetHeight();
	const int Width = m_pApp->GetWidth() - m_pApp->GetDlgAreaWidth();
	int PosX, PosY;
	char Text[256];

	m_bProtectFlash = true;
	m_Device[LEFT] = VIB_Drive[1];
	m_Device[RIGHT] = VIB_Drive[1];
	m_ActiveDevice = m_Device[LEFT];
	VIB_GetCurrentPath(m_Device[LEFT], m_Path[LEFT]);
	VIB_GetCurrentPath(m_Device[RIGHT], m_Path[RIGHT]);
	m_ActivePath = m_Path[LEFT];
	m_Side = LEFT;
	m_CopyFileSize = 0;
	m_pCopyMem = NULL;
	m_CopyFileName[0] = '\0';
	m_fKB = m_pApp->GetKeyboardHandle();
	m_pImage = m_pApp->GetDispImage();
	m_PosX = m_pApp->GetDlgAreaWidth();

	// *** FM dialog ***
	m_pDlg = new GUI_DLG;
	GUI_DlgCreate2(m_pDlg, Width, Height, "File Manager");
	GUI_DlgSetGradCol(m_pDlg, m_pApp->GetGradCol());
	GUI_DlgGetZeroZero(m_pDlg, &PosX, &PosY);
	PosX += 4;
	m_PosY = PosY + 4;
	m_FSWidth = (Width - 24) / 2;
	m_FSHeight = Height - (m_PosY + 72);
	m_pApp->SetTP(TextStyle::BOLD);
	std::snprintf(Text, 256, "%s:%s", VIB_GetDeviceName(m_Device[LEFT]), m_Path[LEFT]);
	m_pDlgItem[ID_LEFT_DEV] = GUI_DlgAddGButton(m_pDlg, 8, m_PosY, m_FSWidth, 22, Text, m_pApp->GetGradCol(), ID_LEFT_DEV);
	std::snprintf(Text, 256, "%s:%s", VIB_GetDeviceName(m_Device[RIGHT]), m_Path[RIGHT]);
	m_pDlgItem[ID_RIGHT_DEV]= GUI_DlgAddGButton(m_pDlg, 16 + m_FSWidth, m_PosY, m_FSWidth, 22, Text, m_pApp->GetGradCol(), ID_RIGHT_DEV);
	m_pApp->SetTP(TextStyle::MONOSPACE);
	m_pDlgItem[ID_LEFT_FS] = GUI_DlgAddFileSelectBox(m_pDlg, 8, m_PosY + 30, m_FSWidth, m_FSHeight, m_Device[LEFT], m_File[LEFT],
		RD_FILESIZE | RD_DIR | RD_DATE | RD_TIME, NULL, ID_LEFT_FS);
	m_pDlgItem[ID_RIGHT_FS] = GUI_DlgAddFileSelectBox(m_pDlg, 16 + m_FSWidth, m_PosY + 30, m_FSWidth, m_FSHeight, m_Device[RIGHT], m_File[RIGHT],
		RD_FILESIZE | RD_DIR | RD_DATE | RD_TIME, NULL, ID_RIGHT_FS);
	m_pApp->SetTP(TextStyle::NORMAL);
	GUI_DlgAddGButton(m_pDlg, 8,              Height - 32, m_FSWidth,       24, "_Left Menu",  m_pApp->GetGradCol(), ID_LEFT_B);
	GUI_DlgAddGButton(m_pDlg, 16 + m_FSWidth, Height - 32, m_FSWidth - 106, 24, "_Right Menu", m_pApp->GetGradCol(), ID_RIGHT_B);
	GUI_DlgAddGButton(m_pDlg, Width - 106, Height - 32, 98, 24, m_pApp->GetStr(StringTable::BACK), m_pApp->GetGradCol(), DLG_ABORT);
	GUI_DlgGotoItem2(m_pDlg, m_pDlgItem[ID_LEFT_FS]);

	// *** File command dialog ***
	m_pDlgFC = new GUI_DLG;
	GUI_DlgCreate2(m_pDlgFC, 216, 260, NULL);
	GUI_DlgAddSelectBox(m_pDlgFC, 8, 8, 200, 216,
		"Open\n"
		"Delete\n"
		"Rename\n"
		"Copy\n"
		"Copy  (--> RAM)\n"
		"Paste (RAM -->)\n"
		"Edit text file\n"
		"Create directory\n"
		"Delete all files\n"
		"File information\n"
		"Drive information\n"
		"Imagebrowser\n", &m_SelFC, 1);
	GUI_DlgAddButton(m_pDlgFC, 8, 228, 96, 24, "_OK", 2);
	GUI_DlgAddButton(m_pDlgFC, 112, 228, 96, 24, m_pApp->GetStr(StringTable::CANCEL), DLG_ABORT);

	// *** Directory command dialog ***
	m_pDlgDC = new GUI_DLG;
	GUI_DlgCreate2(m_pDlgDC, 216, 180, NULL);
	GUI_DlgAddSelectBox(m_pDlgDC, 8, 8, 200, 132,
		"Open directory\n"
		"Delete dir\n"
		"Create new dir\n"
		"Rename dir\n"
		"File information\n"
		"Drive information\n"
		"Imagebrowser\n", &m_SelDC, 1);
	GUI_DlgAddButton(m_pDlgDC, 8, 148, 96, 24, "_OK", 2);
	GUI_DlgAddButton(m_pDlgDC, 112, 148, 96, 24, m_pApp->GetStr(StringTable::CANCEL), DLG_ABORT);
}

/*************************************************************************/
CDlgFileMgr::~CDlgFileMgr()
/*************************************************************************/
/*! @brief Destructor.
**************************************************************************/
{
	GUI_DlgFree(m_pDlg);
	GUI_DlgFree(m_pDlgFC);
	GUI_DlgFree(m_pDlgDC);
	delete m_pDlgFC;
	delete m_pDlgDC;
	delete m_pDlg;
}

/*************************************************************************/
CDlgFileMgr *CDlgFileMgr::CreateInstance()
/*************************************************************************/
/*! @brief Creates CDlgFileMgr instance.
	@return Pointer to CDlgFileMgr instance
**************************************************************************/
{
	if (m_pThis == NULL)
		m_pThis = new CDlgFileMgr();
	return m_pThis;
}

/*************************************************************************/
void CDlgFileMgr::DisposeInstance()
/*************************************************************************/
/*! @brief Disposes CDlgFileMgr instance.
**************************************************************************/
{
	if (m_pThis)
		delete m_pThis;
	m_pThis = NULL;
}

/*************************************************************************/
int CDlgFileMgr::Run()
/*************************************************************************/
/*! @brief Main function.
**************************************************************************/
{
	int Id, nKey;
	int Sel, FSize, Side;
	int Action;
	bool bActive = true;
	char *FName;
	CImageBrowser IBrowser;

	Update();
	SetSide(LEFT, &FName, &FSize);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	while (bActive)
	{
		Action = NOACTION;
		nKey = getc(m_fKB);
		Id = GUI_DlgWork(m_pDlg, nKey);

		// *** Keyboard ***
		switch (nKey)
		{
		case EOF:
			clearerr(m_fKB);
			VIB_WaitBios(50);
			break;
		case KB_BACKSP:
			if (VIB_ChDir(m_Device[m_Side], "..") == 0)
			{
				VIB_GetCurrentPath(m_Device[m_Side], m_Path[m_Side]);
				m_ActivePath = m_Path[m_Side];
				Update();
			}
			break;
		case KB_DEL:
			Action = DELETE;
			break;
		case ' ':
			Id = (m_Side == LEFT) ? ID_LEFT_B : ID_RIGHT_B;
			break;
		case KB_F1:
			Action = HELP;
			break;
		case KB_F2:
			Action = RENAME;
			break;
		case KB_F4:
			Id = (m_Side == LEFT) ? ID_LEFT_DEV : ID_RIGHT_DEV;
			break;
		case KB_F10:
			Action = FINFO;
			break;
		}

		// *** Dialog ***
		switch (Id)
		{
		case DLG_FOCUS_CHANGED:
		case DLG_VALUE_CHANGED:
			Sel = GUI_DlgGetSelectedID(m_pDlg);
			if (Sel == ID_LEFT_FS || Sel == ID_LEFT_B || Sel == ID_LEFT_DEV)
				SetSide(LEFT, &FName, &FSize);
			if (Sel == ID_RIGHT_FS || Sel == ID_RIGHT_B || Sel == ID_RIGHT_DEV)
				SetSide(RIGHT, &FName, &FSize);
			break;
		case ID_LEFT_FS:
			SetSide(LEFT, &FName, &FSize);
			Action = (FSize == FAT_DIRECTORY) ? CHDIRLEFT : CMD;
			break;
		case ID_RIGHT_FS:
			SetSide(RIGHT, &FName, &FSize);
			Action = (FSize == FAT_DIRECTORY) ? CHDIRRIGHT : CMD;
			break;
		case ID_LEFT_B:
			SetSide(LEFT, &FName, &FSize);
			Action = (FSize == FAT_DIRECTORY) ? DIRCMD : FILECMD;
			break;
		case ID_RIGHT_B:
			SetSide(RIGHT, &FName, &FSize);
			Action = (FSize == FAT_DIRECTORY) ? DIRCMD : FILECMD;
			break;
		case ID_LEFT_DEV:
			SetSide(LEFT, &FName, &FSize);
			Action = SELLEFTDEVICE;
			break;
		case ID_RIGHT_DEV:
			SetSide(RIGHT, &FName, &FSize);
			Action = SELRIGHTDEVICE;
			break;
		case DLG_ABORT:
			bActive = false;
			break;
		}

		// *** Menu ***
		switch (Action)
		{
		case FILECMD:
			GUI_DlgEnable(m_pDlg, 0);
			GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
			Sel = GUI_DlgModal(m_pDlgFC, m_pImage, m_PosX + (m_FSWidth + 8) * m_Side + 8, m_FSHeight - 200, m_fKB);
			GUI_DlgEnable(m_pDlg, 1);
			if (Sel == DLG_ABORT)
				break;
			switch (m_SelFC)
			{
				case 1: Action = CMD; break;
				case 2: Action = DELETE; break;
				case 3: Action = RENAME; break;
				case 4: Action = COPYFILE; break;
				case 5: Action = COPY; break;
				case 6: Action = PASTE; break;
				case 7: EditTextFile(FName); break;
				case 8: Action = CREATEDIR; break;
				case 9: Action = DELETEALL; break;
				case 10: Action = FINFO; break;
				case 11: Action = DINFO; break;
				case 12: Action = IMAGEBROWSER; break;
			}
			break;
		case DIRCMD:
			GUI_DlgEnable(m_pDlg, 0);
			GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
			Sel = GUI_DlgModal(m_pDlgDC, m_pImage, m_PosX + (m_FSWidth + 8) * m_Side + 8, m_FSHeight - 100, m_fKB);
			GUI_DlgEnable(m_pDlg, 1);
			if (Sel == DLG_ABORT)
				break;
			switch (m_SelDC)
			{
				case 1: Action = (m_Side == LEFT) ? CHDIRLEFT : CHDIRRIGHT; break;
				case 2: Action = DELETE; break;
				case 3: Action = CREATEDIR; break;
				case 4: Action = RENAME; break;
				case 5: Action = FINFO; break;
				case 6: Action = DINFO; break;
				case 7: Action = IMAGEBROWSERD; break;
			}
			break;
		}

		switch (Action)
		{
		case HELP:
			GUI_DlgEnable(m_pDlg, 0);
			GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
			m_pApp->MessageBox(
				"\nF2: Rename file\nF4: Change drive\nF10: File information\nSPACE: Show menu\n\n",
				0, "Help");
			GUI_DlgEnable(m_pDlg, 1);
			break;
		case CMD:
			FileCommand(FName);
			break;
		case DELETE:
			DeleteFile(FName);
			break;
		case RENAME:
			RenameFile(FName);
			break;
		case COPYFILE:
			GUI_DlgEnable(m_pDlg, 0);
			GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
			CopyFile(FName);
			GUI_DlgEnable(m_pDlg, 1);
			break;
		case COPY:
			CopyFile2RAM(FName);
			break;
		case PASTE:
			PasteFile();
			break;
		case CREATEDIR:
			CreateDir();
			break;
		case DELETEALL:
			if (CheckForProtectedFlash())
				break;
			GUI_DlgEnable(m_pDlg, 0);
			GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
			if (m_pApp->MessageBox("\nDelete all files in current directory?\n\n", 1, "!!!") == 1)
			{
				GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
				if (m_pApp->MessageBox("\nAre you sure?\n\n", 1, "???") == 1)
				{
					DeleteAllFiles();
					Update();
				}
			}
			GUI_DlgEnable(m_pDlg, 1);
			break;
		case FINFO:
			FileInfoBox(FName);
			break;
		case DINFO:
			DriveInfoBox();
			break;
		case IMAGEBROWSER:
			IBrowser.Run(m_pApp->GetBgImage(), m_ActiveDevice, NULL, m_fKB);
			RecBackground();
			break;
		case IMAGEBROWSERD:
			IBrowser.Run(m_pApp->GetBgImage(), m_ActiveDevice, FName, m_fKB);
			RecBackground();
			break;
		case CHDIRLEFT:
		case CHDIRRIGHT:
			Side = Action - CHDIRLEFT;
			VIB_ChDir(m_Device[Side], FName);
			VIB_GetCurrentPath(m_Device[Side], m_Path[Side]);
			m_ActivePath = m_Path[Side];
			Update();
			break;
		case SELLEFTDEVICE:
		case SELRIGHTDEVICE:
			Sel = SelectDevice();
			if (Sel > 0)
			{
				Side = Action - SELLEFTDEVICE;
				m_Device[Side] = Sel;
				VIB_ChDir(m_Device[Side], "\\");
				VIB_GetCurrentPath(m_Device[Side], m_Path[Side]);
				SetSide(Side, &FName, &FSize);
				m_ActiveDevice = m_Device[Side];
				m_ActivePath = m_Path[Side];
				Update();
			}
			break;
		}
		if (Id != DLG_EOF)
			GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
	}
	VIB_ChDir(m_Device[LEFT], "\\");
	VIB_ChDir(m_Device[RIGHT], "\\");
	m_Path[LEFT][0] = m_Path[RIGHT][0] = '\\';
	m_Path[LEFT][1] = m_Path[RIGHT][1] = '\0';

	return Id;
}

/*************************************************************************/
void CDlgFileMgr::SetSide(int Side, char **ppFName, int *pFSize)
/*************************************************************************/
/*! @brief Sets active side of file-manager window.
	@param Side Side
	@param[out] ppFName Pointer to file name
	@param[out] pFSize File size
**************************************************************************/
{
	if (m_Side != Side)
	{
		m_Side = Side;
		m_ActiveDevice = m_Device[Side];
		m_ActivePath = m_Path[Side];
		VIB_ChDir(m_Device[Side], m_Path[Side]);
	}
	*ppFName = m_File[Side];
	*pFSize = GUI_DlgGetFileSelectBoxFSize(m_pDlgItem[ID_LEFT_FS + Side]);
}

/*************************************************************************/
void CDlgFileMgr::Update()
/*************************************************************************/
/*! @brief Updates dialog.
**************************************************************************/
{
	int i;
	char Text[256];

	m_pApp->SetTP(TextStyle::MONOSPACE);
	for (i = LEFT; i <= RIGHT; i++)
	{
		VIB_ChDir(m_Device[i], m_Path[i]);
		GUI_DlgModifyFileSelectBox(m_pDlgItem[ID_LEFT_FS + i], 8 + i * (8 + m_FSWidth), m_PosY + 30, m_FSWidth, m_FSHeight,
			m_Device[i], RD_FILESIZE | RD_DIR | RD_DATE | RD_TIME, NULL);
	}
	m_pApp->SetTP(TextStyle::BOLD);
	for (i = LEFT; i <= RIGHT; i++)
	{
		std::snprintf(Text, 256, "%s:%s", VIB_GetDeviceName(m_Device[i]), m_Path[i]);
		GUI_DlgModifyGButton(m_pDlgItem[ID_LEFT_DEV + i], 8 + i * (8 + m_FSWidth), m_PosY, m_FSWidth, 22, Text, m_pApp->GetGradCol());
	}
	m_pApp->SetTP(TextStyle::NORMAL);
	VIB_ChDir(m_ActiveDevice, m_ActivePath);
}

/*************************************************************************/
void CDlgFileMgr::FileCommand(const char *FName)
/*************************************************************************/
/*! @brief Analyzes file extension.
	@param FName File name
**************************************************************************/
{
	if (strncmp(&FName[9], "OUT", 3) == 0)
	{
		if (m_pApp->MessageBox("\nReally start program?\n\n", 1, "!!!") == 1)
		{
			GUI_MessageBox(m_pImage, "\nStarting program...\n\n", NULL, GUI_MBSIMPLE);
			VIB_RunApplication(m_ActiveDevice, FName);
		}
	}
	else if (strncmp(&FName[9], "BMP", 3) == 0)
	{
		DisplayBMPFile(FName);
		RecBackground();
	}
	else if (strncmp(&FName[9], "PNG", 3) == 0)
	{
		DisplayPNGFile(FName);
		RecBackground();
	}
	else if (strncmp(&FName[9], "JPG", 3) == 0)
	{
		DisplayJPGFile(FName);
		RecBackground();
	}
/*	else if ((strncmp(&FName[9], "JP2", 3) == 0) ||
			 (strncmp(&FName[9], "J2K", 3) == 0))
	{
		DisplayJP2File(FName);
		RecBackground();
	}*/
	else if ((strncmp(&FName[9], "TXT", 3) == 0) ||
			 (strncmp(&FName[9], "LOG", 3) == 0) ||
			 (strncmp(&FName[9], "INI", 3) == 0))
	{
		EditTextFile(FName);
	}
	else if ((strncmp(&FName[9], "VBF", 3) == 0) ||
			 (strncmp(&FName[9], "RBF", 3) == 0))
	{
		DisplayRBFFile(FName);
	}
	else if (strncmp(&FName[9], "TTF", 3) == 0)
	{
		DisplayTTFFile(FName);
		RecBackground();
	}
	else if (strncmp(&FName[9], "VBU", 3) == 0)
	{
		DisplayVBUFile(FName);
		RecBackground();
	}
	else if (strncmp(&FName[9], "AVI", 3) == 0)
	{
		DisplayAVIFile(FName);
		RecBackground();
	}
}

/*************************************************************************/
void CDlgFileMgr::RenameFile(const char *FName)
/*************************************************************************/
/*! @brief Renames a file.
	@param FName Filename
**************************************************************************/
{
	int ID;
	int i = 0, j = 0;
	char Text[32], Ext[8], *pStr;
	GUI_DLG *pDlg;

	if (CheckForProtectedFlash())
		return;

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	pDlg = new GUI_DLG;
	if (pDlg == NULL)
		return;
	if (GUI_DlgCreate2(pDlg, 172, 114, "Rename file") != GUI_E_OK)
	{
		delete pDlg;
		return;
	}
	GUI_DlgSetGradCol(pDlg, m_pApp->GetGradCol());
	GUI_DlgAddText(pDlg,  10, 30, "old:");
	GUI_DlgAddLabel(pDlg,  10, 52, "_new:", 10);
	m_pApp->SetTP(TextStyle::MONOSPACE);
	GUI_DlgAddText(pDlg, 54, 30, FName);

	// Remove spaces
	while (FName[i])
	{
		if (FName[i] != ' ')
			Text[j++] = FName[i];
		i++;
	}
	Text[j] = '\0';

	// Get extension
	pStr = strpbrk(Text, ".");
	if (pStr)
	{
		VIB_SStrCpy(Ext, &pStr[1], 8);
		pStr[0] = '\0';	// Cut name
	}
	else
	{
		Ext[0] = '\0';
	}

	GUI_DlgAddSEditBox2(pDlg, 50, 50, 70, Text, 10);
	GUI_DlgAddSEditBox2(pDlg, 130, 50, 32, Ext, 11);
	m_pApp->SetTP(TextStyle::NORMAL);
	GUI_DlgAddText(pDlg, 122, 52, ".");
	GUI_DlgAddButton(pDlg, 8, 82, 72, 24, "_OK", 1);
	GUI_DlgAddButton(pDlg, 90, 82, 72, 24, m_pApp->GetStr(StringTable::CANCEL), DLG_ABORT);
	ID = GUI_DlgModal(pDlg, m_pImage, m_PosX + (m_FSWidth + 8) * m_Side + 8, m_FSHeight - 50, m_fKB);
	GUI_DlgFree(pDlg);
	delete pDlg;

	if (ID != DLG_ABORT && Text[0])
	{
		sprintf(Text, "%s.%s", Text, Ext);
		VIB_RenameFile(m_ActiveDevice, FName, Text);
		Update();
	}
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
}

/*************************************************************************/
void CDlgFileMgr::CreateDir()
/*************************************************************************/
/*! @brief Creates a new directory.
**************************************************************************/
{
	int ID;
	char Text[32];
	GUI_DLG *pDlg;

	if (m_ActiveDevice == VIB_Drive[0])
		return;

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	pDlg = new GUI_DLG;
	if (pDlg == NULL)
		return;
	if (GUI_DlgCreate2(pDlg, 176, 100, "Create new dir") != GUI_E_OK)
	{
		delete pDlg;
		return;
	}
	GUI_DlgSetGradCol(pDlg, m_pApp->GetGradCol());
	GUI_DlgAddLabel(pDlg, 12, 40, "_new:", 10);
	GUI_DlgAddSEditBox(pDlg, 52, 38, 106, Text, 10);
	GUI_DlgAddButton(pDlg, 8, 68, 72, 24, "_OK", 1);
	GUI_DlgAddButton(pDlg, 92, 68, 72, 24, m_pApp->GetStr(StringTable::CANCEL), DLG_ABORT);
	ID = GUI_DlgModal(pDlg, m_pImage, m_PosX + (m_FSWidth + 8) * m_Side + 8, m_FSHeight - 50, m_fKB);
	GUI_DlgFree(pDlg);
	delete pDlg;

	if (ID != DLG_ABORT && Text[0])
	{
		VIB_MkDir(m_ActiveDevice, Text);
		Update();
	}
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
}

/*************************************************************************/
void CDlgFileMgr::DeleteFile(const char *FName)
/*************************************************************************/
/*! @brief Deletes a file.
	@param FName Filename
	@return 
**************************************************************************/
{
	char Text[128];

	if (CheckForProtectedFlash())
		return;

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	if (VIB_FindFile2(m_ActiveDevice, FName) == FAT_DIRECTORY)
	{
		if (FName[0] == '.')
			return;
		std::snprintf(Text, 128, "\nDelete directory \"%s\"?\n\n", FName);
		if (m_pApp->MessageBox(Text, 1) == 1)
		{
			if (VIB_RmDir(m_ActiveDevice, FName) != E_NONE)
			{
				std::snprintf(Text, 128, "\nDirectory \"%s\" is not empty!\nDelete anyway?\n", FName);
				if (m_pApp->MessageBox(Text, 1) == 1)
				{
					GUI_MessageBox(m_pImage, "\nDeleting directory...\n\n", NULL, GUI_MBSIMPLE);
					DeleteRecursive(FName);
				}
			}
		}
	}
	else
	{
		std::snprintf(Text, 128, "\nDelete file \"%s\"?\n\n", FName);
		if (m_pApp->MessageBox(Text, 1) == 1)
			VIB_DeleteFile(m_ActiveDevice, FName);
	}

	Update();
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
}

/*************************************************************************/
void CDlgFileMgr::DeleteAllFiles()
/*************************************************************************/
/*! @brief Deletes all files in directory.
**************************************************************************/
{
	int i, j;
	int Filecount;
	char *pDirtext;
	char Filename[16];

	if (m_ActiveDevice == VIB_Drive[0] && m_bProtectFlash)
		return;

	pDirtext = (char*)malloc(0x10000);
	if (pDirtext == NULL)
		return;

	Filecount = VIB_ReadDirEx(m_ActiveDevice, pDirtext, 0);
	for (i = 0; i < Filecount; i++)
	{
		j = 0;
		while (pDirtext + i * 13 + j && j < 12)
		{
			Filename[j] = pDirtext[i * 13 + j];
			j++;
		}
		Filename[j] = '\0';
		VIB_DeleteFile(m_ActiveDevice, Filename);
	}
	free(pDirtext);
}

/*************************************************************************/
int CDlgFileMgr::DeleteRecursive(const char *FName)
/*************************************************************************/
/*! @brief Deletes recursive all files in directory.
**************************************************************************/
{
	int i, j;
	int Filecount;
	char *pDirtext;
	char Filename[16];

	pDirtext = new char[0x4000];
	if (pDirtext == NULL)
		return E_OUTOFMEMORY;

	VIB_ChDir(m_ActiveDevice, FName);
	DeleteAllFiles();

	Filecount = VIB_ReadDirEx(m_ActiveDevice, pDirtext, RD_DIR);
	for (i = 2; i < Filecount; i++)
	{
		j = 0;
		while (pDirtext + i * 13 + j && j < 12)
		{
			Filename[j] = pDirtext[i * 13 + j];
			j++;
		}
		Filename[j] = '\0';
		DeleteRecursive(Filename);
	}
	VIB_ChDir(m_ActiveDevice, "..");
	VIB_RmDir(m_ActiveDevice, FName);
	delete [] pDirtext;
	return E_NONE;
}

/*************************************************************************/
int CDlgFileMgr::CopyFile(const char *FName)
/*************************************************************************/
/*! @brief Copies a file.
	@param FName Filename
	@return Error code
**************************************************************************/
{
	const int Width = 200;
	int FSize;
	int SrcDevice, DstDevice;
	bool Flag;
	unsigned char *pMemory;
	char *SrcPath, *DstPath;
	char Text[64];

	if (m_Side == LEFT)
	{
		SrcDevice = m_Device[LEFT];
		DstDevice = m_Device[RIGHT];
		SrcPath   = m_Path[LEFT];
		DstPath   = m_Path[RIGHT];
	}
	else
	{
		DstDevice = m_Device[LEFT];
		SrcDevice = m_Device[RIGHT];
		DstPath   = m_Path[LEFT];
		SrcPath   = m_Path[RIGHT];
	}

	m_ActiveDevice = DstDevice;
	Flag = CheckForProtectedFlash();
	m_ActiveDevice = SrcDevice;
	if (Flag)
		return E_ACCESSDENIED;

	if (SrcPath[0])
	{
		VIB_ChDir(SrcDevice, "\\");
		VIB_ChDir(SrcDevice, SrcPath);
	}
	FSize = VIB_FindFile2(SrcDevice, FName);
	if (FSize > 0)
	{
		pMemory = (unsigned char*)VIB_MemAlloc(FSize);
		if (pMemory == NULL)
		{
			m_pApp->MessageBox("\nmalloc() failed\n\n");
			return E_OUTOFMEMORY;
		}
		GUI_Button(m_pImage, m_PosX + (m_pDlg->rgbDlg.Width - Width) / 2, 172, Width, 20, "Reading", 5);
		if (m_pImage)
			GUI_Display(m_pImage, 0, 0);
		VIB_ReadFile(SrcDevice, FName, pMemory);

		if (DstPath[0])
		{
			VIB_ChDir(DstDevice, "\\");
			VIB_ChDir(DstDevice, DstPath);
		}
		if (VIB_FindFile2(DstDevice, FName) >= 0) // File already exists
		{
			std::snprintf(Text, 64, "\nReplace file\n%s?\n\n", FName);
			if (m_pApp->MessageBox(Text, 1) != 1)
				return E_FILEEXISTS;
		}
		GUI_Button(m_pImage, m_PosX + (m_pDlg->rgbDlg.Width - Width) / 2, 200, Width, 20, "Writing", 5);
		if (m_pImage)
			GUI_Display(m_pImage, 0, 0);
		VIB_DeleteFile(DstDevice, FName);
		FSize = VIB_WriteFile(DstDevice, FName, pMemory, FSize);
		if (SrcPath[0])
		{
			VIB_ChDir(SrcDevice, "\\");
			VIB_ChDir(SrcDevice, SrcPath);
		}
		VIB_MemFree(pMemory);
		if (FSize < 0)
		{
			m_pApp->MessageBox("\nWrite error!\n\n");
			return E_UNKNOWN;
		}
		Update();
	}
	return 0;
}

/*************************************************************************/
int CDlgFileMgr::CopyFile2RAM(const char *FName)
/*************************************************************************/
/*! @brief Copies a file to RAM.
	@param FName Filename
	@return Error code
**************************************************************************/
{
	const int FSize = VIB_FindFile2(m_ActiveDevice, FName);

	if (FSize > 0)
	{
		if (m_pCopyMem)
		{
			VIB_MemFree(m_pCopyMem);
			m_pCopyMem = NULL;
		}
		m_pCopyMem = (unsigned char*)VIB_MemAlloc(FSize);
		if (m_pCopyMem == NULL)
		{
			m_pApp->MessageBox("\nmalloc() failed\n\n");
			return -1;
		}
		m_CopyFileSize = VIB_ReadFile(m_ActiveDevice, FName, m_pCopyMem);
		VIB_SStrCpy(m_CopyFileName, FName, 16);
		return 0;
	}
	else
	{
		return -1;
	}
}

/*************************************************************************/
int CDlgFileMgr::PasteFile()
/*************************************************************************/
/*! @brief Pastes a file from RAM.
	@return Error code
**************************************************************************/
{
	int Ret = 0;
	int FSize;
	char Text[128];

	if (m_pCopyMem == NULL)
		return -1;
	if (CheckForProtectedFlash())
		return -1;

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, NULL, m_PosX, 0);

	FSize = VIB_FindFile2(m_ActiveDevice, m_CopyFileName);
	if (FSize >= 0)
	{
		std::snprintf(Text, 128, "\nReplace file\n%s?\n\n", m_CopyFileName);
		if (m_pApp->MessageBox(Text, 1) == 1)
			VIB_DeleteFile(m_ActiveDevice, m_CopyFileName);
		else
			return -2;
	}
	if (Ret == 0)
	{
		FSize = VIB_WriteFile(m_ActiveDevice, m_CopyFileName, m_pCopyMem, m_CopyFileSize);
		Update();
	}
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
	return Ret;
}

/*************************************************************************/
void CDlgFileMgr::FileInfoBox(const char *FName) const
/*************************************************************************/
/*! @brief Draws FileInfoBox.
	@param FName Filename
**************************************************************************/
{
	const int Height = 140;
	const int DirWidth = 280;
	int Width;
	FILEINFO FInfo;
	GUI_DLG *pDlg;
	char Text[512];
	char SizeStr[32];

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	// *** Get information ***
	VIB_GetFileInfo(m_ActiveDevice, FName, &FInfo);
	Width = strlen(FInfo.LName) * 8 + 100;
	if (Width < DirWidth)
		Width = DirWidth;

	if (FInfo.FileSize != FAT_DIRECTORY)
		sprintf(SizeStr, "%d Bytes", FInfo.FileSize);
	else
		strcpy(SizeStr, "< DIR >");
	std::snprintf(Text, 512,
		"%s\n%s\n%s\n"
		"%02d.%02d.%04d %02d:%02d:%02d\n"
		"%02d.%02d.%04d %02d:%02d:%02d\n"
		"%c%c%c%c%c\n",
		FName,
		(FInfo.LName[0] == NULL) ? FName : FInfo.LName,
		SizeStr,
		FInfo.CrtDate.Bits.Day,  FInfo.CrtDate.Bits.Month,  FInfo.CrtDate.Bits.Year + 1980,
		FInfo.CrtTime.Bits.Hour, FInfo.CrtTime.Bits.Minute, FInfo.CrtTime.Bits.Second * 2,
		FInfo.WrtDate.Bits.Day,  FInfo.WrtDate.Bits.Month,  FInfo.WrtDate.Bits.Year + 1980,
		FInfo.WrtTime.Bits.Hour, FInfo.WrtTime.Bits.Minute, FInfo.WrtTime.Bits.Second * 2,
		(FInfo.Attr & ATTR_READ_ONLY) ? 'R' : '-',
		(FInfo.Attr & ATTR_HIDDEN) ? 'H' : '-',
		(FInfo.Attr & ATTR_SYSTEM) ? 'S' : '-',
		(FInfo.Attr & ATTR_DIRECTORY) ? 'D' : '-',
		(FInfo.Attr & ATTR_ARCHIVE) ? 'A' : '-');

	// *** Show information ***
	pDlg = new GUI_DLG;
	if (pDlg)
	{
		if (GUI_DlgCreate2(pDlg, Width, Height + 86, "File Information") == GUI_E_OK)
		{
			GUI_DlgSetGradCol(pDlg, m_pApp->GetGradCol());
			m_pApp->SetTP(TextStyle::BOLD);
			GUI_DlgAddTextBox(pDlg, 4, 52, 96, Height,
				"Name:\n"
				"LName:\n"
				"Size:\n"
				"Created:\n"
				"Changed:\n"
				"Attributes:\n", 0);
			m_pApp->SetTP(TextStyle::MONOSPACE);
			GUI_DlgAddTextBox(pDlg, 96, 52, Width - 104, Height, Text, 0);
			m_pApp->SetTP(TextStyle::NORMAL);
			GUI_DlgAddButton(pDlg, (Width - 80) / 2, Height + 54, 80, 24, "_OK", 1);
			GUI_DlgModal(pDlg, m_pImage, -1, -1, m_fKB);
			GUI_DlgFree(pDlg);
		}
		delete pDlg;
	}
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
}

/*************************************************************************/
void CDlgFileMgr::DriveInfoBox() const
/*************************************************************************/
/*! @brief Draws DriveInfoBox.
**************************************************************************/
{
	const int Height = 122;
	const int Width = 240;
	DRIVEINFO DInfo;
	GUI_DLG *pDlg;
	char Text[256];

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	// *** Get information ***
	VIB_GetDriveInfo(m_ActiveDevice, &DInfo);
	std::snprintf(Text, 256, "%s\n%8d KB\n%8d KB\n%8d KB\nFAT%d\n",
		DInfo.Name, DInfo.Size, DInfo.Size-DInfo.Free, DInfo.Free, DInfo.FATType);

	// *** Show information ***
	pDlg = new GUI_DLG;
	if (pDlg)
	{
		if (GUI_DlgCreate2(pDlg, Width, Height + 86, "Drive Information") == GUI_E_OK)
		{
			GUI_DlgSetGradCol(pDlg, m_pApp->GetGradCol());
			m_pApp->SetTP(TextStyle::BOLD);
			GUI_DlgAddTextBox(pDlg, 4, 52, 112, Height,
				"Name:\n"
				"Capacity:\n"
				"Used:\n"
				"Free:\n"
				"File system:\n", 0);
			m_pApp->SetTP(TextStyle::MONOSPACE);
			GUI_DlgAddTextBox(pDlg, 112, 52, Width - 120, Height, Text, 0);
			m_pApp->SetTP(TextStyle::NORMAL);
			GUI_DlgAddButton(pDlg, (Width - 80) / 2, Height + 54, 80, 24, "_OK", 1);
			GUI_DlgModal(pDlg, m_pImage, -1, -1, m_fKB);
			GUI_DlgFree(pDlg);
		}
		delete pDlg;
	}
	GUI_DlgEnable(m_pDlg, 1);
}

/*************************************************************************/
void CDlgFileMgr::GetScrollKeys(int Width, int Height, int nKey,
	int *pxOff, int *pyOff)
/*************************************************************************/
/*! @brief Check keys and calculate display offset.
	@param Width Width of image
	@param Height Height of image
	@param nKey Scan code
	@param pxOff New x offset
	@param pyOff New y offset
**************************************************************************/
{
	const int iWidth = m_pApp->GetWidth();
	const int iHeight = m_pApp->GetHeight();
	int xOff = *pxOff;
	int yOff = *pyOff;

	switch (nKey)
	{
	case KB_LEFT:
		xOff -= iWidth/10;
		if (xOff < 0)
			xOff = 0;
		xOff &= ~3;
		break;
	case KB_RIGHT:
		xOff = _min2(xOff + (iWidth / 10), Width - iWidth);
		xOff = _max2(0, xOff);
		xOff &= ~3;
		break;
	case KB_UP:
		yOff -= iHeight/10;
		if (yOff < 0)
			yOff = 0;
		break;
	case KB_DOWN:
		yOff = _min2(yOff + (iHeight / 10), Height - iHeight);
		yOff = _max2(0, yOff);
		break;
	case KB_HOME:
		xOff = yOff = 0;
		break;
	case KB_END:
		xOff = 0;
		yOff = _max2(0, Height - iHeight);
		break;
	case KB_PGUP:
		xOff = _max2(0, Width - iWidth);
		yOff = 0;
		break;
	case KB_PGDOWN:
		xOff = _max2(0, Width - iWidth);
		yOff = _max2(0, Height - iHeight);
		break;
	case KB_OK:
		xOff = _max2(0, (Width - iWidth) / 2);
		yOff = _max2(0, (Height - iHeight) / 2);
		break;
	}
	*pxOff = xOff;
	*pyOff = yOff;
}

/*************************************************************************/
int CDlgFileMgr::DisplayImage(CIMAGE *pShowImage, const char *FName, int Depth)
/*************************************************************************/
/*! @brief Displays one image.
	@param pShowImage Image
	@param FName File name
	@param Depth Bit depth
	@return Pressed key
**************************************************************************/
{
	const int Width  = pShowImage->Width;
	const int Height = pShowImage->Height;
	const int iWidth = m_pApp->GetWidth();
	const int iHeight = m_pApp->GetHeight();
	int PicPosX, PicPosY;
	int xOff = 0, yOff = 0;
	int nKey;
	int nOff, nBarLen;
	bool bInfo = true;
	bool bActive = true;
	bool bOverview = false;
	bool bDirty = true;
	char Text[64];
	CIMAGE cScaleImage;
	CIMAGE *pImage = m_pApp->GetBgImage();

	PicPosX = (iWidth - Width) / 2;
	if (PicPosX < 0)
		PicPosX = 0;
	PicPosY = (iHeight - Height) / 2;
	if (PicPosY < 0)
		PicPosY = 0;

	do
	{
		if (bDirty)
		{
			if (Width < iWidth || Height < iHeight)
				m_pApp->InitBackground();
			GUI_CopyArea(pShowImage, pImage, xOff, yOff, Width, Height, PicPosX, PicPosY);
		
			if (PicPosX > 2 && PicPosY > 2)
			{
				GUI_Border(pImage, PicPosX - 2, PicPosY - 2, Width + 4, Height + 4, 5);
				GUI_Shadow(pImage, PicPosX + Width + 1, PicPosY + 8, 8, Height - 7);
				GUI_Shadow(pImage, PicPosX + 8, PicPosY + Height + 1, Width + 1, 8);
			}
			if (bInfo)
			{
				std::snprintf(Text, 64, "%s %4d x %4d x %2d", FName, Width, Height, Depth);
				m_pApp->SetTP(TextStyle::SHADOW);
				GUI_TextOut(pImage, (iWidth - 240) / 2, iHeight - 24, Text);
				if (xOff || yOff)
				{
					std::snprintf(Text, 64, "v: %4d, h: %4d", xOff, yOff);
					GUI_TextOut(pImage, (iWidth - 128) / 2, iHeight - 42, Text);
				}
				m_pApp->SetTP(TextStyle::NORMAL);

				// *** Scrollbars ***
				if (Width > iWidth)
				{
					nBarLen = (iWidth * iWidth) / Width - 4;
					nOff = (xOff * iWidth) / Width + 2;
					GUI_Border(pImage, nOff, PicPosY + _min2(Height, iHeight) - 4, nBarLen, 3, 1);
				}
				if (Height > iHeight)
				{
					nBarLen = (iHeight * iHeight) / Height - 4;
					nOff = (yOff * iHeight) / Height + 2;
					GUI_Border(pImage, PicPosX + _min2(Width, iWidth) - 4, nOff, 3, nBarLen, 1);
				}

				// *** Overview ***
				if ((Width > iWidth || Height > iHeight) && bOverview)
				{
					cScaleImage = GUI_CImage(NULL, NULL, NULL, 320, 240);
					if (cScaleImage.Width)
					{
						const float fScaleX = (float)Width / 320;
						const float fScaleY = (float)Height /240;
						const int oy = (float)yOff / fScaleY;
						const int ix = (float)(xOff + iWidth) / fScaleX;
						const int iy = (int)((float)yOff / fScaleY) + (int)((float)iHeight / fScaleY);

						GUI_ScaleImageNN(pShowImage, &cScaleImage);
						GUI_Shadow(&cScaleImage, 0, 0, 320, oy);
						GUI_Shadow(&cScaleImage, 0, oy, (float)xOff / fScaleX, (float)iHeight / fScaleY);
						GUI_Shadow(&cScaleImage, ix, oy, 320 - ix, (float)iHeight/fScaleY);
						GUI_Shadow(&cScaleImage, 0, iy, 320, 240 - iy);
						GUI_IRect(&cScaleImage, (float)xOff / fScaleX, oy, (float)iWidth / fScaleX, (float)iHeight / fScaleY);
						GUI_CopyArea(&cScaleImage, pImage, 0, 0, 320, 240, 4, 4);
						GUI_Border(pImage, 2, 2, 320 + 4, 240 + 4, 5);
						GUI_FreeCImage(&cScaleImage);
					}
				}
			}
			GUI_Display(pImage, 0, 0);
		}
		bDirty = true;

		nKey = getc(m_fKB);
		if (GUI_DlgGetCoord) // Check Mouse
		{
			int txp, typ;

			if (GUI_DlgGetCoord(&txp, &typ) > 0)
			{
				if (txp < 10)
					nKey = KB_BACKSP;
				if (txp > iWidth - 10)
					nKey = ' ';
				bActive = false;
			}
		}

		switch (nKey)
		{
		case EOF:
			_UNSET(m_fKB, _STATEOF);
			VIB_WaitBios(10);
			bDirty = false;
			break;
		case KB_F1:
			m_pApp->MessageBox(
				"\nI: Information\nO:Overview\nCursor: Move region\nESC: Cancel\n\n",
				0, "Help");
			break;
		case 'i':
		case 'I':
			bInfo = !bInfo;
			break;
		case 'o':
		case 'O':
			bOverview = !bOverview;
			break;
		case KB_ESC:
		case KB_BACKSP:
		case ' ':
			bActive = false;
			break;
		}
		GetScrollKeys(Width, Height, nKey, &xOff, &yOff);
	} while (bActive);

	return nKey;
}

/*************************************************************************/
int CDlgFileMgr::DisplayBMPFile(const char *FName)
/*************************************************************************/
/*! @brief Shows a BMP file.
	@param FName Filename
	@return Pressed key
**************************************************************************/
{
	CIMAGE cImage;
	int Width, Height, Depth;
	int nKey;

	if (GUI_GetBMPInfo(m_ActiveDevice, FName, &Width, &Height, &Depth) < 0)
		return EOF;
	cImage = GUI_ReadNewCImage(m_ActiveDevice, FName);
	if (cImage.Width == 0)
		return EOF;
	nKey = DisplayImage(&cImage, FName, Depth);
	GUI_FreeCImage(&cImage);
	return nKey;
}

/*************************************************************************/
int CDlgFileMgr::DisplayPNGFile(const char *FName)
/*************************************************************************/
/*! @brief Shows a PNG file.
	@param FName Filename
	@return Pressed key
**************************************************************************/
{
	CIMAGE cImage;
	int Width, Height, Depth;
	int nKey;

	if (PNG_GetInfo(m_ActiveDevice, FName, &Width, &Height, &Depth) < 0)
		return EOF;
	cImage = PNG_ReadNewCImage(m_ActiveDevice, FName);
	if (cImage.Width == 0)
		return EOF;
	nKey = DisplayImage(&cImage, FName, Depth);
	GUI_FreeCImage(&cImage);
	return nKey;
}

/*************************************************************************/
int CDlgFileMgr::DisplayJPGFile(const char *FName)
/*************************************************************************/
/*! @brief Shows a JPG file.
	@param FName Filename
	@return Pressed key
**************************************************************************/
{
	CIMAGE cImage;
	int Width, Height, Depth;
	int nKey;

	if (JPEG_GetInfo(m_ActiveDevice, FName, &Width, &Height, &Depth) < 0)
		return EOF;
	cImage = JPEG_ReadNewCImage(m_ActiveDevice, FName);
	if (cImage.Width == 0)
		return EOF;
	nKey = DisplayImage(&cImage, FName, Depth);
	GUI_FreeCImage(&cImage);
	return nKey;
}

/*************************************************************************/
void CDlgFileMgr::DisplayRBFFile(const char *FName)
/*************************************************************************/
/*! @brief Shows information from '<tt>.RBF /.VBF</tt>'.
	@param FName Filename
**************************************************************************/
{
	int FSize;
	int Type, Revision;
	char *Buffer;
	char Str[32], Text[256];

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	FSize = VIB_FindFile2(m_ActiveDevice, FName);
	if (FSize > 64)
	{
		Buffer = (char*)VIB_MemAlloc(FSize);
		if (Buffer)
		{
			FSize = VIB_ReadFile(m_ActiveDevice, FName, (unsigned char*)Buffer);
			if (strncmp(&Buffer[FSize - 64], "VERS", 4) == 0)
			{
				Str[4] = '\0';
				strncpy(Str, &Buffer[FSize - 60], 4);
				Type = atoi(Str);
				strncpy(Str, &Buffer[FSize - 56], 4);
				Revision = atoi(Str);
			}
			else
			{
				Type = 0;
				Revision = 0;
				strcpy(&Buffer[FSize - 52], "??.??.???? ??:??:??");
			}

			std::snprintf(Text, 64, "\nDesign Type: %.4d (%s)\nRevision: %.4d\n%s\n\n",
				Type, SatInfo2String(Type), Revision, &Buffer[FSize - 52]);
			m_pApp->MessageBox(Text, 0, "Info");
			VIB_MemFree(Buffer);
		}
	}

	GUI_DlgEnable(m_pDlg, 1);
}

/*************************************************************************/
void CDlgFileMgr::DisplayTTFFile(const char *FName)
/*************************************************************************/
/*! @brief Shows information from '<tt>.ttf</tt>'.
	@param FName Filename
**************************************************************************/
{
#if (USE_FREETYPE == 1)
	const int Width = 32;
	const int Height = 36;
	int i, k;
	CIMAGE cImage;
	TEXTPARAMETER TP;
	char Text[8];
	void *ftFont;

	cImage = GUI_CImage(NULL, NULL, NULL, 532, 612);
	if (cImage.Width == 0)
		return;

	ftFont = GUI_FTFontFile(m_ActiveDevice, FName, 32, 32, 1);

	if (ftFont)
	{
		GUI_Fill(&cImage, &rgbWhite);
		GUI_SetTxtBackCol(rgbWhite);
		GUI_SetTxtFrontCol(rgbBlue);
		for (i = 0; i < 16; i++)
		{
			GUI_TextOutFormat(&cImage, i * Width + 28, 2, "%x", i);
			GUI_TextOutFormat(&cImage, 2, i * Height + 28, "%x", i);
		}
		m_pApp->SetTP(TextStyle::NORMAL);

		GUI_InitTxtParam(&TP);
		GUI_SetTxtFTFontParam(ftFont, &TP);
		TP.BackCol = rgbWhite;
		TP.FrontCol = rgbBlack;
		Text[1] = '\0';
		k = 0;
		for (i = 0; i < 16; i++)
		{
			for (int j = 0; j < 16; j++)
			{
				Text[0] = k++;
				GUI_TextOutTP(&cImage, j * Width + 20, i * Height + 20, Text, &TP);
			}
			GUI_Line(&cImage, 18, i * Height + 20, 16 * Width + 18, i * Height + 20, &rgbBlue);
		}
		GUI_Line(&cImage, 18, i * Height + 20, 16 * Width + 18, i * Height + 20, &rgbBlue);
		for (i = 0; i < 17; i++)
			GUI_Line(&cImage, i * Width + 18, 20, i * Width + 18, 16 * Height + 20, &rgbBlue);
		DisplayImage(&cImage, GUI_FTGetName(ftFont), 8);
		GUI_FTFreeFont(ftFont);
	}
	GUI_FreeCImage(&cImage);
#endif
}

/*************************************************************************/
void CDlgFileMgr::DisplayVBUFile(const char *FName)
/*************************************************************************/
/*! @brief Shows information of VisionBox Update file.

	Executes firmware update.
	@param FName Filename
**************************************************************************/
{
	char *pDescription;
	int Bootloader, FPGAVersion[2], AddOnVersion[4], GBitVersion;
	int result;
	GUI_DLG Dlg;
	DLG_ITEMD *pLogBox;
	DLG_ITEMD *pButtonStart;
	DLG_ITEMS *pStartText;
	char *Text;

	if (VIB_FirmwareUpdateFileVersion(m_ActiveDevice, FName, &pDescription,
		&Bootloader, FPGAVersion, AddOnVersion, &GBitVersion) != 0)
	{
		m_pApp->MessageBox("Failed to read update information!\n", 0, "Error");
		return;
	}

	Text = (char*)VIB_MemAlloc(10 * 1024);
	if (Text == NULL)
	{
		free(pDescription);
		return;
	}

	// Create version string
	Text[0] = '\0';
	if (pDescription)
	{
		strcat(Text, pDescription);
		free(pDescription);
	}
	strcat(Text, "\nVersion information:\n");
	sprintf(Text, "%s%20s | %20s | %20s\n", Text, "", "Currently running", "Update Archive");
	sprintf(Text, "%s%20s | %17d.%02d | ", Text, "Bootloader",
		VIB_HWInfo.Bootloader / 100, VIB_HWInfo.Bootloader % 100);
	if (Bootloader < 0)
		sprintf(Text, "%s%20s\n", Text, "no update");
	else
		sprintf(Text, "%s%17d.%02d\n", Text, Bootloader / 100, Bootloader % 100);
	for (int i = 0; i < 2; i++)
	{
		if (FPGAVersion[i] == -1)
			sprintf(Text, "%s%18s %d | %17d.%02d | %20s\n", Text, "Main FPGA",
				i, VIB_HWInfo.FPGA_Version[i] / 100, VIB_HWInfo.FPGA_Version[i] % 100, "no update");
		else if (FPGAVersion[i] >= 0)
			sprintf(Text, "%s%18s %d | %17d.%02d | %17d.%02d\n", Text, "Main FPGA",
				i, VIB_HWInfo.FPGA_Version[i] / 100, VIB_HWInfo.FPGA_Version[i] % 100, FPGAVersion[i] / 100, FPGAVersion[i] % 100);
	}
	for (int i = 0; i < 4; i++)
	{
		if (AddOnVersion[i] == -1)
			sprintf(Text, "%s%18s %d | %17d.%02d | %20s\n", Text, "Add-On FPGA",
				i, VIB_HWInfo.AddOnVersion[i] / 100, VIB_HWInfo.AddOnVersion[i] % 100, "no update");
		else if (AddOnVersion[i] >= 0)
			sprintf(Text, "%s%18s %d | %17d.%02d | %17d.%02d\n", Text, "Add-On FPGA",
				i, VIB_HWInfo.AddOnVersion[i] / 100, VIB_HWInfo.AddOnVersion[i] % 100, AddOnVersion[i] / 100, AddOnVersion[i] % 100);
	}
	if (GBitVersion == -1)
		sprintf(Text, "%s%20s | %20d | %20s\n", Text, "GBit Stack Software", GBIT_Version, "no update");
	else if (GBitVersion >= 0)
		sprintf(Text, "%s%20s | %20d | %20d\n", Text, "GBit Stack Software", GBIT_Version, GBitVersion);
	strcat(Text, "\n");

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	// Create dialog
	Dlg = GUI_DlgCreate(620, 358, "Firmware Update");
	GUI_DlgSetGradCol(&Dlg, rgbGradBlue);
	m_pApp->SetTP(TextStyle::MONOSPACE);
	pLogBox = GUI_DlgAddLogBox(&Dlg, 10, 30, Dlg.rgbDlg.Width - 20, Dlg.rgbDlg.Height-110, Text, 1);
	m_pApp->SetTP(TextStyle::NORMAL);
	pStartText = GUI_DlgAddText(&Dlg, 10, Dlg.rgbDlg.Height - 70, "Press 'Start' to start the update");
	pButtonStart = GUI_DlgAddButton(&Dlg, 8, Dlg.rgbDlg.Height - 40, 96, 24, "Start", 2);
	GUI_DlgAddButton(&Dlg, 112, Dlg.rgbDlg.Height - 40, 96, 24, "_Close", DLG_ABORT);
	do
	{
		result = GUI_DlgModal(&Dlg, NULL, -1, -1, m_fKB);
	}
	while (result != 2 && result != DLG_ABORT);

	// Update
	if (result == 2)
	{
		if (m_pApp->MessageBox("\nStart update?\nDo not turn off power during the update process!\n\n", 1, "Firmware Update") == 1)
		{
			FILE *pLogFile;
			char logFile[40];

			sprintf(logFile, "DRV:%s:FwUpdate.txt", VIB_GetDeviceName(VIB_Drive[1]));
			if (VIB_FindFile2(VIB_Drive[1], "FwUpdate.txt") >= 0)
			{
				VIB_DeleteFile(VIB_Drive[1], "FwUpdate.bak");
				VIB_RenameFile(VIB_Drive[1], "FwUpdate.txt", "FwUpdate.bak");
			}
			pLogFile = fopen(logFile, "w");
			if (pLogFile)
			{
				int logSize;

				GUI_MessageBoxEx(NULL, m_fKB, "\nFirmware update is in progress, do not turn off power!\n\n", "Firmware Update", NULL, NULL, NULL);
				result = VIB_FirmwareUpdateFile(m_ActiveDevice, FName, pLogFile, 0);
				fclose(pLogFile);
				GUI_DlgLogBoxClear(pLogBox);
				logSize = VIB_FindFile2(VIB_Drive[1], "FwUpdate.txt");
				if (logSize > 0)
				{
					char *pLogBuffer = (char*)VIB_MemAlloc(logSize + 1);

					if (pLogBuffer)
					{
						VIB_ReadFile(VIB_Drive[1], "FwUpdate.txt", pLogBuffer);
						pLogBuffer[logSize] = '\0';
						GUI_DlgLogBoxPrint(pLogBox, pLogBuffer);
						VIB_MemFree(pLogBuffer);
					}
				}
			}

			// Show log file
			GUI_DlgSetSItemState(pStartText, DLG_I_INVISIBLE);
			GUI_DlgSetDItemState(pButtonStart, DLG_I_DISABLED);
			GUI_DlgModal(&Dlg, m_pImage, -1, -1, m_fKB);
		}
	}

	GUI_DlgFree(&Dlg);
	VIB_MemFree(Text);
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
}

/*************************************************************************/
void CDlgFileMgr::DisplayAVIFile(const char *FName)
/*************************************************************************/
/*! @brief Shows information of AVI file.
**************************************************************************/
{
	const int Height = 100;
	const int Width = 220;
	int AWidth, AHeight, ADepth, AFrames;
	GUI_DLG *pDlg;
	char Text[256];

	if (GUI_AVIReadHeader(m_ActiveDevice, FName, &AWidth, &AHeight, &ADepth, &AFrames) < 0)
		return;

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	std::snprintf(Text, 256, "%s\n%d\n%d\n%d\n%d\n",
		FName, AWidth, AHeight, ADepth, AFrames);

	// *** Show information ***
	pDlg = new GUI_DLG;
	if (pDlg)
	{
		if (GUI_DlgCreate2(pDlg, Width, Height + 86, "AVI Information") == GUI_E_OK)
		{
			GUI_DlgSetGradCol(pDlg, m_pApp->GetGradCol());
			m_pApp->SetTP(TextStyle::BOLD);
			GUI_DlgAddTextBox(pDlg, 4, 42, 96, Height,
				"Name:\n"
				"Width:\n"
				"Height:\n"
				"Depth:\n"
				"Frames:\n", 0);
			m_pApp->SetTP(TextStyle::MONOSPACE);
			GUI_DlgAddTextBox(pDlg, 96, 42, Width - 104, Height, Text, 0);
			m_pApp->SetTP(TextStyle::NORMAL);
			GUI_DlgAddButton(pDlg, (Width - 80) / 2, Height + 54, 80, 24, "_OK", 1);
			GUI_DlgModal(pDlg, m_pImage, -1, -1, m_fKB);
			GUI_DlgFree(pDlg);
		}
		delete pDlg;
	}
	GUI_DlgEnable(m_pDlg, 1);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
}

/*************************************************************************/
void CDlgFileMgr::EditTextFile(const char *FName)
/*************************************************************************/
/*! @brief Edits text file.
	@param FName Filename
**************************************************************************/
{
	const int Width = m_pApp->GetWidth();
	const int Height = m_pApp->GetHeight();
	int FSize, MemSize;
	int ExitKey = 0;
	int bChange;
	bool bSave = false;
	char Text[128];
	CIMAGE *pImage = m_pApp->GetBgImage();
	unsigned char *pMemory;

	FSize = VIB_FindFile2(m_ActiveDevice, FName);
	if (FSize > 0)
	{
		MemSize = FSize + 256 * 1024; // Some additional memory for editing the file
		pMemory = (unsigned char*)VIB_MemAlloc(MemSize);
		if (pMemory == NULL)
		{
			m_pApp->MessageBox("\nError\n\n");
			return;
		}
		VIB_ReadFile(m_ActiveDevice, FName, pMemory);
		do
		{
			m_pApp->SetTP(TextStyle::MONOSPACE);
			bChange = GUI_Editor(pImage, FName, 0, 0, Width, Height, MemSize, (char*)pMemory, m_fKB, &FSize, &ExitKey);
			m_pApp->SetTP(TextStyle::NORMAL);
			if (bChange)
			{
				if (ExitKey == KB_SAVE)
					bSave = true;
				else
				{
					GUI_Display(pImage, 0, 0);
					std::snprintf(Text, 128, "\nSave changes in %s ?\n\n", FName);
					if (m_pApp->MessageBox(Text, 1) == 1)
						bSave = true;
				}
				if (bSave)
				{
					if (!CheckForProtectedFlash())
					{
						VIB_DeleteFile(m_ActiveDevice, FName);
						VIB_WriteFile(m_ActiveDevice, FName, pMemory, FSize);
					}
					bSave = false;
				}
			}
		}
		while (ExitKey != KB_ESC);
		VIB_MemFree(pMemory);
		RecBackground();
	}
}

/*************************************************************************/
const char *CDlgFileMgr::SatInfo2String(int Type) const
/*************************************************************************/
/*! @brief Converts Sat info to string.
	@param Type Type of VBF design
	@return Name of VBF design
**************************************************************************/
{
	switch (Type)
	{
		case VBF_SAT_DUMMY:  return "None";
		case VBF_EARTH:      return "Earth";
		case VBF_MOON:       return "Moon";
		case VBF_SAT_WDVI:   return "DVI";
		case VBF_SAT_ANALOG: return "Analog";
		case VBF_SAT_CLIO:   return "CameraLink I/O";
		case VBF_SAT_CLIN:   return "CameraLink In";
		case VBF_SAT_CLCH:   return "CameraLink Chain";
		case VBF_SAT_1394:   return "IEEE 1394";
		case VBF_SAT_LVDS:   return "LVDS";
		case VBF_SAT_CLINr1: return "CameraLink Ext";
		case VBF_SAT_CHCLO:  return "CameraLink Chain";
		case VBF_SAT_CHININ: return "CameraLink Chain 2*In";
		case VBF_SAT_ANYBUS: return "Anybus";
		case VBF_SAT_GBIT:   return "Gigabit Ethernet";
		case VBF_SAT_CAN:    return "CAN Bus";
		case VBF_SAT_LWL:    return "LWL";
		case VBF_SAT_ATA:    return "ATA storage";
		case VBF_SAT_DIO:    return "Digital IO";
		default:             return "???";
	}
}

/*************************************************************************/
void CDlgFileMgr::RecBackground()
/*************************************************************************/
/*! @brief Recovers background image
**************************************************************************/
{
	m_pApp->RecBackground(1);
	CDlgTools::GetInstance()->Show();
}

/*************************************************************************/
int CDlgFileMgr::SelectDevice()
/*************************************************************************/
/*! @brief Selects a device.
	@return Device
**************************************************************************/
{
	int nSelect = 1;
	int ret;
	GUI_DLG *pDlg;
	char Text[256];
	char tmp[64];

	GUI_DlgEnable(m_pDlg, 0);
	GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);

	Text[0] = '\0';
	for (int i = 0; i < VIB_DriveCount; i++)
	{
		std::snprintf(tmp, 64, "VIB_Drive%d: (%s)\n", i, VIB_GetDeviceName(VIB_Drive[i]));
		strcat(Text, tmp);
	}

	pDlg = new GUI_DLG;
	GUI_DlgCreate2(pDlg, m_FSWidth, 120, NULL);
	GUI_DlgAddSelectBox(pDlg, 4, 4, m_FSWidth - 8, 80, Text, &nSelect, 1);
	GUI_DlgAddButton(pDlg, 4, 90, (m_FSWidth - 16) / 2, 24, "_OK", 10);
	GUI_DlgAddButton(pDlg, (m_FSWidth / 2) + 4, 90, (m_FSWidth - 16) / 2, 24, m_pApp->GetStr(StringTable::CANCEL), DLG_ABORT);

	ret = GUI_DlgModal(pDlg, m_pImage, m_PosX + (m_FSWidth + 8) * m_Side + 8, 60, m_fKB);
	GUI_DlgFree(pDlg);
	delete pDlg;

	GUI_DlgEnable(m_pDlg, 1);

	if (ret != DLG_ABORT)
		if (VIB_Drive[nSelect - 1])
			return VIB_Drive[nSelect - 1];

	return -1;
}

/*************************************************************************/
bool CDlgFileMgr::CheckForProtectedFlash() const
/*************************************************************************/
/*! @brief Checks if active drive is protected internal flash memory.
	@return \p true / \p false
**************************************************************************/
{
	if (m_ActiveDevice == VIB_Drive[0] && m_bProtectFlash)
	{
		int ret;

//		m_pA->MessageBox("\nInternal flash is write protected!\n\n");
		GUI_DlgEnable(m_pDlg, 0);
		GUI_DlgUpdate(m_pDlg, m_pImage, m_PosX, 0);
		ret = (CDlgPassword::GetInstance())->CheckPassword(m_fKB, 1);
		GUI_DlgEnable(m_pDlg, 1);
		if (!ret)
			return true;
	}
	return false;
}

/*************************************************************************/
