// WndDirectUI.cpp: Implementierungsdatei
//
#include "stdafx.h"
#include "todowin.h"
#include "WndDirectUI.h"
#include "memdc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDirectUIGroup
/////////////////////////////////////////////////////////////////////////////
//
// Credits...
//
// John A. Johnson : DT_NOPREFIX was deleted in all the code
// Andreas Kapust : ::OnMousemove bugfix was added to handle the scrollbar correctly
// Zebrex : HitTest failed on collapsed group
//
CDirectUIGroup::CDirectUIGroup(CString strName, CImageList* pList, int* pnStyle)
{
m_strName = strName;
m_nHeight = 0;
m_pImageList = pList;
m_pnStyle = pnStyle;
m_uiItemState= 0;
m_rcExpandCollapseBtn.SetRectEmpty();
m_bIsCollapsed = FALSE;
CalcHeight();
}
CDirectUIGroup::~CDirectUIGroup()
{
RemoveAllItems();
}
COLORREF CDirectUIGroup::MakeXPColor(COLORREF cl, double factor)
{
if(factor>0.0&&factor<=1.0){
BYTE red,green,blue,lightred,lightgreen,lightblue;
red = GetRValue(cl);
green = GetGValue(cl);
blue = GetBValue(cl);
lightred = (BYTE)((factor*(255-red)) + red);
lightgreen = (BYTE)((factor*(255-green)) + green);
lightblue = (BYTE)((factor*(255-blue)) + blue);
cl = RGB(lightred,lightgreen,lightblue);
}
return(cl);
}
void CDirectUIGroup::OnDraw(CDC* pDC, CRect rcItem)
{
const int nHeaderRadius = 5;
switch (*m_pnStyle)
{
case CWndDirectUI::styleOffice:
{
// Draw Header
LOGFONT lf;
CFont::FromHandle((HFONT) GetStockObject(ANSI_VAR_FONT))->GetLogFont(&lf);
CFont fnHeader;
lf.lfWeight = FW_BOLD;
fnHeader.CreateFontIndirect(&lf);
pDC->SelectObject(&fnHeader);
CRect rcHeader;
rcHeader.SetRect(rcItem.left, rcItem.top, rcItem.right, rcItem.top + GetSystemMetrics(SM_CYCAPTION)); // Whole top area
pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
pDC->DrawText(m_strName, rcHeader, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
CPen pnSeparator;
pnSeparator.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DFACE));
pDC->MoveTo(rcHeader.left, rcHeader.bottom);
pDC->LineTo(rcHeader.BottomRight());
// Draw Items
CRect rcItems;
rcItems.SetRect(rcItem.left+1, rcHeader.bottom, rcItem.right-1, rcHeader.bottom);
if (m_pImageList) m_pImageList->SetBkColor(GetSysColor(COLOR_WINDOW));
pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHT));
CPen pnUnderline;
pnUnderline.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_HIGHLIGHT));
pDC->SelectObject(&pnUnderline);
// Draw Items
if (!m_bIsCollapsed)
{
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
rcItems.top = rcItems.bottom;
rcItems.bottom += MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8); // add 12,5% space between the items
m_lstItems.GetNext(pos)->OnDraw(pDC, rcItems, m_pImageList, *m_pnStyle);
}
}
}
break;
case CWndDirectUI::styleXPclassic:
{
CPen pnBorder;
CPen pnMarker;
CBrush brHeader;
CBrush brItemArea;
COLORREF clBorder = GetSysColor(COLOR_3DFACE);
COLORREF clText = GetSysColor(COLOR_BTNTEXT);
COLORREF clItemArea = GetSysColor(COLOR_WINDOW);
pnBorder.CreatePen(PS_SOLID, 1, clBorder);
pnMarker.CreatePen(PS_SOLID, 1, clText);
brHeader.CreateSolidBrush(clBorder);
brItemArea.CreateSolidBrush(clItemArea);
// Draw Header
LOGFONT lf;
CFont::FromHandle((HFONT) GetStockObject(ANSI_VAR_FONT))->GetLogFont(&lf);
CFont fnHeader;
lf.lfWeight = FW_BOLD;
fnHeader.CreateFontIndirect(&lf);
pDC->SelectObject(&fnHeader);
// Draw Header
CRect rcHeader;
CRect rcHeaderTextArea;
rcHeader.SetRect(rcItem.left, rcItem.top, rcItem.right, rcItem.top + GetSystemMetrics(SM_CYCAPTION)); // Whole top area
pDC->SetTextColor(clText);
pDC->SetBkColor(clBorder);
rcHeaderTextArea.SetRect(rcHeader.left+nHeaderRadius, rcHeader.top, rcHeader.right-nHeaderRadius, rcHeader.bottom); // area between
pDC->SelectObject(&brHeader);
pDC->FillSolidRect(rcHeader, clBorder);
pDC->DrawText(m_strName, rcHeaderTextArea, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
// Draw the Expand/Collapse button
const int nBtnSpace = 2;
int nBtnSize;
nBtnSize = GetSystemMetrics(SM_CYCAPTION)-nBtnSpace-nBtnSpace;
m_rcExpandCollapseBtn.SetRect(rcItem.right-nHeaderRadius-nBtnSize, rcItem.top +nBtnSpace, rcItem.right-nHeaderRadius, rcItem.top+nBtnSpace+nBtnSize);
if (m_uiItemState & ODS_SELECTED) pDC->Draw3dRect(m_rcExpandCollapseBtn, GetSysColor(COLOR_3DHILIGHT), GetSysColor(COLOR_3DSHADOW));
pDC->SelectObject(&pnMarker);
CPoint ptCenter = m_rcExpandCollapseBtn.CenterPoint();
CPoint ptLeft = ptCenter +CPoint(-4, m_bIsCollapsed ? -4:4);
CPoint ptRight = ptCenter +CPoint( 4, m_bIsCollapsed ? -4:4);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptLeft);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptRight);
ptCenter.Offset(0, m_bIsCollapsed ?3:-3);
ptLeft.Offset(0, m_bIsCollapsed ?3:-3);
ptRight.Offset(0, m_bIsCollapsed ?3:-3);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptLeft);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptRight);
m_rcExpandCollapseBtn.left = rcHeader.left;
// Now draw the lighter area for all items
pDC->SelectObject(&pnBorder);
pDC->SelectObject(&brItemArea);
pDC->Rectangle(rcItem.left, rcHeaderTextArea.bottom-1, rcItem.right, rcItem.bottom);
// Draw Items
pDC->SelectObject(&pnMarker);
if (!m_bIsCollapsed)
{
CRect rcItems;
rcItems.SetRect(rcItem.left+1, rcHeaderTextArea.bottom, rcItem.right-1, rcHeaderTextArea.bottom);
if (m_pImageList) m_pImageList->SetBkColor(clItemArea);
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
rcItems.top = rcItems.bottom;
rcItems.bottom += MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8); // add 12,5% space between the items
m_lstItems.GetNext(pos)->OnDraw(pDC, rcItems, m_pImageList, *m_pnStyle);
}
}
}
break;
case CWndDirectUI::styleXP:
default:
{
CPen pnMarker;
CPen pnBorder;
CPen pnBtn;
CBrush brHeader;
CBrush brItemArea;
COLORREF clBorder = GetSysColor(COLOR_HIGHLIGHT);
COLORREF clText = GetSysColor(COLOR_HIGHLIGHTTEXT);
COLORREF clItemArea = MakeXPColor(clBorder, 0.85); // Seems to be ok
pnMarker.CreatePen(PS_SOLID, 1, clText);
pnBtn .CreatePen(PS_SOLID, 1, clItemArea);
pnBorder.CreatePen(PS_SOLID, 1, clBorder);
brHeader.CreateSolidBrush(clBorder);
brItemArea.CreateSolidBrush(clItemArea);
// Draw Header
LOGFONT lf;
CFont::FromHandle((HFONT) GetStockObject(ANSI_VAR_FONT))->GetLogFont(&lf);
CFont fnHeader;
lf.lfWeight = FW_BOLD;
fnHeader.CreateFontIndirect(&lf);
pDC->SelectObject(&fnHeader);
// Calculate all area sizes
CRect rcHeader;
CRect rcPieLeft;
CRect rcPieRight;
CRect rcHeaderTextArea;
rcHeader.SetRect(rcItem.left, rcItem.top, rcItem.right, rcItem.top + GetSystemMetrics(SM_CYCAPTION)); // Whole top area
rcPieLeft.SetRect(rcItem.left, rcItem.top, rcItem.left+nHeaderRadius+nHeaderRadius, rcItem.top+nHeaderRadius+nHeaderRadius); // Upper-left edge
rcPieRight.SetRect(rcItem.right-nHeaderRadius-nHeaderRadius, rcItem.top, rcItem.right, rcItem.top+nHeaderRadius+nHeaderRadius);// Upper-right edge
rcHeaderTextArea.SetRect(rcHeader.left+nHeaderRadius, rcHeader.top, rcHeader.right-nHeaderRadius, rcHeader.bottom); // area between
// Draw the "title bar"
pDC->SelectObject(&pnBorder);
pDC->SelectObject(&brHeader);
pDC->Pie(rcPieLeft, CPoint(rcPieLeft.left+nHeaderRadius, rcPieLeft.top), CPoint(rcPieLeft.left, rcPieLeft.top+nHeaderRadius));
pDC->Pie(rcPieRight, CPoint(rcPieRight.left+nHeaderRadius, rcPieRight.top+nHeaderRadius), CPoint(rcPieRight.left+nHeaderRadius, rcPieRight.top));
pDC->FillSolidRect(rcHeaderTextArea, clBorder);
pDC->FillSolidRect(CRect(rcHeader.left, rcHeader.top+nHeaderRadius, rcHeader.left+nHeaderRadius, rcHeader.bottom), clBorder);
pDC->FillSolidRect(CRect(rcHeader.right-nHeaderRadius, rcHeader.top+nHeaderRadius, rcHeader.right, rcHeader.bottom), clBorder);
if (m_uiItemState & ODS_SELECTED)
pDC->SetTextColor(clItemArea);
else
pDC->SetTextColor(clText);
pDC->SetBkColor(clBorder);
// Make the text field a little smaller
rcHeaderTextArea.left += nHeaderRadius+nHeaderRadius;
pDC->DrawText(m_strName, rcHeaderTextArea, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
// Draw the Expand/Collapse button
const int nBtnSpace = 4;
int nBtnSize;
nBtnSize = GetSystemMetrics(SM_CYCAPTION)-nBtnSpace-nBtnSpace;
m_rcExpandCollapseBtn.SetRect(rcItem.right-nHeaderRadius-nBtnSize, rcItem.top +nBtnSpace, rcItem.right-nHeaderRadius, rcItem.top+nBtnSpace+nBtnSize);
pDC->SelectStockObject(NULL_BRUSH);
pDC->SelectObject(&pnBtn);
pDC->Ellipse(m_rcExpandCollapseBtn);
if (m_uiItemState & ODS_SELECTED)
pDC->SelectObject(&pnBtn);
else
pDC->SelectObject(&pnMarker);
CPoint ptCenter = m_rcExpandCollapseBtn.CenterPoint();
CPoint ptLeft = ptCenter +CPoint(-4, m_bIsCollapsed ? -4:4);
CPoint ptRight = ptCenter +CPoint( 4, m_bIsCollapsed ? -4:4);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptLeft);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptRight);
ptCenter.Offset(0, m_bIsCollapsed ?3:-3);
ptLeft.Offset(0, m_bIsCollapsed ?3:-3);
ptRight.Offset(0, m_bIsCollapsed ?3:-3);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptLeft);
pDC->MoveTo(ptCenter);
pDC->LineTo(ptRight);
m_rcExpandCollapseBtn.left = rcHeader.left;
// Now draw the lighter area for all items
pDC->SelectObject(&pnBorder);
pDC->SelectObject(&brItemArea);
pDC->Rectangle(rcItem.left, rcHeaderTextArea.bottom-1, rcItem.right, rcItem.bottom);
// Draw Items
if (!m_bIsCollapsed)
{
CRect rcItems;
rcItems.SetRect(rcItem.left+1, rcHeaderTextArea.bottom, rcItem.right-1, rcHeaderTextArea.bottom);
if (m_pImageList) m_pImageList->SetBkColor(clItemArea);
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
rcItems.top = rcItems.bottom;
rcItems.bottom += MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8); // add 12,5% space between the items
m_lstItems.GetNext(pos)->OnDraw(pDC, rcItems, m_pImageList, *m_pnStyle);
}
}
}
}
}
int CDirectUIGroup::AddItem(CDirectUIItem *pItem)
{
m_lstItems.AddTail(pItem);
CalcHeight();
return m_lstItems.GetCount()-1;
}
void CDirectUIGroup::RemoveAllItems()
{
while (m_lstItems.GetCount()) delete m_lstItems.RemoveHead();
CalcHeight();
}
void CDirectUIGroup::CalcHeight()
{
m_nHeight = GetSystemMetrics(SM_CYCAPTION);
if (!m_bIsCollapsed)
m_nHeight += (m_lstItems.GetCount()*MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8)); // 12.5% Space
}
BOOL CDirectUIGroup::HitTestButton(CPoint point)
{
if (*m_pnStyle == CWndDirectUI::styleOffice) return FALSE; // Not supported for Office style
return (PtInRect(m_rcExpandCollapseBtn, point)) ? TRUE:FALSE;
}
CDirectUIItem* CDirectUIGroup::HitTest(CPoint point)
{
if (m_bIsCollapsed) return FALSE;
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
CDirectUIItem* pItem = m_lstItems.GetNext(pos);
if (pItem->HitTest(point)) return pItem;
}
return NULL;
}
void CDirectUIGroup::ParseToolbar(CToolBar *pToolbar)
{
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
CDirectUIItem* pItem = m_lstItems.GetNext(pos);
pItem->ParseToolbar(pToolbar);
}
}
BOOL CDirectUIGroup::Expand(BOOL bExpand)
{
if (m_bIsCollapsed != bExpand) return FALSE;
m_bIsCollapsed = !bExpand;
CalcHeight();
return TRUE;
}
void CDirectUIGroup::ToggleExpand()
{
m_bIsCollapsed = !m_bIsCollapsed;
CalcHeight();
}
/////////////////////////////////////////////////////////////////////////////
// CDirectUIItem
CDirectUIItem::CDirectUIItem(CString strName, UINT uiCommand, int nIconIndex)
{
m_rcItem.SetRectEmpty();
m_strName = strName;
m_nIconIndex = nIconIndex;
m_uiCommand = uiCommand;
m_uiItemState= 0;
}
void CDirectUIItem::OnDraw(CDC* pDC, CRect rcItem, CImageList* pImageList, int nStyle)
{
const nBorderX = 10;
const nBorderIconX = 4;
const nIconSize = 16;
switch (nStyle)
{
case CWndDirectUI::styleOffice:
{
m_rcItem = rcItem;
rcItem.left += nIconSize+nBorderIconX;
pDC->SelectStockObject(ANSI_VAR_FONT);
pDC->DrawText(m_strName, rcItem, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
pDC->DrawText(m_strName, m_rcItem, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS|DT_CALCRECT);
m_rcItem.OffsetRect(nIconSize+nBorderIconX, 0);
if ((m_nIconIndex != -1) && (pImageList))
pImageList->Draw(pDC, m_nIconIndex, CPoint(m_rcItem.left-nIconSize-nBorderIconX, rcItem.top+((rcItem.Height()-nIconSize)/2)), ILD_NORMAL);
if (m_uiItemState & ODS_SELECTED)
{
pDC->MoveTo(m_rcItem.left, m_rcItem.bottom);
pDC->LineTo(m_rcItem.right, m_rcItem.bottom);
}
}
break;
case CWndDirectUI::styleXP:
default:
{
rcItem.left += nBorderX;
rcItem.right -= nBorderX;
// When there's an icon place the text more to the right
if (m_nIconIndex != -1)
rcItem.left += nIconSize+nBorderIconX;
m_rcItem = rcItem;
// Item selected? Then draw it brighter
if (m_uiItemState & ODS_SELECTED)
pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHT));
else
pDC->SetTextColor(CDirectUIGroup::MakeXPColor(GetSysColor(COLOR_HIGHLIGHT), 0.15));
pDC->SelectStockObject(ANSI_VAR_FONT);
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(m_strName, rcItem, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
pDC->DrawText(m_strName, m_rcItem, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS|DT_CALCRECT);
// Item selected? Then underline it (doing it this way I don't need to create an underlined font)
if (m_uiItemState & ODS_SELECTED)
{
pDC->MoveTo(m_rcItem.left, m_rcItem.bottom);
pDC->LineTo(m_rcItem.right, m_rcItem.bottom);
}
if ((m_nIconIndex != -1) && (pImageList))
{
// Finally draw the icon
m_rcItem.left -= (nBorderIconX+nIconSize);
if (m_uiItemState & ODS_SELECTED)
pImageList->Draw(pDC, m_nIconIndex, CPoint(m_rcItem.left, rcItem.top+((rcItem.Height()-nIconSize)/2)), ILD_SELECTED);
else
pImageList->Draw(pDC, m_nIconIndex, CPoint(m_rcItem.left, rcItem.top+((rcItem.Height()-nIconSize)/2)), ILD_NORMAL);
}
}
}
}
BOOL CDirectUIItem::HitTest(CPoint point)
{
return (PtInRect(m_rcItem, point)) ? TRUE:FALSE;
}
void CDirectUIItem::ParseToolbar(CToolBar *pToolbar)
{
ASSERT(pToolbar);
int nBitmap = pToolbar->SendMessage(TB_GETBITMAP, m_uiCommand, 0);
if (nBitmap > 0)
m_nIconIndex = nBitmap;
else
m_nIconIndex = -1;
}
/////////////////////////////////////////////////////////////////////////////
// CWndDirectUI
BEGIN_MESSAGE_MAP(CWndDirectUI, CWnd)
//{{AFX_MSG_MAP(CWndDirectUI)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_SETCURSOR()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_VSCROLL()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Behandlungsroutinen f�r Nachrichten CWndDirectUI
CWndDirectUI::CWndDirectUI()
{
m_pLastHitItem = NULL;
m_pLastHitGroup = NULL;
m_hHand = AfxGetApp()->LoadCursor(IDC_MYHAND);
VERIFY(m_hHand); // If asserts, add this cursor to your resource
m_nStyle = styleXP;
m_lstImages.Create(1, 1, ILC_COLOR,1, 1);
}
CWndDirectUI::~CWndDirectUI()
{
RemoveAll();
}
void CWndDirectUI::OnPaint()
{
const int nSpaceX = 10;
const int nSpaceY = 10;
CPaintDC dc(this); // device context for painting
CRect rc;
CRect rcItem;
GetWindowRect(&rc);
rc -= rc.TopLeft();
BOOL bHasScrollbar;
BOOL bNeedScrollbar;
int nOffsetY;
bHasScrollbar = ::GetWindowLong(m_hWnd, GWL_STYLE) & WS_VSCROLL ? TRUE:FALSE;
if (bHasScrollbar)
{
rc.right -= GetSystemMetrics(SM_CXHTHUMB);
nOffsetY = GetScrollPos(SB_VERT);
}
else
nOffsetY = 0;
rc.bottom +=nOffsetY;
CMemDC MemDC(&dc, &rc);
dc.SetWindowOrg(0, nOffsetY);
switch (m_nStyle)
{
case styleXPclassic:
case styleOffice:
MemDC.FillSolidRect(rc, GetSysColor(COLOR_WINDOW));
break;
case styleXP:
default:
MemDC.FillSolidRect(rc, CDirectUIGroup::MakeXPColor(GetSysColor(COLOR_HIGHLIGHT), 0.4));
}
rcItem.SetRect(nSpaceX, 0, rc.right - nSpaceX, 0);
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
{
CDirectUIGroup* pGroup = m_lstGroups.GetNext(pos);
rcItem.top = rcItem.bottom + nSpaceY;
rcItem.bottom = rcItem.top + pGroup->m_nHeight;
pGroup->OnDraw(&MemDC, rcItem);
}
// Show Scrollbar if needed
bNeedScrollbar = ((rc.Height()-nOffsetY) < (rcItem.bottom+nSpaceY)) ? TRUE:FALSE;
if (bNeedScrollbar != bHasScrollbar)
{
if (bNeedScrollbar)
ShowScrollBar(SB_VERT, TRUE);
else
ShowScrollBar(SB_VERT, FALSE);
Invalidate();
}
if (bNeedScrollbar)
{
// Set Scrollbar range
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_PAGE|SIF_RANGE;
si.nMin = 0;
si.nMax = rcItem.bottom+nSpaceY;
si.nPage = rc.Height()-nOffsetY;
SetScrollInfo(SB_VERT, &si, TRUE);
}
}
BOOL CWndDirectUI::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CWndDirectUI::RemoveAll()
{
while (m_lstGroups.GetCount()) delete m_lstGroups.RemoveHead();
}
int CWndDirectUI::AddGroup(CString strName)
{
CDirectUIGroup* pGroup = new CDirectUIGroup(strName, &m_lstImages, &m_nStyle);
m_lstGroups.AddTail(pGroup);
InvalidateIfPossible();
return m_lstGroups.GetCount()-1;
}
BOOL CWndDirectUI::RemoveGroup(int nGroup)
{
CDirectUIGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return FALSE;
POSITION pos = m_lstGroups.Find(pGroup);
ASSERT(pos);
if (!pos) return FALSE;
m_lstGroups.RemoveAt(pos);
delete pGroup;
InvalidateIfPossible();
return TRUE;
}
CString& CWndDirectUI::GetGroupName(int nGroup)
{
static CString strNull;
CDirectUIGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return strNull;
return pGroup->m_strName;
}
BOOL CWndDirectUI::ChangeGroupName(int nGroup, CString strName)
{
CDirectUIGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return FALSE;
pGroup->m_strName = strName;
InvalidateIfPossible();
return TRUE;
}
BOOL CWndDirectUI::ExpandGroup(int nGroup, BOOL bExpand)
{
CDirectUIGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return FALSE;
if (pGroup->Expand(bExpand)) InvalidateIfPossible();
return TRUE;
}
BOOL CWndDirectUI::InitFromMenu(UINT id)
{
// Main funtion! Use a 2D Menu
RemoveAll();
CMenu mnuGroups;
MENUITEMINFO info;
if (!mnuGroups.LoadMenu(id)) return FALSE;
int i = 0;
int j = 0;
while (mnuGroups.GetSubMenu(i))
{
CMenu* pMenu = mnuGroups.GetSubMenu(i);
CString strName;
mnuGroups.GetMenuString(i, strName, MF_BYPOSITION);
CDirectUIGroup* pGroup = new CDirectUIGroup(strName, &m_lstImages, &m_nStyle);
info.cbSize = sizeof (MENUITEMINFO);
info.fMask = MIIM_ID;
j = 0;
while (pMenu->GetMenuString(j, strName, MF_BYPOSITION))
{
pMenu->GetMenuItemInfo(j, &info, TRUE);
pGroup->AddItem(new CDirectUIItem(strName, info.wID));
j++;
}
m_lstGroups.AddTail(pGroup);
i++;
}
InvalidateIfPossible();
return TRUE;
}
BOOL CWndDirectUI::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (((m_pLastHitItem != NULL) | (m_pLastHitGroup != NULL)) & (nHitTest == HTCLIENT))
{
SetCursor(m_hHand);
return TRUE;
}
else
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CWndDirectUI::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd::OnLButtonDown(nFlags, point);
if (m_pLastHitGroup)
{
m_pLastHitGroup->ToggleExpand();
Invalidate();
}
}
void CWndDirectUI::OnMouseMove(UINT nFlags, CPoint point)
{
// Do the hoover thing
CDirectUIItem* pItem;
CDirectUIGroup* pCurrentGroup;
CDirectUIGroup* pGroup;
pItem = NULL;
pGroup = NULL;
if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_VSCROLL)
point.y += GetScrollPos(SB_VERT);
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
{
pCurrentGroup = m_lstGroups.GetNext(pos);
if (pCurrentGroup->HitTestButton(point))
{
pGroup = pCurrentGroup;
break;
}
pItem = pCurrentGroup->HitTest(point);
if (pItem != NULL) break;
}
if (pGroup != m_pLastHitGroup)
{
if (m_pLastHitGroup) m_pLastHitGroup->m_uiItemState &= ~ODS_SELECTED;
m_pLastHitGroup = pGroup;
if (m_pLastHitGroup) m_pLastHitGroup->m_uiItemState |= ODS_SELECTED;
Invalidate();
}
else if (pItem != m_pLastHitItem)
{
// Draw Item
if (m_pLastHitItem) m_pLastHitItem->m_uiItemState &= ~ODS_SELECTED;
m_pLastHitItem = pItem;
if (m_pLastHitItem) m_pLastHitItem->m_uiItemState |= ODS_SELECTED;
Invalidate();
}
CWnd::OnMouseMove(nFlags, point);
}
void CWndDirectUI::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_pLastHitItem)
AfxGetMainWnd()->PostMessage(WM_COMMAND, m_pLastHitItem->m_uiCommand, 0);
CWnd::OnLButtonUp(nFlags, point);
}
CDirectUIGroup* CWndDirectUI::GetGroupByNumber(int nPos)
{
if (nPos < 0) return NULL;
CDirectUIGroup* pGroup;
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
{
pGroup = m_lstGroups.GetNext(pos);
if (nPos == 0) return pGroup;
nPos--;
}
return NULL;
}
void CWndDirectUI::InvalidateIfPossible()
{
if (IsWindow(m_hWnd)) Invalidate();
}
BOOL CWndDirectUI::SetToolbarImages(UINT uiToolbar)
{
// Use this function after inserting all items and groups
// Create an invisible toolbar and let it do all the work
CToolBar tbToolbar;
if (!tbToolbar.Create(this, WS_CHILD, 42)) return FALSE;
if (!tbToolbar.LoadToolBar(uiToolbar)) return FALSE;
m_lstImages.Detach();
if (!m_lstImages.Create(CImageList::FromHandle((HIMAGELIST)tbToolbar.SendMessage(TB_GETIMAGELIST, 0, 0)))) return FALSE;
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
m_lstGroups.GetNext(pos)->ParseToolbar(&tbToolbar);
InvalidateIfPossible();
return TRUE;
}
BOOL CWndDirectUI::AddItem(int nGroup, CString strItem, UINT uiCommand)
{
CDirectUIGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return FALSE;
pGroup->AddItem(new CDirectUIItem(strItem, uiCommand));
InvalidateIfPossible();
return TRUE;
}
BOOL CWndDirectUI::SetStyle(int nStyle)
{
m_nStyle = nStyle;
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
m_lstGroups.GetNext(pos)->CalcHeight();
InvalidateIfPossible();
return TRUE;
}
int CWndDirectUI::GetStyle()
{
return m_nStyle;
}
void CWndDirectUI::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
switch (nSBCode)
{
case SB_BOTTOM:
nPos = GetScrollLimit(SB_VERT);
break;
case SB_ENDSCROLL:
return;
case SB_LINEDOWN:
nPos = GetScrollPos(SB_VERT) +1;
break;
case SB_LINEUP:
nPos = GetScrollPos(SB_VERT) -1;
break;
case SB_PAGEDOWN:
nPos = GetScrollPos(SB_VERT) + MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8);
break;
case SB_PAGEUP:
nPos = GetScrollPos(SB_VERT) - MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8);
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
break;
case SB_TOP:
nPos = 0;
break;
}
Invalidate();
SetScrollPos(SB_VERT, nPos, TRUE);
}
BOOL CWndDirectUI::Create(const RECT &rect, CWnd *pParentWnd, UINT nID)
{
return CWnd::Create(NULL, _T("WndDirectUI"), WS_CHILD|WS_VISIBLE, rect, pParentWnd, nID);
}