Click here to Skip to main content
15,895,799 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 256.2K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// ==========================================================================
// 							Class Implementation : COXStatusBar
// ==========================================================================

// Implementation file : status.cpp

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.                      
                         
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "xstatus4.h"
#include "OXSkins.h"

#include <windowsx.h>
#include <malloc.h>

#include "UTBStrOp.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[]=__FILE__;
#endif

#define CX_BORDER   1
#define CY_BORDER   1

#define SBPF_UPDATE 0x0001  // pending update of text
#define CX_PANE_BORDER 6    // 3 pixels on each side of each pane


IMPLEMENT_DYNAMIC(COXStatusBar, CStatusBar)

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// Definition of static members

// Data members -------------------------------------------------------------
// protected:
	//  CObArray	m_PaneBmp;
	// --- Each item represents a pane. When there is
	// 	   a pointer stored in it, that pane contains a bitmap
    // 	   Each item represents a pane. When there is         
	//     a WORD stored in it, that pane contains a COLOR

    //  CDWordArray m_ColorArray;
	// --- An array containing possible textcolors when drawing a pane with Text in it.
	
	//  CPtrArray  	m_EvolArray;
	// --- An array containing possible Objects that configure each a Progress bar in a pane.

	//  CDC m_srcDC;
	// --- A memory DC used to bitblt the bitmaps from.

// Member functions ---------------------------------------------------------
// public:

COXStatusBar::COXStatusBar() :
	m_pStatusbarSkin(NULL)
	{
	}

COXStatusBar::~COXStatusBar()
	{     
	// free all bitmaps and their container objects
	int i(0);
	CBmpInfo* pBmpInfo=NULL;
	while(i < m_PaneBmp.GetSize())
		{
		pBmpInfo=(CBmpInfo*)m_PaneBmp[i];
		if(pBmpInfo != NULL)
			{
			pBmpInfo->m_pBitmap->DeleteObject();
			delete pBmpInfo->m_pBitmap;			
			delete pBmpInfo;
			}
		i++;
		}

	// free all pane fonts objects
	i=0;
	CFont* pFont=NULL;
	while(i < m_PaneFont.GetSize())
		{
		pFont=(CFont*)m_PaneFont[i];
		if(pFont != NULL)
			{
			pFont->DeleteObject();
			delete pFont;
			}
		i++;
		}

	// free all progress container objects
	i=0;
	CEvolInfo* pEvolInfo=NULL;
	while(i < m_EvolArray.GetSize())
		{
		pEvolInfo=(CEvolInfo*)m_EvolArray[i];
		if(pEvolInfo != NULL)
			{
			delete pEvolInfo;
			}
		i++;
		}

	// if necessary delete the classic skin
	if (m_pStatusbarSkin != NULL)
		delete m_pStatusbarSkin;

	// Workarround for destructor of CStatusBar where the text of a pane is not
	// freed correctly everytime.
	if(m_nCount>0)
		{
		AFX_STATUSPANE* pSBP=_GetPanePtr(0);
		for (i=0; i < m_nCount; i++)
			{
			pSBP->strText.Empty();
			pSBP->strText.FreeExtra();
			++pSBP;
			}
		}
	}

BOOL COXStatusBar::SetPaneCursor(int nIndex, UINT nCursorID /*=0 */)
	{
	// Check whether we are reseting the cursor
	if (nCursorID==0)
		{
		m_CursorArray[nIndex]=(DWORD)NULL;
		return TRUE;
		}

	// The cursor is read from resource now
	HCURSOR hNewCursor=AfxGetApp()->LoadCursor(nCursorID);
	if (hNewCursor != NULL)
		{
		m_CursorArray[nIndex]=(DWORD)(INT_PTR)hNewCursor;
		}
	else
		{
		TRACE1("COXStatusBar::SetPaneCursor : Failed to load cursor with ID %i\n",
			nCursorID);
		return FALSE;
		}

	return TRUE;
	}

BOOL COXStatusBar::SetPaneFont(int nIndex, CFont* pFont /*=NULL */)
{
	CFont* pPaneFont=(CFont*)m_PaneFont[nIndex];
	if(pPaneFont != NULL)
		pPaneFont->DeleteObject();

	// to restore the default font
	if (pFont==NULL)
	{
		// if pane font==NULL there was no special font selected, so just return
		if (pPaneFont != NULL)
		{
			if (m_ColorArray[nIndex]==::GetSysColor(COLOR_BTNTEXT))
			{
				UINT nID, nStyle;
				int cxWidth;
				GetPaneInfo(nIndex, nID, nStyle, cxWidth);
				nStyle &= ~SBT_OWNERDRAW;
				SetPaneInfo(nIndex, nID, nStyle, cxWidth);
			}

			delete pPaneFont;
			m_PaneFont[nIndex]=NULL;
		}

		return TRUE;
	}

	// Create a new font object for this pane
	pPaneFont=new CFont;
	// Assign this font to the pane
	m_PaneFont[nIndex]=pPaneFont;
	LOGFONT logFont;                                // Logical font struct
	pFont->GetObject(sizeof(LOGFONT), &logFont);
	if (!pPaneFont->CreateFontIndirect(&logFont))
	{
		TRACE(_T("In COXStatusBar::SetPaneFont : Failed to create the font for pane %d\n"), nIndex);
		delete pPaneFont;
		m_PaneFont[nIndex]=NULL;
		return FALSE;
	}

	UINT nID, nStyle;
	int cxWidth;
	GetPaneInfo(nIndex, nID, nStyle, cxWidth);
	nStyle |= SBT_OWNERDRAW;
	SetPaneInfo(nIndex, nID, nStyle, cxWidth);

	return TRUE;
}

BOOL COXStatusBar::SetPaneText(int nIndex, LPCTSTR lpszNewText,
	COLORREF clrTextColor /*=::GetSysColor(COLOR_BTNTEXT) */, BOOL bUpdate /*=TRUE */)
{
	BOOL bSuccess=CStatusBar::SetPaneText(nIndex, lpszNewText, bUpdate);
	if (!bSuccess)
		return FALSE;

	// changing the textcolor requires an ownerdrawn style
	if (clrTextColor != m_ColorArray[nIndex] && m_PaneFont[nIndex]==NULL)
	{
		UINT nID, nStyle;
		int cxWidth;
		GetPaneInfo(nIndex, nID, nStyle, cxWidth);
		// if the color is changed back to the default stausbar text color,
		// remove the OWNERDRAWN style
		if (clrTextColor != ::GetSysColor(COLOR_BTNTEXT))
			nStyle |= SBT_OWNERDRAW;
		else
			nStyle &= ~SBT_OWNERDRAW;

		m_ColorArray[nIndex]=clrTextColor;

		SetPaneInfo(nIndex, nID, nStyle, cxWidth);
		}
	else
		m_ColorArray[nIndex]=clrTextColor;

	return TRUE;
	}

void COXStatusBar::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
	{
	ASSERT(TRUE);
	
	// You should get the pointer to the device context from the "lpDrawItemStruct" ptr.
	CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);

	int nOldBkMode=pDC->SetBkMode(TRANSPARENT);
	CFont* pPaneFont=(CFont*)m_PaneFont[lpDrawItemStruct->itemID];
	CFont* pOldFont=NULL;

	if (pPaneFont == NULL)
	{
		pPaneFont = GetFont();
	}

	if (pPaneFont != NULL)
	{
		pOldFont=pDC->SelectObject(pPaneFont);
		ASSERT(pOldFont != NULL);
	}

	COLORREF clrOldTextColor=
		pDC->SetTextColor(m_ColorArray[lpDrawItemStruct->itemID]);

	CString PaneText=GetPaneText(lpDrawItemStruct->itemID);
	CSize sStrSize=pDC->GetTextExtent(PaneText);
	pDC->TextOut(lpDrawItemStruct->rcItem.left + 2, lpDrawItemStruct->rcItem.top +
		((lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top - sStrSize.cy) / 2), PaneText);
	pDC->SetTextColor(clrOldTextColor);
	if (pOldFont != NULL)
		pDC->SelectObject(pOldFont);

	pDC->SetBkMode(nOldBkMode);
	}

void COXStatusBar::OnPaint()
{
	GetStatusbarSkin()->OnPaintStatusbar( this );
}

AFX_STATUSPANE* COXStatusBar::_GetPanePtr(int nIndex) const
	{
	ASSERT(nIndex >= 0 && nIndex < m_nCount);
	ASSERT(m_pData != NULL);
	return ((AFX_STATUSPANE*)m_pData) + nIndex;
	}

BOOL COXStatusBar::SetIndicators(const UINT FAR* lpIDArray, int nIDCount)
	{
	// Init the Bitmap array
	int i=0;
	for(i=0; i < nIDCount;i++)
		{
		m_PaneBmp.SetAtGrow(i, NULL);
		}
		
	// Init the Bitmap array
	for(i=0; i < nIDCount;i++)
		{
		m_PaneFont.SetAtGrow(i, NULL);
		}

	// Init the Color array
	for(int j=0; j < nIDCount;j++)
		{
		m_ColorArray.SetAtGrow(j, ::GetSysColor(COLOR_BTNTEXT));
		}
		
	// Init the Progress array
	for(int k=0; k < nIDCount;k++)
		{
		m_EvolArray.SetAtGrow(k, NULL);
		}

	// Init the ToolTip array
	m_TipArray.SetSize(nIDCount);

	// Init the Cursor array
	for(i=0; i < nIDCount;i++)
		{
		m_CursorArray.SetAtGrow(i, NULL);
		}

	return CStatusBar::SetIndicators(lpIDArray, nIDCount);
	}  


BOOL COXStatusBar::SetPaneBitmap(int nIndex, UINT nIDResource , 
								 EOrientation eBMPOrient /*=EO_CenterFit */,
								 COLORREF clrMask /*=RGB(255,255,255) */, 
								 BOOL bUpdate /*=TRUE */)
	{
	CRect rect;
	BOOL bSucces=TRUE;
	
	ASSERT((EO_FIRST <= (int)eBMPOrient) && ((int) eBMPOrient <= EO_LAST));
	CBmpInfo* pBmpInfo=(CBmpInfo*)m_PaneBmp[nIndex];

	// First Check whether we want to remove the bitmap from this pane
	if(nIDResource==0)
		{
		if(pBmpInfo != NULL)
			{
			m_PaneBmp[nIndex]=NULL;
			pBmpInfo->m_pBitmap->DeleteObject();
			delete pBmpInfo->m_pBitmap;
			delete pBmpInfo;
			}

		}
	else
		{
		if(pBmpInfo==NULL)
			// The pane we're referring to, has no bitmap assigned to it yet.
			{
			// The CBmpInfo is the class where all bitmap info will be stored
			pBmpInfo=new CBmpInfo;
			pBmpInfo->m_pBitmap=new CBitmap;
			if (!pBmpInfo->m_pBitmap->LoadBitmap(nIDResource))
				{
				delete pBmpInfo->m_pBitmap;
				delete pBmpInfo;
				pBmpInfo=NULL;
				//////////
				// if we set pBmpInfo to NULL we steel have some info 
				// in m_PaneBmp[nIndex]
				///////
				m_PaneBmp[nIndex]=NULL;
				bSucces=FALSE;
				TRACE0("COXStatusBar::SetPaneBitmap: Cannot load bitmap resource!");
				////////////////////////
				}
			//// 
			}
		else 
			{
			if (pBmpInfo->m_nIDResource != nIDResource)
				{
				pBmpInfo->m_pBitmap->DeleteObject();
				//////////
				// if we set pBmpInfo to NULL we steel have some info in m_PaneBmp[nIndex]
				///////
				if(!pBmpInfo->m_pBitmap->LoadBitmap(nIDResource))
					{
					delete pBmpInfo->m_pBitmap;
					delete pBmpInfo;
					pBmpInfo=NULL;
					m_PaneBmp[nIndex]=NULL;
					bSucces=FALSE;
					TRACE0("COXStatusBar::SetPaneBitmap: Cannot load bitmap resource!");
					// have to update pane
				    GetItemRect(nIndex, &rect);  // get pane rect
					InvalidateRect(rect, FALSE);
					}
				////////////////////////
				}
			}
			
		if(!bSucces)
    		return FALSE;
    
		// must exist and a pane with a bitmap does not have text
		ASSERT(pBmpInfo != NULL);
		CStatusBar::SetPaneText(nIndex, _T(""));

		// Set the background color
		pBmpInfo->m_clrMask=clrMask;
		// Store the resource ID of the loaded bitmap
		pBmpInfo->m_nIDResource=nIDResource;
		// Reset the size of the bitmap
		pBmpInfo->m_BmpSize.cx=0;
		pBmpInfo->m_BmpSize.cy=0;
    
		// Set bitmap Layout and determine true size of bitmap
		pBmpInfo->m_eBmpOrien=eBMPOrient;
		BITMAP bm;
		pBmpInfo->m_pBitmap->GetObject(sizeof(bm), &bm);
		pBmpInfo->m_BmpSize=CSize(bm.bmWidth, bm.bmHeight);

		// Assign this Bitmap Info to the pane
		m_PaneBmp[nIndex]=pBmpInfo;
		}


	// Adding, removing or changing a Bitmap can cause a pane to grow or shrink.
	// Could influence the stored rects for the evolution panes, so recalc them
	UpdateAllPanes(TRUE, FALSE);

	if(bUpdate)
	{
		// Changed because otherwise moving the orientation would not invalidate the old region
		Invalidate(TRUE);
//	    GetItemRect(nIndex, &rect);  // get pane rect
//		InvalidateRect(rect, FALSE);
	}
	
	return TRUE;
	}


void COXStatusBar::UpdateAllPanes(BOOL bUpdateRects, BOOL bUpdateText)
{
	ASSERT_VALID(this);
	ASSERT(::IsWindow(m_hWnd));

	// update the status pane locations
	if (bUpdateRects)
	{
		// get border information and client work area
		CRect rect; GetWindowRect(rect);
		rect.OffsetRect(-rect.left, -rect.top);
		CalcInsideRect(rect, TRUE);
		int rgBorders[3];
		VERIFY((BOOL)DefWindowProc(SB_GETBORDERS, 0, (LPARAM)&rgBorders));

		// determine extra space for stretchy pane
		int cxExtra=rect.Width() + rgBorders[2];
		int nStretchyCount=0;
		AFX_STATUSPANE* pSBP=_GetPanePtr(0);
		int i=0;
		for (i=0; i < m_nCount; i++)
		{
			if (pSBP->nStyle & SBPS_STRETCH)
				++nStretchyCount;
			cxExtra -= (pSBP->cxText+CX_PANE_BORDER + rgBorders[2]);
			++pSBP;
		}

		// determine right edge of each pane
		int* rgRights=(int*)_alloca(m_nCount * sizeof(int));
		int right=rgBorders[0];
		pSBP=_GetPanePtr(0);
		for (i=0; i < m_nCount; i++)
		{
			// determine size of the pane
			ASSERT(pSBP->cxText >= 0);

			right += pSBP->cxText+CX_PANE_BORDER;
			if ((pSBP->nStyle & SBPS_STRETCH) && cxExtra > 0)
			{
				ASSERT(nStretchyCount != 0);
				int cxAddExtra=cxExtra / nStretchyCount;
				right += cxAddExtra;
				--nStretchyCount;
				cxExtra -= cxAddExtra;
			}
			rgRights[i]=right;

			// next pane
			++pSBP;
			right += rgBorders[2];
		}

		// set new right edges for all panes
		DefWindowProc(SB_SETPARTS, m_nCount, (LPARAM)rgRights);

		// Move all ProgressWindow Ctrls
		pSBP=_GetPanePtr(0);
		CEvolInfo* pEvolInfo=NULL;

		for (i=0; i < m_nCount; i++)
		{
			pEvolInfo=(CEvolInfo*)m_EvolArray[i];
			if (pEvolInfo != NULL)
			{
				if (pSBP->nStyle & SBPS_PERCENT)
				{
					CDC* pDC=GetDC();
					CFont* pPaneFont=(CFont*)m_PaneFont[i];
					CFont* pOldFont=NULL;
					if(pPaneFont!=NULL)
						pOldFont=pDC->SelectObject(pPaneFont);
					CRect rect(0, 0, 0, 0);
					pDC->DrawText(_T("999%"),rect,DT_CALCRECT|DT_SINGLELINE|DT_LEFT);
					if(pOldFont!=NULL)
						pDC->SelectObject(pOldFont);
					ReleaseDC(pDC);
		
					if (!pEvolInfo->m_bRectInitialized)
						pEvolInfo->m_bRectInitialized=CreateEvolutionPane(i,pEvolInfo);
					if (pEvolInfo->m_bRectInitialized && 
						CalcInsideBorder(i, pEvolInfo->m_ProgressRect, TRUE))
					{
						if (pEvolInfo->m_bPercentText)
							pEvolInfo->m_ProgressRect.left+=rect.Width(); 

						pEvolInfo->m_ProgressPane.SetWindowPos(NULL,
							pEvolInfo->m_ProgressRect.left, 
							pEvolInfo->m_ProgressRect.top,
							pEvolInfo->m_ProgressRect.Width(), 
							pEvolInfo->m_ProgressRect.Height(),
							SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
					}
				}
			}

			// next pane
			++pSBP;
		}

	}

	// update text in the status panes if specified
	if (bUpdateText)
	{
		AFX_STATUSPANE* pSBP=_GetPanePtr(0);
		for (int i=0; i < m_nCount; i++)
		{
			if (pSBP->nFlags & SBPF_UPDATE)
				CStatusBar::SetPaneText(i, pSBP->strText);

			++pSBP;
		}
		
	}
}

BOOL COXStatusBar::CalcInsideBorder(int nIndex, CRect& PaneRect, BOOL bEvolutionBar)
	// --- In  : nIndex : the pane specified
	// --- Out : PaneRect : will receive the coordinates of the space of a pane within its borders
	// --- Returns : succeeded or not
	// --- Effect : calculate the coordinates of the space of a pane within the borders of this pane
{
	int rgBorders[3];
	VERIFY((BOOL)DefWindowProc(SB_GETBORDERS, 0, (LPARAM)&rgBorders));

	GetItemRect(nIndex, PaneRect);  // get pane rect
	if (PaneRect.IsRectEmpty())
		return FALSE;

	// adjust the itemrect to exclude the borders
	PaneRect.left=PaneRect.left + rgBorders[2];
	PaneRect.top=PaneRect.top + rgBorders[0] + 1;
	PaneRect.right -= rgBorders[2];
	PaneRect.bottom -= rgBorders[0] + 1;
	if(bEvolutionBar)
	{
		PaneRect.bottom--;
	}

	return TRUE;
}

void COXStatusBar::SetBarProgress(int nIndex, BOOL bUpdate/*=TRUE*/, 
								  DWORD dwTotal/*=100*/, DWORD dwDone/*=0*/)
{
	// bUpdate not used anymore, but still there to provide compatibility
	// this line was added to avoid compiler warning
	UNREFERENCED_PARAMETER(bUpdate);

	ASSERT(dwDone <= dwTotal);

	CEvolInfo* pEvolInfo=(CEvolInfo*)m_EvolArray[nIndex];
	if (pEvolInfo==NULL)
	{
		TRACE(_T("The pane '%i'has never been SetUp as a progress pane\n"), nIndex);
		return; 
	}

	pEvolInfo->m_bRectInitialized=CreateEvolutionPane(nIndex, pEvolInfo);
	if (!pEvolInfo->m_bRectInitialized)
		 return;

	// Adjust the progresscontrol
#if _MFC_VER>0x0421
	pEvolInfo->m_ProgressPane.SetRange32(0,dwTotal);
#else
	pEvolInfo->m_ProgressPane.SetRange(0,dwTotal);
#endif
	pEvolInfo->m_ProgressPane.SetPos(dwDone);

	if (dwTotal > 0)
		pEvolInfo->m_nPercentDone=(unsigned short)((dwDone * 100) / dwTotal);
	else
		pEvolInfo->m_nPercentDone=0;
	
	if (pEvolInfo->m_bPercentText)
	{
		// Setting the text for this caused the entire pane to,be invalidated
		// Invalidate only the part designated for the text, so we avoid nasty 
		// screen flashes
		//
		SetRedraw(FALSE);
		// Draw the percentage text
		TCHAR tmpBuf[5];
		UTBStr::stprintf(tmpBuf, 5, _T("%d%%"),pEvolInfo->m_nPercentDone);
		CStatusBar::SetPaneText(nIndex, tmpBuf);

		SetRedraw(TRUE);

		CRect rect;
		GetItemRect(nIndex,rect);
		rect.right=pEvolInfo->m_ProgressRect.left-1;
		InvalidateRect(rect);
		//
		////////////////////////////////
	}
}

void COXStatusBar::ResetBar(int nIndex, BOOL bDestroy /*=FALSE */)
{
	if(m_EvolArray[nIndex] != NULL)
	{
		if (bDestroy)
		{
			CEvolInfo* pEvolInfo=(CEvolInfo*)m_EvolArray[nIndex];
			delete pEvolInfo;
			m_EvolArray[nIndex]=NULL;
			CStatusBar::SetPaneText(nIndex, _T(""));
		}

		//	Redraw the frame control under the gauge
		SetBarProgress(nIndex, TRUE, 100, 0);
	}
}

BOOL COXStatusBar::SetUpBar(int nIndex, BOOL bUpdate /*=TRUE */, 
							BOOL bPercentText /*=TRUE */)
{
	UNREFERENCED_PARAMETER(bUpdate);

	CEvolInfo*	pEvolutionInfo;
	if(m_EvolArray[nIndex] != NULL)
	{
		pEvolutionInfo=(CEvolInfo*)m_EvolArray[nIndex];
		delete pEvolutionInfo;
		m_EvolArray[nIndex]=NULL;
	}
	
	if(m_EvolArray[nIndex]==NULL)
		// a new progress ctrl has to be created
	{
		pEvolutionInfo=new CEvolInfo;
		m_EvolArray[nIndex]=pEvolutionInfo;
		pEvolutionInfo->m_nPercentDone=0;
		pEvolutionInfo->m_ProgressRect.SetRectEmpty();
		pEvolutionInfo->m_bPercentText=bPercentText;
		pEvolutionInfo->m_bRectInitialized=FALSE;

		pEvolutionInfo->m_bRectInitialized=CreateEvolutionPane(nIndex, pEvolutionInfo);
    }
	else 
		ResetBar(nIndex);

	return TRUE;
}

BOOL COXStatusBar::CreateEvolutionPane(int nIndex, CEvolInfo* pEvolInfo)
{
	if (pEvolInfo->m_bRectInitialized)
		return TRUE;

	// subtract the borders
	if (!CalcInsideBorder(nIndex, pEvolInfo->m_ProgressRect, TRUE))
		return FALSE;

	if (pEvolInfo->m_bPercentText)
	{
		CDC* pDC=GetDC();
		CFont* pPaneFont=(CFont*)m_PaneFont[nIndex];
		CFont* pOldFont=NULL;
		if(pPaneFont!=NULL)
			pOldFont=pDC->SelectObject(pPaneFont);
		CRect rect(0, 0, 0, 0);
		pDC->DrawText(_T("999%"),rect,DT_CALCRECT|DT_SINGLELINE|DT_LEFT);
		if(pOldFont!=NULL)
			pDC->SelectObject(pOldFont);
		pEvolInfo->m_ProgressRect.left+=rect.Width();

		ReleaseDC(pDC);
	}

	CStatusBar::SetPaneText(nIndex, _T(""));

	if (!pEvolInfo->m_ProgressPane.Create(WS_CHILD | WS_VISIBLE,
		pEvolInfo->m_ProgressRect, this, nIndex))
	{
		TRACE(_T("In COXStatusBar::SetUpBar : Could not create a progressctrl for pane %i\n"), nIndex);
		return FALSE;
	}

	//Remove the WS_EX_STATICEDGE extended style that's automatically
	//added by internal Win32 drawing code - Nish Feb 10, 2005
	pEvolInfo->m_ProgressPane.ModifyStyleEx(WS_EX_STATICEDGE, NULL, SWP_FRAMECHANGED);

	return TRUE;
}

BOOL COXStatusBar::ActivatePaneTips(BOOL bActivate)
{
	EnableToolTips(bActivate);
	
	return TRUE;
}

BOOL COXStatusBar::SetPaneTip(int nIndex, LPCTSTR lpszNewPaneTip)
{
	ASSERT(lpszNewPaneTip != NULL);

	//add the text to the tooltip array
	m_TipArray.SetAt(nIndex, lpszNewPaneTip);
	
	return TRUE;
}

BOOL COXStatusBar::DeletePaneTip(int nIndex)
{
	//remove the text out of the tooltip array
	m_TipArray.SetAt(nIndex, _T(""));
	
	return TRUE;
}

void COXStatusBar::SetPaneStyle(int nIndex, UINT nStyle)
{
	AFX_STATUSPANE* pSBP=_GetPanePtr(nIndex);
	if (pSBP->nStyle != nStyle)
	{
		pSBP->nFlags |= SBPF_UPDATE;
		// use SetPaneText, since it updates the style and text
		if ((pSBP->nStyle ^ nStyle) & SBPS_STRETCH)
		{
			pSBP->nStyle=nStyle;
			UpdateAllPanes(TRUE, /*FALSE*/TRUE);
		}
		else
		{
			pSBP->nStyle=nStyle;
//			pSBP->nFlags |= SBPF_UPDATE;
			CStatusBar::SetPaneText(nIndex, pSBP->strText);
		}
		RedrawWindow();
	}
}

void COXStatusBar::SetPaneInfo(int nIndex, UINT nID, UINT nStyle, int cxWidth)
{
	ASSERT_VALID(this);

	BOOL bChanged=FALSE;
	AFX_STATUSPANE* pSBP=_GetPanePtr(nIndex);
	pSBP->nID=nID;
	if (pSBP->nStyle != nStyle)
	{
		if ((pSBP->nStyle ^ nStyle) & SBPS_STRETCH)
			bChanged=TRUE;
		else
		{
			pSBP->nStyle=nStyle;
			pSBP->nFlags |= SBPF_UPDATE;
			CStatusBar::SetPaneText(nIndex, pSBP->strText);
		}
		pSBP->nStyle=nStyle;
	}
	
	if (cxWidth != pSBP->cxText)
	{
		// change width of one pane -> invalidate the entire status bar
		pSBP->cxText=cxWidth;
		bChanged=TRUE;
	}
	
	if (bChanged)
		UpdateAllPanes(TRUE, FALSE);
}

void PASCAL COXStatusBar::DrawStatusBmp(CDC* pDC,int nPane , UINT nStyle)
	// --- In  : pDC : the device context to draw on
	//			 rect : the client coordinates of the pane to draw
	//			 nPane : the index of the pane to draw
	//			 nStyle : the style of the pane
	// --- Out : 
	// --- Returns :
	// --- Effect : Draws a standard 3D pane with a Bitmap in it
	{
	ASSERT(pDC->m_hDC != NULL);
	CBmpInfo* pBMPInfo=(CBmpInfo*)m_PaneBmp[nPane];
	ASSERT(pBMPInfo != NULL);
	
    if(!(nStyle & SBPS_DISABLED))
    	{
		CRect rectPane, rcDestBMP;
		CSize szSourceBMP;

		CalcInsideBorder(nPane, rectPane);

		// Calculate origin of bitmap drawing within panerect
		int WidthDiff=rectPane.Width() - pBMPInfo->m_BmpSize.cx;
		int HeightDiff=rectPane.Height() - pBMPInfo->m_BmpSize.cy;
		CSize BMPDrawSize (WidthDiff > 0 ? pBMPInfo->m_BmpSize.cx : rectPane.Width(),
						   HeightDiff > 0 ? pBMPInfo->m_BmpSize.cy : rectPane.Height());

		CPoint BMPDrawOrigin=rectPane.TopLeft();
		BMPDrawOrigin.y=HeightDiff > 0 ? BMPDrawOrigin.y + HeightDiff / 2 : BMPDrawOrigin.y;
		rcDestBMP=CRect(BMPDrawOrigin, BMPDrawSize);
		szSourceBMP=pBMPInfo->m_BmpSize;

		switch(pBMPInfo->m_eBmpOrien)
			{
			case EO_Stretch:
				rcDestBMP=rectPane;
				break;
			case EO_CenterClip:
				szSourceBMP=rcDestBMP.Size();
			case EO_CenterFit:
				rcDestBMP.OffsetRect(WidthDiff > 0 ? WidthDiff / 2 : 0, 0);
				break;
			case EO_RightClip:
				szSourceBMP=rcDestBMP.Size();
			case EO_RightFit:
				rcDestBMP.OffsetRect(WidthDiff > 0 ? WidthDiff : 0, 0);
				break;
			case EO_LeftClip:
				szSourceBMP=rcDestBMP.Size();
			case EO_LeftFit:
				break;
			default:
				ASSERT(FALSE);
			}

		DrawTranspBitmap(pDC, pBMPInfo, rcDestBMP, szSourceBMP);
		}
		
	}

void COXStatusBar::DrawTranspBitmap(CDC* pDC, CBmpInfo* pInfo, CRect& rcDrawBMP, CSize& szSrcBMP)
	{
	ASSERT(pDC != NULL);
	ASSERT(pInfo != NULL);

	CBitmap    bmAndBack, bmAndObject, bmAndMem, bmSave;
	CDC        dcMem, dcBack, dcObject, dcTemp, dcSave;

	VERIFY(dcTemp.CreateCompatibleDC(pDC));
	dcTemp.SelectObject(pInfo->m_pBitmap);   // Select the bitmap

	CSize TempSize=pInfo->m_BmpSize;
	dcTemp.DPtoLP(&TempSize);     // Convert from device
		   						  // to logical points

	// Create some DCs to hold temporary data.
	VERIFY(dcBack.CreateCompatibleDC(pDC));
	VERIFY(dcObject.CreateCompatibleDC(pDC));
	VERIFY(dcMem.CreateCompatibleDC(pDC));
	VERIFY(dcSave.CreateCompatibleDC(pDC));

	// Create a bitmap for each DC. DCs are required for a number of
	// GDI functions.

	// Monochrome DC
	VERIFY(bmAndBack.CreateBitmap(TempSize.cx, TempSize.cy, 1, 1, NULL));

	// Monochrome DC
	VERIFY(bmAndObject.CreateBitmap(TempSize.cx, TempSize.cy, 1, 1, NULL));

	VERIFY(bmAndMem.CreateCompatibleBitmap(pDC, TempSize.cx, TempSize.cy));
	VERIFY(bmSave.CreateCompatibleBitmap(pDC, TempSize.cx, TempSize.cy));

	// Each DC must select a bitmap object to store pixel data.
	CBitmap* pbmBackOld  =dcBack.SelectObject(&bmAndBack);
	CBitmap* pbmObjectOld=dcObject.SelectObject(&bmAndObject);
	CBitmap* pbmMemOld   =dcMem.SelectObject(&bmAndMem);
	CBitmap* pbmSaveOld  =dcSave.SelectObject(&bmSave);

	// Set proper mapping mode.
	dcTemp.SetMapMode(pDC->GetMapMode());

	// Save the bitmap sent here, because it will be overwritten.
	dcSave.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcTemp, 0, 0, SRCCOPY);

	// Set the background color of the source DC to the color.
	// contained in the parts of the bitmap that should be transparent
	COLORREF clrOldBkColor=dcTemp.SetBkColor(pInfo->m_clrMask);

	// Create the object mask for the bitmap by performing a BitBlt
	// from the source bitmap to a monochrome bitmap.
	dcObject.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcTemp, 0, 0, SRCCOPY);

	// Set the background color of the source DC back to the original
	// color.
	dcTemp.SetBkColor(clrOldBkColor);

	// Create the inverse of the object mask.
	dcBack.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcObject, 0, 0, NOTSRCCOPY);

	// Copy the background of the main DC to the destination.
//	dcMem.BitBlt(0, 0, TempSize.cx, TempSize.cy, pDC, rcDrawBMP.left, rcDrawBMP.top-2, SRCCOPY);
	dcMem.StretchBlt(0, 0, TempSize.cx, TempSize.cy, pDC, 
		rcDrawBMP.left, rcDrawBMP.top, rcDrawBMP.Width(), rcDrawBMP.Height(), SRCCOPY);

	// Mask out the places where the bitmap will be placed.
	dcMem.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcObject, 0, 0, SRCAND);

	// Mask out the transparent colored pixels on the bitmap.
	dcTemp.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcBack, 0, 0, SRCAND);

	// XOR the bitmap with the background on the destination DC.
	dcMem.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcTemp, 0, 0, SRCPAINT);

	// Copy the destination to the screen.
	pDC->StretchBlt(rcDrawBMP.left, rcDrawBMP.top, rcDrawBMP.Width(), rcDrawBMP.Height(), 
		&dcMem, 0, 0 ,szSrcBMP.cx, szSrcBMP.cy, SRCCOPY);

	// Place the original bitmap back into the bitmap sent here.
	dcTemp.BitBlt(0, 0, TempSize.cx, TempSize.cy, &dcSave, 0, 0, SRCCOPY);

	// Delete the memory bitmaps.
	CBitmap* pTempBmp=NULL;
	pTempBmp=dcBack.SelectObject(pbmBackOld);
	ASSERT(pTempBmp != NULL);
	pTempBmp->DeleteObject();
	pTempBmp=dcObject.SelectObject(pbmObjectOld);
	ASSERT(pTempBmp != NULL);
	pTempBmp->DeleteObject();
	pTempBmp=dcMem.SelectObject(pbmMemOld);
	ASSERT(pTempBmp != NULL);
	pTempBmp->DeleteObject();
	pTempBmp=dcSave.SelectObject(pbmSaveOld);
	ASSERT(pTempBmp != NULL);
	pTempBmp->DeleteObject();

	// Delete the memory DCs.
	dcMem.DeleteDC();
	dcBack.DeleteDC();
	dcObject.DeleteDC();
	dcSave.DeleteDC();
	dcTemp.DeleteDC();
	}

BEGIN_MESSAGE_MAP(COXStatusBar, CStatusBar)
	//{{AFX_MSG_MAP(COXStatusBar)
	ON_WM_LBUTTONDBLCLK()
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_SETCURSOR()
	ON_MESSAGE(SB_SETMINHEIGHT, OnSetMinHeight)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

LRESULT COXStatusBar::OnSetMinHeight(WPARAM wParam, LPARAM)
	{
	LRESULT lResult=Default();
	
	// MFC does not allow a height smaller than the font height
	m_nMinHeight=PtrToInt(wParam);
	
	return lResult;
	}

void COXStatusBar::OnSize(UINT nType, int cx, int cy)
{
	ASSERT_VALID(this);
	ASSERT(::IsWindow(m_hWnd));

	CControlBar::OnSize(nType, cx, cy);

	// need to adjust pane right edges (because of stretchy pane)
	if (m_nCount > 0)
		UpdateAllPanes(TRUE, TRUE);

	/////////////
	// fixed: 15.01.1998
	// bitmap does not refresh correctly if you size
	// (horizontally) the application window.  If you reduce the width of the
	// window to hide the bitmap and then expand the width to show it, the bitmap
	// is not always refreshed
	///////////
	// redraw panes with bitmaps
	CRect rect;
	for (int nIndex=0; nIndex < m_nCount; nIndex++)
	{
		GetItemRect(nIndex, &rect);  // get pane rect
		InvalidateRect(rect, FALSE);
	}
	/////////////////////
}

void COXStatusBar::OnLButtonDblClk(UINT nFlags, CPoint point)
	{
	UNREFERENCED_PARAMETER(nFlags);

	CRect PaneRect;
	// first walk through to calculate extra space
	for (int i=0; i < m_nCount; i++)
		{
		GetItemRect(i, PaneRect);
		if (PaneRect.PtInRect(point) != 0)
			{
			GetParent()->SendMessage(WM_STAT_DBLCLICK, (WPARAM)GetItemID(i));
			break;
			}
		}
	
	}

OXINTRET COXStatusBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
	{

	int key=GetAsyncKeyState(VK_LBUTTON);
	if(key&0x8001) 
	{
		return -1;
	}

	ASSERT_VALID(this);
	ASSERT(::IsWindow(m_hWnd));
	CRect PaneRect;

	// check child windows first by calling CControlBar
	int nHit= PtrToInt(CControlBar::OnToolHitTest(point, pTI));
	if (nHit != -1)
		{
		if (pTI != NULL)
			{
			pTI->uFlags &= ~TTF_NOTBUTTON;
			pTI->uFlags &= ~TTF_CENTERTIP;

			pTI->lpszText=_tcsdup(m_TipArray.GetAt(nHit));
			}

		return nHit + m_nCount;  // register a different toolinfo struct than the percent text
		}

	// now hit test against Panes of Statusbar
	for (int i=0; i < m_nCount; i++)
		{
		GetItemRect(i, PaneRect);
		if (PaneRect.PtInRect(point))
			{
			if (pTI != NULL)
				{
				pTI->hwnd=m_hWnd;
				pTI->rect=PaneRect;
				pTI->lpszText=_tcsdup(m_TipArray.GetAt(i));
				}
			
			// found matching rect, return the ID of the Pane
			return GetItemID(i);
			}
		}
	
	return -1;
	}

BOOL COXStatusBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
	{
	if (nHitTest==HTCLIENT)
		{
		DWORD dwMessagePos=::GetMessagePos();
		CPoint point(GET_X_LPARAM(dwMessagePos),GET_Y_LPARAM(dwMessagePos));
		ScreenToClient(&point);

		// Walk through all panes to find match
		CRect PaneRect;
		int i=0;
		for (i=0; i < m_nCount; i++)
			{
			GetItemRect(i, PaneRect);
			if (PaneRect.PtInRect(point) != 0)
				break;
			}

		if (i < m_nCount && m_CursorArray[i] != NULL)
			{
			::SetCursor((HCURSOR)(INT_PTR)m_CursorArray[i]);
			// ... We handled the message
			return TRUE;
			}
		}

	// ... Call base class implementation
	return CStatusBar::OnSetCursor(pWnd, nHitTest, message);
	}

int COXStatusBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
	{
	if (CStatusBar::OnCreate(lpCreateStruct)==-1)
		return -1;
	
	if (!m_srcDC.CreateCompatibleDC(NULL))
		return -1;
	
	return 0;
	}

COXStatusbarSkin* COXStatusBar::GetStatusbarSkin()
{
	// Check if the app is derived from COXSkinnedApp
	COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp());
	if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL)
		return pSkinnedApp->GetCurrentSkin()->GetStatusbarSkin();
	else
	{
		// Create a classic skin for this class if not created already
		if (m_pStatusbarSkin == NULL)
			m_pStatusbarSkin = new COXStatusbarSkinClassic();

		return m_pStatusbarSkin;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions