/**********************************************************************
UML StateWizard provides its software under the LGPL License and
zlib/libpng License.
Email us at info@intelliwizard.com for any information, suggestions and
feature requestions.
Home Page: http://www.intelliwizard.com
*************************************************************************/
/* =============================================================================
* Filename: StateChartView.cpp
*
* Copyright Inc
* All rights reserved.
* -----------------------------------------------------------------------------
* General description of this file:
*
* The state chart implementation.
* -----------------------------------------------------------------------------
* Revision History
* -----------------------------------------------------------------------------
* Version Date Author Revision Detail
* 1.0.0 2004/12/21 State charts and arrows drawing.
* 2005/03/16 Draw arc for each corner of the rectangle.
Draw an arrow for default state.
Calcute column width and row height of each state.
* ===========================================================================*/
#include "stdafx.h"
#include "StateChartView.h"
#include "dib.h"
#include "treefile.h"
#include "..\Common\ParamStore.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CStateChartView
IMPLEMENT_DYNCREATE(CStateChartView, CScrollView)
BEGIN_MESSAGE_MAP(CStateChartView, CScrollView)
//{{AFX_MSG_MAP(CStateChartView)
ON_WM_RBUTTONDOWN()
ON_COMMAND(IDD_ADD_STATE, OnAddState)
ON_COMMAND(IDD_DEL_APP, OnDelApp)
ON_COMMAND(IDD_ADD_HANDLE, OnAddHandle)
ON_COMMAND(IDD_DEFLT_CHANGE, OnDefltChange)
ON_COMMAND(IDD_DEL_STATE, OnDelState)
ON_COMMAND(IDD_GOTO_ENTRY, OnGotoEntry)
ON_COMMAND(IDD_GOTO_EXIT, OnGotoExit)
ON_COMMAND(IDD_MENU_SAVEASBMP,OnSaveAsBmp)
ON_COMMAND(IDD_MENU_SAVEASTXT,OnSaveAsTxt)
ON_WM_LBUTTONDOWN()
ON_WM_DESTROY()
ON_WM_LBUTTONUP()
ON_WM_SETCURSOR()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
ON_COMMAND_RANGE(WM_STATE_TRAN_ITEM_0, WM_STATE_TRAN_ITEM_LAST, OnGotoHdler)
// ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CStateChartView construction/destruction
int g_nMaxLevelNum = CParamStore::GetInstance().GetIntValue("StateChart","MaxLevel") == -1
? DEF_STATE_CHART_MAX_LEVEL : CParamStore::GetInstance().GetIntValue("StateChart","MaxLevel");
//int g_nIsCriticalSection = 0;
CStateChartView::CStateChartView()
{
// TODO: add construction code here
m_hItemDrag = NULL;
m_bMouseMove = FALSE;
m_hTopStateItem =NULL;
}
CStateChartView::~CStateChartView()
{
}
BOOL CStateChartView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO : Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CScrollView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CStateChartView drawing
/********************************************************************************************
DESCRIPTION:
INPUT: m_hTopStateItem
m_hTopStateItem is the tree item of the top state item to be draw; We have to record down it, because while state chart is open,
the selected state tree item may be changed.
OUTPUT:
NOTE:
**********************************************************************************************/
void CStateChartView::OnDraw(CDC* pDC)
{
// TODO: add draw code for native data here
TRACE("Starting....\n");
///////////////////
if (m_hTopStateItem==NULL) return;
SME_STATE_T nSelState = 0;
m_EventLineNo = 0;
CalculateStateChartSize(pDC, m_hTopStateItem, m_hTopStateItem);
CalculateColWidthRowHeight(m_hTopStateItem, m_hTopStateItem);
// ensure scroll bars work
TRACE("Ensure scroll bars %d %d\n", ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSelState])->nWidth,
((STATE_CHART_INFO_T*)m_StateChartInfoList[nSelState])->nHeight);
ASSERT(((STATE_CHART_INFO_T*)m_StateChartInfoList[nSelState])->nWidth>0);
ASSERT(((STATE_CHART_INFO_T*)m_StateChartInfoList[nSelState])->nHeight>0);
int mm;
CSize size, sizePage, sizeLine;
GetDeviceScrollSizes(mm, size, sizePage, sizeLine);
SetScrollSizes(MM_TEXT,
CSize(max(size.cx, ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSelState])->nWidth+ 100),
max(size.cy, ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSelState])->nHeight+ 100 )));
DrawStateChart(pDC, m_hTopStateItem, m_hTopStateItem, 50,50);
DrawArrow(pDC, m_hTopStateItem, m_hTopStateItem);
}
/********************************************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
NOTE:
**********************************************************************************************/
void CStateChartView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
// TODO: calculate the total size of this view
// Initialize state chart list to record information
m_hTopStateItem = m_pStateTree->tree.GetSelectedItem();
InitChartInfoList(m_hTopStateItem);
InitEventInfoList(m_hTopStateItem, m_hTopStateItem);
InitStateNameList(m_hTopStateItem);
m_nSelStateSeqNo = -1;
m_EventLineNo = 0;
m_bSizeChange = -1;
g_nMaxLevelNum = CParamStore::GetInstance().GetIntValue("StateChart","MaxLevel") == -1
? DEF_STATE_CHART_MAX_LEVEL : CParamStore::GetInstance().GetIntValue("StateChart","MaxLevel");
m_nSavedMaxLevel = g_nMaxLevelNum;
/* m_ListBox.Create
(LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY | WS_BORDER | WS_VSCROLL , CRect(0, 0, 50, 50), this, IDD_LBXITEMS);
BOOL bRetValue = FALSE;
HICON hIcon = NULL;
bRetValue = m_ImageList.Create(16, 16, ILC_COLOR8 | ILC_MASK, 1, 1);
ASSERT(bRetValue == TRUE);
// Add some icons
hIcon = AfxGetApp()->LoadIcon(IDI_EVENT_ID);
m_ImageList.Add(hIcon);
m_ListBox.SetImageList(&m_ImageList);
m_Font.CreateFont(
14, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_BOLD, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Microsoft Sans Serif") // lpszFacename
);
m_ListBox.SetFont(&m_Font);
m_ListBox.ShowWindow(SW_HIDE); //Hide m_ListBox
m_ListBox.SetOwner(GetParent());
*/
CSize sizeTotal;
sizeTotal.cx = sizeTotal.cy = 100;
SetScrollSizes(MM_TEXT, sizeTotal);
m_hItemDrag = NULL;
m_bMouseMove = FALSE;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Initialize state chart information.
// INPUT: 1) hSelector:
// OUTPUT: CPtrArray m_StateChartInfoList; The size of list is the number of descendants.
// RETURN:
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL CStateChartView::InitChartInfoList(HTREEITEM hSelector)
{
m_StateChartInfoList.RemoveAll();
int nSum = 0;
m_pStateTree->tree.GetChildSum(hSelector, &nSum);
int i = 0;
for (; i < nSum; i++)
{
STATE_CHART_INFO_T *pNewItem = (STATE_CHART_INFO_T*)new(STATE_CHART_INFO_T);
ASSERT(NULL != pNewItem);
memset(pNewItem, 0, sizeof(STATE_CHART_INFO_T));
m_StateChartInfoList.Add(pNewItem);
}
return TRUE;
}
/********************************************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
NOTE:
**********************************************************************************************/
void CStateChartView::ZeroCharInfoList()
{
int nSize = (int)m_StateChartInfoList.GetSize();
int i = 0;
for (; i < nSize; i++)
{
memset(m_StateChartInfoList[i], 0, sizeof(STATE_CHART_INFO_T));
}
}
/********************************************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
NOTE:
**********************************************************************************************/
BOOL CStateChartView::DestroyChartInfoList()
{
int nSize = (int)m_StateChartInfoList.GetSize();
int i = 0;
for (; i < nSize; i++)
{
delete((STATE_CHART_INFO_T*)m_StateChartInfoList[i]);
}
m_StateChartInfoList.RemoveAll();
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get all descendant state names of given state. It is a recursive function.
// INPUT: A state tree item.
// OUTPUT: CStringArray m_StateNameList;
// RETURN:
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
void CStateChartView::InitStateNameList(HTREEITEM hItem)
{
if (m_pStateTree->tree.GetItemData(hItem) &(STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
CString sName = m_pStateTree->tree.GetItemText(hItem);
sName.Replace("(default)", NULL);
sName.TrimLeft();
sName.TrimRight();
m_StateNameList.Add(sName);
}
HTREEITEM hChild = m_pStateTree->tree.GetChildItem(hItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
InitStateNameList(hChild);
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get all events which trigger state transitions below the given state: hSrcItem
// INPUT: 1)hSrcItem: The state 2)hSelItem: The current selected item.
// OUTPUT: CStringArray m_EventNameList;
// RETURN:
// NOTE: Do NOT filter out too deep states.
//
///////////////////////////////////////////////////////////////////////////////////////////
void CStateChartView::InitEventNameList(HTREEITEM hSrcItem, HTREEITEM hSelItem)
{
//if (GetStateLevel(hSrcItem, hSelItem) > g_nMaxLevelNum)
// return; // exceed the maximum level of state to be drawn
HTREEITEM hEvent = m_pStateTree->tree.GetChildItem(hSrcItem);
CString sEvent;
while (true)
{
if (NULL == hEvent)
break;
if (m_pStateTree->tree.GetItemData(hEvent) & STATE_TREE_EVENT_ID_MASK)
{
HTREEITEM hDestState = m_pStateTree->tree.GetChildItem(hEvent);
CString sDestStateName = m_pStateTree->tree.GetItemText(hDestState);
if (sDestStateName != STR_INTERNAL_TRAN)
{
sDestStateName.Replace("Transit to:", NULL);
sDestStateName.TrimLeft();
sDestStateName.TrimRight();
HTREEITEM hDestItem = NULL;
if (GetDestStateItem(hSelItem, sDestStateName, hDestItem) == FALSE)
{
/*
if (GetStateLevel(hDestItem, hSelItem) > g_nMaxLevelNum)
{
hEvent = m_pStateTree->tree.GetNextSiblingItem(hEvent);
continue; // exceed the maximum level of state to be drawn
}
*/
m_EventNameList.Add(m_pStateTree->tree.GetItemText(hEvent));
}
}
}
hEvent = m_pStateTree->tree.GetNextSiblingItem(hEvent);
}
HTREEITEM hChild = m_pStateTree->tree.GetChildItem(hSrcItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
InitEventNameList(hChild, hSelItem);
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Allocate the memory for state transition info list. The size depends on m_EventNameList.
// INPUT: m_EventNameList
// OUTPUT: CPtrArray m_EventLineInfoList;
// RETURN:
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
void CStateChartView::InitEventInfoList(HTREEITEM hSrcItem, HTREEITEM hSelItem)
{
m_EventNameList.RemoveAll();
InitEventNameList(hSrcItem, hSelItem);
int sum = (int)m_EventNameList.GetSize();
int i = 0;
for (; i < sum; i++)
{
EVENT_LINE_INFO_T *pNewItem = (EVENT_LINE_INFO_T*)new(EVENT_LINE_INFO_T);
memset(pNewItem, 0, sizeof(EVENT_LINE_INFO_T));
m_EventLineInfoList.Add(pNewItem);
}
}
/********************************************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
NOTE:
**********************************************************************************************/
void CStateChartView::ZeroEventInfoList()
{
int nSize = (int)m_EventLineInfoList.GetSize();
int i = 0;
for (; i < nSize; i++)
{
memset(m_EventLineInfoList[i], 0, sizeof(EVENT_LINE_INFO_T));
}
}
/********************************************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
NOTE:
**********************************************************************************************/
BOOL CStateChartView::DestroyEventInfoList()
{
int nSize = (int)m_EventLineInfoList.GetSize();
int i = 0;
for (; i < nSize; i++)
{
delete((EVENT_LINE_INFO_T*)m_EventLineInfoList[i]);
}
m_EventLineInfoList.RemoveAll();
return TRUE;
}
void CStateChartView::OnDestroy()
{
// m_Font.DeleteObject();
// m_ListBox.DestroyWindow();
DestroyChartInfoList();
DestroyEventInfoList();
m_EventNameList.RemoveAll();
m_StateNameList.RemoveAll();
g_nMaxLevelNum = m_nSavedMaxLevel;
CScrollView::OnDestroy();
// TODO: Add your message handler code here
}
/////////////////////////////////////////////////////////////////////////////
// CStateChartView printing
BOOL CStateChartView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CStateChartView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CStateChartView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// CStateChartView diagnostics
#ifdef _DEBUG
void CStateChartView::AssertValid() const
{
CScrollView::AssertValid();
}
void CStateChartView::Dump(CDumpContext& dc) const
{
CScrollView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CStateChartView message handlers
// StateRect origin position is input data;
// StateRect width and height are output data;
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Calculate the state width and height.
// INPUT:
// OUTPUT: m_StateChartInfo[nState].nWidth and m_StateChartInfo[nState].nHeight
// RETURN:
// NOTE: Filter out too deep states.
//
///////////////////////////////////////////////////////////////////////////////////////////
#define STATE_CHART_MARGIN 32
#define STATE_CHART_HALF_MARGIN (STATE_CHART_MARGIN>>1)
void CStateChartView::CalculateStateChartSize(CDC* pDC,
HTREEITEM hSelItem,
HTREEITEM hStart)
{
//////////////////////////////////////////////////////////////////////////
// if (GetStateLevel(hSelItem, hStart) > g_nMaxLevelNum)
// return; // exceed the maximum level of state to be drawn
int nChildrenNum=0,nColNum,nRowNum;
SME_STATE_T nState = GetChartInfoSeqNum(hSelItem);
/*
CString stemp;
stemp = m_pStateTree->tree.GetItemText(hSelItem);
*/
CRect TextRect;
TextRect.SetRect(0,0,0,0);
// Calculate the size of rectangle in which draw the text.
if (m_pStateTree->tree.GetItemData(hSelItem) & STATE_TREE_APPLICATION_MASK)
pDC->DrawText(m_pStateTree->tree.GetItemText(hSelItem), -1, &TextRect, DT_CALCRECT | DT_SINGLELINE);
else
{
CString sSelStateName = m_pStateTree->tree.GetItemText(hSelItem);
sSelStateName.Replace("(default)", NULL);
sSelStateName.TrimLeft();
sSelStateName.TrimRight();
pDC->DrawText(sSelStateName, -1, &TextRect, DT_CALCRECT | DT_SINGLELINE);
}
if (((m_pStateTree->tree.GetItemData(hSelItem)) & STATE_TREE_HAS_DEFAULT_CHILD_STATE) == 0 ||
(GetStateLevel(hSelItem, hStart) > g_nMaxLevelNum - 1))
{
// This state is a leaf.
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth = TextRect.Width() + STATE_CHART_MARGIN;
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight = TextRect.Height() + STATE_CHART_MARGIN;
TRACE("leaf state =%d width=%d height=%d \n",
nState,
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth,
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight);
return;
}
// If state is not a leaf, draw text on the top of state rectangle.
// The least width and height.
HTREEITEM hChild = m_pStateTree->tree.GetChildItem(hSelItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
nChildrenNum++;
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
if (nChildrenNum==0)
return; // To prevent nChildrenNum equal to 0.
nColNum=(int)(sqrt((double)(nChildrenNum-1)))+1;
nRowNum=(int)((nChildrenNum-1)/nColNum)+1;
// Get the max width in every column and max height in every row among child states.
int *pMaxWidthInColumn = new int[nColNum];
int *pMaxHeightInRow = new int[nRowNum];
int i;
for (i=0; i<nColNum; i++) pMaxWidthInColumn[i] = 0;
for (i=0; i<nRowNum; i++) pMaxHeightInRow[i] = 0;
int nChildIdx = 0;
hChild = m_pStateTree->tree.GetChildItem(hSelItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
int nChildXPos = nChildIdx % nColNum;
int nChildYPos = nChildIdx / nColNum;
CRect ChildRect(0,0,0,0);
SME_STATE_T nChildState = GetChartInfoSeqNum(hChild);
CString sChildStateName;
sChildStateName = m_pStateTree->tree.GetItemText(hChild);
sChildStateName.Replace("(default)", NULL);
sChildStateName.TrimLeft();
sChildStateName.TrimRight();
// Return child state width and height.
CalculateStateChartSize(pDC, hChild, hStart);
// Keep track of max width in every column.
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nWidth > pMaxWidthInColumn[nChildXPos])
pMaxWidthInColumn[nChildXPos] = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nWidth;
// Keep track of max height in every row.
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nHeight > pMaxHeightInRow[nChildYPos])
pMaxHeightInRow[nChildYPos] = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nHeight;
nChildIdx++;
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
// The width of a state is the summary of every column width or the state name drawing width.
// Text string width
int nStateWidth1 = TextRect.Width() + STATE_CHART_MARGIN;
// Total child state width.
int nStateWidth2 = STATE_CHART_MARGIN * (nColNum + 1);
for (i=0; i<nColNum; i++)
nStateWidth2 += pMaxWidthInColumn[i];
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth = max(nStateWidth1,nStateWidth2);
// The height of a state is the summary of every row height and the state name drawing height.
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight = TextRect.Height() + STATE_CHART_MARGIN * (nRowNum+1);
for (i=0; i<nRowNum; i++)
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight += pMaxHeightInRow[i];
delete pMaxWidthInColumn;
delete pMaxHeightInRow;
TRACE("state =%d width=%d height=%d \n",
nState,
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth,
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight);
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Calculate the column width and row height of the state.
// INPUT: 1) hItem: Handler of current state to be drawn
// 2) hStart: Handler of selected item
// OUTPUT: m_StateChartInfo[nState].nColWidth and m_StateChartInfo[nState].nRowHeight
// RETURN:
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
void CStateChartView::CalculateColWidthRowHeight(HTREEITEM hItem, HTREEITEM hStart)
{
if (GetStateLevel(hItem, hStart) > g_nMaxLevelNum)
return; // exceed the maximum level of state to be drawn
int nChildrenNum=0,nColNum,nRowNum;
HTREEITEM hChild = m_pStateTree->tree.GetChildItem(hItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
nChildrenNum++;
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
if (nChildrenNum==0)
return; // To prevent nChildrenNum equal to 0.
nColNum=(int)(sqrt((double)(nChildrenNum-1)))+1;
nRowNum=(int)((nChildrenNum-1)/nColNum)+1;
// Get the max width in every column and max height in every row among child states.
int *pMaxWidthInColumn = new int[nColNum];
int *pMaxHeightInRow = new int[nRowNum];
int i;
for (i=0; i<nColNum; i++) pMaxWidthInColumn[i] = 0;
for (i=0; i<nRowNum; i++) pMaxHeightInRow[i] = 0;
int nChildIdx = 0;
// Get max width in every column and max height in every row.
hChild = m_pStateTree->tree.GetChildItem(hItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
int nChildXPos = nChildIdx % nColNum;
int nChildYPos = nChildIdx / nColNum;
SME_STATE_T nChildState = GetChartInfoSeqNum(hChild);
// Keep track of max width in every column.
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nWidth > pMaxWidthInColumn[nChildXPos])
pMaxWidthInColumn[nChildXPos] = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nWidth;
// Keep track of max height in every row.
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nHeight > pMaxHeightInRow[nChildYPos])
pMaxHeightInRow[nChildYPos] = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nHeight;
nChildIdx ++;
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
// Assign column width and row height for every state.
hChild = m_pStateTree->tree.GetChildItem(hItem);
nChildIdx = 0;
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
int nChildXPos = nChildIdx % nColNum;
int nChildYPos = nChildIdx / nColNum;
SME_STATE_T nChildState = GetChartInfoSeqNum(hChild);
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nColWidth < pMaxWidthInColumn[nChildXPos])
((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nColWidth = pMaxWidthInColumn[nChildXPos];
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nRowHeight < pMaxHeightInRow[nChildYPos])
((STATE_CHART_INFO_T*)m_StateChartInfoList[nChildState])->nRowHeight = pMaxHeightInRow[nChildYPos];
nChildIdx ++;
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
// Scan child state width and height.
hChild = m_pStateTree->tree.GetChildItem(hItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
CalculateColWidthRowHeight(hChild, hStart);
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
if (pMaxWidthInColumn) delete pMaxWidthInColumn;
if (pMaxHeightInRow) delete pMaxHeightInRow;
pMaxWidthInColumn = 0;
pMaxHeightInRow = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Draw the state chart.
// INPUT: 1)pDC:
// 2)hItem: Handler of current state to be drawn
// 3)hStart: Handler of selected tree item
// 4)nOriginPosX:
// 5)nOriginPosY:
//
// OUTPUT:
// RETURN:
// NOTE: Filter out too deep states.
//
///////////////////////////////////////////////////////////////////////////////////////////
void CStateChartView::DrawStateChart(CDC* pDC,
HTREEITEM hItem,
HTREEITEM hStart,
int nOriginPosX,
int nOriginPosY)
{
// if (GetStateLevel(hItem, hStart) > g_nMaxLevelNum)
// return; // exceed the maximum level of state to be drawn
// Draw this state.
// The origin position is (nOriginPosX, nOriginPosY)
SME_STATE_T nState = GetChartInfoSeqNum(hItem);
CString sItemName;
// Get pure name of state or application
sItemName = m_pStateTree->tree.GetItemText(hItem);
if (m_pStateTree->tree.GetItemData(hItem) & STATE_TREE_STATE_MASK)
{
sItemName.Replace("(default)", NULL);
sItemName.TrimLeft();
sItemName.TrimRight();
}
CRect StateRect(nOriginPosX, nOriginPosY,
nOriginPosX + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth,
nOriginPosY + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight);
// Draw an arrow for default state.
if ((m_pStateTree->tree.GetItemData(hItem) & STATE_TREE_DEFAULT_STATE) != 0)
{
POINT ArrowPoints[3] = {{nOriginPosX-8,nOriginPosY-6},
{nOriginPosX,nOriginPosY},
{nOriginPosX-8,nOriginPosY+6}};
CRgn ArrowRgn;
ArrowRgn.CreatePolygonRgn(ArrowPoints,3,WINDING);
CBrush Brush(RGB(200,0,0)); //grey red
pDC->FillRgn(&ArrowRgn,&Brush);
ArrowRgn.DeleteObject();
}
int nArcHeight = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight >> 2;
if (nState == m_nSelStateSeqNo && m_nSelStateSeqNo != -1)
{
CBrush newBrush;
CBrush* oldBrush;
newBrush.CreateSolidBrush(RGB(255, 255, 100)); //light yellow
oldBrush=pDC->SelectObject(&newBrush );
pDC->RoundRect(&StateRect, CPoint(nArcHeight, nArcHeight));
pDC->SelectObject(oldBrush);
newBrush.DeleteObject();
}
else
{
pDC->RoundRect(&StateRect, CPoint(nArcHeight, nArcHeight));
}
/*
pDC->Pie(CRect(nOriginPosX, nOriginPosY, nOriginPosX+nArcHeight, nOriginPosY+nArcHeight),
CPoint(nOriginPosX+nArcHeight/2, nOriginPosY),
CPoint(nOriginPosX, nOriginPosY+nArcHeight/2));
/*
int nMiddleX = nOriginPosX + m_StateChartInfo[nState].nWidth/2;
int nRadius = m_StateChartInfo[nState].nHeight >> 2;
int nLimit = 35; // limit for the boundary of radius
nRadius = (nRadius > nLimit)?nLimit:nRadius;
pDC->Pie(CRect(nMiddleX-nRadius, nOriginPosY-nRadius, nMiddleX+nRadius, nOriginPosY+nRadius),
CPoint(nMiddleX-nRadius, nOriginPosY),
CPoint(nMiddleX+nRadius, nOriginPosY));
pDC->Pie(CRect(nMiddleX-nRadius, nOriginPosY+m_StateChartInfo[nState].nHeight-nRadius, nMiddleX+nRadius, nOriginPosY+m_StateChartInfo[nState].nHeight+nRadius),
CPoint(nMiddleX+nRadius, nOriginPosY+m_StateChartInfo[nState].nHeight),
CPoint(nMiddleX-nRadius, nOriginPosY+m_StateChartInfo[nState].nHeight));
/*
// Draw 4 arcs for rectangle angles in a counterclockwise direction.
int nArcHeight = m_StateChartInfo[nState].nHeight >> 3;
// Left top
pDC->Arc(CRect(nOriginPosX, nOriginPosY, nOriginPosX + (nArcHeight<<1), nOriginPosY + (nArcHeight<<1)),
CPoint(nOriginPosX+nArcHeight, nOriginPosY),
CPoint(nOriginPosX, nOriginPosY+nArcHeight));
pDC->MoveTo(CPoint(nOriginPosX, nOriginPosY+nArcHeight));
pDC->LineTo(CPoint(nOriginPosX, nOriginPosY+m_StateChartInfo[nState].nHeight-nArcHeight));
// Left bottom
pDC->Arc(CRect(nOriginPosX, nOriginPosY+m_StateChartInfo[nState].nHeight-(nArcHeight<<1),
nOriginPosX + (nArcHeight<<1), nOriginPosY + m_StateChartInfo[nState].nHeight),
CPoint(nOriginPosX, nOriginPosY+m_StateChartInfo[nState].nHeight-nArcHeight),
CPoint(nOriginPosX+nArcHeight, nOriginPosY+ m_StateChartInfo[nState].nHeight));
pDC->MoveTo(CPoint(nOriginPosX+nArcHeight, nOriginPosY+ m_StateChartInfo[nState].nHeight));
pDC->LineTo(CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth-nArcHeight, nOriginPosY+m_StateChartInfo[nState].nHeight));
// Right bottom
pDC->Arc(CRect(nOriginPosX + m_StateChartInfo[nState].nWidth - (nArcHeight<<1), nOriginPosY+ m_StateChartInfo[nState].nHeight-(nArcHeight<<1),
nOriginPosX + m_StateChartInfo[nState].nWidth, nOriginPosY + m_StateChartInfo[nState].nHeight),
CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth-nArcHeight, nOriginPosY+m_StateChartInfo[nState].nHeight),
CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth, nOriginPosY+m_StateChartInfo[nState].nHeight-nArcHeight));
pDC->MoveTo(CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth, nOriginPosY+m_StateChartInfo[nState].nHeight-nArcHeight));
pDC->LineTo(CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth, nOriginPosY+nArcHeight));
// Right top
pDC->Arc(CRect(nOriginPosX + m_StateChartInfo[nState].nWidth - (nArcHeight<<1),
nOriginPosY, nOriginPosX + m_StateChartInfo[nState].nWidth, nOriginPosY + (nArcHeight<<1)),
CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth, nOriginPosY+nArcHeight),
CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth-nArcHeight, nOriginPosY));
pDC->MoveTo(CPoint(nOriginPosX+m_StateChartInfo[nState].nWidth-nArcHeight, nOriginPosY));
pDC->LineTo(CPoint(nOriginPosX+nArcHeight, nOriginPosY));
*/
pDC->TextOut(nOriginPosX + STATE_CHART_HALF_MARGIN,
nOriginPosY + STATE_CHART_HALF_MARGIN,
sItemName);
// Keep track of state chart left-top position for drawing state trasnsition arrows.
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft = nOriginPosX;
((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop = nOriginPosY;
// exceed the maximum level of state to be drawn or state is a leaf
if ((m_pStateTree->tree.GetItemData(hItem) & STATE_TREE_HAS_DEFAULT_CHILD_STATE) == 0 ||
(GetStateLevel(hItem, hStart) > g_nMaxLevelNum - 1))
{
// This state is a leaf.
return;
}
// If state is not a leaf, draw child states.
CRect TextRect;
TextRect.SetRect(0,0,0,0);
// Calculate the size of rectangle in which draw the text.
pDC->DrawText(sItemName, -1, &TextRect, DT_CALCRECT | DT_SINGLELINE);
int nChildrenNum=0,nColNum,nRowNum;
HTREEITEM hChild = m_pStateTree->tree.GetChildItem(hItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
nChildrenNum++;
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
nColNum=(int)(sqrt((double)(nChildrenNum-1)))+1;
nRowNum=(int)((nChildrenNum-1)/nColNum)+1;
// Determine the original positions among child states.
int nXCount=0;
int nYCount=0;
int nChildOriginX = nOriginPosX + STATE_CHART_MARGIN;
int nChildOriginY = nOriginPosY + STATE_CHART_MARGIN + TextRect.Height();
hChild = m_pStateTree->tree.GetChildItem(hItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
int i = GetChartInfoSeqNum(hChild);
// Draw the child state
DrawStateChart(pDC,hChild, hStart, nChildOriginX, nChildOriginY);
nXCount++;
if (nXCount != nColNum)
{
nChildOriginX += ((STATE_CHART_INFO_T*)m_StateChartInfoList[i])->nColWidth + STATE_CHART_MARGIN;
}
else
{
// Move to next line.
// Go back to original X-position.
nChildOriginX = nOriginPosX + STATE_CHART_MARGIN;
nChildOriginY += ((STATE_CHART_INFO_T*)m_StateChartInfoList[i])->nRowHeight + STATE_CHART_MARGIN;
nXCount =0;
nYCount ++;
}
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Draw the arrow from source state to destination state.
// INPUT: 1) pDC:
// 2) hSrcItem: Tree handler item of source state to be drawn
// 3) hSelItem: Current selected item
// OUTPUT:
// RETURN:
// NOTE: If the level of source state is over g_nMaxLevelNum, then all about its status will be
// hidden.
//
///////////////////////////////////////////////////////////////////////////////////////////
void CStateChartView::DrawArrow(CDC* pDC,
HTREEITEM hSrcItem,
HTREEITEM hSelItem)
{
if (GetStateLevel(hSrcItem, hSelItem) > g_nMaxLevelNum)
return; // exceed the maximum level of state to be drawn
SME_STATE_T nSrcState;
nSrcState = GetChartInfoSeqNum(hSrcItem);
HTREEITEM hEvent = m_pStateTree->tree.GetChildItem(hSrcItem);
while (true)
{
if (NULL == hEvent)
break;
if (m_pStateTree->tree.GetItemData(hEvent) & STATE_TREE_EVENT_ID_MASK)
{
HTREEITEM hDestState = m_pStateTree->tree.GetChildItem(hEvent);
CString sDestStateName = m_pStateTree->tree.GetItemText(hDestState);
if (sDestStateName != STR_INTERNAL_TRAN)
{
sDestStateName.Replace("Transit to:", NULL);
sDestStateName.TrimLeft();
sDestStateName.TrimRight();
HTREEITEM hDestItem = NULL;
if (GetDestStateItem(hSelItem, sDestStateName, hDestItem) == FALSE)
{
if (GetStateLevel(hDestItem, hSelItem) > g_nMaxLevelNum)
{
hEvent = m_pStateTree->tree.GetNextSiblingItem(hEvent);
continue; // exceed the maximum level of state to be drawn
}
SME_STATE_T nDestState;
nDestState = GetChartInfoSeqNum(hDestItem);
int nSrcX = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nLeft;
int nSrcY = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nTop;
int nDestX = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nLeft;
int nDestY = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nTop;
BOOL bAdjustXYBoth= FALSE;
if (nSrcState == nDestState)
{
int nRadius = ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nHeight >> 2;
int nLimit = 35; // limit for the boundary of radius
nRadius = (nRadius > nLimit)?nLimit:nRadius;
pDC->Arc(
CRect(nSrcX-nRadius, nSrcY+nRadius, nSrcX+nRadius, nSrcY-nRadius),
CPoint(nSrcX+nRadius, nSrcY),
CPoint(nSrcX, nSrcY+nRadius));
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nStartX = nSrcX;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nStartY = nSrcY+nRadius;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nEndX = nSrcX+nRadius;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nEndY = nSrcY;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nRadius = nRadius;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nSrcState = nSrcState;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nDestState = nDestState;
m_EventLineNo++;
nDestX += nRadius;
nSrcX = nDestX;
nSrcY = nDestY+40;
// Draw arrow header the angle is 30.
const double fDiff = 3.1415926535 * 20 / 180;
double fXLen = tan(fDiff)*10;
POINT ArrowPoints[3] = {
{nDestX, nDestY},
{(int)(nDestX + fXLen), (int)(nDestY - 10)},
{(int)(nDestX - fXLen), (int)(nDestY - 10)}};
CRgn ArrowRgn;
ArrowRgn.CreatePolygonRgn(ArrowPoints,3,WINDING);
CBrush Brush(RGB(0,0,0));
pDC->FillRgn(&ArrowRgn,&Brush);
ArrowRgn.DeleteObject();
hEvent = m_pStateTree->tree.GetNextSiblingItem(hEvent);
continue;
}
// case 1: Dest state is on the left of the src state without any intersection.
if (nSrcX > nDestX + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nWidth)
// Draw it from right to left.
// Draw it from the left side of src state chart to the right side of dest state chart.
nDestX += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nWidth;
// case 4: Dest state is below the src state without some intersection.
else if (nSrcX + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nWidth < nDestX)
// Draw it from left to right.
// Draw it from the right side of src state chart to the left side of dest state chart.
nSrcX += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nWidth;
else
{
// case 2: Dest state is on the left the src state with some intersection.
// case 3: Dest state is on the right the src state with some intersection.
// Draw it from the center of top/down side of src state chart to the center of down/top side of dest state chart.
//if (nSrcY > nDestY + (STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState]->nHeight
// || nSrcY + (STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState]->nHeight < nDestY)
{
nSrcX += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nWidth >> 1;
nDestX += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nWidth >> 1;
bAdjustXYBoth = TRUE;
}
};
// case 1: Dest state is above the src state without any intersection.
if (nSrcY > nDestY + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nHeight)
// Draw it from bottom to top.
// Draw it from the top side of src state chart to the bottom side of dest state chart.
nDestY += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nHeight;
// case 4: Dest state is below the src state without some intersection.
else if (nSrcY + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nHeight < nDestY)
// Draw it from top to down.
// Draw it from the bottom side of src state chart to the top side of dest state chart.
nSrcY += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nHeight;
else
{
// case 2: Dest state is above the src state with some intersection.
// case 3: Dest state is below the src state with some intersection.
// And there is no inersection in terms of horizontal direction.
// Draw it from the center of left/right side of src state chart to the center of right/left side of dest state chart.
//if (nSrcX > nDestX + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nWidth
// || nSrcX + ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nWidth < nDestX)
if (!bAdjustXYBoth)
{
nSrcY += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nSrcState])->nHeight >> 1;
nDestY += ((STATE_CHART_INFO_T*)m_StateChartInfoList[nDestState])->nHeight >> 1;
};
};
pDC->MoveTo(nSrcX, nSrcY);
pDC->LineTo(nDestX, nDestY);
// Test ?????????????
int nDiff = nSrcX - nDestX;
if (abs(nDiff) < 4)
{
nSrcX = (nSrcX + nDestX)/2;
nDestX = nSrcX;
}
nDiff = nSrcY - nDestY;
if (abs(nDiff) < 4)
{
nSrcY = (nDestY + nSrcY)/2;
nDestY = nSrcY;
}
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nStartX = nSrcX;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nStartY = nSrcY;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nEndX= nDestX;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nEndY = nDestY;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nRadius = 0;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nSrcState = nSrcState;
((EVENT_LINE_INFO_T*)m_EventLineInfoList[m_EventLineNo])->nDestState = nDestState;
m_EventLineNo++;
// Draw arrow header the angle is 30.
double fAngle = atan2((double)(nSrcY-nDestY), (double)(nDestX - nSrcX));
const double fDiff = 3.1415926535 * 20 / 180;
POINT ArrowPoints[3] = {
{nDestX, nDestY},
{(int)(nDestX - cos(fDiff-fAngle)*10), (int)(nDestY - sin(fDiff-fAngle)*10)},
{(int)(nDestX - cos(fDiff+fAngle)*10), (int)(nDestY + sin(fDiff+fAngle)*10)}};
CRgn ArrowRgn;
ArrowRgn.CreatePolygonRgn(ArrowPoints,3,WINDING);
CBrush Brush(RGB(0,0,0));
pDC->FillRgn(&ArrowRgn,&Brush);
ArrowRgn.DeleteObject();
}
}
}
hEvent = m_pStateTree->tree.GetNextSiblingItem(hEvent);
}
HTREEITEM hChild = m_pStateTree->tree.GetChildItem(hSrcItem);
while (true)
{
if (NULL == hChild)
break;
if (m_pStateTree->tree.GetItemData(hChild) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK))
{
DrawArrow(pDC, hChild, hSelItem);
}
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get sequence number in StateChartInfo array
// INPUT: 1) hItem: Current handler of selected item in state tree
// OUTPUT:
// RETURN:
// NOTE: Count the state or application items which is in front of the current state in state
// tree.
// Current state is the start node. Thus, sequence we get is the number from application
///////////////////////////////////////////////////////////////////////////////////////////
int CStateChartView::GetChartInfoSeqNum(HTREEITEM hItem)
{
int nSum = 0;
// m_pStateTree->tree.GetSelectedItem() may change, use m_hTopStateItem instead.
m_pStateTree->tree.CountBeforehandAppState(m_hTopStateItem, hItem, &nSum);
return nSum;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Draw the arrow from source state to destination state.
// INPUT: 1) hSelItem: Item handler in state tree to be started from
// 2) sDestStateName: State name of transited state
// 3) hDestStateItem: Handler of transited state
// OUTPUT: 1) TRUE 2) FALSE
// RETURN:
// NOTE: Get destinate state handler if it is a child of selected item in state tree. If it
// is not, then the variable hDestStateItem will be assigned null.
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL CStateChartView::GetDestStateItem(HTREEITEM hSelItem,
LPCTSTR sDestStateName,
HTREEITEM &hDestStateItem)
{
if ((m_pStateTree->tree.GetItemData(hSelItem) & (STATE_TREE_APPLICATION_MASK|STATE_TREE_STATE_MASK)) != 0)
{
// Get text of current selected tree item
CString sCurrentName = "";
// Selected item is a state
if ((m_pStateTree->tree.GetItemData(hSelItem) & STATE_TREE_STATE_MASK) != 0)
{
CString sStateName = m_pStateTree->tree.GetItemText(hSelItem);
if ((m_pStateTree->tree.GetItemData(hSelItem) & STATE_TREE_DEFAULT_STATE) != 0)
sStateName.Replace("(default)", NULL);
sStateName.TrimLeft();
sStateName.TrimRight();
sCurrentName = sStateName;
}
// Selected item is an application
if ((m_pStateTree->tree.GetItemData(hSelItem) & STATE_TREE_APPLICATION_MASK) != 0)
{
sCurrentName = m_pStateTree->tree.GetItemText(hSelItem);
}
if(sCurrentName.CompareNoCase(sDestStateName) == 0)
{
hDestStateItem = hSelItem;
return FALSE;
}
}
// Recursive check tree items
HTREEITEM hChild;
hChild = m_pStateTree->tree.GetChildItem(hSelItem);
while (true)
{
if (NULL == hChild)
break;
if(GetDestStateItem(hChild, sDestStateName, hDestStateItem) == FALSE)
return FALSE;
hChild = m_pStateTree->tree.GetNextSiblingItem(hChild);
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get current state's level based on selected item in state tree
// INPUT: 1) hItem: Current item to be counted its level
// 2) hStart: Selected item in state tree.
//
// OUTPUT:
// RETURN:
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
int CStateChartView::GetStateLevel(HTREEITEM hItem, HTREEITEM hStart)
{
if (hItem == hStart) // the same node in state tree
return 0;
HTREEITEM hParent;
int nLevel = 1; // initialize to be one
hParent = m_pStateTree->tree.GetParentItem(hItem);
while (true)
{
if (NULL == hParent)
break;
if (hParent == hStart)
break;
nLevel++;
hParent = m_pStateTree->tree.GetParentItem(hParent);
}
return nLevel;
}
void CStateChartView::PostNcDestroy()
{
// TODO: Add your specialized code here and/or call the base class
// do not delete off the heap...
// CScrollView::PostNcDestroy();
}
/********************************************************************************************
DESCRIPTION: Pop action list by a menu on the selected object,app, state, state chart.
INPUT:
OUTPUT:
NOTE:
**********************************************************************************************/
void CStateChartView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
SME_STATE_T nSelState = m_nSelStateSeqNo;
HTREEITEM hSelecter = m_pStateTree->tree.GetSelectedItem();
// When users has left-clicked on item , right click will do nothing
if (nSelState == -1)
{
CPoint local = point;
CClientDC dc(this);
OnPrepareDC(&dc);
dc.DPtoLP(&local);// get local position
SME_STATE_T nState = 0;
while(true)
{
if (nState >= m_StateChartInfoList.GetSize())
break;
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop == 0)
{
// State which exceeds state hierarchy level
nState++;
continue;
}
if (local.x > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft && local.x < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth)
&& local.y > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop && local.y < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight))
nSelState = nState;
nState++;
} //while true.
}// if nSelState==-1
// Update color here to turn yellow when right click on item
if (m_nSelStateSeqNo != nSelState)
{
m_nSelStateSeqNo = nSelState;
Invalidate();
UpdateWindow();
}
CMenu Menu;
if (nSelState != -1)
{
DWORD lMask;
Menu.CreatePopupMenu();
lMask = m_pStateTree->tree.GetItemData(hSelecter);
if (lMask & STATE_TREE_APPLICATION_MASK && nSelState == 0)
{
Menu.AppendMenu(MF_POPUP, IDD_ADD_STATE, "New State");
Menu.AppendMenu(MF_POPUP, IDD_DEL_APP, "Remove Application");
Menu.AppendMenu(MF_POPUP, IDD_ADD_HANDLE, "Add Event Handler");
Menu.AppendMenu(MF_SEPARATOR);
Menu.AppendMenu(MF_POPUP, IDD_GOTO_ENTRY, "Go To Entry");
Menu.AppendMenu(MF_POPUP, IDD_GOTO_EXIT, "Go To Exit");
}
else
{
Menu.AppendMenu(MF_POPUP, IDD_ADD_STATE, "New State");
Menu.AppendMenu(MF_POPUP, IDD_DEFLT_CHANGE, "Set As Default");
Menu.AppendMenu(MF_POPUP, IDD_DEL_STATE, "Delete State");
Menu.AppendMenu(MF_POPUP, IDD_ADD_HANDLE, "Add Event Handler");
Menu.AppendMenu(MF_SEPARATOR);
Menu.AppendMenu(MF_POPUP, IDD_GOTO_ENTRY, "Go To Entry");
Menu.AppendMenu(MF_POPUP, IDD_GOTO_EXIT, "Go To Exit");
long nSeq = m_nSelStateSeqNo;
HTREEITEM hNewSelState;
hNewSelState = m_pStateTree->tree.GetSpecifiedState(
m_pStateTree->tree.GetSelectedApp(hSelecter),
&nSeq
);
if (m_pStateTree->tree.GetItemData(hNewSelState) & STATE_TREE_DEFAULT_STATE)
Menu.EnableMenuItem(IDD_DEFLT_CHANGE, MF_GRAYED);
// Gray goto exit or entry menu item if they are empty function
HTREEITEM hEntry;
HTREEITEM hExit;
CString sEntry;
CString sExit;
hEntry = m_pStateTree->tree.GetChildItem(hNewSelState);
hExit = m_pStateTree->tree.GetNextSiblingItem(hEntry);
sEntry = m_pStateTree->tree.GetItemText(hEntry);
sExit = m_pStateTree->tree.GetItemText(hExit);
sEntry.TrimLeft();
sEntry.TrimRight();
sExit.TrimLeft();
sExit.TrimRight();
sEntry.Replace("Entry:", NULL);
sExit.Replace("Exit:", NULL);
if (sEntry.IsEmpty())
Menu.EnableMenuItem(IDD_GOTO_ENTRY, MF_GRAYED);
if (sExit.IsEmpty())
Menu.EnableMenuItem(IDD_GOTO_EXIT, MF_GRAYED);
}
}
else // on any state selected.
{
Menu.CreatePopupMenu();
Menu.AppendMenu(MF_POPUP, IDD_MENU_SAVEASBMP, "Save as BMP file");
Menu.AppendMenu(MF_POPUP, IDD_MENU_SAVEASTXT, "Save as TXT file");
}
Menu.EnableMenuItem(IDD_DRAW_CHART, MF_GRAYED);
CPoint curPos;
GetCursorPos(&curPos);
Menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERTICAL,curPos.x,curPos.y,this);
CScrollView::OnRButtonDown(nFlags, point);
}
/********************************************************************************************
DESCRIPTION: If the mouse is over a line, display the state transitions. If the mouse is over a
state chart, drag the selected state to be a child of state.
INPUT:
OUTPUT:
NOTE:
m_hItemDrag: The state that is being draging. If it is NULL, there is no state draging.
A special case: When the mouse is out of state chart window, press down, move the mouse to the state chart,
relase the mouse, m_hItemDrag should be NULL.
**********************************************************************************************/
void CStateChartView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_bMouseMove = FALSE;
m_dwDragStart = GetTickCount();
m_hItemDrag = NULL;
// TODO: Add your message handler code here and/or call default
CPoint local = point;
CClientDC dc(this);
OnPrepareDC(&dc);
dc.DPtoLP(&local);// get local position
if (PointIsOnLine(local, 5))
;
else
{
HTREEITEM hSelecter = m_pStateTree->tree.GetSelectedItem();
SME_STATE_T nState = 0;
SME_STATE_T nSelState = -1;
while(true)
{
if (nState >= m_StateChartInfoList.GetSize())
break;
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop == 0)
{
// State which exceeds state hierarchy level
nState++;
continue;
}
if (local.x > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft && local.x < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth)
&& local.y > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop && local.y < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight))
nSelState = nState;
nState++;
}
if (m_nSelStateSeqNo != nSelState)
{
m_nSelStateSeqNo = nSelState;
Invalidate();
UpdateWindow();
}
long nSelStatel = nSelState;
m_hItemDrag =
m_pStateTree->tree.GetSpecifiedState(m_pStateTree->tree.GetSelectedItem(),&nSelStatel);
if (m_hItemDrag == NULL)
return;
}
/*
if (g_nIsCriticalSection == 0)
{
g_nIsCriticalSection = 1;
if (PointIsOnLine(local, 5))
{
m_ActionNameList.RemoveAll();
CRect rect;
m_ListBox.GetWindowRect(&rect);
CString sText;
CSize sz;
int nMaxLen=0;
CDC* pDC = m_ListBox.GetDC();
for (int i= 1; i < m_ListBox.GetCount();i++)
{
m_ListBox.GetText(i, sText);
sz = pDC->GetTextExtent(sText);
CString sSrcState;
CString sEventName;
int idx = sText.Find("->");
ASSERT( -1 != idx);
sSrcState = sText.Left(idx);
idx = sText.Find(":");
sEventName = sText.Right(sText.GetLength()-idx-1);
sSrcState.TrimLeft();
sSrcState.TrimRight();
sEventName.TrimLeft();
sEventName.TrimRight();
for (long j = 0 ; j < m_StateNameList.GetSize(); j++)
{
CString sName = m_StateNameList[j];
if (sName == sSrcState)
break;
}
HTREEITEM hNewSelState =
m_pStateTree->tree.GetSpecifiedState(m_pStateTree->tree.GetSelectedItem(),&j);
HTREEITEM hAction;
HTREEITEM hItem;
// Get Entry Item and Entry is the first child of current state
hItem = m_pStateTree->tree.GetChildItem(hNewSelState);
while (true)
{
if (NULL == hItem)
break;
if (m_pStateTree->tree.GetItemData(hItem) & STATE_TREE_EVENT_ID_MASK)
{
CString sName = m_pStateTree->tree.GetItemText(hItem);
if (sName == sEventName)
{
hAction = m_pStateTree->tree.GetChildItem(hItem);
hAction = m_pStateTree->tree.GetNextSiblingItem(hAction);
break;
}
}
hItem = m_pStateTree->tree.GetNextSiblingItem(hItem);
}
CString sFuncName;
sFuncName = m_pStateTree->tree.GetItemText(hAction);
sFuncName.TrimRight();
sFuncName.TrimLeft();
idx = sFuncName.ReverseFind(':');
if (sFuncName.Right(sFuncName.GetLength()-idx-1).IsEmpty())
{
m_ListBox.EnableItem(i, FALSE);
m_ActionNameList.Add(" ");
}
else
m_ActionNameList.Add(sFuncName);
if (sz.cx > nMaxLen)
nMaxLen = sz.cx;
}
m_ListBox.ReleaseDC(pDC);
m_ListBox.MoveWindow(CRect(local.x, local.y, local.x+nMaxLen+ICON_SIZE, local.y+rect.Height()), TRUE);
m_ListBox.ShowWindow(SW_SHOWNA);
}
else
{
m_ListBox.ShowWindow(SW_HIDE);
}
g_nIsCriticalSection = 0;
}
*/
CScrollView::OnLButtonDown(nFlags, point);
}
/********************************************************************************************
DESCRIPTION: Check whether a given point is on any line of state transitions.
If meets, pops the state transition list
INPUT:
OUTPUT: m_ActionNameList;
NOTE:
**********************************************************************************************/
BOOL CStateChartView::PointIsOnLine(CPoint point, int nError)
{
int i = 0;
int nMatch = 0;
int nDiff;
/* if (bIsListBox == TRUE)
{
m_ListBox.ResetContent();
m_ListBox.AddString(_T("State Transition:"), -1);
}
*/
BOOL bFound = FALSE;
BOOL bNeedCheck = FALSE;
CMenu Menu;
m_ActionNameList.RemoveAll();
while (true)
{
if (i >= m_EventLineNo)
break;
if (((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nRadius == 0)
{
int nMaxX;
int nMinX;
int nMaxY;
int nMinY;
if (((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndX >= ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartX)
{
nMaxX = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndX;
nMinX = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartX;
}
else
{
nMinX = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndX;
nMaxX = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartX;
}
if (((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndY >= ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartY)
{
nMaxY = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndY;
nMinY = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartY;
}
else
{
nMinY = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndY;
nMaxY = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartY;
}
if (nMaxX == nMinX)
{
if (point.y >= nMinY && point.y <= nMaxY)
{
nDiff = point.x-nMaxX;
if (abs(nDiff) < nError)
bFound = TRUE;
}
else
{
i++;
continue;
}
}
else if (nMaxY == nMinY)
{
if (point.x >= nMinX && point.x <= nMaxX )
{
nDiff = point.y-nMaxY;
if (abs(nDiff) < nError)
bFound = TRUE;
}
else
{
i++;
continue;
}
}
else if (point.x >= nMinX && point.x <= nMaxX && point.y >= nMinY && point.y <= nMaxY)
{
double k = (((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndY-((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartY)/(double)(((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndX-((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartX);
/* double Y = k*(point.x-((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndX)+ ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndY;
nDiff = (int)Y-point.y;
if (abs(nDiff) < nError)
bFound = TRUE;
*/
// ��P��x0��y0����ֱ��Ax��By��C=0�ľ���: d = |Ax0 +By0 +C| /sqrt(A*A+B*B)
// In this case: k = -(A/B)
double Y = k*point.x-point.y
-k*((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndX+((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nEndY;
double X = k*k+1;
X = sqrt((double)X);
nDiff = (abs((int)Y))/(int)X;
if (abs(nDiff) < nError)
bFound = TRUE;
}
}
else
{
CPoint p;
p.x = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartX;
p.y = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nStartY -
((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nRadius;
double nDiff;
double nDist;
int nMulRes = (point.x-p.x)*(point.x-p.x)+(point.y-p.y)*(point.y-p.y);
nDist = sqrt((double)nMulRes);
nDiff = nDist-((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nRadius;
if (abs((int)nDiff) < nError)
{
if (point.x > p.x && point.y >p.y)
;
else bFound = TRUE;
}
}
if (bFound == TRUE)
{
bFound = FALSE;
if (nMatch == 0)
{
Menu.CreatePopupMenu();
}
long nSrcState = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nSrcState;
long nDestState = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nDestState;
CString sText = m_StateNameList[nSrcState];
sText += " -> ";
sText += m_StateNameList[nDestState];
sText += ": ";
sText += m_EventNameList[i];
Menu.AppendMenu(MF_POPUP, WM_STATE_TRAN_ITEM_0+nMatch, sText);
HTREEITEM hNewSelState =
m_pStateTree->tree.GetSpecifiedState(m_pStateTree->tree.GetSelectedItem(),&nSrcState);
HTREEITEM hAction;
HTREEITEM hItem;
// Get Entry Item and Entry is the first child of current state
hItem = m_pStateTree->tree.GetChildItem(hNewSelState);
while (true)
{
if (NULL == hItem)
break;
if (m_pStateTree->tree.GetItemData(hItem) & STATE_TREE_EVENT_ID_MASK)
{
CString sName = m_pStateTree->tree.GetItemText(hItem);
if (sName == m_EventNameList[i])
{
hAction = m_pStateTree->tree.GetChildItem(hItem);
hAction = m_pStateTree->tree.GetNextSiblingItem(hAction);
break;
}
}
hItem = m_pStateTree->tree.GetNextSiblingItem(hItem);
}
// Get function name depending on the class or non-class
CString sFuncName = m_pStateTree->tree.GetItemFuncName(hAction);
if (sFuncName.IsEmpty())
{
Menu.EnableMenuItem(nMatch, MF_GRAYED|MF_BYPOSITION);
}
m_ActionNameList.Add(sFuncName);
/* if (bIsListBox == TRUE)
{
int nSrcState = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nSrcState;
int nDestState = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nDestState;
CString sText = m_StateNameList[nSrcState];
sText += " -> ";
sText += m_StateNameList[nDestState];
sText += ": ";
sText += m_EventNameList[i];
m_ListBox.AddString(_T(sText), 0);
}
else
{
m_sShowText += m_EventNameList[i];
m_sShowText += "(";
int nSrcState = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nSrcState;
int nDestState = ((EVENT_LINE_INFO_T*)m_EventLineInfoList[i])->nDestState;
m_sShowText += m_StateNameList[nSrcState];
m_sShowText += "->";
m_sShowText += m_StateNameList[nDestState];
m_sShowText += ")\n";
}
*/
nMatch++;
}
i++;
}
if (nMatch == 0)
return FALSE;
CPoint curPos;
GetCursorPos(&curPos);
Menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERTICAL,curPos.x,curPos.y,this);
return TRUE;
}
/********************************************************************************************
DESCRIPTION: If the mouse is draging a state, move the selected state to be a child of state.
INPUT:
OUTPUT:
NOTE:
m_hItemDrag: The state that is being draging. If it is NULL, there is no state draging.
A special case: When the mouse is out of state chart window, press down, move the mouse to the state chart,
relase the mouse, m_hItemDrag should be NULL.
**********************************************************************************************/
void CStateChartView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (m_hItemDrag==NULL)
return;
// Confirm not to respond to events by enlarging window
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
if (m_bSizeChange == 1)
{
m_bSizeChange = -1;
return;
}
CPoint local = point;
CClientDC dc(this);
OnPrepareDC(&dc);
dc.DPtoLP(&local);// get local position
HTREEITEM hSelecter = m_pStateTree->tree.GetSelectedItem();
SME_STATE_T nState = 0;
SME_STATE_T nSelState = -1;
while(true)
{
if (nState >= m_StateChartInfoList.GetSize())
break;
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop == 0)
{
// State which exceeds state hierarchy level
nState++;
continue;
}
if (local.x > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft && local.x < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth)
&& local.y > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop && local.y < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight))
nSelState = nState;
nState++;
}
if ((m_bMouseMove == TRUE) && (nSelState != -1))
{
long nSelStatel = nSelState;
HTREEITEM hNewSelState =
m_pStateTree->tree.GetSpecifiedState(m_pStateTree->tree.GetSelectedItem(),&nSelStatel);
if ((m_pStateTree->tree.GetParentItem(m_hItemDrag) != hNewSelState) && (m_hItemDrag != hNewSelState))
{
// Confirm whether hNewParent is child of hItem then deny
HTREEITEM hParent = m_pStateTree->tree.GetParentItem(hNewSelState);
BOOL bIsParent = FALSE;
while(true)
{
if (m_pStateTree->tree.GetItemData(hParent) & STATE_TREE_WORKSPACE_MASK)
break;
if (hParent == m_hItemDrag)
{
bIsParent = TRUE;
break;
}
hParent = m_pStateTree->tree.GetParentItem(hParent);
}
if (bIsParent == FALSE)
{
m_pStateTree->MoveItem(m_hItemDrag, hNewSelState);
m_bMouseMove = FALSE;
//Restore the old selected tree item.
m_pStateTree->tree.SelectItem(hSelecter);
m_EventNameList.RemoveAll();
m_StateNameList.RemoveAll();
InitStateNameList(hSelecter);
InitEventNameList(hSelecter, hSelecter);
ZeroCharInfoList();
ZeroEventInfoList();
// Eliminate limits on level allowed to be showed
// g_nMaxLevelNum = 255; ???????
}
}
else //not move to an other state.
{
m_hItemDrag=NULL;
CScrollView::OnLButtonUp(nFlags, point);
return;
}
}
else //if ((m_bMouseMove == TRUE) && (nSelState != -1))
{
m_hItemDrag=NULL;
CScrollView::OnLButtonUp(nFlags, point);
return;
}
m_nSelStateSeqNo = nSelState;
m_hItemDrag=NULL;
Invalidate();
UpdateWindow();
CScrollView::OnLButtonUp(nFlags, point);
}
void CStateChartView::OnMouseMove(UINT nFlags, CPoint point)
{
if(((GetTickCount() - m_dwDragStart) < DRAG_DELAY) || m_hItemDrag == NULL)
return;
if (nFlags == MK_LBUTTON)
{
::SetCursor(::LoadCursor(NULL, IDC_SIZEALL));
HTREEITEM hSelecter = m_pStateTree->tree.GetSelectedItem();
SME_STATE_T nState = 0;
SME_STATE_T nSelState = -1;
while(true)
{
if (nState >= m_StateChartInfoList.GetSize())
break;
if (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop == 0)
{
// State which exceeds state hierarchy level
nState++;
continue;
}
if (point.x > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft && point.x < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nLeft+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nWidth)
&& point.y > ((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop && point.y < (((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nTop+((STATE_CHART_INFO_T*)m_StateChartInfoList[nState])->nHeight))
nSelState = nState;
nState++;
}
if (nSelState != -1)
{
long nSelStatel = nSelState;
HTREEITEM hNewSelState =
m_pStateTree->tree.GetSpecifiedState(m_pStateTree->tree.GetSelectedItem(),&nSelStatel);
if ((m_pStateTree->tree.GetParentItem(m_hItemDrag) != hNewSelState) && (m_hItemDrag != hNewSelState))
{
// Confirm whether hNewParent is child of hItem then deny
HTREEITEM hParent = m_pStateTree->tree.GetParentItem(hNewSelState);
BOOL bIsParent = FALSE;
while(true)
{
if (m_pStateTree->tree.GetItemData(hParent) & STATE_TREE_WORKSPACE_MASK)
break;
if (hParent == m_hItemDrag)
{
bIsParent = TRUE;
break;
}
hParent = m_pStateTree->tree.GetParentItem(hParent);
}
if (bIsParent == TRUE)
::SetCursor(::LoadCursor(NULL, IDC_NO));
}
}
else
::SetCursor(::LoadCursor(NULL, IDC_NO));
}
// TODO: Add your message handler code here and/or call default
m_bMouseMove = TRUE;
CScrollView::OnMouseMove(nFlags, point);
}