khanat-opennel-code/code/nel/tools/logic/logic_editor_dll/ConditionsView.cpp
2016-01-24 17:08:32 +01:00

748 lines
16 KiB
C++

// ConditionsView.cpp : implementation file
//
#include "stdafx.h"
#include "logic_editor.h"
#include "ConditionsView.h"
#include "Logic_editorDoc.h"
#include "MainFrm.h"
#include "ChildFrm.h"
#include "EditorFormView.h"
#include "TMenu.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef ID_MOVEASCHILD
#define ID_MOVEASCHILD 32857
#endif
#ifndef ID_MOVEASSIBLING
#define ID_MOVEASSIBLING 32858
#endif
#ifndef ID_COPYASSIBLING
#define ID_COPYASSIBLING 32859
#endif
#ifndef ID_COPYASCHILD
#define ID_COPYASCHILD 32860
#endif
/////////////////////////////////////////////////////////////////////////////
// CConditionsView
IMPLEMENT_DYNCREATE(CConditionsView, CTreeView)
CConditionsView::CConditionsView()
{
}
CConditionsView::~CConditionsView()
{
}
BEGIN_MESSAGE_MAP(CConditionsView, CTreeView)
//{{AFX_MSG_MAP(CConditionsView)
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
ON_WM_KILLFOCUS()
ON_NOTIFY_REFLECT(TVN_BEGINRDRAG, OnBeginrdrag)
ON_WM_MOUSEMOVE()
ON_WM_RBUTTONUP()
//}}AFX_MSG_MAP
ON_COMMAND(ID_MOVEASCHILD, OnMoveAsChild)
ON_COMMAND(ID_MOVEASSIBLING, OnMoveAsSibling)
ON_COMMAND(ID_COPYASCHILD, OnCopyAsChild)
ON_COMMAND(ID_COPYASSIBLING, OnCopyAsSibling)
END_MESSAGE_MAP()
// Creating Drag Image for a CTreeCtrl without images
// Contribution of Pal K Tonder on www.codeguru.com
// The method CreateDragImage is used during drag'n drop to create a drag image. The problem is that it only works for a CTreeCtrl with images.
// The following method, CreateDragImageEx, checks whether the CTreeCtrl has a valid normal CImageList. If so, it just calls the standard CreateDragImage method and returns.
// If, on the other hand, no valid CImageList is found, a bitmap is created based on the size of item rect, and the item text is drawn into it. Then a CImageList is
// created and the bitmap is added to it.
CImageList* CConditionsView::CreateDragImageEx(HTREEITEM hItem)
{
CTreeCtrl & tree = GetTreeCtrl();
if(tree.GetImageList(TVSIL_NORMAL) != NULL)
return tree.CreateDragImage(hItem);
CRect rect;
tree.GetItemRect(hItem, rect, TRUE);
rect.OffsetRect(-rect.left, -rect.top);
// Create bitmap
CClientDC dc (this);
CDC memDC;
if(!memDC.CreateCompatibleDC(&dc))
return NULL;
CBitmap bitmap;
if(!bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height()))
return NULL;
CBitmap* pOldMemDCBitmap = memDC.SelectObject( &bitmap );
CFont* pOldFont = memDC.SelectObject(GetFont());
memDC.FillSolidRect(&rect, RGB(0, 255, 0)); // Here green is used as mask color
memDC.SetTextColor(GetSysColor(COLOR_GRAYTEXT));
memDC.TextOut(rect.left, rect.top, tree.GetItemText(hItem));
memDC.SelectObject( pOldFont );
memDC.SelectObject( pOldMemDCBitmap );
// Create imagelist
CImageList* pImageList = new CImageList;
pImageList->Create(rect.Width(), rect.Height(),
ILC_COLOR | ILC_MASK, 0, 1);
pImageList->Add(&bitmap, RGB(0, 255, 0)); // Here green is used as mask color
return pImageList;
}
/////////////////////////////////////////////////////////////////////////////
// CConditionsView drawing
void CConditionsView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
}
/////////////////////////////////////////////////////////////////////////////
// CConditionsView diagnostics
#ifdef _DEBUG
void CConditionsView::AssertValid() const
{
CTreeView::AssertValid();
}
void CConditionsView::Dump(CDumpContext& dc) const
{
CTreeView::Dump(dc);
}
#endif //_DEBUG
void CConditionsView::expand(UINT nCode, HTREEITEM hItem)
{
HTREEITEM hElement;
HTreeItemArray pile;
CTreeCtrl &m_tree = GetTreeCtrl();
if (hItem == NULL)
hElement = m_tree.GetRootItem();
else
{
m_tree.Expand(hItem,nCode);
hElement = m_tree.GetChildItem(hItem);
}
pile.RemoveAll();
while ((hElement != NULL) || (pile.GetSize() != 0))
{
while ((hElement == NULL) && (pile.GetSize()!=0))
{
hElement = pile[pile.GetSize()-1];
pile.RemoveAt(pile.GetSize()-1);
hElement = m_tree.GetNextSiblingItem(hElement);
}
if (hElement)
{
pile.Add(hElement);
m_tree.Expand(hElement,nCode);
hElement = m_tree.GetChildItem(hElement);
}
}
}
HMENU CConditionsView::GetRDragMenu()
{
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu( MF_STRING, ID_MOVEASCHILD, _T("Move As Child") );
menu.AppendMenu( MF_STRING, ID_MOVEASSIBLING, _T("Move As Sibling") );
menu.AppendMenu( MF_STRING, ID_COPYASCHILD, _T("Copy As Child") );
menu.AppendMenu( MF_STRING, ID_COPYASSIBLING, _T("Copy As Sibling") );
return menu.Detach();
}
/////////////////////////////////////////////////////////////////////////////
// CConditionsView message handlers
void CConditionsView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
m_pSelectedCondition = NULL;
m_pDragCondition = NULL;
m_pSelectedNode = NULL;
m_pDragImage = NULL;
m_hitemDrag = NULL;
m_hitemDrop = NULL;
m_bRDragging = FALSE;
m_bRDragCanceled = FALSE;
}
void CConditionsView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
/** TO DO : REDRAW ONLY IF Some CONDITIONS have changed **/
SetRedraw(FALSE);
CTreeView::OnUpdate(pSender,lHint,pHint);
BOOL bSelection = FALSE;
// get a pointer on associated document
CLogic_editorDoc *pDoc = static_cast<CLogic_editorDoc*>(GetDocument());
ASSERT_VALID(pDoc);
CTreeCtrl &m_tree = GetTreeCtrl();
m_tree.DeleteAllItems();
m_mapItemToNode.RemoveAll();
TPositionList heap;
HTREEITEM hItem = m_tree.InsertItem( "Conditions",0,0);
// get the states map
CCondition *pCondition;
CString condName;
POSITION pos = pDoc->m_conditions.GetStartPosition();
while (pos != NULL)
{
pDoc->m_conditions.GetNextAssoc( pos, condName, (void*&)pCondition );
hItem = m_tree.InsertItem( condName , m_tree.GetRootItem());
//
if ( m_pSelectedCondition == pCondition && m_pSelectedNode == NULL)
{
m_tree.SelectItem( hItem );
bSelection = TRUE;
}
CConditionNode *pNode, *pNodeTemp;
HTREEITEM parentHItem = hItem;
POSITION nodePos = pCondition->m_ctConditionTree.GetHeadPosition();
while (nodePos != NULL)
{
pNode = pCondition->m_ctConditionTree.GetNext( nodePos );
if (pNode != NULL)
{
hItem = m_tree.InsertItem( pNode->getNodeAsString() , parentHItem);
// memorize the association hItem/pNode in the map
m_mapItemToNode.SetAt( hItem, pNode);
if (m_pSelectedNode == pNode)
{
m_tree.SelectItem( hItem );
bSelection = TRUE;
}
for (;;)
{
// get the deepest first level node in the sub tree
POSITION subPos = pNode->m_ctSubTree.GetHeadPosition();
while (subPos != NULL)
{
pNodeTemp = pNode->m_ctSubTree.GetNext(subPos);
if (pNodeTemp != NULL)
{
pNode = pNodeTemp;
hItem = m_tree.InsertItem( pNode->getNodeAsString() , hItem);
m_mapItemToNode.SetAt( hItem, pNode);
if (m_pSelectedNode == pNode)
{
m_tree.SelectItem( hItem );
bSelection = TRUE;
}
// push the position
heap.AddTail( subPos );
subPos = pNode->m_ctSubTree.GetHeadPosition();
}
}
// get sibling if any, if none, get next node
do
{
pNode = pNode->getParentNode();
hItem = m_tree.GetParentItem( hItem );
// pop subPos
if( heap.IsEmpty() )
break;
subPos = heap.GetTail();
heap.RemoveTail();
if (subPos != NULL)
{
pNodeTemp = pNode->m_ctSubTree.GetNext( subPos );
if (pNodeTemp != NULL)
{
pNode = pNodeTemp;
hItem = m_tree.InsertItem( pNode->getNodeAsString() , hItem);
// memorize the association hItem/pNode in the map
m_mapItemToNode.SetAt( hItem, pNode);
if (m_pSelectedNode == pNode)
{
m_tree.SelectItem( hItem );
bSelection = TRUE;
}
//push
heap.AddTail( subPos );
subPos = pNode->m_ctSubTree.GetHeadPosition();
}
else
break;
}
}
while (subPos == NULL);
if (pNode == NULL)
break;
}
}
}
}
// expand all tree
expand(/*TVE_EXPAND ,NULL*/ );
if (!bSelection)
{
m_pSelectedNode = NULL;
m_pSelectedCondition = NULL;
}
else
{
// assure the selected item is visible (if any)
hItem = m_tree.GetSelectedItem();
ASSERT (hItem != NULL);
m_tree.EnsureVisible( hItem );
}
SetRedraw(/*TRUE*/);
}
BOOL CConditionsView::PreCreateWindow(CREATESTRUCT& cs)
{
// modify arborescence style
cs.style |=(TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS/*|TVS_EDITLABELS*/);
// cs.style &= ~TVS_DISABLEDRAGDROP;
return CTreeView::PreCreateWindow(cs);
}
void CConditionsView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
//
m_pSelectedCondition = NULL;
m_pSelectedNode = NULL;
// get the selected item and update the good frame (open the condition edition page in the form too)
CTreeCtrl &treeCtrl = GetTreeCtrl();
HTREEITEM hItem;
hItem = treeCtrl.GetSelectedItem();
//
if (hItem == treeCtrl.GetRootItem())
return;
// get the node selected (if any)
if ( ! m_mapItemToNode.Lookup(hItem, m_pSelectedNode) )
m_pSelectedNode = NULL;
// get the condition (if any)
while ( treeCtrl.GetParentItem( hItem ) != treeCtrl.GetRootItem() )
hItem = treeCtrl.GetParentItem( hItem );
CString condName = treeCtrl.GetItemText( hItem );
CLogic_editorDoc *pDoc = static_cast<CLogic_editorDoc *> (GetDocument());
// to update the fields of the condition page in the form view
CMainFrame *pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
// Get the active MDI child window.
CChildFrame *pChild = (CChildFrame *) pFrame->GetActiveFrame();
CEditorFormView *pFormView = static_cast<CEditorFormView *> ( pChild->m_wndSplitter.GetPane(0,1) );
CConditionPage *pCondPage = static_cast<CConditionPage*> ( pFormView->m_pPropertySheet->GetPage(2) );
if ( pDoc->m_conditions.Lookup( condName, (void*&) m_pSelectedCondition) )
{
pFormView->m_pPropertySheet->SetActivePage( pCondPage );
if ( pCondPage->m_pSelectedConditionNode != m_pSelectedNode || m_pSelectedNode == NULL)
{
pCondPage->m_pSelectedCondition = this->m_pSelectedCondition;
pCondPage->m_pSelectedConditionNode = this->m_pSelectedNode;
pCondPage->Update();
}
}
else
{
if (pCondPage->m_pSelectedCondition != NULL)
{
pCondPage->m_pSelectedConditionNode = this->m_pSelectedNode; // = NULL
pCondPage->m_pSelectedCondition = this->m_pSelectedCondition; // = NULL
pCondPage->Update();
}
}
this->SetFocus();
//
*pResult = 0;
}
void CConditionsView::OnKillFocus(CWnd* pNewWnd)
{
// keep the current selection, so do not call CTreeView::OnKillFocus()
// CTreeView::OnKillFocus(pNewWnd);
}
void CConditionsView::OnBeginrdrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
*pResult = 0;
CTreeCtrl &tree = GetTreeCtrl();
CPoint ptAction;
GetCursorPos(&ptAction);
ScreenToClient(&ptAction);
m_bRDragging = TRUE;
m_bRDragCanceled = FALSE;
m_hitemDrag = pNMTreeView->itemNew.hItem;
m_hitemDrop = NULL;
m_pDragImage = CreateDragImageEx(m_hitemDrag); // get the image list for dragging
m_pDragImage->BeginDrag(0, CPoint(10,-15));
tree.SelectDropTarget(NULL); // to prevent image corruption.
m_pDragImage->DragEnter(NULL, ptAction);
SetCapture();
// get the drag condition
HTREEITEM hItem = m_hitemDrag;
//
if (hItem == tree.GetRootItem())
return;
// get the condition (if any)
while ( tree.GetParentItem( hItem ) != tree.GetRootItem() )
hItem = tree.GetParentItem( hItem );
CString condName = tree.GetItemText( hItem );
CLogic_editorDoc *pDoc = static_cast<CLogic_editorDoc *> (GetDocument());
pDoc->m_conditions.Lookup( condName, (void*&) m_pDragCondition);
}
void CConditionsView::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM hitem;
UINT flags;
CTreeCtrl &tree = GetTreeCtrl();
if (m_bRDragging)
{
POINT pt = point;
ClientToScreen( &pt );
CImageList::DragMove(pt);
if ((hitem = tree.HitTest(point, &flags)) != NULL)
{
CImageList::DragShowNolock(FALSE);
tree.SelectDropTarget(hitem);
m_hitemDrop = hitem;
CImageList::DragShowNolock(TRUE);
}
}
CTreeView::OnMouseMove(nFlags, point);
}
void CConditionsView::OnRButtonUp(UINT nFlags, CPoint point)
{
CTreeCtrl &tree = GetTreeCtrl();
if (m_bRDragging)
{
m_bRDragging = FALSE;
CImageList::DragLeave(this);
CImageList::EndDrag();
ReleaseCapture();
delete m_pDragImage;
if( m_hitemDrag == m_hitemDrop )
return;
CTMenu menu;
menu.Attach( GetRDragMenu() );
menu.AddMenuTitle( tree.GetItemText(m_hitemDrag) );
// if the target is a condition and the dragged item is a node, do not allow '..as sibling' operations
CConditionNode *pNode;
if ( m_mapItemToNode.Lookup(m_hitemDrag, pNode) && ! m_mapItemToNode.Lookup(m_hitemDrop, pNode) )
{
menu.EnableMenuItem( ID_MOVEASSIBLING, MF_GRAYED );
menu.EnableMenuItem( ID_COPYASSIBLING, MF_GRAYED );
}
if( menu == NULL ) return;
ClientToScreen( &point );
menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
point.x, point.y,
this);
tree.SelectDropTarget(NULL);
}
else
CTreeView::OnRButtonUp(nFlags, point);
}
void CConditionsView::OnMoveAsChild()
{
CTreeCtrl &tree = GetTreeCtrl();
// Check that the dragged item is not an ancestor
HTREEITEM htiParent = m_hitemDrop;
while( (htiParent = tree.GetParentItem( htiParent )) != NULL )
{
if( htiParent == m_hitemDrag )
return;
}
CConditionNode* pTargetNode = NULL;
CCondition * pTargetCond = NULL;
CConditionNode *pDragNode;
// get the drag object
if ( m_mapItemToNode.Lookup( m_hitemDrag, pDragNode ) )
{
CConditionNode *pParentNode = pDragNode->getParentNode();
// parent is a node
if (pParentNode != NULL)
{
POSITION pos = pParentNode->m_ctSubTree.Find( pDragNode );
if (pos != NULL)
{
pParentNode->m_ctSubTree.RemoveAt( pos );
}
else
return;
}
// parent is a condition
else
{
POSITION pos = m_pDragCondition->m_ctConditionTree.Find( pDragNode );
if (pos != NULL)
{
m_pDragCondition->m_ctConditionTree.RemoveAt( pos );
}
else
return;
}
}
else
return;
CLogic_editorDoc *pDoc = static_cast<CLogic_editorDoc *> (GetDocument());
// target is a node
if ( m_mapItemToNode.Lookup( m_hitemDrop, pTargetNode ) )
{
pTargetNode->m_ctSubTree.AddTail( pDragNode );
pDragNode->m_pParentNode = pTargetNode;
}
// target is a condition
else
{
CString name = tree.GetItemText( m_hitemDrop );
if (pDoc->m_conditions.Lookup( name, (void*&)pTargetCond ) )
{
pTargetCond->m_ctConditionTree.AddTail( pDragNode );
pDragNode->m_pParentNode = NULL;
}
else
{
AfxMessageBox("Error : root condition not found");
delete pDragNode;
}
}
// for the moment, update all views, but moving branch may be faster
pDoc->UpdateAllViews(NULL);
/*
Expand( m_hitemDrop, TVE_EXPAND ) ;
HTREEITEM htiNew = CopyBranch( m_hitemDrag, m_hitemDrop, TVI_LAST );
DeleteItem(m_hitemDrag);
SelectItem( htiNew );
*/
}
void CConditionsView::OnMoveAsSibling()
{
CTreeCtrl &tree = GetTreeCtrl();
if (m_hitemDrop == tree.GetRootItem() )
return;
m_hitemDrop = tree.GetParentItem( m_hitemDrop);
OnMoveAsChild();
}
void CConditionsView::OnCopyAsChild()
{
CTreeCtrl &tree = GetTreeCtrl();
// Check that the dragged item is not an ancestor
HTREEITEM htiParent = m_hitemDrop;
while( (htiParent = tree.GetParentItem( htiParent )) != NULL )
{
if( htiParent == m_hitemDrag )
return;
}
CConditionNode* pTargetNode = NULL;
CCondition * pTargetCond = NULL;
CConditionNode *pDragNode = NULL;
CConditionNode *pNewNode = NULL;
// get the drag object
if ( m_mapItemToNode.Lookup( m_hitemDrag, pDragNode ) )
{
pNewNode = new CConditionNode(*pDragNode);
}
else
return;
CLogic_editorDoc *pDoc = static_cast<CLogic_editorDoc *> (GetDocument());
// target is a node
if ( m_mapItemToNode.Lookup( m_hitemDrop, pTargetNode ) )
{
pTargetNode->m_ctSubTree.AddTail( pNewNode );
pNewNode->m_pParentNode = pTargetNode;
}
// target is a condition
else
{
CString name = tree.GetItemText( m_hitemDrop );
if (pDoc->m_conditions.Lookup( name, (void*&)pTargetCond ) )
{
pTargetCond->m_ctConditionTree.AddTail( pNewNode );
pNewNode->m_pParentNode = NULL;
}
else
{
AfxMessageBox("Error : root condition not found");
delete pNewNode;
}
}
// for the moment, update all views, but moving branch may be faster
pDoc->UpdateAllViews(NULL);
/*
HTREEITEM htiNew = CopyBranch( m_hitemDrag, m_hitemDrop, TVI_LAST );
*/
}
void CConditionsView::OnCopyAsSibling()
{
CTreeCtrl &tree = GetTreeCtrl();
if (m_hitemDrop == tree.GetRootItem() )
return;
m_hitemDrop = tree.GetParentItem( m_hitemDrop);
OnCopyAsChild();
}