4372 lines
98 KiB
C++
4372 lines
98 KiB
C++
// ==========================================================================
|
|
// Class Implementation : OXTreeCtrl
|
|
// ==========================================================================
|
|
|
|
// Source file :OXTreeCtrl.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "OXTreeCtrl.h"
|
|
|
|
#include "UTBStrOp.h"
|
|
#include "UTB64Bit.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#endif
|
|
|
|
#define _OX_MAX_ITEM_TEXT 300
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXTreeCtrl
|
|
|
|
IMPLEMENT_DYNAMIC(COXTreeCtrl, CListCtrl)
|
|
|
|
COXTreeCtrl::COXTreeCtrl():
|
|
m_ptLastClick(0,0),m_wndCal(),m_bInit(FALSE)
|
|
{
|
|
m_nIndent= TV_MININDENT;
|
|
m_dwExStyle=0;
|
|
m_dwTCStyle=0;
|
|
m_xtiRoot.SetExpand();
|
|
m_pActiveEditWnd=NULL;
|
|
m_nEditColumn=-1;
|
|
m_nItemHeight=0;
|
|
m_nItemsCount=0;
|
|
|
|
m_bClick=FALSE;
|
|
m_bCanEdit=FALSE;
|
|
m_nLastIndex=-1;
|
|
m_nLastColumn=-1;
|
|
|
|
m_bCreatingDragImage=FALSE;
|
|
m_hOldDropTarget=NULL;
|
|
|
|
m_bFirstTimeHooking=TRUE;
|
|
|
|
m_nRedrawFlag=0;
|
|
|
|
m_nTimerCheckKeyboardInput=0;
|
|
m_sSearchMask=_T("");
|
|
|
|
m_clrHorizontalGrid = 0; // black is the default
|
|
m_clrVerticalGrid = 0; // black is the default
|
|
m_lpfnDefaultCompare = NULL;
|
|
}
|
|
|
|
COXTreeCtrl::~COXTreeCtrl()
|
|
{
|
|
m_mapCompareFunctions.RemoveAll();
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(COXTreeCtrl, CListCtrl)
|
|
//{{AFX_MSG_MAP(COXTreeCtrl)
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONDBLCLK()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_MBUTTONDOWN()
|
|
ON_NOTIFY_REFLECT_EX(NM_KILLFOCUS, OnKillfocus)
|
|
ON_NOTIFY_REFLECT_EX(NM_SETFOCUS, OnSetfocus)
|
|
ON_NOTIFY_REFLECT_EX(LVN_BEGINLABELEDIT, OnBeginlabeledit)
|
|
ON_NOTIFY_REFLECT_EX(LVN_ENDLABELEDIT, OnEndlabeledit)
|
|
ON_WM_HSCROLL()
|
|
ON_WM_VSCROLL()
|
|
ON_WM_PARENTNOTIFY()
|
|
ON_WM_TIMER()
|
|
ON_WM_DESTROY()
|
|
ON_WM_SIZE()
|
|
ON_WM_KEYDOWN()
|
|
//}}AFX_MSG_MAP
|
|
ON_WM_MEASUREITEM_REFLECT()
|
|
ON_WM_STYLECHANGED()
|
|
#ifndef OX_TREECTRL_NOITEMTIPS
|
|
ON_MESSAGE(WM_DOYOUNEEDITEMTIP, OnNeedItemTip)
|
|
ON_MESSAGE(WM_USER_ADJUSTLASTCOLUMN, OnUserAdjustLastColumn)
|
|
#endif
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXTreeCtrl message handlers
|
|
|
|
void COXTreeCtrl::DrawItem(LPDRAWITEMSTRUCT lpDIS)
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
//--- Effect :draw item
|
|
{
|
|
int itemID=lpDIS->itemID;
|
|
if(itemID == -1)
|
|
return;
|
|
|
|
COXTreeItem *xti=(COXTreeItem*)CListCtrl::GetItemData(itemID);
|
|
|
|
|
|
if( xti == NULL )
|
|
return;
|
|
|
|
|
|
int nLevel=xti->GetItemLevel();
|
|
CRect rcItem(lpDIS->rcItem);
|
|
|
|
CDC dc;
|
|
dc.Attach(lpDIS->hDC);
|
|
|
|
CRect rcGrid=rcItem;
|
|
rcGrid.left += GetItemIndent(xti);
|
|
switch(lpDIS->itemAction)
|
|
{
|
|
case ODA_SELECT:
|
|
case ODA_DRAWENTIRE:
|
|
{
|
|
if(m_bCreatingDragImage)
|
|
{
|
|
COLORREF clrOldForground, clrOldBackground;
|
|
rcItem.left=0;
|
|
LV_COLUMN lvc;
|
|
lvc.mask=LVCF_FMT|LVCF_WIDTH;
|
|
int nCol=0;
|
|
CFont *pOldFont=NULL;
|
|
VERIFY(GetColumn(nCol, &lvc));
|
|
rcItem.right=rcItem.left + lvc.cx;
|
|
if(dc.RectVisible(rcItem))
|
|
{
|
|
DrawItemImages(&dc,xti,itemID,rcItem,0,FALSE);
|
|
clrOldForground=dc.SetTextColor(xti->IsDisabled() ?
|
|
::GetSysColor(COLOR_3DSHADOW) : (xti->HasColor(nCol) ?
|
|
xti->GetItemColor(nCol) : GetTextColor()));
|
|
|
|
if (xti->HasBackColor(nCol))
|
|
clrOldBackground=dc.SetBkColor((!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol)));
|
|
else
|
|
clrOldBackground=dc.SetBkColor((!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
|
|
|
|
CString sTxt=GetItemText((HTREEITEM) xti,nCol);
|
|
if(xti->HasFont(nCol))
|
|
pOldFont=dc.SelectObject(xti->GetItemFont(nCol));
|
|
UINT nEllipsisFormat;
|
|
VERIFY(GetItemDrawEllipsis((HTREEITEM)xti,nEllipsisFormat,nCol));
|
|
// draw item's text
|
|
DrawItemText(&dc,sTxt,rcItem,lvc.fmt,FALSE,
|
|
(!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()),
|
|
nEllipsisFormat);
|
|
dc.SetTextColor(clrOldForground);
|
|
dc.SetBkColor(clrOldBackground);
|
|
|
|
if(xti->HasFont(nCol))
|
|
{
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL bShowSelAlways=GetShowSelAlways();
|
|
BOOL bFocus=(::GetFocus() == m_hWnd);
|
|
BOOL bShowSel=bShowSelAlways | bFocus;
|
|
BOOL bDropHilited=GetItemState(GetItemFromIndex(itemID),
|
|
TVIS_DROPHILITED)==TVIS_DROPHILITED;
|
|
BOOL bShowItemSel=bShowSel && (((lpDIS->itemState &
|
|
ODS_SELECTED)==ODS_SELECTED) || bDropHilited);
|
|
COLORREF clrOldForground, clrOldBackground;
|
|
int nOffset=GetItemIndent(xti);
|
|
int nFocusRectOffset=rcItem.left + nOffset;
|
|
CRect rcLines=rcItem;
|
|
rcLines.right=rcLines.left + nOffset;
|
|
|
|
DrawLines(&dc,rcLines,xti,nLevel);
|
|
|
|
rcItem.left += nOffset;
|
|
LV_COLUMN lvc;
|
|
lvc.mask=LVCF_FMT|LVCF_WIDTH;
|
|
int nCol=0;
|
|
int nColCnt=GetColumnsCount();
|
|
BOOL bRowSel=(BOOL)(m_dwExStyle & TVOXS_ROWSEL);
|
|
for(nCol=0; nCol<nColCnt; nCol++)
|
|
{
|
|
CFont *pOldFont=NULL;
|
|
VERIFY(GetColumn(nCol, &lvc));
|
|
rcItem.right =rcItem.left + lvc.cx;
|
|
if(nCol == 0)
|
|
rcItem.right -= nOffset;
|
|
if(dc.RectVisible(rcItem))
|
|
{
|
|
DrawItemImages(
|
|
&dc,xti,itemID,rcItem,nCol,(bRowSel && bShowItemSel));
|
|
|
|
if(nCol == 0)
|
|
{
|
|
nFocusRectOffset=rcItem.left;
|
|
}
|
|
|
|
clrOldForground=dc.SetTextColor(bShowItemSel &&
|
|
((nCol == 0 || bRowSel) && GetFocus()==this) ?
|
|
::GetSysColor(COLOR_HIGHLIGHTTEXT) : (xti->IsDisabled() ?
|
|
::GetSysColor(COLOR_3DSHADOW) : (xti->HasColor(nCol) ?
|
|
xti->GetItemColor(nCol) : GetTextColor())));
|
|
|
|
COLORREF clrBackground = bShowItemSel && (nCol==0 || bRowSel) ?
|
|
(GetFocus()==this ? ::GetSysColor(COLOR_HIGHLIGHT) :
|
|
::GetSysColor(COLOR_BTNFACE)) :
|
|
(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) :
|
|
((xti->HasBackColor(nCol) ? xti->GetItemBackColor(nCol) : GetTextBkColor())));
|
|
|
|
clrOldBackground=dc.SetBkColor(clrBackground);
|
|
|
|
CString sTxt=GetItemText((HTREEITEM) xti,nCol);
|
|
if(xti->HasFont(nCol))
|
|
pOldFont=dc.SelectObject(xti->GetItemFont(nCol));
|
|
UINT nEllipsisFormat;
|
|
VERIFY(GetItemDrawEllipsis((HTREEITEM)xti,nEllipsisFormat,nCol));
|
|
|
|
dc.FillSolidRect(rcItem, clrBackground);
|
|
|
|
// Draw item's text
|
|
if (nCol != 0)
|
|
rcItem.left += 1;
|
|
|
|
DrawItemText(&dc,sTxt,rcItem,lvc.fmt,
|
|
(lpDIS->itemState & ODS_FOCUS) && bFocus && nCol==0 &&
|
|
!bRowSel, bRowSel && bShowItemSel ?
|
|
(GetFocus()==this ? ::GetSysColor(COLOR_HIGHLIGHT) :
|
|
::GetSysColor(COLOR_BTNFACE)) :
|
|
(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) :
|
|
((xti->HasBackColor(nCol) ? xti->GetItemBackColor(nCol) : GetTextBkColor()))),nEllipsisFormat);
|
|
|
|
dc.SetTextColor(clrOldForground);
|
|
dc.SetBkColor(clrOldBackground);
|
|
|
|
if(xti->HasFont(nCol))
|
|
{
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
if(HasGrid(TVOXS_VGRID))
|
|
{
|
|
CPen pen;
|
|
pen.CreatePen(PS_SOLID, 1, m_clrVerticalGrid);
|
|
CPen* pOldPen = (CPen*) dc.SelectObject(&pen);
|
|
dc.MoveTo(rcItem.right-1,rcItem.top);
|
|
dc.LineTo(rcItem.right-1,rcItem.bottom);
|
|
dc.SelectObject(pOldPen);
|
|
}
|
|
}
|
|
rcItem.left =rcItem.right;
|
|
}
|
|
if(HasGrid(TVOXS_HGRID))
|
|
{
|
|
CPen pen;
|
|
pen.CreatePen(PS_SOLID, 1, m_clrHorizontalGrid);
|
|
CPen* pOldPen = (CPen*) dc.SelectObject(&pen);
|
|
|
|
// draw horizontal grid line
|
|
if(GetDrawGridFullLength())
|
|
{
|
|
CRect clientRect;
|
|
GetClientRect(clientRect);
|
|
dc.MoveTo(clientRect.left,rcGrid.bottom-1);
|
|
dc.LineTo(clientRect.right,rcGrid.bottom-1);
|
|
}
|
|
else
|
|
{
|
|
dc.MoveTo(rcGrid.left,rcGrid.bottom-1);
|
|
dc.LineTo(rcGrid.right,rcGrid.bottom-1);
|
|
}
|
|
|
|
dc.SelectObject(pOldPen);
|
|
}
|
|
if((lpDIS->itemState & ODS_FOCUS) && bFocus && bRowSel &&
|
|
!(m_dwExStyle & TVOXS_NOFOCUSRECT))
|
|
{
|
|
rcGrid.left=nFocusRectOffset;
|
|
dc.DrawFocusRect(rcGrid);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
dc.Detach();
|
|
}
|
|
|
|
void COXTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
if(GetFocus()!=this)
|
|
{
|
|
SetFocus();
|
|
}
|
|
m_ptLastClick=point;
|
|
UINT nFl;
|
|
int idx=HitTest(point,&nFl);
|
|
|
|
HTREEITEM hti=GetItemFromIndex(idx);
|
|
ASSERT(hti);
|
|
COXTreeItem *xti=GetXItem(hti);
|
|
ASSERT(xti);
|
|
m_bCanEdit=FALSE;
|
|
if(idx!=-1)
|
|
{
|
|
if (nFl & TVHT_ONITEMBUTTON)
|
|
{
|
|
Expand(hti,TVE_TOGGLE);
|
|
return;
|
|
}
|
|
if(nFl & TVHT_ONITEM)
|
|
{
|
|
CListCtrl::OnLButtonDown(nFlags,point);
|
|
}
|
|
else
|
|
{
|
|
if(GetPickAnywhere())
|
|
{
|
|
CRect rcItem;
|
|
CListCtrl::GetItemRect(idx,&rcItem,LVIR_BOUNDS);
|
|
rcItem.left+=GetItemIndent(xti);
|
|
if(rcItem.PtInRect(point))
|
|
{
|
|
if((GetKeyState(VK_SHIFT)&0x8000) ||
|
|
(GetKeyState(VK_CONTROL)&0x8000))
|
|
{
|
|
VERIFY(CListCtrl::GetItemPosition(idx,&point));
|
|
}
|
|
CListCtrl::OnLButtonDown(LVHT_ONITEM,point);
|
|
}
|
|
}
|
|
}
|
|
|
|
// try to detect subitem to edit label
|
|
CRect rcEdit;
|
|
int nCol=GetEditColumn(xti,&rcEdit);
|
|
|
|
m_nLastIndex=idx;
|
|
m_nLastColumn=nCol;
|
|
}
|
|
else
|
|
{
|
|
if((GetExStyle()&TVOXS_MULTISEL)!=0)
|
|
{
|
|
CWnd::OnLButtonDown(nFlags, point);
|
|
}
|
|
m_nLastIndex=-1;
|
|
m_nLastColumn=-1;
|
|
}
|
|
|
|
m_bClick=!m_bClick;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::InsertItem(LPCTSTR lpszItem, HTREEITEM hParent,
|
|
HTREEITEM hInsertAfter)
|
|
{
|
|
if(hParent==NULL)
|
|
hParent=TVI_ROOT;
|
|
|
|
COXTreeItem *pParent=GetXItem(hParent);
|
|
if(!pParent)
|
|
return NULL;
|
|
COXTreeItem *pInsAfter;
|
|
if(hInsertAfter == TVI_FIRST)
|
|
{
|
|
pInsAfter=(COXTreeItem *) TVI_FIRST;
|
|
}
|
|
else if(hInsertAfter == TVI_SORT)
|
|
{
|
|
pInsAfter=pParent->FindItemToInsertAfter(lpszItem);
|
|
}
|
|
else
|
|
{
|
|
pInsAfter=GetXItem(hInsertAfter);
|
|
}
|
|
COXTreeItem * pNewItem=new COXTreeItem(lpszItem);
|
|
ASSERT(pParent);
|
|
BOOL bDrawBtn=pParent->NeedDrawButton();
|
|
pParent->AddChild(pNewItem,pInsAfter);
|
|
AddItemToCtrl(pNewItem);
|
|
if(pParent->NeedDrawButton() != bDrawBtn && HasButtons())
|
|
{
|
|
// parent button's state changed, redraw parent
|
|
int idx=GetItemIndexInternal(pParent);
|
|
if(idx != -1)
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
}
|
|
m_nItemsCount++;
|
|
return (HTREEITEM)pNewItem;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::InsertItem(LPTV_INSERTSTRUCT lpTVIS)
|
|
{
|
|
if(lpTVIS->hParent==NULL)
|
|
lpTVIS->hParent=TVI_ROOT;
|
|
|
|
COXTreeItem *pParent=GetXItem(lpTVIS->hParent);
|
|
if(!pParent)
|
|
return NULL;
|
|
COXTreeItem *pInsAfter;
|
|
if(lpTVIS->hInsertAfter == TVI_FIRST)
|
|
{
|
|
pInsAfter=(COXTreeItem *) TVI_FIRST;
|
|
}
|
|
else if(lpTVIS->hInsertAfter == TVI_SORT)
|
|
{
|
|
pInsAfter=pParent->FindItemToInsertAfter(lpTVIS->item.pszText);
|
|
}
|
|
else
|
|
{
|
|
pInsAfter=GetXItem(lpTVIS->hInsertAfter);
|
|
}
|
|
|
|
COXTreeItem * pNewItem= new COXTreeItem(lpTVIS->item.pszText);
|
|
|
|
BOOL bDrawBtn=pParent->NeedDrawButton();
|
|
pParent->AddChild(pNewItem,pInsAfter);
|
|
lpTVIS->item.mask |= TVIF_HANDLE;
|
|
lpTVIS->item.hItem=(HTREEITEM) pNewItem;
|
|
VERIFY(SetItem(&(lpTVIS->item)));
|
|
AddItemToCtrl(pNewItem);
|
|
if(pParent->NeedDrawButton() != bDrawBtn && HasButtons())
|
|
{
|
|
// parent button's state changed, redraw parent
|
|
int idx=GetItemIndexInternal(pParent);
|
|
if(idx != -1)
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
}
|
|
m_nItemsCount++;
|
|
return (HTREEITEM) pNewItem;
|
|
}
|
|
|
|
|
|
HTREEITEM COXTreeCtrl::InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,
|
|
int nSelectedImage, UINT nState,
|
|
UINT nStateMask, LPARAM lParam,
|
|
HTREEITEM hParent, HTREEITEM hInsertAfter)
|
|
{
|
|
TV_INSERTSTRUCT tvis;
|
|
tvis.hParent=hParent;
|
|
tvis.hInsertAfter=hInsertAfter;
|
|
tvis.item.mask=nMask;
|
|
tvis.item.state=nState;
|
|
tvis.item.stateMask=nStateMask;
|
|
tvis.item.pszText=(LPTSTR)lpszItem;
|
|
tvis.item.iImage=nImage;
|
|
tvis.item.iSelectedImage=nSelectedImage;
|
|
tvis.item.lParam=lParam;
|
|
|
|
return InsertItem(&tvis);
|
|
}
|
|
|
|
|
|
HTREEITEM COXTreeCtrl::InsertItem(LPCTSTR lpszItem,
|
|
int nImage,
|
|
int nSelectedImage,
|
|
HTREEITEM hParent/*=TVI_ROOT*/,
|
|
HTREEITEM hInsertAfter/*=TVI_LAST*/)
|
|
{
|
|
TV_INSERTSTRUCT tvis;
|
|
tvis.hParent=hParent;
|
|
tvis.hInsertAfter=hInsertAfter;
|
|
tvis.item.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT;
|
|
tvis.item.pszText=(LPTSTR)lpszItem;
|
|
tvis.item.iImage=nImage;
|
|
tvis.item.iSelectedImage=nSelectedImage;
|
|
|
|
return InsertItem(&tvis);
|
|
}
|
|
|
|
|
|
int COXTreeCtrl::GetItemIndex(HTREEITEM hItem) const
|
|
{
|
|
return GetItemIndexInternal(GetXItem(hItem));
|
|
}
|
|
|
|
|
|
int COXTreeCtrl::GetItemIndexInternal(COXTreeItem *pItem) const
|
|
{
|
|
if(pItem == &m_xtiRoot)
|
|
return -1;
|
|
LV_FINDINFO lvfi;
|
|
lvfi.flags=LVFI_PARAM;
|
|
lvfi.lParam=(LPARAM)pItem;
|
|
return CListCtrl::FindItem(&lvfi);
|
|
}
|
|
|
|
COXTreeItem* COXTreeCtrl::GetXItem(HTREEITEM hti) const
|
|
{
|
|
if(hti == TVI_ROOT)
|
|
return &m_xtiRoot;
|
|
if(hti == TVI_FIRST || hti == TVI_LAST)
|
|
return NULL;
|
|
#ifdef _DEBUG
|
|
if(hti)
|
|
ASSERT(_CrtIsValidPointer(hti,sizeof(COXTreeItem),FALSE));
|
|
#endif
|
|
return (COXTreeItem*)hti;
|
|
}
|
|
|
|
void COXTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
|
|
{
|
|
if(GetFocus() != this)
|
|
SetFocus();
|
|
|
|
UINT flgs = nFlags;
|
|
int idx = HitTest(point,&flgs);
|
|
|
|
if (idx != -1)
|
|
if (GetPickAnywhere() || (flgs & (TVHT_ONITEM | TVHT_ONITEMBUTTON)))
|
|
{
|
|
Expand((HTREEITEM )CListCtrl::GetItemData(idx),TVE_TOGGLE);
|
|
CListCtrl::OnLButtonDblClk(nFlags,point);
|
|
}
|
|
m_bClick=FALSE;
|
|
}
|
|
|
|
void COXTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
UINT flgs = nFlags;
|
|
int idx = HitTest(point,&flgs);
|
|
|
|
if (idx != -1)
|
|
if (GetPickAnywhere() || (flgs & (TVHT_ONITEM | TVHT_ONITEMBUTTON)))
|
|
CListCtrl::OnRButtonDown(nFlags,point);
|
|
}
|
|
|
|
void COXTreeCtrl::OnMButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
UINT flgs = nFlags;
|
|
int idx = HitTest(point,&flgs);
|
|
|
|
if (idx != -1)
|
|
if (GetPickAnywhere() || (flgs & (TVHT_ONITEM | TVHT_ONITEMBUTTON)))
|
|
CListCtrl::OnMButtonDown(nFlags,point);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::Expand(HTREEITEM hItem, UINT nCode)
|
|
{
|
|
COXTreeItem *pItem=GetXItem(hItem);
|
|
ASSERT(pItem);
|
|
if(SendItemExpandingNotify(hItem,nCode))
|
|
{
|
|
return FALSE;// parent voted against!
|
|
}
|
|
|
|
SetRedraw(FALSE);
|
|
|
|
pItem->Expand(nCode,this);
|
|
|
|
SetRedraw(TRUE);
|
|
|
|
CListCtrl::RedrawItems(GetItemIndex(hItem),GetItemIndex(hItem));
|
|
|
|
SendItemExpandedNotify(hItem,nCode);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int COXTreeCtrl::SetItemAtPos(int pos,COXTreeItem *pItem)
|
|
{
|
|
int idx=CListCtrl::InsertItem(pos,LPSTR_TEXTCALLBACK);
|
|
if(idx == -1)
|
|
return -1;
|
|
CListCtrl::SetItemData(idx,(DWORD)PtrToUlong (pItem));
|
|
for(int i=1;i < pItem->GetSubitemsCount();i++)
|
|
{
|
|
LPCTSTR lpszText=GetItemText((HTREEITEM)pItem,i);
|
|
if(lpszText)
|
|
{
|
|
CListCtrl::SetItemText(pos,i,LPSTR_TEXTCALLBACK);
|
|
}
|
|
}
|
|
|
|
TV_ITEM tvi;
|
|
::ZeroMemory((void*)&tvi,sizeof(tvi));
|
|
if(pItem->m_tvi.iImage>=0)
|
|
{
|
|
tvi.mask|=TVIF_IMAGE;
|
|
tvi.iImage=pItem->m_tvi.iImage;
|
|
}
|
|
if(pItem->m_tvi.iSelectedImage>=0)
|
|
{
|
|
tvi.mask|=TVIF_SELECTEDIMAGE;
|
|
tvi.iSelectedImage=pItem->m_tvi.iSelectedImage;
|
|
}
|
|
if((pItem->m_tvi.state & INDEXTOSTATEIMAGEMASK(0xF))!=0)
|
|
{
|
|
tvi.state=(pItem->m_tvi.state & INDEXTOSTATEIMAGEMASK(0xF));
|
|
tvi.stateMask=tvi.state;
|
|
tvi.mask|=TVIF_STATE;
|
|
}
|
|
if(tvi.mask!=0)
|
|
{
|
|
tvi.hItem=pItem->m_tvi.hItem;
|
|
tvi.mask|=TVIF_HANDLE;
|
|
VERIFY(SetItem(&tvi));
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::AddItemToCtrl(COXTreeItem *pItem)
|
|
// --- In : item handle
|
|
// --- Out :
|
|
// --- Returns :Nonzero if successful; otherwise 0
|
|
//--- Effect :
|
|
{
|
|
ASSERT(pItem!=NULL);
|
|
|
|
if(pItem->pxParent!=NULL && pItem->pxParent->m_tvi.cChildren==0)
|
|
pItem->pxParent->m_tvi.cChildren=1;
|
|
|
|
if (pItem->IsAnyParentCollapsed())
|
|
return TRUE;
|
|
|
|
if(pItem->IsHidden())
|
|
return TRUE;
|
|
|
|
COXTreeItem *pPrevItem=pItem->GetPrevInTree();
|
|
while(pPrevItem != &m_xtiRoot && !pPrevItem->IsVisible())
|
|
{
|
|
pPrevItem=pPrevItem->GetPrevInTree();
|
|
if(!pPrevItem)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
ASSERT(pPrevItem);
|
|
int nIndex;
|
|
if(pPrevItem == &m_xtiRoot)
|
|
nIndex=0;//will be first item!
|
|
else
|
|
{
|
|
nIndex=GetItemIndexInternal(pPrevItem) + 1;
|
|
ASSERT(nIndex);
|
|
}
|
|
BOOL bRet=(-1 != SetItemAtPos(nIndex,pItem));
|
|
return bRet;
|
|
}
|
|
|
|
void COXTreeCtrl::DeleteChildrenItems(COXTreeItem *pItem)
|
|
// --- In :handle of the item
|
|
// --- Out :
|
|
// --- Returns :
|
|
//--- Effect :delete children of specified item
|
|
{
|
|
COXTreeItem *xti=pItem->pxFirstChild;
|
|
while(xti)
|
|
{
|
|
DeleteChildrenItems(xti);
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(idx!=-1)
|
|
{
|
|
CListCtrl::DeleteItem(idx);
|
|
|
|
}
|
|
xti=xti->pxNext;
|
|
}
|
|
pItem->DeleteChildren();
|
|
pItem->m_tvi.cChildren=0;
|
|
}
|
|
|
|
void COXTreeCtrl::DrawItemText(CDC *pDC,LPCTSTR sText,CRect& rcTxt,UINT nJustify,
|
|
BOOL bDrawFocus,COLORREF clrFillOutside,
|
|
UINT nEllipsisMode)
|
|
{
|
|
|
|
CRect rcText=rcTxt;
|
|
CRect rcFill=rcTxt;
|
|
// check rect need to be drawn
|
|
if(!pDC->RectVisible(&rcText))
|
|
return;
|
|
// check text
|
|
if(!sText || sText == LPSTR_TEXTCALLBACK)
|
|
return;
|
|
|
|
COLORREF clrBack=pDC->GetBkColor();
|
|
if(!rcFill.IsRectEmpty())
|
|
pDC->FillSolidRect(rcFill,clrFillOutside);
|
|
pDC->SetBkColor(clrBack);
|
|
|
|
UINT nFormat=DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER;
|
|
nFormat|=nEllipsisMode;
|
|
|
|
rcText.DeflateRect(2,0);
|
|
rcFill=rcText;
|
|
pDC->DrawText(sText,rcFill,nFormat|DT_CALCRECT);
|
|
rcFill.top=rcTxt.top;
|
|
rcFill.bottom=rcTxt.bottom;
|
|
rcFill.InflateRect(2,0);
|
|
int nTextSize=rcFill.Width();
|
|
|
|
switch(nJustify & LVCFMT_JUSTIFYMASK)
|
|
{
|
|
case LVCFMT_LEFT:
|
|
nFormat|=DT_LEFT;
|
|
rcFill.left=__max(rcFill.left,rcTxt.left);
|
|
rcFill.right=__min(rcFill.right,rcTxt.right);
|
|
break;
|
|
case LVCFMT_RIGHT:
|
|
nFormat|=DT_RIGHT;
|
|
rcFill.right=rcTxt.right;
|
|
rcFill.left=__max(rcFill.right-nTextSize,rcTxt.left);
|
|
break;
|
|
case LVCFMT_CENTER:
|
|
nFormat|=DT_CENTER;
|
|
rcFill.left=__max(rcTxt.left+((rcTxt.Width()-nTextSize)/2),rcTxt.left);
|
|
rcFill.right=__min(rcTxt.right-((rcTxt.Width()-nTextSize)/2)+
|
|
(rcTxt.Width()-nTextSize)%2,rcTxt.right);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
if(!rcFill.IsRectEmpty())
|
|
{
|
|
pDC->FillSolidRect(rcFill,clrBack);
|
|
}
|
|
|
|
// Draw the text
|
|
pDC->SetBkMode(TRANSPARENT);
|
|
pDC->DrawText(sText,rcText,nFormat);
|
|
|
|
if(bDrawFocus && !(m_dwExStyle & TVOXS_NOFOCUSRECT))
|
|
{
|
|
pDC->DrawFocusRect(rcFill);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::GetShowSelAlways() const
|
|
{
|
|
return ((GetStyle() & TVS_SHOWSELALWAYS) == TVS_SHOWSELALWAYS);
|
|
}
|
|
|
|
|
|
BOOL COXTreeCtrl::OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult)
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
//--- Effect :
|
|
{
|
|
UNREFERENCED_PARAMETER(pNMHDR);
|
|
RefreshFocusItem();
|
|
*pResult=0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void COXTreeCtrl::RefreshFocusItem()
|
|
{
|
|
int nFocusItem=CListCtrl::GetNextItem(-1,LVNI_SELECTED);
|
|
while(nFocusItem != -1)
|
|
{
|
|
RedrawItems(nFocusItem,nFocusItem);
|
|
nFocusItem=CListCtrl::GetNextItem(nFocusItem,LVNI_SELECTED);
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
UNREFERENCED_PARAMETER(pNMHDR);
|
|
RefreshFocusItem();
|
|
*pResult=0;
|
|
m_bClick=FALSE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CImageList* COXTreeCtrl::SetImageList(CImageList* pImageList, int nImageList)
|
|
{
|
|
switch(nImageList)
|
|
{
|
|
case TVSIL_NORMAL:
|
|
nImageList=LVSIL_SMALL;
|
|
break;
|
|
case TVSIL_STATE:
|
|
nImageList=LVSIL_STATE;
|
|
break;
|
|
default:
|
|
TRACE(_T("COXTreeCtrl::SetImageList: unknown image list type!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
return CListCtrl::SetImageList(pImageList,nImageList);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::HasButtons() const
|
|
{
|
|
return (m_dwTCStyle & TVS_HASBUTTONS);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::HasLines() const
|
|
{
|
|
return (m_dwTCStyle & TVS_HASLINES);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::HasLinesAtRoot() const
|
|
{
|
|
return (m_dwTCStyle & TVS_LINESATROOT);
|
|
}
|
|
|
|
|
|
int COXTreeCtrl::GetItemStateIndex(int nItem) const
|
|
{
|
|
LV_ITEM lvI;
|
|
lvI.mask=LVIF_IMAGE | LVIF_STATE;
|
|
lvI.iItem=nItem;
|
|
lvI.iSubItem =0;
|
|
lvI.state=0;
|
|
lvI.stateMask=INDEXTOSTATEIMAGEMASK(0xF);
|
|
if (CListCtrl::GetItem(&lvI))
|
|
return STATEIMAGEMASKTOINDEX(lvI.state) - 1;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void COXTreeCtrl::DrawLines(CDC *pDC, LPRECT rLines, COXTreeItem *pItem, int nLev)
|
|
{
|
|
int nLevel=nLev;
|
|
CPen penBtn(PS_SOLID,1,::GetSysColor(COLOR_3DSHADOW));
|
|
pDC->ExtTextOut(0,0,ETO_OPAQUE,rLines,_T(""),0,NULL);
|
|
CRect rcLines(rLines);
|
|
if(!rcLines.IsRectEmpty())
|
|
{
|
|
if (pItem != NULL && pItem->HasBackColor())
|
|
pDC->FillSolidRect(rcLines,(!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : pItem->GetItemBackColor()));
|
|
else
|
|
{
|
|
if (IsPropertiesWnd())
|
|
pDC->FillSolidRect(rcLines, ::GetSysColor(COLOR_BTNFACE));
|
|
else
|
|
pDC->FillSolidRect(rcLines,(!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
|
|
}
|
|
}
|
|
CRect rcStep;
|
|
rcStep=rcLines;
|
|
rcStep.left=rcStep.right - m_nIndent;
|
|
COXTreeItem *xti=pItem;
|
|
int nLineMode;
|
|
if(xti->IsLastUnhidden() && GetItemIndexInternal(xti)==0)
|
|
nLineMode=0; // first & last node at the same time
|
|
else if(GetItemIndexInternal(xti)==0)
|
|
nLineMode=4; // first node
|
|
else if(xti->IsLastUnhidden())
|
|
nLineMode=2; // last node
|
|
else
|
|
nLineMode=3; // there are node(s) below
|
|
|
|
if(HasLines())
|
|
DrawLine(pDC,&m_penLines,rcStep,nLineMode);
|
|
|
|
CPen *pOld=pDC->SelectObject(&penBtn);
|
|
if(HasButtons() && pItem->NeedDrawButton())
|
|
{
|
|
CRect rcButton;
|
|
CalcBtnRect(&rcButton,rcStep);
|
|
DrawButton(pDC,rcButton,pItem->IsExpanded());
|
|
}
|
|
pDC->SelectObject(pOld);
|
|
if(HasLines())
|
|
{
|
|
while(nLevel > 0)
|
|
{
|
|
xti=xti->pxParent;
|
|
rcStep.OffsetRect(-m_nIndent,0);
|
|
if(!xti->IsLastUnhidden())
|
|
DrawLine(pDC,&m_penLines,rcStep,1);
|
|
nLevel--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void COXTreeCtrl::DrawLine(CDC *pDC, CPen* pPen, CRect& rc, int nMode)
|
|
{
|
|
CPen *penOld=pDC->SelectObject(pPen);
|
|
|
|
switch(nMode)
|
|
{
|
|
case 0:
|
|
pDC->MoveTo(rc.left + rc.Width()/2 - 1,rc.top + rc.Height()/2);
|
|
pDC->LineTo(rc.right,rc.top + rc.Height()/2);
|
|
break;
|
|
|
|
case 1:
|
|
pDC->MoveTo(rc.left + rc.Width()/2,rc.top - 1);
|
|
pDC->LineTo(rc.left + rc.Width()/2,rc.bottom);
|
|
break;
|
|
|
|
case 2:
|
|
pDC->MoveTo(rc.left + rc.Width()/2,rc.top - 1);
|
|
pDC->LineTo(rc.left + rc.Width()/2,rc.top + rc.Height()/2);
|
|
pDC->LineTo(rc.right,rc.top + rc.Height()/2);
|
|
break;
|
|
|
|
case 3:
|
|
pDC->MoveTo(rc.left + rc.Width()/2,rc.top - 1);
|
|
pDC->LineTo(rc.left + rc.Width()/2,rc.bottom);
|
|
pDC->MoveTo(rc.left + rc.Width()/2,rc.top + rc.Height()/2);
|
|
pDC->LineTo(rc.right,rc.top + rc.Height()/2);
|
|
break;
|
|
|
|
case 4:
|
|
pDC->MoveTo(rc.left + rc.Width()/2,rc.bottom + 1);
|
|
pDC->LineTo(rc.left + rc.Width()/2,rc.top + rc.Height()/2);
|
|
pDC->LineTo(rc.right,rc.top + rc.Height()/2);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
if(penOld!=NULL)
|
|
{
|
|
pDC->SelectObject(penOld);
|
|
}
|
|
}
|
|
|
|
void COXTreeCtrl::DrawButton(CDC *pDC,CRect& rcButton,BOOL bExpand)
|
|
{
|
|
pDC->Rectangle(rcButton);
|
|
|
|
CRect rcInnerSpace=rcButton;
|
|
rcInnerSpace.DeflateRect(1,1);
|
|
if(!rcInnerSpace.IsRectEmpty())
|
|
{
|
|
pDC->FillSolidRect(rcInnerSpace,(!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
|
|
}
|
|
|
|
CPen penPlusMinus;
|
|
penPlusMinus.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT));
|
|
CPen* pOldPen = pDC->SelectObject(&penPlusMinus);
|
|
|
|
pDC->MoveTo(rcButton.left + 2,rcButton.top + rcButton.Height()/2);
|
|
pDC->LineTo(rcButton.right-2,rcButton.top + rcButton.Height()/2);
|
|
if(!bExpand)
|
|
{
|
|
pDC->MoveTo(rcButton.left + rcButton.Width()/2,rcButton.top +2);
|
|
pDC->LineTo(rcButton.left + rcButton.Width()/2,rcButton.bottom -2);
|
|
}
|
|
|
|
pDC->SelectObject(pOldPen);
|
|
}
|
|
|
|
void COXTreeCtrl::CalcBtnRect(CRect *prcButton,CRect& rcStep)
|
|
{
|
|
(*prcButton)=rcStep;
|
|
int nSide=__max((rcStep.Height()*5)/10,9);
|
|
int offx =(rcStep.Width() - nSide + 1)/2;
|
|
int offy=(rcStep.Height() - nSide + 1)/2;
|
|
prcButton->top += offy;
|
|
prcButton->bottom=prcButton->top +nSide;
|
|
prcButton->left += offx;
|
|
prcButton->right=prcButton->left + nSide;
|
|
}
|
|
|
|
int COXTreeCtrl::HitTest(CPoint pt, UINT* pFlags) const
|
|
{
|
|
UINT nListFlags;
|
|
int idx=CListCtrl::HitTest(pt,&nListFlags);
|
|
if(!pFlags)
|
|
return idx;
|
|
(*pFlags)=0;
|
|
if(idx != -1)
|
|
{
|
|
CRect rcItem;
|
|
COXTreeItem *xti=(COXTreeItem *)CListCtrl::GetItemData(idx);
|
|
if(CListCtrl::GetItemRect(idx,&rcItem,LVIR_BOUNDS))
|
|
{
|
|
int nIndent=-1;
|
|
CRect rcButton,rcText,rcImage,rcStateImage;
|
|
GetItemPartRect(rButton,xti,&rcButton,&nIndent);
|
|
GetItemPartRect(rImage,xti,&rcImage,&nIndent);
|
|
GetItemPartRect(rStateImage,xti,&rcStateImage,&nIndent);
|
|
GetItemPartRect(rText,xti,&rcText,&nIndent);
|
|
*pFlags=TVHT_ONITEM;
|
|
if(rcText.PtInRect(pt))
|
|
(*pFlags) |= TVHT_ONITEMLABEL;
|
|
else
|
|
if(rcImage.PtInRect(pt))
|
|
(*pFlags) |= TVHT_ONITEMICON;
|
|
else
|
|
if(rcStateImage.PtInRect(pt))
|
|
(*pFlags) |= TVHT_ONITEMSTATEICON;
|
|
else
|
|
if(rcButton.PtInRect(pt))
|
|
(*pFlags) |= TVHT_ONITEMBUTTON;
|
|
else
|
|
if(rcItem.PtInRect(pt))
|
|
(*pFlags) |= TVHT_TORIGHT;
|
|
else
|
|
{
|
|
(*pFlags) |= TVHT_NOWHERE;
|
|
(*pFlags) &= ~TVHT_ONITEM;
|
|
}
|
|
}
|
|
}
|
|
if ((*pFlags)==0)
|
|
{
|
|
if (nListFlags&LVHT_ABOVE)
|
|
*pFlags=TVHT_ABOVE;
|
|
else if (nListFlags&LVHT_BELOW)
|
|
*pFlags=TVHT_BELOW;
|
|
else if (nListFlags&LVHT_TOLEFT)
|
|
*pFlags=TVHT_TOLEFT;
|
|
else if (nListFlags&LVHT_TORIGHT)
|
|
*pFlags=TVHT_TORIGHT;
|
|
else if (nListFlags&LVHT_NOWHERE)
|
|
*pFlags=TVHT_NOWHERE;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
|
|
HTREEITEM COXTreeCtrl::HitTest(TVHITTESTINFO* pHitTestInfo) const
|
|
{
|
|
ASSERT(pHitTestInfo!=NULL);
|
|
pHitTestInfo->hItem=NULL;
|
|
int nIndex=HitTest(pHitTestInfo->pt,&pHitTestInfo->flags);
|
|
if(nIndex>=0)
|
|
{
|
|
pHitTestInfo->hItem=GetItemFromIndex(nIndex);
|
|
}
|
|
return pHitTestInfo->hItem;
|
|
}
|
|
|
|
|
|
BOOL COXTreeCtrl::Init()
|
|
{
|
|
if(m_bInit)
|
|
return TRUE;
|
|
|
|
// create line pen
|
|
LOGBRUSH logBrush;
|
|
logBrush.lbColor=GetSysColor(COLOR_3DSHADOW);
|
|
logBrush.lbStyle=BS_SOLID;
|
|
logBrush.lbHatch=HS_HORIZONTAL;
|
|
if (!m_penLines.CreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &logBrush, 0, NULL))
|
|
{
|
|
if (!m_penLines.CreatePen(PS_COSMETIC, 1, &logBrush, 0, NULL))
|
|
{
|
|
TRACE(_T("COXTreeCtrl::Init: Error creating the lines Pen\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
CRect rClient;
|
|
GetClientRect(&rClient);
|
|
// insert at least one column initially
|
|
if(CListCtrl::InsertColumn(0,_T(""),LVCFMT_LEFT,rClient.Width()) == -1)
|
|
{
|
|
TRACE(_T("COXTreeCtrl::Init: Error inserting column\n"));
|
|
return FALSE;
|
|
}
|
|
VERIFY(SetBkColor(::GetSysColor(COLOR_WINDOW)));
|
|
VERIFY(SetTextBkColor(::GetSysColor(COLOR_WINDOW)));
|
|
VERIFY(SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)));
|
|
|
|
// subclass header control
|
|
HWND hWnd=GetHeaderCtrlHandle();
|
|
if(hWnd!=NULL)
|
|
{
|
|
if(!::IsWindow(m_wndHdr.GetSafeHwnd()))
|
|
VERIFY(m_wndHdr.SubclassWindow(hWnd));
|
|
else
|
|
ASSERT(m_wndHdr.GetSafeHwnd()==hWnd);
|
|
}
|
|
|
|
m_bInit=TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXTreeCtrl::PreSubclassWindow()
|
|
{
|
|
_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
|
|
// hook not already in progress
|
|
if(pThreadState->m_pWndInit==NULL)
|
|
{
|
|
VERIFY(Init());
|
|
}
|
|
|
|
CListCtrl::PreSubclassWindow();
|
|
DWORD dwStyle=CListCtrl::GetStyle();
|
|
|
|
ASSERT(dwStyle & LVS_REPORT);
|
|
ASSERT(dwStyle & LVS_OWNERDRAWFIXED);
|
|
ASSERT(!(dwStyle & LVS_SORTASCENDING));
|
|
ASSERT(!(dwStyle & LVS_SORTDESCENDING));
|
|
|
|
if(dwStyle & LVS_SHOWSELALWAYS)
|
|
m_dwTCStyle |= TVS_SHOWSELALWAYS;
|
|
if(dwStyle & LVS_EDITLABELS)
|
|
m_dwTCStyle |= TVS_EDITLABELS;
|
|
|
|
if(dwStyle & LVS_NOCOLUMNHEADER)
|
|
m_dwExStyle &= ~TVOXS_COLUMNHDR;
|
|
else
|
|
m_dwExStyle |= TVOXS_COLUMNHDR;
|
|
|
|
if(dwStyle & LVS_SINGLESEL)
|
|
m_dwExStyle &= ~TVOXS_MULTISEL;
|
|
else
|
|
m_dwExStyle |= TVOXS_MULTISEL;
|
|
|
|
if(dwStyle & LVS_NOSCROLL)
|
|
m_dwExStyle |= TVOXS_NOSCROLL;
|
|
else
|
|
m_dwExStyle &= ~TVOXS_NOSCROLL;
|
|
|
|
if(dwStyle & LVS_NOSORTHEADER)
|
|
m_dwExStyle |= TVOXS_NOSORTHEADER;
|
|
else
|
|
m_dwExStyle &= ~TVOXS_NOSORTHEADER;
|
|
|
|
if(dwStyle & LVS_SHAREIMAGELISTS)
|
|
m_dwExStyle |= TVOXS_SHAREIMAGELISTS;
|
|
else
|
|
m_dwExStyle &= ~TVOXS_SHAREIMAGELISTS;
|
|
|
|
#ifndef OX_TREECTRL_NOITEMTIPS
|
|
m_dwExStyle |= TVOXS_ITEMTIPS;
|
|
#endif
|
|
}
|
|
|
|
int COXTreeCtrl::GetItemIndent(COXTreeItem *pItem) const
|
|
{
|
|
if (IsPropertiesWnd())
|
|
{
|
|
// We have a properies window
|
|
if((HasLines() || HasButtons()) && HasLinesAtRoot())
|
|
return m_nIndent;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int nLevel=pItem->GetItemLevel();
|
|
int nIndent;
|
|
if((HasLines() || HasButtons()) && HasLinesAtRoot())
|
|
nIndent=m_nIndent *nLevel;
|
|
else
|
|
nIndent=m_nIndent *(nLevel-1);
|
|
return nIndent;
|
|
}
|
|
|
|
void COXTreeCtrl::GetItemPartRect(COXTreeCtrl::eItemPartRect eType,
|
|
COXTreeItem *pItem,CRect *rTarget,
|
|
int *nIndent) const
|
|
{
|
|
ASSERT_POINTER(pItem,COXTreeItem);
|
|
if((*nIndent) == -1)
|
|
(*nIndent)=GetItemIndent(pItem);
|
|
int nIndex=GetItemIndexInternal(pItem);
|
|
|
|
CRect rcItem;
|
|
CListCtrl::GetItemRect(nIndex,&rcItem,LVIR_BOUNDS);
|
|
|
|
CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
|
|
CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
|
|
|
|
CRect rcLastIndent=rcItem;
|
|
if(*nIndent)
|
|
{
|
|
rcLastIndent.right=rcItem.left + *nIndent;
|
|
rcLastIndent.left=rcLastIndent.right - m_nIndent;
|
|
}
|
|
else
|
|
{
|
|
rcLastIndent.SetRectEmpty();
|
|
}
|
|
|
|
|
|
switch(eType)
|
|
{
|
|
case rButton://button rect
|
|
{
|
|
if(!HasButtons())
|
|
{
|
|
rTarget->SetRectEmpty();
|
|
}
|
|
else
|
|
{
|
|
(*rTarget)=rcLastIndent;
|
|
int nSide=(rcLastIndent.Height()*5)/10;
|
|
int offx =(rcLastIndent.Width() - nSide)/2;
|
|
int offy=(rcLastIndent.Height() - nSide)/2;
|
|
rTarget->top += offy;
|
|
rTarget->bottom -= offy;
|
|
rTarget->left += offx;
|
|
rTarget->right -= offx;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case rImage:// item image rect
|
|
{
|
|
if(pImgList == NULL)
|
|
{
|
|
// no image list
|
|
rTarget->SetRectEmpty();
|
|
return;
|
|
}
|
|
int nStateOffsetX;
|
|
IMAGEINFO imgInfo;
|
|
if(pStateImgList && GetItemStateIndex(nIndex) != -1)
|
|
{
|
|
pStateImgList->GetImageInfo(0,&imgInfo);
|
|
nStateOffsetX=imgInfo.rcImage.right - imgInfo.rcImage.left;
|
|
}
|
|
else
|
|
nStateOffsetX=0;
|
|
pImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImage(imgInfo.rcImage);
|
|
rTarget->left=rcItem.left + *nIndent + nStateOffsetX;
|
|
rTarget->top=rcItem.bottom - rcImage.Height();
|
|
rTarget->right=rTarget->left + rcImage.Width();
|
|
rTarget->bottom=rcItem.bottom;
|
|
}
|
|
break;
|
|
|
|
case rStateImage:
|
|
{
|
|
if(pStateImgList == NULL)
|
|
rTarget->SetRectEmpty();
|
|
else
|
|
{
|
|
IMAGEINFO imgInfo;
|
|
pStateImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcStateImage(imgInfo.rcImage);
|
|
rTarget->left=rcItem.left + *nIndent;
|
|
rTarget->top=rcItem.bottom - rcStateImage.Height();
|
|
rTarget->right=rTarget->left + rcStateImage.Width();
|
|
rTarget->bottom=rcItem.bottom;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case rText:
|
|
{
|
|
CSize szText=GetColTextExtent(nIndex,0);
|
|
CRect rcText;
|
|
LV_COLUMN lvc;
|
|
memset(&lvc,0,sizeof(LV_COLUMN));
|
|
lvc.mask=LVCF_FMT;
|
|
ASSERT(GetColumn(0, &lvc));
|
|
int nImgWidth=0;
|
|
IMAGEINFO imgInfo;
|
|
if(pImgList)
|
|
{
|
|
pImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImg(imgInfo.rcImage);
|
|
nImgWidth += rcImg.Width();
|
|
}
|
|
if(pStateImgList && GetItemStateIndex(nIndex) != -1)
|
|
{
|
|
pStateImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImg(imgInfo.rcImage);
|
|
nImgWidth += rcImg.Width();
|
|
}
|
|
rcText.top=rcItem.top;
|
|
rcText.bottom=rcItem.bottom;
|
|
szText.cx=__min(szText.cx,GetColumnWidth(0)-nImgWidth-(*nIndent));
|
|
int fmt=lvc.fmt & LVCFMT_JUSTIFYMASK;
|
|
switch(fmt)
|
|
{
|
|
case LVCFMT_LEFT:
|
|
{
|
|
rcText.left=rcItem.left + (*nIndent) + nImgWidth;
|
|
rcText.right=rcText.left + szText.cx;
|
|
}
|
|
break;
|
|
case LVCFMT_RIGHT:
|
|
{
|
|
rcText.right=rcItem.left + GetColumnWidth(0);
|
|
rcText.left=rcText.right - szText.cx;
|
|
}
|
|
break;
|
|
case LVCFMT_CENTER:
|
|
{
|
|
int dx=(GetColumnWidth(0)-nImgWidth-(*nIndent)-szText.cx)/2;
|
|
if(dx < 0)
|
|
dx=0;
|
|
rcText.left=rcItem.left + (*nIndent) + nImgWidth + dx;
|
|
rcText.right=rcText.left + GetColumnWidth(0) - dx;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
(*rTarget)=rcText;
|
|
}
|
|
break;
|
|
default:
|
|
// unknown kind of rect passed!
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
CSize COXTreeCtrl::GetColTextExtent(int nIndex,int nCol) const
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :dimension of specified item's text
|
|
//--- Effect :
|
|
{
|
|
ASSERT(nCol <= GetColumnsCount());//column number must be valid!
|
|
|
|
COXTreeItem *xti=(COXTreeItem*)CListCtrl::GetItemData(nIndex);
|
|
ASSERT_POINTER(xti,COXTreeItem);
|
|
|
|
CString sText=GetItemText((HTREEITEM) xti,nCol);
|
|
CWnd* pWnd=(CWnd*)this;
|
|
CDC *pDC=pWnd->GetDC();
|
|
CFont * pOldFont=NULL;
|
|
if(xti->HasFont(nCol))
|
|
pOldFont=pDC->SelectObject(xti->GetItemFont(nCol));
|
|
|
|
CSize sz=pDC->GetTextExtent(sText);
|
|
sz.cx=__min(sz.cx,GetColumnWidth(nCol));
|
|
if(xti->HasFont(nCol))
|
|
pDC->SelectObject(pOldFont);
|
|
pWnd->ReleaseDC(pDC);
|
|
return sz;
|
|
}
|
|
|
|
int COXTreeCtrl::GetColumnsCount() const
|
|
{
|
|
int cnt=0;
|
|
LV_COLUMN lvc;
|
|
memset(&lvc, 0, sizeof(LV_COLUMN));
|
|
lvc.mask=LVCF_FMT;
|
|
while(GetColumn(cnt, &lvc))
|
|
cnt++;
|
|
return cnt;
|
|
}
|
|
|
|
void COXTreeCtrl::DrawItemImages(CDC *pDC, COXTreeItem* xti, int nItem,
|
|
CRect& rcItem, int nCol, BOOL bRowSel)
|
|
{
|
|
UNREFERENCED_PARAMETER(nItem);
|
|
|
|
CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
|
|
CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
|
|
|
|
IMAGEINFO imi;
|
|
CRect rcErase;
|
|
CRect rcImage;
|
|
CPoint ptStart;
|
|
if(pStateImgList && nCol == 0)
|
|
{
|
|
int idx=STATEIMAGEMASKTOINDEX(xti->m_tvi.state)-1;
|
|
if(idx != -1)
|
|
{
|
|
// ask the image size
|
|
pStateImgList->GetImageInfo(idx,&imi);
|
|
// clear the entry image rect
|
|
rcErase=rcItem;
|
|
rcImage=imi.rcImage;
|
|
rcErase.right=rcErase.left + rcImage.Width();
|
|
/* The COXTreeCtrl did not paint checkboxes properly when the
|
|
control lost focus, in this situation all check boxes would
|
|
be painted with the background of COLOR_BTNFACE.
|
|
pDC->FillSolidRect(
|
|
&rcErase,((GetFocus()!=this || !IsWindowEnabled()) ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));*/
|
|
ptStart=rcItem.TopLeft();
|
|
if(rcImage.Height()<rcErase.Height())
|
|
{
|
|
ptStart.y+=(rcErase.Height()-rcImage.Height())/2;
|
|
}
|
|
// now draw the state img
|
|
pStateImgList->Draw(pDC,idx,ptStart,ILD_TRANSPARENT);
|
|
// Move left of the item rect to draw text later
|
|
rcItem.left += CRect(imi.rcImage).Width();
|
|
}
|
|
}
|
|
if(nCol == 0)
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
// retreive item's images and state
|
|
tvi.mask=TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE | TVIF_STATE;
|
|
tvi.stateMask=TVIS_SELECTED;
|
|
tvi.hItem=(HTREEITEM)xti;
|
|
if(!GetItem(&tvi))
|
|
return;
|
|
if(pImgList)
|
|
{
|
|
int nImg;
|
|
if(tvi.state & TVIS_SELECTED)
|
|
{
|
|
nImg=tvi.iSelectedImage;
|
|
}
|
|
else
|
|
{
|
|
nImg=tvi.iImage;
|
|
}
|
|
if(nImg==-1)
|
|
{
|
|
return;
|
|
}
|
|
// ask the image size
|
|
pImgList->GetImageInfo(nImg,&imi);
|
|
// clear the entry image rect
|
|
rcErase=rcItem;
|
|
rcImage=imi.rcImage;
|
|
rcErase.right=rcErase.left + rcImage.Width();
|
|
|
|
if (xti->HasBackColor(nCol))
|
|
pDC->FillSolidRect(&rcErase,
|
|
(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol)));
|
|
else
|
|
pDC->FillSolidRect(&rcErase,
|
|
(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
|
|
|
|
ptStart=rcItem.TopLeft();
|
|
if(rcImage.Height()<rcErase.Height())
|
|
{
|
|
ptStart.y+=(rcErase.Height()-rcImage.Height())/2;
|
|
}
|
|
pImgList->Draw(pDC,nImg,ptStart,ILD_TRANSPARENT);
|
|
rcItem.left += CRect(imi.rcImage).Width();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nImg=xti->GetSubItemImage(nCol);
|
|
if(nImg >= 0)
|
|
{
|
|
ASSERT(nImg < pImgList->GetImageCount());
|
|
COLORREF clrBack=CLR_NONE;
|
|
pImgList->GetImageInfo(nImg,&imi);
|
|
// ask the image size
|
|
pImgList->GetImageInfo(nImg,&imi);
|
|
// clear the entry image rect
|
|
rcErase=rcItem;
|
|
rcImage=imi.rcImage;
|
|
rcErase.right=rcErase.left + CRect(imi.rcImage).Width();
|
|
// if entry row selection mode set, set subitem image
|
|
// background color
|
|
if(bRowSel)
|
|
{
|
|
if (xti->HasBackColor(nCol))
|
|
{
|
|
clrBack=pImgList->SetBkColor(
|
|
(GetFocus()!=this || !IsWindowEnabled()) ?
|
|
::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol));
|
|
COLORREF clrBkDC=pDC->GetBkColor();
|
|
pDC->FillSolidRect(&rcErase,
|
|
(GetFocus()!=this || !IsWindowEnabled()) ?
|
|
::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol));
|
|
pDC->SetBkColor(clrBkDC);
|
|
}
|
|
else
|
|
{
|
|
clrBack=pImgList->SetBkColor(
|
|
(GetFocus()!=this || !IsWindowEnabled()) ?
|
|
::GetSysColor(COLOR_BTNFACE) : ::GetSysColor(COLOR_HIGHLIGHT));
|
|
COLORREF clrBkDC=pDC->GetBkColor();
|
|
pDC->FillSolidRect(&rcErase,
|
|
(GetFocus()!=this || !IsWindowEnabled()) ?
|
|
::GetSysColor(COLOR_BTNFACE) : ::GetSysColor(COLOR_HIGHLIGHT));
|
|
pDC->SetBkColor(clrBkDC);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xti->HasBackColor(nCol))
|
|
pDC->FillSolidRect(&rcErase,
|
|
(!IsWindowEnabled() ? ::GetSysColor(COLOR_BTNFACE) : xti->GetItemBackColor(nCol)));
|
|
else
|
|
pDC->FillSolidRect(&rcErase,(!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
|
|
}
|
|
|
|
ptStart=rcItem.TopLeft();
|
|
if(rcImage.Height()<rcErase.Height())
|
|
{
|
|
ptStart.y+=(rcErase.Height()-rcImage.Height())/2;
|
|
}
|
|
pImgList->Draw(pDC,nImg,ptStart,bRowSel ? ILD_FOCUS : ILD_TRANSPARENT);
|
|
if(bRowSel)
|
|
{
|
|
pImgList->SetBkColor(clrBack);
|
|
}
|
|
rcItem.left += CRect(imi.rcImage).Width();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL COXTreeCtrl::SetItem(TV_ITEM *pTVI)
|
|
{
|
|
// user must provide a valid handle
|
|
ASSERT(pTVI->mask & TVIF_HANDLE);
|
|
COXTreeItem *xti=GetXItem(pTVI->hItem);
|
|
ASSERT(xti);
|
|
UINT uMaskCb=0;// mask for send TVN_SETDISPINFO
|
|
|
|
if(pTVI->mask & TVIF_IMAGE)
|
|
{
|
|
xti->m_tvi.iImage=pTVI->iImage;
|
|
if(pTVI->iImage == I_IMAGECALLBACK)
|
|
uMaskCb |= TVIF_IMAGE;
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_TEXT)
|
|
{
|
|
if(pTVI->pszText == LPSTR_TEXTCALLBACK)
|
|
{
|
|
if(xti->m_tvi.pszText && xti->m_tvi.pszText != LPSTR_TEXTCALLBACK)
|
|
delete [] xti->m_tvi.pszText;
|
|
|
|
xti->m_tvi.pszText=LPSTR_TEXTCALLBACK;
|
|
uMaskCb |= TVIF_TEXT;
|
|
}
|
|
else
|
|
{
|
|
// allocate space for new item text and copy string
|
|
TCHAR * pChar=new TCHAR[_tcslen(pTVI->pszText) + 1];
|
|
UTBStr::tcscpy(pChar, _tcslen(pTVI->pszText) + 1, pTVI->pszText);
|
|
// The user specified new text for item
|
|
if(xti->m_tvi.pszText && xti->m_tvi.pszText != LPSTR_TEXTCALLBACK)
|
|
delete [] xti->m_tvi.pszText;
|
|
xti->m_tvi.pszText=pChar;
|
|
}
|
|
}
|
|
|
|
if (pTVI->mask & TVIF_STATE)
|
|
{
|
|
xti->m_tvi.state &= ~(pTVI->stateMask);
|
|
xti->m_tvi.state |= pTVI->state;
|
|
if (pTVI->stateMask & TVIS_STATEIMAGEMASK)
|
|
{
|
|
xti->m_tvi.state |= (pTVI->state & TVIS_STATEIMAGEMASK);
|
|
}
|
|
if (pTVI->stateMask & TVIS_OVERLAYMASK)
|
|
{
|
|
xti->m_tvi.state |= (pTVI->state & TVIS_OVERLAYMASK) ? TVIS_OVERLAYMASK : 0;
|
|
}
|
|
if (pTVI->stateMask & TVIS_CUT)
|
|
{
|
|
xti->m_tvi.state |= (pTVI->state & TVIS_CUT) ? TVIS_CUT : 0;
|
|
}
|
|
if (pTVI->stateMask & TVIS_DROPHILITED)
|
|
{
|
|
xti->m_tvi.state |= (pTVI->state & TVIS_DROPHILITED) ? TVIS_DROPHILITED : 0;
|
|
}
|
|
if(pTVI->stateMask & TVIS_EXPANDED)
|
|
{
|
|
xti->m_tvi.state |= (pTVI->state & TVIS_EXPANDED) ? TVIS_EXPANDED : 0;
|
|
}
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_PARAM)
|
|
{
|
|
xti->m_tvi.lParam=pTVI->lParam;
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_SELECTEDIMAGE)
|
|
{
|
|
xti->m_tvi.iSelectedImage=pTVI->iSelectedImage;
|
|
if(pTVI->iSelectedImage == I_IMAGECALLBACK)
|
|
uMaskCb |= TVIF_SELECTEDIMAGE;
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_CHILDREN)
|
|
{
|
|
xti->m_tvi.cChildren=pTVI->cChildren;
|
|
}
|
|
|
|
if(uMaskCb != 0)
|
|
{
|
|
// If any callback detected, send TVN_SETDISPINFO notification to parent
|
|
pTVI->mask=uMaskCb;
|
|
SendSetDispInfoNotify(pTVI);
|
|
}
|
|
|
|
// Now translate TVIF_xxx to LVIF_xxx
|
|
|
|
int nItem=GetItemIndexInternal(xti);
|
|
if(nItem != -1) // item currently in list ctrl
|
|
{
|
|
LV_ITEM lvi;
|
|
memset(&lvi, 0, sizeof(LV_ITEM));
|
|
lvi.iItem=nItem;
|
|
lvi.iSubItem=0;
|
|
if (pTVI->mask & TVIF_IMAGE)
|
|
{
|
|
lvi.mask |= LVIF_IMAGE;
|
|
lvi.iImage=pTVI->iImage;
|
|
}
|
|
if (pTVI->mask & TVIF_STATE)
|
|
{
|
|
lvi.mask |= LVIF_STATE;
|
|
if (pTVI->stateMask & TVIS_STATEIMAGEMASK)
|
|
{
|
|
lvi.state |= (pTVI->state & TVIS_STATEIMAGEMASK);
|
|
lvi.stateMask |= LVIS_STATEIMAGEMASK;
|
|
}
|
|
if (pTVI->stateMask & TVIS_SELECTED)
|
|
{
|
|
lvi.state |= (pTVI->state & TVIS_SELECTED) ? LVIS_SELECTED : 0;
|
|
lvi.stateMask |= LVIS_SELECTED;
|
|
}
|
|
if (pTVI->stateMask & TVIS_OVERLAYMASK)
|
|
{
|
|
lvi.state |= (pTVI->state & TVIS_OVERLAYMASK) ? LVIS_OVERLAYMASK : 0;
|
|
lvi.stateMask |= LVIS_OVERLAYMASK;
|
|
}
|
|
if (pTVI->stateMask & TVIS_CUT)
|
|
{
|
|
lvi.state |= (pTVI->state & TVIS_CUT) ? LVIS_CUT : 0;
|
|
lvi.stateMask |= LVIS_CUT;
|
|
}
|
|
if (pTVI->stateMask & TVIS_DROPHILITED)
|
|
{
|
|
lvi.state |= (pTVI->state & TVIS_DROPHILITED) ? LVIS_DROPHILITED : 0;
|
|
lvi.stateMask |= LVIS_DROPHILITED;
|
|
}
|
|
if(pTVI->stateMask & TVIS_EXPANDED)
|
|
{
|
|
UINT nCode=(pTVI->state & TVIS_EXPANDED)? TVE_EXPAND : TVE_COLLAPSE;
|
|
Expand(pTVI->hItem,nCode);
|
|
}
|
|
}
|
|
if(!CListCtrl::SetItem(&lvi))
|
|
return FALSE;
|
|
}
|
|
|
|
if((m_hOldDropTarget!=pTVI->hItem) && (nItem!=-1) &&
|
|
(pTVI->mask&TVIF_STATE) && (pTVI->stateMask&TVIS_DROPHILITED) &&
|
|
(pTVI->state&TVIS_DROPHILITED))
|
|
{
|
|
if(m_hOldDropTarget!=NULL)
|
|
{
|
|
SetItemState(m_hOldDropTarget,0,TVIS_DROPHILITED);
|
|
}
|
|
m_hOldDropTarget=pTVI->hItem;
|
|
UpdateWindow();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXTreeCtrl::SendSetDispInfoNotify(TV_ITEM* pTVI)
|
|
{
|
|
TV_DISPINFO di;
|
|
|
|
di.hdr.code =TVN_SETDISPINFO;
|
|
di.hdr.hwndFrom=GetSafeHwnd();
|
|
di.hdr.idFrom =GetDlgCtrlID();
|
|
|
|
di.item=*pTVI;
|
|
|
|
//Now send TVN_SETDISPINFO notification message to parent
|
|
GetParent()->SendMessage(WM_NOTIFY,di.hdr.idFrom,(LPARAM)&di);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage,
|
|
int nSelectedImage, UINT nState, UINT nStateMask,
|
|
LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(nStateMask);
|
|
UNREFERENCED_PARAMETER(nState);
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=nMask;
|
|
tvi.hItem=hItem;
|
|
tvi.pszText=(LPTSTR)lpszItem;
|
|
tvi.iImage=nImage;
|
|
tvi.iSelectedImage=nSelectedImage;
|
|
tvi.lParam=lParam;
|
|
return SetItem(&tvi);
|
|
}
|
|
|
|
|
|
BOOL COXTreeCtrl::GetItem(TV_ITEM *pTVI) const
|
|
{
|
|
COXTreeItem *xti=GetXItem(pTVI->hItem);
|
|
ASSERT(xti);
|
|
UINT uMaskCb=0;// mask for send TVN_GEIDISPINFO if nesessary
|
|
|
|
if(pTVI->mask & TVIF_TEXT)
|
|
{
|
|
if(xti->m_tvi.pszText == LPSTR_TEXTCALLBACK)
|
|
{
|
|
uMaskCb |= TVIF_TEXT;
|
|
}
|
|
else if(xti->m_tvi.pszText)
|
|
{
|
|
UTBStr::tcsncpy(pTVI->pszText, pTVI->cchTextMax, xti->m_tvi.pszText,pTVI->cchTextMax);
|
|
}
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_IMAGE)
|
|
{
|
|
if(xti->m_tvi.iImage == I_IMAGECALLBACK)
|
|
uMaskCb |= TVIF_IMAGE;
|
|
pTVI->iImage=xti->m_tvi.iImage;
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_PARAM)
|
|
pTVI->lParam=xti->m_tvi.lParam;
|
|
|
|
if(pTVI->mask & TVIF_SELECTEDIMAGE)
|
|
{
|
|
if(xti->m_tvi.iSelectedImage == I_IMAGECALLBACK)
|
|
uMaskCb |= TVIF_SELECTEDIMAGE;
|
|
pTVI->iSelectedImage=xti->m_tvi.iSelectedImage;
|
|
}
|
|
|
|
if (pTVI->mask & TVIF_STATE)
|
|
{
|
|
int idx=GetItemIndexInternal(xti);
|
|
xti->m_tvi.state &= ~(TVIS_SELECTED | LVIS_FOCUSED | TVIS_EXPANDED |
|
|
TVIS_EXPANDEDONCE);
|
|
if(idx != -1)
|
|
{
|
|
UINT uStt=CListCtrl::GetItemState(idx,LVIS_SELECTED | LVIS_FOCUSED);
|
|
if(uStt & LVIS_SELECTED)
|
|
xti->m_tvi.state |= TVIS_SELECTED;
|
|
if(uStt & LVIS_FOCUSED)
|
|
xti->m_tvi.state |= LVIS_FOCUSED;
|
|
}
|
|
if(xti->IsExpanded())
|
|
xti->m_tvi.state |= TVIS_EXPANDED;
|
|
if(xti->IsExpandedOnce())
|
|
xti->m_tvi.state |= TVIS_EXPANDEDONCE;
|
|
pTVI->state=(xti->m_tvi.state & pTVI->stateMask);
|
|
}
|
|
|
|
if(pTVI->mask & TVIF_CHILDREN)
|
|
{
|
|
pTVI->cChildren=xti->m_tvi.cChildren;
|
|
}
|
|
|
|
if(uMaskCb != 0)
|
|
{
|
|
pTVI->mask=uMaskCb;
|
|
pTVI->lParam=xti->m_tvi.lParam;
|
|
SendGetDispInfoNotify(pTVI);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void COXTreeCtrl::SendGetDispInfoNotify(TV_ITEM *pTVI) const
|
|
{
|
|
TV_DISPINFO di;
|
|
di.hdr.code =TVN_GETDISPINFO;
|
|
di.hdr.hwndFrom=GetSafeHwnd();
|
|
di.hdr.idFrom =GetDlgCtrlID();
|
|
di.item=*pTVI;
|
|
|
|
//Now send TVN_GETDISPINFO notification message to parent
|
|
GetParent()->SendMessage(WM_NOTIFY,di.hdr.idFrom,(LPARAM)&di);
|
|
// save the changed item info
|
|
*pTVI=di.item;
|
|
}
|
|
|
|
CString COXTreeCtrl::GetItemText(HTREEITEM hItem,int nCol) const
|
|
{
|
|
static TCHAR t[_OX_MAX_ITEM_TEXT];
|
|
ASSERT(nCol >= 0);
|
|
|
|
// make sure that the string buffer is empty
|
|
t[0] = 0;
|
|
|
|
if(nCol == 0)
|
|
{
|
|
TV_ITEM item;
|
|
item.hItem=hItem;
|
|
item.mask=TVIF_TEXT;
|
|
item.cchTextMax=sizeof(t)/sizeof(TCHAR);
|
|
item.pszText=t;
|
|
GetItem(&item);
|
|
return t;
|
|
}
|
|
else
|
|
{
|
|
COXTreeItem * xti=GetXItem(hItem);
|
|
if(xti)
|
|
return xti->GetSubItemText(nCol);
|
|
}
|
|
return _T("");
|
|
}
|
|
|
|
BOOL COXTreeCtrl::GetItemImage(HTREEITEM hItem,int &nImg,int &nSelImg,int nCol)
|
|
{
|
|
if(nCol == 0)
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE;
|
|
tvi.hItem=hItem;
|
|
if(!GetItem(&tvi))
|
|
return FALSE;
|
|
nImg=tvi.iImage;
|
|
nSelImg=tvi.iSelectedImage;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
COXTreeItem* xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
int nIm=xti->GetSubItemImage(nCol);
|
|
if(nIm == -1)
|
|
return FALSE;
|
|
nImg=nIm;
|
|
nSelImg=0;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemImage(HTREEITEM hItem, int nImage,
|
|
int nSelectedImage, int nCol)
|
|
{
|
|
if(nCol == 0)
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE;
|
|
tvi.hItem=hItem;
|
|
tvi.iImage=nImage;
|
|
tvi.iSelectedImage=nSelectedImage;
|
|
return SetItem(&tvi);
|
|
}
|
|
else
|
|
{
|
|
if(nImage!=nSelectedImage)
|
|
{
|
|
TRACE(_T("COXTreeCtrl::SetItemImage: the selected image is not supported for subitems, ignored\n"));
|
|
}
|
|
return SetSubItem(hItem,nCol,OX_SUBITEM_IMAGE,NULL,nImage);
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::GetItemDrawEllipsis(HTREEITEM hItem, UINT& nEllipsisFormat,
|
|
int nCol/*=0*/) const
|
|
{
|
|
COXTreeItem* xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
nEllipsisFormat=xti->GetDrawEllipsis(nCol);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemDrawEllipsis(HTREEITEM hItem, UINT nEllipsisFormat,
|
|
int nCol/*=0*/)
|
|
{
|
|
COXTreeItem* xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
xti->SetDrawEllipsis(nEllipsisFormat,nCol);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::ModifyStyle(DWORD dwRemove, DWORD dwAdd,
|
|
UINT nFlags/*=0*/)
|
|
{
|
|
DWORD dwLCStyleAdd=0;// list control style to add
|
|
DWORD dwLCStyleRemove=0;// list control style to remove
|
|
|
|
if(dwRemove & TVS_SHOWSELALWAYS)
|
|
dwLCStyleRemove |= LVS_SHOWSELALWAYS;
|
|
|
|
if(dwRemove & TVS_EDITLABELS)
|
|
dwLCStyleRemove |= LVS_EDITLABELS;
|
|
|
|
if(dwAdd & TVS_SHOWSELALWAYS)
|
|
dwLCStyleAdd |= LVS_SHOWSELALWAYS;
|
|
|
|
if(dwAdd & TVS_EDITLABELS)
|
|
dwLCStyleAdd |= LVS_EDITLABELS;
|
|
// add common window styles
|
|
|
|
dwLCStyleAdd |= (dwAdd & 0xffff0000);
|
|
dwLCStyleRemove |= (dwRemove & 0xffff0000);
|
|
|
|
|
|
if(dwLCStyleRemove || dwLCStyleAdd)
|
|
if(!CListCtrl::ModifyStyle(dwLCStyleRemove,dwLCStyleAdd,nFlags))
|
|
return FALSE;
|
|
DWORD dwStyleOld=m_dwTCStyle;
|
|
m_dwTCStyle |= dwAdd;
|
|
m_dwTCStyle &= ~dwRemove;
|
|
if(dwStyleOld != m_dwTCStyle)
|
|
{
|
|
Invalidate();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD COXTreeCtrl::GetStyle() const
|
|
{
|
|
DWORD dwStyle=m_dwTCStyle | (IsWindowVisible()? 0x10000000L :0);
|
|
return dwStyle;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::ModifyExStyle(DWORD dwExStyleRemove,DWORD dwExStyleAdd,
|
|
UINT nFlags/*=0*/)
|
|
{
|
|
DWORD dwLCStyleAdd=0;// list control style to add
|
|
DWORD dwLCStyleRemove=0;// list control style to remove
|
|
|
|
if(dwExStyleAdd & TVOXS_MULTISEL)
|
|
dwLCStyleRemove |= LVS_SINGLESEL;
|
|
|
|
if(dwExStyleRemove & TVOXS_MULTISEL)
|
|
dwLCStyleAdd |= LVS_SINGLESEL;
|
|
|
|
if(dwExStyleAdd & TVOXS_COLUMNHDR)
|
|
dwLCStyleRemove |= LVS_NOCOLUMNHEADER;
|
|
|
|
if(dwExStyleRemove & TVOXS_COLUMNHDR)
|
|
dwLCStyleAdd |= LVS_NOCOLUMNHEADER;
|
|
|
|
if(dwExStyleAdd & TVOXS_NOSCROLL)
|
|
dwLCStyleAdd |= LVS_NOSCROLL;
|
|
|
|
if(dwExStyleRemove & TVOXS_NOSCROLL)
|
|
dwLCStyleRemove |= LVS_NOSCROLL;
|
|
|
|
if(dwExStyleAdd & TVOXS_NOSORTHEADER)
|
|
dwLCStyleAdd |= LVS_NOSORTHEADER;
|
|
|
|
if(dwExStyleRemove & TVOXS_NOSORTHEADER)
|
|
dwLCStyleRemove |= LVS_NOSORTHEADER;
|
|
|
|
if(dwExStyleAdd & TVOXS_SHAREIMAGELISTS)
|
|
dwLCStyleAdd |= LVS_SHAREIMAGELISTS;
|
|
|
|
if(dwExStyleRemove & TVOXS_SHAREIMAGELISTS)
|
|
dwLCStyleRemove |= LVS_SHAREIMAGELISTS;
|
|
|
|
|
|
if(dwLCStyleRemove || dwLCStyleAdd)
|
|
if(!CListCtrl::ModifyStyle(dwLCStyleRemove,dwLCStyleAdd,nFlags))
|
|
return FALSE;
|
|
|
|
if((dwExStyleAdd&TVOXS_ITEMTIPS) && !(m_dwExStyle&TVOXS_ITEMTIPS))
|
|
{
|
|
#ifndef OX_TREECTRL_NOITEMTIPS
|
|
m_ItemTip.Attach(this);
|
|
#endif
|
|
}
|
|
|
|
if((dwExStyleRemove&TVOXS_ITEMTIPS) && (m_dwExStyle&TVOXS_ITEMTIPS))
|
|
{
|
|
#ifndef OX_TREECTRL_NOITEMTIPS
|
|
m_ItemTip.Detach();
|
|
#endif
|
|
}
|
|
|
|
DWORD dwOld=m_dwExStyle;
|
|
m_dwExStyle |= dwExStyleAdd;
|
|
m_dwExStyle &= ~dwExStyleRemove;
|
|
if(m_dwExStyle != dwOld)
|
|
Invalidate();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD COXTreeCtrl::GetExStyle() const
|
|
{
|
|
return m_dwExStyle;
|
|
}
|
|
|
|
int COXTreeCtrl::InsertColumn(int nCol, const LV_COLUMN* pColumn)
|
|
{
|
|
BOOL bRet= CListCtrl::InsertColumn(nCol,pColumn);
|
|
return bRet;
|
|
}
|
|
|
|
int COXTreeCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading,
|
|
int nFormat, int nWidth, int nSubItem)
|
|
{
|
|
BOOL bRet=CListCtrl::InsertColumn(nCol,lpszColumnHeading,nFormat,
|
|
nWidth,nSubItem);
|
|
return bRet;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetSubItem(HTREEITEM hItem, int nColumn, UINT uFlags,
|
|
LPCTSTR lpszText, int nImage, CFont *pFont, COLORREF clr, COLORREF clrBack)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
if(nColumn <= 0)
|
|
return FALSE;
|
|
BOOL bRet=xti->SetSubItem(nColumn,uFlags,lpszText,nImage,pFont,clr,clrBack);
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(bRet && idx != -1)
|
|
{
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::HideItem(HTREEITEM hItem,BOOL bHide)
|
|
{
|
|
ASSERT(hItem != TVI_ROOT);
|
|
if (hItem==TVI_ROOT)
|
|
return FALSE;
|
|
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
if(xti->IsHidden() == bHide)
|
|
return TRUE; // already hidden
|
|
|
|
SetRedraw(FALSE);
|
|
|
|
BOOL bResult=TRUE;
|
|
|
|
HTREEITEM hPrevVisibleItem=GetPrevVisibleItem(hItem);
|
|
HTREEITEM hPrevSiblingItem=GetPrevSiblingItem(hItem);
|
|
|
|
xti->SetHidden(bHide);
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(idx == -1 && bHide)
|
|
{
|
|
bResult=TRUE;
|
|
}
|
|
else
|
|
{
|
|
BOOL bItemExp=xti->IsExpanded();
|
|
if(bHide && !bItemExp)
|
|
{
|
|
bResult=CListCtrl::DeleteItem(idx);
|
|
}
|
|
else if(bHide && bItemExp)
|
|
{
|
|
xti->RemoveChildrenFromCtrl(this);
|
|
bResult=CListCtrl::DeleteItem(idx);
|
|
}
|
|
else if(xti->IsVisible())
|
|
{
|
|
if(!AddItemToCtrl(xti))
|
|
{
|
|
bResult=FALSE;
|
|
}
|
|
else
|
|
{
|
|
idx=GetItemIndexInternal(xti);
|
|
ASSERT(idx != -1);
|
|
if(xti->IsExpanded())
|
|
{
|
|
xti->AddChildrenToCtrl(this,idx + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bResult && hPrevVisibleItem!=NULL && hPrevSiblingItem!=NULL)
|
|
RedrawTreeItems(hPrevSiblingItem,hPrevVisibleItem);
|
|
|
|
SetRedraw(TRUE);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::DeleteItem(HTREEITEM hItem)
|
|
{
|
|
HTREEITEM hParentItem=GetParentItem(hItem);
|
|
|
|
TV_ITEM tvi;
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(xti != &m_xtiRoot && !HideItem(hItem))
|
|
return FALSE;
|
|
if(xti == &m_xtiRoot)
|
|
{
|
|
::ZeroMemory(&tvi, sizeof(tvi));
|
|
tvi.hItem=xti->m_tvi.hItem;
|
|
SendDeleteItemNotify(&tvi);
|
|
xti->DeleteChildren();
|
|
m_nItemsCount=0;
|
|
return CListCtrl::DeleteAllItems();
|
|
}
|
|
|
|
if(hParentItem!=NULL)
|
|
{
|
|
COXTreeItem *xtiParent=GetXItem(hParentItem);
|
|
ASSERT(xtiParent!=NULL);
|
|
if(xtiParent->GetChildrenCount()<=1 && xtiParent->m_tvi.cChildren==1)
|
|
{
|
|
xtiParent->m_tvi.cChildren=0;
|
|
if(xtiParent!=&m_xtiRoot)
|
|
{
|
|
xtiParent->m_bExpand=FALSE;
|
|
xtiParent->m_bExpandedOnce=FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi=xti->m_tvi;
|
|
tvi.mask |= TVIF_HANDLE;
|
|
tvi.hItem=(HTREEITEM) xti;
|
|
|
|
SendDeleteItemNotify(&tvi);
|
|
xti->RemoveChildrenFromCtrl(this);
|
|
|
|
// item should have been already deleted from list
|
|
ASSERT(GetItemIndexInternal(xti)==-1);
|
|
delete xti;
|
|
ASSERT(m_nItemsCount);
|
|
m_nItemsCount--;
|
|
|
|
if (hParentItem != NULL)
|
|
{
|
|
COXTreeItem* pParent = GetXItem(hParentItem);
|
|
if (pParent->GetChildrenCount() == 0)
|
|
RedrawTreeItems(hParentItem, hParentItem);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::DeleteAllItems()
|
|
{
|
|
ASSERT(&m_xtiRoot);
|
|
return DeleteItem(GetRootItem());
|
|
}
|
|
|
|
BOOL COXTreeCtrl::DeleteColumn(int nCol)
|
|
{
|
|
if(nCol==0)
|
|
{
|
|
if(!DeleteAllItems())
|
|
{
|
|
return FALSE;
|
|
}
|
|
while(CListCtrl::DeleteColumn(0));
|
|
return TRUE;
|
|
}
|
|
|
|
if(DeleteSubitems(GetRootItem(),nCol))
|
|
{
|
|
return CListCtrl::DeleteColumn(nCol);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::DeleteSubitems(HTREEITEM hParentItem, int nCol)
|
|
{
|
|
BOOL bSuccess=TRUE;
|
|
HTREEITEM hItem=GetNextItem(hParentItem,TVGN_CHILD);
|
|
while(hItem!=NULL)
|
|
{
|
|
COXTreeItem* pItem=GetXItem(hItem);
|
|
ASSERT(pItem!=NULL);
|
|
pItem->DeleteSubitem(nCol);
|
|
if(!DeleteSubitems(hItem,nCol))
|
|
{
|
|
bSuccess=FALSE;
|
|
break;
|
|
}
|
|
hItem=GetNextItem(hItem,TVGN_NEXT);
|
|
}
|
|
|
|
return (bSuccess);
|
|
}
|
|
|
|
|
|
UINT COXTreeCtrl::GetVisibleCount() const
|
|
{
|
|
return CListCtrl::GetItemCount();
|
|
}
|
|
|
|
UINT COXTreeCtrl::GetCount() const
|
|
{
|
|
return m_nItemsCount;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetNextItem(HTREEITEM hItem, UINT nCode)
|
|
{
|
|
COXTreeItem * xti=GetXItem(hItem);
|
|
int idx;
|
|
switch(nCode)
|
|
{
|
|
case TVGN_CHILD:
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM)(xti->pxFirstChild);
|
|
|
|
case TVGN_FIRSTVISIBLE:
|
|
return GetFirstVisibleItem();
|
|
|
|
case TVGN_NEXTVISIBLE:
|
|
return GetNextVisibleItem(hItem,FALSE);
|
|
|
|
case TVGN_PREVIOUSVISIBLE:
|
|
return GetPrevVisibleItem(hItem,FALSE);
|
|
|
|
case TVGN_DROPHILITE:
|
|
{
|
|
if(!xti)
|
|
idx=-1;
|
|
else
|
|
idx=GetItemIndexInternal(xti);
|
|
int idNext=CListCtrl::GetNextItem(idx,LVNI_DROPHILITED);
|
|
if(idNext == -1 || idNext >= CListCtrl::GetItemCount())
|
|
return NULL;
|
|
return (HTREEITEM) CListCtrl::GetItemData(idNext);
|
|
}
|
|
|
|
case TVGN_NEXT:
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM)(xti->pxNext);
|
|
|
|
case TVGN_CARET:
|
|
idx=CListCtrl::GetNextItem(-1,LVNI_FOCUSED);
|
|
if(idx == -1)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
HTREEITEM hti=GetItemFromIndex(idx);
|
|
if(hti && GetItemState(hti,LVIS_SELECTED)==LVIS_SELECTED)
|
|
{
|
|
return hti;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
case TVGN_PARENT:
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM) (xti->pxParent);
|
|
|
|
case TVGN_PREVIOUS:
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM) (xti->pxPrev);
|
|
|
|
case TVGN_ROOT:
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM)(xti->pxParent ? xti->pxParent->pxFirstChild : NULL);
|
|
|
|
case TVGN_FIRSTSELECTED:
|
|
idx=CListCtrl::GetNextItem(-1,LVNI_SELECTED);
|
|
if(idx == -1)
|
|
return NULL;
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
|
|
case TVGN_NEXTSELECTED:
|
|
if(!xti)
|
|
return NULL;
|
|
idx=GetItemIndexInternal(xti);
|
|
if(idx == -1)
|
|
return NULL;
|
|
idx=CListCtrl::GetNextItem(idx,LVNI_SELECTED);
|
|
if(idx == -1)
|
|
return NULL;
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
|
|
}
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetFirstVisibleItem()
|
|
{
|
|
int idx=CListCtrl::GetTopIndex();
|
|
if(idx == -1 || idx >= CListCtrl::GetItemCount())
|
|
return NULL;
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetNextVisibleItem(HTREEITEM hItem,
|
|
BOOL bCurrentlyViewable/*=FALSE*/)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
// walk down throuth tree structure and find the next item in list ctrl
|
|
if(!xti)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
HTREEITEM hItemFirstVisible=GetFirstVisibleItem();
|
|
ASSERT(hItemFirstVisible!=NULL);
|
|
CRect rectFistVisible;
|
|
GetItemRect(hItemFirstVisible,rectFistVisible,FALSE);
|
|
rect.top=rectFistVisible.top;
|
|
|
|
xti=xti->GetNextInTree();
|
|
for(; xti ; xti=xti->GetNextInTree())
|
|
{
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(idx != -1)
|
|
{
|
|
if(bCurrentlyViewable)
|
|
{
|
|
CRect rectItem;
|
|
CListCtrl::GetItemRect(idx,rectItem,LVIR_BOUNDS);
|
|
if((rectItem.top>=rect.top && rectItem.top<=rect.bottom) ||
|
|
(rectItem.bottom>=rect.top && rectItem.bottom<=rect.bottom))
|
|
{
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetPrevVisibleItem(HTREEITEM hItem,
|
|
BOOL bCurrentlyViewable/*=FALSE*/)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
// walk up throuth tree structure and find the item in list ctrl
|
|
if(!xti)
|
|
return NULL;
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
HTREEITEM hItemFirstVisible=GetFirstVisibleItem();
|
|
if(hItemFirstVisible==NULL)
|
|
return NULL;
|
|
|
|
CRect rectFistVisible;
|
|
GetItemRect(hItemFirstVisible,rectFistVisible,FALSE);
|
|
rect.top=rectFistVisible.top;
|
|
|
|
xti=xti->GetPrevInTree();
|
|
for(; xti ; xti=xti->GetPrevInTree())
|
|
{
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(idx != -1)
|
|
{
|
|
if(bCurrentlyViewable)
|
|
{
|
|
CRect rectItem;
|
|
CListCtrl::GetItemRect(idx,rectItem,LVIR_BOUNDS);
|
|
if((rectItem.top>=rect.top && rectItem.top<=rect.bottom) ||
|
|
(rectItem.bottom>=rect.top && rectItem.bottom<=rect.bottom))
|
|
{
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetFirstHiddenItem()
|
|
{
|
|
COXTreeItem *xti=&m_xtiRoot;// start form root item
|
|
|
|
xti=xti->GetNextInTree();
|
|
// now iterate the tree and find first hidden item
|
|
for(; xti ; xti=xti->GetNextInTree())
|
|
{
|
|
if(xti->IsHidden())
|
|
return (HTREEITEM) xti;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetNextHiddenItem(HTREEITEM hItem)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
xti=xti->GetNextInTree();
|
|
// now iterate the tree and stop when a hidden item found
|
|
for(; xti ; xti=xti->GetNextInTree())
|
|
{
|
|
if(xti->IsHidden())
|
|
return (HTREEITEM) xti;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetPrevHiddenItem(HTREEITEM hItem)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
xti=xti->GetPrevInTree();
|
|
// now iterate the tree and stop when a hidden item found
|
|
for(; xti ; xti=xti->GetPrevInTree())
|
|
{
|
|
if(xti->IsHidden())
|
|
return (HTREEITEM) xti;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetSelectedItem()
|
|
{
|
|
return GetNextItem(TVI_ROOT,TVGN_FIRSTSELECTED);
|
|
}
|
|
|
|
CImageList* COXTreeCtrl::GetImageList(UINT nImage)
|
|
{
|
|
UINT nListImg;
|
|
switch(nImage)
|
|
{
|
|
case TVSIL_NORMAL:
|
|
nListImg=LVSIL_SMALL;
|
|
break;
|
|
case TVSIL_STATE:
|
|
nListImg=LVSIL_STATE;
|
|
default:
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
return CListCtrl::GetImageList(nListImg);
|
|
}
|
|
|
|
UINT COXTreeCtrl::GetIndent() const
|
|
{
|
|
return m_nIndent;
|
|
}
|
|
|
|
void COXTreeCtrl::SetIndent(UINT nIndent)
|
|
{
|
|
nIndent=nIndent>TV_MININDENT ? nIndent : TV_MININDENT;
|
|
m_nIndent=nIndent;
|
|
RedrawWindow();
|
|
}
|
|
|
|
BOOL COXTreeCtrl::ItemHasChildren(HTREEITEM hItem) const
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
return xti->ItemHasChildren();
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetChildItem(HTREEITEM hItem)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM) (xti->pxFirstChild);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetNextSiblingItem(HTREEITEM hItem)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM) (xti->pxNext);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetPrevSiblingItem(HTREEITEM hItem)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM) (xti->pxPrev);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetParentItem(HTREEITEM hItem)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
return (HTREEITEM) (xti->pxParent);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetDropHilightItem()
|
|
{
|
|
int idx=CListCtrl::GetNextItem(-1,LVNI_DROPHILITED);
|
|
if(idx == -1 || idx >= CListCtrl::GetItemCount())
|
|
return NULL;
|
|
return (HTREEITEM) CListCtrl::GetItemData(idx);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetRootItem() const
|
|
{
|
|
return (HTREEITEM)(&m_xtiRoot);
|
|
}
|
|
|
|
UINT COXTreeCtrl::GetItemState(HTREEITEM hItem, UINT nStateMask) const
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_HANDLE | TVIF_STATE;
|
|
tvi.hItem=hItem;
|
|
tvi.stateMask=nStateMask;
|
|
VERIFY(GetItem(&tvi));
|
|
return tvi.state;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask)
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_HANDLE | TVIF_STATE;
|
|
tvi.hItem=hItem;
|
|
tvi.stateMask=nStateMask;
|
|
tvi.state=nState;
|
|
return SetItem(&tvi);
|
|
}
|
|
|
|
DWORD COXTreeCtrl::GetItemData(HTREEITEM hItem) const
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_HANDLE | TVIF_PARAM;
|
|
tvi.hItem=hItem;
|
|
VERIFY(GetItem(&tvi));
|
|
return (DWORD)tvi.lParam;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemData(HTREEITEM hItem, DWORD dwData)
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_HANDLE | TVIF_PARAM;
|
|
tvi.hItem=hItem;
|
|
tvi.lParam=dwData;
|
|
return SetItem(&tvi);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(idx == -1 || idx >= CListCtrl::GetItemCount())
|
|
return FALSE;
|
|
CRect r;
|
|
if(bTextOnly)
|
|
{
|
|
int nIndent=-1;
|
|
GetItemPartRect(rText,xti,&r,&nIndent);
|
|
::SetRect(lpRect,r.left,r.top,r.right,r.bottom);
|
|
return TRUE;
|
|
}
|
|
return CListCtrl::GetItemRect(idx,lpRect,LVIR_BOUNDS);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemColor(HTREEITEM hItem,COLORREF clr,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(!nCol)
|
|
{
|
|
xti->SetColor(clr);
|
|
}
|
|
else
|
|
{
|
|
COXTreeSubItem *pSubItem=xti->GetSubItem(nCol);
|
|
if(!pSubItem)
|
|
return FALSE;
|
|
pSubItem->SetColor(clr);
|
|
}
|
|
if(idx != -1)
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemBackColor(HTREEITEM hItem,COLORREF clr,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(!nCol)
|
|
{
|
|
xti->SetBackColor(clr);
|
|
}
|
|
else
|
|
{
|
|
COXTreeSubItem *pSubItem=xti->GetSubItem(nCol);
|
|
if(!pSubItem)
|
|
return FALSE;
|
|
pSubItem->SetBackColor(clr);
|
|
}
|
|
if(idx != -1)
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
return TRUE;
|
|
}
|
|
|
|
COLORREF COXTreeCtrl::GetItemColor(HTREEITEM hItem,int nCol) const
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return 0;
|
|
if(xti->HasColor(nCol))
|
|
return xti->GetItemColor(nCol);
|
|
return ::GetSysColor(COLOR_BTNTEXT);
|
|
}
|
|
|
|
CFont* COXTreeCtrl::GetItemFont(HTREEITEM hItem,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return NULL;
|
|
return xti->GetItemFont(nCol);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemFont(HTREEITEM hItem,CFont *pFont,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
BOOL bRes=xti->SetFont(nCol,pFont);
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(bRes && idx != -1 && idx < CListCtrl::GetItemCount())
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
return bRes;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LV_DISPINFO* pDispInfo= (LV_DISPINFO*) pNMHDR;
|
|
*pResult = 0;
|
|
|
|
// We need to fire TVN_BEGINLABELEDIT Notification
|
|
NMTVDISPINFO tvdi;
|
|
::memset(&tvdi, 0, sizeof(NMTVDISPINFO));
|
|
tvdi.hdr.hwndFrom = pNMHDR->hwndFrom;
|
|
tvdi.hdr.idFrom = pNMHDR->idFrom;
|
|
tvdi.hdr.code = pNMHDR->code;
|
|
tvdi.item.mask = TVIF_HANDLE | TVIF_PARAM;
|
|
tvdi.item.hItem = (HTREEITEM)(INT_PTR) pDispInfo->item.iItem;
|
|
tvdi.item.lParam = pDispInfo->item.lParam;
|
|
*pResult = GetParent()->SendMessage(TVN_BEGINLABELEDIT, pNMHDR->idFrom, (LPARAM) &tvdi);
|
|
|
|
int nItem=pDispInfo->item.iItem;
|
|
HWND hWndEdit=(HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L);
|
|
|
|
if(m_pActiveEditWnd!=NULL && m_pActiveEditWnd->GetSafeHwnd())
|
|
return FALSE;
|
|
|
|
ASSERT(nItem != -1);
|
|
COXTreeItem *xti=(COXTreeItem *) CListCtrl::GetItemData(nItem);
|
|
ASSERT(xti);
|
|
if(xti->IsDisabled())
|
|
{
|
|
if(pResult != NULL)
|
|
*pResult = TRUE;
|
|
return TRUE;
|
|
}
|
|
CRect rcEdit;
|
|
int nCol=GetEditColumn(xti,&rcEdit);
|
|
if(nCol == -1)
|
|
{
|
|
// No editable column found
|
|
if(pResult != NULL)
|
|
*pResult = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if(xti->GetEditMode(nCol)==OXET_NOEDIT)
|
|
{
|
|
// No editable column found
|
|
if(pResult != NULL)
|
|
*pResult = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
m_nEditColumn=nCol;
|
|
m_pActiveEditWnd=StartEditSubItem(hWndEdit,xti,rcEdit,nCol,pResult);
|
|
|
|
if (GetParent() != NULL && GetParent()->SendMessage(WM_USER_QUERY_PROPERTIESWND))
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
int COXTreeCtrl::GetEditColumn(COXTreeItem *xti,CRect * rcColText)
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns : specified item's column to edit
|
|
//--- Effect :
|
|
{
|
|
// fill rcItem with entry item rect
|
|
CRect rcItem;
|
|
int nIndex=GetItemIndexInternal(xti);
|
|
if(nIndex == -1)
|
|
return -1;
|
|
CListCtrl::GetItemRect(nIndex,&rcItem,LVIR_BOUNDS);
|
|
|
|
CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
|
|
CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
|
|
|
|
// Now find the column
|
|
int nColumnsCount=GetColumnsCount();
|
|
int nCol=-1;
|
|
for(int colnum=0; colnum < nColumnsCount; colnum++)
|
|
{
|
|
int nColWidth=GetColumnWidth(colnum);
|
|
if(m_ptLastClick.x >= rcItem.left &&
|
|
m_ptLastClick.x <= (rcItem.left + nColWidth))
|
|
{
|
|
nCol=colnum;
|
|
break;
|
|
}
|
|
rcItem.left += nColWidth;
|
|
}
|
|
if(nCol == -1)
|
|
return -1;// no column found
|
|
if(nCol && !xti->GetSubItem(nCol))
|
|
return -1; // this item has no subitems at given column
|
|
|
|
rcItem.right=rcItem.left + GetColumnWidth(nCol);
|
|
|
|
int nIndent=nCol == 0 ? GetItemIndent(xti) : 0;
|
|
|
|
// CSize szText=GetColTextExtent(nIndex,nCol);
|
|
CSize szText=CSize(rcItem.Width(),rcItem.Height());
|
|
CRect rcText;
|
|
|
|
LV_COLUMN lvc;
|
|
memset(&lvc, 0, sizeof(LV_COLUMN));
|
|
lvc.mask=LVCF_FMT;
|
|
VERIFY(GetColumn(nCol, &lvc));
|
|
|
|
int nImgWidth=0;
|
|
IMAGEINFO imgInfo;
|
|
int nImg=xti->GetItemImage(nCol);
|
|
|
|
if(pImgList && nImg != -1)
|
|
{
|
|
pImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImg(imgInfo.rcImage);
|
|
nImgWidth += rcImg.Width();
|
|
}
|
|
|
|
if(pStateImgList && nCol == 0 && GetItemStateIndex(nIndex) != -1)
|
|
{
|
|
pStateImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImg(imgInfo.rcImage);
|
|
nImgWidth += rcImg.Width();
|
|
}
|
|
|
|
rcText.top=rcItem.top;
|
|
rcText.bottom=rcItem.bottom;
|
|
szText.cx=__min(szText.cx,GetColumnWidth(nCol)-nImgWidth-nIndent);
|
|
int fmt=lvc.fmt & LVCFMT_JUSTIFYMASK;
|
|
switch(fmt)
|
|
{
|
|
case LVCFMT_LEFT:
|
|
{
|
|
rcText.left=rcItem.left + nIndent + nImgWidth;
|
|
rcText.right=rcText.left + szText.cx;
|
|
}
|
|
break;
|
|
case LVCFMT_RIGHT:
|
|
{
|
|
rcText.right=rcItem.left + GetColumnWidth(nCol);
|
|
rcText.left=rcText.right - szText.cx;
|
|
}
|
|
break;
|
|
case LVCFMT_CENTER:
|
|
{
|
|
rcItem.left += nIndent + nImgWidth;
|
|
int nCenter=rcItem.left + (rcItem.right - rcItem.left)/2;
|
|
rcText.left=nCenter - szText.cx/2;
|
|
rcText.right=nCenter + szText.cx/2;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
(*rcColText)=rcText;
|
|
if(rcText.Width() < 6)
|
|
rcText.InflateRect(4,4);
|
|
if(!rcText.PtInRect(m_ptLastClick))
|
|
return -1;
|
|
return nCol;
|
|
}
|
|
|
|
|
|
CEdit* COXTreeCtrl::EditLabel(HTREEITEM hti, int nCol/*=0*/)
|
|
{
|
|
if(!(GetStyle()&TVS_EDITLABELS))
|
|
return NULL;
|
|
|
|
COXTreeItem* xti=GetXItem(hti);
|
|
if(!xti)
|
|
return NULL;
|
|
|
|
int nIndex=GetItemIndex(hti);
|
|
if(nIndex<0)
|
|
return NULL;
|
|
|
|
CRect rcItem;
|
|
if(!GetItemRect(hti,&rcItem,TRUE))
|
|
return NULL;
|
|
int nColumnsCount=GetColumnsCount();
|
|
if(nCol>=nColumnsCount)
|
|
return NULL;
|
|
|
|
if(nCol>0)
|
|
rcItem.left=0;
|
|
for(int colnum=0; colnum < nCol; colnum++)
|
|
rcItem.left += GetColumnWidth(colnum);
|
|
if(nCol>0)
|
|
rcItem.right=rcItem.left + GetColumnWidth(nCol);
|
|
|
|
m_ptLastClick=rcItem.CenterPoint()-CPoint(GetScrollPos(SB_HORZ),0);
|
|
|
|
if(GetFocus() != this)
|
|
SetFocus();
|
|
|
|
return (CEdit*)CWnd::FromHandle((HWND)SendMessage(LVM_EDITLABEL,nIndex));
|
|
}
|
|
|
|
CWnd* COXTreeCtrl::StartEditSubItem(HWND hWndEdit,COXTreeItem *xti,CRect& rcEdit,
|
|
int nCol,LRESULT* pResult)
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
//--- Effect :
|
|
{
|
|
CRect rcClient;
|
|
GetClientRect(&rcClient);
|
|
int nEditType=xti->GetEditMode(nCol);
|
|
switch(nEditType)
|
|
{
|
|
case OXET_COMBO:
|
|
{
|
|
int nLeft=-GetScrollPos(SB_HORZ);
|
|
for(int i=0;i < nCol;i++)
|
|
nLeft += GetColumnWidth(i);
|
|
CRect rcCombo=rcEdit;
|
|
rcCombo.left=nLeft;
|
|
CImageList *pImgList=GetImageList(TVSIL_NORMAL);
|
|
rcCombo.right=rcCombo.left + GetColumnWidth(nCol);
|
|
if(xti->GetItemImage(nCol) != -1 &&pImgList)
|
|
{
|
|
IMAGEINFO ii;
|
|
pImgList->GetImageInfo(0,&ii);
|
|
rcCombo.left += CRect(ii.rcImage).Width();
|
|
}
|
|
if(rcCombo.right > rcClient.right)
|
|
{
|
|
// perform scrolling
|
|
CSize szScroll;
|
|
szScroll.cx=rcCombo.right - rcClient.right;
|
|
szScroll.cy=0;
|
|
Scroll(szScroll);
|
|
rcCombo.right -= szScroll.cx;
|
|
rcCombo.left -= szScroll.cx;
|
|
}
|
|
rcCombo.bottom += rcEdit.Height()*5;
|
|
(*pResult)=1;
|
|
m_wndCombo.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST|WS_VSCROLL|WS_HSCROLL,
|
|
rcCombo,this,100);
|
|
m_wndCombo.SetFont(GetFont());
|
|
|
|
m_wndCombo.Init((HTREEITEM) xti,GetItemIndexInternal(xti),nCol);
|
|
|
|
m_wndCombo.SetFocus();
|
|
}
|
|
return &m_wndCombo;
|
|
case OXET_EDIT:
|
|
{
|
|
m_wndEdit.Init();
|
|
LV_COLUMN lvc;
|
|
lvc.mask=LVCF_FMT;
|
|
VERIFY(CListCtrl::GetColumn(nCol,&lvc));
|
|
DWORD dwAlign=ES_LEFT;
|
|
CPoint pos;
|
|
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
|
|
{
|
|
case LVCFMT_LEFT:
|
|
pos=rcEdit.TopLeft();
|
|
dwAlign=ES_LEFT;
|
|
break;
|
|
case LVCFMT_RIGHT:
|
|
pos.x=rcEdit.right;
|
|
pos.y=rcEdit.top;
|
|
dwAlign=ES_RIGHT;
|
|
break;
|
|
case LVCFMT_CENTER:
|
|
pos.x=rcEdit.left + rcEdit.Width()/2;
|
|
pos.y=rcEdit.top;
|
|
dwAlign=ES_CENTER;
|
|
break;
|
|
}
|
|
// scroll control if column been edited is not visible
|
|
if(pos.x < 0 || pos.x > rcClient.right)
|
|
{
|
|
// perform scrolling
|
|
CSize szScroll;
|
|
szScroll.cx=pos.x - rcClient.right;
|
|
szScroll.cy=0;
|
|
Scroll(szScroll);
|
|
pos.x -= szScroll.cx;
|
|
}
|
|
m_wndEdit.SubclassWindow(hWndEdit);
|
|
m_wndEdit.KeepPos(pos,dwAlign);
|
|
|
|
if ( m_dwExStyle & TVOXS_KEEPCOLUMNSIZE )
|
|
m_wndEdit.KeepColumnSize(CSize(rcEdit.right,rcEdit.bottom));
|
|
else
|
|
m_wndEdit.KeepBounds(CSize(rcClient.Width(),rcClient.Height()));
|
|
|
|
m_wndEdit.SetWindowText(GetItemText((HTREEITEM)xti,nCol));
|
|
return &m_wndEdit;
|
|
}
|
|
case OXET_CALENDAR:
|
|
{
|
|
int nLeft=-GetScrollPos(SB_HORZ);
|
|
for(int i=0;i < nCol;i++)
|
|
nLeft += GetColumnWidth(i);
|
|
CRect rcCal=rcEdit;
|
|
rcCal.left=nLeft;
|
|
CImageList *pImgList=GetImageList(TVSIL_NORMAL);
|
|
rcCal.right=rcCal.left + GetColumnWidth(nCol);
|
|
if(xti->GetItemImage(nCol) != -1 &&pImgList)
|
|
{
|
|
IMAGEINFO ii;
|
|
pImgList->GetImageInfo(0,&ii);
|
|
rcCal.left += CRect(ii.rcImage).Width();
|
|
}
|
|
if(rcCal.right > rcClient.right)
|
|
{
|
|
// perform scrolling
|
|
CSize szScroll;
|
|
szScroll.cx=rcCal.right - rcClient.right;
|
|
szScroll.cy=0;
|
|
Scroll(szScroll);
|
|
rcCal.right -= szScroll.cx;
|
|
rcCal.left -= szScroll.cx;
|
|
}
|
|
(*pResult)=1;
|
|
m_wndCal.Create(WS_CHILD | WS_VISIBLE |WS_BORDER,rcCal,this,7);
|
|
m_wndCal.Init((HTREEITEM)xti,GetItemIndexInternal(xti),nCol);
|
|
m_wndCal.SetFocus();
|
|
return &m_wndCal;
|
|
}
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::IsItemHidden(HTREEITEM hItem) const
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
return xti->IsHidden();
|
|
}
|
|
|
|
BOOL COXTreeCtrl::DisableItem(HTREEITEM hItem,BOOL bDisable)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(xti->IsDisabled() == bDisable)
|
|
return TRUE; // already disabled or undisabled
|
|
xti->SetDisabled(bDisable);
|
|
int idx=GetItemIndexInternal(xti);
|
|
if(idx == -1)
|
|
return TRUE;
|
|
CListCtrl::RedrawItems(idx,idx);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::IsItemDisabled(HTREEITEM hItem) const
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
return xti->IsDisabled();
|
|
}
|
|
|
|
BOOL COXTreeCtrl::IsItemDescendant(HTREEITEM hParentItem, HTREEITEM hItem)
|
|
{
|
|
ASSERT(hParentItem!=NULL);
|
|
ASSERT(hItem!=NULL);
|
|
if(hParentItem==NULL || hItem==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HTREEITEM hDirectParent=GetParentItem(hItem);
|
|
if(hDirectParent==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return (hParentItem==hDirectParent ||
|
|
IsItemDescendant(hParentItem,hDirectParent));
|
|
}
|
|
}
|
|
|
|
|
|
void COXTreeCtrl::SendDeleteItemNotify(TV_ITEM* ptvi)
|
|
{
|
|
NM_TREEVIEW nmt;
|
|
memset(&nmt,0,sizeof(nmt));
|
|
|
|
nmt.itemOld=*ptvi;
|
|
nmt.hdr.code=TVN_DELETEITEM;
|
|
nmt.hdr.idFrom=GetDlgCtrlID();
|
|
nmt.hdr.hwndFrom=GetSafeHwnd();
|
|
GetParent()->SendMessage(WM_NOTIFY,nmt.hdr.idFrom , (LPARAM)&nmt);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SendItemExpandingNotify(HTREEITEM hItem,UINT nCode)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
ASSERT(xti);
|
|
NM_TREEVIEW nmt;
|
|
|
|
memset(&nmt, 0, sizeof(nmt));
|
|
|
|
nmt.hdr.idFrom=GetDlgCtrlID();
|
|
nmt.hdr.hwndFrom=GetSafeHwnd();
|
|
nmt.hdr.code=TVN_ITEMEXPANDING;
|
|
nmt.action=nCode;
|
|
|
|
nmt.itemNew=xti->m_tvi;
|
|
nmt.itemNew.mask |= TVIF_HANDLE;
|
|
nmt.itemNew.hItem=(HTREEITEM) xti;
|
|
|
|
return (BOOL)(GetParent()->SendMessage(WM_NOTIFY,nmt.hdr.idFrom,(LPARAM)(&nmt)));
|
|
}
|
|
|
|
void COXTreeCtrl::SendItemExpandedNotify(HTREEITEM hItem,UINT nCode)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
ASSERT(xti);
|
|
|
|
NM_TREEVIEW nmt;
|
|
memset(&nmt, 0, sizeof(nmt));
|
|
|
|
nmt.hdr.idFrom=GetDlgCtrlID();
|
|
nmt.hdr.hwndFrom=GetSafeHwnd();
|
|
nmt.hdr.code=TVN_ITEMEXPANDED;
|
|
nmt.action=nCode;
|
|
|
|
nmt.itemNew=xti->m_tvi;
|
|
nmt.itemNew.mask |= TVIF_HANDLE;
|
|
nmt.itemNew.hItem=(HTREEITEM) xti;
|
|
GetParent()->SendMessage(WM_NOTIFY,nmt.hdr.idFrom,(LPARAM)(&nmt));
|
|
}
|
|
|
|
BOOL COXTreeCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LV_DISPINFO* pDispInfo=(LV_DISPINFO*)pNMHDR;
|
|
if ((pDispInfo->item.pszText != NULL) && (pDispInfo->item.iItem != -1))
|
|
{
|
|
HTREEITEM hItem=(HTREEITEM) CListCtrl::GetItemData(pDispInfo->item.iItem);
|
|
VERIFY(SetItemText(hItem,pDispInfo->item.pszText,m_nEditColumn));
|
|
return FALSE;
|
|
}
|
|
|
|
*pResult=0;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SetItemText(HTREEITEM hItem, LPCTSTR lpszItem ,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
if(!xti)
|
|
return FALSE;
|
|
if(nCol == 0)
|
|
{
|
|
TV_ITEM tvi;
|
|
memset(&tvi,0,sizeof(tvi));
|
|
tvi.mask=TVIF_HANDLE | TVIF_TEXT;
|
|
tvi.hItem=hItem;
|
|
tvi.pszText=(LPTSTR)lpszItem;
|
|
return SetItem(&tvi);
|
|
}
|
|
return xti->SetSubItemText(lpszItem,nCol);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::GetPickAnywhere() const
|
|
{
|
|
return (m_dwExStyle & TVOXS_PICKANYWHERE);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::GetDrawGridFullLength() const
|
|
{
|
|
return (m_dwExStyle & TVOXS_FLGRID);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::HasGrid(UINT nGridType) const
|
|
{
|
|
return (m_dwExStyle & nGridType);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::ResizeColToFit(int nCol)
|
|
{
|
|
if(nCol >= GetColumnsCount())
|
|
return FALSE;
|
|
int nWidth=GetFullColumnWidth(nCol);
|
|
|
|
return SetColumnWidth(nCol,nWidth);
|
|
}
|
|
|
|
|
|
int COXTreeCtrl::GetFullColumnWidth(int nCol)
|
|
{
|
|
if(GetItemCount()==0)
|
|
return 6;
|
|
|
|
int nImgWidth=0,nStateImgWidth=0;
|
|
CImageList* pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
|
|
CImageList* pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
|
|
|
|
// calc image width
|
|
if(pImgList && pImgList->GetImageCount() > 0)
|
|
{
|
|
IMAGEINFO imi;
|
|
VERIFY(pImgList->GetImageInfo(0,&imi));
|
|
nImgWidth=imi.rcImage.right - imi.rcImage.left;
|
|
}
|
|
|
|
// calc state image width
|
|
if(pStateImgList && pStateImgList->GetImageCount() > 0)
|
|
{
|
|
IMAGEINFO imi;
|
|
VERIFY(pStateImgList->GetImageInfo(0,&imi));
|
|
nStateImgWidth=imi.rcImage.right - imi.rcImage.left;
|
|
}
|
|
|
|
int nIndex=CListCtrl::GetNextItem(-1,LVNI_ALL);
|
|
|
|
int nMaxWidth=0;
|
|
CDC *pDC=GetDC();
|
|
// look throuth currently visible items and find max width
|
|
while(nIndex != -1)
|
|
{
|
|
int nWidth=0;
|
|
COXTreeItem *xti=GetXItem((HTREEITEM) CListCtrl::GetItemData(nIndex));
|
|
|
|
if(nCol == 0)
|
|
{
|
|
// add item indent
|
|
nWidth += GetItemIndent(xti);
|
|
// add item's state image width, if any
|
|
if(pStateImgList)
|
|
{
|
|
int idx=STATEIMAGEMASKTOINDEX(xti->m_tvi.state)-1;
|
|
if(idx != -1)
|
|
nWidth += nStateImgWidth;
|
|
}
|
|
// add main image width
|
|
nWidth += nImgWidth;
|
|
}
|
|
else
|
|
{
|
|
if(xti->GetSubItemImage(nCol) != -1)
|
|
nWidth += nImgWidth;
|
|
}
|
|
// finally calc and add item's text width
|
|
CFont *pFont=xti->HasFont(nCol) ? xti->GetItemFont(nCol) : GetFont();
|
|
CFont *pOldFont=pDC->SelectObject(pFont);
|
|
CSize szText=pDC->GetTextExtent(GetItemText((HTREEITEM) xti,nCol));
|
|
pDC->SelectObject(pOldFont);
|
|
nWidth += szText.cx + 6;
|
|
if(nWidth > nMaxWidth)
|
|
nMaxWidth=nWidth;
|
|
// retreive next item
|
|
nIndex=CListCtrl::GetNextItem(nIndex,LVNI_ALL);
|
|
}
|
|
ReleaseDC(pDC);
|
|
return nMaxWidth;
|
|
}
|
|
|
|
void COXTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
if(GetFocus() != this)
|
|
SetFocus();
|
|
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
|
|
}
|
|
|
|
void COXTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
//--- Effect :
|
|
{
|
|
if(GetFocus() != this)
|
|
SetFocus();
|
|
|
|
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
|
|
}
|
|
|
|
void COXTreeCtrl::SetEditMode(HTREEITEM hItem,UINT uMode,CStringArray& saTextEx,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
ASSERT(xti);
|
|
xti->SetEditMode(uMode,saTextEx,nCol);
|
|
}
|
|
|
|
void COXTreeCtrl::SetPlainEditMode(HTREEITEM hItem,int nCol)
|
|
{
|
|
CStringArray sArray;
|
|
SetEditMode(hItem,OXET_EDIT,sArray,nCol);
|
|
}
|
|
|
|
void COXTreeCtrl::SetNoEditMode(HTREEITEM hItem,int nCol)
|
|
{
|
|
CStringArray sArray;
|
|
SetEditMode(hItem,OXET_NOEDIT,sArray,nCol);
|
|
}
|
|
|
|
void COXTreeCtrl::SetItemTextEx(HTREEITEM hItem,CStringArray& saTextEx,int nCol)
|
|
{
|
|
COXTreeItem* xti=GetXItem(hItem);
|
|
ASSERT(xti);
|
|
if(xti)
|
|
xti->SetTextEx(saTextEx,nCol);
|
|
}
|
|
|
|
CStringArray& COXTreeCtrl::GetItemTextEx(HTREEITEM hItem,int nCol)
|
|
{
|
|
COXTreeItem *xti=GetXItem(hItem);
|
|
ASSERT(xti);
|
|
return xti->GetTextEx(nCol);
|
|
}
|
|
|
|
void COXTreeCtrl::PostNcDestroy()
|
|
{
|
|
m_bInit=FALSE;
|
|
CListCtrl::PostNcDestroy();
|
|
}
|
|
|
|
void COXTreeCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
|
|
{
|
|
if(m_nItemHeight)
|
|
{
|
|
lpMeasureItemStruct->itemHeight=max(m_nItemHeight,
|
|
lpMeasureItemStruct->itemHeight);
|
|
}
|
|
else
|
|
{
|
|
m_nItemHeight=lpMeasureItemStruct->itemHeight;
|
|
}
|
|
}
|
|
|
|
UINT COXTreeCtrl::GetItemHeight() const
|
|
{
|
|
return m_nItemHeight;
|
|
}
|
|
|
|
void COXTreeCtrl::SetItemHeight(UINT nHeight)
|
|
{
|
|
m_nItemHeight=nHeight;
|
|
////
|
|
CRect rect;
|
|
GetWindowRect(rect);
|
|
WINDOWPOS wp;
|
|
wp.hwnd=m_hWnd;
|
|
wp.cx=rect.Width();
|
|
wp.cy=rect.Height();
|
|
wp.flags=SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
|
|
SendMessage(WM_WINDOWPOSCHANGED,0,(LPARAM)&wp);
|
|
////
|
|
}
|
|
|
|
|
|
BOOL COXTreeCtrl::EnsureVisible(HTREEITEM hti)
|
|
{
|
|
COXTreeItem* xti=GetXItem(hti);
|
|
if(!xti || xti==&m_xtiRoot)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if(!xti->IsVisible())
|
|
{
|
|
if(xti->IsHidden())
|
|
{
|
|
xti->SetHidden(FALSE);
|
|
}
|
|
|
|
CPtrArray arrItemsToExpand;
|
|
HTREEITEM htiParent=GetParentItem(hti);
|
|
COXTreeItem* xtiParent;
|
|
BOOL bFlag=FALSE;
|
|
while(!bFlag && htiParent!=NULL)
|
|
{
|
|
xtiParent=GetXItem(htiParent);
|
|
ASSERT(xtiParent);
|
|
if(xtiParent==&m_xtiRoot ||
|
|
(xtiParent->IsVisible() && xtiParent->IsExpanded()))
|
|
{
|
|
bFlag=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if(xtiParent->IsHidden())
|
|
{
|
|
xtiParent->SetHidden(FALSE);
|
|
}
|
|
if(!xtiParent->IsExpanded())
|
|
{
|
|
arrItemsToExpand.Add(htiParent);
|
|
}
|
|
htiParent=GetParentItem(htiParent);
|
|
}
|
|
}
|
|
if(arrItemsToExpand.GetSize()>0)
|
|
{
|
|
for(int nIndex=(int)arrItemsToExpand.GetSize()-1; nIndex>=0; nIndex--)
|
|
Expand((HTREEITEM)arrItemsToExpand[nIndex],TVE_EXPAND);
|
|
}
|
|
}
|
|
|
|
int nIndex=GetItemIndex(hti);
|
|
if(nIndex<0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
return CListCtrl::EnsureVisible(nIndex,FALSE);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::EnsureFirstVisible(HTREEITEM hti)
|
|
{
|
|
if(!EnsureVisible(hti))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HTREEITEM hItemFirstVisible=GetFirstVisibleItem();
|
|
if(hItemFirstVisible==hti)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
int nIndex=GetItemIndex(hti);
|
|
int nIndexFirstVisible=GetItemIndex(hItemFirstVisible);
|
|
ASSERT(nIndex!=nIndexFirstVisible);
|
|
|
|
CRect rect;
|
|
GetItemRect(hti,rect,FALSE);
|
|
CSize sizeScroll(0,(nIndex-nIndexFirstVisible)*rect.Height());
|
|
CListCtrl::Scroll(sizeScroll);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::Select(HTREEITEM hti, UINT nCode)
|
|
{
|
|
if(nCode==TVGN_FIRSTVISIBLE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if(hti==NULL)
|
|
{
|
|
switch(nCode)
|
|
{
|
|
case TVGN_CARET:
|
|
{
|
|
HTREEITEM hItem=GetNextItem(TVI_ROOT,TVGN_FIRSTSELECTED);
|
|
while(hItem)
|
|
{
|
|
SetItemState(hItem,0,TVIS_SELECTED);
|
|
hItem=GetNextItem(hItem,TVGN_NEXTSELECTED);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case TVGN_DROPHILITE:
|
|
{
|
|
if(m_hOldDropTarget!=NULL)
|
|
{
|
|
SetItemState(m_hOldDropTarget,0,TVIS_DROPHILITED);
|
|
UpdateWindow();
|
|
m_hOldDropTarget = NULL;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
COXTreeItem* xti=GetXItem(hti);
|
|
if(xti==&m_xtiRoot && nCode==TVGN_DROPHILITE)
|
|
{
|
|
if(m_hOldDropTarget!=NULL)
|
|
{
|
|
SetItemState(m_hOldDropTarget,0,TVIS_DROPHILITED);
|
|
UpdateWindow();
|
|
m_hOldDropTarget = NULL;
|
|
}
|
|
}
|
|
if(!xti || xti==&m_xtiRoot)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
int nIndex=GetItemIndexInternal(xti);
|
|
|
|
BOOL bResult=FALSE;
|
|
switch(nCode)
|
|
{
|
|
case TVGN_CARET:
|
|
{
|
|
bResult=SetItemState(hti,TVIS_SELECTED,TVIS_SELECTED) &
|
|
CListCtrl::SetItemState(nIndex,LVIS_FOCUSED,LVIS_FOCUSED);
|
|
break;
|
|
}
|
|
case TVGN_DROPHILITE:
|
|
{
|
|
bResult=SetItemState(hti,TVIS_DROPHILITED,TVIS_DROPHILITED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SelectItem(HTREEITEM hti)
|
|
{
|
|
return Select(hti,TVGN_CARET);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SelectDropTarget(HTREEITEM hti)
|
|
{
|
|
return Select(hti,TVGN_DROPHILITE);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SelectSetFirstVisible(HTREEITEM hti)
|
|
{
|
|
return Select(hti,TVGN_FIRSTVISIBLE);
|
|
}
|
|
|
|
CImageList* COXTreeCtrl::CreateDragImage(HTREEITEM hti, BOOL bCreateMultipleImage)
|
|
{
|
|
int nIndex=GetItemIndex(hti);
|
|
if(nIndex<0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
m_bCreatingDragImage=TRUE;
|
|
|
|
CImageList* m_pDragImageList=new CImageList;
|
|
|
|
UINT nCount=GetSelectedCount();
|
|
nCount=(nCount>0 && bCreateMultipleImage) ? nCount : 1;
|
|
|
|
CRect rectItem;
|
|
GetItemRect(hti,&rectItem,FALSE);
|
|
UINT nItemHeight=rectItem.Height();
|
|
rectItem.bottom=nItemHeight*nCount;
|
|
int cyScreen=GetSystemMetrics(SM_CYSCREEN);
|
|
rectItem.bottom=rectItem.bottom>cyScreen ? cyScreen : rectItem.bottom;
|
|
rectItem.top=rectItem.left=0;
|
|
rectItem.right=GetColumnWidth(0);
|
|
m_pDragImageList->Create(rectItem.Width(),rectItem.Height(),TRUE,0,1);
|
|
|
|
CClientDC dcClient(this);
|
|
CDC dc;
|
|
dc.CreateCompatibleDC(&dcClient);
|
|
CBitmap bitmap;
|
|
bitmap.CreateCompatibleBitmap(&dcClient,rectItem.Width(),rectItem.Height());
|
|
CBitmap* pOldBitmap=dc.SelectObject(&bitmap);
|
|
CFont* pOldFont=dc.SelectObject(GetFont());
|
|
|
|
HTREEITEM hSelectedItem=NULL;
|
|
if(nCount>1)
|
|
{
|
|
hSelectedItem=GetNextItem(TVI_ROOT,TVGN_FIRSTSELECTED);
|
|
ASSERT(hSelectedItem);
|
|
nIndex=GetItemIndex(hSelectedItem);
|
|
rectItem.bottom=rectItem.top+nItemHeight;
|
|
}
|
|
|
|
while(TRUE)
|
|
{
|
|
DRAWITEMSTRUCT dis;
|
|
dis.CtlType=ODT_LISTVIEW;
|
|
dis.CtlID=0;
|
|
dis.itemID=nIndex;
|
|
dis.itemAction=ODA_DRAWENTIRE;
|
|
dis.itemState=ODS_DEFAULT;
|
|
dis.hwndItem=NULL;
|
|
dis.hDC=dc;
|
|
dis.rcItem=rectItem;
|
|
dis.itemData=GetXItem(hti)->m_tvi.lParam;
|
|
DrawItem(&dis);
|
|
|
|
if(nCount==1)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hSelectedItem=GetNextItem(hSelectedItem,TVGN_NEXTSELECTED);
|
|
if(hSelectedItem)
|
|
{
|
|
nIndex=GetItemIndex(hSelectedItem);
|
|
rectItem.top+=nItemHeight;
|
|
rectItem.bottom+=nItemHeight;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pOldBitmap)
|
|
{
|
|
dc.SelectObject(pOldBitmap);
|
|
}
|
|
if(pOldFont)
|
|
{
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
m_pDragImageList->Add(&bitmap,(!IsWindowEnabled() ?
|
|
::GetSysColor(COLOR_BTNFACE) : GetTextBkColor()));
|
|
|
|
m_bCreatingDragImage=FALSE;
|
|
return m_pDragImageList;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SortChildren(HTREEITEM hti, int nCol/*=0*/,
|
|
BOOL bAscending/*=TRUE*/,
|
|
PFNTVCOMPARE lpfnCompare/*=NULL*/,
|
|
LPARAM lParam/*=NULL*/)
|
|
{
|
|
COXTreeHeader* pHeader=(COXTreeHeader*)GetDlgItem(0);
|
|
ASSERT(pHeader);
|
|
pHeader->SortColumn(nCol,bAscending ? 1 : -1);
|
|
|
|
CWaitCursor waitCursor;
|
|
SetRedraw(FALSE);
|
|
|
|
hti=hti==NULL ? GetRootItem() : hti;
|
|
COXTreeItem* xti=GetXItem(hti);
|
|
ASSERT(xti);
|
|
BOOL bOldExpand=xti->IsExpanded();
|
|
if(bOldExpand)
|
|
{
|
|
xti->SetExpand(FALSE);
|
|
COXTreeItem *xtiTemp=xti->pxFirstChild;
|
|
while(xtiTemp)
|
|
{
|
|
if(!xtiTemp->IsHidden())
|
|
{
|
|
int nIndex=GetItemIndexInternal(xtiTemp);
|
|
ASSERT(nIndex!=-1);
|
|
xtiTemp->RemoveChildrenFromCtrl(this);
|
|
CListCtrl::DeleteItem(nIndex);
|
|
}
|
|
xtiTemp=xtiTemp->pxNext;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (lpfnCompare != NULL)
|
|
xti->SortChildren(nCol,(hti==GetRootItem() ? FALSE : TRUE),
|
|
bAscending,lpfnCompare,lParam);
|
|
else
|
|
{
|
|
// Find out if a compare function for that column
|
|
// has been specified.
|
|
PFNTVCOMPARE lpfnColumnCompare = NULL;
|
|
m_mapCompareFunctions.Lookup(nCol, lpfnColumnCompare);
|
|
|
|
if (lpfnColumnCompare != NULL)
|
|
xti->SortChildren(nCol,(hti==GetRootItem() ? FALSE : TRUE),
|
|
bAscending,lpfnColumnCompare,lParam);
|
|
else // default compare function
|
|
xti->SortChildren(nCol,(hti==GetRootItem() ? FALSE : TRUE),
|
|
bAscending,m_lpfnDefaultCompare,lParam);
|
|
}
|
|
|
|
if(bOldExpand)
|
|
{
|
|
xti->SetExpand(TRUE);
|
|
COXTreeItem *xtiTemp=xti->pxFirstChild;
|
|
int pos=GetItemIndexInternal(xti) + 1;
|
|
while(xtiTemp)
|
|
{
|
|
if(!xtiTemp->IsHidden())
|
|
{
|
|
SetItemAtPos(pos,xtiTemp);
|
|
pos ++;
|
|
pos=xtiTemp->AddChildrenToCtrl(this,pos);
|
|
}
|
|
xtiTemp=xtiTemp->pxNext;
|
|
}
|
|
}
|
|
|
|
SetRedraw(TRUE);
|
|
waitCursor.Restore();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::SortChildrenCB(LPTV_SORTCB pSort, int nCol/*=0*/)
|
|
{
|
|
return SortChildren(pSort->hParent,nCol,TRUE,pSort->lpfnCompare,pSort->lParam);
|
|
}
|
|
|
|
HTREEITEM COXTreeCtrl::GetItemFromIndex(int nIndex) const
|
|
{
|
|
ASSERT(nIndex>=-1);
|
|
if(nIndex==-1)
|
|
{
|
|
return GetRootItem();
|
|
}
|
|
|
|
return (HTREEITEM)((CListCtrl*)this)->GetItemData(nIndex);
|
|
}
|
|
|
|
|
|
LRESULT COXTreeCtrl::OnNeedItemTip(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
#ifndef OX_TREECTRL_NOITEMTIPS
|
|
LPNEEDITEMTIPINFO pnitInfo=(LPNEEDITEMTIPINFO)lParam;
|
|
int nResult=pnitInfo->result;
|
|
|
|
if(nResult!=ID_NIT_WRONGFORMAT && nResult!=ID_NIT_OUTOFCONTROLBORDER)
|
|
{
|
|
CPoint point;
|
|
point.x=pnitInfo->point.x;
|
|
point.y=pnitInfo->point.y;
|
|
|
|
UINT nFl;
|
|
int idx=HitTest(point,&nFl);
|
|
|
|
HTREEITEM hti=GetItemFromIndex(idx);
|
|
ASSERT(hti);
|
|
COXTreeItem *xti=GetXItem(hti);
|
|
ASSERT(xti);
|
|
|
|
if(idx==-1)
|
|
{
|
|
pnitInfo->result=ID_NIT_OUTOFCONTROLBORDER;
|
|
return 0;
|
|
}
|
|
pnitInfo->row=idx;
|
|
|
|
CRect rcItem;
|
|
CListCtrl::GetItemRect(idx,&rcItem,LVIR_BOUNDS);
|
|
|
|
// Now find the column
|
|
int nCol=0;
|
|
while(TRUE)
|
|
{
|
|
int nColWidth=GetColumnWidth(nCol);
|
|
if(nColWidth<0)
|
|
{
|
|
pnitInfo->result=ID_NIT_OUTOFCONTROLBORDER;
|
|
return 0;
|
|
}
|
|
|
|
rcItem.right=rcItem.left+nColWidth;
|
|
if(rcItem.PtInRect(point))
|
|
{
|
|
break;
|
|
}
|
|
rcItem.left=rcItem.right;
|
|
nCol++;
|
|
}
|
|
if(nCol && !xti->GetSubItem(nCol))
|
|
{
|
|
// this item has no subitems at given column
|
|
pnitInfo->result=ID_NIT_CUSTOMREJECT;
|
|
return 0;
|
|
}
|
|
pnitInfo->col=nCol;
|
|
|
|
CImageList *pImgList=CListCtrl::GetImageList(LVSIL_SMALL);
|
|
CImageList *pStateImgList=CListCtrl::GetImageList(LVSIL_STATE);
|
|
|
|
LV_COLUMN lvc;
|
|
memset(&lvc, 0, sizeof(LV_COLUMN));
|
|
lvc.mask=LVCF_FMT;
|
|
VERIFY(GetColumn(nCol, &lvc));
|
|
|
|
int nImgWidth=0;
|
|
IMAGEINFO imgInfo;
|
|
int nImg=xti->GetItemImage(nCol);
|
|
|
|
if(pImgList && nImg!=-1)
|
|
{
|
|
pImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImg(imgInfo.rcImage);
|
|
nImgWidth += rcImg.Width();
|
|
}
|
|
|
|
if(pStateImgList && nCol==0 &&
|
|
GetItemStateIndex(GetItemIndexInternal(xti))!=-1)
|
|
{
|
|
pStateImgList->GetImageInfo(0,&imgInfo);
|
|
CRect rcImg(imgInfo.rcImage);
|
|
nImgWidth += rcImg.Width();
|
|
}
|
|
|
|
rcItem.left+=nImgWidth;
|
|
rcItem.left+=nCol==0 ? GetItemIndent(xti) : 0;
|
|
if(!rcItem.PtInRect(point))
|
|
{
|
|
pnitInfo->result=ID_NIT_OUTOFITEMBORDER;
|
|
return 0;
|
|
}
|
|
|
|
pnitInfo->clrText=xti->IsDisabled() ? ::GetSysColor(COLOR_3DSHADOW) :
|
|
xti->HasColor(nCol) ? xti->GetItemColor(nCol) : GetTextColor();
|
|
// pnitInfo->clrBackground=GetTextBkColor();
|
|
pnitInfo->clrBackground=ID_OX_COLOR_NONE;
|
|
|
|
CString sText=GetItemText((HTREEITEM)xti,nCol);
|
|
if(sText.IsEmpty())
|
|
{
|
|
pnitInfo->result=ID_NIT_NOTHIDDEN;
|
|
return 0;
|
|
}
|
|
lstrcpyn(pnitInfo->itemText,sText,pnitInfo->sizeText);
|
|
pnitInfo->pFont=(LPARAM)GetFont();
|
|
if(xti->HasFont(nCol))
|
|
{
|
|
pnitInfo->pFont=(LPARAM)xti->GetItemFont(nCol);
|
|
}
|
|
|
|
int nOffset=2;
|
|
rcItem.DeflateRect(nOffset,0);
|
|
|
|
CClientDC dc(this);
|
|
CFont* pOldFont=pnitInfo->pFont==NULL ? NULL :
|
|
dc.SelectObject((CFont*)pnitInfo->pFont);
|
|
CRect rectText(0, 0, 0, 0);
|
|
dc.DrawText(sText,&rectText,DT_CALCRECT|DT_LEFT|DT_SINGLELINE);
|
|
if(pOldFont)
|
|
{
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
|
|
CRect rectClient;
|
|
GetClientRect(&rectClient);
|
|
|
|
int fmt=lvc.fmt&LVCFMT_JUSTIFYMASK;
|
|
int nTextWidth=rectText.Width();
|
|
switch(fmt)
|
|
{
|
|
case LVCFMT_LEFT:
|
|
{
|
|
rectText.left=rcItem.left;
|
|
rectText.right=rectText.left+nTextWidth;
|
|
pnitInfo->alignment=DT_LEFT;
|
|
break;
|
|
}
|
|
case LVCFMT_RIGHT:
|
|
{
|
|
rectText.right=rcItem.right;
|
|
rectText.left=rectText.right-nTextWidth;
|
|
pnitInfo->alignment=DT_RIGHT;
|
|
break;
|
|
}
|
|
case LVCFMT_CENTER:
|
|
{
|
|
int nCenter=rcItem.left+(rcItem.right-rcItem.left)/2;
|
|
rectText.left=nCenter-nTextWidth/2;
|
|
rectText.right=nCenter+nTextWidth/2;
|
|
rectText.right+=nTextWidth%2;
|
|
pnitInfo->alignment=DT_CENTER;
|
|
break;
|
|
}
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
if(rectText.Width()<=rcItem.Width() &&
|
|
rectText.right<=rectClient.right && rectText.left>=rectClient.left)
|
|
{
|
|
pnitInfo->result=ID_NIT_NOTHIDDEN;
|
|
return 0;
|
|
}
|
|
|
|
if(rcItem.Width()<rectText.Width())
|
|
{
|
|
rcItem.right=rcItem.left+rectText.Width();
|
|
}
|
|
rcItem.InflateRect(nOffset,0);
|
|
|
|
pnitInfo->rectItem.left=rcItem.left;
|
|
pnitInfo->rectItem.right=rcItem.right;
|
|
pnitInfo->rectItem.top=rcItem.top;
|
|
pnitInfo->rectItem.bottom=rcItem.bottom;
|
|
|
|
pnitInfo->offset=nOffset;
|
|
|
|
pnitInfo->result=ID_NIT_SUCCESS;
|
|
}
|
|
#else
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void COXTreeCtrl::OnTimer(UINT nIDEvent)
|
|
{
|
|
if(nIDEvent==m_nTimerCheckKeyboardInput)
|
|
{
|
|
m_sSearchMask=_T("");
|
|
return;
|
|
}
|
|
|
|
CListCtrl::OnTimer(nIDEvent);
|
|
}
|
|
|
|
void COXTreeCtrl::OnDestroy()
|
|
{
|
|
if(m_nTimerCheckKeyboardInput!=NULL)
|
|
KillTimer(m_nTimerCheckKeyboardInput);
|
|
|
|
CListCtrl::OnDestroy();
|
|
}
|
|
|
|
void COXTreeCtrl::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CListCtrl::OnSize(nType, cx, cy);
|
|
|
|
if (m_dwExStyle & TVOXS_EXTENDCOLUMNS)
|
|
PostMessage(WM_USER_ADJUSTLASTCOLUMN);
|
|
}
|
|
|
|
LRESULT COXTreeCtrl::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
|
|
#ifndef OX_TREECTRL_NOITEMTIPS
|
|
if(m_bFirstTimeHooking && (m_dwExStyle&TVOXS_ITEMTIPS)==TVOXS_ITEMTIPS &&
|
|
m_ItemTip.GetHookedWnd()!=this)
|
|
{
|
|
m_bFirstTimeHooking=FALSE;
|
|
m_ItemTip.Attach(this);
|
|
}
|
|
#endif
|
|
return CListCtrl::DefWindowProc(message, wParam, lParam);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
|
|
UINT nID, DWORD dwExStyle/*=0*/)
|
|
{
|
|
DWORD dwWndStyle=dwStyle&0xffff0000;
|
|
m_dwTCStyle=dwStyle&0x0000ffff;
|
|
m_dwExStyle=dwExStyle;
|
|
DWORD dwListStyle=LVS_REPORT|LVS_OWNERDRAWFIXED;
|
|
|
|
if(m_dwTCStyle & TVS_SHOWSELALWAYS)
|
|
dwListStyle |= LVS_SHOWSELALWAYS;
|
|
if(m_dwTCStyle & TVS_EDITLABELS)
|
|
dwListStyle |= LVS_EDITLABELS;
|
|
|
|
if(!(m_dwExStyle & TVOXS_MULTISEL))
|
|
dwListStyle |= LVS_SINGLESEL;
|
|
if(!(m_dwExStyle & TVOXS_COLUMNHDR))
|
|
dwListStyle |= LVS_NOCOLUMNHEADER;
|
|
if(m_dwExStyle & TVOXS_NOSCROLL)
|
|
{
|
|
dwListStyle |= LVS_NOSCROLL;
|
|
}
|
|
else
|
|
dwWndStyle |= WS_VSCROLL | WS_HSCROLL;
|
|
if(m_dwExStyle & TVOXS_NOSORTHEADER)
|
|
dwListStyle |= LVS_NOSORTHEADER;
|
|
if(m_dwExStyle & TVOXS_SHAREIMAGELISTS)
|
|
dwListStyle |= LVS_SHAREIMAGELISTS;
|
|
|
|
if(!CListCtrl::Create(dwListStyle|dwWndStyle,rect,pParentWnd,nID))
|
|
{
|
|
return FALSE;
|
|
}
|
|
DWORD dwAddStyle=::GetWindowLongPtr(m_hWnd,GWL_STYLE);
|
|
m_dwTCStyle|=(0xFFFF0000&dwAddStyle);
|
|
|
|
return Init();
|
|
}
|
|
|
|
BOOL COXTreeCtrl::IsHeaderSorting() const
|
|
{
|
|
return ((m_dwExStyle&TVOXS_NOSORTHEADER)!=TVOXS_NOSORTHEADER &&
|
|
(m_dwExStyle&TVOXS_COLUMNHDR)==TVOXS_COLUMNHDR);
|
|
}
|
|
|
|
int COXTreeCtrl::GetSortCol() const
|
|
{
|
|
COXTreeHeader* pHeader=(COXTreeHeader*)GetDlgItem(0);
|
|
ASSERT(pHeader);
|
|
return pHeader->GetSortCol();
|
|
}
|
|
|
|
int COXTreeCtrl::GetSortOrder() const
|
|
{
|
|
COXTreeHeader* pHeader=(COXTreeHeader*)GetDlgItem(0);
|
|
ASSERT(pHeader);
|
|
return pHeader->GetSortOrder();
|
|
}
|
|
|
|
void COXTreeCtrl::OnParentNotify(UINT message, LPARAM lParam)
|
|
{
|
|
CListCtrl::OnParentNotify(message,lParam);
|
|
|
|
if(LOWORD(message) == WM_CREATE)
|
|
{
|
|
HWND hWnd=GetHeaderCtrlHandle();
|
|
if(hWnd==(HWND)lParam)
|
|
{
|
|
if(!::IsWindow(m_wndHdr.GetSafeHwnd()))
|
|
VERIFY(m_wndHdr.SubclassWindow(hWnd));
|
|
else
|
|
ASSERT(m_wndHdr.GetSafeHwnd()==hWnd);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
HWND COXTreeCtrl::GetHeaderCtrlHandle()
|
|
{
|
|
ASSERT_VALID(this);
|
|
if (m_hWnd == NULL)
|
|
// ... This control has not been created yet
|
|
return NULL;
|
|
|
|
// Get the first child of the list control
|
|
// Normally the list only has one child window : the header control
|
|
HWND hHeaderWnd=::GetDlgItem(m_hWnd, 0);
|
|
if(hHeaderWnd != NULL)
|
|
{
|
|
// Make extra sure we actually have a header ctrl
|
|
const int nMaxClassNameLength=50;
|
|
TCHAR szClass[nMaxClassNameLength + 1];
|
|
::GetClassName(hHeaderWnd, szClass, nMaxClassNameLength);
|
|
if(_tcscmp(szClass, _T("SysHeader32")) == 0)
|
|
{
|
|
return hHeaderWnd;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXTreeCtrl::GetHeaderCtrlHandle : No child window found\n"));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::CopyItem(HTREEITEM hItemToCopy, HTREEITEM hParent/*=NULL*/,
|
|
HTREEITEM hInsertAfter/*=TVI_LAST*/,
|
|
BOOL bCopyDescendants/*=TRUE*/,
|
|
HTREEITEM* pNewItem/*=NULL*/,
|
|
COXTreeCtrl* /*pDestinationTree=NULL*/)
|
|
{
|
|
ASSERT(hItemToCopy!=NULL);
|
|
|
|
// define if we can copy an item: we cannot copy an item with its descendants
|
|
// to itself or its descendants
|
|
BOOL bCanCopy=TRUE;
|
|
if(bCopyDescendants)
|
|
{
|
|
HTREEITEM hTestItem=hParent;
|
|
while(hTestItem!=NULL)
|
|
{
|
|
if(hTestItem==hItemToCopy)
|
|
{
|
|
bCanCopy=FALSE;
|
|
break;
|
|
}
|
|
hTestItem=GetParentItem(hTestItem);
|
|
}
|
|
}
|
|
|
|
if(!bCanCopy)
|
|
return FALSE;
|
|
|
|
COXTreeItem* pxParent=GetXItem(hParent);
|
|
ASSERT(pxParent!=NULL);
|
|
|
|
COXTreeItem* pxItemToCopy=GetXItem(hItemToCopy);
|
|
ASSERT(pxItemToCopy!=NULL);
|
|
|
|
COXTreeItem* pxInsertAfter=NULL;
|
|
if(hInsertAfter==TVI_FIRST || hInsertAfter==TVI_LAST)
|
|
pxInsertAfter=(COXTreeItem*)hInsertAfter;
|
|
else
|
|
pxInsertAfter=GetXItem(hInsertAfter);
|
|
|
|
COXTreeItem* pTempNewItem=pxParent->CopyChild(pxItemToCopy,pxInsertAfter,bCopyDescendants);
|
|
|
|
if (pNewItem)
|
|
*pNewItem=(HTREEITEM) pTempNewItem;
|
|
|
|
BOOL bWasHidden=IsItemHidden(hParent);
|
|
if(!bWasHidden)
|
|
{
|
|
// lock the control updates
|
|
SetRedraw(FALSE);
|
|
|
|
// hiding of item will remove it from list control while
|
|
// saving internal logic
|
|
HideItem(hParent,TRUE);
|
|
|
|
// restore the visibility of hidden item
|
|
HideItem(hParent,FALSE);
|
|
|
|
// unlock the control updates
|
|
SetRedraw(TRUE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::MoveItem(HTREEITEM hItemToMove, HTREEITEM hParent/*=NULL*/,
|
|
HTREEITEM hInsertAfter/*=TVI_LAST*/,
|
|
COXTreeCtrl* pDestinationTree/*=NULL*/)
|
|
{
|
|
if(hItemToMove==hInsertAfter)
|
|
return TRUE;
|
|
|
|
// define if we can move item: we cannot move dragged item to its
|
|
// descendants
|
|
BOOL bCanMove=TRUE;
|
|
HTREEITEM hTestItem=hParent;
|
|
while(hTestItem!=NULL)
|
|
{
|
|
if(hTestItem==hItemToMove)
|
|
{
|
|
bCanMove=FALSE;
|
|
break;
|
|
}
|
|
hTestItem=GetParentItem(hTestItem);
|
|
}
|
|
|
|
if(!bCanMove)
|
|
return FALSE;
|
|
|
|
|
|
COXTreeItem* pxParent;
|
|
if (pDestinationTree != NULL)
|
|
pxParent = pDestinationTree->GetXItem(hParent);
|
|
else
|
|
pxParent = GetXItem(hParent);
|
|
ASSERT(pxParent!=NULL);
|
|
|
|
COXTreeItem* pxItemToMove=GetXItem(hItemToMove);
|
|
ASSERT(pxItemToMove!=NULL);
|
|
|
|
COXTreeItem* pxInsertAfter=NULL;
|
|
if(hInsertAfter==TVI_FIRST || hInsertAfter==TVI_LAST)
|
|
pxInsertAfter=(COXTreeItem*)hInsertAfter;
|
|
else
|
|
pxInsertAfter=GetXItem(hInsertAfter);
|
|
|
|
|
|
// lock the control updates
|
|
SetRedraw(FALSE);
|
|
if (pDestinationTree != NULL)
|
|
pDestinationTree->SetRedraw(FALSE);
|
|
|
|
// hiding of item will remove it from list control while
|
|
// saving internal logic
|
|
HideItem(hItemToMove,TRUE);
|
|
|
|
// remove the moved item and its descendants out of internal chain
|
|
pxItemToMove->Unlink();
|
|
// insert moved item and its descendants
|
|
pxParent->AddChild(pxItemToMove,pxInsertAfter);
|
|
|
|
|
|
// show the reallocated item
|
|
if (pDestinationTree != NULL)
|
|
pDestinationTree->HideItem(hItemToMove,FALSE);
|
|
else
|
|
HideItem(hItemToMove,FALSE);
|
|
|
|
// unlock the control updates
|
|
SetRedraw(TRUE);
|
|
if (pDestinationTree != NULL)
|
|
pDestinationTree->SetRedraw(TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXTreeCtrl::RedrawTreeItems(HTREEITEM hItemFirst, HTREEITEM hItemLast)
|
|
{
|
|
if(hItemFirst==NULL || GetItemIndex(hItemFirst)==-1 ||
|
|
hItemLast==NULL || GetItemIndex(hItemLast)==-1)
|
|
return FALSE;
|
|
|
|
CListCtrl::RedrawItems(GetItemIndex(hItemFirst),GetItemIndex(hItemLast));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXTreeCtrl::OnStyleChanged( int nStyleType, LPSTYLESTRUCT lpStyleStruct )
|
|
{
|
|
if (nStyleType==GWL_STYLE)
|
|
m_dwTCStyle=(lpStyleStruct->styleNew & 0xFFFF0000) | (m_dwTCStyle & 0x0000FFFF);
|
|
}
|
|
|
|
BOOL COXTreeCtrl::PreTranslateMessage( MSG* pMsg )
|
|
{
|
|
return CListCtrl::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
void COXTreeCtrl::SetHorizontalGridColor(COLORREF clr)
|
|
{
|
|
m_clrHorizontalGrid = clr;
|
|
}
|
|
|
|
void COXTreeCtrl::SetVerticalGridColor(COLORREF clr)
|
|
{
|
|
m_clrVerticalGrid = clr;
|
|
}
|
|
|
|
BOOL COXTreeCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
|
|
if (m_dwExStyle & TVOXS_EXTENDCOLUMNS)
|
|
{
|
|
HD_NOTIFY *pHDN = (HD_NOTIFY*) lParam;
|
|
|
|
if ((pHDN->hdr.code == HDN_BEGINTRACKA || pHDN->hdr.code == HDN_BEGINTRACKW) &&
|
|
pHDN->iItem == GetColumnsCount() - 1)
|
|
{
|
|
*pResult = TRUE; // disable tracking
|
|
return TRUE;
|
|
}
|
|
|
|
else if (pHDN->hdr.code == HDN_ITEMCHANGINGA || pHDN->hdr.code == HDN_ITEMCHANGINGW ||
|
|
pHDN->hdr.code == HDN_TRACKA || pHDN->hdr.code == HDN_TRACKW)
|
|
{
|
|
// Adjust the last column
|
|
PostMessage(WM_USER_ADJUSTLASTCOLUMN);
|
|
}
|
|
}
|
|
|
|
return CListCtrl::OnNotify(wParam, lParam, pResult);
|
|
}
|
|
|
|
LRESULT COXTreeCtrl::OnUserAdjustLastColumn(WPARAM /*wParam*/, LPARAM /*lParam*/)
|
|
{
|
|
if (!m_bInit)
|
|
return 0;
|
|
|
|
// Make the last column ends where the window ends
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
|
|
int iCount = GetColumnsCount();//m_wndHdr.GetItemCount();
|
|
if (iCount <= 0)
|
|
return 0;
|
|
|
|
// Loop through all columns and make sure none is larger than the window
|
|
int iAccumulatedWidth = 0;
|
|
for (int i = 0; i < iCount; i++)
|
|
{
|
|
int iCurrentWidth = GetColumnWidth(i);
|
|
|
|
if (iCurrentWidth + iAccumulatedWidth > rectClient.Width())
|
|
{
|
|
// The current column is too wide
|
|
iCurrentWidth = rectClient.Width() - iAccumulatedWidth;
|
|
if (iCurrentWidth < 0)
|
|
iCurrentWidth = 0;
|
|
SetColumnWidth(i, iCurrentWidth);
|
|
}
|
|
else if (i == iCount - 1 && iCurrentWidth + iAccumulatedWidth < rectClient.Width())
|
|
{
|
|
// This is the last column and it is not wide enough
|
|
iCurrentWidth = rectClient.Width() - iAccumulatedWidth;
|
|
SetColumnWidth(i, iCurrentWidth);
|
|
}
|
|
|
|
iAccumulatedWidth += iCurrentWidth;
|
|
}
|
|
|
|
// Send the the message to the parent
|
|
CWnd* pParent = GetParent();
|
|
if (pParent!= NULL)
|
|
pParent->SendMessage(WM_USER_ADJUSTLASTCOLUMN, 0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void COXTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
if (nChar == VK_CONTROL || nChar == VK_MENU)
|
|
return;
|
|
|
|
// Navigation support
|
|
if (nChar == VK_UP ||
|
|
nChar == VK_DOWN ||
|
|
nChar == VK_HOME ||
|
|
nChar == VK_END ||
|
|
nChar == VK_PRIOR ||
|
|
nChar == VK_NEXT)
|
|
{
|
|
CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
return;
|
|
}
|
|
else if (nChar == VK_RIGHT)
|
|
{
|
|
// Try to expand the selected item
|
|
HTREEITEM hSelectedItem = GetSelectedItem();
|
|
if (hSelectedItem != NULL)
|
|
{
|
|
COXTreeItem* pItem = GetXItem(hSelectedItem);
|
|
if (!pItem->IsExpanded())
|
|
Expand(hSelectedItem, TVE_EXPAND);
|
|
else if (pItem->pxFirstChild != NULL)
|
|
{
|
|
// Already expanded, so select the first child
|
|
SelectItem(NULL);
|
|
SelectItem((HTREEITEM) pItem->pxFirstChild);
|
|
}
|
|
}
|
|
}
|
|
else if (nChar == VK_LEFT)
|
|
{
|
|
// Try to collapse the selected item
|
|
HTREEITEM hSelectedItem = GetSelectedItem();
|
|
if (hSelectedItem != NULL)
|
|
{
|
|
COXTreeItem* pItem = GetXItem(hSelectedItem);
|
|
if (pItem->IsExpanded())
|
|
Expand(hSelectedItem, TVE_COLLAPSE);
|
|
else if (pItem->pxParent != NULL)
|
|
{
|
|
// Already collapsed, so select parent
|
|
SelectItem(NULL);
|
|
SelectItem((HTREEITEM) pItem->pxParent);
|
|
}
|
|
}
|
|
}
|
|
|
|
int nCount=GetVisibleCount();
|
|
if(nCount>1)
|
|
{
|
|
if(m_nTimerCheckKeyboardInput!=NULL)
|
|
KillTimer(m_nTimerCheckKeyboardInput);
|
|
|
|
TCHAR chSymbol[2];
|
|
chSymbol[0]=(TCHAR)nChar;
|
|
chSymbol[1]=0;
|
|
CString sNewSymbol=chSymbol;
|
|
m_sSearchMask+=sNewSymbol;
|
|
CString sMask=m_sSearchMask;
|
|
sMask.MakeUpper();
|
|
|
|
int nStartIndex=CListCtrl::GetNextItem(-1,LVNI_ALL|LVNI_FOCUSED);
|
|
|
|
HTREEITEM hti;
|
|
CString sText;
|
|
int nIndex=nStartIndex;
|
|
BOOL bIncludeCurrent=FALSE;
|
|
if(nStartIndex!=-1 && sMask.GetLength()>1)
|
|
{
|
|
nIndex--;
|
|
bIncludeCurrent=TRUE;
|
|
}
|
|
while(TRUE)
|
|
{
|
|
nIndex++;
|
|
if(nIndex>=nCount)
|
|
{
|
|
nIndex=0;
|
|
if(nStartIndex==-1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(nIndex==nStartIndex)
|
|
{
|
|
if(!bIncludeCurrent)
|
|
break;
|
|
else
|
|
bIncludeCurrent=FALSE;
|
|
}
|
|
|
|
hti=GetItemFromIndex(nIndex);
|
|
ASSERT(hti);
|
|
sText=GetItemText(hti);
|
|
sText.MakeUpper();
|
|
if(!sText.IsEmpty() && sText.Find(sMask)==0)
|
|
{
|
|
SelectItem(NULL);
|
|
SelectItem(hti);
|
|
EnsureVisible(hti);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// timer for keyboard input
|
|
m_nTimerCheckKeyboardInput= (UINT)SetTimer(IDT_OXTREECTRL_CHECKFORKEYBOARDINPUT,
|
|
ID_OXTREECTRL_CHECKFORKEYBOARDINPUT_DELAY,NULL);
|
|
if(m_nTimerCheckKeyboardInput==0)
|
|
{
|
|
TRACE(_T("COXTreeCtrl::OnKeydown: Unable to set timer for keyboard input\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL COXTreeCtrl::IsPropertiesWnd() const
|
|
{
|
|
if (GetParent() != NULL && GetParent()->SendMessage(WM_USER_QUERY_PROPERTIESWND))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
void COXTreeCtrl::SetColumnCompareFunction(int nCol, PFNTVCOMPARE lpfnDefaultCompare)
|
|
{
|
|
m_mapCompareFunctions.SetAt(nCol, lpfnDefaultCompare);
|
|
}
|