// ColorTypeInDlg.cpp : implementation file
//

#include "stdafx.h"
#include "demopaja.h"
#include "demopajadoc.h"
#include "ColorTypeInDlg.h"
#include "DIB.h"
#include <stdlib.h>
#include "FlatPopUpMenu.h"
#include "ColorSwatchSetC.h"

using namespace PajaTypes;
using namespace Composition;


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

/////////////////////////////////////////////////////////////////////////////
// CColorTypeInDlg dialog


void
AFXAPI
CColorTypeInDlg::DDX_MyText( CDataExchange* pDX, int nIDC, float& value, float range )
{
	TCHAR	szBuffer[32];
	HWND	hWndCtrl = pDX->PrepareEditCtrl( nIDC );

	if( pDX->m_bSaveAndValidate ) {
		// to value
		szBuffer[0] = 0;
		::GetWindowText( hWndCtrl, szBuffer, 30 );
		value = _tcstod( szBuffer, NULL ) / range;
	}
	else {
		// from value
		_sntprintf( szBuffer, 31, "%d", (int32)(value * range) );
		::SetWindowText( hWndCtrl, szBuffer );
	}
}


CColorTypeInDlg::CColorTypeInDlg(CWnd* pParent /*=NULL*/) :
	CDialog(CColorTypeInDlg::IDD, pParent),
	m_f32Inc( 0.01f ),
	m_hCursor( 0 ),
	m_iMode( MODE_RGB ),
	m_iTracking( TRACK_NONE ),
	m_pParam( 0 )
{
	//{{AFX_DATA_INIT(CColorTypeInDlg)
	m_f32ValueA = 0.0f;
	m_f32ValueB = 0.0f;
	m_f32ValueG = 0.0f;
	m_f32ValueR = 0.0f;
	//}}AFX_DATA_INIT
}


static
inline
void
clamp_value( float32& f32Value, float32 f32Min, float32 f32Max )
{
	if( f32Value < f32Min )
		f32Value = f32Min;
	if( f32Value > f32Max )
		f32Value = f32Max;
}

void CColorTypeInDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CColorTypeInDlg)
	DDX_Control(pDX, IDC_BUTTON_SWATCHMENU, m_rButtonSwatchmenu);
	DDX_Control(pDX, IDC_SCROLLBAR_SWATCH, m_rScrollbarSwatch);
	DDX_Control(pDX, IDC_SWATCHES, m_rStaticSwatch);
	DDX_Control(pDX, IDOK, m_rOk);
	DDX_Control(pDX, IDCANCEL, m_rCancel);
	DDX_Control(pDX, IDC_SLIDERR, m_rSliderR);
	DDX_Control(pDX, IDC_SLIDERG, m_rSliderG);
	DDX_Control(pDX, IDC_SLIDERB, m_rSliderB);
	DDX_Control(pDX, IDC_SLIDERA, m_rSliderA);
	DDX_Control(pDX, IDC_STATIC_R, m_rStaticR);
	DDX_Control(pDX, IDC_STATIC_G, m_rStaticG);
	DDX_Control(pDX, IDC_STATIC_B, m_rStaticB);
	DDX_Control(pDX, IDC_COLOR, m_rColor);
	DDX_Control(pDX, IDC_NEWCOLOR, m_rNewColor);
	DDX_Control(pDX, IDC_EDITR, m_rEditR);
	DDX_Control(pDX, IDC_EDITB, m_rEditB);
	DDX_Control(pDX, IDC_EDITG, m_rEditG);
	DDX_Control(pDX, IDC_EDITA, m_rEditA);
	//}}AFX_DATA_MAP

	DDX_MyText(pDX, IDC_EDITA, m_f32ValueA, 255.0f);
	clamp_value( m_f32ValueA, 0, 1 );

	if( m_iMode == MODE_RGB ) {
		DDX_MyText( pDX, IDC_EDITR, m_f32ValueR, 255.0f );
		DDX_MyText( pDX, IDC_EDITG, m_f32ValueG, 255.0f );
		DDX_MyText( pDX, IDC_EDITB, m_f32ValueB, 255.0f );

		clamp_value( m_f32ValueR, 0, 1 );
		clamp_value( m_f32ValueG, 0, 1 );
		clamp_value( m_f32ValueB, 0, 1 );

		RgbToHsv( m_f32ValueR, m_f32ValueG, m_f32ValueR, m_f32ValueH, m_f32ValueS, m_f32ValueV );
	}
	else {
		if( !pDX->m_bSaveAndValidate )
			RgbToHsv( m_f32ValueR, m_f32ValueG, m_f32ValueB, m_f32ValueH, m_f32ValueS, m_f32ValueV );

		DDX_MyText( pDX, IDC_EDITR, m_f32ValueH, 359.0f );
		DDX_MyText( pDX, IDC_EDITG, m_f32ValueS, 255.0f );
		DDX_MyText( pDX, IDC_EDITB, m_f32ValueV, 255.0f );

		clamp_value( m_f32ValueH, 0, 1 );
		clamp_value( m_f32ValueS, 0, 1 );
		clamp_value( m_f32ValueV, 0, 1 );

		if( pDX->m_bSaveAndValidate )
			HsvToRgb( m_f32ValueH, m_f32ValueS, m_f32ValueV, m_f32ValueR, m_f32ValueG, m_f32ValueB );
	}
}


BEGIN_MESSAGE_MAP(CColorTypeInDlg, CDialog)
	//{{AFX_MSG_MAP(CColorTypeInDlg)
	ON_WM_PAINT()
	ON_WM_MOUSEMOVE()
	ON_WM_SETCURSOR()
	ON_EN_CHANGE(IDC_EDITR, OnChangeEditr)
	ON_EN_CHANGE(IDC_EDITG, OnChangeEditg)
	ON_EN_CHANGE(IDC_EDITB, OnChangeEditb)
	ON_EN_CHANGE(IDC_EDITA, OnChangeEdita)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_VSCROLL()
	ON_BN_CLICKED(IDC_BUTTON_SWATCHMENU, OnButtonSwatchmenu)
	ON_WM_RBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CColorTypeInDlg message handlers

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

	// Create imagelist
	if( !m_rImageList.Create( IDB_TRIPOINTER, 11, 1, RGB( 255, 0, 255 ) ) )
		return -1;

	// set RGB mode
	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();
	m_iMode = pApp->GetProfileInt( "Settings", "ColorPickerMode", MODE_RGB );

	// update dialog data
	ColorC	rColor;
	if( m_pParam )
		m_pParam->get_val( m_i32Time, rColor );
	else
		rColor = m_rColorValue;

	m_f32ValueR = rColor[0];
	m_f32ValueG = rColor[1];
	m_f32ValueB = rColor[2];
	m_f32ValueA = rColor[3];
	UpdateData( FALSE );

	CClientDC	rDC( this );
	if( !m_rDIB.Create( &rDC, IDB_COLORRAMP ) )
		return FALSE;

	if( m_iMode == MODE_RGB ) {
		// RGB
		m_rStaticR.SetWindowText( "R" );
		m_rStaticG.SetWindowText( "G" );
		m_rStaticB.SetWindowText( "B" );
	}
	else {
		// HSB
		m_rStaticR.SetWindowText( "H" );
		m_rStaticG.SetWindowText( "S" );
		m_rStaticB.SetWindowText( "B" );
	}
	
	m_rOk.SetFlat( FALSE );
	m_rCancel.SetFlat( FALSE );

	// 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_rBitmapMenu.LoadMappedBitmap( IDB_SWATCHMENU, 0, rColors, 3 ) )
		return -1;
	m_rButtonSwatchmenu.SetBitmaps( m_rBitmapMenu );
	m_rButtonSwatchmenu.SetFlat( TRUE );

	m_iScrollSwatchY = 0;

	UpdateColorSwatches();

	if( !m_sCaption.IsEmpty() )
		SetWindowText( m_sCaption );

	return TRUE;
}

void CColorTypeInDlg::UpdateColorSwatches()
{
	CDemopajaDoc*	pDoc = GetDoc();
	ASSERT_VALID( pDoc );

	ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();

	m_rSwatches.clear();

	for( uint32 i = 0; i < pSwatches->get_color_count(); i++ ) {
		ColorC		rCol = pSwatches->get_color( i );
		COLORREF	rSwatch = RGB( rCol[0] * 255, rCol[1] * 255, rCol[2] * 255 );
		m_rSwatches.push_back( rSwatch );
	}


	// Update scroll

	CRect	rSwatchRect = GetControlRect( m_rStaticSwatch);

	m_iSwatchRows = m_rSwatches.size() / 16;
	m_iSwatchSize = (rSwatchRect.Width() - 2) / 16;

	SCROLLINFO	rScrollInfo;
	rScrollInfo.cbSize = sizeof( SCROLLINFO );
	rScrollInfo.fMask = SIF_RANGE | SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS;
	rScrollInfo.nMin = 0;
	rScrollInfo.nMax = m_iSwatchRows * m_iSwatchSize + 2 * m_iSwatchSize + 2;
	rScrollInfo.nPage = rSwatchRect.Height();
	rScrollInfo.nPos = m_iScrollSwatchY;
	m_rScrollbarSwatch.SetScrollInfo( &rScrollInfo, TRUE );
}


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


	CBrush	rBlackBrush( RGB( 0, 0, 0 ) );
	CBrush	rWhiteBrush( RGB( 255, 255, 255 ) );

	CRect	rColorRect = GetControlRect( m_rNewColor );
	COLORREF	rColor = RGB( (int32)(m_f32ValueR * 255.0f), (int32)(m_f32ValueG * 255.0f), (int32)(m_f32ValueB * 255.0f) );
	rColorRect.DeflateRect( 1, 1 );
	dc.FrameRect( rColorRect, &rBlackBrush );
	rColorRect.DeflateRect( 1, 1 );
	dc.FrameRect( rColorRect, &rWhiteBrush );
	rColorRect.DeflateRect( 1, 1 );
	dc.FillSolidRect( rColorRect, rColor );


	CRect	rSliderRRect = GetControlRect( m_rSliderR );
	CRect	rSliderGRect = GetControlRect( m_rSliderG );
	CRect	rSliderBRect = GetControlRect( m_rSliderB );
	CRect	rSliderARect = GetControlRect( m_rSliderA );

	int32	i32A = (int32)(m_f32ValueA * 255.0f);

	uint32	i;
	int32	i32X;

	// Draw gradient
	if( m_iMode == MODE_RGB ) {
		int32	i32R = (int32)(m_f32ValueR * 255.0f);
		int32	i32G = (int32)(m_f32ValueG * 255.0f);
		int32	i32B = (int32)(m_f32ValueB * 255.0f);

		// Red
		for( i = 0; i < (rSliderRRect.Width() - 2) / 4; i++ ) {
			rColor = RGB( i * 255 / ((rSliderRRect.Width() - 2) / 4), i32G, i32B );
			dc.FillSolidRect( rSliderRRect.left + 1 + i * 4, rSliderRRect.top + 1, 4, rSliderRRect.Height() - 2, rColor );
		}

		dc.Draw3dRect( rSliderRRect.left - 1, rSliderRRect.top - 1, rSliderRRect.Width() + 2, rSliderRRect.Height() + 2,
			::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
		dc.FrameRect( rSliderRRect, &rBlackBrush );
	
		dc.FillSolidRect( rSliderRRect.left - 3, rSliderRRect.bottom + 1, rSliderRRect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
		i32X = rSliderRRect.left - 3 + i32R * (rSliderRRect.Width() - 4) / 255;
		m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderRRect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
			ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );

		// Green
		for( i = 0; i < (rSliderGRect.Width() - 2) / 4; i++ ) {
			rColor = RGB( i32R, i * 255 / ((rSliderRRect.Width() - 2) / 4), i32B );
			dc.FillSolidRect( rSliderGRect.left + 1 + i * 4, rSliderGRect.top + 1, 4, rSliderGRect.Height() - 2, rColor );
		}

		dc.Draw3dRect( rSliderGRect.left - 1, rSliderGRect.top - 1, rSliderGRect.Width() + 2, rSliderGRect.Height() + 2,
			::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
		dc.FrameRect( rSliderGRect, &rBlackBrush );
		
		dc.FillSolidRect( rSliderGRect.left - 3, rSliderGRect.bottom + 1, rSliderGRect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
		i32X = rSliderGRect.left - 3 + i32G * (rSliderGRect.Width() - 4) / 255;
		m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderGRect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
			ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );

		// Blue
		for( i = 0; i < (rSliderBRect.Width() - 2) / 4; i++ ) {
			rColor = RGB( i32R, i32G, i * 255 / ((rSliderRRect.Width() - 2) / 4) );
			dc.FillSolidRect( rSliderBRect.left + 1 + i * 4, rSliderBRect.top + 1, 4, rSliderBRect.Height() - 2, rColor );
		}

		dc.Draw3dRect( rSliderBRect.left - 1, rSliderBRect.top - 1, rSliderBRect.Width() + 2, rSliderBRect.Height() + 2,
			::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
		dc.FrameRect( rSliderBRect, &rBlackBrush );

		dc.FillSolidRect( rSliderBRect.left - 3, rSliderBRect.bottom + 1, rSliderBRect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
		i32X = rSliderBRect.left - 3 + i32B * (rSliderBRect.Width() - 4) / 255;
		m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderBRect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
			ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );
	}
	else {
		int32	i32H = (int32)(m_f32ValueH * 255.0f);
		int32	i32S = (int32)(m_f32ValueS * 255.0f);
		int32	i32V = (int32)(m_f32ValueV * 255.0f);

		float32	f32R, f32G, f32B;

		// Hue
		for( i = 0; i < (rSliderRRect.Width() - 2) / 2; i++ ) {
			HsvToRgb( (float32)i / (float32)((rSliderRRect.Width() - 2) / 2), m_f32ValueS, m_f32ValueV, f32R, f32G, f32B );
			rColor = RGB( (int32)(f32R * 255.0f), (int32)(f32G * 255.0f), (int32)(f32B * 255.0f) );
			dc.FillSolidRect( rSliderRRect.left + 1 + i * 2, rSliderRRect.top + 1, 2, rSliderRRect.Height() - 2, rColor );
		}

		dc.Draw3dRect( rSliderRRect.left - 1, rSliderRRect.top - 1, rSliderRRect.Width() + 2, rSliderRRect.Height() + 2,
			::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
		dc.FrameRect( rSliderRRect, &rBlackBrush );

		dc.FillSolidRect( rSliderRRect.left - 3, rSliderRRect.bottom + 1, rSliderRRect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
		i32X = rSliderRRect.left - 3 + i32H * (rSliderRRect.Width() - 4) / 255;
		m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderRRect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
			ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );

		// Saturation
		for( i = 0; i < (rSliderGRect.Width() - 2) / 4; i++ ) {
			HsvToRgb( m_f32ValueH, (float32)i / (float32)((rSliderRRect.Width() - 2) / 4), m_f32ValueV, f32R, f32G, f32B );
			rColor = RGB( (int32)(f32R * 255.0f), (int32)(f32G * 255.0f), (int32)(f32B * 255.0f) );
			dc.FillSolidRect( rSliderGRect.left + 1 + i * 4, rSliderGRect.top + 1, 4, rSliderGRect.Height() - 2, rColor );
		}

		dc.Draw3dRect( rSliderGRect.left - 1, rSliderGRect.top - 1, rSliderGRect.Width() + 2, rSliderGRect.Height() + 2,
			::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
		dc.FrameRect( rSliderGRect, &rBlackBrush );

		dc.FillSolidRect( rSliderGRect.left - 3, rSliderGRect.bottom + 1, rSliderGRect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
		i32X = rSliderGRect.left - 3 + i32S * (rSliderGRect.Width() - 4) / 255;
		m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderGRect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
			ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );

		// Value
		for( i = 0; i < (rSliderBRect.Width() - 2) / 4; i++ ) {
			HsvToRgb( m_f32ValueH, m_f32ValueS, (float32)i / (float32)((rSliderRRect.Width() - 2) / 4), f32R, f32G, f32B );
			rColor = RGB( (int32)(f32R * 255.0f), (int32)(f32G * 255.0f), (int32)(f32B * 255.0f) );
			dc.FillSolidRect( rSliderBRect.left + 1 + i * 4, rSliderBRect.top + 1, 4, rSliderBRect.Height() - 2, rColor );
		}

		dc.Draw3dRect( rSliderBRect.left - 1, rSliderBRect.top - 1, rSliderBRect.Width() + 2, rSliderBRect.Height() + 2,
			::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
		dc.FrameRect( rSliderBRect, &rBlackBrush );

		dc.FillSolidRect( rSliderBRect.left - 3, rSliderBRect.bottom + 1, rSliderBRect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
		i32X = rSliderBRect.left - 3 + i32V * (rSliderBRect.Width() - 4) / 255;
		m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderBRect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
			ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );
	}


	// Alpha
	for( i = 0; i < (rSliderARect.Width() - 2) / 4; i++ ) {
		int32	i32Grey = i * 255 / ((rSliderRRect.Width() - 2) / 4);
		rColor = RGB( i32Grey, i32Grey, i32Grey );
		dc.FillSolidRect( rSliderARect.left + 1 + i * 4, rSliderARect.top + 1, 4, rSliderARect.Height() - 1, rColor );
	}

	dc.Draw3dRect( rSliderARect.left - 1, rSliderARect.top - 1, rSliderARect.Width() + 2, rSliderARect.Height() + 2,
		::GetSysColor( COLOR_BTNSHADOW ), ::GetSysColor( COLOR_BTNHILIGHT ) );
	dc.FrameRect( rSliderARect, &rBlackBrush );

	dc.FillSolidRect( rSliderARect.left - 3, rSliderARect.bottom + 1, rSliderARect.Width() + 7, 6, ::GetSysColor( COLOR_BTNFACE ) );
	i32X = rSliderARect.left - 3 + i32A * (rSliderARect.Width() - 4) / 255;
	m_rImageList.DrawIndirect( &dc, 0, CPoint( i32X, rSliderARect.bottom + 1 ), CSize( 11, 6 ), CPoint( 0, 0 ),
		ILD_NORMAL, SRCCOPY, CLR_NONE, CLR_DEFAULT );


	// Draw swatches

	CRect	rSwatchRect = GetControlRect( m_rStaticSwatch);
	rSwatchRect.DeflateRect( 1, 1 );

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

	// create new clip region
	CRgn	rRegion;
	rRegion.CreateRectRgnIndirect( rSwatchRect );
	dc.SelectClipRgn( &rRegion );



	CRect	rSwatch;
	int	iX = 0, iY = 0;

	for( i = 0; i < m_rSwatches.size(); i++ ) {
		rSwatch.left = rSwatchRect.left + iX * m_iSwatchSize;
		rSwatch.right = rSwatch.left + m_iSwatchSize + 1;
		rSwatch.top = rSwatchRect.top + iY * m_iSwatchSize - m_iScrollSwatchY;
		rSwatch.bottom = rSwatch.top + m_iSwatchSize + 1;

		dc.FrameRect( rSwatch, &rBlackBrush );
		rSwatch.DeflateRect( 1, 1 );
		dc.FillSolidRect( rSwatch, m_rSwatches[i] );

		iX++;
		if( iX > 15 ) {
			iX = 0;
			iY++;
		}
	}

	// Fill the last row
	rSwatch.left = rSwatchRect.left + iX * m_iSwatchSize + (iX == 0 ? 0 : 1);
	rSwatch.right = rSwatchRect.right;
	rSwatch.top = rSwatchRect.top + iY * m_iSwatchSize - m_iScrollSwatchY + 1;
	rSwatch.bottom = rSwatch.top + m_iSwatchSize;
	dc.FillSolidRect( rSwatch, ::GetSysColor( COLOR_BTNFACE ) );

	rSwatch.left = rSwatchRect.left;
	rSwatch.right = rSwatchRect.right;
	rSwatch.top += m_iSwatchSize;
	rSwatch.bottom += m_iSwatchSize + 2;
	dc.FillSolidRect( rSwatch, ::GetSysColor( COLOR_BTNFACE ) );

	rSwatch.left = rSwatchRect.left + 16 * m_iSwatchSize + 1;
	rSwatch.right = rSwatchRect.right;
	rSwatch.top = rSwatchRect.top;
	dc.FillSolidRect( rSwatch, ::GetSysColor( COLOR_BTNFACE ) );

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

}

CRect CColorTypeInDlg::GetControlRect( CWnd& rWnd )
{
	CRect	rRect;
	rWnd.GetClientRect( rRect );
	rWnd.MapWindowPoints( this, rRect );
	return rRect;
}

void CColorTypeInDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	CRect	rPickRect = GetControlRect( m_rColor );
	CRect	rSliderRRect = GetControlRect( m_rSliderR );
	CRect	rSliderGRect = GetControlRect( m_rSliderG );
	CRect	rSliderBRect = GetControlRect( m_rSliderB );
	CRect	rSliderARect = GetControlRect( m_rSliderA );
	CRect	rSwatchRect = GetControlRect( m_rStaticSwatch);

	rSliderRRect.bottom += 8;
	rSliderGRect.bottom += 8;
	rSliderBRect.bottom += 8;
	rSliderARect.bottom += 8;

	m_hCursor = 0;

	if( rPickRect.PtInRect( point ) ) {
		m_hCursor = AfxGetApp()->LoadCursor( IDC_COLORPICK );
		if( nFlags & MK_LBUTTON )
			PickColor( point - rPickRect.TopLeft() );
	}

	if( rSwatchRect.PtInRect( point ) ) {
		m_hCursor = AfxGetApp()->LoadCursor( IDC_COLORPICK );
		if( nFlags & MK_LBUTTON )
			PickSwatchColor( point - rSwatchRect.TopLeft() );
	}

	if( m_iTracking == TRACK_SLIDER_R ) {
		int32	i32Value;
		if( m_iMode == MODE_RGB ) {
			i32Value = (point.x - rSliderRRect.left + 1) * 255 / (rSliderRRect.Width() - 2);
			if( i32Value < 0 ) i32Value = 0;
			if( i32Value > 255 ) i32Value = 255;
		}
		else {
			i32Value = (point.x - rSliderRRect.left + 1) * 359 / (rSliderRRect.Width() - 2);
			if( i32Value < 0 ) i32Value = 0;
			if( i32Value > 359 ) i32Value = 359;
		}
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditR.SetWindowText( sStr );
	}
	else if( m_iTracking == TRACK_SLIDER_G ) {
		int32	i32Value = (point.x - rSliderGRect.left + 1) * 255 / (rSliderGRect.Width() - 2);
		if( i32Value < 0 ) i32Value = 0;
		if( i32Value > 255 ) i32Value = 255;
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditG.SetWindowText( sStr );
	}
	else if( m_iTracking == TRACK_SLIDER_B ) {
		int32	i32Value = (point.x - rSliderBRect.left + 1) * 255 / (rSliderBRect.Width() - 2);
		if( i32Value < 0 ) i32Value = 0;
		if( i32Value > 255 ) i32Value = 255;
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditB.SetWindowText( sStr );
	}
	else if( m_iTracking == TRACK_SLIDER_A ) {
		int32	i32Value = (point.x - rSliderARect.left + 1) * 255 / (rSliderARect.Width() - 2);
		if( i32Value < 0 ) i32Value = 0;
		if( i32Value > 255 ) i32Value = 255;
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditA.SetWindowText( sStr );
	}

	CDialog::OnMouseMove(nFlags, point);
}

void CColorTypeInDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CRect	rPickRect = GetControlRect( m_rColor );
	CRect	rSliderRRect = GetControlRect( m_rSliderR );
	CRect	rSliderGRect = GetControlRect( m_rSliderG );
	CRect	rSliderBRect = GetControlRect( m_rSliderB );
	CRect	rSliderARect = GetControlRect( m_rSliderA );
	CRect	rSwatchRect = GetControlRect( m_rStaticSwatch);

	rSliderRRect.bottom += 8;
	rSliderGRect.bottom += 8;
	rSliderBRect.bottom += 8;
	rSliderARect.bottom += 8;

	if( rPickRect.PtInRect( point ) ) {
		PickColor( point - rPickRect.TopLeft() );
		return;
	}
	else if( rSwatchRect.PtInRect( point ) ) {
		PickSwatchColor( point - rSwatchRect.TopLeft() );
		return;
	}
	else if( rSliderRRect.PtInRect( point ) ) {
		int32	i32Value;
		if( m_iMode == MODE_RGB ) {
			i32Value = (point.x - rSliderRRect.left + 1) * 255 / (rSliderRRect.Width() - 2);
			if( i32Value < 0 ) i32Value = 0;
			if( i32Value > 255 ) i32Value = 255;
		}
		else {
			i32Value = (point.x - rSliderRRect.left + 1) * 359 / (rSliderRRect.Width() - 2);
			if( i32Value < 0 ) i32Value = 0;
			if( i32Value > 359 ) i32Value = 359;
		}
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditR.SetWindowText( sStr );
		SetCapture();
		m_iTracking = TRACK_SLIDER_R;
		return;
	}
	else if( rSliderGRect.PtInRect( point ) ) {
		int32	i32Value = (point.x - rSliderRRect.left + 1) * 255 / (rSliderRRect.Width() - 2);
		if( i32Value < 0 ) i32Value = 0;
		if( i32Value > 255 ) i32Value = 255;
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditG.SetWindowText( sStr );
		SetCapture();
		m_iTracking = TRACK_SLIDER_G;
		return;
	}
	else if( rSliderBRect.PtInRect( point ) ) {
		int32	i32Value = (point.x - rSliderRRect.left + 1) * 255 / (rSliderRRect.Width() - 2);
		if( i32Value < 0 ) i32Value = 0;
		if( i32Value > 255 ) i32Value = 255;
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditB.SetWindowText( sStr );
		SetCapture();
		m_iTracking = TRACK_SLIDER_B;
		return;
	}
	else if( rSliderARect.PtInRect( point ) ) {
		int32	i32Value = (point.x - rSliderRRect.left + 1) * 255 / (rSliderRRect.Width() - 2);
		if( i32Value < 0 ) i32Value = 0;
		if( i32Value > 255 ) i32Value = 255;
		CString	sStr;
		sStr.Format( "%d", i32Value );
		m_rEditA.SetWindowText( sStr );
		SetCapture();
		m_iTracking = TRACK_SLIDER_A;
		return;
	}
	
	CDialog::OnLButtonDown(nFlags, point);
}

void CColorTypeInDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if( GetCapture() == this ) {
		ReleaseCapture();
		m_hCursor = 0;
	}

	m_iTracking = TRACK_NONE;

	CDialog::OnLButtonUp(nFlags, point);
}

void CColorTypeInDlg::PickColor( CPoint pt )
{
	if( pt.x >= 0 && pt.x < 198 && pt.y >= 0 && pt.y < 15 ) {
		COLORREF	rColor = m_rDIB.ColorAt( pt.x + 1, pt.y + 1 );

		m_f32ValueR = (float32)GetBValue( rColor ) / 255.0f;
		m_f32ValueG = (float32)GetGValue( rColor ) / 255.0f;
		m_f32ValueB = (float32)GetRValue( rColor ) / 255.0f;

		ColorC	rColorVal;
		rColorVal[0] = m_f32ValueR;
		rColorVal[1] = m_f32ValueG;
		rColorVal[2] = m_f32ValueB;
		rColorVal[3] = m_f32ValueA;

		UpdateData( FALSE );

		if( m_pParam ) {
			CDemopajaDoc*	pDoc = GetDoc();
			ASSERT_VALID( pDoc );
			pDoc->HandleParamNotify( m_pParam->set_val( m_i32Time, rColorVal ) );
			pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
		}
		else {
			m_rColorValue = rColorVal;
		}
		Redraw( COLOR_REDRAW_COLOR | COLOR_REDRAW_SLIDERS );
	}
}

void CColorTypeInDlg::PickSwatchColor( CPoint pt )
{
	pt -= CPoint( 1, 1 );
	pt.y += m_iScrollSwatchY;

	int	iCol = pt.x / m_iSwatchSize;
	int	iRow = pt.y / m_iSwatchSize;

	if( iCol < 0 )
		iCol = 0;
	if( iCol > 15 )
		iCol = 15;
	if( iRow < 0 )
		iRow = 0;
	if( iRow > m_iSwatchRows )
		iRow = m_iSwatchRows;

	int iIdx = iCol + 16 * iRow;

	if( iIdx >= m_rSwatches.size() )
		return;

	COLORREF	rColor = m_rSwatches[iIdx];

	m_f32ValueR = (float32)GetRValue( rColor ) / 255.0f;
	m_f32ValueG = (float32)GetGValue( rColor ) / 255.0f;
	m_f32ValueB = (float32)GetBValue( rColor ) / 255.0f;

	ColorC	rColorVal;
	rColorVal[0] = m_f32ValueR;
	rColorVal[1] = m_f32ValueG;
	rColorVal[2] = m_f32ValueB;
	rColorVal[3] = m_f32ValueA;

	UpdateData( FALSE );

	if( m_pParam ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		pDoc->HandleParamNotify( m_pParam->set_val( m_i32Time, rColorVal ) );
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
	}
	else {
		m_rColorValue = rColorVal;
	}

	Redraw( COLOR_REDRAW_COLOR | COLOR_REDRAW_SLIDERS );
}

BOOL CColorTypeInDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	if( m_hCursor && pWnd == this ) {
		::SetCursor( m_hCursor );
		return TRUE;
	}
	return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

void CColorTypeInDlg::OnChangeEditr() 
{
	UpdateData( TRUE );

	ColorC	rColor;
	rColor[0] = m_f32ValueR;
	rColor[1] = m_f32ValueG;
	rColor[2] = m_f32ValueB;
	rColor[3] = m_f32ValueA;

	if( m_pParam ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		pDoc->HandleParamNotify( m_pParam->set_val( m_i32Time, rColor ) );
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
	}
	else
		m_rColorValue = rColor;

	Redraw( COLOR_REDRAW_COLOR | COLOR_REDRAW_SLIDERS );
}

void CColorTypeInDlg::OnChangeEditg() 
{
	UpdateData( TRUE );

	ColorC	rColor;
	rColor[0] = m_f32ValueR;
	rColor[1] = m_f32ValueG;
	rColor[2] = m_f32ValueB;
	rColor[3] = m_f32ValueA;

	if( m_pParam ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		pDoc->HandleParamNotify( m_pParam->set_val( m_i32Time, rColor ) );
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
	}
	else
		m_rColorValue = rColor;
		
	Redraw( COLOR_REDRAW_COLOR | COLOR_REDRAW_SLIDERS );
}

void CColorTypeInDlg::OnChangeEditb() 
{
	UpdateData( TRUE );

	ColorC	rColor;
	rColor[0] = m_f32ValueR;
	rColor[1] = m_f32ValueG;
	rColor[2] = m_f32ValueB;
	rColor[3] = m_f32ValueA;

	if( m_pParam ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		pDoc->HandleParamNotify( m_pParam->set_val( m_i32Time, rColor ) );
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
	}
	else
		m_rColorValue = rColor;
		
	Redraw( COLOR_REDRAW_COLOR | COLOR_REDRAW_SLIDERS );
}

void CColorTypeInDlg::OnChangeEdita() 
{
	UpdateData( TRUE );

	ColorC	rColor;
	rColor[0] = m_f32ValueR;
	rColor[1] = m_f32ValueG;
	rColor[2] = m_f32ValueB;
	rColor[3] = m_f32ValueA;

	if( m_pParam ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		pDoc->HandleParamNotify( m_pParam->set_val( m_i32Time, rColor ) );
		pDoc->NotifyViews( NOTIFY_REDRAW_GRAPHICS );
	}
	else
		m_rColorValue = rColor;

	Redraw( COLOR_REDRAW_SLIDERS );
}


void CColorTypeInDlg::SetMode( int iMode )
{
	if( iMode == MODE_RGB ) {
		// RGB
		m_rStaticR.SetWindowText( "R" );
		m_rStaticG.SetWindowText( "G" );
		m_rStaticB.SetWindowText( "B" );
	}
	else {
		// HSB
		m_rStaticR.SetWindowText( "H" );
		m_rStaticG.SetWindowText( "S" );
		m_rStaticB.SetWindowText( "B" );
	}

	m_iMode = iMode;

	UpdateData( FALSE );

	Redraw( COLOR_REDRAW_COLOR | COLOR_REDRAW_SLIDERS );
}

void CColorTypeInDlg::HsvToRgb( float32 fH, float32 fS, float32 fV, float32& fR, float32& fG, float32& fB )
{
	if( fV == 0.0f ) {
		// Achromatic case
		fR = 0;
		fG = 0;
		fB = 0;
	}
	else {
		float32	fFrac, fP, fQ, fT;
		int32	iSextant;

		if( fH == 1.0f )
			fH = 0;
		fH *= 6.0f;
		iSextant = (int32)fH;
		fFrac = fH - iSextant;
		fP = fV * (1.0f - fS);
		fQ = fV * (1.0f - (fS * fFrac));
		fT = fV * (1.0f - (fS * (1.0f - fFrac)));

		switch( iSextant ) {
		case 0:	fR = fV;	fG = fT;	fB = fP; break;
		case 1:	fR = fQ;	fG = fV;	fB = fP; break;
		case 2:	fR = fP;	fG = fV;	fB = fT; break;
		case 3:	fR = fP;	fG = fQ;	fB = fV; break;
		case 4:	fR = fT;	fG = fP;	fB = fV; break;
		case 5:	fR = fV;	fG = fP;	fB = fQ; break;
		}
	}
}


void CColorTypeInDlg::RgbToHsv( float32 fR, float32 fG, float32 fB, float32& fH, float32& fS, float32& fV )
{
	float32	fMax = __max( __max( fR, fG ), fB );
	float32	fMin = __min( __min( fR, fG ), fB );

	fV = fMax;
	fS = (fMax != 0.0f) ? ((fMax - fMin) / fMax) : 0.0f;

	if( fS == 0.0f ) {
		fH = 0.0f;
		return;
	}

	float32	fDelta = fMax - fMin;

	if( fR == fMax )
		fH = (fG - fB) / fDelta;
	else if( fG == fMax )
		fH = 2.0f + (fB - fR) / fDelta;
	else
		fH = 4.0f + (fR - fG) / fDelta;

	fH /= 6.0f;

	if( fH < 0 )
		fH += 1.0f;
}

BOOL CColorTypeInDlg::DestroyWindow() 
{
	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();
	pApp->WriteProfileInt( "Settings", "ColorPickerMode", m_iMode );
	
	return CDialog::DestroyWindow();
}

void CColorTypeInDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
//	CDialog::OnVScroll(nSBCode, nPos, pScrollBar);

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

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

	if( m_iScrollSwatchY < rScrollInfo.nMin )
		m_iScrollSwatchY = rScrollInfo.nMin;
	if( m_iScrollSwatchY > (rScrollInfo.nMax - rScrollInfo.nPage) )
		m_iScrollSwatchY = rScrollInfo.nMax - rScrollInfo.nPage;

	pScrollBar->SetScrollPos( m_iScrollSwatchY );

	// redraw
	Redraw( COLOR_REDRAW_SWATCH );
}

void CColorTypeInDlg::Redraw( int iReason )
{
	if( iReason & COLOR_REDRAW_COLOR ) {
		CRect	rColor = GetControlRect( m_rNewColor );
		InvalidateRect( rColor, FALSE );
	}

	if( iReason & COLOR_REDRAW_SLIDERS ) {
		CRect	rSliderRRect = GetControlRect( m_rSliderR );
		CRect	rSliderARect = GetControlRect( m_rSliderA );
		rSliderRRect.bottom = rSliderARect.bottom + 8;
		rSliderRRect.left -= 4;
		rSliderRRect.right += 4;
		InvalidateRect( rSliderRRect, FALSE );
	}

	if( iReason & COLOR_REDRAW_SWATCH ) {
		CRect	rSwatchRect = GetControlRect( m_rStaticSwatch);
		InvalidateRect( rSwatchRect, FALSE );
	}
}

void CColorTypeInDlg::OnButtonSwatchmenu() 
{
	CDemopajaApp*	pApp = (CDemopajaApp*)AfxGetApp();

	CFlatPopupMenu	rMenu;

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

	rMenu.AppendItem( m_iMode == MODE_RGB ? CFlatPopupMenu::itemBold : 0, "RGB", 1 );
	rMenu.AppendItem( m_iMode == MODE_HSB ? CFlatPopupMenu::itemBold : 0, "HSB", 2 );
	rMenu.AppendItem( CFlatPopupMenu::itemSeparator, NULL, 0 );
	rMenu.AppendItem( 0, "Load Swatches...", 3 );
	rMenu.AppendItem( 0, "Append Swatches...", 4 );
	rMenu.AppendItem( 0, "Save Swatches...", 5 );
	rMenu.AppendItem( 0, "Clear All", 6 );

	CPoint	rPt;
	::GetCursorPos( &rPt );

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

	if( i32Id == 1 ) {
		SetMode( MODE_RGB );
	}
	else if( i32Id == 2 ) {
		SetMode( MODE_HSB );
	}
	else if( i32Id == 3 ) {
		// Load
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();

		if( pSwatches->is_modified() ) {
			int	iRes = MessageBox( "The color swatch set has been changed.\n\nSave changes?", "Color Swatches not saved", MB_ICONQUESTION | MB_YESNOCANCEL );

			if( iRes == IDCANCEL ) {
				return;
			}
			else if( iRes == IDYES ) {
				char	szFileType[] = "Color Swatches (*.aco)|*.aco|All Files (*.*)|*.*||";
				CFileDialog	rDlg( FALSE, NULL, pApp->GetCurrentDir( CURDIR_COLORSWATCH ), OFN_HIDEREADONLY | OFN_EXPLORER | OFN_OVERWRITEPROMPT, szFileType );

				if( rDlg.DoModal() == IDOK ) {
					pSwatches->save_swatches( rDlg.GetPathName() );
					pApp->SetCurrentDir( CURDIR_COLORSWATCH, rDlg.GetPathName() );
				}
			}
		}

		char	szFileType[] = "Color Swatches (*.aco)|*.aco|All Files (*.*)|*.*||";
		CFileDialog	rDlg( TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER, szFileType );
		rDlg.m_ofn.lpstrTitle = "Merge";

		if( rDlg.DoModal() == IDOK ) {
			pSwatches->load_swatches( rDlg.GetPathName() );
			UpdateColorSwatches();
			CDemopajaApp*		pApp = (CDemopajaApp*)AfxGetApp();
			pApp->SetCurrentDir( CURDIR_COLORSWATCH, rDlg.GetPathName() );
		}
	}
	else if( i32Id == 4 ) {
		// append
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();

		char	szFileType[] = "Color Swatches (*.aco)|*.aco|All Files (*.*)|*.*||";
		CFileDialog	rDlg( TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER, szFileType );

		if( rDlg.DoModal() == IDOK ) {
			pSwatches->load_swatches( rDlg.GetPathName(), true );
			UpdateColorSwatches();
		}
	}
	else if( i32Id == 5 ) {
		// save
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();

		char	szFileType[] = "Color Swatches (*.aco)|*.aco|All Files (*.*)|*.*||";
		CFileDialog	rDlg( FALSE, NULL, pApp->GetCurrentDir( CURDIR_COLORSWATCH ), OFN_HIDEREADONLY | OFN_EXPLORER | OFN_OVERWRITEPROMPT, szFileType );

		if( rDlg.DoModal() == IDOK ) {
			pSwatches->save_swatches( rDlg.GetPathName() );
			pApp->SetCurrentDir( CURDIR_COLORSWATCH, rDlg.GetPathName() );
		}
	}
	else if( i32Id == 6 ) {
		CDemopajaDoc*	pDoc = GetDoc();
		ASSERT_VALID( pDoc );
		ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();
		pSwatches->clear_all();
	}
}

void CColorTypeInDlg::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CRect	rSwatchRect = GetControlRect( m_rStaticSwatch);

	if( rSwatchRect.PtInRect( point ) ) {
		point -= rSwatchRect.TopLeft();

		point -= CPoint( 1, 1 );
		point.y += m_iScrollSwatchY;

		int	iCol = point.x / m_iSwatchSize;
		int	iRow = point.y / m_iSwatchSize;

		if( iCol < 0 )
			iCol = 0;
		if( iCol > 15 )
			iCol = 15;
		if( iRow < 0 )
			iRow = 0;
		if( iRow > m_iSwatchRows )
			iRow = m_iSwatchRows;

		int iIdx = iCol + 16 * iRow;


		if( iIdx >= m_rSwatches.size() ) {
			iRow = m_rSwatches.size() / 16;
			iCol = m_rSwatches.size() - (iRow * 16);
			iIdx = m_rSwatches.size();
		}

		CRect	rSwatch;
		rSwatch.left = rSwatchRect.left + iCol * m_iSwatchSize;
		rSwatch.right = rSwatch.left + m_iSwatchSize + 1;
		rSwatch.top = rSwatchRect.top + iRow * m_iSwatchSize - m_iScrollSwatchY;
		rSwatch.bottom = rSwatch.top + m_iSwatchSize + 1;

		CClientDC	dc( this );

		// Draw selection

		rSwatchRect.DeflateRect( 1, 1 );

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

		// create new clip region
		CRgn	rRegion;
		rRegion.CreateRectRgnIndirect( rSwatchRect );
		dc.SelectClipRgn( &rRegion );

		dc.DrawFocusRect( rSwatch );

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


		CFlatPopupMenu	rMenu;

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

		int32	i32SelFlags = 0;
		if( iIdx >= m_rSwatches.size() )
			i32SelFlags = CFlatPopupMenu::itemNotSelectable | CFlatPopupMenu::itemGrayed;

		rMenu.AppendItem( 0, "Add Swatch", 1 );
		rMenu.AppendItem( i32SelFlags, "Replace Swatch", 2 );
		rMenu.AppendItem( i32SelFlags, "Delete Swatch", 3 );

		CPoint	rPt;
		::GetCursorPos( &rPt );

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

		if( i32Id == 1 ) {
			// Add
			CDemopajaDoc*	pDoc = GetDoc();
			ASSERT_VALID( pDoc );
			ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();
			ColorC	rColor;
			rColor[0] = m_f32ValueR;
			rColor[1] = m_f32ValueG;
			rColor[2] = m_f32ValueB;
			rColor[3] = m_f32ValueA;
			pSwatches->add_color( rColor, iIdx );
			UpdateColorSwatches();
		}
		else if( i32Id == 2 ) {
			// Replace
			CDemopajaDoc*	pDoc = GetDoc();
			ASSERT_VALID( pDoc );
			ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();
			ColorC	rColor;
			rColor[0] = m_f32ValueR;
			rColor[1] = m_f32ValueG;
			rColor[2] = m_f32ValueB;
			rColor[3] = m_f32ValueA;
			if( iIdx >= 0 && iIdx < pSwatches->get_color_count() ) {
				pSwatches->set_color( iIdx, rColor );
				UpdateColorSwatches();
			}
		}
		else if( i32Id == 3 ) {
			// Delete
			CDemopajaDoc*	pDoc = GetDoc();
			ASSERT_VALID( pDoc );
			ColorSwatchSetC*	pSwatches = pDoc->GetColorSwatchSet();
			if( iIdx >= 0 && iIdx < pSwatches->get_color_count() ) {
				pSwatches->del_color( iIdx );
				UpdateColorSwatches();
			}
		}

		Redraw( COLOR_REDRAW_SWATCH );

		return;
	}
	
	CDialog::OnRButtonDown(nFlags, point);
}
