DashedView.cpp
上传用户:whjcdz88
上传日期:2011-09-07
资源大小:121k
文件大小:12k
- // DashedView.cpp : implementation of the CDashedView class
- //
- #include "stdafx.h"
- #include "Dashed.h"
- #include "DashedDoc.h"
- #include "DashedView.h"
- #include "Line.h"
- #include "bezier.h"
- #include <MAPIDBG.h>
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- // timing functions
- #ifdef _DEBUG
- #define LGStartTiming(LGTime)
- LGTime = GetTickCount();
- GdiFlush();
- #define LGNoteTime(description, LGTime)
- GdiFlush();
- LGTime = GetTickCount() -LGTime;
- {CString OutputStr;
- DebugTraceLine();
- OutputStr.Format("%s(%i) : %s %drn", __FILE__,__LINE__, description , LGTime);
- TRACE0((LPCTSTR)OutputStr);}
- #else
- #define LGStartTiming(LGTime)
- #define LGNoteTime(description, LGTime)
- #endif
- /////////////////////////////////////////////////////////////////////////////
- // CDashedView
- IMPLEMENT_DYNCREATE(CDashedView, CView)
- BEGIN_MESSAGE_MAP(CDashedView, CView)
- //{{AFX_MSG_MAP(CDashedView)
- ON_WM_TIMER()
- ON_WM_KEYDOWN()
- ON_WM_ERASEBKGND()
- ON_WM_DESTROY()
- ON_WM_CREATE()
- ON_COMMAND(ID_INCREASEWIDTH, OnIncreasewidth)
- ON_COMMAND(ID_DECREASEWIDTH, OnDecreasewidth)
- ON_COMMAND(ID_ROTATE, OnRotate)
- ON_UPDATE_COMMAND_UI(ID_ROTATE, OnUpdateRotate)
- ON_COMMAND(ID_ROUND, OnRound)
- ON_UPDATE_COMMAND_UI(ID_ROUND, OnUpdateRound)
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CDashedView construction/destruction
- CDashedView::CDashedView()
- {
- m_PenSize = 5;
- m_Radians = 0.5;
- m_Rotate = true;
- m_Round = false;
- }
- CDashedView::~CDashedView()
- {
- }
- BOOL CDashedView::PreCreateWindow(CREATESTRUCT& cs)
- {
- return CView::PreCreateWindow(cs);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CDashedView drawing
- void CDashedView::DrawPathOutline(const COLORREF& c, CDC& dc)
- {
- // make pen and stroke path
- LOGBRUSH lbrush;
- lbrush.lbStyle = BS_SOLID;
- lbrush.lbColor = c;
- CPen Pen(PS_GEOMETRIC | PS_SOLID |
- (m_Round ?
- (PS_JOIN_ROUND | PS_ENDCAP_ROUND):
- (PS_JOIN_MITER | PS_ENDCAP_FLAT) ) , m_PenSize, &lbrush);
- CPen *pOldPen = dc.SelectObject(&Pen);
- dc.StrokePath();
- dc.SelectObject(pOldPen);
- }
- void CDashedView::OnDraw(CDC* pClientDC)
- {
- #ifdef _DEBUG
- DWORD time;
- #endif
-
- CRect rect; GetClientRect(&rect);
-
- // Prepare memory DC to avoid flicker
- CDC memDC;
- CDC* pDC = &memDC;
- pDC->CreateCompatibleDC(pClientDC);
- CBitmap bmp;
- CRect clientRect(rect);
- bmp.CreateCompatibleBitmap(pClientDC, rect.Width(), rect.Height());
- CBitmap* pOldBmp = pDC->SelectObject(&bmp);
- pDC->FillSolidRect(&rect, PALETTERGB(255,255,255));
-
- // various line patterns
- unsigned Type1[8];
- unsigned Type2[8];
- unsigned Type3[8];
- unsigned Type4[8];
- int c1 = CDashLine::GetPattern(Type1, m_Round, m_PenSize, CDashLine::DL_DASHDOTDOT);
- int c2 = CDashLine::GetPattern(Type2, m_Round, m_PenSize, CDashLine::DL_DASHDOT);
- int c3 = CDashLine::GetPattern(Type3, m_Round, m_PenSize, CDashLine::DL_DASH);
- int c4 = CDashLine::GetPattern(Type4, m_Round, m_PenSize, CDashLine::DL_DOT);
- // save the current pen before using DashLine
- CPen *pOldPen = pDC->GetCurrentPen();
- LOGBRUSH lbrush;
- lbrush.lbStyle = BS_SOLID;
- CDashLine Line(*pDC, Type1, c1);
- RecreateEllipse();
- UpdateEllipseRgn(pDC);
-
- // Draw gradient ellipse interior
- {
- pDC->SelectClipRgn(&m_EllipseFillRgn);
- VerticalGradientFill(m_EllipseRect, *pDC);
- pDC->SelectClipRgn(0);
- }
-
- // Draw dotted ellipse border
- Line.SetPattern(Type1, c1);
- {
- LGStartTiming(time);
- // do drawing inside path for win95/8 compatibility
- pDC->BeginPath();
- Line.MoveTo(m_EllipsePts[0]);
- for (int i = 1; i < 12; i+=3)
- Line.BezierTo(m_EllipsePts+i);
- pDC->EndPath();
- LGNoteTime("Ellipse border calculate", time);
- // make pen and stroke path
- LGStartTiming(time);
- DrawPathOutline(PALETTERGB(128,255,128), *pDC);
- LGNoteTime("Ellipse border draw", time);
- }
- // Setup Dash dot dot line
- Line.SetPattern(Type1, c1);
- {
- // do drawing inside path for win95/8 compatibility
- pDC->BeginPath();
- Line.MoveTo(rect.TopLeft());
- Line.LineTo(rect.BottomRight());
- pDC->EndPath();
- // make pen and stroke path
- DrawPathOutline(PALETTERGB(0,0,255), *pDC);
- }
- //Setup Dash dot line
- Line.SetPattern(Type2, c2);
- {
- // do drawing inside path for win95/8 compatibility
- pDC->BeginPath();
- Line.MoveTo(rect.left, rect.bottom);
- Line.LineTo(rect.right, rect.top);
- pDC->EndPath();
- // make pen and stroke path
- DrawPathOutline(PALETTERGB(255,0,255), *pDC);
- }
- //Setup Dash line
- Line.SetPattern(Type3, c3);
- {
- // do drawing inside path for win95/8 compatibility
- pDC->BeginPath();
- Line.MoveTo(rect.left, rect.Height() / 2);
- Line.LineTo(rect.right, rect.Height() / 2);
- pDC->EndPath();
- // make pen and stroke path
- DrawPathOutline(PALETTERGB(0,0,0), *pDC);
- }
- rect.DeflateRect(m_PenSize, m_PenSize);
- // Draw background to rectangle to simulate SetBkMode(OPAQUE) SetBkColor(xxx)
- {
- // do drawing inside path for win95/8 compatibility
- pDC->BeginPath();
- pDC->MoveTo(rect.left, rect.bottom);
- pDC->LineTo(rect.BottomRight());
- pDC->LineTo(rect.right, rect.top);
- pDC->LineTo(rect.TopLeft());
- pDC->LineTo(rect.left, rect.bottom);
- pDC->EndPath();
- // make pen and stroke path
- DrawPathOutline(PALETTERGB(0,255,255), *pDC);
- }
-
- //Setup dot line and draw rectangle
- Line.SetPattern(Type4, c4);
- {
- // do drawing inside path for win95/8 compatibility
- pDC->BeginPath();
- Line.MoveTo(rect.left, rect.bottom);
- Line.LineTo(rect.BottomRight());
- Line.LineTo(rect.right, rect.top);
- Line.LineTo(rect.TopLeft());
- Line.LineTo(rect.left, rect.bottom);
- pDC->EndPath();
- // make pen and stroke path
- DrawPathOutline(PALETTERGB(255,0,0), *pDC);
- }
-
- // bit from memdc to paintdc
- pClientDC->BitBlt(clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(), pDC, 0, 0, SRCCOPY);
- pDC->SelectObject(pOldBmp);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CDashedView diagnostics
- #ifdef _DEBUG
- void CDashedView::AssertValid() const
- {
- CView::AssertValid();
- }
- void CDashedView::Dump(CDumpContext& dc) const
- {
- CView::Dump(dc);
- }
- CDashedDoc* CDashedView::GetDocument() // non-debug version is inline
- {
- ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDashedDoc)));
- return (CDashedDoc*)m_pDocument;
- }
- #endif //_DEBUG
- /////////////////////////////////////////////////////////////////////////////
- // CDashedView message handlers
- void CDashedView::OnTimer(UINT nIDEvent)
- {
- CView::OnTimer(nIDEvent);
- if (nIDEvent == 1)
- RotateEllipse();
- }
- void CDashedView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
- {
- CView::OnKeyDown(nChar, nRepCnt, nFlags);
- if (nChar == VK_DOWN)
- OnDecreasewidth();
- else if (nChar == VK_UP)
- OnIncreasewidth();
- else if (nChar == 'R')
- OnRound();
- else if (nChar == 'S')
- OnRotate();
- else if (nChar == VK_ADD)
- RotateEllipse();
- }
- BOOL CDashedView::OnEraseBkgnd(CDC* pDC)
- {
- return 1;
- }
- void CDashedView::OnDestroy()
- {
- CView::OnDestroy();
- KillTimer(1);
- }
- int CDashedView::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- if (CView::OnCreate(lpCreateStruct) == -1)
- return -1;
-
- // Add timer to rotate ellipse
- if (m_Rotate)
- SetTimer(1,500, 0);
- return 0;
- }
- void CDashedView::OnIncreasewidth()
- {
- ++m_PenSize;
- Invalidate();
- }
- void CDashedView::OnDecreasewidth()
- {
- if (m_PenSize >1)
- {
- --m_PenSize;
- Invalidate();
- }
- }
- void CDashedView::OnRotate()
- {
- m_Rotate = !m_Rotate;
- if (!m_Rotate)
- KillTimer(1);
- else
- SetTimer(1,500, 0);
-
- }
- void CDashedView::OnUpdateRotate(CCmdUI* pCmdUI)
- {
- pCmdUI->SetCheck(m_Rotate);
- pCmdUI->Enable(true);
- }
- void CDashedView::OnRound()
- {
- m_Round = !m_Round;
- Invalidate();
-
- }
- void CDashedView::OnUpdateRound(CCmdUI* pCmdUI)
- {
- pCmdUI->SetCheck(m_Round);
- pCmdUI->Enable(true);
- }
- //***************************************************
- // RotateEllipse()
- //
- //***************************************************
- void CDashedView::RotateEllipse()
- {
- CDC* pDC = GetWindowDC( );
- InvalidateRgn(&m_EllipseRgn);
- m_Radians += 0.1;
- RecreateEllipse();
- UpdateEllipseRgn(pDC);
- InvalidateRgn(&m_EllipseRgn);
- ReleaseDC(pDC);
- }
- //***************************************************
- // UpdateEllipseRgn()
- //
- //***************************************************
- void CDashedView::UpdateEllipseRgn(CDC* pDC)
- {
- // Get fill area of ellipse
- pDC->BeginPath();
- pDC->PolyBezier(m_EllipsePts, 13);
- pDC->EndPath();
- m_EllipseFillRgn.DeleteObject();
- m_EllipseFillRgn.CreateFromPath(pDC);
-
- // Add border width area of ellipse
- pDC->BeginPath();
- pDC->PolyBezier(m_EllipsePts, 13);
- // if you do not close the figure,
- // there will be a hole at the begin/end join
- pDC->CloseFigure();
- pDC->EndPath();
-
- LOGBRUSH lbrush;
- lbrush.lbStyle = BS_SOLID;
- CPen Pen(PS_GEOMETRIC, m_PenSize+4, &lbrush);
- CPen* pOldPen = pDC->SelectObject(&Pen);
- pDC->WidenPath();
- m_EllipseRgn.DeleteObject();
- m_EllipseRgn.CreateFromPath(pDC);
- pDC->SelectObject(pOldPen);
-
- m_EllipseRgn.CombineRgn(&m_EllipseRgn, &m_EllipseFillRgn, RGN_OR);
- }
- //***************************************************
- // RecreateEllipse()
- // Rotates Cnt number of points radians around c
- //
- //***************************************************
- void CDashedView::RecreateEllipse()
- {
- CRect rect;
- GetClientRect(&rect);
- CPoint midPoint((rect.left +rect.right)/2, (rect.top + rect.bottom)/2);
- int size = min(rect.Height(), rect.Width()) * 3 / 8;
- CRect ellipseR(midPoint.x-size, midPoint.y-(size/2), midPoint.x+size, midPoint.y+(size/2));
- // Create an axis aligned ellipse dimensions = ellipseR
- EllipseToBezier(ellipseR, m_EllipsePts);
-
- // Rotate ellipse points
- RotatePoints(m_Radians, midPoint, m_EllipsePts, 13);
- // Get bounding rect of ellipse
- // Note this does NOT include the pen width
- CPoint tl = m_EllipsePts[0];
- CPoint br = tl;
- for (int i = 1; i < 13; ++i)
- {
- if(m_EllipsePts[i].x < tl.x)
- tl.x = m_EllipsePts[i].x;
- else if (m_EllipsePts[i].x > br.x)
- br.x = m_EllipsePts[i].x;
- if(m_EllipsePts[i].y < tl.y)
- tl.y = m_EllipsePts[i].y;
- else if (m_EllipsePts[i].y > br.y)
- br.y = m_EllipsePts[i].y;
- }
- m_EllipseRect = CRect(tl, br);
- }
- /////////////////////////////////////////////////////////////////////////////
- // helper functions
- //
- //
- //***************************************************
- // Rotate
- // Rotates Cnt number of points radians around c
- //
- //***************************************************
- void RotatePoints(double radians, const CPoint& c, CPoint* vCtlPt, unsigned Cnt)
- {
- double sinAng = sin(radians);
- double cosAng = cos(radians);
- LDPoint constTerm( c.x - c.x * cosAng - c.y * sinAng,
- c.y + c.x * sinAng - c.y * cosAng);
-
- for (int i = Cnt-1; i>=0; --i)
- {
- vCtlPt[i] = (LDPoint( vCtlPt[i].x * cosAng + vCtlPt[i].y * sinAng,
- -vCtlPt[i].x * sinAng + vCtlPt[i].y * cosAng) + constTerm).GetCPoint();
- }
- }
- //***************************************************
- // VerticalGradientFill
- // From Blue to red if dc is not paletted
- // Ad hoc slow code
- //***************************************************
- void VerticalGradientFill(const CRect& r, CDC& dc)
- {
- //don't draw gradient if paletted: really ugly
- if (dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
- {
- CBrush brush(HS_BDIAGONAL, RGB(255,0,0));
- dc.FillRect(&r, &brush);
- return;
- }
- // rect is a horizontal strip
- CRect rect = r;
- rect.bottom = rect.top+1;
- int nHeight = r.Height();
- for(int i = 0; i < nHeight; ++i) // Fill in strips
- {
- dc.FillSolidRect(&rect, PALETTERGB(MulDiv(i, 200, nHeight), 0, 255 -MulDiv(i, 200, nHeight)));
- rect.OffsetRect(0,1);
- }
- }