www.gusucode.com > VC++自定义图表控件及使用例子源码程序 > VC++自定义图表控件及使用例子源码程序\code\ChartCtrl_demo\ChartDemo\ChartCtrl\ChartLegend.cpp

    //Download by http://www.NewXing.com
/*
 *
 *	ChartLegend.cpp
 *
 *	Written by C閐ric Moonen (cedric_moonen@hotmail.com)
 *
 *
 *
 *	This code may be used for any non-commercial and commercial purposes in a compiled form.
 *	The code may be redistributed as long as it remains unmodified and providing that the 
 *	author name and this disclaimer remain intact. The sources can be modified WITH the author 
 *	consent only.
 *	
 *	This code is provided without any garanties. I cannot be held responsible for the damage or
 *	the loss of time it causes. Use it at your own risks
 *
 *	An e-mail to notify me that you are using this code is appreciated also.
 *
 *	History:
 *		- 02/03/2008: Legend can now be docked on any side or can be floating.
 *		- 02/03/2008: Added support for transparent legend.
 *		- 24/03/2008: Bug fix for invisible series.
 *		- 28/03/2008: Support for horizontal legend.
 *		- 28/03/2008: Bitmap size is now the same for all series.
 *
 */

#include "stdafx.h"
#include "ChartLegend.h"
#include "ChartSerie.h"
#include "ChartCtrl.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CChartLegend::CChartLegend(CChartCtrl* pParent)
{
	m_pParentCtrl = pParent;
	m_BackColor = RGB(255,255,255);
	m_iFontSize = 100;
	m_strFontName = _T("Times New Roman");

	m_bIsVisible = false;

	m_bDocked = true;
	m_DockSide = dsDockRight;
	m_iLeftPos = m_iTopPos = 0;
	m_bIsTransparent = false;
	m_bIsHorizontal = false;

	m_bShadow = true;
	m_iShadowDepth = 3;
	m_BitmapSize.cx = 16;
	m_BitmapSize.cy = 16;
}

CChartLegend::~CChartLegend()
{
}

void CChartLegend::SetVisible(bool bVisible)
{ 
	m_bIsVisible = bVisible; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::SetBackColor(COLORREF NewColor)	   
{ 
	m_BackColor = NewColor; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::SetShadowColor(COLORREF NewColor) 
{ 
	m_ShadowColor = NewColor; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::EnableShadow(bool bEnable)
{
	m_bShadow = bEnable;
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::SetShadowDepth(int Depth)
{ 
	m_iShadowDepth = Depth; 
	m_pParentCtrl->RefreshCtrl();
}

BOOL CChartLegend::IsPointInside(const CPoint& screenPoint) const
{
	return m_LegendRect.PtInRect(screenPoint);
}

void CChartLegend::SetFont(int iPointSize, const TChartString& strFaceName)
{
	m_iFontSize = iPointSize;
	m_strFontName = strFaceName;
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::SetTransparent(bool bTransparent)
{ 
	m_bIsTransparent = bTransparent; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::SetHorizontalMode(bool bHorizontal)
{
	m_bIsHorizontal = bHorizontal;
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::DockLegend(DockSide dsSide)
{
	m_bDocked = true;
	m_DockSide = dsSide;
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::UndockLegend(int iLeftPos, int iTopPos)
{
	m_bDocked = false;
	m_iLeftPos = iLeftPos;
	m_iTopPos = iTopPos;
	m_pParentCtrl->RefreshCtrl();
}

void CChartLegend::ClipArea(CRect& rcControl, CDC* pDC)
{
	UpdatePosition(pDC,rcControl);
	if (m_LegendRect.IsRectEmpty())
		return;

	if (m_bDocked)
	{
		switch (m_DockSide)
		{
		case dsDockRight:
			rcControl.right = m_LegendRect.left + 2;
			break;
		case dsDockLeft:
			rcControl.left = m_LegendRect.right - 2;
			break;
		case dsDockTop:
			rcControl.top = m_LegendRect.bottom + 2;
			break;
		case dsDockBottom:
			rcControl.bottom = m_LegendRect.top - 2;
			break;
		}
	}
}

void CChartLegend::UpdatePosition(CDC* pDC, const CRect& rcControl)
{
	CRect NewPosition;
	NewPosition.SetRectEmpty();
	if (!m_bIsVisible)
	{
		m_LegendRect = NewPosition;
		return;
	}

	CFont* pOldFont;
	CFont NewFont;
	NewFont.CreatePointFont(m_iFontSize,m_strFontName.c_str(),pDC);
	pOldFont = pDC->SelectObject(&NewFont);

	int Height = 0;		
	int Width = 0;		
	int MaxText = 0;
	CSize TextSize;

	m_pParentCtrl->GoToFirstSerie();
	int Drawn = 0;
	while (CChartSerie* pSerie=m_pParentCtrl->GetNextSerie())
	{
		if ( (pSerie->GetName() == _T("")) || !pSerie->IsVisible() )
			continue;

		Drawn++;
		TextSize = pDC->GetTextExtent(pSerie->GetName().c_str());

		if (!m_bIsHorizontal)
		{
			if (TextSize.cy>m_BitmapSize.cy)
				Height += TextSize.cy + 2;
			else
				Height += m_BitmapSize.cy + 2;

			if (TextSize.cx > MaxText)
				MaxText = TextSize.cx;
		}
		else
		{
			Width += TextSize.cx + 4 + m_BitmapSize.cx + 10;
			if (TextSize.cy > MaxText)
				MaxText = TextSize.cy;
		}
	}
	pDC->SelectObject(pOldFont);
	DeleteObject(NewFont);

	if (!Drawn)
	{
		m_LegendRect = NewPosition;
		return;
	}

	if (!m_bIsHorizontal)
	{
		Width += MaxText + m_BitmapSize.cx + 12;
		Height += 4 + 4 - 2;	// Top and bottom margins. -2 because space counted once too much
	}
	else
	{
		Width += 2 + 2 - 10;
		Height = 4 + max(m_BitmapSize.cy,MaxText) + 4;
	}
	
	if (!m_bDocked)
	{
		NewPosition.top = m_iTopPos;
		NewPosition.left = m_iLeftPos;
		NewPosition.bottom = m_iTopPos + Height + 2;
		NewPosition.right = m_iLeftPos + Width;
	}
	else
	{
		switch (m_DockSide)
		{
		case dsDockRight:
			NewPosition.top = ((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2);
			NewPosition.left = rcControl.right - (Width + 6);
			NewPosition.bottom = NewPosition.top + Height;
			NewPosition.right = NewPosition.left + Width;
			break;
		case dsDockLeft:
			NewPosition.top = ((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2);
			NewPosition.left = rcControl.left + 3; 
			NewPosition.bottom = NewPosition.top + Height;
			NewPosition.right = NewPosition.left + Width;
			break;
		case dsDockTop:
			NewPosition.top = rcControl.top + 3;  //((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2);
			NewPosition.left = ((rcControl.right-rcControl.left)/2) - (Width/2);  // rcControl.left + 3; 
			NewPosition.bottom = NewPosition.top + Height;
			NewPosition.right = NewPosition.left + Width;
			break;
		case dsDockBottom:
			NewPosition.top = rcControl.bottom - (Height + 2);  //((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2);
			NewPosition.left = ((rcControl.right-rcControl.left)/2) - (Width/2);  // rcControl.left + 3; 
			NewPosition.bottom = NewPosition.top + Height;
			NewPosition.right = NewPosition.left + Width;
			break;
		}
	}
	m_LegendRect = NewPosition;
}

void CChartLegend::Draw(CDC *pDC)
{
	if (!pDC->GetSafeHdc())
		return;
	if (!m_bIsVisible)
		return;
	if (m_LegendRect.IsRectEmpty())
		return;

	CPen SolidPen(PS_SOLID,0,RGB(0,0,0));
	CPen* pOldPen;
	CFont* pOldFont;
	CFont NewFont;
	NewFont.CreatePointFont(m_iFontSize,m_strFontName.c_str(),pDC);

	// Draw the shadow
	if (m_bShadow)
	{
		CRect ShadowRect = m_LegendRect;
		ShadowRect.OffsetRect(m_iShadowDepth,m_iShadowDepth);
		CBrush BrushShadow;
		BrushShadow.CreateSolidBrush(m_ShadowColor) ;
		pDC->FillRect(ShadowRect,&BrushShadow);
	}

	if (!m_bIsTransparent)
	{
		//Fill back color
		CBrush BrushBack;
		BrushBack.CreateSolidBrush(m_BackColor) ;
		pDC->FillRect(m_LegendRect,&BrushBack);
	}

	pOldFont = pDC->SelectObject(&NewFont);
	pOldPen = pDC->SelectObject(&SolidPen);

	//Draw rectangle:
	pDC->MoveTo(m_LegendRect.left,m_LegendRect.top);
	pDC->LineTo(m_LegendRect.right,m_LegendRect.top);
	pDC->LineTo(m_LegendRect.right,m_LegendRect.bottom);
	pDC->LineTo(m_LegendRect.left,m_LegendRect.bottom);
	pDC->LineTo(m_LegendRect.left,m_LegendRect.top);

	int iPrevMode = pDC->SetBkMode(TRANSPARENT);
	CRect rectBitmap(m_LegendRect.left+2,m_LegendRect.top+5,
					 m_LegendRect.left+2+m_BitmapSize.cx,
					 m_LegendRect.top+6+m_BitmapSize.cy);
	m_pParentCtrl->GoToFirstSerie();
	while (CChartSerie* pSerie=m_pParentCtrl->GetNextSerie())
	{
		if ( (pSerie->GetName() == _T("")) || !pSerie->IsVisible() )
			continue;

		int MaxHeight = 0;
		CSize TextSize = pDC->GetTextExtent(pSerie->GetName().c_str());
		if (TextSize.cy > m_BitmapSize.cy)
		{
			pDC->ExtTextOut(rectBitmap.right+4,rectBitmap.top,ETO_CLIPPED,NULL,pSerie->GetName().c_str(),NULL);
			CRect rectTemp(rectBitmap);
			int YOffset = TextSize.cy/2 - rectBitmap.Height()/2;
			rectTemp.OffsetRect(0,YOffset);
			pSerie->DrawLegend(pDC,rectTemp);
			MaxHeight = TextSize.cy;
		}
		else
		{
			int YOffset = rectBitmap.CenterPoint().y - TextSize.cy/2;
			pDC->ExtTextOut(rectBitmap.right+4,YOffset,ETO_CLIPPED,NULL,pSerie->GetName().c_str(),NULL);
			MaxHeight = m_BitmapSize.cy;
			pSerie->DrawLegend(pDC,rectBitmap);
		}
		

		if (!m_bIsHorizontal)
			rectBitmap.OffsetRect(0,MaxHeight+2);
		else
			rectBitmap.OffsetRect(m_BitmapSize.cx+4+TextSize.cx+10,0);
	}

	pDC->SetBkMode(iPrevMode);
	pDC->SelectObject(pOldFont);
	DeleteObject(NewFont);
	pDC->SelectObject(pOldPen);
	DeleteObject(SolidPen);
}