1140 lines
29 KiB
C++
1140 lines
29 KiB
C++
// ==========================================================================
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int 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;
|
|
}
|
|
}
|