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.
1089 lines
25 KiB
C++
1089 lines
25 KiB
C++
2 years ago
|
// XTPTrackControl.cpp : implementation of the CXTPTrackControl class.
|
||
|
//
|
||
|
// This file is a part of the XTREME REPORTCONTROL 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 <math.h>
|
||
|
|
||
|
#include "Common/Resource.h"
|
||
|
#include "Common/XTPDrawHelpers.h"
|
||
|
#include "Common/XTPPropExchange.h"
|
||
|
#include "Common/XTPImageManager.h"
|
||
|
#include "Common/XTPCustomHeap.h"
|
||
|
#include "Common/XTPSystemHelpers.h"
|
||
|
#include "Common/XTPSmartPtrInternalT.h"
|
||
|
#include "Common/XTPColorManager.h"
|
||
|
|
||
|
#include "../XTPReportDefines.h"
|
||
|
#include "../XTPReportControl.h"
|
||
|
#include "../XTPReportHeader.h"
|
||
|
#include "../XTPReportColumn.h"
|
||
|
#include "../XTPReportColumns.h"
|
||
|
#include "../XTPReportRow.h"
|
||
|
#include "../XTPReportRecord.h"
|
||
|
#include "../XTPReportRecordItem.h"
|
||
|
#include "../XTPReportRows.h"
|
||
|
#include "../XTPReportSections.h"
|
||
|
#include "../XTPReportSection.h"
|
||
|
#include "../XTPReportPaintManager.h"
|
||
|
#include "../XTPReportHitTestInfo.h"
|
||
|
|
||
|
|
||
|
#include "XTPTrackBlock.h"
|
||
|
#include "XTPTrackControl.h"
|
||
|
#include "XTPTrackControlItem.h"
|
||
|
#include "XTPTrackHeader.h"
|
||
|
#include "XTPTrackPaintManager.h"
|
||
|
#include "XTPTrackUndoManager.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CXTPTrackControl,CXTPReportControl)
|
||
|
//{{AFX_MSG_MAP(CXTPTrackControl)
|
||
|
ON_WM_KEYDOWN()
|
||
|
ON_WM_LBUTTONDOWN()
|
||
|
ON_WM_GETDLGCODE()
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
|
||
|
CXTPTrackControl::CXTPTrackControl()
|
||
|
{
|
||
|
RegisterWindowClass();
|
||
|
|
||
|
m_nTimeLinePosition = 0;
|
||
|
|
||
|
m_nWorkAreaMin = 0;
|
||
|
m_nWorkAreaMax = 100;
|
||
|
|
||
|
m_nTimeLineMin = 0;
|
||
|
m_nTimeLineMax = 100;
|
||
|
|
||
|
m_nViewPortMin = 0;
|
||
|
m_nViewPortMax = 100;
|
||
|
|
||
|
m_bScaleOnResize = TRUE;
|
||
|
|
||
|
m_nSnapMargin = 5;
|
||
|
m_bSnapToBlocks = FALSE;
|
||
|
m_bSnapToMarkers = TRUE;
|
||
|
|
||
|
m_bFlexibleDrag = FALSE;
|
||
|
m_nTrackColumnIndex = -1;
|
||
|
|
||
|
m_bAllowBlockRemove = TRUE;
|
||
|
m_bAllowBlockScale = TRUE;
|
||
|
m_bAllowBlockMove = TRUE;
|
||
|
|
||
|
m_rcSelectedArea.SetRectEmpty();
|
||
|
|
||
|
m_hMoveCursor = AfxGetApp()->LoadCursor(XTP_IDC_HAND);
|
||
|
m_hResizeCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
|
||
|
|
||
|
m_strTimeFormat = _T("%d");
|
||
|
|
||
|
m_pMarkers = new CXTPTrackMarkers(this);
|
||
|
|
||
|
m_nOldTrackWidth = 0;
|
||
|
|
||
|
m_bShowWorkArea = TRUE;
|
||
|
m_bShowTimeLinePosition = TRUE;
|
||
|
|
||
|
SetPaintManager(new CXTPTrackPaintManager());
|
||
|
SetReportHeader(new CXTPTrackHeader(this, m_pColumns));
|
||
|
|
||
|
m_pUndoManager = new CXTPTrackUndoManager();
|
||
|
|
||
|
m_pSelectedBlocks = new CXTPTrackSelectedBlocks();
|
||
|
}
|
||
|
|
||
|
CXTPTrackControl::~CXTPTrackControl()
|
||
|
{
|
||
|
m_pUndoManager->InternalRelease();
|
||
|
|
||
|
m_pMarkers->InternalRelease();
|
||
|
|
||
|
m_pSelectedBlocks->InternalRelease();
|
||
|
}
|
||
|
|
||
|
BOOL CXTPTrackControl::RegisterWindowClass(HINSTANCE hInstance)
|
||
|
{
|
||
|
return XTPDrawHelpers()->RegisterWndClass(hInstance, XTPTRACKCTRL_CLASSNAME, CS_DBLCLKS);
|
||
|
}
|
||
|
|
||
|
LRESULT CXTPTrackControl::SendMessageToParent(UINT nMessage, CXTPTrackBlock* pBlock, CXTPTrackMarker* pMarker) const
|
||
|
{
|
||
|
if (!IsWindow(m_hWnd))
|
||
|
return 0;
|
||
|
|
||
|
XTP_NM_TRACKCONTROL nmgv;
|
||
|
nmgv.pBlock = pBlock;
|
||
|
nmgv.pMarker = pMarker;
|
||
|
|
||
|
return SendNotifyMessage(nMessage, (NMHDR*)&nmgv);
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::SetViewPort(int nViewPortMin, int nViewPortMax)
|
||
|
{
|
||
|
if (nViewPortMin < m_nTimeLineMin)
|
||
|
{
|
||
|
nViewPortMax = m_nTimeLineMin + nViewPortMax - nViewPortMin;
|
||
|
nViewPortMin = m_nTimeLineMin;
|
||
|
}
|
||
|
if (nViewPortMax > m_nTimeLineMax)
|
||
|
{
|
||
|
nViewPortMin = m_nTimeLineMax - (nViewPortMax - nViewPortMin);
|
||
|
nViewPortMax = m_nTimeLineMax;
|
||
|
}
|
||
|
|
||
|
m_nOldTrackWidth = 0;
|
||
|
m_nViewPortMin = nViewPortMin;
|
||
|
m_nViewPortMax = nViewPortMax;
|
||
|
|
||
|
RedrawControl();
|
||
|
|
||
|
SendMessageToParent(XTP_NM_TRACK_SLIDERCHANGED);
|
||
|
}
|
||
|
|
||
|
int CXTPTrackControl::GetTrackColumnIndex() const
|
||
|
{
|
||
|
if (m_nTrackColumnIndex != -1)
|
||
|
return m_nTrackColumnIndex;
|
||
|
|
||
|
return m_pColumns->GetCount() - 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
int CXTPTrackControl::GetTrackOffset() const
|
||
|
{
|
||
|
CXTPReportColumn* pColumn = m_pColumns->Find(GetTrackColumnIndex());
|
||
|
ASSERT(pColumn && pColumn->IsVisible());
|
||
|
|
||
|
return pColumn->GetRect().left;
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::SetTimeLinePosition(int nTimeLinePos)
|
||
|
{
|
||
|
if (m_nTimeLinePosition != nTimeLinePos)
|
||
|
{
|
||
|
m_nTimeLinePosition = nTimeLinePos; //Main Marker
|
||
|
RedrawControl();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::OnDraw(CDC* pDC)
|
||
|
{
|
||
|
AdjustTrackColumnWidth();
|
||
|
|
||
|
CXTPReportControl::OnDraw(pDC);
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::AdjustTrackColumnWidth()
|
||
|
{
|
||
|
CXTPReportColumn* pColumn = GetTrackColumn();
|
||
|
|
||
|
if (pColumn && pColumn->IsVisible())
|
||
|
{
|
||
|
int nTrackWidth = max(1, pColumn->GetWidth() - 14);
|
||
|
|
||
|
if (m_bScaleOnResize)
|
||
|
{
|
||
|
m_nOldTrackWidth = 0;
|
||
|
}
|
||
|
else if (!m_bScaleOnResize && nTrackWidth > 1)
|
||
|
{
|
||
|
if (m_nOldTrackWidth != 0 )
|
||
|
{
|
||
|
double nViewPortMax = m_nViewPortMin + nTrackWidth * m_nOldTrackViewPortRange / m_nOldTrackWidth;
|
||
|
if (nViewPortMax > m_nTimeLineMax)
|
||
|
nViewPortMax = m_nTimeLineMax;
|
||
|
|
||
|
if (fabs(m_nViewPortMax - nViewPortMax) > 1e-6)
|
||
|
{
|
||
|
m_nViewPortMax = nViewPortMax;
|
||
|
|
||
|
SendMessageToParent(XTP_NM_TRACK_SLIDERCHANGED);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_nOldTrackWidth == 0)
|
||
|
{
|
||
|
m_nOldTrackWidth = nTrackWidth;
|
||
|
m_nOldTrackViewPortRange = m_nViewPortMax - m_nViewPortMin;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int CXTPTrackControl::DrawRows(CDC* pDC, CRect& rcClient, int y, CXTPReportRows *pRows, int nTopRow, int nColumnFrom, int nColumnTo, int *pnHeight)
|
||
|
{
|
||
|
int nIndex = CXTPReportControl::DrawRows(pDC, rcClient, y, pRows, nTopRow, nColumnFrom, nColumnTo, pnHeight);
|
||
|
|
||
|
CXTPReportColumn *pColumn = GetTrackColumn();
|
||
|
if (!pColumn || !pColumn->IsVisible())
|
||
|
{
|
||
|
return nIndex;
|
||
|
}
|
||
|
|
||
|
CRect rcTrack = pColumn->GetRect();
|
||
|
|
||
|
if (m_bShowTimeLinePosition)
|
||
|
{
|
||
|
int nPos = PositionToTrack(GetTimeLinePosition());
|
||
|
|
||
|
if (nPos >= rcTrack.left && nPos <= rcTrack.right)
|
||
|
{
|
||
|
pDC->FillSolidRect(CRect(nPos, m_pSectionBody->GetRect().top, nPos + 1, m_pSectionBody->GetRect().bottom + 10), RGB(205, 0, 0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!m_rcSelectedArea.IsRectEmpty())
|
||
|
{
|
||
|
CRect rcSelectedArea = m_rcSelectedArea;
|
||
|
rcSelectedArea.top = max(rcSelectedArea.top, m_pSectionBody->GetRect().top);
|
||
|
|
||
|
COLORREF clrSelectedArea = GetTrackPaintManager()->m_clrSelectedArea;
|
||
|
|
||
|
|
||
|
LPDWORD lpBits;
|
||
|
HBITMAP hBitmap = CXTPImageManager::Create32BPPDIBSection(pDC->GetSafeHdc(), 1, 1, (LPBYTE*)&lpBits);
|
||
|
if (hBitmap)
|
||
|
{
|
||
|
CXTPCompatibleDC dc(pDC, hBitmap);
|
||
|
lpBits[0] = RGB(GetBValue(clrSelectedArea), GetGValue(clrSelectedArea), GetRValue(clrSelectedArea));
|
||
|
|
||
|
XTPImageManager()->AlphaBlend2(pDC->GetSafeHdc(), rcSelectedArea, dc, CRect(0, 0, 1, 1), 100);
|
||
|
//XTPImageManager()->DoAlphaBlend(pDC->GetSafeHdc(), rcSelectedArea, dc, CRect(0, 0, 1, 1));
|
||
|
|
||
|
|
||
|
DeleteObject(hBitmap);
|
||
|
}
|
||
|
|
||
|
pDC->Draw3dRect(rcSelectedArea, clrSelectedArea, clrSelectedArea);
|
||
|
}
|
||
|
|
||
|
return nIndex;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPTrackControl::AdjustLayout()
|
||
|
{
|
||
|
/*
|
||
|
------------------------------
|
||
|
| Group by |
|
||
|
------------------------------
|
||
|
| Time line |
|
||
|
------------------------------
|
||
|
| Header |
|
||
|
------------------------------
|
||
|
| Sections |
|
||
|
------------------------------
|
||
|
| Footer |
|
||
|
------------------------------
|
||
|
*/
|
||
|
|
||
|
if (NULL == GetSafeHwnd())
|
||
|
return;
|
||
|
|
||
|
if (m_bAdjustLayoutRunning) //guard to prevent the recursion similar to OnSize function
|
||
|
return;
|
||
|
|
||
|
m_bAdjustLayoutRunning = TRUE;
|
||
|
|
||
|
CXTPClientRect rcClient(this);
|
||
|
CWindowDC dc(this);
|
||
|
|
||
|
int nHeaderWidth = m_rcHeaderArea.Width();
|
||
|
|
||
|
CXTPReportHeader *pHeader = GetReportHeader();
|
||
|
CXTPReportColumn *pTrack = GetTrackColumn();
|
||
|
|
||
|
int nHeightGroupBy = 0;
|
||
|
int nHeightHeader = 0;
|
||
|
int nHeightFooter = 0;
|
||
|
int nHeightTimeLine = 0;
|
||
|
|
||
|
if (NULL != pHeader && m_bGroupByEnabled)
|
||
|
{
|
||
|
nHeightGroupBy = pHeader->GetGroupByHeight();
|
||
|
}
|
||
|
|
||
|
if (pTrack && pTrack->IsVisible())
|
||
|
{
|
||
|
nHeightTimeLine = 30;
|
||
|
}
|
||
|
|
||
|
if (m_bHeaderVisible)
|
||
|
{
|
||
|
nHeightHeader = GetPaintManager()->GetHeaderHeight(this, &dc);
|
||
|
}
|
||
|
|
||
|
if (m_bFooterVisible)
|
||
|
{
|
||
|
nHeightFooter = GetPaintManager()->GetFooterHeight(this, &dc);
|
||
|
}
|
||
|
|
||
|
// Group by rect
|
||
|
m_rcGroupByArea.SetRect(0, 0, rcClient.Width(), nHeightGroupBy);
|
||
|
|
||
|
// Time line
|
||
|
m_rcTimelineArea.SetRect(0, m_rcGroupByArea.bottom, rcClient.Width(), m_rcGroupByArea.bottom + nHeightTimeLine);
|
||
|
|
||
|
// Header
|
||
|
m_rcHeaderArea.SetRect(0, m_rcTimelineArea.bottom, rcClient.Width(), m_rcTimelineArea.bottom + nHeightHeader);
|
||
|
|
||
|
// Sections
|
||
|
int nHeightSections = rcClient.Height() - nHeightGroupBy - nHeightTimeLine - nHeightHeader - nHeightFooter;
|
||
|
CRect rcSections(0, m_rcHeaderArea.bottom, rcClient.Width(), m_rcHeaderArea.bottom+nHeightSections);
|
||
|
|
||
|
m_pSections->AdjustLayout(&dc, rcSections);
|
||
|
|
||
|
// Footer
|
||
|
m_rcFooterArea.SetRect(0, rcClient.Height() - nHeightFooter, rcClient.Width(), rcClient.Height());
|
||
|
|
||
|
if (nHeaderWidth != m_rcHeaderArea.Width() && pHeader)
|
||
|
{
|
||
|
pHeader->AdjustColumnsWidth(m_rcHeaderArea.Width());
|
||
|
}
|
||
|
|
||
|
m_bAdjustLayoutRunning = FALSE;
|
||
|
}
|
||
|
|
||
|
CXTPReportColumn* CXTPTrackControl::GetTrackColumn() const
|
||
|
{
|
||
|
CXTPReportColumn* pColumn = m_pColumns->Find(GetTrackColumnIndex());
|
||
|
return pColumn;
|
||
|
}
|
||
|
|
||
|
int CXTPTrackControl::PositionToTrack(int nPosition)
|
||
|
{
|
||
|
CXTPReportColumn* pColumn = GetTrackColumn();
|
||
|
|
||
|
|
||
|
CRect rcTrack = pColumn->GetRect();
|
||
|
rcTrack.DeflateRect(7, 0);
|
||
|
|
||
|
return int(rcTrack.left + (nPosition - m_nViewPortMin) * rcTrack.Width() / (m_nViewPortMax - m_nViewPortMin));
|
||
|
}
|
||
|
|
||
|
int CXTPTrackControl::TrackToPosition(int nTrack) const
|
||
|
{
|
||
|
CXTPReportColumn* pColumn = GetTrackColumn();
|
||
|
|
||
|
CRect rcTrack = pColumn->GetRect();
|
||
|
rcTrack.DeflateRect(7, 0);
|
||
|
|
||
|
return int(m_nViewPortMin + (nTrack - rcTrack.left) * (m_nViewPortMax - m_nViewPortMin) / rcTrack.Width());
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::DoPropExchange(CXTPPropExchange* pPX)
|
||
|
{
|
||
|
CXTPReportControl::DoPropExchange(pPX);
|
||
|
|
||
|
|
||
|
PX_Int(pPX, _T("TimeScaleMin"), m_nTimeLineMin);
|
||
|
PX_Int(pPX, _T("TimeScaleMax"), m_nTimeLineMax);
|
||
|
|
||
|
//PX_Int(pPX, _T("ViewPortMin"), m_nViewPortMin);
|
||
|
//PX_Int(pPX, _T("ViewPortMax"), m_nViewPortMax);
|
||
|
|
||
|
PX_Int(pPX, _T("WorkAreaMin"), m_nWorkAreaMin);
|
||
|
PX_Int(pPX, _T("WorkAreaMax"), m_nWorkAreaMax);
|
||
|
|
||
|
PX_Int(pPX, _T("TimeLinePos"), m_nTimeLinePosition);
|
||
|
PX_Int(pPX, _T("TrackColumnIndex"), m_nTrackColumnIndex, -1);
|
||
|
|
||
|
|
||
|
CXTPPropExchangeSection secMarkers(pPX->GetSection(_T("Markers")));
|
||
|
m_pMarkers->DoPropExchange(&secMarkers);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void CXTPTrackControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
{
|
||
|
CXTPReportColumn* pColumn = GetTrackColumn();
|
||
|
if (!pColumn || !pColumn->IsVisible())
|
||
|
{
|
||
|
CXTPReportControl::OnKeyDown(nChar, nRepCnt, nFlags);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((GetKeyState(VK_CONTROL) < 0 || GetKeyState(VK_SHIFT) < 0)
|
||
|
&& (nChar == VK_LEFT || nChar == VK_RIGHT || nChar == VK_UP || nChar == VK_DOWN))
|
||
|
{
|
||
|
|
||
|
CreateDragBlocks();
|
||
|
if (m_arrDragBlocks.GetSize() == 0)
|
||
|
return;
|
||
|
|
||
|
BOOL bResize = m_bAllowBlockScale && GetKeyState(VK_SHIFT) < 0 ? 2 : 0;
|
||
|
|
||
|
if (!bResize && !m_bAllowBlockMove)
|
||
|
return;
|
||
|
|
||
|
XTPDrawHelpers()->KeyToLayout(this, nChar);
|
||
|
|
||
|
CRect rcBlock = m_arrDragBlocks[m_arrDragBlocks.GetSize() - 1].pBlock->GetRect();
|
||
|
CPoint pt = rcBlock.CenterPoint();
|
||
|
ClientToScreen(&pt);
|
||
|
|
||
|
m_ptStartDrag = pt;
|
||
|
|
||
|
if (nChar == VK_LEFT) pt.x -= 20;
|
||
|
if (nChar == VK_RIGHT) pt.x += 20;
|
||
|
if (nChar == VK_UP) pt.y -= 20;
|
||
|
if (nChar == VK_DOWN) pt.y += 20;
|
||
|
|
||
|
|
||
|
OnMoveBlock(pt, bResize);
|
||
|
RedrawControl();
|
||
|
UpdateWindow();
|
||
|
|
||
|
rcBlock = m_arrDragBlocks[m_arrDragBlocks.GetSize() - 1].pBlock->GetRect();
|
||
|
pt = rcBlock.CenterPoint();
|
||
|
if (bResize) pt.x = rcBlock.right - 2;
|
||
|
ClientToScreen(&pt);
|
||
|
|
||
|
SetCursorPos(pt.x, pt.y);
|
||
|
|
||
|
ReleaseDragBlocks();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (nChar == VK_RIGHT && !m_bFocusSubItems)
|
||
|
{
|
||
|
int nDelta = TrackToPosition(10) - TrackToPosition(0);
|
||
|
if (IsLayoutRTL()) nDelta = -nDelta;
|
||
|
|
||
|
SetViewPort(int(m_nViewPortMin + nDelta), int(m_nViewPortMax + nDelta));
|
||
|
return;
|
||
|
}
|
||
|
if (nChar == VK_LEFT && !m_bFocusSubItems)
|
||
|
{
|
||
|
int nDelta = TrackToPosition(10) - TrackToPosition(0);
|
||
|
if (IsLayoutRTL()) nDelta = -nDelta;
|
||
|
|
||
|
SetViewPort(int(m_nViewPortMin - nDelta), int(m_nViewPortMax - nDelta));
|
||
|
return;
|
||
|
}
|
||
|
if (nChar == VK_TAB)
|
||
|
{
|
||
|
CXTPTrackBlock* pOldSelectedBlock = m_pSelectedBlocks->GetAt(m_pSelectedBlocks->GetCount() - 1);
|
||
|
|
||
|
CXTPTrackBlock* pNewSelectedBlock = NULL;
|
||
|
|
||
|
if ((GetKeyState(VK_SHIFT) < 0)) // Back
|
||
|
{
|
||
|
int nOldPosition = pOldSelectedBlock ? pOldSelectedBlock->GetPosition() : INT_MAX;
|
||
|
|
||
|
for (int i = pOldSelectedBlock == 0 ? GetRows()->m_nFocusedRow : GetRows()->GetCount() - 1; i >= 0; i--)
|
||
|
{
|
||
|
CXTPReportRow* pRow = GetRows()->GetAt(i);
|
||
|
if (!pRow || !pRow->GetRecord())
|
||
|
continue;
|
||
|
|
||
|
CXTPTrackControlItem* pTrack = DYNAMIC_DOWNCAST(CXTPTrackControlItem, pRow->GetRecord()->GetItem(GetTrackColumnIndex()));
|
||
|
if (!pTrack || pTrack->GetBlockCount() == 0)
|
||
|
continue;
|
||
|
|
||
|
if (pOldSelectedBlock == NULL || pOldSelectedBlock->GetItem() == pTrack)
|
||
|
{
|
||
|
for (int j = 0; j < pTrack->GetBlockCount(); j++)
|
||
|
{
|
||
|
CXTPTrackBlock* pBlock = pTrack->GetBlock(j);
|
||
|
if (pBlock->IsLocked())
|
||
|
continue;
|
||
|
if (pBlock->GetPosition() >= nOldPosition)
|
||
|
continue;
|
||
|
|
||
|
if (pNewSelectedBlock == NULL || pBlock->GetPosition() > pNewSelectedBlock->GetPosition())
|
||
|
pNewSelectedBlock = pBlock;
|
||
|
}
|
||
|
|
||
|
if (pNewSelectedBlock)
|
||
|
break;
|
||
|
|
||
|
nOldPosition = INT_MAX;
|
||
|
pOldSelectedBlock = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int nOldPosition = pOldSelectedBlock ? pOldSelectedBlock->GetPosition() : -1;
|
||
|
|
||
|
for (int i = pOldSelectedBlock == 0 ? GetRows()->m_nFocusedRow : 0; i < GetRows()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPReportRow* pRow = GetRows()->GetAt(i);
|
||
|
if (!pRow || !pRow->GetRecord())
|
||
|
continue;
|
||
|
|
||
|
CXTPTrackControlItem* pTrack = DYNAMIC_DOWNCAST(CXTPTrackControlItem, pRow->GetRecord()->GetItem(GetTrackColumnIndex()));
|
||
|
if (!pTrack || pTrack->GetBlockCount() == 0)
|
||
|
continue;
|
||
|
|
||
|
if (pOldSelectedBlock == NULL || pOldSelectedBlock->GetItem() == pTrack)
|
||
|
{
|
||
|
for (int j = 0; j < pTrack->GetBlockCount(); j++)
|
||
|
{
|
||
|
CXTPTrackBlock* pBlock = pTrack->GetBlock(j);
|
||
|
if (pBlock->IsLocked())
|
||
|
continue;
|
||
|
if (pBlock->GetPosition() <= nOldPosition)
|
||
|
continue;
|
||
|
|
||
|
if (pNewSelectedBlock == NULL || pBlock->GetPosition() < pNewSelectedBlock->GetPosition())
|
||
|
pNewSelectedBlock = pBlock;
|
||
|
}
|
||
|
|
||
|
if (pNewSelectedBlock)
|
||
|
break;
|
||
|
|
||
|
nOldPosition = -1;
|
||
|
pOldSelectedBlock = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (pNewSelectedBlock != NULL)
|
||
|
{
|
||
|
m_pSelectedBlocks->RemoveAll();
|
||
|
|
||
|
m_pSelectedBlocks->Add(pNewSelectedBlock);
|
||
|
|
||
|
SendMessageToParent(XTP_NM_TRACK_SELECTEDBLOCKSCHANGED);
|
||
|
|
||
|
EnsureVisible(pNewSelectedBlock);
|
||
|
}
|
||
|
|
||
|
RedrawControl();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CXTPReportControl::OnKeyDown(nChar, nRepCnt, nFlags);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINT CXTPTrackControl::OnGetDlgCode()
|
||
|
{
|
||
|
return DLGC_WANTTAB | DLGC_WANTARROWS | DLGC_WANTCHARS;
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::EnsureVisible(CXTPTrackBlock* pBlock)
|
||
|
{
|
||
|
CXTPReportRecord* pRecord = pBlock->GetItem()->GetRecord();
|
||
|
|
||
|
CXTPReportRow* pRow = GetRows()->Find(pRecord);
|
||
|
|
||
|
if (!pRow)
|
||
|
return;
|
||
|
|
||
|
CXTPReportControl::EnsureVisible(pRow);
|
||
|
CXTPReportControl::EnsureVisible(GetTrackColumn());
|
||
|
|
||
|
|
||
|
CXTPReportColumn* pColumn = GetTrackColumn();
|
||
|
if (!pColumn || !pColumn->IsVisible())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (m_nViewPortMin >= pBlock->GetPosition() + pBlock->GetLength())
|
||
|
{
|
||
|
SetViewPort(pBlock->GetPosition(), pBlock->GetPosition() + int(m_nViewPortMax - m_nViewPortMin));
|
||
|
}
|
||
|
else if (m_nViewPortMax <= pBlock->GetPosition())
|
||
|
{
|
||
|
int nViewPortMin = pBlock->GetPosition() + pBlock->GetLength() - int(m_nViewPortMax - m_nViewPortMin);
|
||
|
if (nViewPortMin < m_nTimeLineMin)
|
||
|
nViewPortMin = m_nTimeLineMin;
|
||
|
|
||
|
SetViewPort(nViewPortMin, nViewPortMin + int(m_nViewPortMax - m_nViewPortMin));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
int CXTPTrackControl::SnapPosition(int nPosition)
|
||
|
{
|
||
|
CXTPTrackControl* pControl = this;
|
||
|
int nMargin = pControl->GetSnapMargin();
|
||
|
if (nMargin == 0)
|
||
|
return nPosition;
|
||
|
|
||
|
int nScreenPosition = pControl->PositionToTrack(nPosition);
|
||
|
|
||
|
if (pControl->m_bSnapToMarkers)
|
||
|
{
|
||
|
|
||
|
if (abs(nScreenPosition - pControl->PositionToTrack(pControl->GetTimeLinePosition())) <= nMargin)
|
||
|
{
|
||
|
return pControl->GetTimeLinePosition();
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < pControl->GetMarkers()->GetCount(); i++)
|
||
|
{
|
||
|
if (abs(nScreenPosition - pControl->PositionToTrack(pControl->GetMarkers()->GetAt(i)->GetPosition())) <= nMargin)
|
||
|
{
|
||
|
return pControl->GetMarkers()->GetAt(i)->GetPosition();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pControl->m_bSnapToBlocks)
|
||
|
{
|
||
|
CXTPReportScreenRows *pScreenRows = pControl->GetRows()->GetScreenRows();
|
||
|
|
||
|
for (int i = 0; i < pScreenRows->GetSize(); i++)
|
||
|
{
|
||
|
CXTPReportRow* pRow = pScreenRows->GetAt(i);
|
||
|
if (!pRow || !pRow->GetRecord())
|
||
|
continue;
|
||
|
|
||
|
CXTPTrackControlItem* pTrack = DYNAMIC_DOWNCAST(CXTPTrackControlItem, pRow->GetRecord()->GetItem(GetTrackColumnIndex()));
|
||
|
if (!pTrack)
|
||
|
continue;
|
||
|
|
||
|
for (int j = 0; j < pTrack->GetBlockCount(); j++)
|
||
|
{
|
||
|
CXTPTrackBlock* pBlock = pTrack->GetBlock(j);
|
||
|
|
||
|
if (pBlock->m_bDragging)
|
||
|
continue;
|
||
|
|
||
|
if (abs(nScreenPosition - pControl->PositionToTrack(pBlock->GetPosition())) <= nMargin)
|
||
|
{
|
||
|
return pBlock->GetPosition();
|
||
|
}
|
||
|
|
||
|
if (abs(nScreenPosition - pControl->PositionToTrack(pBlock->GetPosition() + pBlock->GetLength())) <= nMargin)
|
||
|
{
|
||
|
return pBlock->GetPosition() + pBlock->GetLength();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return nPosition;
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::OnMoveBlock(CPoint pt, BOOL bResize)
|
||
|
{
|
||
|
CXTPTrackControl* pControl = this;
|
||
|
|
||
|
pControl->BeginUpdate();
|
||
|
|
||
|
CArray<CXTPTrackBlock*, CXTPTrackBlock*> arrBlocks;
|
||
|
CArray<CXTPTrackControlItem*, CXTPTrackControlItem*> arrItems;
|
||
|
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < m_arrDragBlocks.GetSize(); i++)
|
||
|
{
|
||
|
CXTPTrackBlock* pBlock = m_arrDragBlocks[i].pBlock;
|
||
|
|
||
|
if (bResize && !pBlock->IsResizable())
|
||
|
continue;
|
||
|
|
||
|
CXTPTrackControlItem* pOldTrack = pBlock->GetItem();
|
||
|
|
||
|
CRect rc = m_arrDragBlocks[i].rcOrigin;
|
||
|
rc.OffsetRect(pt - m_ptStartDrag);
|
||
|
|
||
|
CPoint ptHit = CPoint(0, (rc.top + rc.bottom) / 2);
|
||
|
|
||
|
CXTPReportRow* pRow = CXTPReportControl::HitTest(ptHit);
|
||
|
CXTPTrackControlItem* pNewTrack = 0;
|
||
|
|
||
|
if (!bResize && pControl->m_bAllowBlockRemove)
|
||
|
{
|
||
|
if (pRow && pRow->GetRecord())
|
||
|
{
|
||
|
pNewTrack = DYNAMIC_DOWNCAST(CXTPTrackControlItem, pRow->GetRecord()->GetItem(GetTrackColumnIndex()));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNewTrack = pBlock->GetItem();
|
||
|
}
|
||
|
|
||
|
if (pNewTrack && !pNewTrack->IsLocked())
|
||
|
{
|
||
|
if (pBlock->GetItem() != pNewTrack)
|
||
|
{
|
||
|
pBlock->InternalAddRef();
|
||
|
pBlock->Remove();
|
||
|
pNewTrack->Add(pBlock);
|
||
|
}
|
||
|
|
||
|
int nOffet = -(pControl->TrackToPosition(m_ptStartDrag.x) - pControl->TrackToPosition(pt.x));
|
||
|
if (IsLayoutRTL()) nOffet = -nOffet;
|
||
|
|
||
|
int nPosition = pBlock->m_nMRUPosition;
|
||
|
int nLength = pBlock->m_nLength;
|
||
|
|
||
|
|
||
|
if (bResize == 1)
|
||
|
{
|
||
|
int nLeft = m_arrDragBlocks[i].nOldPos;
|
||
|
int nRight =m_arrDragBlocks[i].nOldLength + m_arrDragBlocks[i].nOldPos;
|
||
|
|
||
|
nLeft = max(pControl->GetTimeLineMin(), SnapPosition(nLeft + nOffet));
|
||
|
|
||
|
if (nRight - nLeft < pBlock->GetMinLength())
|
||
|
nLeft = nRight - pBlock->GetMinLength();
|
||
|
else if (nRight - nLeft > pBlock->GetMaxLength())
|
||
|
nLeft = nRight - pBlock->GetMaxLength();
|
||
|
|
||
|
nPosition = nLeft;
|
||
|
nLength = nRight - nLeft;
|
||
|
|
||
|
}
|
||
|
else if (bResize == 2)
|
||
|
{
|
||
|
int nLeft = m_arrDragBlocks[i].nOldPos;
|
||
|
int nRight =m_arrDragBlocks[i].nOldLength + m_arrDragBlocks[i].nOldPos;
|
||
|
|
||
|
nRight = min(pControl->GetTimeLineMax(), SnapPosition(nRight + nOffet));
|
||
|
|
||
|
if (nRight - nLeft < pBlock->GetMinLength())
|
||
|
nRight = nLeft + pBlock->GetMinLength();
|
||
|
else if (nRight - nLeft > pBlock->GetMaxLength())
|
||
|
nRight = nLeft + pBlock->GetMaxLength();
|
||
|
|
||
|
nLength = nRight - nLeft;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int nRight = min(pControl->GetTimeLineMax(), SnapPosition(m_arrDragBlocks[i].nOldPos + m_arrDragBlocks[i].nOldLength + nOffet));
|
||
|
int nLeft = max(pControl->GetTimeLineMin(), SnapPosition(nRight - m_arrDragBlocks[i].nOldLength));
|
||
|
|
||
|
nPosition = nLeft;
|
||
|
}
|
||
|
|
||
|
pBlock->SetPosition(nPosition);
|
||
|
pBlock->SetLength(nLength);
|
||
|
|
||
|
pBlock->m_nLastDragTime = (int)time(0);
|
||
|
|
||
|
arrBlocks.Add(pBlock);
|
||
|
|
||
|
if (pOldTrack)
|
||
|
{
|
||
|
arrItems.Add(pOldTrack);
|
||
|
}
|
||
|
if (pNewTrack != pOldTrack)
|
||
|
{
|
||
|
arrItems.Add(pNewTrack);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = (int)arrBlocks.GetSize() - 1; i >= 0; i--)
|
||
|
{
|
||
|
CXTPTrackBlock* pBlock = arrBlocks[i];
|
||
|
|
||
|
if (!pControl->m_bFlexibleDrag)
|
||
|
{
|
||
|
pBlock->GetItem()->AdjustBlockPosition(pBlock, bResize);
|
||
|
}
|
||
|
|
||
|
pControl->SendMessageToParent(XTP_NM_TRACK_BLOCKCHANGED, pBlock);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < arrItems.GetSize(); i++)
|
||
|
{
|
||
|
CXTPTrackControlItem* pItem = arrItems[i];
|
||
|
pItem->RecalcLayout();
|
||
|
}
|
||
|
|
||
|
EndUpdate();
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::CreateDragBlocks()
|
||
|
{
|
||
|
m_arrDragBlocks.RemoveAll();
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < m_pSelectedBlocks->GetCount(); i++)
|
||
|
{
|
||
|
DRAGBLOCK block;
|
||
|
block.pBlock = (CXTPTrackBlock*)m_pSelectedBlocks->GetAt(i);
|
||
|
if (block.pBlock->IsLocked())
|
||
|
continue;
|
||
|
|
||
|
block.nOldPos = block.pBlock->GetPosition();
|
||
|
block.nOldLength = block.pBlock->GetLength();
|
||
|
block.rcOrigin = block.pBlock->GetRect();
|
||
|
|
||
|
block.pBlock->m_bDragging = TRUE;
|
||
|
|
||
|
m_arrDragBlocks.Add(block);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::ReleaseDragBlocks()
|
||
|
{
|
||
|
for (int i = 0; i < m_arrDragBlocks.GetSize(); i++)
|
||
|
{
|
||
|
m_arrDragBlocks[i].pBlock->m_bDragging = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::StartDragBlocks(BOOL bResize)
|
||
|
{
|
||
|
m_pUndoManager->StartGroup();
|
||
|
|
||
|
// set capture to the window which received this message
|
||
|
SetCapture();
|
||
|
|
||
|
CPoint pt(0, 0);
|
||
|
GetCursorPos(&pt);
|
||
|
|
||
|
m_ptStartDrag = pt;
|
||
|
|
||
|
CreateDragBlocks();
|
||
|
|
||
|
::SetCursor(bResize ? m_hResizeCursor : m_hMoveCursor);
|
||
|
|
||
|
|
||
|
// get messages until capture lost or cancelled/accepted
|
||
|
while (::GetCapture() == m_hWnd)
|
||
|
{
|
||
|
MSG msg;
|
||
|
|
||
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
||
|
{
|
||
|
AfxPostQuitMessage((int)msg.wParam);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (msg.message == WM_LBUTTONUP)
|
||
|
break;
|
||
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
||
|
{
|
||
|
pt = msg.pt;
|
||
|
OnMoveBlock(pt, bResize);
|
||
|
}
|
||
|
else if (msg.message == WM_KEYDOWN)
|
||
|
{
|
||
|
if (msg.wParam == VK_ESCAPE)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
DispatchMessage(&msg);
|
||
|
|
||
|
}
|
||
|
|
||
|
ReleaseCapture();
|
||
|
|
||
|
ReleaseDragBlocks();
|
||
|
|
||
|
m_pUndoManager->EndGroup();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPTrackControl::OnMoveSelection(CPoint pt)
|
||
|
{
|
||
|
CXTPTrackControl* pControl = this;
|
||
|
|
||
|
CRect rc(m_ptStartDrag, pt);
|
||
|
rc.NormalizeRect();
|
||
|
|
||
|
pControl->ScreenToClient(&rc);
|
||
|
|
||
|
int sz = pControl->m_pSelectedBlocks->GetCount();
|
||
|
pControl->m_pSelectedBlocks->RemoveAll();
|
||
|
|
||
|
CXTPReportScreenRows *pScreenRows = pControl->GetRows()->GetScreenRows();
|
||
|
|
||
|
for (int i = 0; i < pScreenRows->GetSize(); i++)
|
||
|
{
|
||
|
CXTPReportRow* pRow = pScreenRows->GetAt(i);
|
||
|
if (!pRow->GetRecord())
|
||
|
continue;
|
||
|
|
||
|
if (pRow->GetRect().top >= rc.bottom || pRow->GetRect().bottom <= rc.top)
|
||
|
continue;
|
||
|
|
||
|
CXTPTrackControlItem* pTrack = DYNAMIC_DOWNCAST(CXTPTrackControlItem, pRow->GetRecord()->GetItem(GetTrackColumnIndex()));
|
||
|
if (!pTrack)
|
||
|
continue;
|
||
|
|
||
|
for (int j = 0; j < pTrack->GetBlockCount(); j++)
|
||
|
{
|
||
|
CXTPTrackBlock* pBlock = pTrack->GetBlock(j);
|
||
|
if (pBlock->IsLocked())
|
||
|
continue;
|
||
|
|
||
|
if (CRect().IntersectRect(pBlock->GetRect(), rc))
|
||
|
{
|
||
|
pControl->m_pSelectedBlocks->Add(pBlock);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (sz != pControl->m_pSelectedBlocks->GetCount())
|
||
|
{
|
||
|
pControl->SendMessageToParent(XTP_NM_TRACK_SELECTEDBLOCKSCHANGED);
|
||
|
}
|
||
|
|
||
|
pControl->m_rcSelectedArea = rc;
|
||
|
pControl->RedrawControl();
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::StartDragSelection()
|
||
|
{
|
||
|
// set capture to the window which received this message
|
||
|
SetCapture();
|
||
|
|
||
|
CPoint pt(0, 0);
|
||
|
GetCursorPos(&pt);
|
||
|
|
||
|
m_ptStartDrag = pt;
|
||
|
|
||
|
|
||
|
// get messages until capture lost or canceled/accepted
|
||
|
while (::GetCapture() == m_hWnd)
|
||
|
{
|
||
|
MSG msg;
|
||
|
|
||
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
||
|
{
|
||
|
AfxPostQuitMessage((int)msg.wParam);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (msg.message == WM_LBUTTONUP)
|
||
|
break;
|
||
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
||
|
{
|
||
|
pt = msg.pt;
|
||
|
OnMoveSelection(pt);
|
||
|
}
|
||
|
else if (msg.message == WM_KEYDOWN)
|
||
|
{
|
||
|
if (msg.wParam == VK_ESCAPE)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
DispatchMessage(&msg);
|
||
|
|
||
|
}
|
||
|
|
||
|
ReleaseCapture();
|
||
|
|
||
|
m_rcSelectedArea.SetRectEmpty();
|
||
|
RedrawControl();
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::OnLButtonDown(UINT nFlags, CPoint point)
|
||
|
{
|
||
|
if (m_pSectionBody->GetRect().PtInRect(point))
|
||
|
{
|
||
|
if (CXTPReportControl::HitTest(point) == NULL)
|
||
|
{
|
||
|
if (m_pSelectedBlocks->GetCount())
|
||
|
{
|
||
|
m_pSelectedBlocks->RemoveAll();
|
||
|
SendMessageToParent(XTP_NM_TRACK_SELECTEDBLOCKSCHANGED);
|
||
|
}
|
||
|
StartDragSelection();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
CXTPReportControl::OnLButtonDown(nFlags, point);
|
||
|
}
|
||
|
|
||
|
void CXTPTrackControl::Populate()
|
||
|
{
|
||
|
CXTPReportControl::Populate();
|
||
|
|
||
|
if (m_pUndoManager) m_pUndoManager->Clear();
|
||
|
}
|
||
|
|
||
|
BOOL CXTPTrackControl::HitTest(CPoint pt, CXTPReportHitTestInfo *pInfo) const
|
||
|
{
|
||
|
if (NULL == pInfo)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pInfo->m_pColumn = NULL;
|
||
|
pInfo->m_pRow = NULL;
|
||
|
pInfo->m_pItem = NULL;
|
||
|
pInfo->m_pBlock = NULL;
|
||
|
pInfo->m_htCode = xtpReportHitTestUnknown;
|
||
|
pInfo->m_iTrackPosition = 0;
|
||
|
|
||
|
if (m_pSections->GetRect().PtInRect(pt))
|
||
|
{
|
||
|
pInfo->m_pRow = CXTPReportControl::HitTest(pt);
|
||
|
|
||
|
if (pInfo->m_pRow)
|
||
|
{
|
||
|
pInfo->m_pItem = pInfo->m_pRow->HitTest(pt, NULL, &pInfo->m_pColumn);
|
||
|
if (pInfo->m_pItem && pInfo->m_pItem->IsKindOf(RUNTIME_CLASS(CXTPTrackControlItem)))
|
||
|
{
|
||
|
CXTPTrackControlItem *pItem = DYNAMIC_DOWNCAST(CXTPTrackControlItem, pInfo->m_pItem);
|
||
|
if (pItem)
|
||
|
{
|
||
|
CXTPTrackBlock *pBlock = pItem->HitTest(pt);
|
||
|
|
||
|
pInfo->m_iTrackPosition = TrackToPosition(pt.x);
|
||
|
|
||
|
if (NULL != pBlock)
|
||
|
{
|
||
|
pInfo->m_htCode = xtpReportHitTestBlock;
|
||
|
pInfo->m_pBlock = pBlock;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (xtpReportHitTestUnknown == pInfo->m_htCode)
|
||
|
{
|
||
|
return CXTPReportControl::HitTest(pt, pInfo);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|