Files
envi-code/SourceCode/Code2026/MFCCtrl/PropItem.cpp
T
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

740 lines
14 KiB
C++

// PropTreeItem.cpp
//
// 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 "PropCtrl.h"
#include "PropItem.h"
// move to CPropCtrl.h
// #define PROPTREEITEM_DEFHEIGHT 40 // default heigt of an item
// #define PROPTREEITEM_SPACE 5 // default horz spacing
// #define PROPTREEITEM_EXPANDBOX 9 // size of the expand box
// #define PROPTREEITEM_CHECKBOX 14 // size of the check box
// #define PROPTREEITEM_EXPANDCOLUMN 16 // width of the expand column
// #define PNINDENT 16 // child level indent
#define PROPTREEITEM_EXPANDBOXHALF (PROPTREEITEM_EXPANDBOX/2)
/////////////////////////////////////////////////////////////////////////////
// drawing helper functions
//
// draw a dotted horizontal line
static void _DotHLine(HDC hdc, LONG x, LONG y, LONG w)
{
for (; w>0; w-=2, x+=2)
SetPixel(hdc, x, y, GetSysColor(COLOR_BTNSHADOW));
}
// draw the plus/minus button
static void _DrawExpand(HDC hdc, LONG x, LONG y, BOOL bExpand, BOOL bFill)
{
HPEN hPen;
HPEN oPen;
HBRUSH oBrush;
hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
oPen = (HPEN)SelectObject(hdc, hPen);
oBrush = (HBRUSH)SelectObject(hdc, GetStockObject(bFill ? WHITE_BRUSH : NULL_BRUSH));
Rectangle(hdc, x, y, x + PROPTREEITEM_EXPANDBOX, y + PROPTREEITEM_EXPANDBOX);
SelectObject(hdc, GetStockObject(BLACK_PEN));
if (!bExpand)
{
MoveToEx(hdc, x + PROPTREEITEM_EXPANDBOXHALF, y + 2, NULL);
LineTo(hdc, x + PROPTREEITEM_EXPANDBOXHALF, y + PROPTREEITEM_EXPANDBOX - 2);
}
MoveToEx(hdc, x + 2, y + PROPTREEITEM_EXPANDBOXHALF, NULL);
LineTo(hdc, x + PROPTREEITEM_EXPANDBOX - 2, y + PROPTREEITEM_EXPANDBOXHALF);
SelectObject(hdc, oPen);
SelectObject(hdc, oBrush);
DeleteObject(hPen);
}
/////////////////////////////////////////////////////////////////////////////
// CPropItem
//
CPropItem::CPropItem() :
m_pProp(NULL),
m_sLabel(_T("")),
m_sInfo(_T("")),
m_loc(0,0),
m_rc(0,0,0,0),
m_lParam(0),
m_nCtrlID(0),
m_dwState(0),
m_bActivated(FALSE),
m_bCommitOnce(FALSE),
m_rcExpand(0,0,0,0),
m_rcCheckbox(0,0,0,0),
m_rcButton(0,0,0,0),
m_pParent(NULL),
m_pSibling(NULL),
m_pChild(NULL),
m_pVis(NULL),
m_nItemType(ITEMTYPE_NULL),
m_bHide(FALSE),
m_bHasBt(FALSE),
m_bHasSpinCtrl(FALSE)
{
}
CPropItem::~CPropItem()
{
}
BOOL CPropItem::IsExpanded()
{
return (m_dwState & TreeItemExpanded) ? TRUE : FALSE;
}
BOOL CPropItem::IsSelected()
{
return (m_dwState & TreeItemSelected) ? TRUE : FALSE;
}
BOOL CPropItem::IsChecked()
{
return (m_dwState & TreeItemChecked) ? TRUE : FALSE;
}
BOOL CPropItem::IsReadOnly()
{
return (m_dwState & TreeItemReadOnly) ? TRUE : FALSE;
}
BOOL CPropItem::IsActivated()
{
return (m_dwState & TreeItemActivated) ? TRUE : FALSE;
}
BOOL CPropItem::IsHide()
{
return m_bHide;
}
void CPropItem::Select(BOOL bSelect)
{
if (bSelect)
m_dwState |= TreeItemSelected;
else
m_dwState &= ~TreeItemSelected;
}
void CPropItem::Expand(BOOL bExpand)
{
if (bExpand)
m_dwState |= TreeItemExpanded;
else
m_dwState &= ~TreeItemExpanded;
}
void CPropItem::Check(BOOL bCheck)
{
if (bCheck)
m_dwState |= TreeItemChecked;
else
m_dwState &= ~TreeItemChecked;
}
void CPropItem::ReadOnly(BOOL bReadOnly)
{
if (bReadOnly)
m_dwState |= TreeItemReadOnly;
else
m_dwState &= ~TreeItemReadOnly;
}
void CPropItem::Hide(BOOL bHide)
{
m_bHide = bHide;
}
BOOL CPropItem::IsCheckBox()
{
return (m_dwState & TreeItemCheckbox) ? TRUE : FALSE;
}
void CPropItem::HasCheckBox(BOOL bCheckbox)
{
if (bCheckbox)
m_dwState |= TreeItemCheckbox;
else
m_dwState &= ~TreeItemCheckbox;
}
BOOL CPropItem::HitExpand(const POINT& pt)
{
return m_rcExpand.PtInRect(pt);
}
BOOL CPropItem::HitCheckBox(const POINT& pt)
{
return m_rcCheckbox.PtInRect(pt);
}
BOOL CPropItem::HitButton(const POINT& pt)
{
return m_rcButton.PtInRect(pt);
}
BOOL CPropItem::IsRootLevel()
{
ASSERT(m_pProp!=NULL);
return GetParent() == m_pProp->GetRootItem();
}
LONG CPropItem::GetTotalHeight()
{
CPropItem* pItem;
LONG nHeight;
nHeight = GetHeight();
if (IsExpanded())
{
for (pItem = GetChild(); pItem; pItem = pItem->GetSibling())
nHeight += pItem->GetTotalHeight();
}
return nHeight;
}
void CPropItem::SetLabelText(LPCTSTR sLabel)
{
m_sLabel = sLabel;
}
LPCTSTR CPropItem::GetLabelText()
{
return m_sLabel;
}
void CPropItem::SetInfoText(LPCTSTR sInfo)
{
m_sInfo = sInfo;
}
LPCTSTR CPropItem::GetInfoText()
{
return m_sInfo;
}
void CPropItem::SetCtrlID(UINT nCtrlID)
{
m_nCtrlID = nCtrlID;
}
UINT CPropItem::GetCtrlID()
{
return m_nCtrlID;
}
LONG CPropItem::GetHeight()
{
return PROPTREEITEM_DEFHEIGHT;
}
LPARAM CPropItem::GetItemValue()
{
// no items are assocatied with this type
return 0L;
}
void CPropItem::SetItemValue(LPARAM)
{
// no items are assocatied with this type
}
void CPropItem::OnMove()
{
// no attributes, do nothing
}
void CPropItem::OnRefresh()
{
// no attributes, do nothing
}
void CPropItem::OnCommit()
{
// no attributes, do nothing
}
void CPropItem::Activate()
{
m_bActivated = TRUE;
m_bCommitOnce = FALSE;
OnActivate();
}
void CPropItem::CommitChanges()
{
m_bActivated = FALSE;
if (m_bCommitOnce)
return;
m_bCommitOnce = TRUE;
ASSERT(m_pProp!=NULL);
OnCommit();
m_pProp->SendNotify(PTN_ITEMCHANGED, this);
m_pProp->RefreshItems(this);
}
void CPropItem::OnActivate()
{
// no attributes, do nothing
}
void CPropItem::SetPropOwner(CPropCtrl* pProp)
{
m_pProp = pProp;
}
CPropCtrl* CPropItem::GetPropOwner()
{
return m_pProp;
}
const POINT& CPropItem::GetLocation()
{
return m_loc;
}
CPropItem* CPropItem::GetParent()
{
return m_pParent;
}
CPropItem* CPropItem::GetSibling()
{
return m_pSibling;
}
CPropItem* CPropItem::GetChild()
{
return m_pChild;
}
CPropItem* CPropItem::GetNextVisible()
{
return m_pVis;
}
void CPropItem::SetParent(CPropItem* pParent)
{
m_pParent = pParent;
}
void CPropItem::SetSibling(CPropItem* pSibling)
{
m_pSibling = pSibling;
}
void CPropItem::SetChild(CPropItem* pChild)
{
m_pChild = pChild;
}
void CPropItem::SetNextVisible(CPropItem* pVis)
{
m_pVis = pVis;
}
LONG CPropItem::DrawItem(CDC* pDC, const RECT& rc, LONG x, LONG y)
{
if (m_bHide)
{
return 0L;
}
CPoint pt;
LONG nTotal, nCol, ey;
CRect drc, ir;
ASSERT(m_pProp!=NULL);
// Add TreeItem the list of visble items
m_pProp->AddToVisibleList(this);
// store the item's location
m_loc = CPoint(x, y);
// store the items rectangle position
m_rc.SetRect(m_pProp->GetOrigin().x + PROPTREEITEM_SPACE, m_loc.y, rc.right, m_loc.y + GetHeight()-1);
m_rc.OffsetRect(0, -m_pProp->GetOrigin().y);
// init temp drawing variables
nTotal = GetHeight();
ey = (nTotal >> 1) - (PROPTREEITEM_EXPANDBOX >> 1) - 2;
bool bCheck = false;
// convert item coordinates to screen coordinates
pt = m_loc;
pt.y -= m_pProp->GetOrigin().y;
nCol = m_pProp->GetOrigin().x;
if (IsRootLevel())
drc.SetRect(pt.x + PROPTREEITEM_EXPANDCOLUMN, pt.y, rc.right, pt.y + nTotal);
else
drc.SetRect(pt.x + PROPTREEITEM_EXPANDCOLUMN, pt.y, nCol, pt.y + nTotal);
// root level items are shaded
if (IsRootLevel())
{
HGDIOBJ hOld = pDC->SelectObject(GetSysColorBrush(COLOR_BTNFACE));
pDC->PatBlt(rc.left, drc.top, rc.right - rc.left + 1, drc.Height(), PATCOPY);
pDC->SelectObject(hOld);
}
// calc/draw expand box position
if (GetChild())
{
m_rcExpand.left = PROPTREEITEM_EXPANDCOLUMN/2 - PROPTREEITEM_EXPANDBOXHALF;
m_rcExpand.top = m_loc.y + ey;
m_rcExpand.right = m_rcExpand.left + PROPTREEITEM_EXPANDBOX - 1;
m_rcExpand.bottom = m_rcExpand.top + PROPTREEITEM_EXPANDBOX - 1;
ir = m_rcExpand;
ir.OffsetRect(0, -m_pProp->GetOrigin().y);
_DrawExpand(pDC->m_hDC, ir.left, ir.top, IsExpanded(), !IsRootLevel());
}
else
m_rcExpand.SetRectEmpty();
// calc/draw check box position
if (IsCheckBox())
{
bCheck = true;
ir.left = drc.left + PROPTREEITEM_SPACE;
ir.top = m_loc.y + ey;
ir.right = ir.left + PROPTREEITEM_CHECKBOX;
ir.bottom = ir.top + PROPTREEITEM_CHECKBOX;
m_rcCheckbox = ir;
}
else
m_rcCheckbox.SetRectEmpty();
if (m_bHasBt)
{
m_rcButton = m_rc;
m_rcButton.left = rc.right - BUTTON_WIDTH;
}
if (m_bHasSpinCtrl)
{
m_rcSpinCtrl = m_rc;
m_rcSpinCtrl.left = rc.right - BUTTON_WIDTH;
}
HRGN hRgn = NULL;
// create a clipping region for the label
if (!IsRootLevel())
{
hRgn = CreateRectRgn(drc.left, drc.top, drc.right, drc.bottom);
SelectClipRgn(pDC->m_hDC, hRgn);
}
// calc label position
ir = drc;
ir.left += PROPTREEITEM_SPACE;
// offset the label text if item has a check box
if (bCheck)
OffsetRect(&ir, PROPTREEITEM_CHECKBOX + PROPTREEITEM_SPACE * 2, 0);
// draw label
if (!m_sLabel.IsEmpty())
{
if (IsRootLevel())
pDC->SelectObject(CPropCtrl::GetBoldFont());
else
pDC->SelectObject(CPropCtrl::GetNormalFont());
pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT));
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(m_sLabel, &ir, DT_SINGLELINE|DT_VCENTER|DT_CALCRECT);
// draw the text highlighted if selected
if (IsSelected())
{
HGDIOBJ oPen = pDC->SelectObject(GetStockObject(NULL_PEN));
HGDIOBJ oBrush = pDC->SelectObject(GetSysColorBrush(COLOR_HIGHLIGHT));
CRect dr;
dr = drc;
dr.left = PROPTREEITEM_EXPANDCOLUMN;
pDC->Rectangle(&dr);
pDC->SelectObject(oPen);
pDC->SelectObject(oBrush);
pDC->SetTextColor(GetSysColor(COLOR_BTNHIGHLIGHT));
}
// check if we need to draw the text as disabled
if (!m_pProp->IsWindowEnabled())
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
pDC->DrawText(m_sLabel, &ir, DT_SINGLELINE|DT_VCENTER);
}
// draw check box frame
if (IsCheckBox())
{
ir = m_rcCheckbox;
ir.OffsetRect(0, -m_pProp->GetOrigin().y);
pDC->DrawFrameControl(&ir, DFC_BUTTON, DFCS_BUTTONCHECK | (IsChecked() ? DFCS_CHECKED : 0));
}
// remove clip region
if (hRgn)
{
SelectClipRgn(pDC->m_hDC, NULL);
DeleteObject(hRgn);
}
// draw horzontal sep
_DotHLine(pDC->m_hDC, PROPTREEITEM_EXPANDCOLUMN, pt.y + nTotal - 1, rc.right - PROPTREEITEM_EXPANDCOLUMN + 1);
// draw separators
if (!IsRootLevel())
{
// column sep
CPen pn1(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
CPen* pOld;
pOld = pDC->SelectObject(&pn1);
pDC->MoveTo(nCol, drc.top);
pDC->LineTo(nCol, drc.bottom);
CPen pn2(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
pDC->SelectObject(&pn2);
pDC->MoveTo(nCol + 1, drc.top);
pDC->LineTo(nCol + 1, drc.bottom);
pDC->SelectObject(pOld);
}
// draw attribute
if (!IsRootLevel())
{
// create clip region
hRgn = CreateRectRgn(m_rc.left, m_rc.top, m_rc.right, m_rc.bottom);
SelectClipRgn(pDC->m_hDC, hRgn);
DrawAttribute(pDC, m_rc);
SelectClipRgn(pDC->m_hDC, NULL);
DeleteObject(hRgn);
}
// draw children
if (GetChild() && IsExpanded())
{
y += nTotal;
CPropItem* pNext;
for (pNext = GetChild(); pNext; pNext = pNext->GetSibling())
{
LONG nHeight = pNext->DrawItem(pDC, rc, x + (IsRootLevel() ? 0 : PNINDENT), y);
nTotal += nHeight;
y += nHeight;
}
}
return nTotal;
}
void CPropItem::DrawAttribute(CDC*, const RECT&)
{
// no attributes are assocatied with this type
}
void CPropItem::HasButton(BOOL bHas)
{
m_bHasBt = bHas;
}
void CPropItem::HasSpinCtrl(BOOL bHas /* = TRUE */)
{
m_bHasSpinCtrl = bHas;
}
// 创建(显示)按钮、pWnd:当前控件
void CPropItem::CreateButton( CWnd* pWnd )
{
if (!m_bHasBt || m_nItemType == ITEMTYPE_NULL)
return;
CPropCtrl* pProp = GetPropOwner();
if (pProp != NULL && NULL != pProp->GetCtrlParent())
{
CPropList* pList = (CPropList*)pProp->GetCtrlParent();
// 先移动给按钮留下位置
CRect rect = m_rc;
rect.right = m_rc.right - BUTTON_WIDTH;
pWnd->MoveWindow(rect);
// 确定Spin的位置
CRect rectBt;
pWnd->GetWindowRect(rectBt);
pList->ScreenToClient(rectBt);
rectBt.left = rectBt.right;
rectBt.right = rectBt.left + BUTTON_WIDTH;
if (m_nItemType == ITEMTYPE_COMBOBOX)
rectBt.DeflateRect(0, 1, 0, 5);
if (NULL == pList->m_pBt)
{
pList->m_pBt = new CButton;
pList->m_pBt->Create(_T("..."), WS_VISIBLE , rectBt, pList, IDC_BUTTON);
}
else
{
pList->m_pBt->MoveWindow(rectBt);
pList->m_pBt->ShowWindow(SW_SHOW);
}
}
}
// 创建(显示)SpinCtrl、pWnd:当前控件
void CPropItem::CreateSpinCtrl( CWnd* pWnd )
{
if (!m_bHasSpinCtrl || m_nItemType == ITEMTYPE_NULL)
return;
CPropCtrl* pProp = GetPropOwner();
if (pProp != NULL && NULL != pProp->GetCtrlParent())
{
CPropList* pList = (CPropList*)pProp->GetCtrlParent();
// 先移动给按钮留下位置
CRect rect = m_rc;
rect.right = m_rc.right - SPINCTRL_WIDTH;
pWnd->MoveWindow(rect);
CRect rcSpinCtrl;
pWnd->GetWindowRect(rcSpinCtrl);
pList->ScreenToClient(rcSpinCtrl);
rcSpinCtrl.left = rcSpinCtrl.right;
rcSpinCtrl.right = rcSpinCtrl.left + SPINCTRL_WIDTH;
if (m_nItemType == ITEMTYPE_COMBOBOX)
rcSpinCtrl.DeflateRect(0, 1, 0, 5);
if (NULL == pList->m_pSpinCtrl)
{
pList->m_pSpinCtrl = new CSpinButtonCtrl;
pList->m_pSpinCtrl->Create(WS_VISIBLE, rcSpinCtrl, pList, IDC_SPINCTRL);
}
else
{
pList->m_pSpinCtrl->MoveWindow(rcSpinCtrl);
pList->m_pSpinCtrl->ShowWindow(SW_SHOW);
}
// 设置伙伴控件
CEdit* pEdit = (CEdit*)this;
pList->m_pSpinCtrl->SetBuddy(pEdit);
}
}
void CPropItem::ShowButton(BOOL bShow/* = TRUE*/)
{
CPropCtrl* pTree = GetPropOwner();
if (NULL != pTree)
{
CPropList* pList = (CPropList*)pTree->GetCtrlParent();
if (NULL != pList)
{
pList->ShowButton(bShow);
}
}
}
void CPropItem::ShowSpinCtrl(BOOL bShow /* = TRUE */)
{
CPropCtrl* pTree = GetPropOwner();
if (NULL != pTree)
{
CPropList* pList = (CPropList*)pTree->GetCtrlParent();
if (NULL != pList)
{
pList->ShowSpinCtrl(bShow);
}
}
}