// 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);
}
*/