// Checkbox.cpp : Implementation of cCheckbox
#include "stdafx.h"
#include "DecalControls.h"
#include "Checkbox.h"

/////////////////////////////////////////////////////////////////////////////
// cCheckbox

cCheckbox::cCheckbox()
: m_bChecked( VARIANT_FALSE ),
m_bRightToLeft( VARIANT_FALSE ),
m_nTextColor( RGB( 0, 0, 0 ) ),
m_bPressed( VARIANT_FALSE ),
m_bMouseIn( VARIANT_FALSE )
{
}

STDMETHODIMP cCheckbox::get_Font(IFontCacheDisp **pVal)
{
   _ASSERTE( pVal != NULL );

   if( m_pFont.p == NULL )
      *pVal = NULL;
   else
      m_pFont->QueryInterface( pVal );

	return S_OK;
}

STDMETHODIMP cCheckbox::putref_Font(IFontCacheDisp *newVal)
{
   _ASSERTE( newVal != NULL );

   if( m_pFont.p )
      m_pFont.Release();

   HRESULT hRes = newVal->QueryInterface( &m_pFont );

   _ASSERTE( SUCCEEDED( hRes ) );
   m_pSite->Reformat();

	return S_OK;
}

STDMETHODIMP cCheckbox::get_Text(BSTR *pVal)
{
   _ASSERTE( pVal != NULL );

   *pVal = OLE2BSTR( m_strText );

	return S_OK;
}

STDMETHODIMP cCheckbox::put_Text(BSTR newVal)
{
   _ASSERTE( newVal != NULL );

   m_strText = newVal;
   m_pSite->Reformat();

	return S_OK;
}

STDMETHODIMP cCheckbox::get_TextColor(long *pVal)
{
   _ASSERTE( pVal != NULL );

   *pVal = m_nTextColor;

	return S_OK;
}

STDMETHODIMP cCheckbox::put_TextColor(long newVal)
{
   _ASSERTE( ( newVal & 0xFF000000L ) == 0 );

   m_nTextColor = newVal;
   m_pSite->Invalidate();

	return S_OK;
}

STDMETHODIMP cCheckbox::get_Checked(VARIANT_BOOL *pVal)
{
   _ASSERTE( pVal != NULL );
   *pVal = m_bChecked;

	return S_OK;
}

STDMETHODIMP cCheckbox::put_Checked(VARIANT_BOOL newVal)
{
   if( m_bChecked == newVal )
      return S_OK;

   m_bChecked = newVal;
   m_pSite->Invalidate();

	return S_OK;
}

STDMETHODIMP cCheckbox::get_RightToLeft(VARIANT_BOOL *pVal)
{
   _ASSERTE( pVal != NULL );

   *pVal = m_bRightToLeft;

	return S_OK;
}

STDMETHODIMP cCheckbox::put_RightToLeft(VARIANT_BOOL newVal)
{
   m_bRightToLeft = newVal;
   m_pSite->Reformat();

	return S_OK;
}

STDMETHODIMP cCheckbox::SchemaLoad(IView *pView, IUnknown *pSchema)
{
   // First attempt to load the font
   CComPtr< IPluginSite > pPlugin;
   m_pSite->get_PluginSite( &pPlugin );

   pPlugin->CreateFontSchema( 14, 0, pSchema, &m_pFont );

   MSXML::IXMLDOMElementPtr pElement = pSchema;

   _variant_t vText = pElement->getAttribute( _T( "text" ) ),
      vTextColor = pElement->getAttribute( _T( "textcolor" ) ),
      vRightToLeft = pElement->getAttribute( _T( "righttoleft" ) ),
      vChecked = pElement->getAttribute( _T( "checked" ) ),
	  vOutline = pElement->getAttribute( _T( "outlinecolor" ) ),
	  vAntialias = pElement->getAttribute( _T( "aa" ) );

   // Text must exist
   _ASSERTE( vText.vt == VT_BSTR );
   m_strText = vText.bstrVal;

   if( vTextColor.vt != VT_NULL )
   {
      try
      {
         m_nTextColor = static_cast< long >( vTextColor );
      }
      catch( ... )
      {
         // Type conversion error
         _ASSERTE( FALSE );
      }
   }

   if( vRightToLeft.vt != VT_NULL )
   {
      try
      {
         m_bRightToLeft = ( static_cast< bool >( vRightToLeft ) ) ? VARIANT_TRUE : VARIANT_FALSE;
      }
      catch( ... )
      {
         // Type conversion error
         _ASSERTE( FALSE );
      }
   }

   if( vChecked.vt != VT_NULL )
   {
      try
      {
         m_bChecked = ( static_cast< bool >( vChecked ) ) ? VARIANT_TRUE : VARIANT_FALSE;
      }
      catch( ... )
      {
         // Type conversion error
         _ASSERTE( FALSE );
      }
   }

	m_nOutlineColor = 0;
	m_bOutline = false;
	if( vOutline.vt != VT_NULL )
	{
		try
		{
			m_bOutline = true;
			m_nOutlineColor = static_cast< long >( vOutline );
		}
		catch( ... )
		{
			// Type conversion error
			_ASSERTE( FALSE );
		}
	}
   
	m_bAA = true;
	if( vAntialias.vt != VT_NULL )
	{
		try
		{
			m_bAA = static_cast< bool >( vAntialias );
		}
		catch( ... )
		{
			// Type conversion error
			_ASSERTE( FALSE );
		}
	}

	return S_OK;
}

#define CHECK_SIZE   13
#define TEXT_OFFSET  4

STDMETHODIMP cCheckbox::Reformat()
{
   if( m_pFont.p == NULL )
   {
      // No font was specified, create the default font
      CComPtr< IPluginSite > pPlugin;
      m_pSite->get_PluginSite( &pPlugin );
	  
	  BSTR bstrFontName;
	  pPlugin->get_FontName(&bstrFontName);
      pPlugin->CreateFont( bstrFontName /*_bstr_t( _T( "Times New Roman" ) )*/, 14, 0, &m_pFont );
   }

   RECT rc;
   m_pSite->get_Position( &rc );

   SIZE szText;
   m_pFont->MeasureText( m_strText, &szText );

   if( szText.cy >= CHECK_SIZE )
   {
      m_ptCheck.y = ( szText.cy - CHECK_SIZE ) / 2;
      m_ptText.y = 0;
   }
   else
   {
      m_ptCheck.y = 0;
      m_ptText.y = ( CHECK_SIZE - szText.cy ) / 2;
   }

   if( m_bRightToLeft )
   {
      m_ptText.x = ( rc.right - rc.left ) - ( CHECK_SIZE + TEXT_OFFSET ) - szText.cx;
      m_ptCheck.x = ( rc.right - rc.left ) - CHECK_SIZE;
   }
   else
   {
      m_ptText.x = CHECK_SIZE + TEXT_OFFSET;
      m_ptCheck.x = 0;
   }

   return S_OK;
}

STDMETHODIMP cCheckbox::Render( ICanvas *pCanvas )
{
   bool bChecked = ( m_bPressed && m_bMouseIn ) ? !m_bChecked : !!m_bChecked;

   CComPtr< IPluginSite > pPlugin;
   m_pSite->get_PluginSite( &pPlugin );

   CComPtr< IIconCache > pIcon;
   SIZE szIcon = { CHECK_SIZE, CHECK_SIZE };
   pPlugin->GetIconCache( &szIcon, &pIcon );

   pIcon->DrawIcon( &m_ptCheck, ( bChecked ) ? 0x0600128B : 0x0600128D, 0, pCanvas );

	long lFlags = 0;

	if( m_bAA )
		lFlags |= eAA;

	if( m_bOutline )
		lFlags |= eOutlined;

	m_pFont->DrawTextEx( &m_ptText, m_strText, m_nTextColor, m_nOutlineColor, lFlags, pCanvas );

   return S_OK;
}

STDMETHODIMP cCheckbox::MouseEnter(struct MouseState *)
{
   _ASSERTE( !m_bMouseIn );

   m_bMouseIn = VARIANT_TRUE;

   if( m_bPressed )
   {
      _ASSERTE( m_pSite.p != NULL );

      m_pSite->Invalidate();
   }

	return S_OK;
}

STDMETHODIMP cCheckbox::MouseExit(struct MouseState *)
{
   _ASSERTE( m_bMouseIn );

   m_bMouseIn = VARIANT_FALSE;

   if( m_bPressed )
   {
      _ASSERTE( m_pSite.p != NULL );

      m_pSite->Invalidate();
   }

	return S_OK;
}

STDMETHODIMP cCheckbox::MouseDown(struct MouseState *)
{
   _ASSERTE( m_pSite != NULL );

   m_bPressed = VARIANT_TRUE;
   m_pSite->Invalidate();

	return S_OK;
}

STDMETHODIMP cCheckbox::MouseUp(struct MouseState *)
{
   m_bPressed = VARIANT_FALSE;

   long nID;
   m_pSite->get_ID( &nID );

   if( m_bMouseIn )
   {
      _ASSERTE( m_pSite.p != NULL );

      m_bChecked = ( m_bChecked ) ? VARIANT_FALSE : VARIANT_TRUE;
      m_pSite->Invalidate();

      // NOTE: The command may destroy the control synchronously
      // so we make a stack copy of the target in case our instance is destroyed
      // for the purpose of completing the command
      Fire_Change( nID, m_bChecked );
   }

	return S_OK;
}

