// WndJobs.cpp: Implementierungsdatei
//
#include "stdafx.h"
#include "todowin.h"
#include "WndJobs.h"
#include "memdc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CJobGroup
CJobGroup::CJobGroup(CString strName, CImageList* pList)
{
m_strName = strName;
m_nHeight = 0;
m_pImageList = pList;
CalcHeight();
}
CJobGroup::~CJobGroup()
{
RemoveAllItems();
}
COLORREF CJobGroup::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 CJobGroup::OnDraw(CDC* pDC, CRect rcItem)
{
const int nHeaderRadius = 5;
CPen pnBorder;
CBrush brHeader;
CBrush brItemArea;
COLORREF clBorder = GetSysColor(COLOR_HIGHLIGHT);
COLORREF clText = GetSysColor(COLOR_HIGHLIGHTTEXT);
COLORREF clItemArea = MakeXPColor(clBorder, 0.85); // Seems to be ok
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);
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_NOPREFIX|DT_END_ELLIPSIS);
// Now draw the lighter area for all items
pDC->SelectObject(&brItemArea);
pDC->Rectangle(rcItem.left, rcHeaderTextArea.bottom, rcItem.right, rcItem.bottom);
// Draw Items
CRect rcItems;
rcItems.SetRect(rcItem.left+1, rcHeaderTextArea.bottom, rcItem.right-1, rcHeaderTextArea.bottom);
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);
}
}
int CJobGroup::AddItem(CJobItem *pItem)
{
m_lstItems.AddTail(pItem);
CalcHeight();
return m_lstItems.GetCount()-1;
}
void CJobGroup::RemoveAllItems()
{
while (m_lstItems.GetCount()) delete m_lstItems.RemoveHead();
CalcHeight();
}
void CJobGroup::CalcHeight()
{
m_nHeight = GetSystemMetrics(SM_CYCAPTION);
m_nHeight += (m_lstItems.GetCount()*MulDiv(GetSystemMetrics(SM_CYMENU), 9, 8)); // 12.5% Space
}
CJobItem* CJobGroup::HitTest(CPoint point)
{
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
CJobItem* pItem = m_lstItems.GetNext(pos);
if (pItem->HitTest(point)) return pItem;
}
return NULL;
}
void CJobGroup::ParseToolbar(CToolBar *pToolbar)
{
for (POSITION pos = m_lstItems.GetHeadPosition(); pos;)
{
CJobItem* pItem = m_lstItems.GetNext(pos);
pItem->ParseToolbar(pToolbar);
}
}
/////////////////////////////////////////////////////////////////////////////
// CJobItem
CJobItem::CJobItem(CString strName, UINT uiCommand, int nIconIndex)
{
m_rcItem.SetRectEmpty();
m_strName = strName;
m_nIconIndex = nIconIndex;
m_uiCommand = uiCommand;
m_uiItemState= 0;
}
void CJobItem::OnDraw(CDC* pDC, CRect rcItem, CImageList* pImageList)
{
const nBorderX = 10;
const nBorderIconX = 4;
const nIconSize = 16;
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(CJobGroup::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_NOPREFIX|DT_END_ELLIPSIS);
pDC->DrawText(m_strName, m_rcItem, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|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)
{
// 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 CJobItem::HitTest(CPoint point)
{
return (PtInRect(m_rcItem, point)) ? TRUE:FALSE;
}
void CJobItem::ParseToolbar(CToolBar *pToolbar)
{
ASSERT(pToolbar);
int nBitmap = pToolbar->SendMessage(TB_GETBITMAP, m_uiCommand, 0);
if (nBitmap > 0)
m_nIconIndex = nBitmap;
else
m_nIconIndex = -1;
}
/////////////////////////////////////////////////////////////////////////////
// CWndJobs
BEGIN_MESSAGE_MAP(CWndJobs, CWnd)
//{{AFX_MSG_MAP(CWndJobs)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_SETCURSOR()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Behandlungsroutinen f�r Nachrichten CWndJobs
CWndJobs::CWndJobs()
{
m_pLastHit = NULL;
m_hHand = AfxGetApp()->LoadCursor(IDC_HAND);
}
CWndJobs::~CWndJobs()
{
RemoveAll();
}
void CWndJobs::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();
CMemDC MemDC(&dc, &rc);
MemDC.FillSolidRect(rc, CJobGroup::MakeXPColor(GetSysColor(COLOR_HIGHLIGHT), 0.4));
rcItem.SetRect(nSpaceX, 0, rc.right - nSpaceX, 0);
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
{
CJobGroup* pGroup = m_lstGroups.GetNext(pos);
rcItem.top = rcItem.bottom + nSpaceY;
rcItem.bottom = rcItem.top + pGroup->m_nHeight;
pGroup->OnDraw(&MemDC, rcItem);
}
}
BOOL CWndJobs::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CWndJobs::RemoveAll()
{
while (m_lstGroups.GetCount()) delete m_lstGroups.RemoveHead();
}
int CWndJobs::AddGroup(CString strName)
{
CJobGroup* pGroup = new CJobGroup(strName, &m_lstImages);
m_lstGroups.AddTail(pGroup);
InvalidateIfPossible();
return m_lstGroups.GetCount()-1;
}
BOOL CWndJobs::RemoveGroup(int nGroup)
{
CJobGroup* 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& CWndJobs::GetGroupName(int nGroup)
{
static CString strNull;
CJobGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return strNull;
return pGroup->m_strName;
}
BOOL CWndJobs::ChangeGroupName(int nGroup, CString strName)
{
CJobGroup* pGroup = GetGroupByNumber(nGroup);
if (!pGroup) return FALSE;
pGroup->m_strName = strName;
InvalidateIfPossible();
return TRUE;
}
BOOL CWndJobs::ExpandGroup(int nGroup, BOOL bExpand)
{
// TODO
ASSERT(FALSE);
return FALSE;
}
BOOL CWndJobs::InitFromMenu(UINT id)
{
// Main funtion! Use a 2D Menu
RemoveAll();
CMenu mnuJobs;
MENUITEMINFO info;
if (!mnuJobs.LoadMenu(id)) return FALSE;
int i = 0;
int j = 0;
while (mnuJobs.GetSubMenu(i))
{
CMenu* pMenu = mnuJobs.GetSubMenu(i);
CString strName;
mnuJobs.GetMenuString(i, strName, MF_BYPOSITION);
CJobGroup* pGroup = new CJobGroup(strName, &m_lstImages);
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 CJobItem(strName, info.wID));
j++;
}
m_lstGroups.AddTail(pGroup);
i++;
}
InvalidateIfPossible();
return TRUE;
}
BOOL CWndJobs::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (m_pLastHit != NULL)
{
SetCursor(m_hHand);
return TRUE;
}
else
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CWndJobs::OnLButtonDown(UINT nFlags, CPoint point)
{
// In future: draw focus rect...
CWnd::OnLButtonDown(nFlags, point);
}
void CWndJobs::OnMouseMove(UINT nFlags, CPoint point)
{
// Do the hoover thing
CJobItem* pItem;
CJobGroup* pGroup;
pItem = NULL;
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
{
pGroup = m_lstGroups.GetNext(pos);
pItem = pGroup->HitTest(point);
if (pItem != NULL) break;
}
if (pItem != m_pLastHit)
{
// Draw Item
if (m_pLastHit) m_pLastHit->m_uiItemState &= ~ODS_SELECTED;
m_pLastHit = pItem;
if (m_pLastHit) m_pLastHit->m_uiItemState |= ODS_SELECTED;
Invalidate();
}
CWnd::OnMouseMove(nFlags, point);
}
void CWndJobs::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_pLastHit)
AfxGetMainWnd()->PostMessage(WM_COMMAND, m_pLastHit->m_uiCommand, 0);
CWnd::OnLButtonUp(nFlags, point);
}
CJobGroup* CWndJobs::GetGroupByNumber(int nPos)
{
if (nPos < 0) return NULL;
CJobGroup* pGroup;
for (POSITION pos = m_lstGroups.GetHeadPosition(); pos;)
{
pGroup = m_lstGroups.GetNext(pos);
if (nPos == 0) return pGroup;
nPos--;
}
return NULL;
}
void CWndJobs::InvalidateIfPossible()
{
if (IsWindow(m_hWnd)) Invalidate();
}
BOOL CWndJobs::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 CWndJobs::AddItem(int nGroup, CString strItem, UINT uiCommand)
{
CJobGroup* pJob = GetGroupByNumber(nGroup);
if (!pJob) return FALSE;
pJob->AddItem(new CJobItem(strItem, uiCommand));
InvalidateIfPossible();
return TRUE;
}