816 lines
26 KiB
C++
816 lines
26 KiB
C++
// OScopeCtrl.cpp : implementation file//
|
|
|
|
#include "stdafx.h"
|
|
#include "math.h"
|
|
|
|
#include "OScopeCtrl.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COScopeCtrl
|
|
COScopeCtrl::COScopeCtrl()
|
|
: m_bCountryCode(false)
|
|
{
|
|
// since plotting is based on a LineTo for each new point
|
|
// we need a starting point (i.e. a "previous" point)
|
|
// use 0.0 as the default first point.
|
|
// these are public member variables, and can be changed outside
|
|
// (after construction). Therefore m_perviousPosition could be set to
|
|
// a more appropriate value prior to the first call to SetPosition.
|
|
m_dPreviousPosition = 0.0;
|
|
|
|
// public variable for the number of decimal places on the y axis
|
|
m_nYDecimals = 3;
|
|
|
|
// set some initial values for the scaling until "SetRange" is called.
|
|
// these are protected varaibles and must be set with SetRange
|
|
// in order to ensure that m_dRange is updated accordingly
|
|
m_dLowerLimit = -10.0;
|
|
m_dUpperLimit = 10.0;
|
|
m_dLowerXLimit = 0.0;
|
|
m_dUpperYLimit = 24.0;
|
|
m_dRange = m_dUpperLimit - m_dLowerLimit; // protected member variable
|
|
|
|
// m_nShiftPixels determines how much the plot shifts (in terms of pixels)
|
|
// with the addition of a new data point
|
|
m_nShiftPixels = 4;
|
|
m_nHalfShiftPixels = m_nShiftPixels/2; // protected
|
|
m_nPlotShiftPixels = m_nShiftPixels + m_nHalfShiftPixels; // protected
|
|
|
|
// background, grid and data colors
|
|
// these are public variables and can be set directly
|
|
m_crBackColor = RGB( 0, 0, 0); // see also SetBackgroundColor
|
|
m_crGridColor = RGB( 0, 255, 255); // see also SetGridColor
|
|
m_crPlotColor = RGB(255, 255, 255); // see also SetPlotColor
|
|
|
|
//set country count color
|
|
m_crCCUColor[CI_EG] = CCU_RGB_ENG;
|
|
m_crCCUColor[CI_GE] = CCU_RGB_GER;
|
|
m_crCCUColor[CI_FR] = CCU_RGB_FRA;
|
|
m_crCCUColor[CI_IT] = CCU_RGB_ITA;
|
|
m_crCCUColor[CI_PL] = CCU_RGB_POL;
|
|
m_crCCUColor[CI_TR] = CCU_RGB_TUR;
|
|
m_crCCUColor[CI_ETC] = CCU_RGB_ETC;
|
|
|
|
// protected variables
|
|
m_penPlot.CreatePen(PS_SOLID, 0, m_crPlotColor);
|
|
m_brushBack.CreateSolidBrush(m_crBackColor);
|
|
|
|
//crate ccu pen & CCUArray
|
|
for(int i = 0 ; i < CI_MAX ; ++i)
|
|
{
|
|
m_CCUpen[i].CreatePen(PS_SOLID, 2, m_crCCUColor[i]);
|
|
m_dCurCCUPosition[i] = 0;
|
|
m_dPreCCUPosition[i] = 0;
|
|
}
|
|
|
|
// public member variables, can be set directly
|
|
m_strXUnitsString.Format(_T("Concurrent User(%06d/%06d)"), 0, 0); // can also be set with SetXUnits
|
|
m_strYUnitsString.Format(_T("Y units")); // can also be set with SetYUnits
|
|
|
|
// protected bitmaps to restore the memory DC's
|
|
m_pbitmapOldGrid = NULL;
|
|
m_pbitmapOldPlot = NULL;
|
|
|
|
InitToolTip();
|
|
|
|
} // COScopeCtrl
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
COScopeCtrl::~COScopeCtrl()
|
|
{
|
|
// just to be picky restore the bitmaps for the two memory dc's
|
|
// (these dc's are being destroyed so there shouldn't be any leaks)
|
|
if (m_pbitmapOldGrid != NULL)
|
|
m_dcGrid.SelectObject(m_pbitmapOldGrid);
|
|
if (m_pbitmapOldPlot != NULL)
|
|
m_dcPlot.SelectObject(m_pbitmapOldPlot);
|
|
if (m_pbitmapCCUOldPlot[0] != NULL) //CCU
|
|
{
|
|
for(int i = 0 ; i < CI_MAX ; ++i)
|
|
m_dcCCUPlot[i].SelectObject(m_pbitmapCCUOldPlot[i]);
|
|
}
|
|
|
|
} // ~COScopeCtrl
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(COScopeCtrl, CWnd)
|
|
//{{AFX_MSG_MAP(COScopeCtrl)
|
|
ON_WM_PAINT()
|
|
ON_WM_SIZE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COScopeCtrl message handlers
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL COScopeCtrl::Create(DWORD dwStyle, const RECT& rect,
|
|
CWnd* pParentWnd, UINT nID)
|
|
{
|
|
BOOL result;
|
|
static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
|
|
|
|
result = CWnd::CreateEx(
|
|
WS_EX_CLIENTEDGE | WS_EX_STATICEDGE,
|
|
className, NULL, dwStyle,
|
|
rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
|
|
pParentWnd->GetSafeHwnd(), (HMENU)nID);
|
|
|
|
if (result != 0)
|
|
InvalidateCtrl();
|
|
|
|
return result;
|
|
} // Create
|
|
|
|
void COScopeCtrl::SetToolTip(CString text)
|
|
{
|
|
m_toolTip.AddTool(this, text, NULL, 0);
|
|
m_toolTip.Activate(TRUE);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::SetRange( bool b, double dLower, double dUpper, int nDecimalPlaces)
|
|
{
|
|
ASSERT(dUpper > dLower);
|
|
|
|
m_dLowerLimit = dLower;
|
|
m_dUpperLimit = dUpper;
|
|
m_nYDecimals = nDecimalPlaces;
|
|
m_dRange = m_dUpperLimit - m_dLowerLimit;
|
|
m_dVerticalFactor = (double)m_nPlotHeight / m_dRange;
|
|
|
|
// clear out the existing garbage, re-start with a clean plot
|
|
if( b )
|
|
InvalidateCtrl();
|
|
else
|
|
RefreshRange();
|
|
|
|
} // SetRange
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::SetXUnits(CString string)
|
|
{
|
|
m_strXUnitsString = string;
|
|
|
|
// clear out the existing garbage, re-start with a clean plot
|
|
//InvalidateCtrl();
|
|
InvalidateXUnits();
|
|
} // SetXUnits
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::SetYUnits(CString string)
|
|
{
|
|
m_strYUnitsString = string;
|
|
|
|
// clear out the existing garbage, re-start with a clean plot
|
|
InvalidateCtrl();
|
|
|
|
} // SetYUnits
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::SetGridColor(COLORREF color)
|
|
{
|
|
m_crGridColor = color;
|
|
|
|
// clear out the existing garbage, re-start with a clean plot
|
|
InvalidateCtrl();
|
|
|
|
} // SetGridColor
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::SetPlotColor(COLORREF color)
|
|
{
|
|
m_crPlotColor = color;
|
|
|
|
m_penPlot.DeleteObject();
|
|
m_penPlot.CreatePen(PS_SOLID, 0, m_crPlotColor);
|
|
|
|
// clear out the existing garbage, re-start with a clean plot
|
|
InvalidateCtrl();
|
|
|
|
} // SetPlotColor
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::SetBackgroundColor(COLORREF color)
|
|
{
|
|
m_crBackColor = color;
|
|
|
|
m_brushBack.DeleteObject();
|
|
m_brushBack.CreateSolidBrush(m_crBackColor);
|
|
|
|
// clear out the existing garbage, re-start with a clean plot
|
|
InvalidateCtrl();
|
|
|
|
} // SetBackgroundColor
|
|
|
|
void COScopeCtrl::InitToolTip()
|
|
{
|
|
if (m_toolTip.m_hWnd == NULL)
|
|
{
|
|
m_toolTip.Create(this);
|
|
m_toolTip.Activate(FALSE);
|
|
m_toolTip.SetDelayTime(TTDT_AUTOPOP, 800);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::RefreshRange()
|
|
{
|
|
// There is a lot of drawing going on here - particularly in terms of
|
|
// drawing the grid. Don't panic, this is all being drawn (only once)
|
|
// to a bitmap. The result is then BitBlt'd to the control whenever needed.
|
|
int i = 0;
|
|
int nCharacters = 0;
|
|
int nTopGridPix = 0, nMidGridPix = 0, nBottomGridPix = 0;
|
|
|
|
CPen *oldPen = NULL;
|
|
CPen solidPen(PS_SOLID, 0, m_crGridColor);
|
|
CFont axisFont, yUnitFont, *oldFont;
|
|
CString strTemp;
|
|
|
|
// in case we haven't established the memory dc's
|
|
CClientDC dc(this);
|
|
|
|
// if we don't have one yet, set up a memory dc for the grid
|
|
if (m_dcGrid.GetSafeHdc() == NULL)
|
|
{
|
|
m_dcGrid.CreateCompatibleDC(&dc);
|
|
m_bitmapGrid.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid);
|
|
}
|
|
|
|
m_dcGrid.SetBkColor (m_crBackColor);
|
|
|
|
// fill the grid background
|
|
m_dcGrid.FillRect(m_rectClient, &m_brushBack);
|
|
|
|
// draw the plot rectangle:
|
|
// determine how wide the y axis scaling values are
|
|
nCharacters = abs((int)log10(fabs(m_dUpperLimit)));
|
|
nCharacters = max(nCharacters, abs((int)log10(fabs(m_dLowerLimit))));
|
|
//nCharacters = 3;
|
|
|
|
// add the units digit, decimal point and a minus sign, and an extra space
|
|
// as well as the number of decimal places to display
|
|
nCharacters = nCharacters + 4 + m_nYDecimals;
|
|
|
|
// adjust the plot rectangle dimensions
|
|
// assume 6 pixels per character (this may need to be adjusted)
|
|
m_rectPlot.left = m_rectClient.left + 4*(nCharacters);
|
|
m_nPlotWidth = m_rectPlot.Width();
|
|
|
|
// draw the plot rectangle
|
|
oldPen = m_dcGrid.SelectObject (&solidPen);
|
|
m_dcGrid.MoveTo (m_rectPlot.left-1, m_rectPlot.top);
|
|
m_dcGrid.LineTo (m_rectPlot.right, m_rectPlot.top);
|
|
m_dcGrid.LineTo (m_rectPlot.right, m_rectPlot.bottom+1);
|
|
m_dcGrid.LineTo (m_rectPlot.left-1, m_rectPlot.bottom+1);
|
|
m_dcGrid.LineTo (m_rectPlot.left-1, m_rectPlot.top);
|
|
m_dcGrid.SelectObject (oldPen);
|
|
|
|
// draw the dotted lines,
|
|
// use SetPixel instead of a dotted pen - this allows for a
|
|
// finer dotted line and a more "technical" look
|
|
nMidGridPix = (m_rectPlot.top + m_rectPlot.bottom)/2;
|
|
nTopGridPix = nMidGridPix - m_nPlotHeight/4;
|
|
nBottomGridPix = nMidGridPix + m_nPlotHeight/4;
|
|
|
|
for (i=m_rectPlot.left; i<m_rectPlot.right; i+=4)
|
|
{
|
|
m_dcGrid.SetPixel (i, nTopGridPix, m_crGridColor);
|
|
m_dcGrid.SetPixel (i, nMidGridPix, m_crGridColor);
|
|
m_dcGrid.SetPixel (i, nBottomGridPix, m_crGridColor);
|
|
}
|
|
|
|
// create some fonts (horizontal and vertical)
|
|
// use a height of 14 pixels and 300 weight
|
|
// (these may need to be adjusted depending on the display)
|
|
axisFont.CreateFont (14, 0, 0, 0, 300,
|
|
FALSE, FALSE, 0, ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
DEFAULT_PITCH|FF_SWISS, _T("Arial"));
|
|
yUnitFont.CreateFont (14, 0, 900, 0, 300,
|
|
FALSE, FALSE, 0, ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
DEFAULT_PITCH|FF_SWISS, _T("Arial"));
|
|
|
|
// grab the horizontal font
|
|
oldFont = m_dcGrid.SelectObject(&axisFont);
|
|
|
|
// y max
|
|
m_dcGrid.SetTextColor (m_crGridColor);
|
|
m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP);
|
|
//strTemp.Format (_T("%.*lf"), m_nYDecimals, m_dUpperLimit);
|
|
strTemp.Format (_T("%d"), (int)m_dUpperLimit);
|
|
m_dcGrid.TextOut (m_rectPlot.left-4, m_rectPlot.top, strTemp);
|
|
|
|
// y min
|
|
m_dcGrid.SetTextAlign (TA_RIGHT|TA_BASELINE);
|
|
//strTemp.Format (_T("%.*lf"), m_nYDecimals, m_dLowerLimit);
|
|
strTemp.Format (_T("%d"), (int)m_dLowerLimit);
|
|
m_dcGrid.TextOut (m_rectPlot.left-4, m_rectPlot.bottom, strTemp);
|
|
|
|
//// x min
|
|
//m_dcGrid.SetTextAlign (TA_LEFT|TA_TOP);
|
|
//m_dcGrid.TextOut (m_rectPlot.left, m_rectPlot.bottom+4, _T("0"));
|
|
|
|
//// x max
|
|
//m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP);
|
|
//strTemp.Format (_T("%d"), m_nPlotWidth/m_nShiftPixels);
|
|
//m_dcGrid.TextOut (m_rectPlot.right, m_rectPlot.bottom+4, strTemp);
|
|
|
|
// x units
|
|
m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP);
|
|
m_dcGrid.TextOut ((m_rectPlot.left+m_rectPlot.right)/2,
|
|
m_rectPlot.bottom+20, m_strXUnitsString);
|
|
|
|
// restore the font
|
|
m_dcGrid.SelectObject(oldFont);
|
|
|
|
// y units
|
|
oldFont = m_dcGrid.SelectObject(&yUnitFont);
|
|
m_dcGrid.SetTextAlign (TA_CENTER|TA_BASELINE);
|
|
m_dcGrid.TextOut ((m_rectClient.left+m_rectPlot.left)/2,
|
|
(m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString);
|
|
m_dcGrid.SelectObject(oldFont);
|
|
|
|
// at this point we are done filling the the grid bitmap,
|
|
// no more drawing to this bitmap is needed until the setting are changed
|
|
|
|
|
|
// if we don't have one yet, set up a memory dc for the plot
|
|
if (m_dcPlot.GetSafeHdc() == NULL)
|
|
{
|
|
m_dcPlot.CreateCompatibleDC(&dc);
|
|
|
|
m_bitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapOldPlot = m_dcPlot.SelectObject(&m_bitmapPlot);
|
|
|
|
for(int i = 0 ; i < CI_MAX ; ++i)
|
|
{
|
|
m_dcCCUPlot[i].CreateCompatibleDC(&dc);
|
|
m_bitmapCCUPlot[i].CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapCCUOldPlot[i] = m_dcCCUPlot[i].SelectObject(&m_bitmapCCUPlot[i]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
// make sure the plot bitmap is cleared
|
|
m_dcPlot.SetBkColor (m_crBackColor);
|
|
m_dcPlot.FillRect(m_rectClient, &m_brushBack);
|
|
*/
|
|
|
|
// finally, force the plot area to redraw
|
|
InvalidateRect(m_rectClient);
|
|
}
|
|
|
|
void COScopeCtrl::InvalidateCtrl()
|
|
{
|
|
// There is a lot of drawing going on here - particularly in terms of
|
|
// drawing the grid. Don't panic, this is all being drawn (only once)
|
|
// to a bitmap. The result is then BitBlt'd to the control whenever needed.
|
|
int i;
|
|
int nCharacters;
|
|
int nTopGridPix, nMidGridPix, nBottomGridPix;
|
|
|
|
CPen *oldPen;
|
|
CPen solidPen(PS_SOLID, 0, m_crGridColor);
|
|
CFont axisFont, yUnitFont, *oldFont;
|
|
CString strTemp;
|
|
|
|
// in case we haven't established the memory dc's
|
|
CClientDC dc(this);
|
|
|
|
// if we don't have one yet, set up a memory dc for the grid
|
|
if (m_dcGrid.GetSafeHdc() == NULL)
|
|
{
|
|
m_dcGrid.CreateCompatibleDC(&dc);
|
|
m_bitmapGrid.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid);
|
|
}
|
|
|
|
m_dcGrid.SetBkColor (m_crBackColor);
|
|
|
|
// fill the grid background
|
|
m_dcGrid.FillRect(m_rectClient, &m_brushBack);
|
|
|
|
// draw the plot rectangle:
|
|
// determine how wide the y axis scaling values are
|
|
nCharacters = abs((int)log10(fabs(m_dUpperLimit)));
|
|
nCharacters = max(nCharacters, abs((int)log10(fabs(m_dLowerLimit))));
|
|
|
|
// add the units digit, decimal point and a minus sign, and an extra space
|
|
// as well as the number of decimal places to display
|
|
nCharacters = nCharacters + 4 + m_nYDecimals;
|
|
|
|
// adjust the plot rectangle dimensions
|
|
// assume 6 pixels per character (this may need to be adjusted)
|
|
m_rectPlot.left = m_rectClient.left + 4*(nCharacters);
|
|
m_nPlotWidth = m_rectPlot.Width();
|
|
|
|
// draw the plot rectangle
|
|
oldPen = m_dcGrid.SelectObject (&solidPen);
|
|
m_dcGrid.MoveTo (m_rectPlot.left-1, m_rectPlot.top);
|
|
m_dcGrid.LineTo (m_rectPlot.right, m_rectPlot.top);
|
|
m_dcGrid.LineTo (m_rectPlot.right, m_rectPlot.bottom+1);
|
|
m_dcGrid.LineTo (m_rectPlot.left-1, m_rectPlot.bottom+1);
|
|
m_dcGrid.LineTo (m_rectPlot.left-1, m_rectPlot.top);
|
|
m_dcGrid.SelectObject (oldPen);
|
|
|
|
// draw the dotted lines,
|
|
// use SetPixel instead of a dotted pen - this allows for a
|
|
// finer dotted line and a more "technical" look
|
|
nMidGridPix = (m_rectPlot.top + m_rectPlot.bottom)/2;
|
|
nTopGridPix = nMidGridPix - m_nPlotHeight/4;
|
|
nBottomGridPix = nMidGridPix + m_nPlotHeight/4;
|
|
|
|
for (i=m_rectPlot.left; i<m_rectPlot.right; i+=4)
|
|
{
|
|
m_dcGrid.SetPixel (i, nTopGridPix, m_crGridColor);
|
|
m_dcGrid.SetPixel (i, nMidGridPix, m_crGridColor);
|
|
m_dcGrid.SetPixel (i, nBottomGridPix, m_crGridColor);
|
|
}
|
|
|
|
// create some fonts (horizontal and vertical)
|
|
// use a height of 14 pixels and 300 weight
|
|
// (these may need to be adjusted depending on the display)
|
|
axisFont.CreateFont (14, 0, 0, 0, 300,
|
|
FALSE, FALSE, 0, ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
DEFAULT_PITCH|FF_SWISS, _T("Arial"));
|
|
yUnitFont.CreateFont (14, 0, 900, 0, 300,
|
|
FALSE, FALSE, 0, ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
DEFAULT_PITCH|FF_SWISS, _T("Arial"));
|
|
|
|
// grab the horizontal font
|
|
oldFont = m_dcGrid.SelectObject(&axisFont);
|
|
|
|
// y max
|
|
m_dcGrid.SetTextColor (m_crGridColor);
|
|
m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP);
|
|
//strTemp.Format ("%.*lf", m_nYDecimals, m_dUpperLimit);
|
|
strTemp.Format (_T("%d"), (int)m_dUpperLimit);
|
|
m_dcGrid.TextOut (m_rectPlot.left, m_rectPlot.top, strTemp);
|
|
|
|
// y min
|
|
m_dcGrid.SetTextAlign (TA_RIGHT|TA_BASELINE);
|
|
//strTemp.Format ("%.*lf", m_nYDecimals, m_dLowerLimit);
|
|
strTemp.Format (_T("%d"), (int)m_dLowerLimit);
|
|
m_dcGrid.TextOut (m_rectPlot.left-4, m_rectPlot.bottom, strTemp);
|
|
|
|
// x min
|
|
m_dcGrid.SetTextAlign (TA_RIGHT|TA_BOTTOM);
|
|
strTemp.Format (_T("%d"), (int)m_dUpperYLimit);
|
|
m_dcGrid.TextOut (m_rectPlot.right, m_rectPlot.bottom+10, strTemp);
|
|
|
|
// x max
|
|
|
|
m_dcGrid.SetTextAlign (TA_RIGHT|TA_BOTTOM);
|
|
strTemp.Format ("%d", (int)m_dLowerXLimit);
|
|
m_dcGrid.TextOut (m_rectPlot.left-4, m_rectPlot.bottom+10, strTemp);
|
|
|
|
if( strTemp == "102" )
|
|
{
|
|
TRACE( "%s\n", strTemp );
|
|
}
|
|
|
|
// x units
|
|
m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP);
|
|
m_dcGrid.TextOut ((m_rectPlot.left+m_rectPlot.right)/2,
|
|
m_rectPlot.bottom+20, m_strXUnitsString);
|
|
|
|
// restore the font
|
|
m_dcGrid.SelectObject(oldFont);
|
|
|
|
// y units
|
|
oldFont = m_dcGrid.SelectObject(&yUnitFont);
|
|
m_dcGrid.SetTextAlign (TA_CENTER|TA_BASELINE);
|
|
m_dcGrid.TextOut ((m_rectClient.left+m_rectPlot.left)/2, (m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString);
|
|
m_dcGrid.SelectObject(oldFont);
|
|
|
|
// at this point we are done filling the the grid bitmap,
|
|
// no more drawing to this bitmap is needed until the setting are changed
|
|
|
|
// if we don't have one yet, set up a memory dc for the plot
|
|
if (m_dcPlot.GetSafeHdc() == NULL)
|
|
{
|
|
m_dcPlot.CreateCompatibleDC(&dc);
|
|
m_bitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapOldPlot = m_dcPlot.SelectObject(&m_bitmapPlot);
|
|
}
|
|
for(int i = 0 ; i < CI_MAX ; ++i)
|
|
{
|
|
if(m_dcCCUPlot[i].GetSafeHdc() == NULL)
|
|
{
|
|
m_dcCCUPlot[i].CreateCompatibleDC(&dc);
|
|
m_bitmapCCUPlot[i].CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapCCUOldPlot[i] = m_dcCCUPlot[i].SelectObject(&m_bitmapCCUPlot[i]);
|
|
}
|
|
}
|
|
|
|
|
|
// make sure the plot bitmap is cleared
|
|
m_dcPlot.SetBkColor (m_crBackColor);
|
|
m_dcPlot.FillRect(m_rectClient, &m_brushBack);
|
|
|
|
// finally, force the plot area to redraw
|
|
InvalidateRect(m_rectClient);
|
|
|
|
} // InvalidateCtrl
|
|
|
|
void COScopeCtrl::InvalidateXUnits()
|
|
{
|
|
// There is a lot of drawing going on here - particularly in terms of
|
|
// drawing the grid. Don't panic, this is all being drawn (only once)
|
|
// to a bitmap. The result is then BitBlt'd to the control whenever needed.
|
|
|
|
CFont axisFont, *oldFont;
|
|
|
|
// in case we haven't established the memory dc's
|
|
CClientDC dc(this);
|
|
|
|
// if we don't have one yet, set up a memory dc for the grid
|
|
if (m_dcGrid.GetSafeHdc() == NULL)
|
|
{
|
|
m_dcGrid.CreateCompatibleDC(&dc);
|
|
m_bitmapGrid.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid);
|
|
}
|
|
|
|
// create some fonts (horizontal and vertical)
|
|
// use a height of 14 pixels and 300 weight
|
|
// (these may need to be adjusted depending on the display)
|
|
axisFont.CreateFont (14, 0, 0, 0, 300,
|
|
FALSE, FALSE, 0, ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
DEFAULT_PITCH|FF_SWISS, _T("Arial"));
|
|
|
|
// grab the horizontal font
|
|
oldFont = m_dcGrid.SelectObject(&axisFont);
|
|
|
|
// x units
|
|
m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP);
|
|
m_dcGrid.TextOut ((m_rectPlot.left+m_rectPlot.right)/2, m_rectPlot.bottom+20, m_strXUnitsString);
|
|
|
|
// restore the font
|
|
m_dcGrid.SelectObject(oldFont);
|
|
|
|
// finally, force the plot area to redraw
|
|
InvalidateRect(m_rectClient);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
double COScopeCtrl::AppendPoint(bool bCCU, double dNewPoint)
|
|
{
|
|
// append a data point to the plot
|
|
// return the previous point
|
|
m_bCountryCode = bCCU;
|
|
double dPrevious;
|
|
|
|
dPrevious = m_dCurrentPosition;
|
|
m_dCurrentPosition = dNewPoint;
|
|
DrawPoint();
|
|
|
|
Invalidate();
|
|
return dPrevious;
|
|
|
|
} // AppendPoint
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void COScopeCtrl::AppendCCUPoint(double dNewGB,double dNewDE,double dNewFR,double dNewIT,double dNewPL,double dNewTR, double dNewETC )
|
|
{
|
|
m_dCurCCUPosition[CI_EG] = dNewGB;
|
|
m_dCurCCUPosition[CI_GE] = dNewDE;
|
|
m_dCurCCUPosition[CI_FR] = dNewFR;
|
|
m_dCurCCUPosition[CI_IT] = dNewIT;
|
|
m_dCurCCUPosition[CI_PL] = dNewPL;
|
|
m_dCurCCUPosition[CI_TR] = dNewTR;
|
|
m_dCurCCUPosition[CI_ETC] = dNewETC;
|
|
} //AppendCCUPoint
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
CDC memDC;
|
|
CBitmap memBitmap;
|
|
CBitmap* oldBitmap; // bitmap originally found in CMemDC
|
|
|
|
// no real plotting work is performed here,
|
|
// just putting the existing bitmaps on the client
|
|
|
|
// to avoid flicker, establish a memory dc, draw to it
|
|
// and then BitBlt it to the client
|
|
memDC.CreateCompatibleDC(&dc);
|
|
memBitmap.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
|
|
oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap);
|
|
|
|
if (memDC.GetSafeHdc() != NULL)
|
|
{
|
|
// first drop the grid on the memory dc
|
|
memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, &m_dcGrid, 0, 0, SRCCOPY);
|
|
// now add the plot on top as a "pattern" via SRCPAINT.
|
|
// works well with dark background and a light plot
|
|
memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, &m_dcPlot, 0, 0, SRCPAINT); //SRCPAINT
|
|
|
|
//CCU
|
|
if(m_bCountryCode)
|
|
{
|
|
for(int i = 0 ; i < CI_MAX ; ++i)
|
|
memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, &m_dcCCUPlot[i], 0, 0, SRCPAINT);
|
|
}
|
|
|
|
|
|
// finally send the result to the display
|
|
dc.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, &memDC, 0, 0, SRCCOPY);
|
|
}
|
|
|
|
memDC.SelectObject(oldBitmap);
|
|
|
|
} // OnPaint
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::DrawPoint()
|
|
{
|
|
// this does the work of "scrolling" the plot to the left
|
|
// and appending a new data point all of the plotting is
|
|
// directed to the memory based bitmap associated with m_dcPlot
|
|
// the will subsequently be BitBlt'd to the client in OnPaint
|
|
|
|
int currX, prevX, currY, prevY;
|
|
int currCCUX[CI_MAX], prevCCUX[CI_MAX], currCCUY[CI_MAX], prevCCUY[CI_MAX];
|
|
CPen *oldPen;
|
|
CPen *oldCCUPen[CI_MAX];
|
|
CRect rectCleanUp;
|
|
|
|
if (m_dcPlot.GetSafeHdc() != NULL)
|
|
{
|
|
// shift the plot by BitBlt'ing it to itself
|
|
// note: the m_dcPlot covers the entire client
|
|
// but we only shift bitmap that is the size
|
|
// of the plot rectangle
|
|
// grab the right side of the plot (exluding m_nShiftPixels on the left)
|
|
// move this grabbed bitmap to the left by m_nShiftPixels
|
|
|
|
m_dcPlot.BitBlt(m_rectPlot.left, m_rectPlot.top+1, m_nPlotWidth, m_nPlotHeight, &m_dcPlot, m_rectPlot.left+m_nShiftPixels, m_rectPlot.top+1, SRCCOPY);
|
|
|
|
// establish a rectangle over the right side of plot
|
|
// which now needs to be cleaned up proir to adding the new point
|
|
rectCleanUp = m_rectPlot;
|
|
rectCleanUp.left = rectCleanUp.right - m_nShiftPixels;
|
|
|
|
// fill the cleanup area with the background
|
|
m_dcPlot.FillRect(rectCleanUp, &m_brushBack);
|
|
|
|
// draw the next line segement
|
|
|
|
// grab the plotting pen
|
|
oldPen = m_dcPlot.SelectObject(&m_penPlot);
|
|
|
|
// move to the previous point
|
|
prevX = m_rectPlot.right - m_nPlotShiftPixels;
|
|
prevY = m_rectPlot.bottom - (long)((m_dPreviousPosition - m_dLowerLimit) * m_dVerticalFactor);
|
|
m_dcPlot.MoveTo (prevX, prevY);
|
|
|
|
// draw to the current point
|
|
currX = m_rectPlot.right-m_nHalfShiftPixels;
|
|
currY = m_rectPlot.bottom - (long)((m_dCurrentPosition - m_dLowerLimit) * m_dVerticalFactor);
|
|
m_dcPlot.LineTo (currX, currY);
|
|
|
|
// restore the pen
|
|
m_dcPlot.SelectObject(oldPen);
|
|
|
|
// if the data leaks over the upper or lower plot boundaries
|
|
// fill the upper and lower leakage with the background
|
|
// this will facilitate clipping on an as needed basis
|
|
// as opposed to always calling IntersectClipRect
|
|
if ((prevY <= m_rectPlot.top) || (currY <= m_rectPlot.top))
|
|
m_dcPlot.FillRect(CRect(prevX, m_rectClient.top, currX+1, m_rectPlot.top+1), &m_brushBack);
|
|
if ((prevY >= m_rectPlot.bottom) || (currY >= m_rectPlot.bottom))
|
|
m_dcPlot.FillRect(CRect(prevX, m_rectPlot.bottom+1, currX+1, m_rectClient.bottom+1), &m_brushBack);
|
|
|
|
// store the current point for connection to the next point
|
|
m_dPreviousPosition = m_dCurrentPosition;
|
|
|
|
if(m_bCountryCode)
|
|
{
|
|
for(int i = 0 ; i < CI_MAX ; ++i)
|
|
{
|
|
m_dcCCUPlot[i].BitBlt(m_rectPlot.left, m_rectPlot.top+1, m_nPlotWidth, m_nPlotHeight, &m_dcCCUPlot[i], m_rectPlot.left+m_nShiftPixels, m_rectPlot.top+1, SRCCOPY);
|
|
if(m_dcCCUPlot[i].GetSafeHdc() != NULL)
|
|
{
|
|
//grab the plotting pen
|
|
oldCCUPen[i] = m_dcCCUPlot[i].SelectObject(&m_CCUpen[i]);
|
|
|
|
//previous point
|
|
prevCCUX[i] = m_rectPlot.right - m_nPlotShiftPixels;
|
|
prevCCUY[i] = m_rectPlot.bottom - (long)((m_dPreCCUPosition[i] - m_dLowerLimit) * m_dVerticalFactor);
|
|
m_dcCCUPlot[i].MoveTo(prevCCUX[i], prevCCUY[i]);
|
|
//current point
|
|
currCCUX[i] = m_rectPlot.right-m_nHalfShiftPixels;
|
|
currCCUY[i] = m_rectPlot.bottom - (long)((m_dCurCCUPosition[i] - m_dLowerLimit) * m_dVerticalFactor);
|
|
m_dcCCUPlot[i].LineTo (currCCUX[i], currCCUY[i]);
|
|
//restore the pen
|
|
m_dcCCUPlot[i].SelectObject(oldCCUPen[i]);
|
|
|
|
if ((prevCCUY[i] <= m_rectPlot.top) || (currCCUY[i] <= m_rectPlot.top))
|
|
m_dcCCUPlot[i].FillRect(CRect(prevCCUX[i], m_rectClient.top, currCCUX[i]+1, m_rectPlot.top+1), &m_brushBack);
|
|
if ((prevCCUY[i] >= m_rectPlot.bottom) || (currCCUY[i] >= m_rectPlot.bottom))
|
|
m_dcCCUPlot[i].FillRect(CRect(prevCCUX[i], m_rectPlot.bottom+1, currCCUX[i]+1, m_rectClient.bottom+1), &m_brushBack);
|
|
|
|
// store the current point for connection to the next point
|
|
m_dPreCCUPosition[i] = m_dCurCCUPosition[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // end DrawPoint
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy);
|
|
|
|
// NOTE: OnSize automatically gets called during the setup of the control
|
|
|
|
GetClientRect(m_rectClient);
|
|
|
|
// set some member variables to avoid multiple function calls
|
|
m_nClientHeight = m_rectClient.Height();
|
|
m_nClientWidth = m_rectClient.Width();
|
|
|
|
// the "left" coordinate and "width" will be modified in
|
|
// InvalidateCtrl to be based on the width of the y axis scaling
|
|
m_rectPlot.left = 5;
|
|
m_rectPlot.top = 5;
|
|
m_rectPlot.right = m_rectClient.right-10;
|
|
m_rectPlot.bottom = m_rectClient.bottom-20;
|
|
|
|
// set some member variables to avoid multiple function calls
|
|
m_nPlotHeight = m_rectPlot.Height();
|
|
m_nPlotWidth = m_rectPlot.Width();
|
|
|
|
// set the scaling factor for now, this can be adjusted
|
|
// in the SetRange functions
|
|
m_dVerticalFactor = (double)m_nPlotHeight / m_dRange;
|
|
|
|
} // OnSize
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void COScopeCtrl::Reset()
|
|
{
|
|
m_dPreviousPosition = 0;
|
|
m_dCurrentPosition = 0;
|
|
|
|
InvalidateCtrl();
|
|
}
|
|
|
|
int COScopeCtrl::GetWidth()
|
|
{
|
|
int nWidth = m_rectPlot.right - m_rectPlot.left;
|
|
return nWidth;
|
|
}
|
|
|
|
BOOL COScopeCtrl::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
m_toolTip.RelayEvent(pMsg);
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
int COScopeCtrl::GetRightPixel()
|
|
{
|
|
return m_rectPlot.right;
|
|
}
|
|
|
|
int COScopeCtrl::GetLeftPixel()
|
|
{
|
|
return m_rectPlot.left;
|
|
} |