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++

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;
}
}