/******************************************************************************

Copyright (c) 2000 Microsoft Corporation

Module Name:
    Behav_GRADIENT.cpp

Abstract:
    This file contains the implementation of the CPCHBehavior_GRADIENT class,
    that dictates how hyperlinks work in the help center.

Revision History:
    <NAME> (dmassare)  06/06/2000
        created

******************************************************************************/

#include "stdafx.h"

////////////////////////////////////////////////////////////////////////////////

static const CComBSTR c_bstrStartColor  ( L"start-color"    );
static const CComBSTR c_bstrEndColor    ( L"end-color"      );

static const CComBSTR c_bstrGradientType( L"gradient-type"  );
static const CComBSTR c_bstrReturnToZero( L"return-to-zero" );

////////////////////////////////////////////////////////////////////////////////

static COLORREF local_GetColor( /*[in]*/  IHTMLElement*      elem     ,
                                /*[in]*/  IHTMLCurrentStyle* style    ,
                                /*[in]*/  BSTR               bstrName )
{
    CComVariant vColor;
    COLORREF    color;
    bool        fSystem;

    (void)style->getAttribute( bstrName, 0, &vColor );

    (void)MPC::HTML::ConvertColor( vColor, color, fSystem );

    return color;
}

////////////////////////////////////////////////////////////////////////////////

CPCHBehavior_GRADIENT::CPCHBehavior_GRADIENT()
{
    __HCP_FUNC_ENTRY( "CPCHBehavior_GRADIENT::CPCHBehavior_GRADIENT" );

    m_lCookie       = 0;     // long     m_lCookie;
                             //
                             // COLORREF m_clsStart;
                             // COLORREF m_clsEnd;
    m_fHorizontal   = true;  // bool     m_fHorizontal;
    m_fReturnToZero = false; // bool     m_fReturnToZero;
}

/////////////////////////////////////////////////////////////////////////////

void CPCHBehavior_GRADIENT::GetColors( /*[in]*/ bool fForce )
{
    CComPtr<IHTMLCurrentStyle> pStyle;
    CComVariant                v;

	if(m_elem && m_elem2 && SUCCEEDED(m_elem2->get_currentStyle( &pStyle )) && pStyle)
	{
		m_clsStart = local_GetColor( m_elem, pStyle, c_bstrStartColor );
		m_clsEnd   = local_GetColor( m_elem, pStyle, c_bstrEndColor   );

		if(SUCCEEDED(pStyle->getAttribute( c_bstrGradientType, 0, &v )) && v.vt == VT_BSTR &&
		   SUCCEEDED(v.ChangeType        ( VT_I4                     ))                     )
		{
			if(v.lVal == 0) m_fHorizontal = false;
		}
		v.Clear();
	
		if(SUCCEEDED(pStyle->getAttribute( c_bstrReturnToZero, 0, &v )) && v.vt == VT_BSTR &&
		   SUCCEEDED(v.ChangeType        ( VT_I4                     ))                     )
		{
			if(v.lVal != 0) m_fReturnToZero = true;
		}
		v.Clear();
	
		if(m_fRTL && m_fHorizontal && !m_fReturnToZero)
		{
			COLORREF tmp;
	
			tmp        = m_clsStart;
			m_clsStart = m_clsEnd;
			m_clsEnd   = tmp;
		}
	}
}

HRESULT CPCHBehavior_GRADIENT::onEvent( DISPID id, DISPPARAMS* pdispparams, VARIANT* )
{
	if(id == DISPID_PCH_E_CSSCHANGED)
	{
		GetColors( /*fForce*/true );
	}

	return S_OK;
}

////////////////////////////////////////////////////////////////////////////////

STDMETHODIMP CPCHBehavior_GRADIENT::Init( /*[in]*/ IElementBehaviorSite* pBehaviorSite )
{
    __HCP_FUNC_ENTRY( "CPCHBehavior_GRADIENT::Init" );

    HRESULT            hr;
	CComPtr<IDispatch> pDisp;


    __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior::Init( pBehaviorSite ));

	__MPC_EXIT_IF_METHOD_FAILS(hr, AttachToEvent( NULL, (CLASS_METHOD)onEvent, NULL, &pDisp ));
	__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().RegisterEvents( -1, 0, pDisp, &m_lCookie ));

	GetColors( /*fForce*/false );

    hr = S_OK;


    __HCP_FUNC_CLEANUP;

    __HCP_FUNC_EXIT(hr);
}

STDMETHODIMP CPCHBehavior_GRADIENT::Detach()
{
    if(m_lCookie)
    {
		(void)m_parent->Events().UnregisterEvents( m_lCookie );

        m_lCookie = 0;
    }

    return CPCHBehavior::Detach();
}

////////////////////////////////////////////////////////////////////////////////

#define COLOR2COLOR16(col) (COLOR16)((col) << 8);

STDMETHODIMP CPCHBehavior_GRADIENT::Draw( /*[in]*/ RECT   rcBounds     ,
										  /*[in]*/ RECT   rcUpdate     ,
										  /*[in]*/ LONG   lDrawFlags   ,
										  /*[in]*/ HDC    hdc          ,
										  /*[in]*/ LPVOID pvDrawObject )
{
	if(m_clsStart != m_clsEnd)
	{
		TRIVERTEX     vert[2];
		GRADIENT_RECT gRect;
		ULONG         dwMode = m_fHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V;
	
		vert[0].x      = rcBounds.left;
		vert[0].y      = rcBounds.top;
		vert[0].Red    = COLOR2COLOR16(GetRValue(m_clsStart));
		vert[0].Green  = COLOR2COLOR16(GetGValue(m_clsStart));
		vert[0].Blue   = COLOR2COLOR16(GetBValue(m_clsStart));
		vert[0].Alpha  = 0;
	
		vert[1].x      = rcBounds.right;
		vert[1].y      = rcBounds.bottom;
		vert[1].Red    = COLOR2COLOR16(GetRValue(m_clsEnd));
		vert[1].Green  = COLOR2COLOR16(GetGValue(m_clsEnd));
		vert[1].Blue   = COLOR2COLOR16(GetBValue(m_clsEnd));
		vert[1].Alpha  = 0;
	
		gRect.UpperLeft  = 0;
		gRect.LowerRight = 1;
	
		if(m_fReturnToZero)
		{
			if(m_fHorizontal) vert[1].x = vert[0].x + (rcBounds.right  - rcBounds.left) / 2;
			else              vert[1].y = vert[0].y + (rcBounds.bottom - rcBounds.top ) / 2;
			
			::GradientFill(hdc, vert, 2, &gRect, 1, dwMode );
	
	
			if(m_fHorizontal) vert[0].x = rcBounds.right;
			else              vert[0].y = rcBounds.bottom;
		}
	
		////DebugLog( "GRADIENT %d %d %d %d\n", (int)rcBounds.left, (int)rcBounds.top, (int)rcBounds.right, (int)rcBounds.bottom );
		::GradientFill( hdc, vert, 2, &gRect, 1, dwMode );
	}
	else
	{
		HBRUSH hbrush = ::CreateSolidBrush( m_clsStart );
		
		if(hbrush)
		{
			::FillRect( hdc, &rcBounds, hbrush );
			
			::DeleteObject( hbrush );
		}
	}

    return S_OK;
}

STDMETHODIMP CPCHBehavior_GRADIENT::GetPainterInfo( /*[in]*/ HTML_PAINTER_INFO *pInfo )
{
    if(pInfo)
    {
		pInfo->lFlags          = HTMLPAINTER_TRANSPARENT;
		pInfo->lZOrder         = HTMLPAINT_ZORDER_BELOW_CONTENT;
		pInfo->iidDrawObject   = IID_NULL;
		pInfo->rcExpand.left   = 0;
		pInfo->rcExpand.top    = 0;
		pInfo->rcExpand.right  = 0;
		pInfo->rcExpand.bottom = 0;
    }

    return S_OK;
}

STDMETHODIMP CPCHBehavior_GRADIENT::HitTestPoint( /*[in]*/ POINT pt       ,
												  /*[in]*/ BOOL* pbHit    ,
												  /*[in]*/ LONG* plPartID )
{
    return E_NOTIMPL;
}

STDMETHODIMP CPCHBehavior_GRADIENT::OnResize( /*[in]*/ SIZE pt )
{
    return E_NOTIMPL;
}
