Click here to Skip to main content
15,879,326 members
Articles / Desktop Programming / MFC

2D Graph ActiveX Control

Rate me:
Please Sign up or sign in to vote.
4.89/5 (159 votes)
5 Aug 2003MIT8 min read 1.5M   70.2K   339  
An ActiveX control for 2D data visualisation
// NTGraphCtl.cpp : Implementation of the CNTGraphCtrl ActiveX Control class.
// Nikolai Teofilov (Sonntag, 9. M�rz 2003)
//

#include "stdafx.h"
#include "NTGraph.h"
#include "NTGraphCtl.h"
#include "NTGraphPpg.h"

#include <math.h>
#include "MemDC.h"
#define PT2DBLX(x) (double)((x - m_axisRect.left)*dResX)+ dRangeX[MIN]
#define PT2DBLY(y) (double)((m_axisRect.bottom - y)*dResY)+ dRangeY[MIN]


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


IMPLEMENT_DYNCREATE(CNTGraphCtrl, COleControl)


/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CNTGraphCtrl, COleControl)
	//{{AFX_MSG_MAP(CNTGraphCtrl)
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
#ifdef STATIC
	ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
#endif
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CNTGraphCtrl, COleControl)
	//{{AFX_DISPATCH_MAP(CNTGraphCtrl)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ShowGrid", m_showGrid, OnShowGridChanged, VT_BOOL)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "XLabel", m_strLabelX, OnXLabelChanged, VT_BSTR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "YLabel", m_strLabelY, OnYLabelChanged, VT_BSTR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "GridColor", m_gridColor, OnGridColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "LabelColor", m_labelColor, OnLabelColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "AxisColor", m_axisColor, OnAxisColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "NGridX", m_nGridX, OnNGridXChanged, VT_I2)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "NGridY", m_nGridY, OnNGridYChanged, VT_I2)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "GraphTitle", m_strGraphTitle, OnGraphTitleChanged, VT_BSTR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorColor", m_cursorColor, OnCursorColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ZoomMode", m_zoomMode, OnZoomModeChanged, VT_BOOL)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorMode", m_cursorMode, OnCursorModeChanged, VT_BOOL)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "XCursor", m_xCursor, OnXCursorChanged, VT_R8)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "YCursor", m_yCursor, OnYCursorChanged, VT_R8)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "PanMode", m_panMode, OnPanModeChanged, VT_BOOL)
	DISP_PROPERTY_EX(CNTGraphCtrl, "ElementCount", GetElementCount, SetElementCount, VT_I2)
	DISP_PROPERTY_EX(CNTGraphCtrl, "TickFont", GetTickFont, SetTickFont, VT_DISPATCH)
	DISP_PROPERTY_EX(CNTGraphCtrl, "TitleFont", GetTitleFont, SetTitleFont, VT_DISPATCH)
	DISP_PROPERTY_EX(CNTGraphCtrl, "LabelFont", GetLabelFont, SetLabelFont, VT_DISPATCH)
	DISP_FUNCTION(CNTGraphCtrl, "ClearGraph", ClearGraph, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CNTGraphCtrl, "CreateElement", CreateElement, VT_BOOL, VTS_I4)
	DISP_FUNCTION(CNTGraphCtrl, "SetRange", SetRange, VT_BOOL, VTS_R8 VTS_R8 VTS_R8 VTS_R8)
	DISP_FUNCTION(CNTGraphCtrl, "SetXYValue", SetXYValue, VT_BOOL, VTS_R8 VTS_R8 VTS_I4 VTS_I2)
	DISP_FUNCTION(CNTGraphCtrl, "Copy2Clipboard", Copy2Clipboard, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CNTGraphCtrl, "AutoRange", AutoRange, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CNTGraphCtrl, "ShowElement", ShowElement, VT_EMPTY, VTS_I2 VTS_BOOL)
	DISP_PROPERTY_PARAM(CNTGraphCtrl, "ElementLinetype", GetElementLinetype, SetElementLinetype, VT_I2, VTS_I2)
	DISP_PROPERTY_PARAM(CNTGraphCtrl, "ElementLinewidth", GetElementLinewidth, SetElementLinewidth, VT_I2, VTS_I2)
	DISP_PROPERTY_PARAM(CNTGraphCtrl, "ElementColor", GetElementColor, SetElementColor, VT_COLOR, VTS_I2)
	DISP_STOCKPROP_APPEARANCE()
	DISP_STOCKPROP_BACKCOLOR()
	DISP_STOCKPROP_BORDERSTYLE()
	DISP_STOCKPROP_ENABLED()
	DISP_STOCKPROP_CAPTION()
	//}}AFX_DISPATCH_MAP
	DISP_FUNCTION_ID(CNTGraphCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()


/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CNTGraphCtrl, COleControl)
	//{{AFX_EVENT_MAP(CNTGraphCtrl)
	EVENT_CUSTOM("CursorEvent", FireCursorEvent, VTS_R8  VTS_R8)
	//}}AFX_EVENT_MAP
END_EVENT_MAP()


/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CNTGraphCtrl, 3)
	PROPPAGEID(CNTGraphPropPage::guid)
	PROPPAGEID(CLSID_CColorPropPage)
	PROPPAGEID(CLSID_CFontPropPage)
END_PROPPAGEIDS(CNTGraphCtrl)


/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CNTGraphCtrl, "NTGRAPH.NTGraphCtrl.1",
	0x14f24365, 0x6c9d, 0x419e, 0x89, 0x94, 0xe7, 0xc9, 0x17, 0x9c, 0xa3, 0x4f)


/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CNTGraphCtrl, _tlid, _wVerMajor, _wVerMinor)


/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DNTGraph =
		{ 0x3b090608, 0x7603, 0x486d, { 0x9e, 0x9c, 0x9f, 0x26, 0x86, 0x4e, 0x13, 0xa0 } };
const IID BASED_CODE IID_DNTGraphEvents =
		{ 0x35000290, 0x97bd, 0x4b15, { 0xba, 0x89, 0xf4, 0xd, 0x82, 0x24, 0xdd, 0xd9 } };


/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwNTGraphOleMisc =
	OLEMISC_ACTIVATEWHENVISIBLE |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CNTGraphCtrl, IDS_NTGRAPH, _dwNTGraphOleMisc)


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::CNTGraphCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CNTGraphCtrl

BOOL CNTGraphCtrl::CNTGraphCtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegApartmentThreading to 0.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_NTGRAPH,
			IDB_NTGRAPH,
			afxRegApartmentThreading,
			_dwNTGraphOleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}

//////////////////////////////////////////////////////////////////////////////
// static FONTDESC structure containing default attributes of the fonts

static const FONTDESC _fontdescTick =
  { sizeof(FONTDESC), OLESTR("Arial"), FONTSIZE( 8 ), FW_NORMAL, 
     ANSI_CHARSET, FALSE, FALSE, FALSE };

static const FONTDESC _fontdescTitle =
  { sizeof(FONTDESC), OLESTR("Arial"), FONTSIZE( 12 ), FW_BOLD, 
     ANSI_CHARSET, FALSE, FALSE, FALSE };

static const FONTDESC _fontdescLabel =
  { sizeof(FONTDESC), OLESTR("Arial"), FONTSIZE( 12 ), FW_NORMAL, 
     ANSI_CHARSET, FALSE, FALSE, FALSE };

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::CNTGraphCtrl - Constructor

CNTGraphCtrl::CNTGraphCtrl() : m_fontTick( &m_xFontNotification ), 
                               m_fontTitle( &m_xFontNotification ), 
							   m_fontLabel( &m_xFontNotification )
{
	InitializeIIDs(&IID_DNTGraph, &IID_DNTGraphEvents);

	   
	COleControl::SetInitialSize(250,150);

	// Initialize the control's instance data.

 	m_strLabelX = "X Axis" ;
	m_strLabelY = "Y Axis" ;
	m_strGraphTitle = "XY Graph";
	m_nGridX = 5 ;
	m_nGridY = 5;
	
	bIsElementAllocated = FALSE ;
	bIsElementAvailable = FALSE;
	bIsFontCreated = FALSE;
	bUnzoom = FALSE;

	nPlotIndex = 0 ;
	nPointCount = 2000 ;
	nElementCount = 2 ;
	
	m_BGColor    = RGB(255,255,255);
	m_axisColor  = RGB(0,0,0);
	m_labelColor = RGB(0,0,0);
	m_gridColor  = RGB(0,0,0);
    m_cursorColor = RGB(255,0,0);

	SetRange(0,1,0,1);
	m_OldPoint=Corrdinate(0,0);



}

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::~CNTGraphCtrl - Destructor

CNTGraphCtrl::~CNTGraphCtrl()
{
	// TODO: Cleanup your control's instance data here.
	for( int i = 0  ; i < nElementCount ; i++){
		mpElement[i].DeleteElement() ;
	}

}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnDraw - Drawing function
void CNTGraphCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
   
	DoSuperclassPaint(pdc, rcBounds);

	m_ctlRect = rcBounds;
	PrepareForDrawing(pdc, &rcBounds);

	// make a memory dc
	CMemDC memDC(pdc, &rcBounds);	
	
	// set up a memory dc for the background stuff 
	// if one isn't being used
	if ((m_dcBackground.GetSafeHdc() == NULL) || (m_bitmapBackground.m_hObject == NULL))
	{
		m_dcBackground.CreateCompatibleDC(pdc) ;
		m_bitmapBackground.CreateCompatibleBitmap(pdc, m_ctlRect.Width(), m_ctlRect.Height()) ;
		m_pBitmapOldBackground = m_dcBackground.SelectObject(&m_bitmapBackground) ;

		// Fill this bitmap with the background.

		// Note: This requires some serious drawing and calculating, 
		// therefore it is drawn "once" to a bitmap and 
		// the bitmap is stored and blt'd when needed.

		CBrush hbrBackground(TranslateColor(GetBackColor()));
		m_dcBackground.FillRect (m_ctlRect,&hbrBackground);			
		hbrBackground.DeleteObject();
								
	}


	// drop in the background
	memDC.BitBlt(0, 0, m_ctlRect.Width(), m_ctlRect.Height(), 
			           &m_dcBackground, 0, 0, SRCCOPY) ;
    
	// add the Graph to the background
	DrawGraph(&memDC);

	delete m_pYLabelFont;
	
}

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::DoPropExchange - Persistence support

void CNTGraphCtrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.
    PX_Bool(pPX,_T("ShowGrid"),m_showGrid,FALSE);
	PX_Bool(pPX,_T("PanMode"),m_panMode,FALSE);
	PX_Bool(pPX,_T("CursorMode"),m_cursorMode,FALSE);
	PX_Bool(pPX,_T("ZoomMode"),m_zoomMode,FALSE);
	PX_Font(pPX, _T("TickFont"), m_fontTick, &_fontdescTick);
	PX_Font(pPX, _T("TitleFont"), m_fontTitle, &_fontdescTitle);
	PX_Font(pPX, _T("LabelFont"), m_fontLabel, &_fontdescLabel);

}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::GetControlFlags -
// Flags to customize MFC's implementation of ActiveX controls.
//
// For information on using these flags, please see MFC technical note
// #nnn, "Optimizing an ActiveX Control".
DWORD CNTGraphCtrl::GetControlFlags()
{
	DWORD dwFlags = COleControl::GetControlFlags();


	// The control will not be redrawn when making the transition
	// between the active and inactivate state.
	dwFlags |= noFlickerActivate;
	return dwFlags;
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnResetState - Reset control to default state

void CNTGraphCtrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange

	// TODO: Reset any other control state here.
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::AboutBox - Display an "About" box to the user

void CNTGraphCtrl::AboutBox()
{
	CDialog dlgAbout(IDD_ABOUTBOX_NTGRAPH);
	dlgAbout.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
BOOL CNTGraphCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
	// cs.lpszClass = _T("STATIC");
	
	// Add the Transparent style to the control
    // cs.dwExStyle |= WS_EX_TRANSPARENT;

	return COleControl::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::IsSubclassedControl - This is a subclassed control
BOOL CNTGraphCtrl::IsSubclassedControl()
{
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnOcmCommand - Handle command messages

LRESULT CNTGraphCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
{
#ifdef _WIN32
	WORD wNotifyCode = HIWORD(wParam);
#else
	WORD wNotifyCode = HIWORD(lParam);
#endif

	// TODO: Switch on wNotifyCode here.

	return 0;
}




/////////////////////////////////////////////////////////////////////////////
////////////////////////// Source of CGraphElement //////////////////////////
/////////////////////////////////////////////////////////////////////////////
CGraphElement::CGraphElement() 
{
	    dValueX = NULL ;
		dValueY = NULL ;
		bIsPlotAvailable = FALSE ;
		bBufferAllocated = FALSE ;
		m_Color = RGB(0,0,0);
		m_Type =   0;
		m_Width =  0;
		m_nCount = 0;        // Added by A. Hofmann		
		m_bShow = TRUE;      // Added by A. Hofmann
}

BOOL CGraphElement::NewElement(UINT nPoint)
{

	dValueX = new double[nPoint] ; 
	dValueY = new double[nPoint] ;  
	if ( (!dValueX) || (!dValueY) ) 
		return FALSE ;
	bBufferAllocated = TRUE ;
	return TRUE ;

}

BOOL CGraphElement::DeleteElement()
{
	if ( bBufferAllocated ) {
		delete [] dValueX;
		delete [] dValueY ;		
	}
	bBufferAllocated = FALSE ;
	return TRUE ;
}

/////////////////////////////////////////////////////////////////////
void CNTGraphCtrl::PrepareForDrawing(CDC *pDC, CRect rect)
{

	m_BGColor=TranslateColor(GetBackColor());
 
	m_ctlRect = rect ;
	CreateYFont(pDC); // Create system font for Y label  

	CalcRect(pDC) ; // Compute rectangle 
	ResCalc();   // Compute resolution per dot.

    pDC->SetViewportExt (rect.right , rect.bottom );
    pDC->DPtoLP(&m_ctlRect);
 
}

void CNTGraphCtrl::DrawGraph(CDC *pDC)
{
	DrawTitle(pDC);	
	DrawAxis(pDC);
	DrawAxisLabel(pDC);
        
	if (m_showGrid)
		DrawGrid(pDC);
	else 
		DrawTicks(pDC);

	if (m_cursorMode)
		DrawCursor(pDC);

	PlotElement(pDC) ;
}


void CNTGraphCtrl::DrawAxis(CDC *pDC)
{

	CPen *old , pen(PS_SOLID, 2, m_axisColor);
	
	old = pDC->SelectObject(&pen) ;
		pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MIN]));
		pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MIN]));
		pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MIN]));
		pDC->LineTo(Corrdinate(dRangeX[MIN],dRangeY[MAX]));
        pDC->MoveTo(Corrdinate(dRangeX[MAX],dRangeY[MIN]));
		pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MAX]));
		pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MAX]));
		pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MAX]));
	pDC->SelectObject(old) ;
	pen.DeleteObject();
}

void CNTGraphCtrl::DrawTitle(CDC *pDC)
{

	CFont* pOldFont;
	TEXTMETRIC tm;

	pOldFont = SelectFontObject(pDC, m_fontTitle);
	pDC->SetTextColor (m_labelColor);
    pDC->GetTextMetrics(&tm);

	pDC->SetTextAlign(TA_TOP | TA_CENTER);
	pDC->SetBkMode(TRANSPARENT);
    pDC->TextOut((m_ctlRect.left + m_ctlRect.right) / 2,
                 (m_ctlRect.top+m_axisRect.top - tm.tmHeight) / 2,
                  m_strGraphTitle, m_strGraphTitle.GetLength());


   pDC->SelectObject(pOldFont);

}

void CNTGraphCtrl::DrawGrid(CDC *pDC)
{
	CPen *old , pen(PS_SOLID, 0, m_gridColor);
	CPoint m_start, m_stop ;
	int i  ;
	double x ,y ;
	double step ;

	old = pDC->SelectObject(&pen);
	
	// Draw vertical grid 

	step = (dRangeX[MAX] - dRangeX[MIN]) / (double)m_nGridX ;
	for( i = 1 ; i < m_nGridX ; i++ )
	{
		x = dRangeX[MIN] + (step * (double)i) ;
		m_start = Corrdinate(x,dRangeY[MIN]);
		m_stop  = Corrdinate(x,dRangeY[MAX]);
		pDC->MoveTo(m_start);
		pDC->LineTo(m_stop);
	}
	
	// Draw horizontal grid.

	step = (dRangeY[MAX] - dRangeY[MIN]) / (double)m_nGridY ;
	for( i = 1 ; i < m_nGridY ; i++ )
	{
		y = dRangeY[MIN] + (step * (double)i) ;
		m_start = Corrdinate(dRangeX[MIN],y) ;
		m_stop  = Corrdinate(dRangeX[MAX],y) ;
		pDC->MoveTo(m_start);
		pDC->LineTo(m_stop);
	}
	
	pDC->SelectObject(old);
}

void CNTGraphCtrl::DrawAxisLabel(CDC *pDC)
{
	CFont *pOldFont;

	int i ;
	double res , x, y  ; 
	CPoint point ;
	CSize txtSize ;
	CString str ;

	pDC->SetTextColor (m_labelColor);
	pDC->SetTextAlign(TA_RIGHT);
	pDC->SetBkMode(TRANSPARENT);

    ////////////////////////////////////////////////
	pOldFont  = SelectFontObject(pDC, m_fontTick);
	////////////////////////////////////////////////
	
	res = (dRangeY[MAX] - dRangeY[MIN]) / m_nGridY ;

	CSize sz;
	sz.cx=0;

	// Draw Y Tick Labels
	for ( i = 0 ; i <= m_nGridY ; i++)
	{
		y = dRangeY[MIN] + (res * (double)i) ;
		point = Corrdinate(dRangeX[MIN],y) ;

		str.Format("%g",y) ;

		txtSize = pDC->GetTextExtent(str) ;

		if (sz.cx < txtSize.cx) sz=txtSize;

		point.x -= 5 ;
		point.y -= txtSize.cy/2 ;

		pDC->TextOut(point.x,point.y,str) ;
	}


	// Draw X Tick Labels
	res = (dRangeX[MAX] - dRangeX[MIN]) / m_nGridX ;

	for ( i = 0 ; i <= m_nGridX ; i ++ )
	{
		x = dRangeX[MIN] + ( res * (double)i);
		point = Corrdinate(x,dRangeY[MIN]);
		
		str.Format("%g",x);

		txtSize = pDC->GetTextExtent(str) ;

		point.x += txtSize.cx/2;
		point.y += 5 ;

		pDC->TextOut(point.x,point.y,str);
	}
	 
    ////////////////////////////////////////////////
    SelectFontObject(pDC, m_fontLabel);
	////////////////////////////////////////////////

    // Draw X Axis Title
	txtSize = pDC->GetTextExtent(m_strLabelX);
    point.x = m_axisRect.CenterPoint().x + (txtSize.cx/2); 
	point.y = (m_ctlRect.bottom + m_axisRect.bottom)/2;
	point.y -= (txtSize.cy - sz.cy)/2;
    
	pDC->TextOut(point.x,point.y,m_strLabelX);

    //////////////////////////////////////////////
    pDC->SelectObject(m_pYLabelFont);
	//////////////////////////////////////////////

	// Draw Y Axis Title
	txtSize = pDC->GetTextExtent(m_strLabelY);
	point.x = (m_ctlRect.left+m_axisRect.left)/2;
	point.x -= ( txtSize.cy + sz.cx )/2 ;
	point.y = m_axisRect.CenterPoint().y  - (txtSize.cx/2);
	pDC->TextOut(point.x,point.y,m_strLabelY);
	
	pDC->SelectObject(pOldFont);

}

//////////////////////////////////
// Draw ticks in 1/5 fine scale 
void CNTGraphCtrl::DrawTicks(CDC *pDC)
{

	CPen *old , pen(PS_SOLID, 0, m_gridColor);
	CPoint m_start, m_stop ;
	int i  ;
	double x ,y ;
	double step ;

	old = pDC->SelectObject(&pen);
	
	// Draw vertical Major Ticks 

	step = (dRangeX[MAX] - dRangeX[MIN]) / (double)m_nGridX ;
	for( i = 1 ; i < m_nGridX ; i++ )
	{
		x = dRangeX[MIN] + (step * (double)i) ;
		m_start = Corrdinate(x,dRangeY[MIN]);
		m_stop = m_start; m_stop.y -= 5;	// Major Ticks on Botom
		pDC->MoveTo(m_start);
		pDC->LineTo(m_stop);
	}

	for( i = 1 ; i < m_nGridX ; i++ )
	{
		x = dRangeX[MIN] + (step * (double)i) ;
		m_start = Corrdinate(x,dRangeY[MAX]);
		m_stop = m_start; m_stop.y += 5;	// Major Ticks on Top
		pDC->MoveTo(m_start);
		pDC->LineTo(m_stop);
	}
	

	// Draw horizontal Major Ticks
	step = (dRangeY[MAX] - dRangeY[MIN]) / (double)m_nGridY ;
	for( i = 1 ; i < m_nGridY ; i++ )
	{
		y = dRangeY[MIN] + (step * (double)i) ;
		m_start = Corrdinate(dRangeX[MIN],y) ;
		m_stop  = m_start; m_stop.x += 5;	 // Major Ticks on Left
		pDC->MoveTo(m_start);
		pDC->LineTo(m_stop);
	}
	
	for( i = 1 ; i < m_nGridY ; i++ )
	{
		y = dRangeY[MIN] + (step * (double)i) ;
		m_start = Corrdinate(dRangeX[MAX],y) ;
		m_stop  = m_start; m_stop.x -= 5;	// Major Ticks on Right
		pDC->MoveTo(m_start);
		pDC->LineTo(m_stop);
	}

	pDC->SelectObject(old);
}

void CNTGraphCtrl::PlotElement(CDC *pDC)
{
	
	// If there is no data available for plot then return .
	if ( !nPlotIndex ) return ;
		
	CPen *oldPen , *pen;
	CBrush *oldBrush , *brush;
	CPoint pt;
	
	for(int i = 0 ; i < nElementCount ; i++) 
	{

		// Added by A.Hofmann
		//////////////////////////////////
		// Check show state of the element
		if ( ! mpElement[i].m_bShow )
			continue;

		

		// Create the new pen as the color of serie 
		pen = new CPen(mpElement[i].m_Type, mpElement[i].m_Width, mpElement[i].m_Color);
		oldPen = pDC->SelectObject(pen) ; 

		// Create the new brush as the color of serie 
		brush = new CBrush(mpElement[i].m_Color);
		oldBrush = pDC->SelectObject(brush) ; 		
		

		
   		double X,Y;
		X=mpElement[i].dValueX[0];
        Y=mpElement[i].dValueY[0];

		// Clip the ploting area if it exceed ranged .
		if(X > dRangeX[MAX] ) X = dRangeX[MAX] ;
		if(X < dRangeX[MIN] ) X = dRangeX[MIN] ;
		if(Y > dRangeY[MAX] ) Y = dRangeY[MAX] ;
		if(Y < dRangeY[MIN] ) Y = dRangeY[MIN] ;

		// calculate the corrdinate of ploting point.
		pt = Corrdinate(X,Y) ;
		pDC->MoveTo(pt);

		CPoint old_pt(pt);
		//Start plot all available data.
		for(int index = 1 ; index <= mpElement[i].m_nCount ; index++){

			X=mpElement[i].dValueX[index];
            Y=mpElement[i].dValueY[index];

			// Clip the ploting area if it exceed ranged.
			if(X > dRangeX[MAX] ) X = dRangeX[MAX] ;
			if(X < dRangeX[MIN] ) X = dRangeX[MIN] ;
			if(Y > dRangeY[MAX] ) Y = dRangeY[MAX] ;
			if(Y < dRangeY[MIN] ) Y = dRangeY[MIN] ;

			pt = Corrdinate(X,Y);
            
			
			if(	((old_pt.x==pt.x)&&
				   ((pt.x==m_axisRect.BottomRight().x)||(pt.x==m_axisRect.TopLeft().x)))
				|| 
				((old_pt.y==pt.y)&&
			        ((pt.y==m_axisRect.BottomRight().y)||(pt.y==m_axisRect.TopLeft().y)))
			  )
			{
				pDC->MoveTo(pt) ;
				continue;
			}          				

			int symsz = mpElement[i].m_Width;
			if (symsz <= 0) symsz = 1;
			CRect rect(pt.x-symsz,pt.y-symsz,pt.x+symsz,pt.y+symsz);

			if (mpElement[i].m_Type <=5)	    // Draw lines.
				pDC->LineTo(pt);
    		else if (mpElement[i].m_Type == 6)	// Draw dots.
				pDC->Ellipse(rect);
			else if (mpElement[i].m_Type == 7)	// Draw rectangles.
			   	pDC->Rectangle(rect);			
			else
				pDC->MoveTo(pt) ;

			old_pt=pt;
	
		    
		}

	    pDC->SelectObject(oldPen);
		delete pen ;
		pDC->SelectObject(oldBrush);
		delete brush;


	}


}


void CNTGraphCtrl::DrawCursor(CDC *pDC)
{

  CPen *old , pen(PS_SOLID, 1, m_cursorColor);
  	
	old = pDC->SelectObject(&pen) ;
        pDC->MoveTo(Corrdinate(m_xCursor,dRangeY[MIN]));
		pDC->LineTo(Corrdinate(m_xCursor,dRangeY[MAX]));
		pDC->MoveTo(Corrdinate(dRangeX[MIN],m_yCursor));
		pDC->LineTo(Corrdinate(dRangeX[MAX],m_yCursor));
	pDC->SelectObject(old) ;
}

void CNTGraphCtrl::ClearGraph()
{
	// Added by A. Hofmann
	for(int i = 0 ; i < nElementCount; i++ )
		mpElement[i].m_nCount = 0;

	dAutoRangeX[MIN]=dRangeX[MIN];
    dAutoRangeY[MIN]=dRangeY[MIN];
	dAutoRangeX[MAX]=dRangeX[MAX];
	dAutoRangeY[MAX]=dRangeY[MAX];
	bIsElementAvailable=FALSE;
	
	nPlotIndex = 0 ;
	InvalidateControl();
}

///////////////////////////////////////////////
// Allocate memory for the elements 
BOOL CNTGraphCtrl::CreateElement(long nElement)
{
	
	if( !bIsElementAllocated )
	{
		for(int i = 0 ; i < nElementCount ; i++ ) {
			if ( !mpElement[i].NewElement(nElement)) {
				AfxMessageBox("Can not allocate element!") ;
				return FALSE ;
			}
		}
	}
	
	nPointCount = nElement ;
	bIsElementAllocated = TRUE ;
	return TRUE ;

}

BOOL CNTGraphCtrl::SetRange(double MinX, double MaxX, double MinY, double MaxY) 
{
	dRangeY[MIN] = MinY ;
	dRangeY[MAX] = MaxY ;
	dRangeX[MAX] = MaxX ;
	dRangeX[MIN] = MinX ;

	InvalidateControl();
	return TRUE;
}

BOOL CNTGraphCtrl::SetXYValue(double X, double Y, long index, short iElementId) 
{
	if(!bIsElementAllocated ) return FALSE;
	if (iElementId > (nElementCount-1)) return FALSE;

	// Prevent writting to unallocated buffer 
	if(index >= nPointCount ) return FALSE;

	if(bIsElementAvailable) 
	{

		if(X<dAutoRangeX[MIN])	dAutoRangeX[MIN]=X;
		if(Y<dAutoRangeY[MIN])	dAutoRangeY[MIN]=Y;
		if(X>dAutoRangeX[MAX])	dAutoRangeX[MAX]=X;
		if(Y>dAutoRangeY[MAX])  dAutoRangeY[MAX]=Y;
		
	} else {

        dAutoRangeX[MIN]=X*0.9;
        dAutoRangeY[MIN]=Y*0.9;
		dAutoRangeX[MAX]=X*1.1;
		dAutoRangeY[MAX]=Y*1.1;
		bIsElementAvailable = TRUE ;
    }
		
	mpElement[iElementId].dValueX[index] = X ;
	mpElement[iElementId].dValueY[index] = Y ;
	mpElement[iElementId].bIsPlotAvailable = TRUE ;
	mpElement[iElementId].m_nCount = index; // Added by A. Hofmann

	nPlotIndex = index ;
    
	InvalidateControl();

	return TRUE;
}

CPoint CNTGraphCtrl::Corrdinate(double x, double y)
{
	double rx , ry ;
	int xPixel , yPixel ;
	CPoint retPt ;

	rx = x - dRangeX[MIN] ; // Calculate horizontal offset from origin
	ry = y - dRangeY[MIN] ; // Calculate vertical offset from origin .

	// Convert offset to be number of pixel on screen .
	xPixel = (int)(rx / dResX) ; 
	yPixel = (int)(ry / dResY) ;

	//Calulate point to be drawn .
	retPt.x= xPixel + m_axisRect.left ;
	retPt.y= m_axisRect.bottom - yPixel; 
	return retPt ;
}

void CNTGraphCtrl::CalcRect(CDC *pDC)
{
	int offset = 15;
    
	CSize txtXLabelSize,txtYLabelSize(0,0),txtTitleSize ;
	CString str ;
	CFont *pOldFont, *pSaveFont ;

	pOldFont  = SelectFontObject(pDC, m_fontTick);
	
	double res = (dRangeY[MAX] - dRangeY[MIN]) / m_nGridY ;
	
	// Calculate Y Label sizes.
	CSize sz(0,0);
	for (int i = 0 ; i <= m_nGridY ; i++)
	{
	    double y = dRangeY[MIN] + (res * (double)i) ;
		str.Format("%g",y) ;
		sz = pDC->GetTextExtent(str);
		if (txtYLabelSize.cx < sz.cx) txtYLabelSize=sz;
	}

	str.Format("%g",dRangeX[MAX]);
	txtXLabelSize = pDC->GetTextExtent(str);
	
	pDC->SelectObject(pOldFont);
	pSaveFont = SelectFontObject(pDC, m_fontTitle);

	txtTitleSize = pDC->GetTextExtent(m_strLabelX);
	pDC->SelectObject(pSaveFont);

	m_axisRect.left  = m_ctlRect.left + txtTitleSize.cy+txtYLabelSize.cx + offset;
	m_axisRect.right = m_ctlRect.right - (txtXLabelSize.cx/2) - offset;
	m_axisRect.top   = m_ctlRect.top + txtTitleSize.cy + offset;
	m_axisRect.bottom= m_ctlRect.bottom - (txtTitleSize.cy+txtXLabelSize.cy) - offset; 

}

////////////////////////////////
//Calculate resolution per dot
void CNTGraphCtrl::ResCalc()
{
	double dpixelx, dpixely ;

	dpixelx = (double)m_axisRect.Width() ;
	dpixely = (double)m_axisRect.Height() ;
	dResY = (dRangeY[MAX] - dRangeY[MIN]) / dpixely ;
	dResX = (dRangeX[MAX] - dRangeX[MIN]) / dpixelx ;

}
/////////////////////////////////////////////////////////////////////////////
// Create desired fonts for draw labels on x axis and y axis and graph title.
void CNTGraphCtrl::CreateYFont(CDC *pDC)
{
		
	//Create system font ..
	LOGFONT lf;
	CFont *pOldFont,*pLogFont;
		
	pOldFont  = SelectFontObject(pDC, m_fontLabel);
	pLogFont  = pDC->SelectObject(pOldFont);

	    
	// Retrieve a copy of the LOGFONT structure 
	// for a currently selected stock font.
	if (pLogFont)
        pLogFont->GetLogFont(&lf);
	
	// Rotate font 90 degree for Y axis label
	SetGraphicsMode( pDC->m_hDC, GM_ADVANCED );
	lf.lfOrientation = 900 ; 
	lf.lfEscapement = 900 ;
	
	m_pYLabelFont = new CFont;
	m_pYLabelFont->CreateFontIndirect(&lf);

    pDC->SelectObject(pOldFont);

}


void CNTGraphCtrl::CursorPosition(CPoint point) 
{
     double rx,ry;

	 rx = PT2DBLX(point.x);
	 ry = PT2DBLY(point.y);
      
	 if (m_axisRect.PtInRect(point)) 
	 {
		m_xCursor = rx;
		m_yCursor = ry;
	 }

	//Fire Cursor Position Event
	FireCursorEvent(rx,ry);
	
}

void CNTGraphCtrl::OnShowGridChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnXLabelChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnYLabelChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnGridColorChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnLabelColorChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnAxisColorChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnNGridXChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnNGridYChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}



short CNTGraphCtrl::GetElementCount() {	return nElementCount;}

void CNTGraphCtrl::SetElementCount(short nNewValue) 
{
    nElementCount = nNewValue;
	if (nElementCount <0) 
		nElementCount=0;
	SetModifiedFlag();
}

void CNTGraphCtrl::OnCursorModeChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnGraphTitleChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnCursorColorChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}


void CNTGraphCtrl::OnZoomModeChanged() 
{
	
	dOldRangeX[MIN]=dRangeX[MIN];
	dOldRangeY[MIN]=dRangeY[MIN];
	dOldRangeX[MAX]=dRangeX[MAX];
	dOldRangeY[MAX]=dRangeY[MAX];

	bUnzoom = TRUE;
	SetModifiedFlag();
}


////////////////////////////////////////////////////////
//  Implementation of the Custom Font Proprties
LPDISPATCH CNTGraphCtrl::GetTickFont() { return m_fontTick.GetFontDispatch( ); }

void CNTGraphCtrl::SetTickFont(LPDISPATCH newValue) 
{
	m_fontTick.InitializeFont( &_fontdescTick, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );
}

LPDISPATCH CNTGraphCtrl::GetTitleFont() { return m_fontTitle.GetFontDispatch( ); }

void CNTGraphCtrl::SetTitleFont(LPDISPATCH newValue) 
{
	m_fontTitle.InitializeFont( &_fontdescTitle, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );
}

LPDISPATCH CNTGraphCtrl::GetLabelFont() { return m_fontLabel.GetFontDispatch( ); }

void CNTGraphCtrl::SetLabelFont(LPDISPATCH newValue) 
{
	m_fontLabel.InitializeFont( &_fontdescLabel, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );

}

void CNTGraphCtrl::OnFontChanged() 
{
	//bIsFontCreated = FALSE;
	InvalidateControl();
	SetModifiedFlag( );
	COleControl::OnFontChanged();
}

////////////////////////////////////////////////////////
// New Method Show/Hide Graph Element
// Added by A.Hofmann
void CNTGraphCtrl::ShowElement(short ElementID, BOOL bShow) 
{

	if (bIsElementAllocated) 
		mpElement[ElementID].m_bShow = bShow;
	InvalidateControl();

	SetModifiedFlag();
}
////////////////////////////////////////////////////////
// New Method to copy a control bitmap to the clipboard
// Code Project Article: "Clipboard Copy in a Nutshell"
// by Keith Rule
void CNTGraphCtrl::Copy2Clipboard() 
{
    CRect rect;
    CClientDC dc(this);
    GetClientRect(&rect);
	CDC memDC;
    CBitmap bitmap;
    
	// Create memDC
    memDC.CreateCompatibleDC(&dc);
    bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
    CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
    
	// Fill in memDC
    memDC.FillSolidRect(rect, dc.GetBkColor());
    OnDraw(&memDC, rect, rect);
    
	// Copy contents of memDC to clipboard
    OpenClipboard();
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, bitmap.GetSafeHandle()); // CF_METAFILEPICT
    CloseClipboard();
    
	// Clean up
    memDC.SelectObject(pOldBitmap);
    bitmap.Detach();	

}


///////////////////////////////////////////////////////////
//  Samstag, 25. Januar 2003 20.20 Uhr Nikolai
///////////////////////////////////////////////////////////
void CNTGraphCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	

	CursorPosition(point);
	m_OldPoint = point;

	if (m_cursorMode)
        InvalidateControl();       
     
	if (m_zoomMode && nFlags==MK_LBUTTON) 
	{
		if (bUnzoom) 
		{
			dOldRangeX[MIN]=dRangeX[MIN];
			dOldRangeY[MIN]=dRangeY[MIN];
			dOldRangeX[MAX]=dRangeX[MAX];
			dOldRangeY[MAX]=dRangeY[MAX];
			bUnzoom = FALSE;
		}
         
		CRectTracker tracker;
		double xmin, xmax, ymin, ymax;
        xmin=dRangeX[MIN];
        xmin=dRangeX[MAX];
		ymin=dRangeY[MIN];
		ymax=dRangeY[MAX];

		if (tracker.TrackRubberBand(this, point) )
		{
			CPoint pt1, pt2;

			tracker.m_rect.NormalizeRect ();
			pt1= tracker.m_rect.TopLeft ();
			pt2= tracker.m_rect.BottomRight ();

			xmin = PT2DBLX(pt1.x);
			ymax = PT2DBLY(pt1.y);
			xmax = PT2DBLX(pt2.x);
			ymin = PT2DBLY(pt2.y);
					
		}

		SetRange(xmin,xmax,ymin,ymax);	
		
		//MessageBeep(0);

		// Don't ask me why!
		CClientDC dc(this); 
		SendMessage(WM_LBUTTONUP, (WPARAM) dc.GetSafeHdc(), 0);
		
    }

	COleControl::OnLButtonDown(nFlags, point);
}

void CNTGraphCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{


	if (m_axisRect.PtInRect(point)) { 

		if (nFlags==MK_LBUTTON) 
		{
			if (m_cursorMode) 
			{
				double x,y;

				x = PT2DBLX(point.x);
				y = PT2DBLY(point.y);

				CString str;
				str.Format("x= %g y= %g",x,y);
				m_ttip.UpdateTipText(LPCTSTR(str), this);

				RelayEvent(WM_LBUTTONDOWN, (WPARAM)nFlags,
				MAKELPARAM(LOWORD(point.x), LOWORD(point.y)));
            }

			if (m_panMode)
			{
				DoPan(point);
				SetCursor(AfxGetApp()->LoadCursor(IDC_PANMOVE));
			}
        }

		
        
		if (m_cursorMode)
		       	SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
		else if (m_zoomMode)
		        SetCursor(AfxGetApp()->LoadCursor(IDC_MAGNIFY));
	}
	else 
	{
       	SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));

		TOOLINFO ti;
		FillToolInfo(&ti);
		m_ttip.SendMessage(TTM_TRACKACTIVATE, FALSE, (LPARAM)&ti);
	}


	COleControl::OnMouseMove(nFlags, point);
}

void CNTGraphCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	
	if(m_zoomMode)
		SetRange(dOldRangeX[MIN],dOldRangeX[MAX],dOldRangeY[MIN],dOldRangeY[MAX]);
	
	COleControl::OnRButtonDown(nFlags, point);
}

void CNTGraphCtrl::AutoRange() 
{
	if (!bIsElementAvailable) {
		dAutoRangeX[MIN]=dRangeX[MIN];
        dAutoRangeY[MIN]=dRangeY[MIN];
		dAutoRangeX[MAX]=dRangeX[MAX];
		dAutoRangeY[MAX]=dRangeY[MAX];
	}
	SetRange(dAutoRangeX[MIN],dAutoRangeX[MAX],dAutoRangeY[MIN],dAutoRangeY[MAX]);
}

void CNTGraphCtrl::OnXCursorChanged() 
{
   if (m_cursorMode)
		InvalidateControl();

   SetModifiedFlag();
}

void CNTGraphCtrl::OnYCursorChanged() 
{
   if (m_cursorMode)
	InvalidateControl();

	SetModifiedFlag();
}


int CNTGraphCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (COleControl::OnCreate(lpCreateStruct) == -1)
		return -1;


	if (m_ttip.Create(this, TTS_ALWAYSTIP) && 
		m_ttip.AddTool(this)
		&& m_ttip.AddTool(this, LPCTSTR("Graph"))
		&&	m_ttip.AddTool(this, TTF_TRACK))
	{
		
	    TOOLINFO ti;
        FillToolInfo(&ti);

        m_ttip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti);
        m_ttip.SetDelayTime(TTDT_AUTOPOP, SHRT_MAX);   // stop the tooltip coming up automatically
        m_ttip.SetDelayTime(TTDT_INITIAL, 0);

	}
	else
	{
		TRACE("Error in creating ToolTip");
		
	}
	
	return 0;
}

void CNTGraphCtrl::RelayEvent(UINT message, WPARAM wParam, LPARAM lParam)
{

	
	TOOLINFO ti;
	FillToolInfo(&ti);
	m_ttip.SendMessage(TTM_TRACKACTIVATE, m_cursorMode, (LPARAM)&ti);
	
	
	if (NULL != m_ttip.m_hWnd) {
       MSG msg;

       msg.hwnd= m_hWnd;
       msg.message= message;
       msg.wParam= wParam;
       msg.lParam= lParam;
       msg.time= 0;
       msg.pt.x= LOWORD (lParam);
       msg.pt.y= HIWORD (lParam);

       m_ttip.RelayEvent(&msg);

   }
}

void CNTGraphCtrl::FillToolInfo(TOOLINFO *ti)
{
    memset(ti, 0, sizeof(TOOLINFO));
    ti->cbSize = sizeof(TOOLINFO);
    ti->hwnd = GetParent()->GetSafeHwnd();
    ti->uFlags = TTF_IDISHWND | TTF_ABSOLUTE | TTF_TRACK;
    ti->uId = (UINT)GetSafeHwnd();
}

/////////////////////////////////////////////
// Pan Mode
void CNTGraphCtrl::OnPanModeChanged() 
{
	m_OldPoint=Corrdinate(0,0);

	SetModifiedFlag();
}

void CNTGraphCtrl::DoPan(CPoint point)
{
	double Y1 = PT2DBLY(point.y);
	double Y2 = PT2DBLY(m_OldPoint.y);
	double yOffset = Y1 - Y2;
	
	double X1 =  PT2DBLX(point.x);
	double X2 =  PT2DBLX(m_OldPoint.x);
	double xOffset = X1 - X2;
	
	SetRange(dRangeX[MIN] - xOffset, dRangeX[MAX] - xOffset, 
			 dRangeY[MIN] - yOffset, dRangeY[MAX] - yOffset);

	m_OldPoint = point;
}

//////////////////////////////////////////////////////////// 
// Modified (09.03.2003)
OLE_COLOR CNTGraphCtrl::GetElementColor(short ElementID) 
{
	return mpElement[ElementID].m_Color;
}

void CNTGraphCtrl::SetElementColor(short ElementID, OLE_COLOR nNewValue) 
{
	mpElement[ElementID].m_Color = nNewValue;
    InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::SetElementLinetype(short ElementID, short nNewValue) 
{
	if (bIsElementAllocated) 
		mpElement[ElementID].m_Type = nNewValue;

	InvalidateControl();
 	SetModifiedFlag();
}

short CNTGraphCtrl::GetElementLinetype(short ElementID) 
{
	if (bIsElementAllocated) 
		return mpElement[ElementID].m_Type ;

	return 0;
}

void CNTGraphCtrl::SetElementLinewidth(short ElementID, short nNewValue) 
{
	if (bIsElementAllocated) 
		mpElement[ElementID].m_Width = nNewValue;

	InvalidateControl();
 	SetModifiedFlag();
}

short CNTGraphCtrl::GetElementLinewidth(short ElementID) 
{
	if (bIsElementAllocated) 
		return mpElement[ElementID].m_Width ;
	return 0;
}
//////////////////////////////////////////////////////////////////////


/*
////////////////////////////////////////////
// Print Graph
// GDI Leak
// ^^^ ^^^^
void CNTGraphCtrl::PrintGraph()
{
       char   pbuf[100] = "NTGraph ActiveX Control Demo";
       HDC    hdcPrn ;

       // Instantiate a CPrintDialog.
       CPrintDialog *printDlg =
           new CPrintDialog(FALSE, PD_ALLPAGES | PD_RETURNDC, NULL);

       // Initialize some of the fields in PRINTDLG structure.
       printDlg->m_pd.nMinPage = printDlg->m_pd.nMaxPage = 1;
       printDlg->m_pd.nFromPage = printDlg->m_pd.nToPage = 1;

       // Display Windows print dialog box.
       printDlg->DoModal();

       // Obtain a handle to the device context.
       hdcPrn = printDlg->GetPrinterDC();
       if (hdcPrn != NULL)
           {
           CDC *pDC = new CDC;
           pDC->Attach (hdcPrn);   // attach a printer DC

           pDC->StartDoc("test");  // begin a new print job

           pDC->StartPage();          // begin a new page
           pDC->TextOut(100, 10, pbuf);// write the string in pbuf
           
           DoPrint(pDC,100,100);

		    
           pDC->EndPage();            // end a page

           pDC->EndDoc();             // end a print job

           pDC->Detach();             // detach the printer DC
           delete pDC;
           }

       delete printDlg;

	InvalidateControl();
}


void CNTGraphCtrl::DoPrint(CDC *pDC, int x, int y)
{
	int xPixel ;
	int yPixel  ;
	int oldmapmode ;

	CDC *dc = GetDC();
	
	xPixel = pDC->GetDeviceCaps(LOGPIXELSX);
	yPixel = pDC->GetDeviceCaps(LOGPIXELSY);
	
	//Calculate ratio to be zoomed.
	xPixel =  xPixel /dc->GetDeviceCaps(LOGPIXELSX);
	yPixel =  yPixel /dc->GetDeviceCaps(LOGPIXELSY);
	ReleaseDC(dc);
	
	oldmapmode = pDC->SetMapMode(MM_ANISOTROPIC);
	pDC->SetViewportExt(xPixel,yPixel);
	pDC->SetViewportOrg(x, y);

	CreateFont(pDC); 

	// add the Graph to the background
	pDC->FillSolidRect(m_ctlRect,m_BGColor);
	DrawGraph(pDC);
	m_pYLabelFont->DeleteObject();

	pDC->SetMapMode(oldmapmode);
}
*/

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions