📄 oscopectrl.cpp
字号:
COLORREF COScopeCtrl::GetPlotColor(int iTrend)
{
return m_PlotData[iTrend].crPlotColor;
} // GetPlotColor
/////////////////////////////////////////////////////////////////////////////
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::InvalidateCtrl(bool deleteGraph)
{
// 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, j, GridPos;
int nCharacters;
CPen *oldPen;
CPen solidPen(PS_SOLID, 0, m_crGridColor);
CFont axisFont, yUnitFont, *oldFont, LegendFont;
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.DeleteObject();
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
double fAbsUpperLimit = fabs(m_PlotData[0].dUpperLimit);
if (fAbsUpperLimit > 0.0)
nCharacters = abs((int)log10(fAbsUpperLimit));
else
nCharacters = 0;
double fAbsLowerLimit = fabs(m_PlotData[0].dLowerLimit);
if (fAbsLowerLimit > 0.0)
nCharacters = max(nCharacters, abs((int)log10(fAbsLowerLimit)));
// 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)
// Changed this so that the Y-Units wouldn't overlap the Y-Scale.
m_rectPlot.left = m_rectClient.left + 8*7+4;//(nCharacters) ;
m_nPlotWidth = m_rectPlot.Width();
// draw the plot rectangle
oldPen = m_dcGrid.SelectObject(&solidPen);
m_dcGrid.MoveTo(m_rectPlot.left, m_rectPlot.top);
m_dcGrid.LineTo(m_rectPlot.right + 1, m_rectPlot.top);
m_dcGrid.LineTo(m_rectPlot.right + 1, m_rectPlot.bottom + 1);
m_dcGrid.LineTo(m_rectPlot.left, m_rectPlot.bottom + 1);
m_dcGrid.LineTo(m_rectPlot.left, 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
// G.Hayduk: added configurable number of grids
for(j = 1; j < (m_nYGrids + 1); j++)
{
GridPos = m_rectPlot.Height()*j/ (m_nYGrids + 1) + m_rectPlot.top;
for(i = m_rectPlot.left; i < m_rectPlot.right; i += 4)
m_dcGrid.SetPixel(i, GridPos, 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,
FALSE, FALSE, 0, DEFAULT_CHARSET, // EC
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,
FALSE, FALSE, 0, DEFAULT_CHARSET, // EC
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);
if(m_str.YMax.IsEmpty())
strTemp.Format(_T("%.*lf"), m_nYDecimals, m_PlotData[0].dUpperLimit);
else
strTemp = m_str.YMax;
m_dcGrid.TextOut(m_rectPlot.left - 4, m_rectPlot.top - 7, strTemp);
if(m_rectPlot.Height()/(m_nYGrids+1) >= 14) {
for(j = 1; j < (m_nYGrids + 1); j++) {
GridPos = m_rectPlot.Height()*j/ (m_nYGrids + 1) + m_rectPlot.top;
strTemp.Format(_T("%.*lf"), m_nYDecimals, m_PlotData[0].dUpperLimit*(m_nYGrids-j+1)/(m_nYGrids+1));
m_dcGrid.TextOut(m_rectPlot.left - 4, GridPos-7, strTemp);
}
} else {
// y/2
strTemp.Format(_T("%.*lf"), m_nYDecimals, m_PlotData[0].dUpperLimit / 2);
m_dcGrid.TextOut(m_rectPlot.left - 2, m_rectPlot.bottom+ ((m_rectPlot.top - m_rectPlot.bottom)/2) - 7 , strTemp);
}
// y min
if(m_str.YMin.IsEmpty())
strTemp.Format(_T("%.*lf"), m_nYDecimals, m_PlotData[0].dLowerLimit);
else
strTemp = m_str.YMin;
m_dcGrid.TextOut(m_rectPlot.left - 4, m_rectPlot.bottom-7, strTemp);
// x units
m_dcGrid.SetTextAlign(TA_RIGHT | TA_BOTTOM);
m_dcGrid.TextOut (m_rectClient.right-2,m_rectClient.bottom-2,m_str.XUnits);
// restore the font
m_dcGrid.SelectObject(oldFont);
// y units
oldFont = m_dcGrid.SelectObject(&yUnitFont);
m_dcGrid.SetTextAlign(TA_CENTER | TA_BASELINE);
CRect rText(0,0,0,0);
m_dcGrid.DrawText(m_str.YUnits, rText, DT_CALCRECT);
m_dcGrid.TextOut ((m_rectClient.left+m_rectPlot.left+4)/2-rText.Height() / 2,
((m_rectPlot.bottom+m_rectPlot.top)/2)-rText.Height()/2, m_str.YUnits) ;
m_dcGrid.SelectObject(oldFont);
LegendFont.CreateFont(12, 0, 0, 0, 300,
FALSE, FALSE, 0, DEFAULT_CHARSET, // EC
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, _T("Arial"));
oldFont = m_dcGrid.SelectObject(&LegendFont);
m_dcGrid.SetTextAlign(TA_LEFT | TA_TOP);
int xpos,ypos;
xpos = m_rectPlot.left + 2;
ypos = m_rectPlot.bottom+2;
for (i=0 ; i < m_NTrends; i++){
if (xpos+12+6*m_PlotData[i].LegendLabel.GetLength()>m_rectPlot.right){
xpos = m_rectPlot.left + 2;
ypos = m_rectPlot.bottom+12;
}
CPen LegendPen(PS_SOLID, 3,m_PlotData[i].crPlotColor);
oldPen = m_dcGrid.SelectObject(&LegendPen);
m_dcGrid.MoveTo(xpos, ypos+8);
m_dcGrid.LineTo(xpos + 8, ypos+4);
m_dcGrid.TextOut(xpos + 12 ,ypos, m_PlotData[i].LegendLabel);
xpos += 12+6*m_PlotData[i].LegendLabel.GetLength();
m_dcGrid.SelectObject(oldPen);
}
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.DeleteObject();
m_bitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
m_pbitmapOldPlot = m_dcPlot.SelectObject(&m_bitmapPlot);
}
// make sure the plot bitmap is cleared
if(deleteGraph)
{
m_dcPlot.SetBkColor(m_crBackColor);
m_dcPlot.FillRect(m_rectClient, &m_brushBack);
}
int iNewSize = m_rectClient.Width() / m_nShiftPixels + 10; // +10 just in case :)
if(m_nMaxPointCnt < iNewSize)
m_nMaxPointCnt = iNewSize; // keep the bigest value
if (theApp.emuledlg->IsRunning())
{
if (thePrefs.IsGraphRecreateDisabled() == false) {
// The timer will redraw the previous points in 200ms
m_bDoUpdate = false;
if(m_nRedrawTimer)
KillTimer(m_nRedrawTimer);
VERIFY( (m_nRedrawTimer = SetTimer(1612, 200, NULL)) ); // reduce flickering
}
}
// finally, force the plot area to redraw
InvalidateRect(m_rectClient);
} // InvalidateCtrl
/////////////////////////////////////////////////////////////////////////////
// G.Hayduk: now, there are two methods: AppendPoints and AppendEmptyPoints
// Added new parameter: bool bUseTrendRatio (TRUE by default)
void COScopeCtrl::AppendPoints(double dNewPoint[], bool bInvalidate, bool bAdd2List, bool bUseTrendRatio)
{
int iTrend;
// append a data point to the plot
for(iTrend = 0; iTrend < m_NTrends; iTrend ++)
{
// Changed this to support the new TrendRatio var
if (bUseTrendRatio)
m_PlotData[iTrend].dCurrentPosition = (double) dNewPoint[iTrend] / m_PlotData[iTrend].iTrendRatio;
else
m_PlotData[iTrend].dCurrentPosition = dNewPoint[iTrend];
if(bAdd2List)
{
m_PlotData[iTrend].lstPoints.AddTail(m_PlotData[iTrend].dCurrentPosition);
while(m_PlotData[iTrend].lstPoints.GetCount() > m_nMaxPointCnt)
m_PlotData[iTrend].lstPoints.RemoveHead();
}
}
// Sometime responsible for 'ghost' point on the left after a resize
if(m_bDoUpdate == false)
return;
if(m_nTrendPoints > 0)
{
if(CustShift.m_nPointsToDo == 0)
{
CustShift.m_nPointsToDo = m_nTrendPoints - 1;
CustShift.m_nWidthToDo = m_nPlotWidth;
CustShift.m_nRmndr = 0;
}
// a little bit tricky setting m_nShiftPixels in "fixed number of points through plot width" mode
m_nShiftPixels = (CustShift.m_nWidthToDo + CustShift.m_nRmndr) / CustShift.m_nPointsToDo;
CustShift.m_nRmndr = (CustShift.m_nWidthToDo + CustShift.m_nRmndr) % CustShift.m_nPointsToDo;
if(CustShift.m_nPointsToDo == 1)
m_nShiftPixels = CustShift.m_nWidthToDo;
CustShift.m_nWidthToDo -= m_nShiftPixels;
CustShift.m_nPointsToDo--;
}
DrawPoint();
if(bInvalidate && ready && m_bDoUpdate)
Invalidate();
return;
} // AppendPoint
/////////////////////////////////////////////////////////////////////////////
// G.Hayduk:
// AppendEmptyPoints adds a vector of data points, without drawing them
// (but shifting the plot), this way you can do a "hole" (space) in the plot
// i.e. indicating "no data here". When points are available, call AppendEmptyPoints
// for first valid vector of data points, and then call AppendPoints again and again
// for valid points
// Added parameter: bool bUseTrendRatio (TRUE by default)
void COScopeCtrl::AppendEmptyPoints(double dNewPoint[], bool bInvalidate, bool bAdd2List, bool bUseTrendRatio)
{
int iTrend, currY;
CRect ScrollRect, rectCleanUp;
// append a data point to the plot
// return the previous point
for(iTrend = 0; iTrend < m_NTrends; iTrend ++)
{
// Changed to support new Trend Ratio var and bUseTrendRatio parameter.
if (bUseTrendRatio)
m_PlotData[iTrend].dCurrentPosition = (double) dNewPoint[iTrend] / m_PlotData[iTrend].iTrendRatio;
else
m_PlotData[iTrend].dCurrentPosition = dNewPoint[iTrend];
if(bAdd2List)
m_PlotData[iTrend].lstPoints.AddTail(m_PlotData[iTrend].dCurrentPosition);
}
if(m_nTrendPoints > 0)
{
if(CustShift.m_nPointsToDo == 0)
{
CustShift.m_nPointsToDo = m_nTrendPoints - 1;
CustShift.m_nWidthToDo = m_nPlotWidth;
CustShift.m_nRmndr = 0;
}
m_nShiftPixels = (CustShift.m_nWidthToDo + CustShift.m_nRmndr) / CustShift.m_nPointsToDo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -