// InspectorBar.cpp : implementation file
//

#pragma warning( disable : 4786 )		// long names generated by STL

#include "afxole.h"
#include "stdafx.h"
#include "demopaja.h"
#include "demopajaDoc.h"
#include "InspectorBar.h"
#include "PajaTypes.h"
#include "FlatPopUpMenu.h"
#include "FileListC.h"
#include "ImportableI.h"
#include "ImportableImageI.h"
#include "MainFrm.h"
#include <vector>
#include <algorithm>
#include "SubSceneC.h"
#include "FolderPropertiesDlg.h"
#include <stdlib.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


using namespace PajaTypes;
using namespace Edit;
using namespace Import;
using namespace PluginClass;

static
void
TRACE_LAST_ERROR( const char* szCaller )
{
	LPVOID lpMsgBuf;
	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		FORMAT_MESSAGE_FROM_SYSTEM | 
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL 
	);
	TRACE( "ERROR %s: %s\n", szCaller, lpMsgBuf );
	LocalFree( lpMsgBuf );
} 

const int32	g_i32ArrowWidth = 20;
const int32	g_i32ImageWidth = 25;
const int32	g_i32IndentWidth = 20;

const int32	g_i32ItemHeight = 18;

const int32	g_i32ButtonRowSize = 22;



static
int32
FolderFlagToColor( int32 i32Flags )
{
	if( i32Flags & FILEHANDLE_FOLDERCOLOR_WHITE )
		return 0;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_RED )
		return 1;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_YELLOW )
		return 2;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_GREEN )
		return 3;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_CYAN )
		return 4;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_BLUE )
		return 5;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_MAGENTA )
		return 6;
	else if( i32Flags & FILEHANDLE_FOLDERCOLOR_BLACK )
		return 7;

	return 0;
}

static
int32
ColorToFolderFlag( int32 i32Color )
{
	switch( i32Color ) {
	case 0: return FILEHANDLE_FOLDERCOLOR_WHITE;
	case 1: return FILEHANDLE_FOLDERCOLOR_RED;
	case 2: return FILEHANDLE_FOLDERCOLOR_YELLOW;
	case 3: return FILEHANDLE_FOLDERCOLOR_GREEN;
	case 4: return FILEHANDLE_FOLDERCOLOR_CYAN;
	case 5: return FILEHANDLE_FOLDERCOLOR_BLUE;
	case 6: return FILEHANDLE_FOLDERCOLOR_MAGENTA;
	case 7: return FILEHANDLE_FOLDERCOLOR_BLACK;
	}
	return FILEHANDLE_FOLDERCOLOR_WHITE;
}

bool
CInspectorBar::CacheItemS::operator<( const CInspectorBar::CacheItemS& rOther ) const
{
	int32	i32Score1 = 0, i32Score2 = 0;


	// The two files are in same folder.
	if( m_pHandle->get_parent_handle() == rOther.m_pHandle->get_parent_handle() ) {

		if( m_bFolder )
			i32Score1 -= 10;
		if( rOther.m_bFolder )
			i32Score2 -= 10;

//		if( m_sName.compare( rOther.m_sName ) == -1 )
		if( _stricmp( m_sName.c_str(), rOther.m_sName.c_str() ) == -1 )
			i32Score2 += 1;
		else
			i32Score1 += 1;
	}

//	if( m_bFolder && !rOther.m_bFolder ) {
//		return true;
//	}
//	if( m_pHandle->get_parent() == rOther.m_pHandle->get_parent() && m_sName.compare( rOther.m_sName ) == -1 ) {
//		return true;
//	}
	return i32Score1 < i32Score2;
}


/////////////////////////////////////////////////////////////////////////////
// CInspectorBar

CInspectorBar::CInspectorBar() :
	m_i32ListOffsetX( 0 ),
	m_i32ListOffsetY( 0 ),
	m_i32NameSize( 125 ),
	m_i32TypeSize( 80 ),
	m_i32RefSize( 30 ),
	m_i32InfoSize( 150 ),
	m_i32PathSize( 150 ),
	m_bInitialised( false ),
	m_bFileCacheValid( false ),
	m_i32FileCacheMaxHeight( 0 ),
	m_i32SelItem( -1 ),
	m_hCursor( 0 ),
	m_i32ListTrack( LIST_TRACK_NONE ),
	m_i32HeaderTrack( HEADER_TRACK_NONE )
{
}

CInspectorBar::~CInspectorBar()
{
}


BEGIN_MESSAGE_MAP(CInspectorBar, baseCMyBar)
	//{{AFX_MSG_MAP(CInspectorBar)
	ON_WM_SIZE()
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_SETCURSOR()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_DESTROY()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED( IDC_IMPORTFILE, OnImportFile )
	ON_BN_CLICKED( IDC_CREATEFILE, OnCreateFile )
	ON_BN_CLICKED( IDC_CREATEFOLDER, OnCreateFolder )
	ON_BN_CLICKED( IDC_CREATESCENE, OnCreateScene )
	ON_BN_CLICKED( IDC_DELETEFILE, OnDeleteFile )
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInspectorBar message handlers

void CInspectorBar::OnSize(UINT nType, int cx, int cy) 
{
	baseCMyBar::OnSize( nType, cx, cy );

	//	m_rListCtrl.MoveWindow( 0, 0, cx, cy, TRUE );

	CRect	rRect;
	GetClientRect( rRect );

	if( m_bInitialised ) {
		int32	i32VScrollSize = ::GetSystemMetrics( SM_CXVSCROLL );
		int32	i32HScrollSize = ::GetSystemMetrics( SM_CXHSCROLL );

		// Header
		m_rHeaderRect.left = 1;
		m_rHeaderRect.right = cx - 1 - i32VScrollSize;
		m_rHeaderRect.top = 1;
		m_rHeaderRect.bottom = 1 + 22;

		// File list
		m_rListRect.left = 1;
		m_rListRect.right = cx - 1 - i32VScrollSize;
		m_rListRect.top = 1 + 22;
		m_rListRect.bottom = cy - 1 - i32HScrollSize - g_i32ButtonRowSize;

	
		// Scrollbars
		m_rListScrollVert.MoveWindow( rRect.right - i32VScrollSize - 1, rRect.top + 1,
									  i32VScrollSize, rRect.Height() - i32HScrollSize - 2 - g_i32ButtonRowSize,
									  TRUE );

		m_rListScrollHoriz.MoveWindow( rRect.left + 1, rRect.bottom - i32HScrollSize - 1 - g_i32ButtonRowSize,
									   rRect.Width() - i32VScrollSize - 2, i32HScrollSize,
									   TRUE );

		m_rImportButton.MoveWindow( 0, rRect.bottom - 22, 22, 20, TRUE );
		m_rCreateButton.MoveWindow( 22, rRect.bottom - 22, 22, 20, TRUE );
		m_rFolderButton.MoveWindow( 44, rRect.bottom - 22, 22, 20, TRUE );
		m_rSceneButton.MoveWindow( 66, rRect.bottom - 22, 22, 20, TRUE );
		m_rDelButton.MoveWindow( 88, rRect.bottom - 22, 22, 20, TRUE );

		UpdateScrollRange();

		Invalidate( TRUE );
	}
}


static
COLORREF
Mix( COLORREF rCol1, COLORREF rCol2, int iAlpha )
{
	int	iR, iG, iB;

	iR = ((GetRValue( rCol1 ) * iAlpha) + (GetRValue( rCol2) * (255 - iAlpha))) / 255;
	iG = ((GetGValue( rCol1 ) * iAlpha) + (GetGValue( rCol2) * (255 - iAlpha))) / 255;
	iB = ((GetBValue( rCol1 ) * iAlpha) + (GetBValue( rCol2) * (255 - iAlpha))) / 255;

	return	RGB( iR, iG, iB );
}


int CInspectorBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (baseCMyBar::OnCreate(lpCreateStruct) == -1)
		return -1;

	// register this window as drop target
	m_rDropTarget.Register( this );

	if( !m_rFont.CreateFont( 14, 0, 0, 0, FW_NORMAL, 0, 0, 0,
		ANSI_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		DEFAULT_PITCH | FF_DONTCARE,
		"arial" ) ) {
		TRACE( "Cannot create default font.\n" );
		return -1;
	}

	if( !m_rSmallFont.CreateFont( 12, 0, 0, 0, FW_NORMAL, 0, 0, 0,
		ANSI_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		DEFAULT_PITCH | FF_DONTCARE,
		"arial" ) ) {
		TRACE( "Cannot create default font.\n" );
		return -1;
	}

	if( !m_rFileTypeImages.Create( IDB_FILETYPES, 16, 14, RGB( 255, 0, 255 ) ) ) {
		TRACE( "Cannot create Filetype Imagelist.\n" );
	}

	if( !m_rFileListImages.Create( IDB_FILELIST, 12, 2, RGB( 255, 0, 255 ) ) ) {
		TRACE( "Cannot create Filelist Imagelist.\n" );
	}
	
	// Create scrollbar for layer list.
	if( !m_rListScrollVert.Create( WS_VISIBLE | WS_CHILD | SBS_VERT,
		CRect( 0, 0, 0, 0 ), this, IDC_FILEINSPECTOR_VSCROLL ) )
		return -1;

	// Create scrollbar for timeline
	if( !m_rListScrollHoriz.Create( WS_VISIBLE | WS_CHILD | SBS_HORZ,
		CRect( 0, 0, 0, 0 ), this, IDC_FILEINSPECTOR_HSCROLL ) )
		return -1;

	if( !m_rImportButton.Create( "", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_VCENTER,
		CRect( 0, 0, 22, 20 ), this, IDC_IMPORTFILE ) ) {
		return -1;
	}
	if( !m_rCreateButton.Create( "", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_VCENTER,
		CRect( 0, 0, 22, 20 ), this, IDC_CREATEFILE ) ) {
		return -1;
	}
	if( !m_rFolderButton.Create( "", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_VCENTER,
		CRect( 0, 0, 22, 20 ), this, IDC_CREATEFOLDER ) ) {
		return -1;
	}
	if( !m_rSceneButton.Create( "", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_VCENTER,
		CRect( 0, 0, 22, 20 ), this, IDC_CREATESCENE ) ) {
		return -1;
	}
	if( !m_rDelButton.Create( "", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_VCENTER,
		CRect( 0, 0, 22, 20 ), this, IDC_DELETEFILE ) ) {
		return -1;
	}

	// map colors
	COLORMAP	rColors[3];
	// magenta BG
	rColors[0].from = RGB( 255, 0, 255 );
	rColors[0].to = ::GetSysColor( COLOR_BTNFACE );
	// light grey
	rColors[1].from = RGB( 192, 192, 192 );
	rColors[1].to = ::GetSysColor( COLOR_BTNFACE );
	// dark grey
	rColors[2].from = RGB( 128, 128, 128 );
	rColors[2].to = ::GetSysColor( COLOR_BTNSHADOW );

	if( !m_rImportBitmap.LoadMappedBitmap( IDB_IMPORTFILE, 0, rColors, 3 ) )
		return -1;
	if( !m_rCreateBitmap.LoadMappedBitmap( IDB_CREATEFILE, 0, rColors, 3 ) )
		return -1;
	if( !m_rFolderBitmap.LoadMappedBitmap( IDB_CREATEFOLDER, 0, rColors, 3 ) )
		return -1;
	if( !m_rSceneBitmap.LoadMappedBitmap( IDB_CREATESCENE, 0, rColors, 3 ) )
		return -1;
	if( !m_rDelBitmap.LoadMappedBitmap( IDB_TRASHBIN, 0, rColors, 3 ) )
		return -1;

	m_rImportButton.SetBitmaps( m_rImportBitmap );
	m_rCreateButton.SetBitmaps( m_rCreateBitmap );
	m_rFolderButton.SetBitmaps( m_rFolderBitmap );
	m_rSceneButton.SetBitmaps( m_rSceneBitmap );
	m_rDelButton.SetBitmaps( m_rDelBitmap );

	m_rImportButton.SetTooltipText( "Import File" );
	m_rCreateButton.SetTooltipText( "Create File" );
	m_rFolderButton.SetTooltipText( "Create Folder" );
	m_rSceneButton.SetTooltipText( "Create Scene" );
	m_rDelButton.SetTooltipText( "Delete" );



	// Create folder imagelist


	if( !m_rFolderImages.Create( 16, 16, ILC_COLOR8 | ILC_MASK, 0, 16 ) )
		return -1;

	// map colors
	COLORMAP	rFolderBaseColors[3];
	// hilight
	rFolderBaseColors[0].from = RGB( 255, 255, 255 );
	rFolderBaseColors[0].to = ::GetSysColor( COLOR_BTNFACE );
	// light grey
	rFolderBaseColors[1].from = RGB( 192, 192, 192 );
	rFolderBaseColors[1].to = ::GetSysColor( COLOR_BTNFACE );
	// dark grey
	rFolderBaseColors[2].from = RGB( 128, 128, 128 );
	rFolderBaseColors[2].to = ::GetSysColor( COLOR_BTNSHADOW );

	COLORREF	rFolderColors[8] = {
		RGB( 255, 255, 255 ),
		RGB( 255, 0,   0 ),
		RGB( 255, 255, 0 ),
		RGB( 0,   255, 0 ),
		RGB( 0,   255, 255 ),
		RGB( 0,   0,   255 ),
		RGB( 255, 0,   255 ),
		RGB( 0,   0,   0 ),
	};

	COLORREF	rBaseGrey = ::GetSysColor( COLOR_BTNFACE );

	for( uint32 i = 0; i < 8; i++ ) {

		rFolderBaseColors[1].to = Mix( rFolderColors[i], rBaseGrey, 64 );
		rFolderBaseColors[0].to = Mix( rFolderBaseColors[1].to, RGB( 255, 255, 255 ), 180 );
		rFolderBaseColors[2].to = Mix( rFolderBaseColors[1].to, RGB( 0, 0, 0 ), 128 );

		CBitmap	rBitmap;

		if( !rBitmap.LoadMappedBitmap( IDB_FOLDERS, 0, rFolderBaseColors, 3 ) )
			return -1;

		m_rFolderImages.Add( &rBitmap, RGB( 255, 0, 255 ) );
	}


	m_bInitialised = true;

  
	return 0;
}


void
CInspectorBar::UpdateList()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	m_bFileCacheValid = false;
	UpdateFileCache();

	UpdateScrollRange();

	if( m_i32SelItem >= m_rFileCache.size() )
		m_i32SelItem = -1;

	Invalidate();
}


void CInspectorBar::OnPaint() 
{
	CPaintDC dc( this ); // device context for painting

	// start flicker free drawing
	CRect	rRect;
    CDC		rMemDC;
    CBitmap	rBitmap;

	GetClientRect( rRect );

	int32	i32VScrollSize = ::GetSystemMetrics( SM_CXVSCROLL );
	int32	i32HScrollSize = ::GetSystemMetrics( SM_CXHSCROLL );

	// create memory DC
    rMemDC.CreateCompatibleDC( &dc );
    rBitmap.CreateCompatibleBitmap( &dc, rRect.Width(), rRect.Height() );
    CBitmap* pOldBm = rMemDC.SelectObject( &rBitmap );

	// clear corner and bottom
	rMemDC.FillSolidRect( rRect.right - i32VScrollSize - 1, rRect.bottom - i32HScrollSize - 1 - g_i32ButtonRowSize, i32VScrollSize, i32HScrollSize, ::GetSysColor( COLOR_BTNFACE ) );
	rMemDC.FillSolidRect( rRect.left, rRect.bottom - g_i32ButtonRowSize, rRect.Width(), g_i32ButtonRowSize, ::GetSysColor( COLOR_BTNFACE ) );

	// draw out
	rMemDC.Draw3dRect( rRect.left, rRect.top, rRect.Width(), rRect.Height() - g_i32ButtonRowSize, ::GetSysColor( COLOR_3DSHADOW ), ::GetSysColor( COLOR_3DHILIGHT ) );


	// Draw header
	DrawHeader( &rMemDC );


	// save old clip region
	CRect	rOldRect;
	CRgn	rOldClipRgn;
	rMemDC.GetClipBox( rOldRect );
	rOldClipRgn.CreateRectRgnIndirect( rOldRect );

	// create new clip region
	CRgn	rRegion;
	rRegion.CreateRectRgnIndirect( m_rListRect );
	rMemDC.SelectClipRgn( &rRegion );


	// clear background
	rMemDC.FillSolidRect( m_rListRect, ::GetSysColor( COLOR_WINDOW ) );

	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );
	FileListC*		pFileList = pDoc->GetFileList();
	ASSERT( pFileList );



	if( m_bFileCacheValid )
		UpdateFileCache();

	uint32	i;

	CRect	rClipRect;

	int32	i32X = -m_i32ListOffsetX;
	int32	i32Y = -m_i32ListOffsetY;

	CDC*	pDC = &rMemDC;

	// set font attributes
	CFont*	pOldFont = pDC->SelectObject( &m_rFont );
	pDC->SetBkMode( TRANSPARENT );
	pDC->SetTextAlign( TA_LEFT | TA_TOP );
	CSize	rTextSize;
	rTextSize = pDC->GetTextExtent( "Xg" );

	CPen	rGreyPen( PS_SOLID, 1, ::GetSysColor( COLOR_BTNSHADOW ) );
	CPen	rLtGreyPen( PS_SOLID, 1, ::GetSysColor( COLOR_BTNHILIGHT ) );
	CPen	rHilightPen( PS_SOLID, 1, ::GetSysColor( COLOR_HIGHLIGHTTEXT ) );
	CPen*	pOldPen = pDC->SelectObject( &rGreyPen );

	pDC->SelectObject( &rLtGreyPen );


	int32	i32RealNameSize = m_i32NameSize + m_i32FileCacheMaxIndent * g_i32IndentWidth;

	// Draw list
	for( i = 0; i < m_rFileCache.size(); i++ ) {

		i32Y = m_rFileCache[i].m_i32Y - m_i32ListOffsetY + m_rListRect.top;
		i32X = -m_i32ListOffsetX;

		if( (i32Y + g_i32ItemHeight) < 0 )
			continue;
		if( i32Y > m_rListRect.bottom )
			break;


		int32	i32IndentX = m_rFileCache[i].m_i32Indent * g_i32IndentWidth;

		if( !m_rFileCache[i].m_bFolder || !m_rFileCache[i].m_bExpanded ) {
			pDC->SelectObject( &rLtGreyPen );
			int32	i32Left = m_rListRect.left + i32IndentX - i32X;
			if( i32Left < 0 ) i32Left = 0;
			pDC->MoveTo( m_rListRect.left + i32IndentX, i32Y + g_i32ItemHeight );
			pDC->LineTo( m_rListRect.right, i32Y + g_i32ItemHeight );
		}

		if( i == m_i32SelItem ) {
			pDC->FillSolidRect( m_rListRect.left, i32Y, m_rListRect.Width(), g_i32ItemHeight - 1, ::GetSysColor( COLOR_HIGHLIGHT ) );
			pDC->SetTextColor( ::GetSysColor( COLOR_HIGHLIGHTTEXT ) );
			pDC->SelectObject( &rHilightPen );
		}
		else {
			pDC->SetTextColor( ::GetSysColor( COLOR_BTNTEXT ) );
			pDC->SelectObject( &rLtGreyPen );
		}

		if( m_rFileCache[i].m_bFolder ) {
			if( m_rFileCache[i].m_bExpanded )
				m_rFileListImages.DrawIndirect( pDC, 0, CPoint( i32X + i32IndentX + 5, i32Y + 2 ), CSize( 12, 16 ), CPoint( 0, 0 ), ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );
			else
				m_rFileListImages.DrawIndirect( pDC, 1, CPoint( i32X + i32IndentX + 5, i32Y + 2 ), CSize( 12, 16 ), CPoint( 0, 0 ), ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );

			m_rFolderImages.DrawIndirect( pDC, m_rFileCache[i].m_i32Pic, CPoint( i32X + i32IndentX + g_i32ArrowWidth, i32Y + 2 ), CSize( 16, 15 ), CPoint( 0, 0 ), ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );
		}
		else {
			m_rFileTypeImages.DrawIndirect( pDC, m_rFileCache[i].m_i32Pic, CPoint( i32X + i32IndentX + g_i32ArrowWidth, i32Y + 2 ), CSize( 16, 15 ), CPoint( 0, 0 ), ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );
		}

		rClipRect.top = i32Y;
		rClipRect.bottom = i32Y + g_i32ItemHeight;

		rClipRect.left = m_rListRect.left - m_i32ListOffsetX;
		rClipRect.right = rClipRect.left + i32RealNameSize;
		pDC->ExtTextOut( i32X + i32IndentX + g_i32ImageWidth + g_i32ArrowWidth, i32Y + 1 + g_i32ItemHeight / 2 - rTextSize.cy / 2, ETO_CLIPPED, rClipRect, m_rFileCache[i].m_sName.c_str(), NULL );
		i32X += i32RealNameSize;

		if( !m_rFileCache[i].m_bFolder ) {

			pDC->MoveTo( i32X, i32Y + 2 * g_i32ItemHeight / 3 );
			pDC->LineTo( i32X, i32Y + g_i32ItemHeight - 1 );

			rClipRect.left = rClipRect.right;
			rClipRect.right = rClipRect.left + m_i32TypeSize;
			pDC->ExtTextOut( i32X + 5, i32Y + 1 + g_i32ItemHeight / 2 - rTextSize.cy / 2, ETO_CLIPPED, rClipRect, m_rFileCache[i].m_sType.c_str(), NULL );
			i32X += m_i32TypeSize;
			pDC->MoveTo( i32X, i32Y + 2 * g_i32ItemHeight / 3 );
			pDC->LineTo( i32X, i32Y + g_i32ItemHeight - 1 );
			
			rClipRect.left = rClipRect.right;
			rClipRect.right = rClipRect.left + m_i32RefSize;
			pDC->ExtTextOut( i32X + 5, i32Y + 1 + g_i32ItemHeight / 2 - rTextSize.cy / 2, ETO_CLIPPED, rClipRect, m_rFileCache[i].m_sRef.c_str(), NULL );
			i32X += m_i32RefSize;
			pDC->MoveTo( i32X, i32Y + 2 * g_i32ItemHeight / 3 );
			pDC->LineTo( i32X, i32Y + g_i32ItemHeight - 1 );
		
			rClipRect.left = rClipRect.right;
			rClipRect.right = rClipRect.left + m_i32InfoSize;
			pDC->ExtTextOut( i32X + 5, i32Y + 1 + g_i32ItemHeight / 2 - rTextSize.cy / 2, ETO_CLIPPED, rClipRect, m_rFileCache[i].m_sInfo.c_str(), NULL );
			i32X += m_i32InfoSize;
			pDC->MoveTo( i32X, i32Y + 2 * g_i32ItemHeight / 3 );
			pDC->LineTo( i32X, i32Y + g_i32ItemHeight - 1 );

			rClipRect.left = rClipRect.right;
			rClipRect.right = rClipRect.left + m_i32PathSize;
			pDC->ExtTextOut( i32X + 5, i32Y + 1 + g_i32ItemHeight / 2 - rTextSize.cy / 2, ETO_CLIPPED, rClipRect, m_rFileCache[i].m_sPath.c_str(), NULL );
		}
	}

	// select old objects
	pDC->SelectObject( pOldFont );
	pDC->SelectObject( pOldPen );


	// restore old clip region
	rMemDC.SelectClipRgn( &rOldClipRgn );
	rOldClipRgn.DeleteObject();
	rRegion.DeleteObject();

	// finish drawing
    dc.BitBlt( 0, 0, rRect.Width(), rRect.Height(), &rMemDC, 0, 0, SRCCOPY );
    ReleaseDC( &dc );
    rMemDC.SelectObject( pOldBm );
    rBitmap.DeleteObject();
    rMemDC.DeleteDC();
}

void CInspectorBar::DrawHeader( CDC* pDC )
{
	// save old clip region
	CRect	rOldRect;
	CRgn	rOldClipRgn;
	pDC->GetClipBox( rOldRect );
	rOldClipRgn.CreateRectRgnIndirect( rOldRect );

	// create new clip region
	CRgn	rRegion;
	rRegion.CreateRectRgnIndirect( m_rHeaderRect );
	pDC->SelectClipRgn( &rRegion );


	// set font attributes
	CFont*	pOldFont = pDC->SelectObject( &m_rSmallFont );
	pDC->SetBkMode( TRANSPARENT );

	// Clear BG
	pDC->FillSolidRect( m_rHeaderRect, ::GetSysColor( COLOR_BTNFACE ) );

	CRect	rClipRect = m_rHeaderRect;
	int32	i32Size = 0;

	rClipRect.left -= m_i32ListOffsetX;

	// name
	i32Size = m_i32NameSize + m_i32FileCacheMaxIndent * 20;
	rClipRect.right = rClipRect.left + i32Size;
	pDC->ExtTextOut( rClipRect.left + 3, m_rHeaderRect.bottom - 16, ETO_CLIPPED, rClipRect, "Name", NULL );
	pDC->Draw3dRect( rClipRect, ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) );
	rClipRect.left += i32Size;

	// type
	i32Size = m_i32TypeSize;
	rClipRect.right = rClipRect.left + i32Size;
	pDC->ExtTextOut( rClipRect.left + 3, m_rHeaderRect.bottom - 16, ETO_CLIPPED, rClipRect, "Type", NULL );
	pDC->Draw3dRect( rClipRect, ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) );
	rClipRect.left += i32Size;

	// ref
	i32Size = m_i32RefSize;
	rClipRect.right = rClipRect.left + i32Size;
	pDC->ExtTextOut( rClipRect.left + 3, m_rHeaderRect.bottom - 16, ETO_CLIPPED, rClipRect, "Ref", NULL );
	pDC->Draw3dRect( rClipRect, ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) );
	rClipRect.left += i32Size;

	// info
	i32Size = m_i32InfoSize;
	rClipRect.right = rClipRect.left + i32Size;
	pDC->ExtTextOut( rClipRect.left + 3, m_rHeaderRect.bottom - 16, ETO_CLIPPED, rClipRect, "Info", NULL );
	pDC->Draw3dRect( rClipRect, ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) );
	rClipRect.left += i32Size;

	// path
	i32Size = m_i32PathSize;
	rClipRect.right = rClipRect.left + i32Size;
	pDC->ExtTextOut( rClipRect.left + 3, m_rHeaderRect.bottom - 16, ETO_CLIPPED, rClipRect, "Path", NULL );
	pDC->Draw3dRect( rClipRect, ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) );
	rClipRect.left += i32Size;


	// restore old clip region
	pDC->SelectClipRgn( &rOldClipRgn );
	rOldClipRgn.DeleteObject();
	rRegion.DeleteObject();

	// select old objects
	pDC->SelectObject( pOldFont );
}


void CInspectorBar::UpdateFolder( FileHandleC* pRoot, int32 i32Indent )
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );
	FileListC*		pFileList = pDoc->GetFileList();
	ASSERT( pFileList );

	std::string	sStr;
	char		szRefCnt[256];
	char		szDrive[_MAX_DRIVE];
	char		szDir[_MAX_DIR];
	char		szFname[_MAX_FNAME];
	char		szExt[_MAX_EXT];

	if( i32Indent > m_i32FileCacheMaxIndent )
		m_i32FileCacheMaxIndent = i32Indent;


	std::vector<CacheItemS>	rLocalCache;


	for( uint32 i = 0; i < pFileList->get_file_count(); i++ ) {
		FileHandleC*	pHandle = pFileList->get_file( i );

		// Check that this file belongs in the parent folder
		if( pHandle->get_parent_handle() != pRoot )
			continue;

		if( pHandle->get_flags() & FILEHANDLE_FOLDER ) {

			CacheItemS	rItem;

			rItem.m_pHandle = pHandle;
			rItem.m_ui32FileIdx = i;
			rItem.m_i32Indent = i32Indent;
			rItem.m_i32Pic = FolderFlagToColor( pHandle->get_flags() ) * 2;
			if( pHandle->get_flags() & FILEHANDLE_FOLDER_EXPANDED ) {
				rItem.m_i32Pic++;
				rItem.m_bExpanded = true;
			}
			else
				rItem.m_bExpanded = false;
			rItem.m_sName = pHandle->get_folder_name();
			rItem.m_sType = "";
			rItem.m_sRef = "";
			rItem.m_sInfo = "";
			rItem.m_sPath = "";
			rItem.m_bFolder = true;

			rLocalCache.push_back( rItem );

//			if( pHandle->get_flags() & FILEHANDLE_FOLDER_EXPANDED )
//				UpdateFolder( pHandle, i32Indent + 1 );
			continue;
		}

		ImportableI*	pImp = pHandle->get_importable();

		if( !pImp )
			continue;

		CacheItemS	rItem;

		rItem.m_pHandle = pHandle;
		rItem.m_ui32FileIdx = i;
		rItem.m_i32Indent = i32Indent;

		rItem.m_i32Pic = 1;
		if( pImp->get_super_class_id() == SUPERCLASS_IMAGE )
			rItem.m_i32Pic = 5;
	
		if( pImp->get_class_id() == CLASS_SUBSCENE_IMPORTABLE )
			rItem.m_i32Pic = 0;
		else if( pImp->get_class_id() == CLASS_SHAREDBUFFER_IMPORTABLE )
			rItem.m_i32Pic = 7;

		_splitpath( pImp->get_filename(), szDrive, szDir, szFname, szExt );

		// name
		sStr = szFname;
		sStr += szExt;
		rItem.m_sName = sStr;

		// type
		rItem.m_sType = pImp->get_class_name();

		// ref count
		_snprintf( szRefCnt, 255, "%d", pFileList->get_file( i )->get_reference_count() );
		rItem.m_sRef = szRefCnt;

		// info
		rItem.m_sInfo = pImp->get_info();

		// path
		sStr = szDrive;
		sStr += szDir;
		rItem.m_sPath = sStr;

		rItem.m_bFolder = false;

		rLocalCache.push_back( rItem );
	}

	std::sort( rLocalCache.begin(), rLocalCache.end() );

	for( i = 0; i < rLocalCache.size(); i++ ) {
		m_rFileCache.push_back( rLocalCache[i] );
		if( rLocalCache[i].m_bFolder && rLocalCache[i].m_bExpanded )
			UpdateFolder( rLocalCache[i].m_pHandle, i32Indent + 1 );
	}
}



void CInspectorBar::UpdateFileCache()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );
	FileListC*		pFileList = pDoc->GetFileList();
	ASSERT( pFileList );

	m_rFileCache.clear();
	int32	i32Y = 0;

	m_i32FileCacheMaxIndent = 0;

	// update root folder
	UpdateFolder( 0, 0 );

//	std::sort( m_rFileCache.begin(), m_rFileCache.end() );

	for( uint32 i = 0; i < m_rFileCache.size(); i++ ) {
		m_rFileCache[i].m_i32Y = i32Y;
		i32Y += g_i32ItemHeight;
	}

	m_i32FileCacheMaxHeight = i32Y;
	m_bFileCacheValid = true;
}

BOOL CInspectorBar::OnEraseBkgnd(CDC* pDC) 
{
	return FALSE;
}

void CInspectorBar::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	if( pScrollBar->GetDlgCtrlID() != IDC_FILEINSPECTOR_HSCROLL ) {
		baseCMyBar::OnHScroll(nSBCode, nPos, pScrollBar);
		return;
	}

	m_i32ListOffsetX = pScrollBar->GetScrollPos();

	SCROLLINFO	rScrollInfo;
	pScrollBar->GetScrollInfo( &rScrollInfo );

	switch ( nSBCode )	{
	case SB_LINEUP:
		m_i32ListOffsetX -= 5;
		break;
	case SB_LINEDOWN:
		m_i32ListOffsetX += 5;
		break;
	case SB_PAGEUP:
		m_i32ListOffsetX -= rScrollInfo.nPage;
		break;
	case SB_PAGEDOWN:
		m_i32ListOffsetX += rScrollInfo.nPage;
		break;
	case SB_TOP:
		m_i32ListOffsetX = rScrollInfo.nMin;
		break;
	case SB_BOTTOM:
		m_i32ListOffsetX = rScrollInfo.nMax;
		break;		
	case SB_THUMBTRACK:
	case SB_THUMBPOSITION:
		m_i32ListOffsetX = nPos;
		break;
	default:
		return;
	}

	if( m_i32ListOffsetX < rScrollInfo.nMin )
		m_i32ListOffsetX = rScrollInfo.nMin;
	if( m_i32ListOffsetX > rScrollInfo.nMax )
		m_i32ListOffsetX = rScrollInfo.nMax;

	pScrollBar->SetScrollPos( m_i32ListOffsetX, TRUE );

	// redraw
	Invalidate( FALSE );	
}

void CInspectorBar::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	if( pScrollBar->GetDlgCtrlID() != IDC_FILEINSPECTOR_VSCROLL ) {
		baseCMyBar::OnVScroll(nSBCode, nPos, pScrollBar);
		return;
	}

	m_i32ListOffsetY = pScrollBar->GetScrollPos();

	SCROLLINFO	rScrollInfo;
	pScrollBar->GetScrollInfo( &rScrollInfo );

	switch ( nSBCode )	{
	case SB_LINEUP:
		m_i32ListOffsetY -= g_i32ItemHeight;
		break;
	case SB_LINEDOWN:
		m_i32ListOffsetY += g_i32ItemHeight;
		break;
	case SB_PAGEUP:
		m_i32ListOffsetY -= rScrollInfo.nPage;
		break;
	case SB_PAGEDOWN:
		m_i32ListOffsetY += rScrollInfo.nPage;
		break;
	case SB_TOP:
		m_i32ListOffsetY = rScrollInfo.nMin;
		break;
	case SB_BOTTOM:
		m_i32ListOffsetY = rScrollInfo.nMax;
		break;		
	case SB_THUMBTRACK:
	case SB_THUMBPOSITION:
		m_i32ListOffsetY = nPos;
		break;
	default:
		return;
	}

	if( m_i32ListOffsetY < rScrollInfo.nMin )
		m_i32ListOffsetY = rScrollInfo.nMin;
	if( m_i32ListOffsetY > rScrollInfo.nMax )
		m_i32ListOffsetY = rScrollInfo.nMax;

	pScrollBar->SetScrollPos( m_i32ListOffsetY, TRUE );

	// redraw
	Invalidate( FALSE );	
}

void CInspectorBar::UpdateScrollRange( bool bUpdatePos )
{
	// update scroll ranges
	if( !m_bFileCacheValid )
		UpdateFileCache();

	bool		bRedraw = false;
	SCROLLINFO	rScrollInfo;
	rScrollInfo.cbSize = sizeof( SCROLLINFO );

	rScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
	rScrollInfo.nMin = 0;
	rScrollInfo.nMax = m_i32FileCacheMaxHeight + 32;
	rScrollInfo.nPage = m_rListRect.Height();
	rScrollInfo.nPos = 0;
	rScrollInfo.nTrackPos = 0;
	m_rListScrollVert.SetScrollInfo( &rScrollInfo );

	if( bUpdatePos && m_rListScrollVert.GetScrollPos() != m_i32ListOffsetY ) {
		m_i32ListOffsetY = m_rListScrollVert.GetScrollPos();
		bRedraw = true;
	}

	int32	i32MaxWidth = m_i32NameSize + m_i32FileCacheMaxIndent * 20 + m_i32TypeSize + m_i32RefSize + m_i32InfoSize + m_i32PathSize;

	rScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
	rScrollInfo.nMin = 0;
	rScrollInfo.nMax = i32MaxWidth;
	rScrollInfo.nPage = m_rHeaderRect.Width();
	rScrollInfo.nPos = 0;
	rScrollInfo.nTrackPos = 0;
	m_rListScrollHoriz.SetScrollInfo( &rScrollInfo );

	if( bUpdatePos && m_rListScrollHoriz.GetScrollPos() != m_i32ListOffsetX ) {
		m_i32ListOffsetX = m_rListScrollHoriz.GetScrollPos();
		bRedraw = true;
	}

	if( bRedraw )
		Invalidate( FALSE );
}

int32 CInspectorBar::HitTestItem( CPoint rPt, int32& i32HitItem )
{
	if( !m_bFileCacheValid )
		UpdateFileCache();

	rPt.y -= m_rListRect.top;
	rPt.x -= m_rListRect.left;

	rPt.x += m_i32ListOffsetX;
	rPt.y += m_i32ListOffsetY;

	for( uint32 i = 0; i < m_rFileCache.size(); i++ ) {
		if( rPt.y >= m_rFileCache[i].m_i32Y && rPt.y < (m_rFileCache[i].m_i32Y + g_i32ItemHeight) ) {
			if( rPt.x >= m_rFileCache[i].m_i32Indent * g_i32IndentWidth ) {
				i32HitItem = i;
				if( rPt.x < (m_rFileCache[i].m_i32Indent * g_i32IndentWidth + g_i32ArrowWidth) )
					return HITTEST_ARROW;
				return HITTEST_ITEM;
			}
		}
	}

	i32HitItem = -1;
	return HITTEST_NONE;
}

int32 CInspectorBar::HitTestHeader( CPoint rPt )
{
	if( !m_rHeaderRect.PtInRect( rPt ) )
		return HEADER_TRACK_NONE;

	int32	i32X = rPt.x - m_rHeaderRect.left + m_i32ListOffsetX;

	int32	i32Border = 0;
	
	i32Border += m_i32NameSize + m_i32FileCacheMaxIndent * 20;
	if( i32X >= (i32Border - 3) && i32X < (i32Border + 3) )
		return HEADER_TRACK_NAME;

	i32Border += m_i32TypeSize;
	if( i32X >= (i32Border - 3) && i32X < (i32Border + 3) )
		return HEADER_TRACK_TYPE;

	i32Border += m_i32RefSize;
	if( i32X >= (i32Border - 3) && i32X < (i32Border + 3) )
		return HEADER_TRACK_REF;

	i32Border += m_i32InfoSize;
	if( i32X >= (i32Border - 3) && i32X < (i32Border + 3) )
		return HEADER_TRACK_INFO;

	i32Border += m_i32PathSize;
	if( i32X >= (i32Border - 3) && i32X < (i32Border + 3) )
		return HEADER_TRACK_PATH;

	return HEADER_TRACK_NONE;
}

void CInspectorBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if( HandleLButtonDown( point ) )
		return;

	baseCMyBar::OnLButtonDown(nFlags, point);
}

void CInspectorBar::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	if( HandleLButtonDown( point, true ) )
		return;

	baseCMyBar::OnLButtonDblClk(nFlags, point);
}

void CInspectorBar::OnMouseMove(UINT nFlags, CPoint point) 
{
	if( m_i32HeaderTrack != HEADER_TRACK_NONE ) {

		int32	i32DeltaX = point.x - m_rOrigPt.x;
		int32	i32Size = m_i32HeaderOrigSize + i32DeltaX;
		if( i32Size < 30 )
			i32Size = 30;
		if( i32Size > 10000 )
			i32Size = 10000;

		switch( m_i32HeaderTrack ) {
		case HEADER_TRACK_NAME:
			m_i32NameSize = i32Size;
			break;
		case HEADER_TRACK_TYPE:
			m_i32TypeSize = i32Size;
			break;
		case HEADER_TRACK_REF:
			m_i32RefSize = i32Size;
			break;
		case HEADER_TRACK_INFO:
			m_i32InfoSize = i32Size;
			break;
		case HEADER_TRACK_PATH:
			m_i32PathSize = i32Size;
			break;
		}

		UpdateScrollRange( false );

		Invalidate( FALSE );
	}

	if( m_i32ListTrack == LIST_TRACK_ITEM ) {
		OnItemDrag();
		m_i32ListTrack = LIST_TRACK_NONE;
	}

	if( HitTestHeader( point ) != HEADER_TRACK_NONE ) {
		m_hCursor = AfxGetApp()->LoadCursor( IDC_SIZEX );
	}
	else {
		m_hCursor = 0;
	}
	
	baseCMyBar::OnMouseMove(nFlags, point);
}

void CInspectorBar::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if( GetCapture() == this )
		ReleaseCapture();

	if( m_i32HeaderTrack ) {
		UpdateScrollRange();
		m_i32HeaderTrack = HEADER_TRACK_NONE;	
	}

	baseCMyBar::OnLButtonUp(nFlags, point);
}

BOOL CInspectorBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	if( m_hCursor ) {
		::SetCursor( m_hCursor );
		return TRUE;
	}
	return baseCMyBar::OnSetCursor(pWnd, nHitTest, message);
}


void CInspectorBar::OnItemDrag()
{
	if( m_i32SelItem >= 0 && m_i32SelItem < (int32)m_rFileCache.size() ) {

		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT( pDoc );

		// Make sure the imporatable exists (i.e. prevent dragging folders).
		FileListC*		pFileList = pDoc->GetFileList();
		FileHandleC*	pHandle = pFileList->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		ImportableI*	pImp = pHandle->get_importable();
		if( !pImp && !(pHandle->get_flags() & FILEHANDLE_FOLDER) )
			return;
		
		COleDataSource*	pDataSrc = new COleDataSource;

		HGLOBAL	hMem = ::GlobalAlloc( GPTR, sizeof( int32 ) );
		if( hMem == NULL ) {
			TRACE( "GlobalAlloc failed\n" );
			return;
		}

		int32*	pNum = (int32*)::GlobalLock( hMem );
		*pNum = m_rFileCache[m_i32SelItem].m_ui32FileIdx;
		::GlobalUnlock( hMem );

		pDataSrc->CacheGlobalData( pDoc->GetPrivateClipboardFormat(), hMem );

		DROPEFFECT	rDrop = pDataSrc->DoDragDrop( DROPEFFECT_COPY | DROPEFFECT_MOVE, NULL );

		delete pDataSrc;
	}
}

void CInspectorBar::OnRButtonDown(UINT nFlags, CPoint point) 
{
	if( HandleRButtonDown( point ) )
		return;
	
	baseCMyBar::OnRButtonDown(nFlags, point);
}

void CInspectorBar::OnRButtonDblClk(UINT nFlags, CPoint point) 
{
	if( HandleRButtonDown( point ) )
		return;
	
	baseCMyBar::OnRButtonDblClk(nFlags, point);
}


bool CInspectorBar::FillProceduralMenu( CFlatPopupMenu& rMenu )
{
	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();
	FactoryC*		pFactory = pApp->GetFactory();

	int32	i32ProcCount = 0;

	for( uint32 i = 0; i < pFactory->get_classdesc_count(); i++ ) {
		ClassDescC*	pDesc = pFactory->get_classdesc( i );
		if( pDesc->get_classtype() == CLASS_TYPE_FILEPROCEDURAL ) {
			rMenu.AppendItem( 0, pDesc->get_name(), 0x80000000 | i );
			i32ProcCount++;
		}
	}

	return i32ProcCount ? true : false;
}

bool CInspectorBar::HandleRButtonDown( CPoint point )
{
	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();
	FactoryC*		pFactory = pApp->GetFactory();

	if( m_rListRect.PtInRect( point ) ) {
		int32	i32Hit = HitTestItem( point, m_i32SelItem );
		Invalidate( FALSE );

		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT( pDoc );

		CFlatPopupMenu	rMenu;
		CFlatPopupMenu	rCreateMenu;

		rMenu.SetFont( "Arial" );
		rMenu.SetFontSize( 8 );
		rMenu.Create( AfxGetInstanceHandle(), IDB_FILELISTRIGHT );

		rCreateMenu.SetFont( "Arial" );
		rCreateMenu.SetFontSize( 8 );
		rCreateMenu.Create( AfxGetInstanceHandle(), IDB_FILELISTRIGHT );

		int32	i32ItemFlags = 0;
		int32	i32ItemReFlags = 0;
		int32	i32ItemSubFlags = 0;
		int32	i32CreateFlags = 0;

		FileHandleC*	pFolderHandle = 0;

		if( !FillProceduralMenu( rCreateMenu ) )
			i32CreateFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;

		// disable some features, if we didnt hit a item
		if( m_i32SelItem == -1 ) {
			i32ItemFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;
			i32ItemReFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;
			i32ItemSubFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;
		}
		else {
			FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
			if( pHandle ) {
				ImportableI*	pImp = pHandle->get_importable();

				if( pHandle->get_flags() & FILEHANDLE_FOLDER ) {
					pFolderHandle = pHandle;
					// disable help
					i32ItemFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;
					i32ItemReFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;
				}
				else if( pImp ) {
					if( !pImp->has_properties() )
						i32ItemSubFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;

					ClassDescC*	pDesc = pFactory->get_classdesc( pImp->get_class_id() );
					if( pDesc->get_classtype() == CLASS_TYPE_FILEPROCEDURAL )
						i32ItemReFlags = CFlatPopupMenu::itemGrayed | CFlatPopupMenu::itemNotSelectable;
				}
			}
		}

		rMenu.AppendItem( 0, "Import...", 1, 0 );
		rMenu.AppendPopup( i32CreateFlags, "Create", rCreateMenu, 4 );
		rMenu.AppendItem( 0, "Create Scene", 7, 5 );
		rMenu.AppendItem( 0, "Create Folder", 9, 7 );
		rMenu.AppendItem( 0, "Delete", 2, 1 );
		rMenu.AppendItem( CFlatPopupMenu::itemSeparator, NULL, 0 );
		rMenu.AppendItem( i32ItemReFlags, "Replace With...", 3, 2 );
		rMenu.AppendItem( i32ItemReFlags, "Reload", 4, 3 );
		rMenu.AppendItem( CFlatPopupMenu::itemSeparator, NULL, 0 );
		rMenu.AppendItem( i32ItemFlags, "Help...", 5 );
		rMenu.AppendItem( CFlatPopupMenu::itemSeparator, NULL, 0 );
		rMenu.AppendItem( i32ItemSubFlags, "Properties...", 6 );

		CPoint	rPt;
		::GetCursorPos( &rPt );

		int32	i32Id = rMenu.Track( rPt.x, rPt.y, NULL, true );

		if( i32Id == 1 ) {
			// import
			pDoc->ImportFile( pFolderHandle );
			pDoc->UpdateFileReferences();
			// update other views too
			pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
		}
		else if( i32Id == 2 ) {
			// delete
			DeleteSelected();
		}
		else if( i32Id == 3 ) {
			// replace with...
			if( m_i32SelItem != -1 ) {
				pDoc->ReplaceFile( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
				pDoc->UpdateFileReferences();
				UpdateList();
				// update other views too
				pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
			}
		}
		else if( i32Id == 4 ) {
			// reload
			if( m_i32SelItem != -1 ) {
				pDoc->ReloadFile( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
				pDoc->UpdateFileReferences();
				UpdateList();
				// update other views too
				pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
			}
		}
		else if( i32Id == 5 ) {
			// Help...
			if( m_i32SelItem != -1 ) {
				FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
				CMainFrame*		pMain = (CMainFrame*)AfxGetMainWnd();
				ImportableI*	pImp = pHandle->get_importable();

				if( pImp && pMain )
					pMain->BrowseHelp( pImp->get_class_id() );
			}
		}
		else if( i32Id == 6 ) {
			// Properties...
			if( m_i32SelItem != -1 ) {
				FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
				if( pHandle->get_flags() & FILEHANDLE_FOLDER ) {
					CFolderPropertiesDlg	rDlg;
					rDlg.m_sName = pHandle->get_folder_name();
					rDlg.m_iColor = FolderFlagToColor( pHandle->get_flags() );
					
					if( rDlg.DoModal() == IDOK ) {
						pDoc->RenameFolder( m_rFileCache[m_i32SelItem].m_ui32FileIdx, rDlg.m_sName, ColorToFolderFlag( rDlg.m_iColor ) );
					}
				}
				else {
					pDoc->PromptFileProperties( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
					pDoc->UpdateFileReferences();
				}
				UpdateList();
				// update other views too
				pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
			}
		}
		else if( i32Id == 7 ) {
			// create scene
			pDoc->CreateScene( pFolderHandle );
			pDoc->UpdateFileReferences();
			// update other views too
			pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
		}
		else if( i32Id == 9 ) {
			// Create folder
			CFolderPropertiesDlg	rDlg;
			rDlg.m_sName = "New Folder";
			rDlg.m_iColor = 0;
			if( rDlg.DoModal() == IDOK ) {
				pDoc->CreateFolder( rDlg.m_sName, pFolderHandle, ColorToFolderFlag( rDlg.m_iColor ) );
				UpdateList();
				// update other views too
				pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
			}
		}
		else if( (i32Id & 0x80000000) ) {
			int32	i32Idx = i32Id & 0x7fffffff;
			ClassDescC*	pDesc = pFactory->get_classdesc( i32Idx );
			if( pDesc )
				pDoc->CreateFile( pDesc->get_class_id(), pFolderHandle );
			UpdateList();
			// update other views too
			pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
		}

		return true;
	}

	return false;
}

bool CInspectorBar::HandleLButtonDown( CPoint point, bool bDblClick )
{
	if( m_rHeaderRect.PtInRect( point ) ) {

		m_i32HeaderTrack = HitTestHeader( point );
		
		switch( m_i32HeaderTrack ) {
		case HEADER_TRACK_NAME:
			m_i32HeaderOrigSize = m_i32NameSize;
			break;
		case HEADER_TRACK_TYPE:
			m_i32HeaderOrigSize = m_i32TypeSize;
			break;
		case HEADER_TRACK_REF:
			m_i32HeaderOrigSize = m_i32RefSize;
			break;
		case HEADER_TRACK_INFO:
			m_i32HeaderOrigSize = m_i32InfoSize;
			break;
		case HEADER_TRACK_PATH:
			m_i32HeaderOrigSize = m_i32PathSize;
			break;
		}
		m_rOrigPt = point;

		if( m_i32HeaderTrack != HEADER_TRACK_NONE )
			SetCapture();

		return true;
	}
	else if( m_rListRect.PtInRect( point ) ) {
		int32	i32Hit = HitTestItem( point, m_i32SelItem );
		Invalidate( FALSE );

		// expand folders, if arrwo pressed
		if( i32Hit == HITTEST_ARROW ) {
			CDemopajaDoc*	pDoc = GetDoc();
			ASSERT( pDoc );
			// Check out if a folder is selected, otherwise choose filder from selected file.
			FileHandleC*	pFolderHandle = 0;
			if( m_i32SelItem != -1 ) {
				FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
				if( pHandle ) {
					ImportableI*	pImp = pHandle->get_importable();
					if( pHandle->get_flags() & FILEHANDLE_FOLDER )
						pFolderHandle = pHandle;
				}
			}

			if( pFolderHandle ) {
				pFolderHandle->toggle_flags( FILEHANDLE_FOLDER_EXPANDED );
				UpdateList();
			}
		}
		else {
			// expand folders on double click
			if( bDblClick ) {
				CDemopajaDoc*	pDoc = GetDoc();
				ASSERT( pDoc );
				// Check out if a folder is selected, otherwise choose filder from selected file.
				FileHandleC*	pFolderHandle = 0;
				if( m_i32SelItem != -1 ) {
					FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
					if( pHandle ) {
						ImportableI*	pImp = pHandle->get_importable();
						if( pHandle->get_flags() & FILEHANDLE_FOLDER )
							pFolderHandle = pHandle;
					}
				}

				if( pFolderHandle ) {
					pFolderHandle->toggle_flags( FILEHANDLE_FOLDER_EXPANDED );
					UpdateList();
				}
			}
			else {
				if( m_i32SelItem != -1 )
					m_i32ListTrack = LIST_TRACK_ITEM;
				else
					m_i32ListTrack = LIST_TRACK_NONE;
			}
		}

		return true;
	}

	return false;
}

void CInspectorBar::OnImportFile()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	// Check out if a folder is selected, otherwise choose filder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( m_i32SelItem != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	// import
	pDoc->ImportFile( pFolderHandle );
	pDoc->UpdateFileReferences();
	UpdateList();
}

void CInspectorBar::OnCreateFile()
{

	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();
	FactoryC*		pFactory = pApp->GetFactory();
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	CFlatPopupMenu	rCreateMenu;

	rCreateMenu.SetFont( "Arial" );
	rCreateMenu.SetFontSize( 8 );
	rCreateMenu.Create( AfxGetInstanceHandle(), IDB_FILELISTRIGHT );

	if( !FillProceduralMenu( rCreateMenu ) ) {
		MessageBox( "No Procedural files to create.", "File Create Error", MB_ICONERROR | MB_OK );
		return;
	}

	// Check out if a folder is selected, otherwise choose filder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( m_i32SelItem != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	CRect	rRect;
	m_rCreateButton.GetWindowRect( rRect );

	int32	i32Id = rCreateMenu.Track( rRect.left, rRect.bottom, NULL, true );

	if( (i32Id & 0x80000000) ) {
		int32	i32Idx = i32Id & 0x7fffffff;
		ClassDescC*	pDesc = pFactory->get_classdesc( i32Idx );
		if( pDesc )
			pDoc->CreateFile( pDesc->get_class_id(), pFolderHandle );
		UpdateList();
		// update other views too
		pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
	}
}

void CInspectorBar::OnCreateFolder()
{
	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();
	FactoryC*		pFactory = pApp->GetFactory();
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	// Check out if a folder is selected, otherwise choose filder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( m_i32SelItem != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	CFolderPropertiesDlg	rDlg;

	rDlg.m_sName = "New Folder";
	rDlg.m_iColor = 0;
	if( rDlg.DoModal() == IDOK ) {
		pDoc->CreateFolder( rDlg.m_sName, pFolderHandle, ColorToFolderFlag( rDlg.m_iColor ) );
		UpdateList();
		// update other views too
		pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
	}
}

void CInspectorBar::OnCreateScene()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	// Check out if a folder is selected, otherwise choose filder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( m_i32SelItem != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	// create scene
	pDoc->CreateScene( pFolderHandle );
	pDoc->UpdateFileReferences();
	UpdateList();
}

void CInspectorBar::OnDeleteFile()
{
	DeleteSelected();
}

void CInspectorBar::DeleteSelected()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	// delete
	if( m_i32SelItem != -1 ) {
		pDoc->DeleteFile( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		pDoc->UpdateFileReferences();
		// update other views too
		pDoc->NotifyViews( NOTIFY_REDRAW_ALL );
	}
}

FileHandleC*
CInspectorBar::GetCurrentFolderHandle() const
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	// Check out if a folder is selected, otherwise choose filder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( m_i32SelItem != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[m_i32SelItem].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	return pFolderHandle;
}

DROPEFFECT
CInspectorBar::OnDragOver( COleDataObject* pDataObject, DWORD dwKeyState, CPoint point )
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	if( !pDataObject->IsDataAvailable( CDemopajaDoc::GetPrivateClipboardFormat() ) )
		return DROPEFFECT_NONE;

	if( !m_rListRect.PtInRect( point ) )
		return DROPEFFECT_NONE;

	// handle automatic scrolling
	if( point.y < m_rListRect.top + 10 ) {
		if( !m_ui32TimerID )
			m_ui32TimerID = SetTimer( TIMER_SCROLL_UP_INIT, 250, NULL );
	}
	else if( point.y > m_rListRect.bottom - 10 ) {
		if( !m_ui32TimerID )
			m_ui32TimerID = SetTimer( TIMER_SCROLL_DOWN_INIT, 250, NULL );
	}
	else {
		if( m_ui32TimerID ) {
			KillTimer( m_ui32TimerID );
			m_ui32TimerID = 0;
		}
	}


	int32	i32Item = -1;
	int32	i32Hit = HitTestItem( point, i32Item );

	HGLOBAL hMem = pDataObject->GetGlobalData( CDemopajaDoc::GetPrivateClipboardFormat() );
	int32*	pMem = (int32*)::GlobalLock( hMem );
	if( !pMem ) {
		TRACE_LAST_ERROR( "CInspectorBar::OnDragOver" );
		return FALSE;
	}
	int32	i32Num = *pMem;
	::GlobalUnlock( hMem );

	FileHandleC*	pHandle = pDoc->GetFileList()->get_file( i32Num );

	// Check out if a folder is selected, otherwise choose filder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( i32Item != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[i32Item].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	if( pFolderHandle == pHandle ) {
		m_i32SelItem = -1;
		InvalidateRect( m_rListRect, TRUE );
		return DROPEFFECT_NONE;
	}

	m_i32SelItem = -1;
	for( uint32 i = 0; i < m_rFileCache.size(); i++ ) {
		if( m_rFileCache[i].m_pHandle == pFolderHandle ) {
			m_i32SelItem = i;
			break;
		}
	}
	InvalidateRect( m_rListRect, TRUE );
	return DROPEFFECT_COPY;
}

BOOL
CInspectorBar::OnDrop( COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point )
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT( pDoc );

	if( !pDataObject->IsDataAvailable( CDemopajaDoc::GetPrivateClipboardFormat() ) )
		return FALSE;

	if( !m_rListRect.PtInRect( point ) )
		return FALSE;

	HGLOBAL hMem = pDataObject->GetGlobalData( CDemopajaDoc::GetPrivateClipboardFormat() );
	int32*	pMem = (int32*)::GlobalLock( hMem );
	if( !pMem ) {
		TRACE_LAST_ERROR( "CInspectorBar::OnDrop" );
		return FALSE;
	}
	int32	i32Num = *pMem;
	::GlobalUnlock( hMem );

	int32	i32Item = -1;
	int32	i32Hit = HitTestItem( point, i32Item );

	// Check out if a folder is selected, otherwise choose folder from selected file.
	FileHandleC*	pFolderHandle = 0;
	if( i32Item != -1 ) {
		FileHandleC*	pHandle = pDoc->GetFileList()->get_file( m_rFileCache[i32Item].m_ui32FileIdx );
		if( pHandle ) {
			ImportableI*	pImp = pHandle->get_importable();
			if( pHandle->get_flags() & FILEHANDLE_FOLDER )
				pFolderHandle = pHandle;
			else
				pFolderHandle = pHandle->get_parent_handle();
		}
	}

	FileHandleC*	pHandle = pDoc->GetFileList()->get_file( i32Num );

	if( pFolderHandle == pHandle ) {
		InvalidateRect( m_rListRect, TRUE );
		return TRUE;
	}

	if( pHandle ) {

		pDoc->MoveFileOrder( i32Num, pFolderHandle );

		UpdateFileCache();

		// Select dropped file
		m_i32SelItem = -1;
		for( uint32 i = 0; i < m_rFileCache.size(); i++ ) {
			if( m_rFileCache[i].m_pHandle == pHandle ) {
				m_i32SelItem = i;
				break;
			}
		}
	}

	InvalidateRect( m_rListRect, TRUE );

	return TRUE;
}

void CInspectorBar::OnDestroy() 
{
	m_rDropTarget.Revoke();
	baseCMyBar::OnDestroy();
}

void CInspectorBar::OnTimer( UINT nIDEvent )
{
	CPoint	rPt;
	::GetCursorPos( &rPt );
	ScreenToClient( &rPt );
	if( m_rListRect.PtInRect( rPt ) ) {
		if( nIDEvent == TIMER_SCROLL_UP_INIT ) {
			KillTimer( m_ui32TimerID );
			m_ui32TimerID = SetTimer( TIMER_SCROLL_UP, 50, NULL );
		}
		else if( nIDEvent == TIMER_SCROLL_DOWN_INIT ) {
			KillTimer( m_ui32TimerID );
			m_ui32TimerID = SetTimer( TIMER_SCROLL_DOWN, 50, NULL );
		}
		else if( nIDEvent == TIMER_SCROLL_UP ) {
			m_i32ListOffsetY -= 4;
			if( m_i32ListOffsetY < 0 )
				m_i32ListOffsetY = 0;
		}
		else if( nIDEvent == TIMER_SCROLL_DOWN ) {
			m_i32ListOffsetY += 4;
			if( m_i32ListOffsetY > (m_i32FileCacheMaxHeight + 32 - m_rListRect.Height()) )
				m_i32ListOffsetY = m_i32FileCacheMaxHeight + 32 - m_rListRect.Height();
		}

		m_rListScrollVert.SetScrollPos( m_i32ListOffsetY, TRUE );
	}
	else {
		KillTimer( m_ui32TimerID );
		m_ui32TimerID = 0;
	}

	Invalidate();
	
	baseCMyBar::OnTimer(nIDEvent);
}

void CInspectorBar::UpdateNotify( uint32 ui32Notify )
{
	if( ui32Notify == NOTIFY_REDRAW_GRAPHICS ) {
		// nothing
	}
	else if( ui32Notify == NOTIFY_REDRAW_ALL ) {
		UpdateList();
		Invalidate();
	}
	else if( ui32Notify == NOTIFY_RESET_VIEWS ) {
		UpdateList();
		Invalidate();
	}
	else if( ui32Notify == NOTIFY_FILELIST_CHANGED ) {
		UpdateList();
	}
	else if( ui32Notify == NOTIFY_LAYERLIST_CHANGED ) {
		// nothing
	}
}
