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

725 lines
14 KiB
C++

// CPropList.cpp : implementation file
//
// Copyright (C) 1998-2001 Scott Ramsay
// sramsay@gonavi.com
// http://www.gonavi.com
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// If you use this code, drop me an email. I'd like to know if you find the code
// useful.
#include "stdafx.h"
#include "Resource.h"
#include "PropCtrl.h"
#include "PropList.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// move to CPropCtrl.h
// #define PROPTREEITEM_EXPANDCOLUMN 16 // width of the expand column
// #define PROPTREEITEM_COLRNG 1 // width of splitter
// #define PROPTREEITEM_DEFHEIGHT 21 // default heigt of an item
/////////////////////////////////////////////////////////////////////////////
// CPropList
CPropList::CPropList() :
m_pProp(NULL),
m_BackBufferSize(0,0),
m_bColDrag(FALSE),
m_nPrevCol(0),
m_pBt(NULL),
m_pSpinCtrl(NULL),
m_bVScrolBar(TRUE)
{
}
CPropList::~CPropList()
{
if (NULL != m_pBt)
{
delete m_pBt;
m_pBt = NULL;
}
if (NULL != m_pSpinCtrl)
{
delete m_pSpinCtrl;
m_pSpinCtrl = NULL;
}
}
BEGIN_MESSAGE_MAP(CPropList, CWnd)
//{{AFX_MSG_MAP(CPropList)
ON_WM_SIZE()
ON_WM_PAINT()
ON_WM_SETCURSOR()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_MOUSEMOVE()
ON_WM_MOUSEWHEEL()
ON_WM_KEYDOWN()
ON_WM_GETDLGCODE()
ON_BN_CLICKED(IDC_BUTTON, OnButtonClick)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINCTRL, OnOnDeltaposSpinCtrl)
ON_WM_HSCROLL()
ON_WM_VSCROLL()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPropList message handlers
void CPropList::SetPropOwner(CPropCtrl* pProp)
{
m_pProp = pProp;
}
BOOL CPropList::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
CWnd* pWnd = this;
LPCTSTR pszCreateClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW));
return pWnd->Create(pszCreateClass, _T(""), dwStyle, rect, pParentWnd, nID);
}
void CPropList::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
RecreateBackBuffer(cx, cy);
if (m_pProp)
{
UpdateResize();
Invalidate();
UpdateWindow();
// inform all items that a resize has been made
m_pProp->UpdateMoveAllItems();
}
}
void CPropList::RecreateBackBuffer(int cx, int cy)
{
if (m_BackBufferSize.cx<cx || m_BackBufferSize.cy<cy)
{
m_BackBufferSize = CSize(cx, cy);
CWindowDC dc(NULL);
int nPlanes = dc.GetDeviceCaps(PLANES);
int nBitCount = dc.GetDeviceCaps(BITSPIXEL);
m_BackBuffer.DeleteObject();
m_BackBuffer.CreateBitmap(cx, cy, nPlanes, nBitCount, NULL);
}
}
void CPropList::UpdateResize()
{
if (m_bVScrolBar)
{
SCROLLINFO si;
LONG nHeight;
CRect rc;
ASSERT(m_pProp!=NULL);
GetClientRect(rc);
nHeight = rc.Height() + 1;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE|SIF_PAGE;
si.nMin = 0;
si.nMax = m_pProp->GetRootItem()->GetTotalHeight();
si.nPage = nHeight;
if ((int)si.nPage>si.nMax)
m_pProp->SetOriginOffset(0);
SetScrollInfo(SB_VERT, &si, TRUE);
}
else
{
ShowScrollBar(SB_VERT, FALSE);
}
// force set column for clipping
m_pProp->SetColumn(m_pProp->GetColumn());
}
void CPropList::OnPaint()
{
CPaintDC dc(this);
CDC memdc;
CBitmap* pOldBitmap;
ASSERT(m_pProp!=NULL);
m_pProp->ClearVisibleList();
memdc.CreateCompatibleDC(&dc);
pOldBitmap = memdc.SelectObject(&m_BackBuffer);
CRect rc;
GetClientRect(rc);
// draw control background
memdc.SelectObject(GetSysColorBrush(COLOR_BTNFACE));
memdc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
// draw control inside fill color
rc.DeflateRect(2,2);
memdc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), m_pProp->IsWindowEnabled() ? WHITENESS : PATCOPY);
rc.InflateRect(2,2);
// draw expand column
memdc.SelectObject(GetSysColorBrush(COLOR_BTNFACE));
memdc.PatBlt(0, 0, PROPTREEITEM_EXPANDCOLUMN, rc.Height(), PATCOPY);
// draw edge
memdc.DrawEdge(&rc, BDR_SUNKENOUTER, BF_RECT);
CPropItem* pItem;
LONG nTotal = 0;
ASSERT(m_pProp->GetRootItem()!=NULL);
rc.DeflateRect(2,2);
// create clip region
HRGN hRgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
SelectClipRgn(memdc.m_hDC, hRgn);
// draw all items
for (pItem = m_pProp->GetRootItem()->GetChild(); pItem; pItem = pItem->GetSibling())
{
LONG nHeight = pItem->DrawItem(&memdc, rc, 0, nTotal);
nTotal += nHeight;
}
// remove clip region
SelectClipRgn(memdc.m_hDC, NULL);
DeleteObject(hRgn);
// copy back buffer to the display
dc.GetClipBox(&rc);
dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memdc, rc.left, rc.top, SRCCOPY);
memdc.DeleteDC();
}
BOOL CPropList::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (nHitTest==HTCLIENT)
{
CPoint pt;
ASSERT(m_pProp!=NULL);
GetCursorPos(&pt);
ScreenToClient(&pt);
switch (m_pProp->HitTest(pt))
{
case HTCOLUMN:
SetCursor(LoadCursor(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_SPLITTER)));
return TRUE;
case HTCHECKBOX:
case HTEXPAND:
SetCursor(LoadCursor(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_FPOINT)));
return TRUE;
}
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CPropList::OnLButtonDown(UINT, CPoint point)
{
ShowButton(FALSE);
ShowSpinCtrl(FALSE);
ASSERT(m_pProp!=NULL);
if (m_pProp->IsDisableInput())
return;
m_pProp->SendNotify(NM_CLICK);
if (!m_pProp->IsWindowEnabled())
return;
SetFocus();
LONG nHit = m_pProp->HitTest(point);
CPropItem* pItem;
CRect rc;
CDC* pDC;
switch (nHit)
{
case HTCOLUMN:
if (m_pProp->SendNotify(PTN_COLUMNCLICK))
break;
m_bColDrag = TRUE;
SetCapture();
m_nPrevCol = m_pProp->GetOrigin().x;
// paint drag line
pDC = GetDC();
GetClientRect(rc);
pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
ReleaseDC(pDC);
break;
case HTCHECKBOX:
if ((pItem = m_pProp->FindItem(point))!=NULL)
{
pItem->Check(!pItem->IsChecked());
m_pProp->SendNotify(PTN_CHECKCLICK, pItem);
Invalidate();
}
break;
case HTEXPAND:
if ((pItem = m_pProp->FindItem(point))!=NULL)
{
if (pItem->GetChild() && !m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
{
pItem->Expand(!pItem->IsExpanded());
UpdateResize();
Invalidate();
UpdateWindow();
CheckVisibleFocus();
}
}
break;
// case HTBUTTON:
// if ((pItem = m_pProp->FindItem(point))!=NULL)
// {
// pItem->MyButtonClick();
// }
// break;
default:
if ((pItem = m_pProp->FindItem(point))!=NULL)
{
CPropItem* pOldFocus = m_pProp->GetFocusedItem();
m_pProp->SelectItems(NULL, FALSE);
m_pProp->SetFocusedItem(pItem);
pItem->Select();
Invalidate();
if (pItem!=pOldFocus)
m_pProp->SendNotify(PTN_SELCHANGE, pItem);
if (nHit==HTATTRIBUTE && !pItem->IsRootLevel())
{
if (!m_pProp->SendNotify(PTN_PROPCLICK, pItem) && !pItem->IsReadOnly())
pItem->Activate();
}
}
else
{
m_pProp->SelectItems(NULL, FALSE);
m_pProp->SetFocusedItem(NULL);
m_pProp->SendNotify(PTN_SELCHANGE);
Invalidate();
}
break;
}
}
void CPropList::OnLButtonUp(UINT, CPoint point)
{
if (m_bColDrag)
{
CDC* pDC = GetDC();
CRect rc;
GetClientRect(rc);
pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
ReleaseDC(pDC);
m_bColDrag = FALSE;
ReleaseCapture();
m_pProp->SetColumn(point.x);
m_pProp->UpdateMoveAllItems();
Invalidate();
}
}
void CPropList::OnLButtonDblClk(UINT, CPoint point)
{
ASSERT(m_pProp!=NULL);
m_pProp->SendNotify(NM_DBLCLK);
CPropItem* pItem;
CPropItem* pOldFocus;
if ((pItem = m_pProp->FindItem(point))!=NULL && pItem->GetChild())
{
switch (m_pProp->HitTest(point))
{
case HTCOLUMN:
break;
case HTCHECKBOX:
pItem->Check(!pItem->IsChecked());
m_pProp->SendNotify(PTN_CHECKCLICK, pItem);
Invalidate();
break;
case HTATTRIBUTE:
if (!pItem->IsRootLevel())
break;
// pass thru to default
default:
pOldFocus = m_pProp->GetFocusedItem();
m_pProp->SelectItems(NULL, FALSE);
m_pProp->SetFocusedItem(pItem);
pItem->Select();
if (pItem!=pOldFocus)
m_pProp->SendNotify(PTN_SELCHANGE, pItem);
// pass thru to HTEXPAND
case HTEXPAND:
if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
{
pItem->Expand(!pItem->IsExpanded());
UpdateResize();
Invalidate();
UpdateWindow();
CheckVisibleFocus();
}
break;
}
}
}
void CPropList::OnMouseMove(UINT, CPoint point)
{
if (m_bColDrag)
{
CDC* pDC = GetDC();
CRect rc;
GetClientRect(rc);
pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
pDC->PatBlt(point.x - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
m_nPrevCol = point.x;
ReleaseDC(pDC);
}
}
BOOL CPropList::OnMouseWheel(UINT, short zDelta, CPoint)
{
SCROLLINFO si;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE;
GetScrollInfo(SB_VERT, &si);
CRect rc;
GetClientRect(rc);
if (si.nMax - si.nMin < rc.Height())
return TRUE;
SetFocus();
OnVScroll(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0, NULL);
return TRUE;
}
void CPropList::OnKeyDown(UINT nChar, UINT, UINT)
{
CPropItem* pItem;
ASSERT(m_pProp!=NULL);
if (m_pProp->IsDisableInput() || !m_pProp->IsWindowEnabled())
return;
switch (nChar)
{
case VK_RETURN:
if ((pItem = m_pProp->GetFocusedItem())!=NULL && !pItem->IsRootLevel() && !pItem->IsReadOnly())
{
pItem->Activate();
}
break;
case VK_HOME:
if (m_pProp->FocusFirst())
Invalidate();
break;
case VK_END:
if (m_pProp->FocusLast())
Invalidate();
break;
case VK_LEFT:
if ((pItem = m_pProp->GetFocusedItem())!=NULL)
{
if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
{
if (pItem->GetChild() && pItem->IsExpanded())
{
pItem->Expand(FALSE);
UpdateResize();
Invalidate();
UpdateWindow();
CheckVisibleFocus();
break;
}
}
}
else
break;
// pass thru to next case VK_UP
case VK_UP:
if (m_pProp->FocusPrev())
Invalidate();
break;
case VK_RIGHT:
if ((pItem = m_pProp->GetFocusedItem())!=NULL)
{
if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
{
if (pItem->GetChild() && !pItem->IsExpanded())
{
pItem->Expand();
UpdateResize();
Invalidate();
UpdateWindow();
CheckVisibleFocus();
break;
}
}
}
else
break;
// pass thru to next case VK_DOWN
case VK_DOWN:
if (m_pProp->FocusNext())
Invalidate();
break;
}
}
UINT CPropList::OnGetDlgCode()
{
return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_WANTALLKEYS;
}
void CPropList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*)
{
SCROLLINFO si;
CRect rc;
LONG nHeight;
SetFocus();
GetClientRect(rc);
nHeight = rc.Height() + 1;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE;
GetScrollInfo(SB_VERT, &si);
LONG ny = m_pProp->GetOrigin().y;
switch (nSBCode)
{
case SB_LINEDOWN:
ny += PROPTREEITEM_DEFHEIGHT;
break;
case SB_LINEUP:
ny -= PROPTREEITEM_DEFHEIGHT;
break;
case SB_PAGEDOWN:
ny += nHeight;
break;
case SB_PAGEUP:
ny -= nHeight;
break;
case SB_THUMBTRACK:
ny = nPos;
break;
}
ny = __min(__max(ny, si.nMin), si.nMax - nHeight);
m_pProp->SetOriginOffset(ny);
si.fMask = SIF_POS;
si.nPos = ny;
SetScrollInfo(SB_VERT, &si, TRUE);
ShowButton(FALSE);
ShowSpinCtrl(FALSE);
Invalidate();
}
void CPropList::CheckVisibleFocus()
{
ASSERT(m_pProp!=NULL);
CPropItem* pItem;
if ((pItem = m_pProp->GetFocusedItem())==NULL)
return;
if (!m_pProp->IsItemVisible(pItem))
{
if (m_pProp->IsSingleSelection())
pItem->Select(FALSE);
m_pProp->SetFocusedItem(NULL);
m_pProp->SendNotify(PTN_SELCHANGE, NULL);
Invalidate();
}
}
/*----------------------------------------------------------------------------*
* 描述: 把右侧按钮事件,发送消息给父窗口(一般为控件所在对话框)
* 备注:
-----------------------------------------------------------------------------*/
void CPropList::OnButtonClick()
{
if (NULL == m_pProp || m_pBt == NULL)
return;
CRect rect;
CPoint pt;
m_pBt->GetWindowRect(rect);
ScreenToClient(rect);
pt.x = (rect.left + rect.right) / 2;
pt.y = (rect.top + rect.bottom) / 2;
CPropItem* pItem = m_pProp->FindItem(pt);
if (pItem == NULL)
return;
CWnd* pWnd = m_pProp->GetParent();
if (pWnd == NULL)
return;
if (pItem->m_nItemType == ITEMTYPE_EDIT)
::SendMessage(pWnd->m_hWnd, WM_EBTNCLICK,
(WPARAM)ITEMTYPE_EDIT, (LPARAM)(CPropItemEdit*)pItem);
else if (pItem->m_nItemType == ITEMTYPE_COMBOBOX)
::SendMessage(pWnd->m_hWnd, WM_EBTNCLICK,
(WPARAM)ITEMTYPE_COMBOBOX, (LPARAM)(CPropItemCombo*)pItem);
}
void CPropList::OnOnDeltaposSpinCtrl(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
m_pSpinCtrl->ShowWindow(SW_SHOW);
// if (GetDlgItem(IDC_SPINCTRL)->ShowWindow(SW_SHOW))
// {
// MessageBox(_T("当前可见"));
// }
// else
// {
// MessageBox(_T("当前不可见"));
// }
*pResult = 0;
}
void CPropList::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
ShowButton(FALSE);
ShowSpinCtrl(FALSE);
CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CPropList::ShowButton( BOOL bShow /*= TRUE*/ )
{
if (NULL != m_pBt)
{
m_pBt->ShowWindow(bShow ? SW_SHOW:SW_HIDE);
}
}
void CPropList::ShowSpinCtrl(BOOL bShow /* = TRUE */)
{
if (NULL != m_pSpinCtrl)
{
m_pSpinCtrl->ShowWindow(bShow ? SW_SHOW:SW_HIDE);
}
}
void CPropList::ShowVScrolBar( BOOL bShow /*= TRUE*/ )
{
m_bVScrolBar = bShow;
}