// DynDialog.cpp : implementation file
//

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

#include "stdafx.h"
#include "demopaja.h"
#include "DemopajaDoc.h"
#include "DynDialog.h"

#include "ParamI.h"
#include "PajaTypes.h"
#include "SpinnerButton.h"
#include "Vector2C.h"
#include "Vector3C.h"
#include "UndoC.h"
#include "FileListC.h"
#include "ImportableI.h"
#include "ColorTypeInDlg.h"
#include "ColorButton.h"
#include "FlatPopupMenu.h"
#include "EffectI.h"
#include "LayerC.h"
#include "TimeSegmentC.h"

#include <vector>
#include <string>

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


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


//uint32	CDynDialog::m_nextFreeId = WM_USER;

CDynDialog::CDynDialog(CWnd* pParent /*=NULL*/)
	: CDialog()
{
	//{{AFX_DATA_INIT(CDynDialog)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
//	m_bUpdating = false;
	m_i32CurY = 0;
	m_i32HitItem = -1;
	m_i32HitSubItem = -1;
	m_i32EditingItem = -1;
	m_i32EditingSubItem = -1;
	m_pEditCtrl = 0;
	m_i32TimerCount = 0;
	m_uiTimerID = 0;
	m_bUpdating = false;
	m_pTimerItem = 0;
	m_pHitItem = 0;
	m_pEditingItem = 0;
	m_ui32RedrawFlags = 0;
}


void CDynDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDynDialog)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CDynDialog, CDialog)
	//{{AFX_MSG_MAP(CDynDialog)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
	ON_EN_KILLFOCUS( IDC_EDITLABEL, OnKillfocusEditLabel )
	ON_EN_CHANGE( IDC_EDITLABEL, OnChangeEditLabel )
	ON_WM_TIMER()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDynDialog message handlers


#define		PADDING				3			// vertical padding
#define		COMP_SPACING		3			// spacing between parameter components
#define		PARAM_SPACING		5			// spacing between parameters
#define		LEFT_INDENT			20			// left indentation
#define		EDIT_HEIGHT			18			// height of normal edit row
#define		MAX_EDIT_WIDTH		75			// maximum editbox size
#define		COLORPICKER_WIDTH	40			// size of color picker
#define		LABEL_WIDTH			10			// width of labels. component (x, y, z) or quantity (%,..)
#define		SPINNER_WIDTH		((EDIT_HEIGHT * 4) / 5)	// size of the spinner button
#define		COMBO_WIDTH			((EDIT_HEIGHT * 4) / 5)	// size of the spinner button

/*
#define		INT_EDIT		0
#define		INT_SPIN		1
#define		INT_COMBO		0
#define		INT_RADIO0		0
#define		INT_CHECK0		0

#define		FLOAT_EDIT		0
#define		FLOAT_SPIN		1

#define		VECTOR2_EDITX	0
#define		VECTOR2_SPINX	1
#define		VECTOR2_EDITY	2
#define		VECTOR2_SPINY	3

#define		VECTOR3_EDITX	0
#define		VECTOR3_SPINX	1
#define		VECTOR3_EDITY	2
#define		VECTOR3_SPINY	3
#define		VECTOR3_EDITZ	4
#define		VECTOR3_SPINZ	5

#define		COLOR_BUTTON	0

#define		TEXT_EDIT		0

#define		FILE_COMBO		0
*/


BOOL
CDynDialog::OnInitDialog() 
{
	CDialog::OnInitDialog();

	// Create two fonts

	if( !m_rBoldFont.CreateFont( 14, 0, 0, 0, FW_BOLD, 0, 0, 0,
		ANSI_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		DEFAULT_PITCH | FF_DONTCARE,
		"Arial" ) ) {
		return FALSE;
	}
	
	if( !m_rThinFont.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" ) ) {
		return FALSE;
	}

	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" ) ) {
		return FALSE;
	}

	// Get text heights
	CClientDC	dc( this );

	CFont*	pOldFont = dc.SelectObject( &m_rBoldFont );
	CSize	bold = dc.GetTextExtent( "Xg", 2 );
	m_i32BoldHeight = bold.cy;

	dc.SelectObject( &m_rThinFont );
	CSize	thin = dc.GetTextExtent( "Xg", 2 );
	m_i32ThinHeight = thin.cy;

	dc.SelectObject( pOldFont );

//	BOOL	bRes = CreateControls();

//	if( !bRes )
//		TRACE( "create controls failed\n" );

//	return bRes;


	// resize window
	CRect		rect;
	GetClientRect( &rect );
	rect.bottom = rect.top + m_i32CurY;
	MoveWindow( &rect, FALSE );

	CalcItemRects();

	return TRUE;
}

/*
BOOL
CDynDialog::CreateControls()
{
	// construct dialog
	uint32		curId = 0;
	CRect		rect;
	int32		cntWidth;
	int32		maxCntWidth;
	int32		captionWidth;

	GetClientRect( &rect );

	captionWidth = rect.Width() / 4;
	cntWidth = rect.Width() - (PADDING * 2) - (LEFT_INDENT * 2) - captionWidth - POSTLABEL_WIDTH;
	maxCntWidth = cntWidth;
//	editWidth = cntWidth - captionWidth;
	if( cntWidth > MAX_EDIT_WIDTH )
		cntWidth = MAX_EDIT_WIDTH;

	m_curPos.x = LEFT_INDENT;
	m_curPos.y = PADDING;


	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();


	for( uint32 i = 0; i < m_params.size(); i++ ) {

		ParamI*	param = m_params[i].m_param;
		curId = 0;

		// Create caption
		CStatic*	caption = new CStatic;

		CtlS	rCaption;
		rCaption.m_pWnd = caption;
		rCaption.m_ui32Type = CTLTYPE_CAPTION;
		m_controls.push_back( rCaption );	// save pointer for deletion

		CString	sName = param->get_name();
		sName += ":";

		if( !caption->Create( sName, WS_CHILD | WS_VISIBLE | SS_SIMPLE,
				CRect( m_curPos.x, m_curPos.y + LABEL_SHIFT, m_curPos.x + captionWidth, m_curPos.y + m_boldHeight + SPACING + LABEL_SHIFT ),
				this ) )
			return FALSE;
		caption->SetFont( &m_thinFont );
//		caption->SetFont( &m_boldFont );
//		m_curPos.y += m_boldHeight + SPACING;		// advace to next position

		m_curPos.x += captionWidth + LEFT_INDENT;

		switch( param->get_type() )
		{
		case PARAM_TYPE_INT:
			{
				ParamIntC*	p = (ParamIntC*)param;
				uint32		id;
				int32		val;

				p->get_val( i32Time, val );

				switch( p->get_style() ) {
				case PARAM_STYLE_EDITBOX:
					//   Caption__________
					//      [______123____][-]		(editbox + spinner)
					//
					{

						// Create edit box
						CEdit*	edit = new CEdit;

						CtlS	rEdit;
						rEdit.m_pWnd = edit;
						rEdit.m_ui32Type = CTLTYPE_EDIT;
						m_controls.push_back( rEdit );
						
						m_params[i].m_id[INT_EDIT] = id = GetNextFreeID();
						if( !edit->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL | ES_RIGHT,
								CRect( m_curPos.x, m_curPos.y, m_curPos.x + cntWidth - SPINNER, m_curPos.y + EDIT_HEIGHT ),
								this, id ) )
							return FALSE;
						edit->ModifyStyleEx( 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );	// sunken border
						m_curPos.y += EDIT_HEIGHT;
						edit->SetFont( &m_thinFont );
						CString	str;
						str.Format( "%d", val );
						edit->SetWindowText( str );

						// Spinner
						CSpinnerButton*	spin = new CSpinnerButton;

						CtlS	rSpin;
						rSpin.m_pWnd = spin;
						rSpin.m_ui32Type = CTLTYPE_SPINNER;
						m_controls.push_back( rSpin );

						uint32	style = WS_CHILD | WS_VISIBLE | SPNB_SETBUDDYINT | WS_GROUP;

						if( p->get_min() != p->get_max() )
							style |= SPNB_USELIMITS;

						m_params[i].m_id[INT_SPIN] = id = GetNextFreeID();
						if( !spin->Create( style, CRect( 0, 0, 0, 0 ), this, id ) )
							return FALSE;

						if( style & SPNB_USELIMITS )
							spin->SetMinMax( p->get_min(), p->get_max() );
						spin->SetScale( p->get_increment() );
						spin->SetBuddy( edit, SPNB_ATTACH_RIGHT );
						spin->SetVal( val );

						m_curPos.y += PARAM_SPACING;
					}
					break;

				case PARAM_STYLE_COMBOBOX:
					//   Caption___________
					//      [_Esko_______|v]		(combobox)
					//
					{

						// Create edit box
						m_params[i].m_id[INT_COMBO] = id = GetNextFreeID();
						CComboBox*	combo = new CComboBox;

						CtlS	rEdit;
						rEdit.m_pWnd = combo;
						rEdit.m_ui32Type = CTLTYPE_EDIT_MAX;
						m_controls.push_back( rEdit );

						if( !combo->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_DROPDOWNLIST,
								CRect( m_curPos.x, m_curPos.y, m_curPos.x + maxCntWidth, m_curPos.y + COMBO_HEIGHT ),
								this, id ) )
							return FALSE;
						m_curPos.y += EDIT_HEIGHT;
						combo->SetFont( &m_thinFont );

						int32	idx;
						for( uint32 j = 0; j < p->get_label_count(); j++ ) {
							idx = combo->AddString( p->get_label_name( j ) );
							combo->SetItemData( idx, p->get_label_value( j ) );
							if( p->get_label_value( j ) == val ) {
								combo->SetCurSel( idx );
							}
						}

						m_curPos.y += PARAM_SPACING;
					}
					break;

				default:
					TRACE( "*** Bad style with ParamIntC!" );
					break;
				}
			}
			break;

		case PARAM_TYPE_FLOAT:
			//   Caption__________  
			//      [______123____][-]		(editbox + spinner)
			//
			{
				ParamFloatC*	p = (ParamFloatC*)param;
				uint32			id;
				float32			val;

				p->get_val( i32Time, val );

				// Create edit box
				m_params[i].m_id[FLOAT_EDIT] = id = GetNextFreeID();
				CEdit*	edit = new CEdit;

				CtlS	rEdit;
				rEdit.m_pWnd = edit;
				rEdit.m_ui32Type = CTLTYPE_EDIT;
				m_controls.push_back( rEdit );

				if( !edit->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL | ES_RIGHT,
						CRect( m_curPos.x, m_curPos.y, m_curPos.x + cntWidth - SPINNER, m_curPos.y + EDIT_HEIGHT ),
						this, id ) )
					return FALSE;
				edit->ModifyStyleEx( 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );	// sunken border
				edit->SetFont( &m_thinFont );

				float32	f32Inc = p->get_increment();

				if( p->get_style() & PARAM_STYLE_PERCENT ) {
					f32Inc *= 100.0f;
					val *= 100.0f;
				}
				CString	str = Format( val, f32Inc );
				edit->SetWindowText( str );

				// Spinner
				CSpinnerButton*	spin = new CSpinnerButton;

				CtlS	rSpin;
				rSpin.m_pWnd = spin;
				rSpin.m_ui32Type = CTLTYPE_SPINNER;
				m_controls.push_back( rSpin );
				
				uint32	style = WS_CHILD | WS_VISIBLE | SPNB_SETBUDDYFLOAT | WS_GROUP;

				if( p->get_min() != p->get_max() )
					style |= SPNB_USELIMITS;

				m_params[i].m_id[FLOAT_SPIN] = id = GetNextFreeID();
				if( !spin->Create( style, CRect( 0, 0, 0, 0 ), this, id ) )
					return FALSE;

				if( style & SPNB_USELIMITS ) {
					if( p->get_style() & PARAM_STYLE_PERCENT )
						spin->SetMinMax( p->get_min() * 100.0f, p->get_max() * 100.0f );
					else
						spin->SetMinMax( p->get_min(), p->get_max() );
				}
				spin->SetScale( f32Inc );
				spin->SetBuddy( edit, SPNB_ATTACH_RIGHT );
				spin->SetVal( val );

				// Post label
				if( (p->get_style() & PARAM_STYLE_PERCENT) || (p->get_style() & PARAM_STYLE_ANGLE) ) {
					CStatic*	label = new CStatic;

					CtlS	rLabel;
					rLabel.m_pWnd = label;
					rLabel.m_ui32Type = CTLTYPE_POST_LABEL;
					m_controls.push_back( rLabel );	// save pointer for deletion

					CString	sName;

					if( p->get_style() & PARAM_STYLE_PERCENT )
						sName = '%';
					else if( p->get_style() & PARAM_STYLE_ANGLE )
						sName = '°';

					if( !label->Create( sName, WS_CHILD | WS_VISIBLE | SS_LEFT,
							CRect( m_curPos.x + cntWidth + 2, m_curPos.y + LABEL_SHIFT, m_curPos.x + cntWidth + 2 + POSTLABEL_WIDTH, m_curPos.y + EDIT_HEIGHT + LABEL_SHIFT ),
							this ) )
						return FALSE;
					label->SetFont( &m_thinFont );
				}

				m_curPos.y += EDIT_HEIGHT;

				m_curPos.y += PARAM_SPACING;
			}
			break;

		case PARAM_TYPE_VECTOR2:
			//   Caption__________
			//   x: [______123____][-]		(editbox + spinner)
			//   y: [______123____][-]
			//
			{

				ParamVector2C*	p = (ParamVector2C*)param;
				uint32			id;
				Vector2C		val;
				char			labels[2][4] = { "X:", "Y:" };

				p->get_val( i32Time, val );

				for( uint32 j = 0; j < 2; j++ ) {

					// axis label
					CStatic*	label = new CStatic;

					CtlS	rLabel;
					rLabel.m_pWnd = label;
					rLabel.m_ui32Type = CTLTYPE_PRE_LABEL;
					m_controls.push_back( rLabel );	// save pointer for deletion

					if( !label->Create( labels[j], WS_CHILD | WS_VISIBLE | SS_LEFT,
							CRect( m_curPos.x - LEFT_INDENT, m_curPos.y + LABEL_SHIFT, m_curPos.x, m_curPos.y + EDIT_HEIGHT - LABEL_SHIFT ),
							this ) )
						return FALSE;
					label->SetFont( &m_thinFont );

					// Create edit box
					m_params[i].m_id[VECTOR2_EDITX + j * 2] = id = GetNextFreeID();
					CEdit*	edit = new CEdit;

					CtlS	rEdit;
					rEdit.m_pWnd = edit;
					rEdit.m_ui32Type = CTLTYPE_EDIT;
					m_controls.push_back( rEdit );

					if( !edit->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL | ES_RIGHT,
							CRect( m_curPos.x, m_curPos.y, m_curPos.x + cntWidth - SPINNER, m_curPos.y + EDIT_HEIGHT ),
							this, id ) )
						return FALSE;
					edit->ModifyStyleEx( 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );	// sunken border
					edit->SetFont( &m_thinFont );

					float32	f32Inc = p->get_increment();

					if( p->get_style() & PARAM_STYLE_PERCENT ) {
						f32Inc *= 100.0f;
						val[j] *= 100.0f;
					}
					CString	str = Format( val[j], f32Inc );
					edit->SetWindowText( str );

					// Spinner
					CSpinnerButton*	spin = new CSpinnerButton;

					CtlS	rSpin;
					rSpin.m_pWnd = spin;
					rSpin.m_ui32Type = CTLTYPE_SPINNER;
					m_controls.push_back( rSpin );
					
					uint32	style = WS_CHILD | WS_VISIBLE | SPNB_SETBUDDYFLOAT | WS_GROUP;

					if( p->get_min() != p->get_max() )
						style |= SPNB_USELIMITS;

					m_params[i].m_id[VECTOR2_SPINX + j * 2] = id = GetNextFreeID();
					if( !spin->Create( style, CRect( 0, 0, 0, 0 ), this, id ) )
						return FALSE;

					if( style & SPNB_USELIMITS ) {
						if( p->get_style() & PARAM_STYLE_PERCENT )
							spin->SetMinMax( p->get_min()[j] * 100.0f, p->get_max()[j] * 100.0f );
						else
							spin->SetMinMax( p->get_min()[j], p->get_max()[j] );
					}
					spin->SetScale( f32Inc );
					spin->SetBuddy( edit, SPNB_ATTACH_RIGHT );
					spin->SetVal( val[j] );

					// Post label
					if( (p->get_style() & PARAM_STYLE_PERCENT) || (p->get_style() & PARAM_STYLE_ANGLE) ) {
						CStatic*	label = new CStatic;

						CtlS	rLabel;
						rLabel.m_pWnd = label;
						rLabel.m_ui32Type = CTLTYPE_POST_LABEL;
						m_controls.push_back( rLabel );	// save pointer for deletion

						CString	sName;

						if( p->get_style() & PARAM_STYLE_PERCENT )
							sName = '%';
						else if( p->get_style() & PARAM_STYLE_ANGLE )
							sName = '°';

						if( !label->Create( sName, WS_CHILD | WS_VISIBLE | SS_LEFT,
								CRect( m_curPos.x + cntWidth + 2, m_curPos.y + LABEL_SHIFT, m_curPos.x + cntWidth + 2 + POSTLABEL_WIDTH, m_curPos.y + EDIT_HEIGHT + LABEL_SHIFT ),
								this ) )
							return FALSE;
						label->SetFont( &m_thinFont );
					}

					m_curPos.y += EDIT_HEIGHT;
				}

				m_curPos.y += PARAM_SPACING;

			}
			break;

		case PARAM_TYPE_VECTOR3:
			//   Caption__________
			//   x: [______123____][-]		(editbox + spinner)
			//   y: [______123____][-]
			//   z: [______123____][-]
			//
			{

				ParamVector3C*	p = (ParamVector3C*)param;
				uint32			id;
				Vector3C		val;
				char			labels[3][4] = { "X:", "Y:", "Z:" };

				p->get_val( i32Time, val );

				for( uint32 j = 0; j < 3; j++ ) {

					// axis label
					CStatic*	label = new CStatic;

					CtlS	rLabel;
					rLabel.m_pWnd = label;
					rLabel.m_ui32Type = CTLTYPE_PRE_LABEL;
					m_controls.push_back( rLabel );	// save pointer for deletion
					
					if( !label->Create( labels[j], WS_CHILD | WS_VISIBLE | SS_LEFT,
							CRect( m_curPos.x - LEFT_INDENT, m_curPos.y + LABEL_SHIFT, m_curPos.x, m_curPos.y + EDIT_HEIGHT - LABEL_SHIFT ),
							this ) )
						return FALSE;
					label->SetFont( &m_thinFont );

					// Create edit box
					m_params[i].m_id[VECTOR3_EDITX + j * 2] = id = GetNextFreeID();
					CEdit*	edit = new CEdit;

					CtlS	rEdit;
					rEdit.m_pWnd = edit;
					rEdit.m_ui32Type = CTLTYPE_EDIT;
					m_controls.push_back( rEdit );
					
					if( !edit->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL | ES_RIGHT,
							CRect( m_curPos.x, m_curPos.y, m_curPos.x + cntWidth - SPINNER, m_curPos.y + EDIT_HEIGHT ),
							this, id ) )
						return FALSE;
					edit->ModifyStyleEx( 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );	// sunken border
					edit->SetFont( &m_thinFont );

					float32	f32Inc = p->get_increment();

					if( p->get_style() & PARAM_STYLE_PERCENT ) {
						f32Inc *= 100.0f;
						val[j] *= 100.0f;
					}
					CString	str = Format( val[j], f32Inc );
					edit->SetWindowText( str );

					// Spinner
					CSpinnerButton*	spin = new CSpinnerButton;

					CtlS	rSpin;
					rSpin.m_pWnd = spin;
					rSpin.m_ui32Type = CTLTYPE_SPINNER;
					m_controls.push_back( rSpin );
					
					uint32	style = WS_CHILD | WS_VISIBLE | SPNB_SETBUDDYFLOAT | WS_GROUP;

					if( p->get_min() != p->get_max() )
						style |= SPNB_USELIMITS;

					m_params[i].m_id[VECTOR3_SPINX + j * 2] = id = GetNextFreeID();
					if( !spin->Create( style, CRect( 0, 0, 0, 0 ), this, id ) )
						return FALSE;

					if( style & SPNB_USELIMITS ) {
						if( p->get_style() & PARAM_STYLE_PERCENT )
							spin->SetMinMax( p->get_min()[j] * 100.0f, p->get_max()[j] * 100.0f );
						else
							spin->SetMinMax( p->get_min()[j], p->get_max()[j] );
					}
					spin->SetScale( f32Inc );
					spin->SetBuddy( edit, SPNB_ATTACH_RIGHT );
					spin->SetVal( val[j] );

					// Post label
					if( (p->get_style() & PARAM_STYLE_PERCENT) || (p->get_style() & PARAM_STYLE_ANGLE) ) {
						CStatic*	label = new CStatic;

						CtlS	rLabel;
						rLabel.m_pWnd = label;
						rLabel.m_ui32Type = CTLTYPE_POST_LABEL;
						m_controls.push_back( rLabel );	// save pointer for deletion

						CString	sName;

						if( p->get_style() & PARAM_STYLE_PERCENT )
							sName = '%';
						else if( p->get_style() & PARAM_STYLE_ANGLE )
							sName = '°';

						if( !label->Create( sName, WS_CHILD | WS_VISIBLE | SS_LEFT,
								CRect( m_curPos.x + cntWidth + 2, m_curPos.y + LABEL_SHIFT, m_curPos.x + cntWidth + 2 + POSTLABEL_WIDTH, m_curPos.y + EDIT_HEIGHT + LABEL_SHIFT ),
								this ) )
							return FALSE;
						label->SetFont( &m_thinFont );
					}

					m_curPos.y += EDIT_HEIGHT;
				}

				m_curPos.y += PARAM_SPACING;
			}
			break;

		case PARAM_TYPE_COLOR:
			//  Caption
			//    [_P_]					(picker button)
			//
			{

				ParamColorC*	p = (ParamColorC*)param;
				uint32			id;

				CColorButton*	button = new CColorButton;

				CtlS	rBut;
				rBut.m_pWnd = button;
				rBut.m_ui32Type = CTLTYPE_BUTTON;
				m_controls.push_back( rBut );
				
				m_params[i].m_id[COLOR_BUTTON] = id = GetNextFreeID();
				if( !button->Create( "", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | WS_GROUP,
						CRect( m_curPos.x, m_curPos.y, m_curPos.x + PICKER_WIDTH, m_curPos.y + PICKER_HEIGHT ),
						this, id ) )
					return FALSE;
				button->ModifyStyleEx( 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );	// sunken border

				ColorC	val;
				p->get_val( i32Time, val );

				button->SetColor( (int32)(val[0] * 255.0f), (int32)(val[1] * 255.0f), (int32)(val[2] * 255.0f), (int32)(val[3] * 255.0f) );

				m_curPos.y += PICKER_HEIGHT + PARAM_SPACING;
			}
			break;


		case PARAM_TYPE_TEXT:
			//  Caption
			//    [_textiä______]				(edit box)
			//
			{
				ParamTextC*	p = (ParamTextC*)param;
				uint32			id;
				std::string		text;

				text = p->get_val( i32Time );

				// Create edit box
				m_params[i].m_id[TEXT_EDIT] = id = GetNextFreeID();
				CEdit*	edit = new CEdit;

				CtlS	rEdit;
				rEdit.m_pWnd = edit;
				rEdit.m_ui32Type = CTLTYPE_EDIT_MAX;
				m_controls.push_back( rEdit );

				if( !edit->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL | ES_RIGHT,
						CRect( m_curPos.x, m_curPos.y, m_curPos.x + maxCntWidth, m_curPos.y + EDIT_HEIGHT ),
						this, id ) )
					return FALSE;
				edit->ModifyStyleEx( 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );	// sunken border
				m_curPos.y += EDIT_HEIGHT;
				edit->SetFont( &m_thinFont );

				edit->SetWindowText( text.c_str() );

				m_curPos.y += PARAM_SPACING;
			}
			break;

		case PARAM_TYPE_FILE:
			{
				ParamFileC*	p = (ParamFileC*)param;
				uint32		id;

				// Create edit box
				m_params[i].m_id[FILE_COMBO] = id = GetNextFreeID();
				CComboBox*	combo = new CComboBox;

				CtlS	rEdit;
				rEdit.m_pWnd = combo;
				rEdit.m_ui32Type = CTLTYPE_EDIT_MAX;
				m_controls.push_back( rEdit );

				if( !combo->Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_DROPDOWNLIST,
						CRect( m_curPos.x, m_curPos.y, m_curPos.x + maxCntWidth, m_curPos.y + COMBO_HEIGHT ),
						this, id ) )
					return FALSE;
				m_curPos.y += EDIT_HEIGHT;
				combo->SetFont( &m_thinFont );


				int32		i32Idx;
				int32		i32Sel = 0;
				std::string	sStr;
				char		szFname[_MAX_FNAME];
				char		szExt[_MAX_EXT];

				i32Idx = combo->AddString( "<Empty>" );
				combo->SetItemData( i32Idx, 0xffffffff );

				FileHandleC*	pParamHandle = p->get_file();
				FileListC*		pFileList = pDoc->GetFileList();

				for( uint32 j = 0; j < pFileList->get_file_count(); j++ ) {

					FileHandleC*	pHandle = pFileList->get_file( j );
					ImportableI*	pImp = 0;

					if( !pHandle )
						continue;
					
					pImp = pHandle->get_importable();
					if( !pImp )
						continue;

					_splitpath( pImp->get_filename(), 0, 0, szFname, szExt );
					sStr = szFname;
					sStr += szExt;
				
					if( (p->get_class_filter() == NULL_CLASSID ||
						 p->get_class_filter() == pImp->get_class_id()) &&
						(p->get_super_class_filter() == NULL_SUPERCLASS ||
						p->get_super_class_filter() == pImp->get_super_class_id()) ) {

						i32Idx = combo->AddString( sStr.c_str() );
						combo->SetItemData( i32Idx, j );
					}

					if( pParamHandle == pHandle )
						i32Sel = i32Idx;
				}
				combo->SetCurSel( i32Sel );


				m_curPos.y += PARAM_SPACING;
			}
			break;

		default:
			TRACE( "*** Invalida parameter type\t" );
			break;
		}

	
		m_curPos.x -= captionWidth + LEFT_INDENT;
	}


	// resize window
	GetClientRect( &rect );
	rect.bottom = rect.top + m_curPos.y;
	MoveWindow( &rect, FALSE );

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}
*/


void
CDynDialog::UpdateFromGizmo( GizmoI* pGizmo )
{
	if( !pGizmo ) {
		m_rParams.clear();
		m_i32CurY = 0;
		return;
	}

	// See if the parameter layout is same as in previous update.
	bool	bSameLayout = true;
	if( pGizmo->get_parameter_count() == m_rParams.size() ) {
		for( uint32 i = 0; i < pGizmo->get_parameter_count(); i++ ) {
			if( pGizmo->get_parameter( i ) != m_rParams[i].m_pParam ) {
				bSameLayout = false;
				break;
			}
		}
	}
	else {
		bSameLayout = false;
	}

	if( !bSameLayout ) {
		m_rParams.clear();
		m_i32CurY = 0;

		for( uint32 i = 0; i < pGizmo->get_parameter_count(); i++ )
			AddParameter( pGizmo->get_parameter( i ) );

		// resize window
		CRect		rect;
		GetClientRect( &rect );
		rect.bottom = rect.top + m_i32CurY;
		MoveWindow( &rect, FALSE );
	}

	CalcItemRects();
	Invalidate();
}

bool
CDynDialog::AddParameter( ParamI* pParam )
{
	ParamItemC	rItem;
	rItem.m_pParam = pParam;

	switch( pParam->get_type() ) {
	case PARAM_TYPE_INT:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT + PARAM_SPACING;
		break;
	case PARAM_TYPE_FLOAT:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT + PARAM_SPACING;
		break;
	case PARAM_TYPE_VECTOR2:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT * 2 + COMP_SPACING + PARAM_SPACING;
		break;
	case PARAM_TYPE_VECTOR3:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT * 3 + COMP_SPACING * 2 + PARAM_SPACING;
		break;
	case PARAM_TYPE_COLOR:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT + PARAM_SPACING;
		break;
	case PARAM_TYPE_TEXT:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT + PARAM_SPACING;
		break;
	case PARAM_TYPE_FILE:
		rItem.m_i32Y = m_i32CurY;
		m_i32CurY += EDIT_HEIGHT + PARAM_SPACING;
		break;
	}

	m_rParams.push_back( rItem );
	return true;
}


void
CDynDialog::UpdateAllParamaters()
{
	for( uint32 i = 0; i < m_rParams.size(); i++ ) {
		ParameterChanged( m_rParams[i].m_pParam );
	}

	if( !m_bUpdating ) {
		if( m_uiTimerID ) {
			KillTimer( m_uiTimerID );
			m_uiTimerID = 0;
		}
		Invalidate( FALSE );
	}
}

void
CDynDialog::ParameterChanged( ParamI* changed )
{
/*	if( m_updating )
		return;

	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();

	for( uint32 i = 0; i < m_params.size(); i++ ) {

		ParamI*	param = m_params[i].m_param;

		if( changed->get_id() != param->get_id() )
			continue;

		switch( param->get_type() )
		{
		case PARAM_TYPE_INT:
			{
				ParamIntC*	p = (ParamIntC*)param;
				int32		val;

				p->get_val( i32Time, val );

				switch( p->get_style() ) {
				case PARAM_STYLE_EDITBOX:
					{
						CString	str;
						str.Format( "%d", val );
						CEdit*	edit = (CEdit*)GetDlgItem( m_params[i].m_id[INT_EDIT] );
						if( edit )
							edit->SetWindowText( str );
					}
					break;

				case PARAM_STYLE_COMBOBOX:
					{

						CComboBox*	combo = (CComboBox*)GetDlgItem( m_params[i].m_id[INT_COMBO] );
						if( combo ) {
							for( uint32 j = 0; j < combo->GetCount(); j++ ) {
								if( combo->GetItemData( j ) == val ) {
									combo->SetCurSel( j );
									break;
								}
							}
						}
					}
					break;

				default:
					break;
				}
			}
			break;

		case PARAM_TYPE_FLOAT:
			{
				ParamFloatC*	p = (ParamFloatC*)param;
				float32			val;

				p->get_val( i32Time, val );

				float32	f32Inc = p->get_increment();
				if( p->get_style() & PARAM_STYLE_PERCENT ) {
					f32Inc *= 100.0f;
					val *= 100.0f;
				}
				CString	str = Format( val, f32Inc );
				CEdit*	edit = (CEdit*)GetDlgItem( m_params[i].m_id[FLOAT_EDIT] );
				if( edit )
					edit->SetWindowText( str );
			}
			break;

		case PARAM_TYPE_VECTOR2:
			//   Caption__________
			//   x: [______123____][-]		(editbox + spinner)
			//   y: [______123____][-]
			//
			{
				ParamVector2C*	p = (ParamVector2C*)param;
				Vector2C		val;

				p->get_val( i32Time, val );

				CString	str;
				CEdit*	edit;
				float32	f32Inc = p->get_increment();
				if( p->get_style() & PARAM_STYLE_PERCENT ) {
					f32Inc *= 100.0f;
					val *= 100.0f;
				}

				str = Format( val[0], f32Inc );
				edit = (CEdit*)GetDlgItem( m_params[i].m_id[VECTOR2_EDITX] );
				if( edit )
					edit->SetWindowText( str );

				str = Format( val[1], f32Inc );
				edit = (CEdit*)GetDlgItem( m_params[i].m_id[VECTOR2_EDITY] );
				if( edit )
					edit->SetWindowText( str );
			}
			break;

		case PARAM_TYPE_VECTOR3:
			{
				ParamVector3C*	p = (ParamVector3C*)param;
				Vector3C		val;

				p->get_val( i32Time, val );

				CString	str;
				CEdit*	edit;
				float32	f32Inc = p->get_increment();
				if( p->get_style() & PARAM_STYLE_PERCENT ) {
					f32Inc *= 100.0f;
					val *= 100.0f;
				}

				str = Format( val[0], f32Inc );
				edit = (CEdit*)GetDlgItem( m_params[i].m_id[VECTOR3_EDITX] );
				if( edit )
					edit->SetWindowText( str );

				str = Format( val[1], f32Inc );
				edit = (CEdit*)GetDlgItem( m_params[i].m_id[VECTOR3_EDITY] );
				if( edit )
					edit->SetWindowText( str );

				str = Format( val[2], f32Inc );
				edit = (CEdit*)GetDlgItem( m_params[i].m_id[VECTOR3_EDITZ] );
				if( edit )
					edit->SetWindowText( str );
			}
			break;

		case PARAM_TYPE_COLOR:
			{
				ParamColorC*	p = (ParamColorC*)param;

				ColorC	val;
				p->get_val( i32Time, val );

				CColorButton*	but = (CColorButton*)GetDlgItem( m_params[i].m_id[COLOR_BUTTON] );
				but->SetColor( (int32)(val[0] * 255.0f), (int32)(val[1] * 255.0f), (int32)(val[2] * 255.0f), (int32)(val[3] * 255.0f) );
			}
			break;

		case PARAM_TYPE_TEXT:
			{
				ParamTextC*	p = (ParamTextC*)param;
				std::string	val;

				val = p->get_val( i32Time );

				CEdit*	edit = (CEdit*)GetDlgItem( m_params[i].m_id[TEXT_EDIT] );
				if( edit )
					edit->SetWindowText( val.c_str() );
			}
			break;

		case PARAM_TYPE_FILE:
			{
				ParamFileC*	p = (ParamFileC*)param;
			
				int32		i32Idx;
				int32		i32Sel = 0;
				std::string	sStr;
				char		szFname[_MAX_FNAME];
				char		szExt[_MAX_EXT];

				CComboBox*	combo = (CComboBox*)GetDlgItem( m_params[i].m_id[FILE_COMBO] );

				combo->ResetContent();

				i32Idx = combo->AddString( "<Empty>" );
				combo->SetItemData( i32Idx, 0xffffffff );

				FileHandleC*	pParamHandle = p->get_file();
				FileListC*		pFileList = pDoc->GetFileList();

				for( uint32 j = 0; j < pFileList->get_file_count(); j++ ) {

					FileHandleC*	pHandle = pFileList->get_file( j );
					ImportableI*	pImp = 0;

					if( !pHandle )
						continue;
					
					pImp = pHandle->get_importable();
					if( !pImp )
						continue;

					_splitpath( pImp->get_filename(), 0, 0, szFname, szExt );
					sStr = szFname;
					sStr += szExt;
				
					if( (p->get_class_filter() == NULL_CLASSID ||
						 p->get_class_filter() == pImp->get_class_id()) &&
						(p->get_super_class_filter() == NULL_SUPERCLASS ||
						p->get_super_class_filter() == pImp->get_super_class_id()) ) {

						i32Idx = combo->AddString( sStr.c_str() );
						combo->SetItemData( i32Idx, j );
					}

					if( pParamHandle == pHandle )
						i32Sel = i32Idx;
				}
				combo->SetCurSel( i32Sel );
			}
			break;

		default:
			TRACE( "*** Invalida parameter type\n" );
			break;
		}
	}
*/
}

/*
uint32
CDynDialog::GetNextFreeID()
{
	uint32	id = m_nextFreeId++;
	if( m_nextFreeId >= 0x7FFF ) {
		m_nextFreeId = WM_USER;
		TRACE( "free ID over flow\n" );
	}
	return id;
}
*/

void CDynDialog::PostNcDestroy() 
{
	// delete created controls
/*	uint32 i;
	for( i = 0; i < m_controls.size(); i++ ) {
		delete m_controls[i].m_pWnd;
	}
	m_controls.clear();*/

	if( m_uiTimerID ) {
		KillTimer( m_uiTimerID );
		m_uiTimerID = 0;
	}
	
	CDialog::PostNcDestroy();
}

BOOL CDynDialog::Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd )
{
	DLGTEMP	temp;
	temp.tmp.style = dwStyle; //WS_CAPTION | WS_SYSMENU | WS_VISIBLE | DS_CENTER | DS_3DLOOK;
	temp.tmp.dwExtendedStyle = WS_EX_DLGMODALFRAME;
	temp.tmp.cdit = 0;
	temp.tmp.x = rect.left;
	temp.tmp.y = rect.top;
	temp.tmp.cx = rect.right - rect.left;
	temp.tmp.cy = rect.bottom - rect.top;
	temp.menu = 0;
	temp.clss = 0;
	temp.name = 0;

	return CDialog::CreateIndirect( &temp, pParentWnd );
}

LRESULT CDynDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
/*	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();

	switch( message ) {
	case WM_COMMAND:
		{
			if( HIWORD( wParam ) == BN_CLICKED ) { 
				// A button Clicked
//				TRACE( "click!\n" );
				uint32	id = (uint32)LOWORD( wParam );
				for( uint32 i = 0; i < m_params.size(); i++ ) {
					// Check if it was one of the color selector buttons
					if( m_params[i].m_param->get_type() == PARAM_TYPE_COLOR ) {
						ParamColorC*	p = (ParamColorC*)m_params[i].m_param;
						if( m_params[i].m_id[COLOR_BUTTON] == id ) {

							CColorTypeInDlg		rDlg;

							rDlg.m_pParam = p;
							rDlg.m_i32Time = i32Time;

							// save current state
							UndoC*	pUndo = new UndoC( "Edit Parameter" );
							UndoC*	pOldUndo = p->begin_editing( pUndo );
							p->end_editing( pOldUndo );
							pDoc->GetUndoManager()->push( pUndo );
							pDoc->SetModifiedFlag();

							if( rDlg.DoModal() != IDOK ) {
								pDoc->GetUndoManager()->undo();
								pDoc->Redraw( REDRAW_GRAPHICS );
							}

							TRACE( "Color button for parameter %s clicked.\n", p->get_name() );
						}
					}
				}
			}
			else if( HIWORD( wParam ) == EN_SETFOCUS ) {
				m_bValueChanged = false;
			}
			else if( HIWORD( wParam ) == EN_CHANGE ) {
				m_bValueChanged = true;
			}
			else if( HIWORD( wParam ) == EN_KILLFOCUS ) {

				if( m_bValueChanged ) {

					uint32	id = (uint32)LOWORD( wParam );
					for( uint32 i = 0; i < m_params.size(); i++ ) {
						if( m_params[i].m_param->get_type() == PARAM_TYPE_INT ) {
							ParamIntC*	p = (ParamIntC*)m_params[i].m_param;
							CEdit*	edit = (CEdit*)GetDlgItem( id );
							if( edit ) {
								CString	str;
								int32	val;
								edit->GetWindowText( str );
								val = atoi( str );
								if( id == m_params[i].m_id[INT_EDIT] ) {

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, val ) );
									pDoc->Redraw( REDRAW_GRAPHICS );
									
								}
							}
						}
						else if( m_params[i].m_param->get_type() == PARAM_TYPE_FLOAT ) {
							ParamFloatC*	p = (ParamFloatC*)m_params[i].m_param;
							CEdit*	edit = (CEdit*)GetDlgItem( id );
							if( edit ) {
								CString	str;
								float32	val;
								edit->GetWindowText( str );
								val = atof( str );

								if( p->get_style() & PARAM_STYLE_PERCENT )
									val /= 100.0f;

								if( id == m_params[i].m_id[FLOAT_EDIT] ) {

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, val ) );
									pDoc->Redraw( REDRAW_GRAPHICS );
									
								}
							}
						}
						else if( m_params[i].m_param->get_type() == PARAM_TYPE_VECTOR2 ) {
							ParamVector2C*	p = (ParamVector2C*)m_params[i].m_param;
							CEdit*	edit = (CEdit*)GetDlgItem( id );
							if( edit ) {
								CString	str;
								float32	val;
								edit->GetWindowText( str );
								val = atof( str );

								if( p->get_style() & PARAM_STYLE_PERCENT )
									val /= 100.0f;

								if( id == m_params[i].m_id[VECTOR2_EDITX] ) {
									Vector2C	vec;
									p->get_val( i32Time, vec );
									vec[0] = val;

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, vec ) );
									pDoc->Redraw( REDRAW_GRAPHICS );
									
								}
								else if( id == m_params[i].m_id[VECTOR2_EDITY] ) {
									Vector2C	vec;
									p->get_val( i32Time, vec );
									vec[1] = val;

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, vec ) );
									pDoc->Redraw( REDRAW_GRAPHICS );
									
								}
								
							}
						}
						else if( m_params[i].m_param->get_type() == PARAM_TYPE_VECTOR3 ) {
							ParamVector3C*	p = (ParamVector3C*)m_params[i].m_param;
							CEdit*	edit = (CEdit*)GetDlgItem( id );
							if( edit ) {
								CString	str;
								float32	val;
								edit->GetWindowText( str );
								val = atof( str );

								if( p->get_style() & PARAM_STYLE_PERCENT )
									val /= 100.0f;

								if( id == m_params[i].m_id[VECTOR3_EDITX] ) {
									Vector3C	vec;
									p->get_val( i32Time, vec );
									vec[0] = val;

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, vec ) );

								}
								else if( id == m_params[i].m_id[VECTOR3_EDITY] ) {
									Vector3C	vec;
									p->get_val( i32Time, vec );
									vec[1] = val;

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, vec ) );
									
								}
								else if( id == m_params[i].m_id[VECTOR3_EDITZ] ) {
									Vector3C	vec;
									p->get_val( i32Time, vec );
									vec[2] = val;

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, vec ) );
									
								}
								pDoc->Redraw( REDRAW_GRAPHICS );
							}
						}
						else if( m_params[i].m_param->get_type() == PARAM_TYPE_TEXT ) {
							ParamTextC*	p = (ParamTextC*)m_params[i].m_param;
							CEdit*	edit = (CEdit*)GetDlgItem( id );
							if( edit ) {
								if( id == m_params[i].m_id[TEXT_EDIT] ) {
									CString	str;
									edit->GetWindowText( str );

									// save current state
									UndoC*	pUndo = new UndoC( "Edit Parameter" );
									UndoC*	pOldUndo = p->begin_editing( pUndo );
									p->end_editing( pOldUndo );
									pDoc->GetUndoManager()->push( pUndo );
									pDoc->SetModifiedFlag();

									pDoc->HandleParamNotify( p->set_val( i32Time, (const char*)str ) );
									pDoc->Redraw( REDRAW_GRAPHICS );
									
								}
							}
						}
					}
				}
			}
			else if( HIWORD( wParam ) == CBN_SELCHANGE ) {
				uint32	id = (uint32)LOWORD( wParam );
				for( uint32 i = 0; i < m_params.size(); i++ ) {

					if( m_params[i].m_param->get_type() == PARAM_TYPE_INT ) {

						ParamIntC*	p = (ParamIntC*)m_params[i].m_param;
						if( id == m_params[i].m_id[INT_COMBO] ) {
							CComboBox*	combo = (CComboBox*)GetDlgItem( id );
							if( combo && combo->GetCurSel() != CB_ERR ) {
								int32	idx = combo->GetCurSel();
								uint32	val = combo->GetItemData( idx );

								// save current state
								UndoC*	pUndo = new UndoC( "Edit Parameter" );
								UndoC*	pOldUndo = p->begin_editing( pUndo );
								p->end_editing( pOldUndo );
								pDoc->GetUndoManager()->push( pUndo );
								pDoc->SetModifiedFlag();

								pDoc->HandleParamNotify( p->set_val( i32Time, val ) );
								pDoc->Redraw( REDRAW_GRAPHICS );

							}
						}
					}
					else if( m_params[i].m_param->get_type() == PARAM_TYPE_FILE ) {
						ParamFileC*	p = (ParamFileC*)m_params[i].m_param;
						if( id == m_params[i].m_id[FILE_COMBO] ) {

							CComboBox*	combo = (CComboBox*)GetDlgItem( id );
							if( combo && combo->GetCurSel() != CB_ERR ) {
								int32	idx = combo->GetCurSel();
								int32	i32Num = combo->GetItemData( idx );

								// save current state
								UndoC*	pUndo = new UndoC( "Edit Parameter" );
								UndoC*	pOldUndo = p->begin_editing( pUndo );
								p->end_editing( pOldUndo );
								pDoc->GetUndoManager()->push( pUndo );
								pDoc->SetModifiedFlag();

								if( i32Num == 0xffffffff ) {
									pDoc->HandleParamNotify( p->set_file( 0 ) );
								}
								else {
									FileListC*		pFileList = pDoc->GetFileList();
									FileHandleC*	pHandle = pFileList->get_file( i32Num );
									pDoc->HandleParamNotify( p->set_file( pHandle ) );
								}
								pDoc->Redraw( REDRAW_GRAPHICS );
							}
						}
					}
				}
			}
		}
		break;
	}
*/


	if( message == WM_COMMAND ) {
		if( wParam == IDOK && m_pEditCtrl ) {
			// get the new label
			CString	sStr;
			m_pEditCtrl->GetWindowText( sStr );

			// delete the edit box
			m_pEditCtrl->DestroyWindow();
			delete m_pEditCtrl;
			m_pEditCtrl = 0;

/*			UndoC*	pUndo;

			// update name
			if( m_pEditingItem->m_i32Flags & ITEM_LAYER ) {
				LayerC*	pLayer = m_pDoc->GetLayer( m_pEditingItem );
				if( pLayer ) {
					pUndo = new UndoC( "Rename Layer" );
					UndoC*	pOldUndo = pLayer->begin_editing( pUndo );
					pLayer->set_name( sStr );
					pLayer->end_editing( pOldUndo );
				}
			}
			else if( m_pEditingItem->m_i32Flags & ITEM_EFFECT ) {
				EffectI*	pEffect = m_pDoc->GetEffect( m_pEditingItem );
				if( pEffect ) {
					pUndo = new UndoC( "Rename Effect" );
					UndoC*	pOldUndo = pEffect->begin_editing( pUndo );
					pEffect->set_name( sStr );
					pEffect->end_editing( pOldUndo );
				}
			}

			// store command
			m_pDoc->GetUndoManager()->push( pUndo );

			// mark document as modified
			m_pDoc->SetModifiedFlag();

			// update window
			m_pDoc->LayerListModified();
			Invalidate( FALSE );

			m_bDiscardReturnAfterEditOK = true;*/

			return 0;
		}
		else if( wParam == IDCANCEL && m_pEditCtrl ) {
			OnKillfocusEditLabel();
			return 0;
		}

	}

	
	return CDialog::WindowProc(message, wParam, lParam);
}


// Hopefully this makes enter behave like TAB.
void
CDynDialog::OnOK()
{
    CWnd *pNextWnd = GetNextDlgTabItem( GetFocus() );

	// This next line of code will make sure that the
	// focus rectangle surrounds the next control...
	// good in the case of fake tabbing from say a
	// CEdit control to a CButton control... 
	// Just calling SetFocus does not do this
	GotoDlgCtrl( GetDlgItem( pNextWnd->GetDlgCtrlID() ) );
}


void CDynDialog::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize( nType, cx, cy );

	CalcItemRects();

/*
	// resize controls

	// construct dialog
	uint32		curId = 0;
	CRect		rect;
	int32		cntWidth;
	int32		maxCntWidth;
	int32		captionWidth;

	GetClientRect( &rect );

	captionWidth = rect.Width() / 4;
	cntWidth = rect.Width() - (PADDING * 2) - (LEFT_INDENT * 2) - captionWidth - POSTLABEL_WIDTH;
	maxCntWidth = cntWidth;
//	editWidth = cntWidth - captionWidth;
	if( cntWidth > MAX_EDIT_WIDTH )
		cntWidth = MAX_EDIT_WIDTH;

	int32	i32CurPosX = LEFT_INDENT;

	CRect	rCtlRect;


	HDWP hdwp = BeginDeferWindowPos( m_controls.size() );

	for( uint32 i = 0; i < m_controls.size(); i++ ) {

		CWnd*	pCtl = m_controls[i].m_pWnd;

		pCtl->GetWindowRect( &rCtlRect );
		ScreenToClient( &rCtlRect );

		if( m_controls[i].m_ui32Type == CTLTYPE_CAPTION ) {

			rCtlRect.left = i32CurPosX;
			rCtlRect.right = rCtlRect.left + captionWidth;
			DeferWindowPos( hdwp, pCtl->m_hWnd, 0, rCtlRect.left, rCtlRect.top, rCtlRect.Width(), rCtlRect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW );
		}
		else if( m_controls[i].m_ui32Type == CTLTYPE_PRE_LABEL ) {

			rCtlRect.left = (i32CurPosX + captionWidth + LEFT_INDENT) - LEFT_INDENT;
			rCtlRect.right = rCtlRect.left + LEFT_INDENT;
			DeferWindowPos( hdwp, pCtl->m_hWnd, 0, rCtlRect.left, rCtlRect.top, rCtlRect.Width(), rCtlRect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW );
		}
		else if( m_controls[i].m_ui32Type == CTLTYPE_POST_LABEL ) {

			rCtlRect.left = i32CurPosX + captionWidth + LEFT_INDENT + cntWidth + 2;
			rCtlRect.right = rCtlRect.left + POSTLABEL_WIDTH;
			DeferWindowPos( hdwp, pCtl->m_hWnd, 0, rCtlRect.left, rCtlRect.top, rCtlRect.Width(), rCtlRect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW );
		}
		else if( m_controls[i].m_ui32Type == CTLTYPE_EDIT ) {

			rCtlRect.left = i32CurPosX + captionWidth + LEFT_INDENT;
			rCtlRect.right = rCtlRect.left + cntWidth - SPINNER;
			DeferWindowPos( hdwp, pCtl->m_hWnd, 0, rCtlRect.left, rCtlRect.top, rCtlRect.Width(), rCtlRect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW );
		}
		else if( m_controls[i].m_ui32Type == CTLTYPE_EDIT_MAX ) {

			rCtlRect.left = i32CurPosX + captionWidth + LEFT_INDENT;
			rCtlRect.right = rCtlRect.left + maxCntWidth;
			DeferWindowPos( hdwp, pCtl->m_hWnd, 0, rCtlRect.left, rCtlRect.top, rCtlRect.Width(), rCtlRect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW );
		}
		else if( m_controls[i].m_ui32Type == CTLTYPE_BUTTON ) {

			rCtlRect.left = i32CurPosX + captionWidth + LEFT_INDENT;
			rCtlRect.right = rCtlRect.left + PICKER_WIDTH;
			DeferWindowPos( hdwp, pCtl->m_hWnd, 0, rCtlRect.left, rCtlRect.top, rCtlRect.Width(), rCtlRect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW );
		}
	}

	EndDeferWindowPos( hdwp );

	for(  i = 0; i < m_controls.size(); i++ ) {
		CWnd*	pCtl = m_controls[i].m_pWnd;
		if( m_controls[i].m_ui32Type == CTLTYPE_SPINNER ) {
			CSpinnerButton*	pSpin = (CSpinnerButton*)pCtl;
			pSpin->SetBuddy( pSpin->GetBuddy(), SPNB_ATTACH_RIGHT );
		}
	}

*/
}

CString CDynDialog::Format( float32 f32Value, float32 f32Inc )
{
	CString	sValue;
	char	szFormat[32];
	_snprintf( szFormat, 31, "%%.%df", (int32)__max( -floor( log10( f32Inc ) ), 0 ) );
	sValue.Format( szFormat, f32Value );
	return sValue;
}


void CDynDialog::DrawEditBox( CDC* pDC, const CRect& rItemRect, const char* szText )
{
	CBrush	rDarkBrush( ::GetSysColor( COLOR_BTNSHADOW ) );
	CRect	rEditRect = rItemRect;

	pDC->Draw3dRect( rEditRect, ::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
	rEditRect.DeflateRect( 1, 1 );
	pDC->FillSolidRect( rEditRect, ::GetSysColor( COLOR_WINDOW ) );

	int32	i32TextX = rEditRect.left + 3;
	int32	i32TextY = rEditRect.top + 1;

	pDC->ExtTextOut( i32TextX, i32TextY, ETO_CLIPPED, rEditRect, szText, NULL );
}

void CDynDialog::DrawEditBoxWithSpinner( CDC* pDC, const CRect& rItemRect, const char* szText, bool bSpinnerUp, bool bSpinnerDown )
{
	CBrush	rDarkBrush( ::GetSysColor( COLOR_BTNSHADOW ) );
	CRect	rEditRect = rItemRect;
	rEditRect.right -= SPINNER_WIDTH;

	pDC->Draw3dRect( rEditRect, ::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
	rEditRect.DeflateRect( 1, 1 );
	pDC->FillSolidRect( rEditRect, ::GetSysColor( COLOR_WINDOW ) );

	int32	i32TextX = rEditRect.left + 3;
	int32	i32TextY = rEditRect.top + 1;

	pDC->ExtTextOut( i32TextX, i32TextY, ETO_CLIPPED, rEditRect, szText, NULL );

	// Spinners

	CRect	rButRect = rEditRect;
	rButRect.left = rButRect.right + 3;
	rButRect.right = rButRect.left + (rButRect.Height() * 4 / 5);

	int32	i32Width = !(rButRect.Width() & 1) ? rButRect.Width() - 1 : rButRect.Width();
	int32	i32Height = rButRect.Height() / 2;

	CRect	rButUpRect;
	rButUpRect.left = rButRect.left;
	rButUpRect.right = rButRect.left + i32Width;
	rButUpRect.top = rButRect.top;
	rButUpRect.bottom = rButRect.top + i32Height;

	CRect	rButDownRect = rButRect;
	rButDownRect.left = rButRect.left;
	rButDownRect.right = rButRect.left + i32Width;
	rButDownRect.top = rButRect.top + i32Height;
	rButDownRect.bottom = rButRect.bottom;


	pDC->DrawEdge( rButUpRect, bSpinnerUp ? BDR_SUNKENINNER : BDR_RAISEDINNER, BF_RECT );
	pDC->DrawEdge( rButDownRect, bSpinnerDown ? BDR_SUNKENINNER : BDR_RAISEDINNER, BF_RECT );


	CPen	rBlackPen( PS_SOLID, -1, RGB( 0, 0, 0 ) );
	CBrush	rBlackBrush( RGB( 0, 0, 0 ) ); 

	CPen*	pOldPen = pDC->SelectObject( &rBlackPen );
	CBrush*	pOldBrush = pDC->SelectObject( &rBlackBrush );


	int32	i32ArrowSize =  i32Width / 4;

	POINT	pt[3];

	// Up arrow
	int	xbase = rButUpRect.left + rButUpRect.Width() / 2;
	if( bSpinnerUp )
		xbase += 1;
	pt[0].x = xbase - i32ArrowSize;
	pt[1].x = xbase;
	pt[2].x = xbase + i32ArrowSize;

	int	ybase = rButUpRect.bottom - rButUpRect.Height() / 3 - 1;	// bottom value is not included in the rect so we always go off by one.
	if( bSpinnerUp )
		ybase += 1;
	pt[0].y = ybase;
	pt[1].y = ybase - i32ArrowSize;
	pt[2].y = ybase;

	pDC->Polygon( pt, 3 );

	// Down Arrow
	xbase = rButDownRect.left + rButDownRect.Width() / 2;
	if( bSpinnerDown )
		xbase += 1;
	pt[0].x = xbase - i32ArrowSize;
	pt[1].x = xbase;
	pt[2].x = xbase + i32ArrowSize;

	ybase = rButDownRect.top + rButDownRect.Height() / 3;
	if( bSpinnerDown )
		ybase += 1;
	pt[0].y = ybase;
	pt[1].y = ybase + i32ArrowSize;
	pt[2].y = ybase;

	pDC->Polygon( pt, 3 );

	pDC->SelectObject( pOldBrush );
	pDC->SelectObject( pOldPen );
}

void CDynDialog::DrawComboBox( CDC* pDC, const CRect& rItemRect, const char* szText, bool bState )
{
	CBrush	rDarkBrush( ::GetSysColor( COLOR_BTNSHADOW ) );

	CRect	rEditRect = rItemRect;
	rEditRect.right -= COMBO_WIDTH;

	pDC->Draw3dRect( rItemRect, ::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
	rEditRect.DeflateRect( 1, 1 );
	pDC->FillSolidRect( rEditRect, ::GetSysColor( COLOR_WINDOW ) );


	int32	i32TextX = rEditRect.left + 3;
	int32	i32TextY = rEditRect.top + 1;

	pDC->ExtTextOut( i32TextX, i32TextY, ETO_CLIPPED, rEditRect, szText, NULL );

	CRect	rButRect = rEditRect;
	rButRect.left = rButRect.right;
	rButRect.right += COMBO_WIDTH;

	if( bState )
		pDC->DrawFrameControl( rButRect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED );
	else
		pDC->DrawFrameControl( rButRect, DFC_BUTTON, DFCS_BUTTONPUSH );
	
	pDC->Draw3dRect( rButRect, ::GetSysColor( COLOR_BTNHILIGHT ), ::GetSysColor( COLOR_BTNSHADOW ) );

	CPen	rBlackPen( PS_SOLID, -1, RGB( 0, 0, 0 ) );
	CBrush	rBlackBrush( RGB( 0, 0, 0 ) ); 

	CPen*	pOldPen = pDC->SelectObject( &rBlackPen );
	CBrush*	pOldBrush = pDC->SelectObject( &rBlackBrush );


	int32	i32ArrowSize =  rButRect.Width() / 6;

	POINT	pt[3];

	// Down Arrow
	int xbase = rButRect.left + rButRect.Width() / 2;
	if( bState )
		xbase += 1;
	pt[0].x = xbase - i32ArrowSize;
	pt[1].x = xbase;
	pt[2].x = xbase + i32ArrowSize;

	int ybase = rButRect.top + rButRect.Height() / 3;
	if( bState )
		ybase += 1;
	pt[0].y = ybase;
	pt[1].y = ybase + i32ArrowSize;
	pt[2].y = ybase;

	pDC->Polygon( pt, 3 );

	pDC->SelectObject( pOldBrush );
	pDC->SelectObject( pOldPen );
}


bool CDynDialog::HitTestControl( const CPoint& rPt )
{
	if( m_pHitItem )
		return true;

	for( uint32 i = 0; i < m_rParams.size(); i++ ) {
		if( m_rParams[i].m_rItemRects[0].PtInRect( rPt ) )
			return true;
	}

	return false;
}

int32 CDynDialog::HitTestEditBox( const CPoint& rPt, const CRect& rItemRect )
{
	if( rItemRect.PtInRect( rPt ) )
		return HITTEST_EDITBOX;

	return HITTEST_NONE;
}

int32 CDynDialog::HitTestEditBoxWithSpinner( const CPoint& rPt, const CRect& rItemRect )
{
	CRect	rEditRect = rItemRect;
	rEditRect.right -= SPINNER_WIDTH;

	CRect	rButUpRect = rItemRect;
	rButUpRect.left = rButUpRect.right - SPINNER_WIDTH;
	rButUpRect.bottom = rButUpRect.top + EDIT_HEIGHT / 2;

	CRect	rButDownRect = rItemRect;
	rButDownRect.left = rButDownRect.right - SPINNER_WIDTH;
	rButDownRect.top = rButDownRect.bottom - EDIT_HEIGHT / 2;

	if( rEditRect.PtInRect( rPt ) )
		return HITTEST_EDITBOX;
	else if( rButUpRect.PtInRect( rPt ) )
		return HITTEST_SPINNERUP;
	else if( rButDownRect.PtInRect( rPt ) )
		return HITTEST_SPINNERDOWN;

	return HITTEST_NONE;
}

int32 CDynDialog::HitTestComboBox( const CPoint& rPt, const CRect& rItemRect )
{
	CRect	rEditRect = rItemRect;
	rEditRect.right -= EDIT_HEIGHT;

	CRect	rButRect = rItemRect;
	rButRect.left = rButRect.right - EDIT_HEIGHT;

	if( rEditRect.PtInRect( rPt ) )
		return HITTEST_EDITBOX;
	else if( rButRect.PtInRect( rPt ) )
		return HITTEST_COMBOBUTTON;

	return HITTEST_NONE;
}


void CDynDialog::OnPaint()
{
	if( m_bUpdating )
		return;

	CPaintDC dc( this ); // device context for painting

	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();

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

	GetClientRect( rRect );

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

	rMemDC.FillSolidRect( rRect, ::GetSysColor( COLOR_BTNFACE ) );


	CFont*	pOldFont = rMemDC.SelectObject( &m_rThinFont );


	int32		i32CntWidth;
	int32		i32MaxCntWidth;
	int32		i32CaptionWidth;

	i32CaptionWidth = rRect.Width() / 4;
	i32CntWidth = rRect.Width() - i32CaptionWidth - 2 * LABEL_WIDTH - 2 * PADDING;
	i32MaxCntWidth = i32CntWidth;
	if( i32CntWidth > MAX_EDIT_WIDTH )
		i32CntWidth = MAX_EDIT_WIDTH;

	CRect	rClipRect;

	CBrush	rDarkBrush( ::GetSysColor( COLOR_BTNSHADOW ) );

	for( uint32 i = 0; i < m_rParams.size(); i++ ) {
		ParamI*	pParam = m_rParams[i].m_pParam;

		if( !pParam )
			continue;

		rMemDC.SetBkMode( TRANSPARENT );
		rMemDC.SetTextColor( RGB( 0, 0, 0 ) );

		CString	sName = pParam->get_name();
		sName += ":";

		int32	i32X = LEFT_INDENT;
		int32	i32Y = m_rParams[i].m_i32Y;

		rClipRect.left = i32X;
		rClipRect.right = i32X + i32CaptionWidth;
		rClipRect.top = i32Y;
		rClipRect.bottom = i32Y + EDIT_HEIGHT;

		rMemDC.SelectObject( &m_rThinFont );
		rMemDC.ExtTextOut( i32X, i32Y + 2, ETO_CLIPPED, rClipRect, sName, NULL );

		CString	sValue, sFormat;

		int32	i32TimeOffset = GetTimeOffset( pParam );

		switch( pParam->get_type() ) {
		case PARAM_TYPE_INT:
			{
				CRect	rItemRect = m_rParams[i].m_rItemRects[0];

				ParamIntC*	pParamInt = (ParamIntC*)pParam;

				int32		i32Val;
				pParamInt->get_val( i32Time + i32TimeOffset, i32Val );

				rMemDC.SelectObject( &m_rThinFont );

				CString	sValue;

				if( pParamInt->get_label_count() ) {
					// draw labels name if possible
					bool	bFound = false;
					for( uint32 j = 0; j < pParamInt->get_label_count(); j++ ) {
						if( i32Val == pParamInt->get_label_value( j ) ) {
							sValue = pParamInt->get_label_name( j );
							bFound = true;
							break;
						}
					}
					if( !bFound ) {
						sValue.Format( "%d", i32Val );
					}
				}
				else {
					sValue.Format( "%d", i32Val );
				}

				if( pParam->get_style() == PARAM_STYLE_COMBOBOX )
					DrawComboBox( &rMemDC, rItemRect, sValue, m_rParams[i].m_i32ActiveItem == ACTIVEITEM_COMBO ? true : false );
				else
					DrawEditBoxWithSpinner( &rMemDC, rItemRect, sValue, m_rParams[i].m_i32ActiveItem == ACTIVEITEM_UP_X ? true : false, m_rParams[i].m_i32ActiveItem == ACTIVEITEM_DOWN_X ? true : false );

			}
			break;

		case PARAM_TYPE_FLOAT:
			{
				CRect	rItemRect = m_rParams[i].m_rItemRects[0];

				ParamFloatC*	pParamFloat = (ParamFloatC*)pParam;
				float32			f32Val;
				float32			f32Scale = 1.0f;
				if( pParam->get_style() & PARAM_STYLE_PERCENT ) 
					f32Scale = 100.0f;
				pParamFloat->get_val( i32Time + i32TimeOffset, f32Val );
				sFormat.Format( "%%.%df", (int32)__max( -floor( log10( pParamFloat->get_increment() * f32Scale ) ), 0 ) );
				sValue.Format( sFormat, f32Val * f32Scale );
				if( pParam->get_style() & PARAM_STYLE_PERCENT ) 
					sValue += "%";
				else if( pParam->get_style() & PARAM_STYLE_ANGLE ) 
					sValue += "°";
				rMemDC.SelectObject( &m_rThinFont );

				DrawEditBoxWithSpinner( &rMemDC, rItemRect, sValue, m_rParams[i].m_i32ActiveItem == ACTIVEITEM_UP_X ? true : false, m_rParams[i].m_i32ActiveItem == ACTIVEITEM_DOWN_X ? true : false );
			}
			break;

		case PARAM_TYPE_VECTOR2:
			{
				ParamVector2C*	pParamVec2 = (ParamVector2C*)pParam;
				Vector2C		rVal;
				float32			f32Scale = 1.0f;
				if( pParam->get_style() & PARAM_STYLE_PERCENT ) 
					f32Scale = 100.0f;
				pParamVec2->get_val( i32Time + i32TimeOffset, rVal );
				int32	i32NFrac = (int32)__max( -floor( log10( pParamVec2->get_increment() * f32Scale ) ), 0 );

				if( pParam->get_style() & PARAM_STYLE_PERCENT )
					sFormat.Format( "%%.%df%%%%", i32NFrac );
				else if( pParam->get_style() & PARAM_STYLE_ANGLE )
					sFormat.Format( "%%.%df°", i32NFrac );
				else
					sFormat.Format( "%%.%df", i32NFrac );

				char	szLabel[2][4] = { "X", "Y" };
				int32	i32Act[4] = { ACTIVEITEM_UP_X, ACTIVEITEM_DOWN_X, ACTIVEITEM_UP_Y, ACTIVEITEM_DOWN_Y };

				for( uint32 j = 0; j < 2; j++ ) {
					CRect	rItemRect = m_rParams[i].m_rItemRects[j];
					rMemDC.SelectObject( &m_rSmallFont );
					rMemDC.TextOut( i32X + i32CaptionWidth + PADDING, i32Y + j * (EDIT_HEIGHT + COMP_SPACING) + 4, szLabel[j] );

					sValue.Format( sFormat, rVal[j] * f32Scale );
					rMemDC.SelectObject( &m_rThinFont );
					DrawEditBoxWithSpinner( &rMemDC, rItemRect, sValue, m_rParams[i].m_i32ActiveItem == i32Act[j * 2]? true : false, m_rParams[i].m_i32ActiveItem == i32Act[j * 2 + 1] ? true : false );
				}
			}
			break;

		case PARAM_TYPE_VECTOR3:
			{
				ParamVector3C*	pParamVec3 = (ParamVector3C*)pParam;
				Vector3C		rVal;
				float32			f32Scale = 1.0f;
				if( pParam->get_style() & PARAM_STYLE_PERCENT ) 
					f32Scale = 100.0f;
				pParamVec3->get_val( i32Time + i32TimeOffset, rVal );
				int32	i32NFrac = (int32)__max( -floor( log10( pParamVec3->get_increment() * f32Scale ) ), 0 );

				if( pParam->get_style() & PARAM_STYLE_PERCENT )
					sFormat.Format( "%%.%df%%%%", i32NFrac );
				else if( pParam->get_style() & PARAM_STYLE_ANGLE )
					sFormat.Format( "%%.%df°", i32NFrac );
				else
					sFormat.Format( "%%.%df", i32NFrac );

				char	szLabel[3][4] = { "X", "Y", "Z" };
				int32	i32Act[6] = { ACTIVEITEM_UP_X, ACTIVEITEM_DOWN_X, ACTIVEITEM_UP_Y, ACTIVEITEM_DOWN_Y, ACTIVEITEM_UP_Z, ACTIVEITEM_DOWN_Z };

				for( uint32 j = 0; j < 3; j++ ) {
					CRect	rItemRect = m_rParams[i].m_rItemRects[j];

					rMemDC.SelectObject( &m_rSmallFont );
					rMemDC.TextOut( i32X + i32CaptionWidth + PADDING, i32Y + j * (EDIT_HEIGHT + COMP_SPACING) + 4, szLabel[j] );

					sValue.Format( sFormat, rVal[j] * f32Scale );
					rMemDC.SelectObject( &m_rThinFont );
					DrawEditBoxWithSpinner( &rMemDC, rItemRect, sValue, m_rParams[i].m_i32ActiveItem == i32Act[j * 2]? true : false, m_rParams[i].m_i32ActiveItem == i32Act[j * 2 + 1] ? true : false );
				}
			}
			break;

		case PARAM_TYPE_COLOR:
			{
				CRect	rItemRect = m_rParams[i].m_rItemRects[0];

				ParamColorC*	pParamColor = (ParamColorC*)pParam;
				ColorC			rVal;
				pParamColor->get_val( i32Time + i32TimeOffset, rVal );

				rMemDC.Draw3dRect( rItemRect, ::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
				rItemRect.DeflateRect( 1, 1 );
				rMemDC.FillSolidRect( rItemRect, RGB( (int)(rVal[0] * 255.0f), (int)(rVal[1] * 255.0f), (int)(rVal[2] * 255.0f) ) );
			}
			break;

		case PARAM_TYPE_TEXT:
			{
				CRect	rItemRect = m_rParams[i].m_rItemRects[0];

				ParamTextC*	pParamText = (ParamTextC*)pParam;
				rMemDC.SelectObject( &m_rThinFont );
				DrawEditBox( &rMemDC, rItemRect, pParamText->get_val( i32Time + i32TimeOffset ) );
			}
			break;

		case PARAM_TYPE_FILE:
			{
				CRect	rItemRect = m_rParams[i].m_rItemRects[0];

				ParamFileC*		pParamFile = (ParamFileC*)pParam;
				FileHandleC*	pHandle = 0;//pParamFile->get_file();
				ImportableI*	pImportable = 0;
				std::string		sStr;

				if( pHandle )
					pImportable = pHandle->get_importable();

				if( pImportable ) {
					char szFname[_MAX_FNAME];
					char szExt[_MAX_EXT];
					_splitpath( pImportable->get_filename(), 0, 0, szFname, szExt );
					sStr += szFname;
					sStr += szExt;
				}
				else
					sStr = "<Empty>";

				rMemDC.SelectObject( &m_rThinFont );
				DrawComboBox( &rMemDC, rItemRect, sStr.c_str(), m_rParams[i].m_i32ActiveItem == ACTIVEITEM_COMBO ? true : false );
			}
			break;
		}
	}

	rMemDC.SelectObject( pOldFont );

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


	// use delayed redraw so that this window get's redrawn more often.
	if( m_ui32RedrawFlags ) {
		m_ui32RedrawFlags = 0;
		m_bUpdating = true;
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
		m_bUpdating = false;
	}
}

BOOL CDynDialog::OnEraseBkgnd(CDC* pDC) 
{
	// dont erase background
	return FALSE;
}


void CDynDialog::CreateEdit( const CRect& rItemRect, const char* szText, bool bSpinner )
{
	if( m_pEditCtrl )
		OnKillfocusEditLabel();

	CRect	rEditRect = rItemRect;
	rEditRect.DeflateRect( 1, 1, 2, 2 );
	rEditRect.OffsetRect( 1, 1 );

	if( bSpinner )
		rEditRect.right -= SPINNER_WIDTH;

	// Create edit control
	m_pEditCtrl = new CEdit;
	if( !m_pEditCtrl->Create( WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, rEditRect, this, IDC_EDITLABEL ) ) {
		delete m_pEditCtrl;
		m_pEditCtrl = 0;
		return;
	}

	m_pEditCtrl->SetFont( &m_rThinFont );
	m_pEditCtrl->SetWindowText( szText );
	m_pEditCtrl->SetSel( 0, -1 );	// select all text
	m_pEditCtrl->SetFocus();
}


void
CDynDialog::SetSpinnerTrack( float32 f32StartVal, float32 f32Inc, float32 f32IncSign, int32 i32StartY )
{
	m_f32TrackStartVal = f32StartVal;
	m_f32TrackInc = f32Inc;
	m_f32TrackIncSign = f32IncSign;
	m_i32TrackStartY = i32StartY;
	SetCapture();

	if( m_uiTimerID ) {
		KillTimer( m_uiTimerID );
		m_uiTimerID = 0;
	}

	m_i32TimerCount = 0;
	m_uiTimerID = SetTimer( 1, 250, NULL );
}

void
CDynDialog::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// If we are editing a label, just kill the focus.
	if( m_pEditCtrl ) {
		OnKillfocusEditLabel();
		return;
	}

	// mouse has not moved
	m_bTrackMoved = false;

	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();

	CString		sValue, sFormat;

	for( uint32 i = 0; i < m_rParams.size(); i++ ) {
		ParamI*	pParam = m_rParams[i].m_pParam;

		int32	i32TimeOffset = GetTimeOffset( pParam );

		if( pParam->get_type() == PARAM_TYPE_INT ) {
			if( m_rParams[i].m_pParam->get_style() == PARAM_STYLE_COMBOBOX ) {
				if( HitTestComboBox( point, m_rParams[i].m_rItemRects[0] ) != HITTEST_NONE ) {
					m_rParams[i].m_i32ActiveItem = ACTIVEITEM_COMBO;
					m_pHitItem = m_rParams[i].m_pParam;
					m_i32HitItem = i;
					m_i32HitSubItem = 0;
					Invalidate();
					break;
				}
			}
			else {
				int32	i32Hit = HitTestEditBoxWithSpinner( point, m_rParams[i].m_rItemRects[0] );
				if( i32Hit != HITTEST_NONE ) {
					// save current state
					UndoC*	pUndo = new UndoC( "Edit Parameter" );
					UndoC*	pOldUndo = pParam->begin_editing( pUndo );
					pParam->end_editing( pOldUndo );
					pDoc->GetUndoManager()->push( pUndo );
					pDoc->SetModifiedFlag();

					ParamIntC*	pParamInt = (ParamIntC*)pParam;
					int32		i32Val;
					pParamInt->get_val( i32Time + i32TimeOffset, i32Val );

					pDoc->BeginDeferHandleParamNotify();

					if( i32Hit == HITTEST_SPINNERUP ) {
						m_rParams[i].m_i32ActiveItem = ACTIVEITEM_UP_X;
						m_pHitItem = m_rParams[i].m_pParam;
						m_i32HitItem = i;
						m_i32HitSubItem = 0;
						SetSpinnerTrack( (float32)i32Val, pParamInt->get_increment(), 1.0f, point.y );
						Invalidate();
						break;
					}
					else if( i32Hit == HITTEST_SPINNERDOWN ) {
						m_rParams[i].m_i32ActiveItem = ACTIVEITEM_DOWN_X;
						m_pHitItem = m_rParams[i].m_pParam;
						m_i32HitItem = i;
						m_i32HitSubItem = 0;
						SetSpinnerTrack( (float32)i32Val, pParamInt->get_increment(), -1.0f, point.y );
						Invalidate();
						break;
					}
					else if( i32Hit == HITTEST_EDITBOX ) {
						m_pEditingItem = m_rParams[i].m_pParam;
						m_i32EditingItem = i;
						m_i32EditingSubItem = 0;
						sValue.Format( "%d", i32Val );
						CreateEdit( m_rParams[i].m_rItemRects[0], sValue, true );
						break;
					}
				}
			}
		}
		else if( pParam->get_type() == PARAM_TYPE_FLOAT ) {
			int32	i32Hit = HitTestEditBoxWithSpinner( point, m_rParams[i].m_rItemRects[0] );
			if( i32Hit != HITTEST_NONE ) {
				// save current state
				UndoC*	pUndo = new UndoC( "Edit Parameter" );
				UndoC*	pOldUndo = pParam->begin_editing( pUndo );
				pParam->end_editing( pOldUndo );
				pDoc->GetUndoManager()->push( pUndo );
				pDoc->SetModifiedFlag();

				ParamFloatC*	pParamFloat = (ParamFloatC*)pParam;
				float32			f32Val;
				float32			f32Scale = 1.0f;
				if( pParam->get_style() & PARAM_STYLE_PERCENT ) 
					f32Scale = 100.0f;
				pParamFloat->get_val( i32Time + i32TimeOffset, f32Val );

				pDoc->BeginDeferHandleParamNotify();

				if( i32Hit == HITTEST_SPINNERUP ) {
					m_rParams[i].m_i32ActiveItem = ACTIVEITEM_UP_X;
					m_pHitItem = m_rParams[i].m_pParam;
					m_i32HitItem = i;
					m_i32HitSubItem = 0;
					SetSpinnerTrack( f32Val, pParamFloat->get_increment(), 1, point.y );
					Invalidate();
					break;
				}
				else if( i32Hit == HITTEST_SPINNERDOWN ) {
					m_rParams[i].m_i32ActiveItem = ACTIVEITEM_DOWN_X;
					m_pHitItem = m_rParams[i].m_pParam;
					m_i32HitItem = i;
					m_i32HitSubItem = 0;
					SetSpinnerTrack( f32Val, pParamFloat->get_increment(), -1, point.y );
					Invalidate();
					break;
				}
				else if( i32Hit == HITTEST_EDITBOX ) {
					m_pEditingItem = m_rParams[i].m_pParam;
					m_i32EditingItem = i;
					m_i32EditingSubItem = 0;
					sFormat.Format( "%%.%df", (int32)__max( -floor( log10( pParamFloat->get_increment() * f32Scale ) ), 0 ) );
					sValue.Format( sFormat, f32Val * f32Scale );
					CreateEdit( m_rParams[i].m_rItemRects[0], sValue, true );
					break;
				}
			}
		}
		else if( pParam->get_type() == PARAM_TYPE_VECTOR2 ) {
			int32	i32Lut[4] = { ACTIVEITEM_UP_X, ACTIVEITEM_DOWN_X, ACTIVEITEM_UP_Y, ACTIVEITEM_DOWN_Y };

			for( uint32 j = 0; j < 2; j++ ) {
				int32	i32Hit = HitTestEditBoxWithSpinner( point, m_rParams[i].m_rItemRects[j] );
				if( i32Hit != HITTEST_NONE ) {

					ParamVector2C*	pParamVec2 = (ParamVector2C*)pParam;
					Vector2C		rVal;
					float32			f32Scale = 1.0f;
					if( pParamVec2->get_style() & PARAM_STYLE_PERCENT ) 
						f32Scale = 100.0f;
					pParamVec2->get_val( i32Time + i32TimeOffset, rVal );

					pDoc->BeginDeferHandleParamNotify();

					if( i32Hit == HITTEST_SPINNERUP ) {
						m_rParams[i].m_i32ActiveItem = i32Lut[j * 2];
						m_pHitItem = m_rParams[i].m_pParam;
						m_i32HitItem = i;
						m_i32HitSubItem = j;
						SetSpinnerTrack( rVal[j], pParamVec2->get_increment(), 1, point.y );
						Invalidate();
						break;
					}
					else if( i32Hit == HITTEST_SPINNERDOWN ) {
						m_rParams[i].m_i32ActiveItem = i32Lut[j * 2 + 1];
						m_pHitItem = m_rParams[i].m_pParam;
						m_i32HitItem = i;
						m_i32HitSubItem = j;
						SetSpinnerTrack( rVal[j], pParamVec2->get_increment(), -1, point.y );
						Invalidate();
						break;
					}
					else if( i32Hit == HITTEST_EDITBOX ) {
						m_pEditingItem = m_rParams[i].m_pParam;
						m_i32EditingItem = i;
						m_i32EditingSubItem = j;
						sFormat.Format( "%%.%df", (int32)__max( -floor( log10( pParamVec2->get_increment() * f32Scale ) ), 0 ) );
						sValue.Format( sFormat, rVal[j] * f32Scale );
						CreateEdit( m_rParams[i].m_rItemRects[j], sValue, true );
						break;
					}
				}
			}
		}
		else if( pParam->get_type() == PARAM_TYPE_VECTOR3 ) {
			int32	i32Lut[6] = { ACTIVEITEM_UP_X, ACTIVEITEM_DOWN_X, ACTIVEITEM_UP_Y, ACTIVEITEM_DOWN_Y, ACTIVEITEM_UP_Z, ACTIVEITEM_DOWN_Z };
			for( uint32 j = 0; j < 3; j++ ) {
				int32	i32Hit = HitTestEditBoxWithSpinner( point, m_rParams[i].m_rItemRects[j] );
				if( i32Hit != HITTEST_NONE ) {

					ParamVector3C*	pParamVec3 = (ParamVector3C*)pParam;
					Vector3C		rVal;
					float32			f32Scale = 1.0f;
					if( pParamVec3->get_style() & PARAM_STYLE_PERCENT ) 
						f32Scale = 100.0f;
					pParamVec3->get_val( i32Time + i32TimeOffset, rVal );

					pDoc->BeginDeferHandleParamNotify();

					if( i32Hit == HITTEST_SPINNERUP ) {
						m_rParams[i].m_i32ActiveItem = i32Lut[j * 2];
						m_pHitItem = m_rParams[i].m_pParam;
						m_i32HitItem = i;
						m_i32HitSubItem = j;
						SetSpinnerTrack( rVal[j], pParamVec3->get_increment(), 1, point.y );
						Invalidate();
						break;
					}
					else if( i32Hit == HITTEST_SPINNERDOWN ) {
						m_rParams[i].m_i32ActiveItem = i32Lut[j * 2 + 1];
						m_pHitItem = m_rParams[i].m_pParam;
						m_i32HitItem = i;
						m_i32HitSubItem = j;
						SetSpinnerTrack( rVal[j], pParamVec3->get_increment(), -1, point.y );
						Invalidate();
						break;
					}
					else if( i32Hit == HITTEST_EDITBOX ) {
						m_pEditingItem = m_rParams[i].m_pParam;
						m_i32EditingItem = i;
						m_i32EditingSubItem = j;
						sFormat.Format( "%%.%df", (int32)__max( -floor( log10( pParamVec3->get_increment() * f32Scale ) ), 0 ) );
						sValue.Format( sFormat, rVal[j] * f32Scale );
						CreateEdit( m_rParams[i].m_rItemRects[j], sValue, true );
						break;
					}
				}
			}
		}
		else if( pParam->get_type() == PARAM_TYPE_COLOR ) {
			// empty
			if( m_rParams[i].m_rItemRects[0].PtInRect( point ) ) {
				m_pHitItem = m_rParams[i].m_pParam;
				m_i32HitItem = i;
				m_i32HitSubItem = 0;
				break;
			}
		}
		else if( pParam->get_type() == PARAM_TYPE_TEXT ) {
			int32	i32Hit = HitTestEditBox( point, m_rParams[i].m_rItemRects[0] );
			if( i32Hit != HITTEST_NONE ) {
				// save current state
				UndoC*	pUndo = new UndoC( "Edit Parameter" );
				UndoC*	pOldUndo = pParam->begin_editing( pUndo );
				pParam->end_editing( pOldUndo );
				pDoc->GetUndoManager()->push( pUndo );
				pDoc->SetModifiedFlag();

				if( i32Hit == HITTEST_EDITBOX ) {
					m_pEditingItem = m_rParams[i].m_pParam;
					m_i32EditingItem = i;
					m_i32EditingSubItem = 0;
					ParamTextC*	pParamText = (ParamTextC*)pParam;
					CreateEdit( m_rParams[i].m_rItemRects[0], pParamText->get_val( i32Time + i32TimeOffset ), true );
					break;
				}
			}
		}
		else if( pParam->get_type() == PARAM_TYPE_FILE ) {
			if( HitTestComboBox( point, m_rParams[i].m_rItemRects[0] ) != HITTEST_NONE ) {
				// save current state
				UndoC*	pUndo = new UndoC( "Edit Parameter" );
				UndoC*	pOldUndo = pParam->begin_editing( pUndo );
				pParam->end_editing( pOldUndo );
				pDoc->GetUndoManager()->push( pUndo );
				pDoc->SetModifiedFlag();

				m_rParams[i].m_i32ActiveItem = ACTIVEITEM_COMBO;
				m_pHitItem = m_rParams[i].m_pParam;
				m_i32HitItem = i;
				m_i32HitSubItem = 0;
				Invalidate( FALSE );
				break;
			}
		}
	}

	CDialog::OnLButtonDown(nFlags, point);
}


void
CDynDialog::ParamIntCombo( const CPoint& rPt, int32 i32MinWidth, ParamIntC* pParam, int32 i32Time )
{
	CFlatPopupMenu	rMenu;
	rMenu.SetFont( "Arial" );
	rMenu.SetFontSize( 8 );
	rMenu.SetMinWidth( i32MinWidth - 1 );
	rMenu.SetColor( CFlatPopupMenu::colorBackground, ::GetSysColor( COLOR_WINDOW ) );
	rMenu.Create( AfxGetInstanceHandle() );

	for( uint32 i = 0; i < pParam->get_label_count(); i++ )
		rMenu.AppendItem( 0, pParam->get_label_name( i ), i + 1 );

	CPoint	rPoint = rPt;
	ClientToScreen( &rPoint );
	int32	i32Id = rMenu.Track( rPoint.x, rPoint.y - 1, NULL, true );

	if( i32Id ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		pDoc->HandleParamNotify( pParam->set_val( i32Time, pParam->get_label_value( i32Id - 1 ) ) );
	}
}

void
CDynDialog::ParamFileCombo( const CPoint& rPt, int32 i32MinWidth, ParamFileC* pParam, int32 i32Time )
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	FileListC*	pFileList = pDoc->GetFileList();

	CFlatPopupMenu	rMenu;
	rMenu.SetFont( "Arial" );
	rMenu.SetFontSize( 8 );
	rMenu.SetMinWidth( i32MinWidth - 1 );
	rMenu.SetColor( CFlatPopupMenu::colorBackground, ::GetSysColor( COLOR_WINDOW ) );
	rMenu.Create( AfxGetInstanceHandle() );


	rMenu.AppendItem( 0, "<Empty>", 0xffffffff );

	std::string		sStr;
	char			szFname[_MAX_FNAME];
	char			szExt[_MAX_EXT];
	FileHandleC*	pParamHandle = 0; //pParam->get_file();

	for( uint32 i = 0; i < pFileList->get_file_count(); i++ ) {

		FileHandleC*	pHandle = pFileList->get_file( i );
		ImportableI*	pImp = 0;

		if( !pHandle )
			continue;
		
		pImp = pHandle->get_importable();
		if( !pImp )
			continue;

		_splitpath( pImp->get_filename(), 0, 0, szFname, szExt );
		sStr = szFname;
		sStr += szExt;
	
		if( (pParam->get_class_filter() == NULL_CLASSID ||
			 pParam->get_class_filter() == pImp->get_class_id()) &&
			(pParam->get_super_class_filter() == NULL_SUPERCLASS ||
			pParam->get_super_class_filter() == pImp->get_super_class_id()) ) {

			rMenu.AppendItem( 0, sStr.c_str(), i + 1 );
		}
	}


	CPoint	rPoint = rPt;
	ClientToScreen( &rPoint );
	int32	i32Id = rMenu.Track( rPoint.x, rPoint.y - 1, NULL, true );

	if( i32Id ) {

		FileHandleC*	pHandle = 0;
		if( i32Id == 0xffffffff )
			pHandle = 0;
		else 
			pHandle = pFileList->get_file( i32Id - 1 );

//		pDoc->HandleParamNotify( pParam->set_file( pHandle ) );
	}
}

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

	if( m_uiTimerID ) {
		KillTimer( m_uiTimerID );
		m_uiTimerID = 0;
	}

	if( m_i32HitItem != -1 && m_pHitItem != 0 ) {
		if( m_i32HitItem >= 0 && m_i32HitItem < m_rParams.size() ) {

			// user pressed mouse, but did not move it, and the timer
			// didnt trigger yet --> just mouse press.
			bool	bSetSpinnerVal = false;
			if( !m_bTrackMoved && !m_i32TimerCount ) {
				m_f32TrackStartVal += m_f32TrackInc * m_f32TrackIncSign;
				bSetSpinnerVal = true;
			}

			CDemopajaDoc*	pDoc = GetDoc();
			ASSERT_VALID( pDoc );
			int32	i32Time = pDoc->GetTimecursor();

			ParamI*	pParam = m_pHitItem; //m_rParams[m_i32HitItem].m_pParam;

			int32	i32TimeOffset = GetTimeOffset( pParam );

			if( pParam->get_type() == PARAM_TYPE_INT ) {
				m_rParams[m_i32HitItem].m_i32ActiveItem = ACTIVEITEM_NONE;
				if( pParam->get_style() == PARAM_STYLE_COMBOBOX ) {
					ParamIntCombo( CPoint( m_rParams[m_i32HitItem].m_rItemRects[0].left, m_rParams[m_i32HitItem].m_rItemRects[0].bottom ), m_rParams[m_i32HitItem].m_rItemRects[0].Width(), (ParamIntC*)pParam, i32Time + i32TimeOffset );
				}
				else {
					if( bSetSpinnerVal ) {
						ParamIntC*	pParamInt = (ParamIntC*)pParam;
						pDoc->HandleParamNotify( pParamInt->set_val( i32Time + i32TimeOffset, (int32)m_f32TrackStartVal ) );
						pDoc->EndDeferHandleParamNotify();
					}
				}
			}
			else if( pParam->get_type() == PARAM_TYPE_FLOAT ) {
				m_rParams[m_i32HitItem].m_i32ActiveItem = ACTIVEITEM_NONE;
				if( bSetSpinnerVal ) {
					ParamFloatC*	pParamFloat = (ParamFloatC*)pParam;
					pDoc->HandleParamNotify( pParamFloat->set_val( i32Time + i32TimeOffset, m_f32TrackStartVal ) );
					pDoc->EndDeferHandleParamNotify();
				}
			}
			else if( pParam->get_type() == PARAM_TYPE_VECTOR2 ) {
				m_rParams[m_i32HitItem].m_i32ActiveItem = ACTIVEITEM_NONE;
				if( bSetSpinnerVal ) {
					ParamVector2C*	pParamVec2 = (ParamVector2C*)pParam;
					Vector2C	rVal;
					pParamVec2->get_val( i32Time + i32TimeOffset, rVal );
					rVal[m_i32HitSubItem] = m_f32TrackStartVal;
					pDoc->HandleParamNotify( pParamVec2->set_val( i32Time + i32TimeOffset, rVal ) );
					pDoc->EndDeferHandleParamNotify();
				}
			}
			else if( pParam->get_type() == PARAM_TYPE_VECTOR3 ) {
				m_rParams[m_i32HitItem].m_i32ActiveItem = ACTIVEITEM_NONE;
				if( bSetSpinnerVal ) {
					ParamVector3C*	pParamVec3 = (ParamVector3C*)pParam;
					Vector3C	rVal;
					pParamVec3->get_val( i32Time + i32TimeOffset, rVal );
					rVal[m_i32HitSubItem] = m_f32TrackStartVal;
					pDoc->HandleParamNotify( pParamVec3->set_val( i32Time + i32TimeOffset, rVal ) );
					pDoc->EndDeferHandleParamNotify();
				}
			}
			else if( pParam->get_type() == PARAM_TYPE_COLOR ) {

				CColorTypeInDlg		rDlg;

				rDlg.m_pParam = (ParamColorC*)pParam;
				rDlg.m_i32Time = i32Time + i32TimeOffset;

				// save current state
				UndoC*	pUndo = new UndoC( "Edit Parameter" );
				UndoC*	pOldUndo = pParam->begin_editing( pUndo );
				pParam->end_editing( pOldUndo );
				pDoc->GetUndoManager()->push( pUndo );
				pDoc->SetModifiedFlag();

				if( rDlg.DoModal() != IDOK ) {
					pDoc->GetUndoManager()->undo();
				}

			}
			else if( pParam->get_type() == PARAM_TYPE_TEXT ) {
				m_rParams[m_i32HitItem].m_i32ActiveItem = ACTIVEITEM_NONE;
			}
			else if( pParam->get_type() == PARAM_TYPE_FILE ) {
				m_rParams[m_i32HitItem].m_i32ActiveItem = ACTIVEITEM_NONE;
				ParamFileCombo( CPoint( m_rParams[m_i32HitItem].m_rItemRects[0].left, m_rParams[m_i32HitItem].m_rItemRects[0].bottom ), m_rParams[m_i32HitItem].m_rItemRects[0].Width(), (ParamFileC*)pParam, i32Time + i32TimeOffset );
			}

			pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );

			m_pHitItem = 0;
			m_i32HitItem = -1;
			m_i32HitSubItem = -1;
		}
	}

	CDialog::OnLButtonUp(nFlags, point);
}

void
CDynDialog::OnMouseMove(UINT nFlags, CPoint point) 
{
	if( nFlags & MK_LBUTTON && GetCapture() == this ) {

		if( m_uiTimerID ) {
			KillTimer( m_uiTimerID );
			m_uiTimerID = 0;
		}

		m_bTrackMoved = true;

		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		int32	i32Time = pDoc->GetTimecursor();

		if( m_pHitItem && m_i32HitItem >= 0 && m_i32HitItem < m_rParams.size() ) {
			ParamI*	pParam = m_pHitItem; //m_rParams[m_i32HitItem].m_pParam;
			int32	i32TimeOffset = GetTimeOffset( pParam );
			float32	f32Val = m_f32TrackStartVal - ((float32)point.y - m_i32TrackStartY) * m_f32TrackInc;

			if( pParam->get_type() == PARAM_TYPE_INT ) {
				ParamIntC*	pParamInt = (ParamIntC*)pParam;
				pDoc->HandleParamNotify( pParamInt->set_val( i32Time + i32TimeOffset, (int32)f32Val ) );
			}
			else if( pParam->get_type() == PARAM_TYPE_FLOAT ) {
				ParamFloatC*	pParamFloat = (ParamFloatC*)pParam;
				pDoc->HandleParamNotify( pParamFloat->set_val( i32Time + i32TimeOffset, f32Val ) );
			}
			else if( pParam->get_type() == PARAM_TYPE_VECTOR2 ) {
				ParamVector2C*	pParamVec2 = (ParamVector2C*)pParam;
				Vector2C	rVal;
				pParamVec2->get_val( i32Time + i32TimeOffset, rVal );
				rVal[m_i32HitSubItem] = f32Val;
				pDoc->HandleParamNotify( pParamVec2->set_val( i32Time + i32TimeOffset, rVal ) );
			}
			else if( pParam->get_type() == PARAM_TYPE_VECTOR3 ) {
				ParamVector3C*	pParamVec3 = (ParamVector3C*)pParam;
				Vector3C	rVal;
				pParamVec3->get_val( i32Time + i32TimeOffset, rVal );
				rVal[m_i32HitSubItem] = f32Val;
				pDoc->HandleParamNotify( pParamVec3->set_val( i32Time + i32TimeOffset, rVal ) );
			}
			pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
		}
	}

	CDialog::OnMouseMove(nFlags, point);
}

void CDynDialog::CalcItemRects()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();

	CRect	rRect;
	GetClientRect( rRect );

	int32		i32CntWidth;
	int32		i32MaxCntWidth;
	int32		i32CaptionWidth;

	i32CaptionWidth = rRect.Width() / 4;
	i32CntWidth = rRect.Width() - i32CaptionWidth - 2 * LABEL_WIDTH - 2 * PADDING;
	i32MaxCntWidth = i32CntWidth;
	if( i32CntWidth > MAX_EDIT_WIDTH )
		i32CntWidth = MAX_EDIT_WIDTH;

	CRect	rClipRect;

	CBrush	rDarkBrush( ::GetSysColor( COLOR_BTNSHADOW ) );

	for( uint32 i = 0; i < m_rParams.size(); i++ ) {
		ParamI*	pParam = m_rParams[i].m_pParam;

		if( !pParam )
			continue;

		int32	i32X = LEFT_INDENT;
		int32	i32Y = m_rParams[i].m_i32Y;

		switch( pParam->get_type() ) {
		case PARAM_TYPE_INT:
			{
				CRect	rItemRect;
				rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
				rItemRect.right = rItemRect.left + i32CntWidth;
				rItemRect.top = i32Y;
				rItemRect.bottom = i32Y + EDIT_HEIGHT;
				m_rParams[i].m_rItemRects[0] = rItemRect;
				m_rParams[i].m_i32RectCount = 1;
			}
			break;

		case PARAM_TYPE_FLOAT:
			{
				CRect	rItemRect;
				rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
				rItemRect.right = rItemRect.left + i32CntWidth;
				rItemRect.top = i32Y;
				rItemRect.bottom = i32Y + EDIT_HEIGHT;
				m_rParams[i].m_rItemRects[0] = rItemRect;
				m_rParams[i].m_i32RectCount = 1;
			}
			break;

		case PARAM_TYPE_VECTOR2:
			{
				for( uint32 j = 0; j < 2; j++ ) {
					CRect	rItemRect;
					rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
					rItemRect.right = rItemRect.left + i32CntWidth;
					rItemRect.top = i32Y + j * (EDIT_HEIGHT + COMP_SPACING);
					rItemRect.bottom = rItemRect.top + EDIT_HEIGHT;
					m_rParams[i].m_rItemRects[j] = rItemRect;
				}
				m_rParams[i].m_i32RectCount = 2;
			}
			break;

		case PARAM_TYPE_VECTOR3:
			{
				for( uint32 j = 0; j < 3; j++ ) {
					CRect	rItemRect;
					rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
					rItemRect.right = rItemRect.left + i32CntWidth;
					rItemRect.top = i32Y + j * (EDIT_HEIGHT + COMP_SPACING);
					rItemRect.bottom = rItemRect.top + EDIT_HEIGHT;
					m_rParams[i].m_rItemRects[j] = rItemRect;
				}
				m_rParams[i].m_i32RectCount = 3;
			}
			break;

		case PARAM_TYPE_COLOR:
			{
				CRect	rItemRect;
				rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
				rItemRect.right = rItemRect.left + COLORPICKER_WIDTH;
				rItemRect.top = i32Y;
				rItemRect.bottom = i32Y + EDIT_HEIGHT;
				m_rParams[i].m_rItemRects[0] = rItemRect;
				m_rParams[i].m_i32RectCount = 1;
			}
			break;

		case PARAM_TYPE_TEXT:
			{
				CRect	rItemRect;
				rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
				rItemRect.right = rItemRect.left + i32MaxCntWidth;
				rItemRect.top = i32Y;
				rItemRect.bottom = i32Y + EDIT_HEIGHT;
				m_rParams[i].m_rItemRects[0] = rItemRect;
				m_rParams[i].m_i32RectCount = 1;
			}
			break;

		case PARAM_TYPE_FILE:
			{
				CRect	rItemRect;
				rItemRect.left = i32X + i32CaptionWidth + LABEL_WIDTH + PADDING;
				rItemRect.right = rItemRect.left + i32MaxCntWidth - EDIT_HEIGHT;
				rItemRect.top = i32Y;
				rItemRect.bottom = i32Y + EDIT_HEIGHT;
				m_rParams[i].m_rItemRects[0] = rItemRect;
				m_rParams[i].m_i32RectCount = 1;
			}
			break;
		}
	}
}

void CDynDialog::OnKillfocusEditLabel()
{
	if( !m_pEditCtrl )
		return;

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

	// delete the edit box
	m_pEditCtrl->DestroyWindow();
	delete m_pEditCtrl;
	m_pEditCtrl = 0;

	pDoc->EndDeferHandleParamNotify();

	// update window
	Invalidate( FALSE );

	m_pEditingItem = 0;
	m_i32EditingItem = -1;
}

void CDynDialog::OnChangeEditLabel()
{
	if( !m_pEditCtrl )
		return;

	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );
	int32	i32Time = pDoc->GetTimecursor();

	CString	sStr;
	m_pEditCtrl->GetWindowText( sStr );

	if( m_pEditingItem && m_i32EditingItem >= 0 && m_i32EditingItem < m_rParams.size() ) {
		ParamI*	pParam = m_pEditingItem; //m_rParams[m_i32EditingItem].m_pParam;

		int32	i32TimeOffset = GetTimeOffset( pParam );

		if( pParam->get_type() == PARAM_TYPE_INT ) {
			ParamIntC*	pParamInt = (ParamIntC*)pParam;
			int32	i32Val = _ttoi( sStr );
			pDoc->HandleParamNotify( pParamInt->set_val( i32Time + i32TimeOffset, i32Val ) );
		}
		else if( pParam->get_type() == PARAM_TYPE_FLOAT ) {
			ParamFloatC*	pParamFloat = (ParamFloatC*)pParam;
			float32	f32Val = _tcstod( sStr, NULL );
			if( pParam->get_style() & PARAM_STYLE_PERCENT ) 
				f32Val /= 100.0f;
			pDoc->HandleParamNotify( pParamFloat->set_val( i32Time + i32TimeOffset, f32Val ) );
		}
		else if( pParam->get_type() == PARAM_TYPE_TEXT ) {
			ParamTextC*	pParamText = (ParamTextC*)pParam;
			pDoc->HandleParamNotify( pParamText->set_val( i32Time + i32TimeOffset, sStr ) );
		}
		else if( pParam->get_type() == PARAM_TYPE_VECTOR2 ) {
			ParamVector2C*	pParamVec2 = (ParamVector2C*)pParam;
			Vector2C	rVal;
			pParamVec2->get_val( i32Time + i32TimeOffset, rVal );
			rVal[m_i32EditingSubItem] = _tcstod( sStr, NULL );
			if( pParamVec2->get_style() & PARAM_STYLE_PERCENT ) 
				rVal[m_i32EditingSubItem] /= 100.0f;
			pDoc->HandleParamNotify( pParamVec2->set_val( i32Time + i32TimeOffset, rVal ) );
		}
		else if( pParam->get_type() == PARAM_TYPE_VECTOR3 ) {
			ParamVector3C*	pParamVec3 = (ParamVector3C*)pParam;
			Vector3C	rVal;
			pParamVec3->get_val( i32Time + i32TimeOffset, rVal );
			rVal[m_i32EditingSubItem] = _tcstod( sStr, NULL );
			if( pParamVec3->get_style() & PARAM_STYLE_PERCENT ) 
				rVal[m_i32EditingSubItem] /= 100.0f;
			pDoc->HandleParamNotify( pParamVec3->set_val( i32Time + i32TimeOffset, rVal ) );
		}
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
	}

}

void CDynDialog::OnTimer(UINT nIDEvent)
{
	if( nIDEvent == 1 ) {

		m_i32TimerCount++;

		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		int32	i32Time = pDoc->GetTimecursor();

		if( m_pHitItem != 0 && m_i32HitItem >= 0 && m_i32HitItem < m_rParams.size() ) {

			ParamI*	pParam = m_pHitItem; //m_rParams[m_i32HitItem].m_pParam;
			int32	i32TimeOffset = GetTimeOffset( pParam );

			m_f32TrackStartVal += m_f32TrackInc * m_f32TrackIncSign;
//			float32	f32Val = m_f32TrackStartVal - ((float32)point.y - m_i32TrackStartY) * m_f32TrackInc;

			if( pParam->get_type() == PARAM_TYPE_INT ) {
				ParamIntC*	pParamInt = (ParamIntC*)pParam;
				pDoc->HandleParamNotify( pParamInt->set_val( i32Time + i32TimeOffset, (int32)m_f32TrackStartVal ) );
			}
			else if( pParam->get_type() == PARAM_TYPE_FLOAT ) {
				ParamFloatC*	pParamFloat = (ParamFloatC*)pParam;
				pDoc->HandleParamNotify( pParamFloat->set_val( i32Time + i32TimeOffset, m_f32TrackStartVal ) );
			}
			else if( pParam->get_type() == PARAM_TYPE_VECTOR2 ) {
				ParamVector2C*	pParamVec2 = (ParamVector2C*)pParam;
				Vector2C	rVal;
				pParamVec2->get_val( i32Time, rVal );
				rVal[m_i32HitSubItem] = m_f32TrackStartVal;
				pDoc->HandleParamNotify( pParamVec2->set_val( i32Time + i32TimeOffset, rVal ) );
			}
			else if( pParam->get_type() == PARAM_TYPE_VECTOR3 ) {
				ParamVector3C*	pParamVec3 = (ParamVector3C*)pParam;
				Vector3C	rVal;
				pParamVec3->get_val( i32Time, rVal );
				rVal[m_i32HitSubItem] = m_f32TrackStartVal;
				pDoc->HandleParamNotify( pParamVec3->set_val( i32Time + i32TimeOffset, rVal ) );
			}
			pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
		}
	}
}

int32 CDynDialog::GetTimeOffset( ParamI* pParam )
{
	GizmoI*		pGizmo = 0;
	EffectI*	pEffect = 0;
	LayerC*		pLayer = 0;

	int32	i32TimeOffset = 0;

	pGizmo = pParam->get_parent();
	if( pGizmo ) {
		pEffect = pGizmo->get_parent();
		if( pEffect ) {
			TimeSegmentC*	pEffectSegment = pEffect->get_timesegment();
			i32TimeOffset -= pEffectSegment->get_segment_start();

			pLayer = pEffect->get_parent();
			if( pLayer ) {
				TimeSegmentC*	pLayerSegment = pLayer->get_timesegment();
				i32TimeOffset -= pLayerSegment->get_segment_start();
			}
		}
	}

	return i32TimeOffset;
}

LRESULT CDynDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	if( message == WM_LBUTTONDBLCLK ) {
		message = WM_LBUTTONDOWN;
	}	

	return CDialog::DefWindowProc(message, wParam, lParam);
}

void CDynDialog::Redraw( uint32 ui32Flags )
{
	m_ui32RedrawFlags = ui32Flags;
	Invalidate( FALSE );
}