diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/grouplist.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/grouplist.cpp')
| -rw-r--r-- | hammer/grouplist.cpp | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/hammer/grouplist.cpp b/hammer/grouplist.cpp new file mode 100644 index 0000000..57c5aab --- /dev/null +++ b/hammer/grouplist.cpp @@ -0,0 +1,845 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements a list view for visgroups. Supports drag and drop, and +// posts a registered windows message to the list view's parent window +// when visgroups are hidden or shown. +// +//=============================================================================// + +#include "stdafx.h" +#include "hammer.h" +#include "GroupList.h" +#include "MapDoc.h" +#include "MapSolid.h" +#include "MapWorld.h" +#include "GlobalFunctions.h" +#include "VisGroup.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +// +// Timer IDs. +// +enum +{ + TIMER_GROUP_DRAG_SCROLL = 1, +}; + + +static const unsigned int g_uToggleStateMsg = ::RegisterWindowMessage(GROUPLIST_MSG_TOGGLE_STATE); +static const unsigned int g_uLeftDragDropMsg = ::RegisterWindowMessage(GROUPLIST_MSG_LEFT_DRAG_DROP); +static const unsigned int g_uRightDragDropMsg = ::RegisterWindowMessage(GROUPLIST_MSG_RIGHT_DRAG_DROP); +static const unsigned int g_uSelChangeMsg = ::RegisterWindowMessage(GROUPLIST_MSG_SEL_CHANGE); + + +BEGIN_MESSAGE_MAP(CGroupList, CTreeCtrl) + //{{AFX_MSG_MAP(CGroupList) + ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) + ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndlabeledit) + ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChange) + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_LBUTTONDBLCLK() + ON_WM_RBUTTONDOWN() + ON_WM_RBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_TIMER() + ON_WM_CONTEXTMENU() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CGroupList::CGroupList(void) +{ + m_pDragImageList = NULL; + m_hDragItem = NULL; + m_bRButtonDown = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CGroupList::~CGroupList(void) +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGroupList::EnableChecks(void) +{ + if (!m_cNormalImageList.GetSafeHandle()) + { + m_cNormalImageList.Create(IDB_VISGROUPSTATUS, 16, 1, RGB(255, 255, 255)); + m_cNormalImageList.SetOverlayImage(1, 1); + m_cNormalImageList.SetOverlayImage(2, 2); + } + + CTreeCtrl::SetImageList(&m_cNormalImageList, TVSIL_NORMAL); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pVisGroup - +// hItemParent - +//----------------------------------------------------------------------------- +void CGroupList::AddVisGroupRecursive(CVisGroup *pVisGroup, HTREEITEM hItemParent) +{ + HTREEITEM hItem = InsertItem(pVisGroup->GetName(), hItemParent, TVI_LAST); + if (hItem != NULL) + { + SetItemData(hItem, (DWORD)pVisGroup); + + // Add the item to our flattened list. +// VisGroupTreeItem_t item; +// item.pVisGroup = pVisGroup; +// item.hItem = hItem; +// m_TreeItems.AddToTail(item); + m_VisGroups.AddToTail(pVisGroup); + + int nCount = pVisGroup->GetChildCount(); + for (int i = 0; i < nCount; i++) + { + CVisGroup *pChild = pVisGroup->GetChild(i); + AddVisGroupRecursive(pChild, hItem); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pGroup - +//----------------------------------------------------------------------------- +void CGroupList::AddVisGroup(CVisGroup *pGroup) +{ + AddVisGroupRecursive(pGroup, TVI_ROOT); +} + + +static void UnsetItemData_R( CTreeCtrl *pCtrl, HTREEITEM hItem ) +{ + pCtrl->SetItemData( hItem, 0 ); + + HTREEITEM hChildItem = pCtrl->GetChildItem( hItem ); + + while( hChildItem != NULL ) + { + UnsetItemData_R( pCtrl, hChildItem ); + hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGroupList::DeleteAllItems(void) +{ + // Un-set all item data because sometimes during a delete it'll trigger selection change notifications + // which might crash things later. + if ( GetSafeHwnd() && m_VisGroups.Count() > 0 ) + { + UnsetItemData_R( this, TVI_ROOT ); + } + + DeleteItem(TVI_ROOT); + m_VisGroups.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGroupList::EnsureVisible(CVisGroup *pVisGroup) +{ + //DBG("EnsureVisible: %s\n", pVisGroup->GetName()); + HTREEITEM hItem = FindVisGroupItem(pVisGroup); + if (hItem) + { + CTreeCtrl::EnsureVisible(hItem); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGroupList::ExpandRecursive(HTREEITEM hItem) +{ + if (hItem) + { + Expand(hItem, TVE_EXPAND); + + if (ItemHasChildren(hItem)) + { + HTREEITEM hChildItem = GetChildItem(hItem); + while (hChildItem != NULL) + { + ExpandRecursive(hChildItem); + hChildItem = GetNextItem(hChildItem, TVGN_NEXT); + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGroupList::ExpandAll(void) +{ + HTREEITEM hItem = GetRootItem(); + while (hItem) + { + ExpandRecursive(hItem); + hItem = GetNextItem(hItem, TVGN_NEXT); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the tree item in the given subtree associated with the given +// visgroup, NULL if none. +//----------------------------------------------------------------------------- +HTREEITEM CGroupList::FindVisGroupItemRecursive(HTREEITEM hItem, CVisGroup *pVisGroup) +{ + if (hItem) + { + CVisGroup *pVisGroupCheck = (CVisGroup *)GetItemData(hItem); + if (pVisGroupCheck == pVisGroup) + { + return hItem; + } + + if (ItemHasChildren(hItem)) + { + HTREEITEM hChildItem = GetChildItem(hItem); + while (hChildItem != NULL) + { + HTREEITEM hFoundItem = FindVisGroupItemRecursive(hChildItem, pVisGroup); + if (hFoundItem) + { + return hFoundItem; + } + + hChildItem = GetNextItem(hChildItem, TVGN_NEXT); + } + } + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the tree item associated with the given visgroup, NULL if none. +//----------------------------------------------------------------------------- +HTREEITEM CGroupList::FindVisGroupItem(CVisGroup *pVisGroup) +{ + HTREEITEM hItem = GetRootItem(); + while (hItem) + { + HTREEITEM hFound = FindVisGroupItemRecursive(hItem, pVisGroup); + if (hFound) + { + return hFound; + } + + hItem = GetNextItem(hItem, TVGN_NEXT); + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the currently selected visgroup in the tree control. +//----------------------------------------------------------------------------- +CVisGroup *CGroupList::GetSelectedVisGroup(void) +{ + HTREEITEM hItem = GetSelectedItem(); + if (hItem) + { + return (CVisGroup *)GetItemData(hItem); + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnLButtonDown(UINT nFlags, CPoint point) +{ + unsigned int uFlags; + HTREEITEM hItemHit = HitTest(point, &uFlags); + if (hItemHit != NULL) + { + if (uFlags & TVHT_ONITEMICON) + { + // Don't forward to the base if they clicked on the check box. + // This prevents undesired expansion/collapse of tree. + return; + } + } + + CTreeCtrl::OnLButtonDown(nFlags, point); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnLButtonUp(UINT nFlags, CPoint point) +{ + KillTimer(TIMER_GROUP_DRAG_SCROLL); + ReleaseCapture(); + + if (!m_hDragItem) + { + unsigned int uFlags; + HTREEITEM hItemHit = HitTest(point, &uFlags); + if (hItemHit != NULL) + { + if (uFlags & TVHT_ONITEMICON) + { + // + // Notify our parent window that this item's state has changed. + // + CWnd *pwndParent = GetParent(); + if (pwndParent != NULL) + { + int nCheckState = GetCheck(hItemHit); + if (!nCheckState) + { + nCheckState = 1; + } + else + { + nCheckState = 0; + } + + CVisGroup *pGroup = (CVisGroup *)GetItemData(hItemHit); + pwndParent->PostMessage(g_uToggleStateMsg, (WPARAM)pGroup, nCheckState); + } + + // Don't forward to the base if they clicked on the check box. + // This prevents undesired expansion/collapse of tree. + return; + } + } + + CTreeCtrl::OnLButtonUp(nFlags, point); + return; + } + + Drop(DROP_LEFT, nFlags, point); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + unsigned int uFlags; + HTREEITEM hItemHit = HitTest(point, &uFlags); + if (hItemHit != NULL) + { + if (uFlags & TVHT_ONITEMICON) + { + // Don't forward to the base if they clicked on the check box. + // This prevents undesired expansion/collapse of tree. + return; + } + } + + CTreeCtrl::OnLButtonDblClk(nFlags, point); +} + + +//----------------------------------------------------------------------------- +// Purpose: Forwards selection change notifications to our parent window. +// Input : pNMHDR - +// pResult - +//----------------------------------------------------------------------------- +void CGroupList::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult) +{ + CWnd *pwndParent = GetParent(); + if (pwndParent != NULL) + { + pwndParent->PostMessage(g_uSelChangeMsg, 0, 0); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pNMHDR - +// pResult - +//----------------------------------------------------------------------------- +void CGroupList::OnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult) +{ + NMTVDISPINFO *pInfo = (NMTVDISPINFO *)pNMHDR; + if (!pInfo->item.pszText) + return; + + CVisGroup *pVisGroup = (CVisGroup *)GetItemData(pInfo->item.hItem); + Assert(pVisGroup); + if (!pVisGroup) + return; + + pVisGroup->SetName(pInfo->item.pszText); + pResult[0] = TRUE; +} + + +//----------------------------------------------------------------------------- +// Purpose: Begins dragging an item in the visgroup list. The drag image is +// created and anchored relative to the mouse cursor. +// Input : pNMHDR - +// pResult - +//----------------------------------------------------------------------------- +void CGroupList::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult) +{ + NMTREEVIEW *ptv = (NMTREEVIEW *)pNMHDR; + BeginDrag(ptv->ptDrag, ptv->itemNew.hItem); + *pResult = 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pt - +// hItem - +//----------------------------------------------------------------------------- +void CGroupList::BeginDrag(CPoint point, HTREEITEM hItem) +{ + m_hDragItem = hItem; + if (m_hDragItem) + { + m_pDragImageList = CreateDragImage(m_hDragItem); + if (m_pDragImageList) + { + CPoint ptHotSpot(0, 0); + m_pDragImageList->BeginDrag(0, ptHotSpot); + m_pDragImageList->DragEnter(this, point); + SelectDropTarget(NULL); + } + + // Timer handles scrolling the list control when dragging outside the window bounds. + SetTimer(TIMER_GROUP_DRAG_SCROLL, 300, NULL); + + SetCapture(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnRButtonDown(UINT nFlags, CPoint point) +{ + m_bRButtonDown = true; + m_ptRButtonDown = point; + m_hDragItem = NULL; + SetCapture(); + + // Chaining to the base class causes us never to receive the button up message + // for a right click without drag, so we don't do that. + //CTreeCtrl::OnRButtonDown(nFlags, point); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pWnd - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnContextMenu(CWnd *pWnd, CPoint point) +{ + KillTimer(TIMER_GROUP_DRAG_SCROLL); + ReleaseCapture(); + + m_bRButtonDown = false; + + if (!m_hDragItem) + { + CTreeCtrl::OnContextMenu(pWnd, point); + return; + } + + Drop(DROP_RIGHT, 0, point); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnRButtonUp(UINT nFlags, CPoint point) +{ + KillTimer(TIMER_GROUP_DRAG_SCROLL); + ReleaseCapture(); + + m_bRButtonDown = false; + + if (!m_hDragItem) + { + CTreeCtrl::OnRButtonUp(nFlags, point); + return; + } + + Drop(DROP_RIGHT, nFlags, point); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : eDropType - +// nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::Drop(DropType_t eDropType, UINT nFlags, CPoint point) +{ + SelectDropTarget(NULL); + + HTREEITEM hDragItem = m_hDragItem; + m_hDragItem = NULL; + + // + // We are dragging. Drop! + // + if (m_pDragImageList) + { + m_pDragImageList->DragLeave(this); + m_pDragImageList->EndDrag(); + delete m_pDragImageList; + m_pDragImageList = NULL; + } + + // + // Get the group that we were dragging. + // + CVisGroup *pDragGroup = (CVisGroup *)GetItemData(hDragItem); + + // + // Determine what group was dropped onto. + // + HTREEITEM hDropItem = HitTest(point); + if (hDropItem == hDragItem) + { + return; + } + + CVisGroup *pDropGroup = NULL; + if (hDropItem) + { + pDropGroup = (CVisGroup *)GetItemData(hDropItem); + } + + if (pDragGroup == pDropGroup) + { + // Shouldn't happen, but just in case. + return; + } + + CWnd *pwndParent = GetParent(); + if (pwndParent != NULL) + { + if (eDropType == DROP_LEFT) + { + pwndParent->PostMessage(g_uLeftDragDropMsg, (WPARAM)pDragGroup, (LPARAM)pDropGroup); + } + else + { + pwndParent->PostMessage(g_uRightDragDropMsg, (WPARAM)pDragGroup, (LPARAM)pDropGroup); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nIDEvent - +//----------------------------------------------------------------------------- +void CGroupList::OnTimer(UINT nIDEvent) +{ + //DBG("OnTimer\n"); + switch (nIDEvent) + { + case TIMER_GROUP_DRAG_SCROLL: + { + CPoint point; + GetCursorPos(&point); + + CRect rect; + GetWindowRect(&rect); + + if (!rect.PtInRect(point)) + { + if (point.y > rect.bottom) + { + // scroll down + int nCount = GetVisibleCount(); + HTREEITEM hItem = GetFirstVisibleItem(); + for (int i = 1; i < nCount; i++) + { + hItem = GetNextVisibleItem(hItem); + } + + hItem = GetNextVisibleItem(hItem); + + if (hItem) + { + CTreeCtrl::EnsureVisible(hItem); + } + } + else if (point.y < rect.top) + { + HTREEITEM hItem = GetFirstVisibleItem(); + HTREEITEM hPrevVisible = this->GetPrevVisibleItem(hItem); + if (hPrevVisible) + { + // scroll up + CTreeCtrl::EnsureVisible(hPrevVisible); + } + } + } + + break; + } + + default: + { + CTreeCtrl::OnTimer(nIDEvent); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : nFlags - +// point - +//----------------------------------------------------------------------------- +void CGroupList::OnMouseMove(UINT nFlags, CPoint point) +{ + CTreeCtrl::OnMouseMove(nFlags, point); + + if (m_bRButtonDown && !m_hDragItem && (point.x != m_ptRButtonDown.x) && (point.y != m_ptRButtonDown.y)) + { + // First mouse move since a right button down. Start dragging. + HTREEITEM hItem = HitTest(m_ptRButtonDown); + BeginDrag(point, hItem); + } + + if (!m_hDragItem) + { + return; + } + + if (m_pDragImageList) + { + m_pDragImageList->DragMove(point); + } + + // + // Highlight the item we hit. + // + HTREEITEM hItem = HitTest(point); + if (hItem == GetDropHilightItem()) + { + return; + } + + // hide image first + if (m_pDragImageList) + { + m_pDragImageList->DragLeave(this); + m_pDragImageList->DragShowNolock(FALSE); + } + + SelectDropTarget(hItem); + + if (m_pDragImageList) + { + m_pDragImageList->DragEnter(this, point); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGroupList::SelectVisGroup(CVisGroup *pVisGroup) +{ + //DBG("SelectVisGroup: %s\n", pVisGroup->GetName()); + HTREEITEM hItem = FindVisGroupItem(pVisGroup); + if (hItem) + { + Select(hItem, TVGN_CARET); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the check status for the given group. +// Input : pVisGroup - +// nCheckState - 0=not checked, 1=checked, -1=gray check (undefined) +//----------------------------------------------------------------------------- +void CGroupList::SetCheck(CVisGroup *pVisGroup, int nCheckState) +{ + HTREEITEM hItem = FindVisGroupItem(pVisGroup); + if (hItem) + { + UINT uState = INDEXTOOVERLAYMASK(0); + if (nCheckState == 1) + { + uState = INDEXTOOVERLAYMASK(1); + } + else if (nCheckState != 0) + { + uState = INDEXTOOVERLAYMASK(2); + } + + SetItemState(hItem, uState, TVIS_OVERLAYMASK); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the check state for the given visgroup. +// Input : pVisGroup - +//----------------------------------------------------------------------------- +int CGroupList::GetCheck(CVisGroup *pVisGroup) +{ + HTREEITEM hItem = FindVisGroupItem(pVisGroup); + if (hItem) + { + return GetCheck(hItem); + } + + return 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CGroupList::GetCheck(HTREEITEM hItem) +{ + UINT uState = (GetItemState(hItem, TVIS_OVERLAYMASK) & TVIS_OVERLAYMASK); + if (uState == INDEXTOOVERLAYMASK(1)) + { + return 1; + } + else if (uState == INDEXTOOVERLAYMASK(0)) + { + return 0; + } + + return -1; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the number of visgroups in the whole tree. +//----------------------------------------------------------------------------- +int CGroupList::GetVisGroupCount() +{ + return m_VisGroups.Count(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CVisGroup *CGroupList::GetVisGroup(int nIndex) +{ + return m_VisGroups.Element(nIndex); +} + + +//----------------------------------------------------------------------------- +// Purpose: Updates the tree control item text with the new group name. +//----------------------------------------------------------------------------- +void CGroupList::UpdateVisGroup(CVisGroup *pVisGroup) +{ + HTREEITEM hItem = FindVisGroupItem(pVisGroup); + if (hItem) + { + SetItemText(hItem, pVisGroup->GetName()); + } +} + +int CGroupList::GetGroupPairCount(void) +{ + return m_GroupPairs.Count(); +} + +void CGroupList::SaveVisGroupExpandStates() +{ + for ( int i = 0; i < GetVisGroupCount(); i++ ) + { + CVisGroup *thisGroup = GetVisGroup(i); + GroupListPair newPair; + for ( int j = 0; j < GetGroupPairCount(); j++ ) + { + GroupListPair thisPair = m_GroupPairs.Element( j ); + if ( thisGroup == thisPair.pVisGroup ) + { + m_GroupPairs.Remove( j ); + break; + } + } + + HTREEITEM thisItem = FindVisGroupItem( thisGroup ); + newPair.pVisGroup = thisGroup; + newPair.bExpanded = false; + if ( thisItem && (GetItemState( thisItem, TVIS_EXPANDED) & TVIS_EXPANDED) ) + { + newPair.bExpanded = true; + } + m_GroupPairs.AddToTail( newPair ); + } +} + +void CGroupList::RestoreVisGroupExpandStates() +{ + ExpandAll(); + for ( int i = 0; i < GetGroupPairCount(); i++ ) + { + GroupListPair thisPair = m_GroupPairs.Element( i ); + HTREEITEM thisItem = FindVisGroupItem( thisPair.pVisGroup ); + if ( thisItem ) + { + if ( thisPair.bExpanded ) + { + Expand(thisItem, TVE_EXPAND); + } + else + { + Expand( thisItem, TVE_COLLAPSE ); + } + } + } +} |