////////////////
// plot.cpp

#include "stdafx.h"
#include "plot.h"

IMPLEMENT_DYNAMIC (CPlot, CFrameWnd)

BEGIN_MESSAGE_MAP(CPlot, CFrameWnd)
	ON_WM_CHAR()
	ON_WM_CLOSE()
	ON_COMMAND_RANGE(IDM_ZOOMIN,IDM_SCALE_AUTO,OnPopup)
	ON_WM_CREATE()
	ON_WM_HSCROLL()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_PAINT()
	ON_WM_RBUTTONDOWN()
	ON_WM_SIZE()
END_MESSAGE_MAP()

CZoom::CZoom (long AleftIDX,long ArightIDX,double AxScale,double AyScale,CRect& AselRect,double AyBaseline)
{
	leftIDX     = AleftIDX; 
	rightIDX    = ArightIDX; 
	xScale      = AxScale; 
	yScale      = AyScale; 
	selectRect  = AselRect; 
	yBaseline   = AyBaseline;
}

CPlot::CPlot (CWnd *pWnd, CString xLabel, CString yLabel, double xTickScale, double yTickScale) 
{
	int i=0;

	m_bInvertOldSel = FALSE;
	m_botMargin = 0;
	m_bSelectionExists = FALSE;
	m_lastDeviceX = 0;
	for (i=0; i<_CPLOT_MAXTRACES; i++) {
		m_lastDeviceY[i] = 0;
	}
	m_lastPageX = 0;
	for (i=0; i<_CPLOT_MAXTRACES; i++) {
		m_lastPageY[i] = 0;
	}
	m_leftIDX = 0;
	m_leftMargin = 0;
	m_leftSelIDX = 0;
	m_localYMax = 10e-300;
	m_localYMin = 10e+300;
	m_majorXTick = 5;
	m_majorYTick = 5;
	m_nPageSize = 0;
	m_nScrollPos = 0;
	m_numScreens = 1;
	m_numTraces = 0;
	m_numXTicks = 20;
	m_numYTicks = 20;
	m_oldXScale = XSCALE;
	m_oldYScale = YSCALE;
	m_origLeftIDX = 0;
	m_origRightIDX = 0;
	m_plotRect = CRect(0,0,0,0);
	m_pMenuMain = new CMenu;
	m_pMenuPopup = new CMenu;
	m_pOwnerWnd = pWnd;
	m_pPenArray[0] = new CPen(PS_SOLID,1,COLOR_BLACK);
	m_pPenArray[1] = new CPen(PS_SOLID,1,COLOR_RED);
	m_pPenArray[2] = new CPen(PS_SOLID,1,COLOR_BLUE);
	m_pPenArray[3] = new CPen(PS_SOLID,1,COLOR_GREEN);
	m_pScaleHistory = new CList<CZoom,CZoom&>(5);
	// m_pYHistory = new CList<double,double&>(500);
	m_yHistories.SetSize(0);
	m_rect = CRect(0,0,0,0);
	m_rightIDX = 0;
	m_rightMargin = 0;
	m_rightSelIDX = 0;
	m_selectRect = CRect(0,0,0,0);
	m_thisDeviceX = 0;
	m_thisDeviceY = 0;
	m_thisPageX = 0;
	m_thisPageY = 0;
	m_topMargin = 0;
	m_xAxisLabel = xLabel;
	m_xScale = XSCALE;
	m_xTickScale = xTickScale;
	m_yAxisLabel = yLabel;
	m_yBaseline = 0;
	m_yScale = YSCALE;
	m_yTickScale = yTickScale;
}

CPlot::~CPlot () 
{
	int i=0;
	for (i=0; i<NUM_PENS; i++)
		delete m_pPenArray[i];
	for (i=0; i<m_numTraces; i++) {
		((CList<double,double&> *)m_yHistories[i])->RemoveAll();
		delete m_yHistories[i];
	}
	m_pScaleHistory->RemoveAll();
	delete m_pScaleHistory;
	delete m_pMenuMain;
	delete m_pMenuPopup;
}


void CPlot::AddPoint (int traceNum, double yVal, short penChoice) 
{
	m_pDC = GetDC();
	if (traceNum < 0 || traceNum >= m_numTraces) return;
	((CList<double,double&> *)m_yHistories[traceNum])->AddTail(yVal);
	m_tracePens[traceNum] = penChoice;
	if (yVal>m_localYMax) m_localYMax=yVal;
	if (yVal<m_localYMin) m_localYMin=yVal; 
	m_pDC->SelectObject(m_pPenArray[penChoice]);
	m_thisPageY = m_thisDeviceY = (long)(m_yBaseline - (yVal * m_yScale));
	if (traceNum == m_numTraces-1) {
		m_lastPageX   = m_thisPageX;
		m_lastDeviceX = m_thisDeviceX;
		m_thisPageX += m_xScale;
		m_thisDeviceX += m_xScale;
		m_rightIDX++;
		m_origRightIDX = m_rightIDX;
		if (m_thisDeviceX > m_rightMargin) {
			// for memory safety, uncomment these lines to delete stored y-values at end of each screen.
			// remove this line when h-scrolling is enabled
			// for (int i=0; i<m_numTraces; i++)
			//	((CList<double,double&> *)m_yHistories[i])->RemoveAll();
			m_numScreens++;
			//m_pDC->SetWindowOrg((int)m_grandX,0);
			m_thisDeviceX = m_leftMargin + m_xScale;
			m_lastDeviceX = m_leftMargin;
			Clear(m_pDC);
			m_leftIDX = m_rightIDX;
			m_origLeftIDX = m_leftIDX;
			m_bSelectionExists = FALSE;
			m_pScaleHistory->RemoveAll();
			m_oldXScale = m_xScale;
			m_oldYScale = m_yScale;
			m_localYMax = 10e-300;
			m_localYMin = 10e+300;
			// Update scrollbar
			SCROLLINFO si;
			GetScrollInfo(SB_HORZ,&si);
			int ptsPerScreen = (int)((double)m_plotRect.Width()/m_xScale);
			si.nMax = m_numScreens * ptsPerScreen;
			si.nPos = (m_numScreens-1) * ptsPerScreen;
			si.nPage = ptsPerScreen;
			SetScrollInfo(SB_HORZ,&si,TRUE);
			m_nPageSize = si.nPage;
			m_nScrollPos = si.nPos;
		}
	}
	m_pDC->MoveTo((long)m_lastDeviceX, (long)m_lastDeviceY[traceNum]);
	m_pDC->LineTo((long)m_thisDeviceX, (long)m_thisDeviceY);
	m_lastDeviceY[traceNum] = m_thisDeviceY;
}

void CPlot::AddTrace()
{
	m_yHistories.Add(new CList<double, double&>(500));
	m_numTraces = m_yHistories.GetSize();
}

void CPlot::Clear (CDC *pDC) 
{
	CPen* pCurPen = m_pDC->GetCurrentPen();
	CBrush* pCurBrush = m_pDC->GetCurrentBrush();

	m_pDC->SelectStockObject(WHITE_BRUSH);
	m_pDC->SelectStockObject(WHITE_PEN);
	m_pDC->Rectangle(&m_rect);
	DrawAxes(m_pDC);

	m_pDC->SelectObject(pCurPen);
	m_pDC->SelectObject(pCurBrush);
}

void CPlot::DrawAxes (CDC *pDC) 
{
	CPen* pCurPen = m_pDC->GetCurrentPen();
	CBrush* pCurBrush = m_pDC->GetCurrentBrush();

	// Draw frame with dotted baseline
	m_pDC->SelectStockObject(BLACK_PEN);
	m_pDC->SelectStockObject(WHITE_BRUSH);
	m_pDC->Rectangle(
		(long)(LEFTMARGIN*m_rect.right),
		(long)(TOPMARGIN*m_rect.bottom),
		(long)(RIGHTMARGIN*m_rect.right),
		(long)(BOTMARGIN*m_rect.bottom));
	CPen pen(PS_DOT,1,RGB(0,0,0));
	m_pDC->SelectObject(&pen);
	m_pDC->MoveTo((long)(LEFTMARGIN*m_rect.right),m_yBaseline);
	m_pDC->LineTo((long)(RIGHTMARGIN*m_rect.right)-1,m_yBaseline);

	// Draw tickmarks
	int i=0;
	int tickLen=0;
	double xTickSpace = (RIGHTMARGIN-LEFTMARGIN)*m_rect.Width()/(m_numXTicks-1);
	double yTickSpace = (BOTMARGIN-TOPMARGIN)*m_rect.Height()/(m_numYTicks-1);
	m_pDC->SelectStockObject(BLACK_PEN);
	for (i=1; i<=m_numXTicks; i++) {
		tickLen = (int)(XTICKLEN*m_rect.Height());
		if (i%m_majorXTick==0) tickLen *= 2;
		m_pDC->MoveTo((long)(m_leftMargin+i*xTickSpace),m_botMargin-1);
		if ( (long)(m_leftMargin+i*xTickSpace) < RIGHTMARGIN*m_rect.right)
			m_pDC->LineTo((long)(m_leftMargin+i*xTickSpace),m_botMargin-tickLen-1);
	}
	i=1;
	while ( (long)(m_yBaseline-i*yTickSpace) > TOPMARGIN*m_rect.bottom) {
		tickLen = (int)(YTICKLEN*m_rect.Width());
		if (i%m_majorYTick==0) tickLen *= 2;
		m_pDC->MoveTo(m_leftMargin,(long)(m_yBaseline-i*yTickSpace));
		m_pDC->LineTo(m_leftMargin+tickLen,(long)(m_yBaseline-i*yTickSpace));
		i++;
	}
	i=1;
	while ( (long)(m_yBaseline+i*yTickSpace) < (BOTMARGIN*m_rect.bottom - yTickSpace)) {
		tickLen = (int)(YTICKLEN*m_rect.Width());
		if (i%m_majorYTick==0) tickLen *= 2;
		m_pDC->MoveTo(m_leftMargin,(long)(m_yBaseline+i*yTickSpace));
		m_pDC->LineTo(m_leftMargin+tickLen,(long)(m_yBaseline+i*yTickSpace));
		i++;
	}

	// Draw axis labels
	HFONT hfnt, hfntPrev; 
	PLOGFONT plf = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT)); 
 	lstrcpy(plf->lfFaceName, "Arial"); 
	plf->lfWeight = FW_NORMAL; 
	plf->lfHeight = (long)(0.40*(1-BOTMARGIN)*m_rect.bottom);
  	m_pDC->SetBkMode(TRANSPARENT); 
	plf->lfEscapement = 900; 
	hfnt = CreateFontIndirect(plf); 
	hfntPrev = (HFONT)SelectObject(m_pDC->m_hDC,hfnt);
	CSize labSize = m_pDC->GetTextExtent(m_yAxisLabel);
	m_pDC->LPtoDP(&labSize);
	m_pDC->TextOut(2, (long)(m_plotRect.top + (double)m_plotRect.Height()/2 +((double)labSize.cx)/2), m_yAxisLabel); 
	DeleteObject(hfnt); 
	plf->lfEscapement = 0; 
	hfnt = CreateFontIndirect(plf);
	SelectObject(m_pDC->m_hDC,hfnt);
	labSize = m_pDC->GetTextExtent(m_xAxisLabel);
	m_pDC->LPtoDP(&labSize);
	m_pDC->TextOut((long)(0.50*m_rect.right-((double)labSize.cx)/2),m_rect.bottom-labSize.cy-1, m_xAxisLabel); 

	// Draw tick labels
	double val=0.0;
	char str[12];
	for (i=1; i<=m_numXTicks; i++) {
		if (i%m_majorXTick==0) {
			val = (xTickSpace/m_xTickScale) * ((m_numScreens-1)*(m_numXTicks-1) + i);
			sprintf (str,"%.2f",val);
			labSize = m_pDC->GetTextExtent(CString(str));
			m_pDC->LPtoDP(&labSize);
			if (m_leftMargin+i*xTickSpace+labSize.cx < m_rect.right)
				m_pDC->TextOut((long)(m_leftMargin+i*xTickSpace-((double)labSize.cx)/2),m_botMargin-1,str);
		}
	}
	i=0;
	do {
		if (i==0) {
			sprintf (str,"0.00");
			labSize = m_pDC->GetTextExtent(CString(str));
			m_pDC->LPtoDP(&labSize);
			m_pDC->TextOut(m_leftMargin-labSize.cx-1,(long)(m_yBaseline-((double)labSize.cy)/2),str);
		}
		else if (i>0 && i%m_majorYTick==0) {
			val = (double)i*yTickSpace/m_yTickScale;
			sprintf (str,"%.2f",val);
			labSize = m_pDC->GetTextExtent(CString(str));
			m_pDC->LPtoDP(&labSize);
			m_pDC->TextOut(m_leftMargin-labSize.cx-1,(long)(m_yBaseline-i*yTickSpace-((double)labSize.cy)/2),str);
		}
		i++;
	} while (m_yBaseline-i*yTickSpace-labSize.cy > m_rect.top);
	i=1;
	while (m_yBaseline+i*yTickSpace-labSize.cy < BOTMARGIN*m_rect.bottom - yTickSpace) {
		if (i%m_majorYTick==0) {
			val = (double)i*yTickSpace/m_yTickScale;
			sprintf (str,"-%.2f",val);
			labSize = m_pDC->GetTextExtent(CString(str));
			m_pDC->LPtoDP(&labSize);
			m_pDC->TextOut(m_leftMargin-labSize.cx-1,(long)(m_yBaseline+i*yTickSpace-((double)labSize.cy)/2),str);
		}
		i++;
	}

	DeleteObject(hfnt); 
	m_pDC->SetBkMode(OPAQUE); 
 	LocalFree((LOCALHANDLE) plf); 
	m_pDC->SelectObject(hfntPrev); 
	m_pDC->SelectObject(pCurPen);

	m_pDC->SelectObject(pCurBrush);
}

void CPlot::DrawSpike ()
{
	// CClientDC dc(this);
	m_pDC->SelectObject(m_pPenArray[BLUE_PEN]);
	m_pDC->MoveTo((long)m_thisDeviceX,(long)m_thisDeviceY);
	m_pDC->LineTo((long)m_thisDeviceX,(long)m_thisDeviceY-30);
}

void CPlot::InvertRect(CDC* pDC, LPCRECT lpRect)
{
	int nOldMode = m_pDC->SetROP2 (R2_NOT);
	m_pDC->SelectStockObject(NULL_BRUSH);
	m_pDC->Rectangle(lpRect);
	m_pDC->SetROP2(nOldMode);
}

void CPlot::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags )
{
	CFrameWnd::OnChar(nChar, nRepCnt, nFlags);
	switch (nChar) {
	case (0x1b):	// escape key
		PostMessage(WM_COMMAND,IDM_BACKUP,0);
		break;
	}
}

void CPlot::OnClose( )
{
	WPARAM wParam;
	wParam = WM_CPLOT_DELETE;

	NMHDR nmhdr;
	nmhdr.hwndFrom = m_hWnd;
	nmhdr.idFrom = 0;
	nmhdr.code = WM_CPLOT_DELETE;

	::SendMessage(m_pOwnerWnd->m_hWnd,WM_NOTIFY,wParam,(LPARAM)&nmhdr);
	CFrameWnd::OnClose();
}

int CPlot::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	m_pMenuMain->CreateMenu();
	m_pMenuPopup->CreatePopupMenu();

	m_pMenuPopup->AppendMenu(MF_STRING,IDM_ZOOMIN,"Zoom in\tF1");
	m_pMenuPopup->AppendMenu(MF_SEPARATOR);
	m_pMenuPopup->AppendMenu(MF_STRING,IDM_EXPAND_VERT,"Expand vertical\tF2");
	m_pMenuPopup->AppendMenu(MF_STRING,IDM_EXPAND_HORIZ,"Expand horizontal\tF3");
	m_pMenuPopup->AppendMenu(MF_STRING,IDM_SHRINK_VERT,"Shrink vertical\tF4");
	m_pMenuPopup->AppendMenu(MF_STRING,IDM_SHRINK_HORIZ,"Shrink horizontal\tF5");
	m_pMenuPopup->AppendMenu(MF_SEPARATOR);
	m_pMenuPopup->AppendMenu(MF_STRING,IDM_BACKUP,"Back up\tESC");
	m_pMenuPopup->AppendMenu(MF_STRING,IDM_SCALE_AUTO,"Auto scale\tAlt+A");

	SetMenu(m_pMenuMain);
	m_pMenuMain->Detach();

	GetClientRect(&m_rect);
	m_rect.NormalizeRect();
	m_pDC = GetDC();
	return 0;
}

void CPlot::OnLButtonDown( UINT nFlags, CPoint point )
{
	CFrameWnd::OnLButtonDown(nFlags, point);
	if (!IsIconic()) {
		// CClientDC dc(this);
		if (m_pDC->GetPixel(m_selectRect.left,m_selectRect.top) != RGB(255,255,255))
			InvertRect(m_pDC,&m_selectRect);
		m_selectRect.left = m_selectRect.right = point.x;
		m_selectRect.top  = m_selectRect.bottom = point.y;
		SetCapture(); 
	}
}

void CPlot::OnLButtonUp( UINT nFlags, CPoint point )
{
	CFrameWnd::OnLButtonUp(nFlags, point);
	if (GetCapture()==this) {
		m_selectRect.right  = point.x;
		m_selectRect.bottom = point.y;
		m_selectRect.NormalizeRect();

		double ptsOnScreen = ((RIGHTMARGIN-LEFTMARGIN)*m_rect.Width())/m_xScale;
		m_leftSelIDX = m_origLeftIDX + 
			(long)(ptsOnScreen*((double)m_selectRect.left - LEFTMARGIN*m_rect.Width())/
			((RIGHTMARGIN-LEFTMARGIN)*m_rect.Width()));
		m_rightSelIDX = m_leftSelIDX + (long)(ptsOnScreen*(double)m_selectRect.Width()/
			((RIGHTMARGIN-LEFTMARGIN)*m_rect.Width()));
		if (m_leftSelIDX < m_origLeftIDX) m_leftSelIDX = m_origLeftIDX;
		if (m_rightSelIDX > m_rightIDX) m_rightSelIDX = m_rightIDX;

		ReleaseCapture();
	}
}

void CPlot::OnMouseMove( UINT nFlags, CPoint point )
{
	CFrameWnd::OnMouseMove(nFlags, point);
	if (GetCapture()==this) {
		// CClientDC dc(this);
		if (m_bSelectionExists) InvertRect(m_pDC,&m_selectRect);
		m_selectRect.right = point.x;
		m_selectRect.bottom = point.y;
		InvertRect(m_pDC,&m_selectRect);
		m_bSelectionExists = TRUE;
	}
}

void CPlot::OnPaint ()
{
	CFrameWnd::OnPaint();
	if (IsWindowVisible()) {
		CClientDC dc (this);
		if (!((CList<double,double&> *)m_yHistories[0])->IsEmpty()) Redraw(&dc);
		else Clear(&dc);
	} 
}

void CPlot::OnHScroll (UINT nCode, UINT nPos, CScrollBar* pScrollBar)
{
	int nDelta;
	int nMaxPos = (int)(m_thisPageX - (double)m_plotRect.Width()/m_xScale);
	switch (nCode) {
	case SB_LINELEFT:
		if (m_nScrollPos <= 0)
			return;
		nDelta = -(min(1,m_nScrollPos));
		break;
	case SB_PAGELEFT:
		if (m_nScrollPos <= 0)
			return;
		nDelta = -(min(m_nPageSize,m_nScrollPos));
		break;
	case SB_THUMBPOSITION:
		nDelta = (int) nPos - m_nScrollPos;
		break;
	case SB_PAGERIGHT:
		if (m_nScrollPos >= nMaxPos)
			return;
		nDelta = min(m_nPageSize,nMaxPos - m_nScrollPos);
		break;
	case SB_LINERIGHT:
		if (m_nScrollPos >= nMaxPos)
			return;
		nDelta = min(1,nMaxPos - m_nScrollPos);
		break;
	default:
		return;
	}
	m_nScrollPos += nDelta;
	SetScrollPos (SB_HORZ, m_nScrollPos, TRUE);
	ScrollWindow(-nDelta,0,NULL,&m_plotRect);
}

void CPlot::OnPopup(UINT nID)
{
	// CClientDC dc(this);
	double magFactor=1.0;
	switch (nID) {
	case IDM_ZOOMIN:
		m_pScaleHistory->AddTail(CZoom(m_leftIDX,m_rightIDX,m_xScale,m_yScale,m_selectRect,m_yBaseline));
		m_yBaseline = (long)((TOPMARGIN*m_rect.bottom) + (double)m_plotRect.Height()*((double)m_yBaseline - 
			m_selectRect.top)/m_selectRect.Height());
		m_origLeftIDX = m_leftIDX;
		m_origRightIDX = m_rightIDX;
		m_leftIDX = m_leftSelIDX;
		m_rightIDX = m_rightSelIDX;
		m_xTickScale = (m_xTickScale/((double)m_plotRect.Width()/(m_rightIDX - m_leftIDX)));
		m_xScale = (double)m_plotRect.Width()/(m_rightIDX - m_leftIDX);
		m_yScale = m_yScale*(double)m_plotRect.Height()/m_selectRect.Height();
		Redraw(m_pDC);
		break;
	case IDM_EXPAND_VERT:
		m_pScaleHistory->AddTail(CZoom(m_leftIDX,m_rightIDX,m_xScale,m_yScale,m_selectRect,m_yBaseline));
		magFactor = (double)m_rect.Height()/(double)m_selectRect.Height();
		m_yScale = m_yScale * magFactor;
		Redraw(m_pDC);
		break;
	case IDM_EXPAND_HORIZ:
		m_pScaleHistory->AddTail(CZoom(m_leftIDX,m_rightIDX,m_xScale,m_yScale,m_selectRect,m_yBaseline));
		magFactor = (double)m_rect.Width()/(double)m_selectRect.Width();
		m_xScale = m_xScale * magFactor;
		Redraw(m_pDC);
		break;
	case IDM_SHRINK_VERT:
		m_pScaleHistory->AddTail(CZoom(m_leftIDX,m_rightIDX,m_xScale,m_yScale,m_selectRect,m_yBaseline));
		magFactor = (double)m_rect.Height()/(double)m_selectRect.Height();
		m_yScale = m_yScale / magFactor;
		Redraw(m_pDC);
		break;
	case IDM_SHRINK_HORIZ:
		m_pScaleHistory->AddTail(CZoom(m_leftIDX,m_rightIDX,m_xScale,m_yScale,m_selectRect,m_yBaseline));
		magFactor = (double)m_rect.Width()/(double)m_selectRect.Width();
		m_xScale = m_xScale / magFactor;
		Redraw(m_pDC);
		break;
	case IDM_BACKUP:
		if (!m_pScaleHistory->IsEmpty()) {
			m_xTickScale = m_xTickScale / (m_pScaleHistory->GetTail().xScale/((double)m_plotRect.Width()/(m_rightIDX - m_leftIDX)));
			m_xScale      = m_pScaleHistory->GetTail().xScale;
			m_yScale      = m_pScaleHistory->GetTail().yScale;
			m_leftIDX     = m_pScaleHistory->GetTail().leftIDX;
			m_rightIDX    = m_pScaleHistory->GetTail().rightIDX;
			m_selectRect  = m_pScaleHistory->GetTail().selectRect;
			m_yBaseline   = (long)m_pScaleHistory->GetTail().yBaseline;
			m_pScaleHistory->RemoveTail();
			Redraw(m_pDC);
			InvertRect(m_pDC,&m_selectRect);
			m_bInvertOldSel = TRUE;
		} 
		else {
			if (m_bInvertOldSel) {
				// CClientDC dc(this);
				InvertRect(m_pDC,&m_selectRect);
				m_bInvertOldSel = FALSE;
				m_bSelectionExists = FALSE;
			}
		}
		break;
	case IDM_SCALE_AUTO:
		m_xScale    = 0.80*(RIGHTMARGIN-LEFTMARGIN)*m_rect.Width()/(m_origRightIDX - m_origLeftIDX);
		m_yScale    = 0.80*(BOTMARGIN-TOPMARGIN)*m_rect.Height()/(m_localYMax - m_localYMin);
		m_leftIDX   = m_origLeftIDX;
		m_rightIDX  = m_origRightIDX;
		m_yBaseline = (long)(TOPMARGIN*m_rect.bottom + (double)m_plotRect.Height()/2);
		m_pScaleHistory->RemoveAll();
		Redraw(m_pDC);
		break;
	}
	if (m_pScaleHistory->IsEmpty() && m_bSelectionExists)
		InvertRect(m_pDC,&m_selectRect);
	else if (!m_pScaleHistory->IsEmpty()) {
		m_bSelectionExists = FALSE;
	}
}

void CPlot::OnRButtonDown( UINT nFlags, CPoint point )
{
	CFrameWnd::OnRButtonDown( nFlags, point );
	if (!IsIconic()) {
		ClientToScreen(&point);
		m_pMenuPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, point.x, point.y, this);
	}
}

void CPlot::OnSize( UINT nType, int cx, int cy )
{
	CFrameWnd::OnSize(nType, cx, cy);

	if (!IsIconic()) {
		// Send a message to the owner
		// WPARAM wParam;
		// wParam = WM_CPLOT_SIZE;
		//::SendMessage(m_pOwnerWnd->m_hWnd,WM_NOTIFY,wParam,(LPARAM)&m_xScale);

		// Update scaling variables and redraw
		if (!IsWindowVisible()) {
			m_oldXScale = m_xScale;
			m_oldYScale = m_yScale;
			m_xScale = m_xScale * (double)cx/m_rect.Width();
			m_yScale = m_yScale * (double)cy/m_rect.Height();
		}
		else {
			m_xScale = m_xScale * (double)cx/m_rect.Width();
			m_yScale = m_yScale * (double)cy/m_rect.Height();
			m_oldXScale = m_xScale;
			m_oldYScale = m_yScale;
		}
		GetClientRect(&m_rect);
		m_rect.NormalizeRect();
		m_plotRect = CRect(
			(long)((LEFTMARGIN + YTICKLEN) * m_rect.Width()),
			(long)( TOPMARGIN * m_rect.bottom + 1),
			(long)( RIGHTMARGIN * m_rect.right - 1),
			(long)((BOTMARGIN - XTICKLEN) * m_rect.Height() - 5)
		);
		m_yBaseline = (long)((BOTMARGIN-TOPMARGIN)*((double)m_rect.Height())/2 + TOPMARGIN*m_rect.bottom);
		m_leftMargin = (long)(LEFTMARGIN * m_rect.Width());
		m_rightMargin = (long)(RIGHTMARGIN * m_rect.Width());
		m_topMargin = (long)(TOPMARGIN * m_rect.Height());
		m_botMargin = (long)(BOTMARGIN * m_rect.Height());
		m_lastDeviceX = m_leftMargin;
		m_thisDeviceX = m_leftMargin + m_xScale;
		for (int i=0; i<_CPLOT_MAXTRACES; i++) {
			m_lastDeviceY[i] = m_yBaseline;
		}
		// CClientDC dc(this);
		Clear(m_pDC);
		if (m_numTraces > 0)
			if (((CList<double,double&> *)m_yHistories[0])->GetCount() >= 1) Redraw(m_pDC); 
	}
}

void CPlot::Redraw(CDC *pDC)
{
	int i=0, LastPtOut = 0;
	double x=0, y=0;
	Clear(m_pDC);
	POSITION pos;
	for (int k=0; k<m_numTraces; k++) {
		pos = ((CList<double,double&> *)m_yHistories[k])->FindIndex(m_leftIDX);
		x = m_leftMargin;
		y = m_yBaseline - ((((CList<double,double&> *)m_yHistories[k])->GetAt(pos)) * m_yScale);
		if (y > m_botMargin-1) y = m_botMargin-1;
		if (y < m_topMargin+1) y = m_topMargin+1;
		m_pDC->MoveTo((long)x,(long)y);
		for (i = m_leftIDX + 1; i < m_rightIDX; i++) {
			y = m_yBaseline - ((((CList<double,double&> *)m_yHistories[k])->GetNext(pos)) * m_yScale);
			if (y > m_botMargin - 1) {
				m_pDC->LineTo((long)(x += m_xScale),(long)(m_botMargin - 1));
				m_pDC->SelectStockObject(NULL_PEN);
				LastPtOut = 1;
			}
			else if (y < m_topMargin + 1) {
				m_pDC->LineTo((long)(x += m_xScale),(long)(m_topMargin + 1));
				m_pDC->SelectStockObject(NULL_PEN);
				LastPtOut = -1;
			}
			else {
				if (LastPtOut == 1) {
					m_pDC->MoveTo((long)x,(long)(m_botMargin - 1));
				}
				else if (LastPtOut == -1) {
					m_pDC->MoveTo((long)x,(long)(m_topMargin + 1));
				}
				m_pDC->SelectObject(m_pPenArray[m_tracePens[k]]);
				m_pDC->LineTo((long)(x += m_xScale),(long)y);
				LastPtOut = 0;
			}
		}
		m_lastPageX = m_thisPageX = x;
		m_lastDeviceY[k] = m_thisDeviceY = y;
		m_thisDeviceX = x;
	}
}


void CPlot::Reset()
{
	int i=0;

	// CClientDC dc(this);
	Clear(m_pDC);
	for (i=0; i<m_numTraces; i++) {
		((CList<double,double&> *)m_yHistories[i])->RemoveAll();
	}
	m_bInvertOldSel = FALSE;
	m_bSelectionExists = FALSE;
	m_lastDeviceX = m_leftMargin;
	m_leftIDX = 0;
	m_leftSelIDX = 0;
	m_localYMax = 10e-300;
	m_localYMin = 10e+300;
	m_nPageSize = 0;
	m_nScrollPos = 0;
	m_numScreens = 1;
	m_oldXScale = XSCALE;
	m_oldYScale = YSCALE;
	m_origLeftIDX = 0;
	m_origRightIDX = 0;
	m_rightIDX = 0;
	m_rightSelIDX = 0;
	m_selectRect = CRect(0,0,0,0);
	m_thisDeviceX = m_lastDeviceX + m_xScale;
	m_thisDeviceY = 0;
	m_xScale = XSCALE;
	m_yBaseline = (long)((BOTMARGIN-TOPMARGIN)*((double)m_rect.Height())/2 + TOPMARGIN*m_rect.bottom);
	for (i=0; i<m_numTraces; i++) {
		m_lastDeviceY[i] = m_yBaseline;
	}
	m_yScale = YSCALE;
}