Files
envi-code/SourceCode/Code2026/CoreCommand/supergridctrl.cpp
T
2026-09-28 15:28:50 +08:00

2350 lines
57 KiB
C++

#include "stdafx.h"
#include "SuperGridCtrl.h"
#include "ListEditCtrl.h"
#include "coretools.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef WM_ITEM_SEL
#define WM_ITEM_SEL (WM_USER+0x105)
#endif
CSuperGridCtrl::CSuperGridCtrl()
{
m_cxImage = m_cyImage = m_bIsDragging = m_CurSubItem = 0;
m_nDragTarget=m_nDragItem = -1;
m_psTreeLine.CreatePen(PS_SOLID, 1, RGB(192,192,192));
m_psRectangle.CreatePen(PS_SOLID, 1, RGB(198,198,198));
m_psPlusMinus.CreatePen(PS_SOLID, 1, RGB(0,0,0));
m_brushErase.CreateSolidBrush(RGB(255,255,255));
m_himl = NULL;
m_bDragStyle = FALSE;
m_bEditStyle = FALSE;
m_dwCellRGB = RGB(192, 192, 192);
}
CSuperGridCtrl::~CSuperGridCtrl()
{
m_psPlusMinus.DeleteObject();
m_psRectangle.DeleteObject();
m_psTreeLine.DeleteObject();
m_brushErase.DeleteObject();
while(m_RootItems.GetCount())
{
CTreeItem * root = (CTreeItem*)m_RootItems.RemoveHead();
if(root!=NULL && GetData(root) != NULL)
delete GetData(root);
if (root)
{
delete root;
root = NULL;
}
}
m_RootItems.RemoveAll();
}
BEGIN_MESSAGE_MAP(CSuperGridCtrl, CListCtrl)
//{{AFX_MSG_MAP(CSuperGridCtrl)
ON_NOTIFY_REFLECT_EX(NM_DBLCLK, OnDblclk)
ON_NOTIFY_REFLECT_EX(LVN_ENDLABELEDIT, OnEndlabeledit)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
ON_WM_MOUSEWHEEL()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_LBUTTONUP()
ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
ON_WM_MEASUREITEM_REFLECT()
ON_WM_DRAWITEM_REFLECT()
ON_WM_SYSCOLORCHANGE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CSuperGridCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= LVS_REPORT | LVS_SINGLESEL | LVS_SHAREIMAGELISTS | LVS_OWNERDRAWFIXED | LVS_SHOWSELALWAYS;
return CListCtrl::PreCreateWindow(cs);
}
int CSuperGridCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
#define OFFSET_FIRST 2 * dScale
#define OFFSET_OTHER 6 * dScale
void CSuperGridCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (lpDrawItemStruct->CtlType != ODT_LISTVIEW)
return;
double dScale = CoreTools::GetDPIScale();
if(lpDrawItemStruct->itemAction == ODA_DRAWENTIRE)
{
if(m_himl==NULL)
{
m_himl = (HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, (WPARAM)(int)(LVSIL_SMALL), 0L);
if(m_himl==NULL)
return;
}
LV_ITEM lvi;
static _TCHAR szBuff[MAX_PATH];
LPCTSTR pszText;
int nItem = lpDrawItemStruct->itemID;
CRect rcItem(lpDrawItemStruct->rcItem);
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT | LVIF_PARAM;
lvi.iItem = nItem;
lvi.iSubItem =0;
lvi.pszText = szBuff;
lvi.cchTextMax = sizeof(szBuff);
lvi.stateMask = 0xFFFF;
GetItem(&lvi);
CTreeItem *pSelItem = (CTreeItem*)lpDrawItemStruct->itemData;
CRect rcLabel;
GetItemRect(nItem, rcLabel, LVIR_LABEL);
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
ASSERT(pDC);
CRect rcClipBox;
pDC->GetClipBox(rcClipBox);
COLORREF crBackground, crText;
if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
// Set the text background and foreground colors
crBackground = GetSysColor (COLOR_HIGHLIGHT);
crText = GetSysColor (COLOR_HIGHLIGHTTEXT);
}
else
{
// Set the text background and foreground colors to the standard window
// colors
crBackground = GetSysColor (COLOR_WINDOW);
crText = GetSysColor (COLOR_WINDOWTEXT);
}
//Get current Icon, you have overridden this I hope :-)
int iImage = GetIcon(pSelItem);
if(iImage!=-1)
{
if(lvi.iImage!=iImage)
{
LV_ITEM lvItem;
lvItem.mask = LVIF_IMAGE;
lvItem.iImage = iImage;
lvItem.iItem = nItem;
lvItem.iSubItem = 0;
SetItem(&lvItem);
lvi.iImage = iImage;
}
}
CRect rc;
GetItemRect(nItem, rc, LVIR_BOUNDS);
CRect rcIcon;
GetItemRect(nItem, rcIcon, LVIR_ICON);
//Draw Current image
int nOffset = (rcItem.Height() - m_cyImage)/2;
int nY = rcItem.bottom - m_cyImage - nOffset;
int nWidth = m_cxImage;//def icon size
//do not draw icon out side 1.st column.
int iTryIndent = GetIndent(pSelItem) * m_cxImage + m_cxImage;
if(rc.left + iTryIndent > GetColumnWidth(0)-2/*looks better -2*/)
nWidth = (rc.left + iTryIndent) - GetColumnWidth(0);
UINT uiFlags = ILD_TRANSPARENT;
if( GetItemState(nItem, LVIF_STATE) & LVIS_DROPHILITED)//if dragging show a SelectDropTarget alike effect :)
uiFlags |= ILD_BLEND50;
int iconLeft(rc.left + (GetIndent(pSelItem) * m_cxImage));
int iconRight(iconLeft + m_cxImage);
if((nWidth=m_cxImage-nWidth) >-1)//calc width of icon
{
CoreTools::drawIcon(m_himl, lvi.iImage, pDC->m_hDC, CPoint(iconLeft, nY), 0);
DrawTreeItem(pDC, pSelItem, nItem, rc);
}
//Draw selection bar (erase old selection too)
pDC->SetBkColor(crBackground);
CRect rcClip = lpDrawItemStruct->rcItem;
rcClip.left += GetIndent(pSelItem) * m_cxImage + m_cxImage + 2;
if(rcClip.left > GetColumnWidth(0))
rcClip.left = GetColumnWidth(0);
//fill background color
ExtTextOut(pDC->GetSafeHdc(), 0, 0, ETO_OPAQUE, rcClip, NULL, 0, NULL);
//draw color in first col if any
rcClip.right = rcLabel.right;
CItemInfo *pItemInfo = GetData(pSelItem);
COLORREF clf = pItemInfo->GetItemClr();
if(clf!=-1)
{
CBrush br(clf);
pDC->FillRect(rcClip, &br);
}
//draw selection rect in 1.st col if selected
if ((lpDrawItemStruct->itemState & ODS_SELECTED) && (m_CurSubItem==0))
{
CBrush br(GetCellRGB());
pDC->FillRect(rcClip,&br);
pDC->DrawFocusRect(rcClip);
}
//if checkbox style
bool bHasCheckBox(false);
UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK;
if (nStateImageMask)
{
int nImage = (nStateImageMask>>12) - 1;
CImageList *pImageList = GetImageList(LVSIL_STATE);
if (pImageList)
{
int cxIcon,cyIcon=0;
ImageList_GetIconSize(pImageList->m_hImageList, &cxIcon, &cyIcon);
cxIcon *= dScale;
cyIcon *= dScale;
CPoint ptIcon(rc.left + (GetIndent(pSelItem) * m_cxImage) + cxIcon, nY);
ptIcon.x += cxIcon * .1;
if (rc.left + (GetIndent(pSelItem) * m_cxImage) + m_cxImage + cxIcon < GetColumnWidth(0))
{
CoreTools::drawIcon(pImageList->GetSafeHandle(), nImage, pDC->GetSafeHdc(), ptIcon, 0);
bHasCheckBox = true;
}
}
}
//draw 1. item
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH;
GetColumn(0, &lvc);
GetItemRect(nItem, rcItem, LVIR_LABEL);
pszText = MakeShortString(pDC, szBuff, lvc.cx - iconRight, 2*OFFSET_FIRST);
rcLabel = rcItem;
rcLabel.left = iconRight + OFFSET_FIRST;
if (bHasCheckBox)
rcLabel.left += m_cxImage;
rcLabel.right += rcLabel.left;
pDC->SetBkColor (crBackground);
pDC->SetTextColor (crText);
pDC->DrawText(pszText,-1, rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_EXTERNALLEADING);
//draw subitems..
for(int nColumn=1; GetColumn(nColumn, &lvc); nColumn++)
{
rcItem.left=rcItem.right;
rcItem.right+=lvc.cx;
if (rcItem.left < rcClipBox.right && rcItem.right > rcClipBox.left && rcItem.right > rcItem.left)
{
//support for colors in each cell
COLORREF clf = pItemInfo->GetBkColor(nColumn-1);
if(clf!=-1)
{
CBrush br(clf);
pDC->FillRect(rcItem, &br);
}
int nRetLen = GetItemText(nItem, nColumn, szBuff, sizeof(szBuff));
if(nRetLen==0)
pszText=NULL;
else
pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_OTHER);
UINT nJustify=DT_LEFT;
if(pszText==szBuff)
{
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
{
case LVCFMT_RIGHT:
nJustify=DT_RIGHT;
break;
case LVCFMT_CENTER:
nJustify=DT_CENTER;
break;
default:
break;
}
}
rcLabel=rcItem;
rcLabel.left+=OFFSET_OTHER;
rcLabel.right-=OFFSET_OTHER;
if (lpDrawItemStruct->itemState & ODS_SELECTED && !m_bIsDragging)
DrawFocusCell(pDC, lpDrawItemStruct->itemID, nColumn);
if(pszText!=NULL)
pDC->DrawText(pszText,-1,rcLabel, nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_EXTERNALLEADING);
}//if
//draw down arrow if combobox regardless of rcClipBox rgn
if (lpDrawItemStruct->itemState & ODS_SELECTED)
DrawComboBox(pDC, pSelItem, nItem, nColumn);
}//for
}//ODA_DRAWENTIRE
}
void CSuperGridCtrl::DrawComboBox(CDC* pDC, CTreeItem *pSelItem, int nItem, int nColumn)
{
CItemInfo* pInfo = GetData(pSelItem);
CItemInfo::CONTROLTYPE ctrlType;
if(pInfo->GetControlType(nColumn-1, ctrlType))
{
if(ctrlType == CItemInfo::combobox)
{
CRect rect;
GetSubItemRect(nItem, nColumn, LVIR_BOUNDS, rect);
rect.left=rect.right - GetSystemMetrics(SM_CYVSCROLL);
pDC->DrawFrameControl(rect, DFC_SCROLL, DFCS_SCROLLDOWN);
}
}
}
//this piece of code is borrowed from the wndproc.c file in the odlistvw.exe example from MSDN and was converted to mfc-style
void CSuperGridCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if (lpMeasureItemStruct->CtlType != ODT_LISTVIEW)
return;
TEXTMETRIC tm;
CClientDC dc(this);
CFont* pFont = GetFont();
CFont* pOldFont = dc.SelectObject(pFont);
dc.GetTextMetrics(&tm);
int nItemHeight = tm.tmHeight + tm.tmExternalLeading;
lpMeasureItemStruct->itemHeight = nItemHeight + 4; //or should I go for max(nItemheight+4, m_cxImage+2);
dc.SelectObject(pOldFont);
}
//the basic rutine making the ... thing snatched it from some tedious code example some where in MSDN call odlistvw.exe
LPCTSTR CSuperGridCtrl::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
{
static const _TCHAR szThreeDots[]=_T("...");
int nStringLen=lstrlen(lpszLong);
if(nStringLen==0 || CoreTools::getStringSZ(pDC->GetSafeHdc(), lpszLong).cx + nOffset < nColumnLen)
return(lpszLong);
static _TCHAR szShort[MAX_PATH];
lstrcpy(szShort,lpszLong);
int nAddLen = CoreTools::getStringSZ(pDC->GetSafeHdc(), szThreeDots).cx;
for(int i=nStringLen-1; i > 0; i--)
{
szShort[i]=0;
if(CoreTools::getStringSZ(pDC->GetSafeHdc(), szShort).cx + nOffset + nAddLen < nColumnLen)
break;
}
lstrcat(szShort,szThreeDots);
return(szShort);
}
void CSuperGridCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
switch(pLVKeyDow->wVKey)
{
case VK_SPACE:
{
if(GetExtendedStyle() & LVS_EX_CHECKBOXES)
{
int nIndex = GetSelectedItem();
if(nIndex !=-1)
{
CTreeItem* pItem = GetTreeItem(nIndex);
if(pItem!=NULL)
{
CItemInfo *pInfo = GetData(pItem);
pInfo->SetCheck(!pInfo->GetCheck());
}
}
}
}break;
case VK_DELETE:
{
/*int nItem = GetSelectedItem();
if(nItem!=-1)
{
CTreeItem* pSelItem = GetTreeItem(nItem);
if(pSelItem != NULL)
{
if(OnDeleteItem(pSelItem, nItem))
DeleteItemEx(pSelItem, nItem);
}
}*/
} break;
case VK_MULTIPLY:
{
int nIndex = GetSelectedItem();
if(nIndex != -1)
{
CWaitCursor wait;
SetRedraw(0);
CTreeItem *pParent = GetTreeItem(nIndex);
int nScroll=0;
if(OnVKMultiply(pParent, nIndex))
{
ExpandAll(pParent, nScroll);
}
SetRedraw(1);
RedrawItems(nIndex, nScroll);
EnsureVisible(nScroll, TRUE);
}
}break;
case VK_ADD:
{
int nIndex = GetSelectedItem();
if(nIndex!=-1)
{
CWaitCursor wait;
CTreeItem *pSelItem = GetTreeItem(nIndex);
int nScrollIndex = 0;
if(OnVKAdd(pSelItem, nIndex))
{
nScrollIndex = Expand(pSelItem, nIndex);
}
CRect rc;
GetItemRect(nIndex, rc, LVIR_BOUNDS);
InvalidateRect(rc);
UpdateWindow();
EnsureVisible(nScrollIndex, 1);
}
}break;
case VK_SUBTRACT:
{
int nIndex = GetSelectedItem();
if(nIndex!=-1)
{
CWaitCursor wait;
CTreeItem *pSelItem = GetTreeItem(nIndex);
if(OnVkSubTract(pSelItem, nIndex))
{
Collapse(pSelItem);
}
CRect rc;
GetItemRect(nIndex, rc, LVIR_BOUNDS);
InvalidateRect(rc);
UpdateWindow();
}
}break;
case VK_UP:
{
int nIndex = GetSelectedItem();
if(nIndex!=-1)
{
CWnd* pParent = GetParent();
if (pParent != NULL)
{
CPoint* pPt = new CPoint(nIndex,0);
pParent->PostMessage(WM_ITEM_SEL,(WPARAM)m_hWnd,(LPARAM)pPt);
}
}
break;
}
case VK_DOWN:
{
int nIndex = GetSelectedItem();
if(nIndex!=-1)
{
CWnd* pParent = GetParent();
if (pParent != NULL)
{
CPoint* pPt = new CPoint(nIndex,0);
pParent->PostMessage(WM_ITEM_SEL,(WPARAM)m_hWnd,(LPARAM)pPt);
}
}
break;
}
default :break;
}
*pResult = 0;
}
BOOL CSuperGridCtrl::HitTestOnSign(CPoint point, LVHITTESTINFO& ht)
{
ht.pt = point;
// Test which subitem was clicked.
SubItemHitTest(&ht);
if(ht.iItem!=-1)
{
//first hittest on checkbox
BOOL bHit = FALSE;
if(GetExtendedStyle() & LVS_EX_CHECKBOXES)
{
if (ht.flags == LVHT_ONITEM && (GetStyle() & LVS_OWNERDRAWFIXED))//isn't this allways ownerdrawfixed :-)
{
CRect rcIcon,rcLabel;
GetItemRect(ht.iItem, rcIcon, LVIR_ICON);//has to be between these two ....right :)
GetItemRect(ht.iItem, rcLabel, LVIR_LABEL);
bHit = PtHitCheckBox(point);
//CTreeItem *pItem = GetTreeItem(ht.iItem);
//int left = (GetIndent(pItem) * m_cxImage) + m_cxImage;
//int right = left + m_cxImage;
//if (point.x >= left && point.x <= right)
// bHit = TRUE;
//else
// bHit = FALSE;
}
else if (ht.flags & LVHT_ONITEMSTATEICON)
bHit = TRUE;
}
CTreeItem* pItem = GetTreeItem(ht.iItem);
if(pItem!=NULL)
{
if(bHit)//if checkbox
{
//yes I know..have to maintain to sets of checkstates here...
//one for listview statemask and one for CTreeItem..but its located here so no harm done
SetCheck(ht.iItem,!GetCheck(ht.iItem));
CItemInfo *pInfo = GetData(pItem);
pInfo->SetCheck(!pInfo->GetCheck());
}
//if haschildren and clicked on + or - then expand/collapse
if(ItemHasChildren(pItem))
{
//hittest on the plus/sign "button"
CRect rcBounds;
GetItemRect(ht.iItem, rcBounds, LVIR_BOUNDS);
CRectangle rect(this, NULL, GetIndent(pItem), rcBounds);
BOOL bRedraw=0;//if OnItemExpanding or OnCollapsing returns false, dont redraw
if(rect.HitTest(point))
{
SetRedraw(0);
int nScrollIndex=0;
if(IsCollapsed(pItem))
{
if(OnItemExpanding(pItem, ht.iItem))
{
nScrollIndex = Expand(pItem, ht.iItem);
OnItemExpanded(pItem, ht.iItem);
bRedraw=1;
}
}
else {
if(OnCollapsing(pItem))
{
Collapse(pItem);
OnItemCollapsed(pItem);
bRedraw=1;
}
}
SetRedraw(1);
if(bRedraw)
{
CRect rc;
GetItemRect(ht.iItem, rc, LVIR_BOUNDS);
InvalidateRect(rc);
UpdateWindow();
EnsureVisible(nScrollIndex, 1);
return 0;
}
}
}//has kids
}//pItem!=NULL
}
return 1;
}
BOOL CSuperGridCtrl::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
if( GetFocus() != this)
SetFocus();
// 如果是在checkbox的sytle下,双击checkbox时,不处理
if (PtHitCheckBox(pNMListView->ptAction))
{
return TRUE;
}
LVHITTESTINFO ht;
ht.pt = pNMListView->ptAction;
SubItemHitTest(&ht);
if(OnItemLButtonDown(ht))
{
BOOL bSelect=1;
bSelect = HitTestOnSign(pNMListView->ptAction, ht);
//normal selection
if(bSelect && ht.iItem !=-1)
{
int nIndex = GetSelectedItem();
if(nIndex!=-1)
{
CTreeItem *pSelItem = GetTreeItem(nIndex);
if (pSelItem != NULL)
{
BOOL bRedraw=0;
if(ItemHasChildren(pSelItem))
{
SetRedraw(0);
int nScrollIndex=0;
if(IsCollapsed(pSelItem))
{
if(OnItemExpanding(pSelItem, nIndex))
{
nScrollIndex = Expand(pSelItem, nIndex);
OnItemExpanded(pSelItem, nIndex);
bRedraw=1;
}
}
else
{
if(OnCollapsing(pSelItem))
{
Collapse(pSelItem);
OnItemCollapsed(pSelItem);
bRedraw=1;
}
}
SetRedraw(1);
if(bRedraw)
{
CRect rc;
GetItemRect(nIndex,rc,LVIR_BOUNDS);
InvalidateRect(rc);
UpdateWindow();
EnsureVisible(nScrollIndex,1);
}
}//ItemHasChildren
}//!=NULL
}
}
}
*pResult = 1;
return TRUE;
}
void CSuperGridCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
if(m_bDragStyle == FALSE) return;
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
if(pNMListView->iItem != -1)
{
m_nDragItem = pNMListView->iItem;
CImageList* pDragImage=NULL;
pDragImage = CreateDragImageEx(m_nDragItem);//override this if you want another dragimage or none at all.
if(pDragImage)
{
pDragImage->BeginDrag(0, CPoint(0,0));
pDragImage->DragEnter(this, pNMListView->ptAction);
SetCapture();
m_bIsDragging = TRUE;
}
DELETE_PTR(pDragImage);
}
*pResult = 0;
}
//Create dragimage : Icon + the itemtext
CImageList *CSuperGridCtrl::CreateDragImageEx(int nItem)
{
CImageList *pList = new CImageList;
//get image index
LV_ITEM lvItem;
lvItem.mask = LVIF_IMAGE;
lvItem.iItem = nItem;
lvItem.iSubItem = 0;
GetItem(&lvItem);
CRect rc;
GetItemRect(nItem, &rc, LVIR_BOUNDS);
CString str;
str = GetItemText(nItem, 0);
CFont *pFont = GetFont();
rc.OffsetRect(-rc.left, -rc.top);
rc.right = GetColumnWidth(0);
pList->Create(rc.Width(), rc.Height(),ILC_COLOR24| ILC_MASK , 1, 1);
CDC *pDC = GetDC();
if(pDC)
{
CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap bmpMap;
bmpMap.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());
CBitmap *pOldBmp = dc.SelectObject(&bmpMap);
CFont *pOldFont = dc.SelectObject(pFont);
dc.FillSolidRect(rc, GetSysColor(COLOR_WINDOW));
CImageList *pImgList = GetImageList(LVSIL_SMALL);
if(pImgList)
pImgList->Draw(&dc, lvItem.iImage, CPoint(0,0), ILD_TRANSPARENT);
dc.TextOut(m_cxImage + 4, 0, str);
dc.SelectObject(pOldFont);
dc.SelectObject(pOldBmp);
//causes an error if the 1st column is hidden so must check the imagelist
if(pList->m_hImageList != NULL)
pList->Add(&bmpMap, RGB(255,255,255));
else {
DELETE_PTR(pList);
}
ReleaseDC(pDC);
}
return pList;
}
void CSuperGridCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_bIsDragging)
{
KillTimer(1);
if (CWnd::GetCapture() != this)
m_bIsDragging=0;
if(nFlags==MK_RBUTTON || nFlags==MK_MBUTTON)
m_bIsDragging=0;
if(GetKeyState(VK_ESCAPE) < 0)
m_bIsDragging=0;
if(!m_bIsDragging)//why not put this in a funtion :)
{
SetItemState (m_nDragTarget, 0, LVIS_DROPHILITED);
CImageList::DragLeave(this);
CImageList::EndDrag();
ReleaseCapture();
InvalidateRect(NULL);
UpdateWindow();
}
else
{
CPoint ptList(point);
MapWindowPoints(this, &ptList, 1);
CImageList::DragMove(ptList);
UINT uHitTest = LVHT_ONITEM;
m_nDragTarget = HitTest(ptList, &uHitTest);
// try turn off hilight for previous DROPHILITED state
int nPrev = GetNextItem(-1,LVNI_DROPHILITED);
if(nPrev != m_nDragTarget)//prevents flicker
SetItemState(nPrev, 0, LVIS_DROPHILITED);
CRect rect;
GetClientRect (rect);
int cy = rect.Height();
if(m_nDragTarget!=-1)
{
SetItemState(m_nDragTarget, LVIS_DROPHILITED, LVIS_DROPHILITED);
CTreeItem* pTarget = GetTreeItem(m_nDragTarget);
if ((point.y >= 0 && point.y <= m_cyImage) || (point.y >= cy - m_cyImage && point.y <= cy) ||
( pTarget!=NULL && ItemHasChildren(pTarget) && IsCollapsed(pTarget)))
{
SetTimer(1,300,NULL);
}
}
}
}
CListCtrl::OnMouseMove(nFlags, point);
}
void CSuperGridCtrl::OnTimer(UINT_PTR nIDEvent)
{
CListCtrl::OnTimer(nIDEvent);
if(nIDEvent==1)
{
if(CWnd::GetCapture()!=this)
{
SetItemState(m_nDragTarget, 0, LVIS_DROPHILITED);
m_bIsDragging=0;
CImageList::DragLeave(this);
CImageList::EndDrag();
ReleaseCapture();
InvalidateRect(NULL);
UpdateWindow();
KillTimer(1);
return;
}
SetTimer(1,300,NULL);//reset timer
DWORD dwPos = ::GetMessagePos();
CPoint ptList(LOWORD(dwPos),HIWORD(dwPos));
ScreenToClient(&ptList);
CRect rect;
GetClientRect(rect);
int cy = rect.Height();
//
// perform autoscroll if the cursor is near the top or bottom.
//
if (ptList.y >= 0 && ptList.y <= m_cyImage)
{
int n = GetTopIndex();
CImageList::DragShowNolock(0);
SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), NULL);
CImageList::DragShowNolock(1);
if (GetTopIndex()== n)
KillTimer (1);
else {
CImageList::DragShowNolock(0);
CImageList::DragMove(ptList);
CImageList::DragShowNolock(1);
return;
}
}
else if (ptList.y >= cy - m_cyImage && ptList.y <= cy)
{
int n = GetTopIndex();
CImageList::DragShowNolock(0);
SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), NULL);
CImageList::DragShowNolock(1);
if (GetTopIndex()== n)
KillTimer (1);
else {
CImageList::DragShowNolock(0);
CImageList::DragMove(ptList);
CImageList::DragShowNolock(1);
return;
}
}
//Hover test
CImageList::DragMove(ptList);
UINT uHitTest = LVHT_ONITEM;
m_nDragTarget = HitTest(ptList, &uHitTest);
if(m_nDragTarget!=-1)
{
//if the target has children
//expand them
CTreeItem* pTarget=GetTreeItem(m_nDragTarget);
if(pTarget != NULL && ItemHasChildren(pTarget) && IsCollapsed(pTarget) && (m_nDragItem!=-1))
{
CImageList::DragShowNolock(0);
CTreeItem* pSource = GetTreeItem(m_nDragItem);
SetRedraw(0);
int nScrollIndex=0;
if(ItemHasChildren(pTarget) && IsCollapsed(pTarget))
{
if(OnItemExpanding(pTarget, m_nDragTarget))
{
nScrollIndex = Expand(pTarget, m_nDragTarget);
OnItemExpanded(pTarget, m_nDragTarget);
}
}
m_nDragItem = NodeToIndex(pSource);
SetRedraw(1);
EnsureVisible(nScrollIndex, 1);
InvalidateRect(NULL);
UpdateWindow();
CImageList::DragShowNolock(1);
KillTimer(1);
return;
}
}
KillTimer(1);
}
}
void CSuperGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_bIsDragging == TRUE)
{
KillTimer(1);
CImageList::DragLeave(this);
CImageList::EndDrag();
ReleaseCapture();
m_bIsDragging = FALSE;
SetItemState(m_nDragTarget, 0, LVIS_DROPHILITED);
if((m_nDragTarget != -1) && (m_nDragTarget != m_nDragItem) && (m_nDragItem!=-1))//no drop on me self
{
CTreeItem* pSource = GetTreeItem(m_nDragItem);
CTreeItem* pTarget = GetTreeItem(m_nDragTarget);
if(IsRoot(pSource))
return;
CTreeItem* pParent = GetParentItem(pSource);
if(pParent==pTarget) //can't drag child to parent
return;
if(!IsChildOf(pSource, pTarget))//can't drag parent to child
{
CWaitCursor wait;
SetRedraw(0);
if(DoDragDrop(pTarget, pSource))
{
UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
SetItemState(m_nDragTarget, uflag, uflag);
m_nDragItem=-1;
//delete source
int nIndex = NodeToIndex(pSource);
DeleteItem(nIndex);
HideChildren(pSource, TRUE, nIndex);
Delete(pSource);
InternaleUpdateTree();
SetRedraw(1);
InvalidateRect(NULL);
UpdateWindow();
}else
SetRedraw(1);
}
}
}
else
CListCtrl::OnLButtonUp(nFlags, point);
}
//used with the drag/drop operation
void CSuperGridCtrl::CopyChildren(CTreeItem* pDest, CTreeItem* pSrc)
{
if (ItemHasChildren(pSrc))
{
POSITION pos = pSrc->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pItem = (CTreeItem *)pSrc->m_listChild.GetNext(pos);
CItemInfo* lp = CopyData(GetData(pItem));
CTreeItem* pNewItem = InsertItem(pDest, lp);
CopyChildren(pNewItem, pItem);
}
}
}
//hmmm
BOOL CSuperGridCtrl::DoDragDrop(CTreeItem* pTarget, CTreeItem* pSource)
{
if(pTarget==NULL)
return 0;
BOOL bUpdate=FALSE;
if(!IsCollapsed(pTarget))
bUpdate=TRUE; //children are expanded, want to see update right away
//make a copy of the source data
CItemInfo* lp = CopyData(GetData(pSource));
//create new node with the source data and make pTarget the parent
CTreeItem* pNewParent = InsertItem(pTarget, lp, bUpdate);
//if the source has children copy all source data and make the newly create item the parent
if(ItemHasChildren(pSource))
CopyChildren(pNewParent, pSource);
return 1;
}
void CSuperGridCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
//its not meself
if( GetFocus() != this)
SetFocus();
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CSuperGridCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if( GetFocus() != this)
SetFocus();
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}
BOOL CSuperGridCtrl::OnMouseWheel( UINT nFlags, short zDelta, CPoint pt )
{
if( GetFocus() != this)
SetFocus();
return CListCtrl::OnMouseWheel(nFlags, zDelta, pt);
}
BOOL CSuperGridCtrl::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN)
{
if(GetFocus()==this)
{
switch( pMsg->wParam )
{
case VK_LEFT:
{
// Decrement the order number.
m_CurSubItem--;
if(m_CurSubItem < 0)
m_CurSubItem = 0;
else{
CHeaderCtrl* pHeader = GetHeaderCtrl();
// Make the column visible.
// We have to take into account that the header may be reordered.
MakeColumnVisible( Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem));
// Invalidate the item.
int iItem = GetSelectedItem();
if( iItem != -1 )
{
CRect rcBounds;
GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
InvalidateRect(&rcBounds);
UpdateWindow();
}
}
}
return TRUE;
case VK_RIGHT:
{
// Increment the order number.
m_CurSubItem++;
CHeaderCtrl* pHeader = GetHeaderCtrl();
int nColumnCount = pHeader->GetItemCount();
// Don't go beyond the last column.
if( m_CurSubItem > nColumnCount -1 )
m_CurSubItem = nColumnCount-1;
else
{
MakeColumnVisible(Header_OrderToIndex( pHeader->m_hWnd, m_CurSubItem));
int iItem = GetSelectedItem();
// Invalidate the item.
if( iItem != -1 )
{
CRect rcBounds;
GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
InvalidateRect(&rcBounds);
UpdateWindow();
}
}
}
return TRUE;
case VK_RETURN://edit itemdata
{
if(m_bEditStyle)
{
BOOL bResult = OnVkReturn();
if(!bResult)
{
int iItem = GetSelectedItem();
if( m_CurSubItem != -1 && iItem != -1)
{
CHeaderCtrl* pHeader = GetHeaderCtrl();
int iSubItem = Header_OrderToIndex(pHeader->m_hWnd, m_CurSubItem);
if(iSubItem==0)//that's just me saying all nodes in col 0 are edit-controls, you may modify this
{
CRect rcItem;
GetItemRect(iItem, rcItem, LVIR_LABEL);
DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL|ES_LEFT;
CEdit *pEdit = new CListEditCtrl(iItem, iSubItem, GetItemText(iItem, iSubItem));
pEdit->Create(dwStyle, rcItem, this, 0x1233);
}
else
EditLabelEx(iItem, iSubItem);
return 1;
}
}
}
}
break;
default:
break;
}
}
}
return CListCtrl::PreTranslateMessage(pMsg);
}
#define IDC_EDITCTRL 0x1234
CEdit* CSuperGridCtrl::EditLabelEx(int nItem, int nCol)
{
CRect rect;
int offset = 0;
if(!EnsureVisible(nItem, TRUE))
return NULL;
GetSubItemRect(nItem, nCol, LVIR_BOUNDS, rect);
// Now scroll if we need to expose the column
CRect rcClient;
GetClientRect(rcClient);
if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
{
CSize size(offset + rect.left,0);
Scroll(size);
rect.left -= size.cx;
}
rect.left += offset;
rect.right = rect.left + GetColumnWidth(nCol);
if(rect.right > rcClient.right)
rect.right = rcClient.right;
// Get Column alignment
LV_COLUMN lvcol;
lvcol.mask = LVCF_FMT;
GetColumn(nCol, &lvcol);
DWORD dwStyle;
if((lvcol.fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
dwStyle = ES_LEFT;
else if((lvcol.fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
dwStyle = ES_RIGHT;
else
dwStyle = ES_CENTER;
dwStyle |=WS_BORDER|WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL;
CEdit *pEdit = new CListEditCtrl(nItem, nCol, GetItemText(nItem, nCol));
pEdit->Create(dwStyle, rect, this, IDC_EDITCTRL);
//pEdit->ModifyStyleEx(0,WS_EX_CLIENTEDGE); //funny thing happend here, uncomment this,
//and then edit an item,
//enter a long text so that the ES_AUTOHSCROLL comes to rescue
//yes that's look funny, ???.
return pEdit;
}
BOOL CSuperGridCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO *plvDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM *plvItem = &plvDispInfo->item;
if (plvItem->pszText != NULL)//valid text
{
if(plvItem->iItem != -1) //valid item
{
CTreeItem*pSelItem = GetTreeItem(plvItem->iItem);
if(pSelItem != NULL)
{
OnUpdateListViewItem(pSelItem, plvItem);
}
}
}
*pResult = 1;
return TRUE;
}
int CSuperGridCtrl::GetNumCol()
{
CHeaderCtrl* pHeader = GetHeaderCtrl();
return pHeader ? pHeader->GetItemCount() : 0;
}
//Think Rex Myer is spooking here
void CSuperGridCtrl::MakeColumnVisible(int nCol)
{
if(nCol < 0)
return;
// Get the order array to total the column offset.
CHeaderCtrl* pHeader = GetHeaderCtrl();
int nColCount = pHeader->GetItemCount();
ASSERT( nCol < nColCount);
int *pOrderarray = new int[nColCount];
Header_GetOrderArray(pHeader->m_hWnd, nColCount, pOrderarray);
// Get the column offset
int offset = 0;
for(int i = 0; pOrderarray[i] != nCol; i++)
offset += GetColumnWidth(pOrderarray[i]);
int colwidth = GetColumnWidth(nCol);
delete[] pOrderarray;
CRect rect;
GetItemRect(0, &rect, LVIR_BOUNDS);
// Now scroll if we need to show the column
CRect rcClient;
GetClientRect(&rcClient);
if(offset + rect.left < 0 || offset + colwidth + rect.left > rcClient.right)
{
CSize size(offset + rect.left,0);
Scroll(size);
InvalidateRect(NULL);
UpdateWindow();
}
}
//Think Rex Myer is spooking here
int CSuperGridCtrl::IndexToOrder( int iIndex )
{
// This translates a column index value to a column order value.
CHeaderCtrl* pHeader = GetHeaderCtrl();
int nColCount = pHeader->GetItemCount();
int *pOrderarray = new int[nColCount];
Header_GetOrderArray(pHeader->m_hWnd, nColCount, pOrderarray);
for(int i=0; i<nColCount; i++)
{
if(pOrderarray[i] == iIndex )
{
delete[] pOrderarray;
return i;
}
}
delete[] pOrderarray;
return -1;
}
void CSuperGridCtrl::DrawFocusCell(CDC *pDC, int nItem, int iSubItem)
{
if(iSubItem==m_CurSubItem)
{
CRect rect;
GetSubItemRect(nItem, iSubItem, LVIR_BOUNDS, rect);
CBrush br(GetCellRGB());
if(iSubItem==0)
GetItemRect(iSubItem, rect, LVIR_LABEL);
pDC->FillRect(rect, &br);
pDC->DrawFocusRect(rect);
}
}
//insert item and return new parent pointer.
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::InsertItem(CTreeItem *pParent, CItemInfo* lpInfo, BOOL bUpdate)
{
if(pParent==NULL)
return NULL;
CTreeItem *pItem = NULL;
pItem = new CTreeItem();
if(lpInfo==NULL)
lpInfo = new CItemInfo;
UpdateData(pItem, lpInfo);
SetIndent(pItem, GetIndent(pParent)+1);
SetParentItem(pItem, pParent);
//add as the last child
pParent->m_listChild.AddTail(pItem);
if(!bUpdate)
Hide(pParent, TRUE);
else
{
//calc listview index for the new node
int nIndex = NodeToIndex(pItem);
CString str = GetData(pItem)->GetItemText();
LV_ITEM lvItem;
lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM;
lvItem.pszText = str.GetBuffer(1);
//insert item
lvItem.iItem = nIndex;
lvItem.iSubItem = 0;
lvItem.lParam = (LPARAM)pItem;
lvItem.iIndent = GetIndent(pItem);
CListCtrl::InsertItem(&lvItem);
if(lpInfo->GetCheck())
SetCheck(nIndex);
//Get subitems
int nSize = GetData(pItem)->GetItemCount();
for(int i=0; i < nSize;i++)
{
CString str = GetData(pItem)->GetSubItem(i);
lvItem.mask = LVIF_TEXT;
lvItem.iSubItem = i+1;
lvItem.pszText = str.GetBuffer(1);
SetItem(&lvItem);
}
InternaleUpdateTree();//better do this
}
return pItem;
}
void CSuperGridCtrl::InternaleUpdateTree()
{
int nItems = GetItemCount();
for(int nItem=0; nItem < nItems; nItem++)
{
CTreeItem* pItem = GetTreeItem(nItem);
SetCurIndex(pItem, nItem);
}
}
int CSuperGridCtrl::NodeToIndex(CTreeItem *pNode)
{
int nStartIndex=0;
POSITION pos = m_RootItems.GetHeadPosition();
while(pos!=NULL)
{
CTreeItem * root = (CTreeItem*)m_RootItems.GetNext(pos);
int ret = _NodeToIndex(root, pNode, nStartIndex);
if(ret != -1)
return ret;
}
return -1;
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetRootItem(int nIndex)
{
POSITION pos = m_RootItems.FindIndex(nIndex);
if(pos==NULL)
return NULL;
return (CTreeItem*)m_RootItems.GetAt(pos);
}
int CSuperGridCtrl::GetRootIndex(CTreeItem * root)
{
int nIndex = 0;
POSITION pos = m_RootItems.GetHeadPosition();
while(pos != NULL)
{
CTreeItem * pItem = (CTreeItem*)m_RootItems.GetNext(pos);
if(pItem== root)
return nIndex;
nIndex++;
}
return -1;
}
BOOL CSuperGridCtrl::IsRoot(CTreeItem * lpItem)
{
return m_RootItems.Find(lpItem) != NULL;
}
void CSuperGridCtrl::DeleteRootItem(CTreeItem * root)
{
POSITION pos = m_RootItems.Find(root);
if(pos!=NULL)
{
CTreeItem* pRoot=(CTreeItem*)m_RootItems.GetAt(pos);
if(pRoot->m_lpNodeInfo!=NULL)
DELETE_PTR(pRoot->m_lpNodeInfo);
if (pRoot)
{
delete pRoot;
pRoot = NULL;
}
m_RootItems.RemoveAt(pos);
}
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::InsertRootItem(CItemInfo * lpInfo)
{
if(lpInfo==NULL)
lpInfo = new CItemInfo;
CTreeItem* pRoot = NULL;
pRoot = new CTreeItem();
CleanMe(pRoot);
UpdateData(pRoot, lpInfo);
SetIndent(pRoot, 1);
SetCurIndex(pRoot, GetItemCount());
SetParentItem(pRoot, NULL);
CItemInfo* lp = GetData(pRoot);
LV_ITEM lvItem;
lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM;
CString strItem = lp->GetItemText();
lvItem.pszText = strItem.GetBuffer(1);
lvItem.iItem = GetItemCount();
lvItem.lParam = (LPARAM)pRoot;
lvItem.iIndent = 1;
lvItem.iSubItem = 0;
CListCtrl::InsertItem(&lvItem);
int nSize = lp->GetItemCount();
for(int i=0; i < nSize;i++)
{
CString str = lp->GetSubItem(i);
lvItem.mask = LVIF_TEXT;
lvItem.iSubItem = i+1;
lvItem.pszText = str.GetBuffer(1);
SetItem(&lvItem);
}
m_RootItems.AddTail(pRoot);
return pRoot;
}
void CSuperGridCtrl::DrawTreeItem(CDC* pDC, CTreeItem* pSelItem, int nListItem, const CRect& rcBounds)
{
int nColWidth = GetColumnWidth(0);
int yDown = rcBounds.top;
CPen* pPenTreeLine = pDC->SelectObject(&m_psTreeLine);
int iIndent = GetIndent(pSelItem);
int nHalfImage = (m_cxImage >> 1);
int nBottomDown = yDown + nHalfImage + ((rcBounds.Height() - m_cyImage) >> 1);
//
BOOL bChild = ItemHasChildren(pSelItem);
BOOL bCollapsed = IsCollapsed(pSelItem);
//draw outline
while(1)
{
CTreeItem* pParent = GetParentItem(pSelItem);
if(pParent==NULL)//no more parents, stop
break;
POSITION pos = pParent->m_listChild.GetTailPosition();
while(pos!=NULL)
{
CTreeItem *pLastChild = (CTreeItem*)pParent->m_listChild.GetPrev(pos);
int nIndex = GetCurIndex(pLastChild);
int nCurIndent = GetIndent(pLastChild);
if(nListItem > nIndex && iIndent > nCurIndent)//no need to go further in this loop
break;
//no drawing outside the 1st columns right
int xLine = rcBounds.left + nCurIndent * m_cxImage - nHalfImage;
if(nIndex == nListItem && nCurIndent==iIndent)
{
//draw '-
int x;
pDC->MoveTo(xLine, yDown);
pDC->LineTo(xLine, nBottomDown);
// -
xLine + nHalfImage > nColWidth ? x = nColWidth: x = xLine + nHalfImage;
pDC->MoveTo(xLine, nBottomDown);
pDC->LineTo(x, nBottomDown);
break;
}
else
if(nIndex > nListItem && nCurIndent==iIndent)
{
//draw |-
int x;
xLine + nHalfImage > nColWidth ? x = nColWidth : x = xLine + nHalfImage;
pDC->MoveTo(xLine, nBottomDown);
pDC->LineTo(x, nBottomDown);
//-
pDC->MoveTo(xLine, yDown);
pDC->LineTo(xLine, rcBounds.bottom);
break;
}
else
if(nIndex > nListItem && nCurIndent < iIndent)
{
//draw |
pDC->MoveTo(xLine, yDown);
pDC->LineTo(xLine, rcBounds.bottom);
break;
}
}
pSelItem = pParent;//next
}
//draw plus/minus sign
if(bChild)
{
CRectangle rect(this, pDC, iIndent, rcBounds);
rect.DrawRectangle(this);
CPen* pPenPlusMinus = pDC->SelectObject(&m_psPlusMinus);
if(bCollapsed)
rect.DrawPlus();
else {
rect.DrawMinus();
//draw line up to parent folder
CPen* pLine = pDC->SelectObject(&m_psTreeLine);
int nOffset = (rcBounds.Height() - m_cyImage)/2;
pDC->MoveTo(rect.GetLeft()+ m_cxImage, rcBounds.top + m_cyImage+nOffset);
pDC->LineTo(rect.GetLeft() + m_cxImage, rcBounds.bottom);
pDC->SelectObject(pLine);
}
pDC->SelectObject(pPenPlusMinus);
}
pDC->SelectObject(pPenTreeLine);
}
//walk all over the place setting the hide/show flag of the nodes.
//it also deletes items from the listviewctrl.
void CSuperGridCtrl::HideChildren(CTreeItem *pItem, BOOL bHide,int nItem)
{
if(!IsCollapsed(pItem))
if(ItemHasChildren(pItem))
{
Hide(pItem, bHide);
POSITION pos = pItem->m_listChild.GetHeadPosition();
while (pos != NULL)
{
HideChildren((CTreeItem *)pItem->m_listChild.GetNext(pos),bHide,nItem+1);
DeleteItem(nItem);
}
}
}
void CSuperGridCtrl::Collapse(CTreeItem *pItem)
{
if(pItem != NULL && ItemHasChildren(pItem))
{
SetRedraw(0);
int nIndex = NodeToIndex(pItem);
HideChildren(pItem, TRUE, nIndex+1);
InternaleUpdateTree();
SetRedraw(1);
}
}
void CSuperGridCtrl::ExpandAll(CTreeItem *pItem, int& nScroll)
{
const int nChildren = (int)pItem->m_listChild.GetCount();
if (nChildren > 0)
{
int nIndex = NodeToIndex(pItem);
nScroll = Expand(pItem, nIndex);
}
POSITION pos = pItem->m_listChild.GetHeadPosition();
while (pos)
{
CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
ExpandAll(pChild, nScroll);
}
}
int CSuperGridCtrl::Expand(CTreeItem* pSelItem, int nIndex)
{
if(ItemHasChildren(pSelItem) && IsCollapsed(pSelItem))
{
LV_ITEM lvItem;
lvItem.mask = LVIF_INDENT;
lvItem.iItem = nIndex;
lvItem.iSubItem = 0;
lvItem.lParam=(LPARAM)pSelItem;
lvItem.iIndent = GetIndent(pSelItem);
SetItem(&lvItem);
Hide(pSelItem, FALSE);
//expand children
POSITION pos = pSelItem->m_listChild.GetHeadPosition();
while(pos != NULL)
{
CTreeItem* pNextNode = (CTreeItem*)pSelItem->m_listChild.GetNext(pos);
CString str = GetData(pNextNode)->GetItemText();
LV_ITEM lvItem;
lvItem.mask = LVIF_TEXT | LVIF_INDENT | LVIF_PARAM;
lvItem.pszText =str.GetBuffer(1);
lvItem.iItem = nIndex + 1;
lvItem.iSubItem = 0;
lvItem.lParam=(LPARAM)pNextNode;
lvItem.iIndent = GetIndent(pSelItem)+1;
CListCtrl::InsertItem(&lvItem);
if(GetData(pNextNode)->GetCheck())
SetCheck(nIndex + 1);
//get subitems
int nSize = GetData(pNextNode)->GetItemCount();
for(int i=0; i< nSize;i++)
{
CString str=GetData(pNextNode)->GetSubItem(i);
lvItem.mask = LVIF_TEXT;
lvItem.iSubItem = i+1;
lvItem.pszText=str.GetBuffer(1);
SetItem(&lvItem);
}
nIndex++;
}
}
InternaleUpdateTree();
return nIndex;
}
int CSuperGridCtrl::SelectNode(CTreeItem *pLocateNode)
{
if(IsRoot(pLocateNode))
{
UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
SetItemState(0, uflag, uflag);
return 0;
}
int nSelectedItem=-1;
CTreeItem* pNode = pLocateNode;
CTreeItem* pTopLevelParent=NULL;
//Get top parent
while(1)
{
CTreeItem *pParent = GetParentItem(pLocateNode);
if(IsRoot(pParent))
break;
pLocateNode = pParent;
}
pTopLevelParent = pLocateNode;//on top of all
//Expand the folder
if(pTopLevelParent != NULL)
{
SetRedraw(0);
CWaitCursor wait;
CTreeItem *pRoot = GetParentItem(pTopLevelParent);
if(IsCollapsed(pRoot))
Expand(pRoot,0);
ExpandUntil(pTopLevelParent, pNode);
UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
nSelectedItem = NodeToIndex(pNode);
SetItemState(nSelectedItem, uflag, uflag);
SetRedraw(1);
EnsureVisible(nSelectedItem, TRUE);
}
return nSelectedItem;
}
void CSuperGridCtrl::ExpandUntil(CTreeItem *pItem, CTreeItem* pStopAt)
{
const int nChildren = (int)pItem->m_listChild.GetCount();
if (nChildren > 0)
{
POSITION pos = pItem->m_listChild.GetHeadPosition();
while (pos)
{
CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
if(pChild == pStopAt)
{
int nSize = GetIndent(pChild);
CTreeItem** ppParentArray = new CTreeItem*[nSize];
int i=0;
while(1)
{
CTreeItem *pParent = GetParentItem(pChild);
if(IsRoot(pParent))
break;
pChild = pParent;
ppParentArray[i] = pChild;
i++;
}
for(int x=i; x > 0; x--)
{
CTreeItem *pParent = ppParentArray[x-1];
Expand(pParent, NodeToIndex(pParent));
}
delete [] ppParentArray;
return;
}
}
}
POSITION pos = pItem->m_listChild.GetHeadPosition();
while (pos)
{
CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
ExpandUntil(pChild, pStopAt);
}
}
void CSuperGridCtrl::DeleteItemEx(CTreeItem *pSelItem, int nItem)
{
SetRedraw(0);
DeleteItem(nItem);//delete cur item in listview
//delete/hide all children in pSelItem
HideChildren(pSelItem, TRUE, nItem);
//delete all internal nodes
// If root, must delete from m_rootData
if(GetParentItem(pSelItem) == NULL )
{
DeleteRootItem(pSelItem);
}
else
Delete(pSelItem);
InternaleUpdateTree();
if(nItem-1<0)//no more items in list
{
SetRedraw(1);
InvalidateRect(NULL);
UpdateWindow();
return;
}
UINT uflag = LVIS_SELECTED | LVIS_FOCUSED;
CRect rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem;//just to get the documention right :)
GetItemRect(nItem, rcTestIfItemIsValidToSelectOtherWiseSubtrackOneFromItem ,LVIR_LABEL) ? SetItemState(nItem, uflag, uflag) : SetItemState(nItem-1, uflag, uflag);
SetRedraw(1);
InvalidateRect(NULL);
UpdateWindow();
}
void CSuperGridCtrl::CleanMe(CTreeItem *pItem)
{
// delete child nodes
POSITION pos = pItem->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pItemData = (CTreeItem*)pItem->m_listChild.GetNext(pos);
if(pItemData!=NULL)
{
if(pItemData->m_lpNodeInfo!=NULL)
DELETE_PTR(pItemData->m_lpNodeInfo);
pItemData->m_listChild.RemoveAll();
delete(pItemData);
}
}
pItem->m_listChild.RemoveAll();
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetNext(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden)
{
static BOOL bFound;
if (bInit)
bFound = FALSE;
if (pNode == pStartAt)
bFound = TRUE;
if(bDontIncludeHidden)
{
if (!IsCollapsed(pStartAt))
{
POSITION pos = pStartAt->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
if (bFound)
return pChild;
pChild = GetNext(pChild, pNode, FALSE, TRUE);
if (pChild != NULL)
return pChild;
}
}
}
else {
POSITION pos = pStartAt->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
if (bFound)
return pChild;
pChild = GetNext(pChild, pNode, FALSE,FALSE);
if (pChild != NULL)
return pChild;
}
}
// if reached top and last level return original
if (bInit)
return pNode;
else
return NULL;
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetPrev(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bInit, BOOL bDontIncludeHidden)
{
static CTreeItem* pPrev;
if (bInit)
pPrev = pStartAt;
if (pNode == pStartAt)
return pPrev;
pPrev = pStartAt;
if(bDontIncludeHidden)
{
if (!IsCollapsed(pStartAt))
{
POSITION pos = pStartAt->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pCur = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
CTreeItem* pChild = GetPrev(pCur,pNode, FALSE,TRUE);
if (pChild != NULL)
return pChild;
}
}
}
else {
POSITION pos = pStartAt->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pCur = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
CTreeItem* pChild = GetPrev(pCur,pNode, FALSE,FALSE);
if (pChild != NULL)
return pChild;
}
}
if (bInit)
return pPrev;
else
return NULL;
}
int CSuperGridCtrl::_NodeToIndex(CTreeItem *pStartpos, CTreeItem* pNode, int& nIndex, BOOL binit)
{
static BOOL bFound = FALSE;
// Account for other root nodes
if(GetParentItem(pStartpos) == NULL && GetRootIndex(pStartpos) !=0)
nIndex++;
if(binit)
bFound=FALSE;
if(pStartpos==pNode)
bFound=TRUE;
if(!IsCollapsed(pStartpos))
{
POSITION pos = GetHeadPosition(pStartpos);
while (pos)
{
CTreeItem *pChild = GetNextChild(pStartpos, pos);
if(bFound)
return nIndex;
// Craig Schmidt: Cannot set nIndex as return value. Worked find with single root but
// the calling function get confused since the return value may indicate
// that the next root needs to be searched. Didn'd spend much time on
// this so there is probably a better way of doing this.
// nIndex = _NodeToIndex(pChild, pNode, nIndex, binit);
_NodeToIndex(pChild, pNode, nIndex, binit);
nIndex++;
}
}
if(binit && bFound)
return nIndex;
else
return -1;
}
BOOL CSuperGridCtrl::Delete(CTreeItem* pNode, BOOL bClean)
{
POSITION pos = m_RootItems.GetHeadPosition();
while(pos!=NULL)
{
CTreeItem * pRoot = (CTreeItem*)m_RootItems.GetNext(pos);
if(_Delete(pRoot, pNode, bClean))
return TRUE;
}
return FALSE;
}
BOOL CSuperGridCtrl::_Delete(CTreeItem* pStartAt, CTreeItem* pNode, BOOL bClean)
{
POSITION pos = pStartAt->m_listChild.GetHeadPosition();
while (pos != NULL)
{
POSITION posPrev = pos;
CTreeItem *pChild = (CTreeItem*)pStartAt->m_listChild.GetNext(pos);
if (pChild == pNode)
{
pStartAt->m_listChild.RemoveAt(posPrev);
if(bClean)
{
if(GetData(pNode)!=NULL)
delete GetData(pNode);
delete pNode;
}
return TRUE;
}
if (_Delete(pChild, pNode) == TRUE)
return TRUE;
}
return FALSE;
}
BOOL CSuperGridCtrl::IsChildOf(const CTreeItem* pParent, const CTreeItem* pChild) const
{
if (pChild == pParent)
return TRUE;
POSITION pos = pParent->m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pNode = (CTreeItem*)pParent->m_listChild.GetNext(pos);
if (IsChildOf(pNode, pChild))
return TRUE;
}
return FALSE;
}
void CSuperGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
if( GetFocus() != this)
SetFocus();
LVHITTESTINFO ht;
ht.pt = point;
SubItemHitTest(&ht);
if(OnItemLButtonDown(ht))
{
BOOL bSelect=1;
bSelect = HitTestOnSign(point, ht);
if(bSelect && ht.iItem!=-1)
{
m_CurSubItem = IndexToOrder(ht.iSubItem);
CHeaderCtrl* pHeader = GetHeaderCtrl();
// Make the column fully visible.
MakeColumnVisible(Header_OrderToIndex(pHeader->m_hWnd, m_CurSubItem));
CListCtrl::OnLButtonDown(nFlags, point);
if(m_bEditStyle)
{
OnControlLButtonDown(nFlags, point, ht);
}
//update row anyway for selection bar
CRect rc;
GetItemRect(ht.iItem, rc, LVIR_BOUNDS);
InvalidateRect(rc);
UpdateWindow();
CWnd* pParent = GetParent();
if (pParent != NULL)
{
CPoint* pPt = new CPoint(ht.iItem,ht.iSubItem);
pParent->PostMessage(WM_ITEM_SEL,(WPARAM)m_hWnd,(LPARAM)pPt);
}
}
}
}
void CSuperGridCtrl::OnUpdateListViewItem(CTreeItem* lpItem, LV_ITEM *plvItem)
{
//default implementation you would go for this 9 out of 10 times
CItemInfo *lp = GetData(lpItem);
CString str = (CString)plvItem->pszText;
if(lp!=NULL)
{
if(plvItem->iSubItem==0)
lp->SetItemText(str);
else //subitem data
lp->SetSubItemText(plvItem->iSubItem-1, str);
UpdateData(lpItem, lp);
}
SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
}
void CSuperGridCtrl::DeleteAll()
{
POSITION pos = m_RootItems.GetHeadPosition();
while(pos!=NULL)
{
CTreeItem * pRoot = (CTreeItem*)m_RootItems.GetNext(pos);
if(pRoot!=NULL)
DeleteItemEx(pRoot, 0);
}
}
POSITION CSuperGridCtrl::GetRootHeadPosition() const
{
return m_RootItems.GetHeadPosition();
}
POSITION CSuperGridCtrl::GetRootTailPosition() const
{
return m_RootItems.GetTailPosition();
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetNextRoot(POSITION& pos) const
{
return (CTreeItem*)m_RootItems.GetNext(pos);
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetPrevRoot(POSITION& pos) const
{
return (CTreeItem*)m_RootItems.GetNext(pos);
}
POSITION CSuperGridCtrl::GetHeadPosition(CTreeItem* pItem) const
{
return pItem->m_listChild.GetHeadPosition();
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetNextChild(CTreeItem *pItem, POSITION& pos) const
{
return (CTreeItem*)pItem->m_listChild.GetNext(pos);
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetPrevChild(CTreeItem *pItem, POSITION& pos) const
{
return (CTreeItem*)pItem->m_listChild.GetPrev(pos);
}
POSITION CSuperGridCtrl::GetTailPosition(CTreeItem *pItem) const
{
return pItem->m_listChild.GetTailPosition();
}
void CSuperGridCtrl::AddTail(CTreeItem *pParent, CTreeItem *pChild)
{
pParent->m_listChild.AddTail(pChild);
}
inline int StrComp(const CString* pElement1, const CString* pElement2)
{
return pElement1->Compare(*pElement2);
}
int CSuperGridCtrl::CompareChildren(const void* p1, const void* p2)
{
CTreeItem * pChild1 = *(CTreeItem**)p1;
CTreeItem * pChild2 = *((CTreeItem**)p2);
CItemInfo *pItem1=(*pChild1).m_lpNodeInfo;
CItemInfo *pItem2=(*pChild2).m_lpNodeInfo;
return StrComp(&(pItem1->GetItemText()), &(pItem2->GetItemText()));
}
void CSuperGridCtrl::Sort(CTreeItem* pParent, BOOL bSortChildren)
{
const int nChildren = NumChildren(pParent);
if (nChildren > 1)
{
CTreeItem** ppSortArray = new CTreeItem*[nChildren];
// Fill in array with pointers to our children.
POSITION pos = pParent->m_listChild.GetHeadPosition();
for (int i=0; pos; i++)
{
ASSERT(i < nChildren);
ppSortArray[i] = (CTreeItem*)pParent->m_listChild.GetAt(pos);
pParent->m_listChild.GetNext(pos);
}
qsort(ppSortArray, nChildren, sizeof(CTreeItem*), CompareChildren);
// reorg children with new sorted list
pos = pParent->m_listChild.GetHeadPosition();
for (i=0; pos; i++)
{
ASSERT(i < nChildren);
pParent->m_listChild.SetAt(pos, ppSortArray[i]);
pParent->m_listChild.GetNext(pos);
}
delete [] ppSortArray;
}
if(bSortChildren)
{
POSITION pos = pParent->m_listChild.GetHeadPosition();
while (pos)
{
CTreeItem *pChild = (CTreeItem*)pParent->m_listChild.GetNext(pos);
Sort(pChild, TRUE);
}
}
}
int CSuperGridCtrl::NumChildren(const CTreeItem *pItem) const
{
return (int)pItem->m_listChild.GetCount();
}
BOOL CSuperGridCtrl::ItemHasChildren(const CTreeItem* pItem) const
{
BOOL bChildren = pItem->m_listChild.GetCount() != 0;
//see if we have a flag
int nFlag = pItem->m_bSetChildFlag;
if(nFlag!=-1)
return 1;
else
return bChildren;
}
void CSuperGridCtrl::SetChildrenFlag(CTreeItem *pItem, int nFlag) const
{
pItem->m_bSetChildFlag = nFlag;
}
BOOL CSuperGridCtrl::IsCollapsed(const CTreeItem* pItem) const
{
return pItem->m_bHideChildren;//e.g not visible
}
void CSuperGridCtrl::Hide(CTreeItem* pItem, BOOL bFlag)
{
pItem->m_bHideChildren=bFlag;
}
int CSuperGridCtrl::GetIndent(const CTreeItem* pItem) const
{
return pItem->m_nIndent;
}
void CSuperGridCtrl::SetIndent(CTreeItem *pItem, int iIndent)
{
pItem->m_nIndent = iIndent;
}
int CSuperGridCtrl::GetCurIndex(const CTreeItem *pItem) const
{
return pItem->m_nIndex;
}
void CSuperGridCtrl::SetCurIndex(CTreeItem* pItem, int nIndex)
{
pItem->m_nIndex = nIndex;
}
void CSuperGridCtrl::SetParentItem(CTreeItem*pItem, CTreeItem* pParent)
{
pItem->m_pParent=pParent;
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetParentItem(const CTreeItem* pItem)
{
return pItem->m_pParent;
};
CItemInfo* CSuperGridCtrl::GetData(const CTreeItem* pItem)
{
return pItem->m_lpNodeInfo;
}
void CSuperGridCtrl::UpdateData(CTreeItem* pItem, CItemInfo* lpInfo)
{
pItem->m_lpNodeInfo = lpInfo;
}
//overrides
CItemInfo* CSuperGridCtrl::CopyData(CItemInfo* lpSrc)
{
ASSERT(FALSE);//debug
return NULL; //release
}
//default implementation for setting icons
int CSuperGridCtrl::GetIcon(const CTreeItem* pItem)
{
int n = GetData(pItem)->GetImage();
if(n!=-1)
return n;
return 0;
}
void CSuperGridCtrl::OnControlLButtonDown(UINT nFlags, CPoint point, LVHITTESTINFO& ht)
{
CTreeItem* pSelItem = GetTreeItem(ht.iItem);
if(ht.iSubItem == 0)
{
POSITION pos = m_listReadOnly.Find(ht.iSubItem);
if(pos == NULL)
{
if(pSelItem->m_bCanEditMe)
{
CRect rcItem;
GetItemRect(ht.iItem, rcItem, LVIR_LABEL);
DWORD dwStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL|ES_LEFT;
CEdit *pEdit = new CListEditCtrl(ht.iItem, ht.iSubItem, GetItemText(ht.iItem, ht.iSubItem));
pEdit->Create(dwStyle, rcItem, this, 0x1233);
}
}
}
else
{
POSITION pos = m_listReadOnly.Find(ht.iSubItem);
if(pos == NULL)
{
if(pSelItem->m_bCanEditMe)
{
EditLabelEx(ht.iItem, ht.iSubItem);
}
}
}
}
COLORREF CSuperGridCtrl::GetCellRGB()
{
return m_dwCellRGB;
}
BOOL CSuperGridCtrl::OnVKMultiply(CTreeItem *pItem, int nIndex)
{
return 1;
}
BOOL CSuperGridCtrl::OnVkSubTract(CTreeItem *pItem, int nIndex)
{
return 1;
}
BOOL CSuperGridCtrl::OnVKAdd(CTreeItem *pItem, int nIndex)
{
return 1;
}
BOOL CSuperGridCtrl::OnDeleteItem(CTreeItem* pItem, int nIndex)
{
return 1;
}
BOOL CSuperGridCtrl::OnItemExpanding(CTreeItem *pItem, int iItem)
{
return 1;
}
BOOL CSuperGridCtrl::OnItemExpanded(CTreeItem* pItem, int iItem)
{
return 1;
}
BOOL CSuperGridCtrl::OnCollapsing(CTreeItem *pItem)
{
return 1;
}
BOOL CSuperGridCtrl::OnItemCollapsed(CTreeItem *pItem)
{
return 1;
}
BOOL CSuperGridCtrl::OnItemLButtonDown(LVHITTESTINFO& ht)
{
return 1;
}
BOOL CSuperGridCtrl::OnVkReturn(void)
{
return 0;
}
void CSuperGridCtrl::OnSysColorChange()
{
CListCtrl::OnSysColorChange();
//nop nothing yet
}
UINT CSuperGridCtrl::_GetCount(CTreeItem* pItem, UINT& nCount)
{
POSITION pos = pItem->m_listChild.GetHeadPosition();
while (pos)
{
CTreeItem *pChild = (CTreeItem*)pItem->m_listChild.GetNext(pos);
nCount = _GetCount(pChild, nCount);
nCount++;
}
return nCount;
}
UINT CSuperGridCtrl::GetCount(void)
{
UINT nCount=0;
UINT _nCount=0;
POSITION pos = m_RootItems.GetHeadPosition();
while(pos!=NULL)
{
CTreeItem * pRoot = (CTreeItem*)m_RootItems.GetNext(pos);
nCount += _GetCount(pRoot, _nCount) + 1;
}
return nCount;
}
/*CSuperGridCtrl::*/CTreeItem* CSuperGridCtrl::GetTreeItem(int nIndex /*nIndex must be valid of course*/ )
{
return reinterpret_cast<CTreeItem*>(GetItemData(nIndex));
}
int CSuperGridCtrl::GetSelectedItem(void) const
{
return GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
}
//////////////////////////////////////////////////////////////////////////
//
// not much but ...
//
//////////////////////////////////////////////////////////////////////////
/*CSuperGridCtrl::*/CTreeItem::~CTreeItem()
{
// delete child nodes
POSITION pos = m_listChild.GetHeadPosition();
while (pos != NULL)
{
CTreeItem* pItem = (CTreeItem*)m_listChild.GetNext(pos);
if(pItem!=NULL)
{
if(pItem->m_lpNodeInfo!=NULL)
DELETE_PTR(pItem->m_lpNodeInfo);
delete pItem;
}
}
m_listChild.RemoveAll();
}
//////////////////////////////////////////////////////////////////////////
//
// Simple class CRectangle for the + - sign,
//
//////////////////////////////////////////////////////////////////////////
CRectangle::CRectangle(CSuperGridCtrl* pCtrl, CDC* pDC, int iIndent, const CRect& rcBounds)
{
m_pDC=pDC;
int nHalfImage = (pCtrl->m_cxImage >> 1);
int nBottomDown = rcBounds.top + nHalfImage + ((rcBounds.Height() - pCtrl->m_cyImage) >> 1);
m_right_bottom.cx = (pCtrl->m_cxImage>>1)+2+1;
m_right_bottom.cy = (pCtrl->m_cyImage>>1)+2+1;
m_left = rcBounds.left + iIndent * pCtrl->m_cxImage - nHalfImage;
m_top = nBottomDown - (m_right_bottom.cy >> 1);
m_left_top.x = m_left - (m_right_bottom.cx >> 1);
m_left_top.y = m_top;
m_topdown = nBottomDown;
}
void CRectangle::DrawRectangle(CSuperGridCtrl* pCtrl)
{
//erase bkgrnd
CRect rc(m_left_top, m_right_bottom);
m_pDC->FillRect(rc, &pCtrl->m_brushErase);
//draw rectangle
CPen* pPenRectangle = m_pDC->SelectObject(&pCtrl->m_psRectangle);
m_pDC->Rectangle(rc);
m_pDC->SelectObject(pPenRectangle);
}
CRectangle::~CRectangle()
{
}
BOOL CRectangle::HitTest(CPoint pt)
{
CRect rc = GetHitTestRect();
return rc.PtInRect(pt);
}
void CRectangle::DrawPlus(void)
{
double dScale = CoreTools::GetDPIScale();
m_pDC->MoveTo(m_left, m_topdown-2 * dScale);
m_pDC->LineTo(m_left, m_topdown+3 * dScale) ;
m_pDC->MoveTo(m_left-2 * dScale, m_topdown);
m_pDC->LineTo(m_left+3 * dScale, m_topdown);
}
void CRectangle::DrawMinus(void)
{
double dScale = CoreTools::GetDPIScale();
m_pDC->MoveTo(m_left-2 * dScale, m_topdown);
m_pDC->LineTo(m_left+3 * dScale, m_topdown);
}
bool CSuperGridCtrl::PtHitCheckBox(const CPoint &pt)
{
bool bHasCheckBox(GetExtendedStyle() & LVS_EX_CHECKBOXES);
if (!bHasCheckBox) return false;
LVHITTESTINFO ht;
ht.pt = pt;
SubItemHitTest(&ht);
CTreeItem *pItem = GetTreeItem(ht.iItem);
int left = (GetIndent(pItem) * m_cxImage) + m_cxImage;
int right = left + m_cxImage;
if (pt.x >= left && pt.x <= right)
return TRUE;
return FALSE;
}