You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
10 KiB
C++
526 lines
10 KiB
C++
// XTPChartControl.cpp
|
|
//
|
|
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Common/XTPImageManager.h"
|
|
#include "Common/XTPToolTipContext.h"
|
|
|
|
#include "Types/XTPChartTypes.h"
|
|
|
|
#include "XTPChartElement.h"
|
|
#include <Chart/XTPChartLegendItem.h>
|
|
#include "XTPChartElementView.h"
|
|
#include "XTPChartSeriesPoint.h"
|
|
#include "XTPChartControl.h"
|
|
#include "XTPChartContent.h"
|
|
#include "XTPChartContentView.h"
|
|
#include "XTPChartDiagramView.h"
|
|
#include "Drawing/XTPChartDeviceContext.h"
|
|
#include "Drawing/XTPChartDeviceCommand.h"
|
|
#include "Drawing/XTPChartDrawThread.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CXTPChartControl
|
|
|
|
const TCHAR XTPCHART_CLASSNAME[] = _T("XTPChartControl");
|
|
|
|
CXTPChartControl::CXTPChartControl()
|
|
{
|
|
m_pCommand = NULL;
|
|
|
|
VERIFY(RegisterWindowClass());
|
|
|
|
m_pContent = new CXTPChartContent();
|
|
m_pContent->AddContainer(this);
|
|
|
|
m_pDrawThread = NULL;
|
|
|
|
m_bUpdateWindow = FALSE;
|
|
|
|
m_pContentView = NULL;
|
|
|
|
m_dwUpdateOptions = 0;
|
|
|
|
m_pCaptureView = NULL;
|
|
|
|
m_pToolTipContext = NULL;
|
|
}
|
|
|
|
CXTPChartControl::~CXTPChartControl()
|
|
{
|
|
SAFE_RELEASE(m_pContentView);
|
|
|
|
// End the monitoring thread.
|
|
if (m_pDrawThread)
|
|
{
|
|
m_pDrawThread->StopNotifications();
|
|
m_pDrawThread = NULL;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pCommand);
|
|
|
|
CMDTARGET_RELEASE(m_pToolTipContext);
|
|
|
|
SetContent(NULL);
|
|
}
|
|
|
|
void CXTPChartControl::PreSubclassWindow()
|
|
{
|
|
CWnd::PreSubclassWindow();
|
|
}
|
|
|
|
void CXTPChartControl::SetContent(CXTPChartContent* pContent)
|
|
{
|
|
if (m_pContent == pContent)
|
|
return;
|
|
|
|
if (m_pContent)
|
|
{
|
|
m_pContent->RemoveContainer(this);
|
|
SAFE_RELEASE(m_pContent);
|
|
}
|
|
|
|
if (pContent)
|
|
{
|
|
m_pContent = pContent;
|
|
m_pContent->AddContainer(this);
|
|
pContent->InternalAddRef();
|
|
}
|
|
|
|
OnChartChanged();
|
|
}
|
|
|
|
BOOL CXTPChartControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
|
|
{
|
|
WNDCLASS wndcls;
|
|
ZeroMemory(&wndcls, sizeof(wndcls));
|
|
|
|
wndcls.style = CS_DBLCLKS;
|
|
wndcls.lpfnWndProc = ::DefWindowProc;
|
|
wndcls.hInstance = hInstance ? hInstance : AfxGetInstanceHandle();
|
|
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
|
|
wndcls.lpszClassName = XTPCHART_CLASSNAME;
|
|
wndcls.hIcon = 0;
|
|
wndcls.hbrBackground = 0;
|
|
|
|
return AfxRegisterClass(&wndcls);
|
|
}
|
|
|
|
void CXTPChartControl::EnableToolTips(BOOL bEnable /* = TRUE */)
|
|
{
|
|
CMDTARGET_RELEASE(m_pToolTipContext);
|
|
|
|
if (bEnable)
|
|
{
|
|
m_pToolTipContext = new CXTPToolTipContext();
|
|
}
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CXTPChartControl, CWnd)
|
|
ON_WM_PAINT()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_KEYDOWN()
|
|
ON_WM_SIZE()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONDBLCLK()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_RBUTTONUP()
|
|
ON_WM_CAPTURECHANGED()
|
|
ON_WM_MOUSEWHEEL()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_KILLFOCUS()
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
BOOL CXTPChartControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
|
|
{
|
|
return CWnd::Create(XTPCHART_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, NULL);
|
|
}
|
|
|
|
|
|
void CXTPChartControl::Draw(CDC *pPaintDC, CRect rc)
|
|
{
|
|
CXTPChartDeviceContext* pDC = m_pContent->CreateDeviceContext(this, pPaintDC->GetSafeHdc(), rc, FALSE);
|
|
|
|
if (pDC)
|
|
{
|
|
if (!m_pCommand)
|
|
{
|
|
if (m_pContentView == 0 || ((m_dwUpdateOptions & xtpChartUpdateView) && m_pCaptureView == NULL))
|
|
{
|
|
if (m_pCaptureView)
|
|
{
|
|
m_pCaptureView = NULL;
|
|
ReleaseCapture();
|
|
}
|
|
SAFE_RELEASE(m_pContentView);
|
|
m_pContentView = m_pContent->CreateView(pDC, rc);
|
|
}
|
|
else if (m_dwUpdateOptions & xtpChartUpdateLayout)
|
|
{
|
|
m_pContentView->CalculateView(pDC, rc);
|
|
}
|
|
|
|
|
|
CXTPChartDeviceCommand* pCommand = NULL;
|
|
|
|
if (m_pContentView)
|
|
{
|
|
pCommand = m_pContentView->CreateDeviceCommand(pDC);
|
|
}
|
|
|
|
m_pCommand = new CXTPChartDrawThreadDeviceCommand(pCommand);
|
|
}
|
|
|
|
pDC->Execute(m_pCommand);
|
|
|
|
delete pDC;
|
|
}
|
|
}
|
|
|
|
void CXTPChartControl::OnPaint()
|
|
{
|
|
CPaintDC dc(this);
|
|
|
|
CRect rc;
|
|
GetClientRect(rc);
|
|
|
|
#if 0
|
|
_int64 nPerfomanceEnd;
|
|
_int64 nPerfomanceStart;
|
|
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&nPerfomanceStart);
|
|
#endif
|
|
|
|
if (m_bmpCache.GetSafeHandle() == 0)
|
|
{
|
|
|
|
CDC memDC;
|
|
memDC.CreateCompatibleDC(&dc);
|
|
|
|
m_bmpCache.DeleteObject();
|
|
m_bmpCache.Attach(CXTPImageManager::Create32BPPDIBSection(0, rc.Width(), rc.Height(), 0));
|
|
|
|
CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
|
|
|
|
Draw(&memDC, rc);
|
|
|
|
dc.BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
|
|
memDC.SelectObject(pOldBitmap);
|
|
|
|
}
|
|
else
|
|
{
|
|
CDC memDC;
|
|
memDC.CreateCompatibleDC(&dc);
|
|
|
|
CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
|
|
|
|
dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
|
|
memDC.SelectObject(pOldBitmap);
|
|
}
|
|
|
|
m_dwUpdateOptions = 0;
|
|
|
|
|
|
#if 0
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&nPerfomanceEnd);
|
|
TRACE(_T("CXTPChartControl::OnPaint: %i \n"), int(nPerfomanceEnd - nPerfomanceStart));
|
|
#endif
|
|
}
|
|
|
|
BOOL CXTPChartControl::OnEraseBkgnd(CDC* /*pDC*/)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPChartControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
}
|
|
|
|
void CXTPChartControl::OnChartChanged(XTPChartUpdateOptions updateOptions)
|
|
{
|
|
m_bmpCache.DeleteObject();
|
|
|
|
SAFE_RELEASE(m_pCommand);
|
|
|
|
m_dwUpdateOptions |= updateOptions;
|
|
|
|
if ((updateOptions & xtpChartUpdateView) && (m_pCaptureView == NULL))
|
|
{
|
|
SAFE_RELEASE(m_pContentView);
|
|
}
|
|
|
|
if (::IsWindow(m_hWnd))
|
|
{
|
|
Invalidate(FALSE);
|
|
|
|
if (m_bUpdateWindow)
|
|
{
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CXTPChartControl::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy);
|
|
|
|
OnChartChanged(xtpChartUpdateLayout);
|
|
}
|
|
|
|
CXTPChartElement* CXTPChartControl::HitTest(CPoint point) const
|
|
{
|
|
if (!m_pCommand)
|
|
return m_pContent;
|
|
|
|
return m_pCommand->HitTest(point, m_pContent);
|
|
}
|
|
|
|
BOOL CXTPChartControl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
|
|
{
|
|
if (m_pContentView)
|
|
{
|
|
ScreenToClient(&pt);
|
|
|
|
CXTPChartDiagramView* pDiagramView = m_pContentView->HitTestDiagramView(pt);
|
|
|
|
if (pDiagramView)
|
|
{
|
|
pDiagramView->OnMouseWheel(nFlags, zDelta, pt);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPChartControl::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnMouseMove(nFlags, point);
|
|
|
|
if (m_pCaptureView)
|
|
{
|
|
m_pCaptureView->OnMouseMove(nFlags, point);
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CXTPChartControl::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnRButtonDown(nFlags, point);
|
|
|
|
}
|
|
|
|
void CXTPChartControl::OnRButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnRButtonUp(nFlags, point);
|
|
|
|
|
|
}
|
|
|
|
BOOL CXTPChartControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
CPoint point;
|
|
GetCursorPos(&point);
|
|
ScreenToClient(&point);
|
|
|
|
|
|
if (m_pCaptureView)
|
|
{
|
|
if (m_pCaptureView->OnSetCursor(point))
|
|
return TRUE;
|
|
}
|
|
else if (m_pContentView)
|
|
{
|
|
CXTPChartDiagramView* pDiagramView = m_pContentView->HitTestDiagramView(point);
|
|
|
|
if (pDiagramView)
|
|
{
|
|
if (pDiagramView->OnSetCursor(point))
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return CWnd::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
|
|
void CXTPChartControl::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonUp(nFlags, point);
|
|
|
|
if (m_pCaptureView)
|
|
{
|
|
m_pCaptureView = NULL;
|
|
ReleaseCapture();
|
|
}
|
|
|
|
}
|
|
void CXTPChartControl::OnCaptureChanged(CWnd* pWnd)
|
|
{
|
|
CWnd::OnCaptureChanged(pWnd);
|
|
|
|
m_pCaptureView = NULL;
|
|
}
|
|
|
|
void CXTPChartControl::OnLButtonDblClk(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonDblClk(nFlags, point);
|
|
|
|
}
|
|
|
|
void CXTPChartControl::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonDown(nFlags, point);
|
|
|
|
SetFocus();
|
|
|
|
NMHDR mHDR;
|
|
mHDR.hwndFrom = m_hWnd;
|
|
mHDR.code = NM_CLICK;
|
|
mHDR.idFrom = GetDlgCtrlID();
|
|
|
|
GetOwner()->SendMessage(WM_NOTIFY, (WPARAM)mHDR.idFrom, (LPARAM)&mHDR);
|
|
|
|
|
|
if (m_pContentView)
|
|
{
|
|
CXTPChartDiagramView* pDiagramView = m_pContentView->HitTestDiagramView(point);
|
|
|
|
if (pDiagramView)
|
|
{
|
|
pDiagramView->OnLButtonDown(nFlags, point);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void CXTPChartControl::SetCapture(CXTPChartElementView* pView)
|
|
{
|
|
m_pCaptureView = pView;
|
|
|
|
CWnd::SetCapture();
|
|
}
|
|
|
|
void CXTPChartControl::PrintToDC(HDC hDC, CRect rcBounds)
|
|
{
|
|
CXTPChartDeviceContext* pDC = m_pContent->CreateDeviceContext(this, hDC, rcBounds, FALSE);
|
|
|
|
if (pDC)
|
|
{
|
|
m_pContent->DrawContent(pDC, rcBounds);
|
|
delete pDC;
|
|
}
|
|
}
|
|
|
|
void CXTPChartControl::SaveAsImage(LPCTSTR lpszFilePath, CSize szBounds)
|
|
{
|
|
CBitmap bmp;
|
|
bmp.Attach(CXTPImageManager::Create32BPPDIBSection(0, szBounds.cx, szBounds.cy, 0));
|
|
|
|
{
|
|
CDC dc;
|
|
dc.CreateCompatibleDC(NULL);
|
|
|
|
CBitmap* pOldBitmap = dc.SelectObject(&bmp);
|
|
|
|
CRect rc(0, 0, szBounds.cx, szBounds.cy);
|
|
CXTPChartDeviceContext* pDC = m_pContent->CreateDeviceContext(this, dc, rc, FALSE);
|
|
|
|
if (pDC)
|
|
{
|
|
m_pContent->DrawContent(pDC, rc);
|
|
|
|
delete pDC;
|
|
}
|
|
|
|
dc.SelectObject(pOldBitmap);
|
|
}
|
|
|
|
CXTPChartDeviceContext::SaveToFile((HBITMAP)bmp.GetSafeHandle(), lpszFilePath);
|
|
}
|
|
|
|
BOOL CXTPChartControl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
if (m_pToolTipContext)
|
|
{
|
|
m_pToolTipContext->FilterToolTipMessage(this, message, wParam, lParam);
|
|
}
|
|
|
|
return CWnd::OnWndMsg(message, wParam, lParam, pResult);
|
|
}
|
|
|
|
INT_PTR CXTPChartControl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
|
|
{
|
|
|
|
ASSERT_VALID(this);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
// check child windows first by calling CControlBar
|
|
INT_PTR nHit = CWnd::OnToolHitTest(point, pTI);
|
|
if (nHit != -1)
|
|
return nHit;
|
|
|
|
|
|
CXTPChartSeriesPoint* pSeriesPoint = DYNAMIC_DOWNCAST(CXTPChartSeriesPoint, HitTest(point));
|
|
|
|
if (pSeriesPoint)
|
|
{
|
|
nHit = (INT_PTR)pSeriesPoint;
|
|
|
|
CString strTip = pSeriesPoint->GetTooltipText();
|
|
if (strTip.GetLength() == 0)
|
|
return -1;
|
|
|
|
CRect rc;
|
|
GetClientRect(rc);
|
|
|
|
CXTPToolTipContext::FillInToolInfo(pTI, m_hWnd, rc, nHit, strTip);
|
|
|
|
return nHit;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
void CXTPChartControl::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
CWnd::OnSetFocus(pOldWnd);
|
|
|
|
}
|
|
|
|
void CXTPChartControl::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
CWnd::OnKillFocus(pNewWnd);
|
|
|
|
}
|