// NTGraphCtl.cpp : Implementation of the CNTGraphCtrl ActiveX Control class.
#include "stdafx.h"
#include "NTGraph.h"
#include "NTGraphCtl.h"
#include "NTGraphPpg.h"
#include <math.h>
#define STATIC
#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()
//}}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, "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, "GraphTitle", m_strGraphTitle, OnGraphTitleChanged, VT_BSTR)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorColor", m_cursorColor, OnCursorColorChanged, VT_COLOR)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ElementColor", m_elementColor, OnElementColorChanged, VT_COLOR)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ZoomMode", m_zoomMode, OnZoomModeChanged, VT_BOOL)
DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorMode", m_cursorMode, OnCursorModeChanged, VT_BOOL)
DISP_PROPERTY_EX(CNTGraphCtrl, "Element", GetElement, SetElement, VT_I2)
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, "SetShowElement", SetShowElement, VT_EMPTY, VTS_BOOL)
DISP_FUNCTION(CNTGraphCtrl, "Copy2Clipboard", Copy2Clipboard, VT_EMPTY, VTS_NONE)
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);
// Initialize the control's instance data.
m_minX=m_minY=0;
m_maxX=m_maxY=10;
SetRange(0,1,0,1);
m_strLabelX = "X Axis" ;
m_strLabelY = "Y Axis" ;
m_strGraphTitle = "XY Graph";
m_nGridX = 5 ;
m_nGridY = 5;
bIsElementAllocated = FALSE ;
bFontIsCreated = 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(0,0,0);
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].DeleteElement() ;
}
if( bFontIsCreated ) {
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;
PrepareForDrawing(&rcBounds);
CBrush hbrBackground(TranslateColor(GetBackColor()));
pdc->FillRect (m_ctlRect,&hbrBackground);
DrawAxis() ;
DrawGraphTitle();
DrawAxisLabel();
if (m_showGrid)
DrawGrid();
else
DrawTicks();
DrawGraphTitle();
PlotElement() ;
if (m_cursorMode)
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("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();
}
#ifdef STATIC
/////////////////////////////////////////////////////////////////////////////
// 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;
}
#endif
/////////////////////////////////////////////////////////////////////////////
////////////////////////// Source of CGraphElement //////////////////////////
/////////////////////////////////////////////////////////////////////////////
CGraphElement::CGraphElement()
{
dValueX = NULL ;
dValueY = NULL ;
bIsPlotAvailable = FALSE ;
bBufferAllocated = FALSE ;
m_Color = RGB(0,0,0);
m_bShow = TRUE; // Added by A. Hofmann
m_nCount = 0; // 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(CRect rect)
{
m_BGColor=TranslateColor(GetBackColor());
m_ctlRect = rect ;
CreateFont(); // Get system font for label draw
bFontIsCreated = TRUE ;
CalcRect() ; // Compute rectangle
ResCalc(); // Compute resolution per dot.
m_pDC->SetViewportExt (rect.right , rect.bottom );
m_pDC->DPtoLP(&m_ctlRect);
}
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()
{
CFont* pOldFont;
TEXTMETRIC tm;
pOldFont = SelectFontObject(m_pDC, m_fontTitle);
m_pDC->GetTextMetrics(&tm);
m_pDC->SetTextAlign(TA_TOP | TA_CENTER);
m_pDC->ExtTextOut((m_ctlRect.left + m_ctlRect.right) / 2,
(m_ctlRect.top+m_axisRect.top - tm.tmHeight) / 2,
ETO_CLIPPED, m_ctlRect, m_strGraphTitle, m_strGraphTitle.GetLength(),NULL);
m_pDC->SelectObject(pOldFont);
}
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 = 1 ; 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 = 1 ; 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);
}
void CNTGraphCtrl::DrawAxisLabel()
{
CFont *pOldFont;
int i ;
double res , x, y ;
CPoint point ;
CSize txtSize ;
CString str ;
pOldFont = m_pDC->SelectObject(pTickFont);
m_pDC->SetTextColor (m_labelColor);
res = (dRangeY[MAX] - dRangeY[MIN]) / m_nGridY ;
m_pDC->SetTextAlign(TA_RIGHT);
m_pDC->SetBkMode(TRANSPARENT);
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 = m_pDC->GetTextExtent(str) ;
if (sz.cx < txtSize.cx) sz=txtSize;
point.x -= 5 ;
point.y -= txtSize.cy/2 ;
m_pDC->TextOut(point.x,point.y,str) ;
}
m_pDC->SelectObject(pXLabelFont);
// Draw X Axis Title
txtSize = m_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;
m_pDC->TextOut(point.x,point.y,m_strLabelX);
// Draw X Tick Labels
m_pDC->SelectObject(pTickFont);
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 = m_pDC->GetTextExtent(str) ;
point.x += txtSize.cx/2;
point.y += 5 ;
m_pDC->TextOut(point.x,point.y,str);
}
m_pDC->SelectObject(pYLabelFont);
// Draw Y Axis Title
txtSize = m_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);
m_pDC->TextOut(point.x,point.y,m_strLabelY);
m_pDC->SelectObject(pOldFont);
}
//////////////////////////////////
// Draw ticks in 1/5 fine scale
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 = 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
m_pDC->MoveTo(m_start);
m_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
m_pDC->MoveTo(m_start);
m_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
m_pDC->MoveTo(m_start);
m_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
m_pDC->MoveTo(m_start);
m_pDC->LineTo(m_stop);
}
m_pDC->SelectObject(old);
}
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++) {
/////////////////////////////
// Added by A.Hofmann
/////////////////////////////
// Check show state of serie
if ( ! mpElement[i].m_bShow )
continue;
// Create the new pen as the color of serie
pen = new CPen(PS_SOLID /*mpElement[i].m_lineType*/,
1 /*mpElement[i].m_lineWidth*/,
mpElement[i].m_Color);
old = m_pDC->SelectObject(pen);
// Calculate the corrdinate of ploting point.
pt = Corrdinate(mpElement[i].dValueX[0],mpElement[i].dValueY[0]) ;
if (m_axisRect.PtInRect(pt))
m_pDC->MoveTo(pt);
else {
if ( pt.y < m_axisRect.bottom) pt.y=m_axisRect.bottom;
if ( pt.y > m_axisRect.top ) pt.y=m_axisRect.top;
if ( pt.x < m_axisRect.left ) pt.x=m_axisRect.left;
if ( pt.x > m_axisRect.right ) pt.x=m_axisRect.right;
m_pDC->MoveTo(pt);
}
// Start plot all available data .
// Changed by A. Hofmann
for(int index = 1 ; index <= mpElement[i].m_nCount;/*nPlotIndex;*/ index++){
pt = Corrdinate(mpElement[i].dValueX[index], mpElement[i].dValueY[index]) ;
// Clipping to Axis Rectangle
if (m_axisRect.PtInRect(pt))
m_pDC->LineTo(pt) ;
else
continue;
}
m_pDC->SelectObject(old);
delete pen ;
}
}
void CNTGraphCtrl::DrawCursor()
{
if(bIsCursorInRange) {
m_axisRect.NormalizeRect ();
CPen *old , pen(PS_SOLID, 1, 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::ClearGraph()
{
// Added by A. Hofmann
for(int i = 0 ; i < nElementCount; i++ )
mpElement[i].m_nCount = 0;
nPlotIndex = 0 ;
InvalidateRect(m_ctlRect);
}
/////////////////////////////////
// Allocate memory for plotting
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 ;
ResCalc();
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;
// 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 ;
mpElement[iElementId].m_nCount = index; // Added by A. Hofmann
nPlotIndex = index ;
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()
{
int offset = 30;
CSize txtXLabelSize,txtYLabelSize,txtTitleSize ;
CString str ;
CPaintDC dc(this); // device context for painting
CFont *pOldFont ;
pOldFont = 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(pOldFont);
m_axisRect.left = m_ctlRect.left + txtTitleSize.cy+txtYLabelSize.cx + offset;
m_axisRect.right = m_ctlRect.right - (txtXLabelSize.cx/2) - (offset/2);
m_axisRect.top = m_ctlRect.top + txtTitleSize.cy + (offset/2);
m_axisRect.bottom= m_ctlRect.bottom - (txtTitleSize.cy+txtXLabelSize.cy) - (offset/2);
}
////////////////////////////////
//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::CreateFont()
{
//Create system font ..
LOGFONT lf;
CFont *pStockFont, *pOldFont;
pOldFont = SelectFontObject(m_pDC, m_fontTick);
pStockFont = SelectFontObject(m_pDC, m_fontTick);
// Retrieve a copy of the LOGFONT structure
// for a currently selected stock font.
if (pStockFont)
pStockFont->GetLogFont(&lf);
// Create a new font for Ticks
pTickFont = new CFont() ;
pTickFont->CreateFontIndirect(&lf);
pOldFont = SelectFontObject(m_pDC, m_fontTitle);
pStockFont = SelectFontObject(m_pDC, m_fontTitle);
// Retrieve a copy of the LOGFONT structure
// for a currently selected stock font.
if (pStockFont)
pStockFont->GetLogFont(&lf);
// Create a new font for Title
pTitleFont = new CFont();
pTitleFont->CreateFontIndirect(&lf);
pOldFont = SelectFontObject(m_pDC, m_fontLabel);
pStockFont = SelectFontObject(m_pDC, m_fontLabel);
// Retrieve a copy of the LOGFONT structure
// for a currently selected stock font.
if (pStockFont)
pStockFont->GetLogFont(&lf);
pXLabelFont = new CFont() ;
pXLabelFont->CreateFontIndirect(&lf);
// Rotate font 90 degree for Y axis label
SetGraphicsMode( m_pDC->m_hDC, GM_ADVANCED );
lf.lfOrientation = 900 ;
lf.lfEscapement = 900 ;
pYLabelFont = new CFont() ;
pYLabelFont->CreateFontIndirect(&lf);
m_pDC->SelectObject(pOldFont);
}
void CNTGraphCtrl::CursorPosition(CPoint point)
{
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;
//Fire Cursor Position Event
FireCursorEvent(rx,ry);
bIsCursorInRange=TRUE;
return;
}
else
{
bIsCursorInRange=FALSE;
return;
}
}
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();
}
void CNTGraphCtrl::OnMinXChanged()
{
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMaxXChanged()
{
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMinYChanged()
{
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
void CNTGraphCtrl::OnMaxYChanged()
{
SetRange(m_minX,m_maxX,m_minY,m_maxY);
InvalidateControl();
SetModifiedFlag();
}
short CNTGraphCtrl::GetElement() { return m_ElementId; }
void CNTGraphCtrl::SetElement(short nNewValue)
{
m_ElementId = nNewValue;
if (m_ElementId <0)
m_ElementId=0;
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()
{
AfxMessageBox("Not implemented yet, but reserved!");
SetModifiedFlag();
}
void CNTGraphCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
CursorPosition(point); // Fire CursorEvent
InvalidateControl();
SetModifiedFlag();
/*
if (::GetCapture() == m_hWnd) // in capture mode
{
POINT p=point;
::ClientToScreen(m_hWnd, &p);
CursorPosition(p); // Fire CursorEvent
InvalidateControl();
SetModifiedFlag();
} else // leave control area and start mouse leave event
TRACKMOUSEEVENT t = {sizeof(TRACKMOUSEEVENT),TME_LEAVE,m_hWnd,0} ;
*/
COleControl::OnLButtonDown(nFlags, point);
}
void CNTGraphCtrl::OnElementColorChanged()
{
mpElement[m_ElementId].m_Color = m_elementColor;
InvalidateControl();
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()
{
InvalidateControl();
SetModifiedFlag( );
COleControl::OnFontChanged();
}
////////////////////////////////////////////////////////
// New Method Show/Hide Graph Element
// Added by A.Hofmann
void CNTGraphCtrl::SetShowElement(BOOL bShow)
{
mpElement[m_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);
CDC memDC;
CBitmap bitmap;
GetClientRect(&rect);
// 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();
}