Files
ls-2019-source/extra/LS_MonitorClient/LS_MonitorClient/OScopeCtrl.cpp
T
2026-11-07 13:30:45 +07:00

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;
}