// PushButton.cpp : Implementation of cPushButton
#include "stdafx.h"
#include "DecalControls.h"
#include "PushButton.h"

/////////////////////////////////////////////////////////////////////////////
// cPushButton

cPushButton::cPushButton()
: m_bPressed( VARIANT_FALSE ),
m_bMouseIn( VARIANT_FALSE ),
m_nFaceColor( RGB( 140, 80, 30 ) ),
m_nTextColor( RGB( 240, 240, 120 ) ), 
m_UseFaceColor(false)					// GKusnick: Render 3D outline.
{
}

void cPushButton::onCreate()
{
   // This control draws over it's entire area
   m_pSite->put_Transparent( VARIANT_FALSE );
}

STDMETHODIMP cPushButton::get_Image(IImageCacheDisp **pVal)
{
   _ASSERTE( pVal != NULL );

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

	return S_OK;
}

STDMETHODIMP cPushButton::putref_Image(IImageCacheDisp *newVal)
{
   if( m_pBackground.p )
      m_pBackground.Release();

   if( newVal != NULL )
   {
      HRESULT hRes = newVal->QueryInterface( &m_pBackground );
      _ASSERTE( SUCCEEDED( hRes ) );
   }

   m_pSite->Invalidate();

	return S_OK;
}

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

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

	return S_OK;
}

STDMETHODIMP cPushButton::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 cPushButton::get_Text(BSTR *pVal)
{
   _ASSERTE( pVal != NULL );

   *pVal = OLE2BSTR( m_strText );

	return S_OK;
}

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

   m_strText = newVal;
   m_pSite->Reformat();
   m_pSite->Invalidate();
	return S_OK;
}

STDMETHODIMP cPushButton::get_FaceColor(long *pVal)
{
   _ASSERTE( pVal != NULL );

   *pVal = m_nFaceColor;

	return S_OK;
}

STDMETHODIMP cPushButton::put_FaceColor(long newVal)
{
   _ASSERTE( ( newVal & 0xFF000000L ) == 0 );

   m_nFaceColor = newVal;
   m_UseFaceColor = true;		// GKusnick: Render 3D outline.
   m_pSite->Invalidate();

	return S_OK;
}

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

   *pVal = m_nTextColor;

	return S_OK;
}

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

   m_nTextColor = newVal;
   m_pSite->Invalidate();

	return S_OK;
}

STDMETHODIMP cPushButton::SchemaLoad( IView *pView, IUnknown *pSchema )
{
	CComPtr< IPluginSite > pPlugin;
	m_pSite->get_PluginSite( &pPlugin );

	// Load some defaults
	pPlugin->CreateFontSchema( 14, 0, pSchema, &m_pFont );
	pPlugin->LoadImageSchema( pSchema, &m_pBackground );

	MSXML::IXMLDOMElementPtr pElement = pSchema;

	_variant_t	vFaceColor = pElement->getAttribute( _T( "facecolor" ) ),
				vTextColor = pElement->getAttribute( _T( "textcolor" ) ),
				vText = pElement->getAttribute( _T( "text" ) ),
				vAntialias = pElement->getAttribute( _T( "aa" ) );

	if( vFaceColor.vt != VT_NULL )
	{
		try
		{
			m_nFaceColor = static_cast< long >( vFaceColor );
			m_UseFaceColor = true;		// GKusnick: Render 3D outline.
		}
		catch( ... )
		{
			// Type conversion error
			_ASSERTE( FALSE );
		}
	}

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

	if( vText.vt != VT_NULL )
	{
		_ASSERTE( vText.vt == VT_BSTR );
		m_strText = vText.bstrVal;
	}

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

	return S_OK;
}

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

   m_bMouseIn = VARIANT_TRUE;

   if( m_bPressed )
   {
      long nID;
      m_pSite->get_ID( &nID );
      Fire_Hit( nID );

      _ASSERTE( m_pSite.p != NULL );

      m_pSite->Invalidate();
   }

	return S_OK;
}

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

   m_bMouseIn = VARIANT_FALSE;

   if( m_bPressed )
   {
      long nID;
      m_pSite->get_ID( &nID );
      Fire_Unhit( nID );

      _ASSERTE( m_pSite.p != NULL );

      m_pSite->Invalidate();
   }

	return S_OK;
}

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

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

   m_bPressed = VARIANT_TRUE;
   m_pSite->Invalidate();

	return S_OK;
}

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

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

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

      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_Accepted( nID );
      Fire_Unhit( nID );
   }
   else
      Fire_Canceled( nID );

	return S_OK;
}

STDMETHODIMP cPushButton::Reformat()
{
   // Everything looks good, calculate the offset of the text
   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 );

   m_ptText.x = ( ( rc.right - rc.left ) - szText.cx ) / 2;
   m_ptText.y = ( ( rc.bottom - rc.top ) - szText.cy ) / 2;

   return S_OK;
}

STDMETHODIMP cPushButton::Render( ICanvas *pCanvas )
{
   _ASSERTE( pCanvas != NULL );
   _ASSERTE( m_pSite.p != NULL );

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

   RECT rcClient = { 0, 0, rcPos.right - rcPos.left, rcPos.bottom - rcPos.top };
   bool bPressed = ( m_bPressed && m_bMouseIn );

   // First draw the background
   if( m_pBackground.p == NULL )
      pCanvas->Fill( &rcClient, m_nFaceColor );
   else
   {
      POINT ptOrg = { ( bPressed ) ? 1 : 0, ( bPressed ) ? 1 : 0 };
      m_pBackground->PatBlt( pCanvas, &rcClient, &ptOrg );
   }

   // Next, draw the text
   POINT ptText = { ( !bPressed ) ? m_ptText.x : m_ptText.x + 1, ( !bPressed ) ? m_ptText.y : m_ptText.y + 1 };
   m_pFont->DrawTextEx( &ptText, m_strText, m_nTextColor, 0, m_bAA ? eAA : 0, pCanvas );

   // Nerfgolem 2001.10.11
   // Do not render the 3D outline if there's a background image.
   // GKusnick: Do render it if there's an explicit face color.
   if( m_pBackground.p == NULL || m_UseFaceColor )
   {
      // Last, draw the '3D' border - colors are generated relative to the face color
      // and the design is taken from the windows button
      long nBrightest = RGB( ( 255 - GetRValue( m_nFaceColor ) ) / 2 + GetRValue( m_nFaceColor ), 
            ( 255 - GetGValue( m_nFaceColor ) ) / 2 + GetGValue( m_nFaceColor ), 
            ( 255 - GetBValue( m_nFaceColor ) ) / 2 + GetBValue( m_nFaceColor ) ),
         nDarkShadow = RGB( GetRValue( m_nFaceColor ) / 4, GetGValue( m_nFaceColor ) / 4, GetBValue( m_nFaceColor ) / 4 ),
         nShadow = RGB( GetRValue( m_nFaceColor ) / 2, GetGValue( m_nFaceColor ) / 2, GetBValue( m_nFaceColor ) / 2 );
   
      RECT rcOuterLeft = { 0, 0, 1, rcClient.bottom - 1 },
         rcInnerLeft = { 1, 1, 2, rcClient.bottom - 2 },
         rcOuterTop = { 0, 0, rcClient.right - 1, 1 },
         rcInnerTop = { 1, 1, rcClient.right - 2, 2 },
         rcOuterRight = { rcClient.right - 1, 0, rcClient.right, rcClient.bottom },
         rcInnerRight = { rcClient.right - 2, 1, rcClient.right - 1, rcClient.bottom - 1 },
         rcOuterBottom = { 0, rcClient.bottom - 1, rcClient.right, rcClient.bottom },
         rcInnerBottom = { 1, rcClient.bottom - 2, rcClient.right - 1, rcClient.bottom - 1 };
   
      if( bPressed )
	  {
         pCanvas->Fill( &rcOuterLeft, nDarkShadow );
         pCanvas->Fill( &rcOuterTop, nDarkShadow );
         pCanvas->Fill( &rcOuterRight, nBrightest );
         pCanvas->Fill( &rcOuterBottom, nBrightest );
   
         pCanvas->Fill( &rcInnerLeft, nShadow );
         pCanvas->Fill( &rcInnerTop, nShadow );
         pCanvas->Fill( &rcInnerRight, m_nFaceColor );
         pCanvas->Fill( &rcInnerBottom, m_nFaceColor );
	  }
      else
	  {
         pCanvas->Fill( &rcOuterLeft, nBrightest );
         pCanvas->Fill( &rcOuterTop, nBrightest );
         pCanvas->Fill( &rcOuterRight, nDarkShadow );
         pCanvas->Fill( &rcOuterBottom, nDarkShadow );
   
         pCanvas->Fill( &rcInnerLeft, m_nFaceColor );
         pCanvas->Fill( &rcInnerTop, m_nFaceColor );
         pCanvas->Fill( &rcInnerRight, nShadow );
         pCanvas->Fill( &rcInnerBottom, nShadow );
	  }
   }

   return S_OK;
}
