// NTGraphCtl.cpp : Implementation of the CNTGraphCtrl ActiveX Control class.
#include "stdafx.h"
#include "NTGraph.h"
#include "NTGraphCtl.h"
#include "NTGraphPpg.h"
#include <math.h>
#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_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
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, "ChangeMappingMode", m_changeMappingMode, OnChangeMappingModeChanged, 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, "MinX", m_minX, OnMinXChanged, VT_R8)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MaxX", m_maxX, OnMaxXChanged, VT_R8)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MinY", m_minY, OnMinYChanged, VT_R8)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MaxY", m_maxY, OnMaxYChanged, VT_R8)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ShowCursor", m_showCursor, OnShowCursorChanged, VT_BOOL)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "GraphTitle", m_strGraphTitle, OnGraphTitleChanged, VT_BSTR)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorColor", m_cursorColor, OnCursorColorChanged, VT_COLOR)
DISP_PROPERTY_EX(CNTGraphCtrl, "PlotColor", GetPlotColor, SetPlotColor, VT_COLOR)
DISP_PROPERTY_EX(CNTGraphCtrl, "Element", GetElement, SetElement, VT_I2)
DISP_PROPERTY_EX(CNTGraphCtrl, "ElementCount", GetElementCount, SetElementCount, VT_I2)
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_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_STOCK_CLICK()
EVENT_STOCK_MOUSEMOVE()
//}}AFX_EVENT_MAP
END_EVENT_MAP()
/////////////////////////////////////////////////////////////////////////////
// Property pages
// TODO: Add more property pages as needed. Remember to increase the count!
BEGIN_PROPPAGEIDS(CNTGraphCtrl, 2)
PROPPAGEID(CNTGraphPropPage::guid)
PROPPAGEID(CLSID_CColorPropPage)
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);
}
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::CNTGraphCtrl - Constructor
CNTGraphCtrl::CNTGraphCtrl()
{
InitializeIIDs(&IID_DNTGraph, &IID_DNTGraphEvents);
// TODO: Initialize your control's instance data here.
m_minX=m_minY=0;
m_maxX=m_maxY=10;
SetRange(0,10,0,10);
m_strLabelX = "X Axis" ;
m_strLabelY = "Y Axis" ;
m_strGraphTitle = "XY Graph";
m_nGridX = 5 ;
m_nGridY = 5;
bIsElementAllocated = FALSE ;
bFontIsCreate = FALSE ;
nPlotIndex = 0 ;
nPointCount = 2000 ;
nElementCount = 2 ;
m_ElementId=0;
m_BGColor = RGB(255,255,255);
m_axisColor = RGB(0,0,0);
m_labelColor = RGB(0,0,0);
m_gridColor = RGB(120,120,120);
m_cursorColor = RGB(255,0,0);
}
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::~CNTGraphCtrl - Destructor
CNTGraphCtrl::~CNTGraphCtrl()
{
// TODO: Cleanup your control's instance data here.
for( int i = 0 ; i < nElementCount ; i++){
mpElement[i].FreeElement() ;
}
if( bFontIsCreate ) {
delete pTickFont ;
delete pXLabelFont;
delete pYLabelFont;
delete pTitleFont ;
}
}
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnDraw - Drawing function
void CNTGraphCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
DoSuperclassPaint(pdc, rcBounds);
m_pDC = pdc;
m_ctlRect = rcBounds;
m_clientRect = rcBounds;
PrepareForDrawing(&rcBounds);
CBrush hbrBackground(TranslateColor(GetBackColor()));
pdc->FillRect (m_ctlRect,&hbrBackground);
DrawAxis() ;
DrawGraphTitle();
DrawAxisLabel();
if (m_showGrid)
DrawGrid();
else
DrawTicks();
DrawGraphTitle();
PlotElement() ;
if (m_showCursor)
DrawCursor();
}
/////////////////////////////////////////////////////////////////////////////
// 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("ChangeMappingMode"),m_changeMappingMode,FALSE);
}
/////////////////////////////////////////////////////////////////////////////
// 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");
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;
}
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl message handlers
void CNTGraphCtrl::PrepareForDrawing(CRect rect)
{
CWnd* pParent = GetParent( );
m_ctlRect = rect ;
m_BGColor=TranslateColor(GetBackColor());
if (m_changeMappingMode) {
m_pDC->SetMapMode(MM_HIMETRIC);
m_pDC->SetMapMode(MM_ANISOTROPIC);
m_pDC->SetWindowExt (400,300);
}
m_pDC->SetViewportExt (rect.right , rect.bottom );
m_pDC->DPtoLP(&m_ctlRect);
pParent->ClientToScreen(m_ctlRect) ;
ScreenToClient(m_ctlRect) ;
CreateFont(); // Get system font for label draw
bFontIsCreate = TRUE ;
CalcRect() ; // Compute rectangle
ResCalc(); // Compute resolution per dot .
return;
}
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()
{
int offset;
if(m_ctlRect)
{
m_clientRect.left = m_ctlRect.left+2 ;
m_clientRect.right = m_ctlRect.right-2 ;
m_clientRect.top = m_ctlRect.top+2 ;
m_clientRect.bottom = m_ctlRect.bottom-2;
} else {
m_clientRect = m_ctlRect ;
}
offset = 20;
CSize txtXLabelSize,txtYLabelSize,txtTitleSize ;
CString str ;
CPaintDC dc(this); // device context for painting
CFont *oldFont ;
oldFont = dc.SelectObject(pTickFont);
int bigY = __max(abs((int)dRangeY[MAX]),abs((int)dRangeY[MIN]));
str.Format("%g",(double)bigY);
txtYLabelSize = dc.GetTextExtent(str);
str.Format("%g",dRangeX[MAX]);
txtXLabelSize = dc.GetTextExtent(str);
dc.SelectObject (pTitleFont);
txtTitleSize = dc.GetTextExtent (m_strLabelX);
dc.SelectObject(oldFont);
m_axisRect.left = m_clientRect.left +(offset)+txtTitleSize.cy+txtYLabelSize.cx+10;
m_axisRect.right = m_clientRect.right - (offset/2) - (txtXLabelSize.cx/2);
m_axisRect.top = m_clientRect.top + (offset/2) + txtTitleSize.cy + 10 ;
m_axisRect.bottom = m_clientRect.bottom - (offset/2)-(txtTitleSize.cy+txtXLabelSize.cy)+10;
}
////////////////////////////////////////////////////////
//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 legend in x axis and
// y axis .
void CNTGraphCtrl::CreateFont()
{
//Create system font ..
LOGFONT d_lf ;
// Init desired font
memset(&d_lf, 0, sizeof(LOGFONT));
lstrcpy(d_lf.lfFaceName, "Times New Roman") ;
// Initial font size
// Get a screen DC
CWindowDC wdc(NULL) ;
const int cyPixels = wdc.GetDeviceCaps(LOGPIXELSY);
d_lf.lfHeight = -1 * MulDiv(8, cyPixels, 72);
// Create a new font 8 pts. for Ticks
pTickFont = new CFont() ;
pTickFont->CreateFontIndirect(&d_lf);
d_lf.lfHeight = -1 * MulDiv(12, cyPixels, 72);
d_lf.lfWeight = FW_BLACK ;
// Create a new font 12 pts. for Title
pTitleFont = new CFont();
pTitleFont->CreateFontIndirect(&d_lf);
// Create a new font 12 pts. for Axis Labels
d_lf.lfWeight = FW_BOLD ;
pXLabelFont = new CFont() ;
pXLabelFont->CreateFontIndirect(&d_lf);
// Rotate font 90 degree for Y axis label
d_lf.lfOrientation = 900 ;
d_lf.lfEscapement = 900 ;
pYLabelFont = new CFont() ;
pYLabelFont->CreateFontIndirect(&d_lf);
}
void CNTGraphCtrl::DrawAxis()
{
m_axisRect.NormalizeRect ();
m_pDC->FillSolidRect (m_axisRect,m_BGColor);
CPen *old , pen(PS_SOLID, 2, m_axisColor);
old = m_pDC->SelectObject(&pen) ;
m_pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MIN]));
m_pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MIN]));
m_pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MIN]));
m_pDC->LineTo(Corrdinate(dRangeX[MIN],dRangeY[MAX]));
m_pDC->MoveTo(Corrdinate(dRangeX[MAX],dRangeY[MIN]));
m_pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MAX]));
m_pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MAX]));
m_pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MAX]));
m_pDC->SelectObject(old) ;
}
void CNTGraphCtrl::DrawGraphTitle()
{
int x , y ;
int oldbkmode ;
CFont *old ;
old = m_pDC->SelectObject(pTitleFont);
oldbkmode = m_pDC->SetBkMode(TRANSPARENT) ;
CSize textSize = m_pDC->GetTextExtent(m_strGraphTitle,
m_strGraphTitle.GetLength()) ;
//Calculate centre window corrdinate of text ;
m_pDC->SetTextAlign(TA_LEFT);
y = m_ctlRect.top + (textSize.cy/2) ;
x = m_clientRect.left + (m_clientRect.Width()/2) - (textSize.cx/2) ;
m_pDC->TextOut(x,y,m_strGraphTitle) ;
m_pDC->SetBkMode(oldbkmode);
m_pDC->SelectObject(old);
}
void CNTGraphCtrl::DrawGrid()
{
CPen *old , pen(PS_SOLID, 0, m_gridColor);
CPoint m_start, m_stop ;
int i ;
double x ,y ;
double step ;
old = m_pDC->SelectObject(&pen);
// Draw vertical grid
step = (dRangeX[MAX] - dRangeX[MIN]) / (double)m_nGridX ;
for( i = 0 ; i <= m_nGridX ; i++ )
{
x = dRangeX[MIN] + (step * (double)i) ;
m_start = Corrdinate(x,dRangeY[MIN]);
m_stop = Corrdinate(x,dRangeY[MAX]);
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
// Draw horizontal grid.
step = (dRangeY[MAX] - dRangeY[MIN]) / (double)m_nGridY ;
for( i = 0 ; i <= m_nGridY ; i++ )
{
y = dRangeY[MIN] + (step * (double)i) ;
m_start = Corrdinate(dRangeX[MIN],y) ;
m_stop = Corrdinate(dRangeX[MAX],y) ;
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
m_pDC->SelectObject(old);
}
BOOL CNTGraphCtrl::SetRange(double MinX, double MaxX, double MinY,double MaxY)
{
dRangeY[MIN] = MinY ;
dRangeY[MAX] = MaxY ;
dRangeX[MAX] = MaxX ;
dRangeX[MIN] = MinX ;
ResCalc();
InvalidateControl();
return TRUE ;
}
void CNTGraphCtrl::DrawAxisLabel()
{
CFont *oldFont ;
oldFont = m_pDC->SelectObject(pTickFont);
m_pDC->SetTextColor (m_labelColor);
int i ;
double res , y ;
CPoint cal_pt ;
CSize txtSize ;
CString str ;
res = (dRangeY[MAX] - dRangeY[MIN]) / m_nGridY ;
m_pDC->SetTextAlign(TA_RIGHT);
m_pDC->SetBkMode(TRANSPARENT);
// Draw X Tick Labels
for ( i = 0 ; i <= m_nGridY ; i++)
{
y = dRangeY[MIN] + (res * (double)i) ;
cal_pt = Corrdinate(dRangeX[MIN],y) ;
str.Format("%g",y) ;
txtSize = m_pDC->GetTextExtent(str) ;
cal_pt.x -= 5 ;
cal_pt.y -= txtSize.cy/2 ;
m_pDC->TextOut(cal_pt.x,cal_pt.y,str) ;
}
// Draw X Label
m_pDC->SelectObject(pXLabelFont);
txtSize = m_pDC->GetTextExtent(m_strLabelX);
cal_pt.x = m_axisRect.CenterPoint().x + (txtSize.cx/2);
cal_pt.y = m_ctlRect.bottom - (txtSize.cy);
m_pDC->TextOut(cal_pt.x,cal_pt.y,m_strLabelX);
// Draw Y Tick Labels
m_pDC->SelectObject(pTickFont);
res = (dRangeX[MAX] - dRangeX[MIN]) / m_nGridX ;
for ( i = 0 ; i <= m_nGridX ; i ++ )
{
y = dRangeX[MIN] + ( res * (double)i);
cal_pt = Corrdinate(y,dRangeY[MIN]);
str.Format("%g",y);
txtSize = m_pDC->GetTextExtent(str) ;
cal_pt.x += txtSize.cx/2;
cal_pt.y += 5 ;
m_pDC->TextOut(cal_pt.x,cal_pt.y,str);
}
// Draw Y Label
m_pDC->SelectObject(pYLabelFont);
txtSize = m_pDC->GetTextExtent(m_strLabelY);
cal_pt.x = m_ctlRect.left + (txtSize.cy/2);
cal_pt.y = m_ctlRect.CenterPoint().y - (txtSize.cx/2);
m_pDC->TextOut(cal_pt.x,cal_pt.y,m_strLabelY);
m_pDC->SelectObject(oldFont);
}
////////////////////////////////////////////////////////
// Draw 1/5 fine scale in log mode
// in order to implement log grid set bLogScale = TRUE
void CNTGraphCtrl::DrawTicks()
{
CPen *old , pen(PS_SOLID, 0, m_gridColor);
CPoint m_start, m_stop ;
int i ;
double x ,y ;
double step ;
old = m_pDC->SelectObject(&pen);
// Draw vertical Major Ticks
step = (dRangeX[MAX] - dRangeX[MIN]) / (double)m_nGridX ;
for( i = 0 ; 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
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
for( i = 0 ; 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
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
// Draw horizontal Major Ticks
step = (dRangeY[MAX] - dRangeY[MIN]) / (double)m_nGridY ;
for( i = 0 ; 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
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
for( i = 0 ; 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
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
m_pDC->SelectObject(old);
}
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 ;
// 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];
mpElement[iElementId].dValueX[index] = x ;
mpElement[iElementId].dValueY[index] = y ;
mpElement[iElementId].bIsPlotAvailable = TRUE ;
nPlotIndex = index ;
return TRUE ;
}
void CNTGraphCtrl::ClearGraph()
{
nPlotIndex = 0 ;
InvalidateRect(m_clientRect);
}
////////////////////////////////////////
// Allocate memory for plotting
BOOL CNTGraphCtrl::CreateElement(long nElement)
{
if( !bIsElementAllocated )
{
for(int i = 0 ; i < nElementCount ; i++ ) {
if ( !mpElement[i].AllocElement(nElement)) {
AfxMessageBox("Can not allocate element!") ;
return FALSE ;
}
}
}
nPointCount = nElement ;
bIsElementAllocated = TRUE ;
return TRUE ;
}
void CNTGraphCtrl::PlotElement()
{
// If there is no data available for plot then return .
if ( !nPlotIndex ) return ;
CPen *old , *pen ;
CPoint pt ;
int i;
for( i = 0 ; i < nElementCount ; i++) {
// Create the new pen as the color of serie
pen = new CPen(PS_SOLID,0,mpElement[i].m_plotColor);
old = m_pDC->SelectObject(pen);
// calculate the corrdinate of ploting point.
pt = Corrdinate(mpElement[i].dValueX[0],mpElement[i].dValueY[0]) ;
m_pDC->MoveTo(pt);
//Start plot all available data .
for(int index = 1 ; index <= nPlotIndex ; index++){
pt = Corrdinate(mpElement[i].dValueX[index],
mpElement[i].dValueY[index]) ;
m_pDC->LineTo(pt) ;
}
m_pDC->SelectObject(old);
delete pen ;
}
}
////////////////////////////////////////////////////
// Source of CGraphElement
CGraphElement::CGraphElement()
{
dValueX = NULL ;
dValueY = NULL ;
bIsPlotAvailable = FALSE ;
bBufferAllocated = FALSE ;
m_plotColor = RGB(0,0,0);
}
BOOL CGraphElement::AllocElement(UINT nPoint)
{
dValueX = (double*)malloc(nPoint * sizeof (double) ) ;
dValueY = (double*)malloc(nPoint * sizeof (double) ) ;
if ( (dValueX == NULL) || (dValueY == NULL) )
return FALSE ;
bBufferAllocated = TRUE ;
return TRUE ;
}
BOOL CGraphElement::FreeElement()
{
if ( bBufferAllocated ) {
free(dValueX) ;
free(dValueY) ;
}
bBufferAllocated = FALSE ;
return TRUE ;
}
void CNTGraphCtrl::OnShowGridChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnChangeMappingModeChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnXLabelChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnYLabelChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnGridColorChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnLabelColorChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnAxisColorChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnNGridXChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnNGridYChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMinXChanged()
{
// TODO: Add notification handler code
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMaxXChanged()
{
// TODO: Add notification handler code
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMinYChanged()
{
// TODO: Add notification handler code
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMaxYChanged()
{
// TODO: Add notification handler code
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
OLE_COLOR CNTGraphCtrl::GetPlotColor()
{
// TODO: Add your property handler here
return mpElement[m_ElementId].m_plotColor;
}
void CNTGraphCtrl::SetPlotColor(OLE_COLOR nNewValue)
{
// TODO: Add your property handler here
mpElement[m_ElementId].m_plotColor = nNewValue;
InvalidateControl();
SetModifiedFlag();
}
short CNTGraphCtrl::GetElement()
{
// TODO: Add your property handler here
return m_ElementId;
}
void CNTGraphCtrl::SetElement(short nNewValue)
{
// TODO: Add your property handler here
m_ElementId = nNewValue;
if (m_ElementId <0)
m_ElementId=0;
SetModifiedFlag();
}
short CNTGraphCtrl::GetElementCount()
{
// TODO: Add your property handler here
return nElementCount;
}
void CNTGraphCtrl::SetElementCount(short nNewValue)
{
// TODO: Add your property handler here
nElementCount = nNewValue;
if (nElementCount <0)
nElementCount=0;
SetModifiedFlag();
}
void CNTGraphCtrl::OnShowCursorChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
double rx,ry;
rx = (double)((point.x - m_axisRect.left)*dResX) + dRangeX[MIN];
ry = (double)((m_axisRect.bottom - point.y)*dResY) + dRangeY[MIN];
if ( point.x < m_axisRect.right &&
point.x > m_axisRect.left &&
point.y > m_axisRect.top &&
point.y < m_axisRect.bottom )
{
m_dXCur = rx;
m_dYCur = ry;
m_bIsCursorInRange=TRUE;
return;
}
else
{
m_bIsCursorInRange=FALSE;
return;
}
COleControl::OnMouseMove(nFlags, point);
}
void CNTGraphCtrl::DrawCursor()
{
if(m_bIsCursorInRange) {
m_axisRect.NormalizeRect ();
CPen *old , pen(PS_SOLID, 2, m_cursorColor);
old = m_pDC->SelectObject(&pen) ;
m_pDC->MoveTo(Corrdinate(m_dXCur,dRangeY[MIN]));
m_pDC->LineTo(Corrdinate(m_dXCur,dRangeY[MAX]));
m_pDC->MoveTo(Corrdinate(dRangeX[MIN],m_dYCur));
m_pDC->LineTo(Corrdinate(dRangeX[MAX],m_dYCur));
m_pDC->SelectObject(old) ;
}
}
void CNTGraphCtrl::OnGraphTitleChanged()
{
// TODO: Add notification handler code
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnCursorColorChanged()
{
// TODO: Add notification handler code
SetModifiedFlag();
}
void CNTGraphCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
InvalidateControl();
COleControl::OnLButtonDown(nFlags, point);
}