windows-nt/Source/XPSP1/NT/shell/osshell/accesory/mspaint/bar.cpp
2020-09-26 16:20:57 +08:00

734 lines
24 KiB
C++

/******************************************************************************/
/* Bar.CPP: IMPLEMENTATION OF THE CStatBar (Status Bar) CLASS */
/* */
/******************************************************************************/
/* */
/* Methods in this file */
/* */
/* CStatBar::CStatBar */
/* CStatBar::~CStatBar */
/* CStatBar::Create */
/* CStatBar::OnSetFont */
/* CStatBar::DoPaint */
/* CStatBar::DrawStatusText */
/* CStatBar::SetText */
/* CStatBar::SetPosition */
/* CStatBar::SetSize */
/* CStatBar::ClearPosition */
/* CStatBar::ClearSize */
/* CStatBar::Reset */
/* CStatBar::OnPaletteChanged */
/* */
/* */
/* Functions in this file */
/* */
/* ClearStatusBarSize */
/* ClearStatusBarPosition */
/* SetPrompt */
/* SetPrompt */
/* ShowStatusBar */
/* IsStatusBarVisible */
/* GetStatusBarHeight */
/* InvalidateStatusBar */
/* ClearStatusBarPositionAndSize */
/* ResetStatusBar */
/* SetStatusBarPosition */
/* SetStatusBarSize */
/* SetStatusBarPositionAndSize */
/* */
/******************************************************************************/
#include "stdafx.h"
#include "global.h"
#include "pbrush.h"
#include "pbrusfrm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC( CStatBar, CStatusBar )
#include "memtrace.h"
CStatBar *g_pStatBarWnd = NULL;
static UINT BASED_CODE indicators[] =
{
ID_SEPARATOR, // status line indicator
IDB_SBPOS,
IDB_SBSIZE
};
BEGIN_MESSAGE_MAP( CStatBar, CStatusBar )
ON_WM_SYSCOLORCHANGE()
ON_MESSAGE(WM_SETFONT, OnSetFont)
ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
ON_WM_NCDESTROY()
END_MESSAGE_MAP()
static int miSlackSpace;
/******************************************************************************/
CStatBar::CStatBar()
{
m_iBitmapWidth = 0;
m_iBitmapHeight = 0;
miSlackSpace = 0;
m_iSizeY = 0;
}
CStatBar::~CStatBar()
{
// Ensure that the CControlBar doesn't assert trying access our parent
// object (CPBFrame) during the destruction of our parent object.
m_pDockSite = NULL;
}
/******************************************************************************/
BOOL CStatBar::Create( CWnd* pParentWnd )
{
BOOL bRC = TRUE;
int cxStatBar; // width of a char in the status bar
// Create the status Bar Window.
bRC = CStatusBar::Create(pParentWnd);
ASSERT (bRC != FALSE);
if (bRC != FALSE)
{
// Set the Pane Indicators.
bRC = SetIndicators( indicators, sizeof( indicators ) / sizeof( UINT ) );
ASSERT( bRC != FALSE );
if (bRC != FALSE)
{
TRY
{
// Load the Separator Strings
VERIFY(m_cstringSizeSeparator.LoadString(IDS_SIZE_SEPARATOR));
VERIFY(m_cstringPosSeparator.LoadString(IDS_POS_SEPARATOR));
}
CATCH(CMemoryException,e)
{
m_cstringSizeSeparator.Empty();
m_cstringPosSeparator.Empty();
}
END_CATCH
// Load the Position and Size Bitmaps
VERIFY(m_posBitmap.LoadBitmap(IDB_SBPOS));
VERIFY(m_sizeBitmap.LoadBitmap(IDB_SBSIZE));
if ( (m_posBitmap.GetSafeHandle() != NULL) &&
(m_sizeBitmap.GetSafeHandle() != NULL) )
{
//Calculate the size of the pane and set them
CClientDC dc(this);
/*DK* What font to select? */
/*DK* What to do if in foreign Language, Size "0"? */
cxStatBar = (dc.GetTextExtent(TEXT("0"), 1)).cx;
BITMAP bmp;
m_posBitmap.GetObject(sizeof (BITMAP), &bmp);
m_iBitmapWidth = bmp.bmWidth;
m_iBitmapHeight = bmp.bmHeight;
int iPaneWidth;
UINT uiID, uiStyle;
GetPaneInfo( 0, uiID, uiStyle, iPaneWidth) ;
SetPaneInfo( 0, uiID, SBPS_NORMAL | SBPS_STRETCH, iPaneWidth );
GetPaneInfo(1, uiID, uiStyle, iPaneWidth);
if (iPaneWidth < bmp.bmWidth + (SIZE_POS_PANE_WIDTH * cxStatBar))
{
iPaneWidth = bmp.bmWidth + (SIZE_POS_PANE_WIDTH * cxStatBar);
SetPaneInfo(1, uiID, uiStyle, iPaneWidth);
}
GetPaneInfo(2, uiID, uiStyle, iPaneWidth);
if (iPaneWidth < bmp.bmWidth + (SIZE_POS_PANE_WIDTH * cxStatBar))
{
iPaneWidth = bmp.bmWidth + (SIZE_POS_PANE_WIDTH * cxStatBar);
SetPaneInfo(2, uiID, uiStyle, iPaneWidth);
}
// force a height change
CFont *pcFontTemp = GetFont();
// initialize font height etc
OnSetFont( (WPARAM)(HFONT)pcFontTemp->GetSafeHandle(), 0 );
}
else
{
bRC = FALSE;
}
}
}
return bRC;
}
/******************************************************************************/
void CStatBar::OnNcDestroy( void )
{
m_posBitmap.DeleteObject();
m_sizeBitmap.DeleteObject();
m_posBitmap.m_hObject = NULL;
m_sizeBitmap.m_hObject = NULL;
m_cstringSizeSeparator.Empty();
m_cstringPosSeparator.Empty();
CStatusBar::OnNcDestroy();
}
/******************************************************************************/
CSize CStatBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
CSize size = CStatusBar::CalcFixedLayout( bStretch, bHorz );
size.cy = m_iSizeY;
return size;
}
/******************************************************************************/
/* Change the height of the status bar to allow the bitmaps to be painted */
/* in the panes. The height is set in the OnSetFont OnSetFont method. Save */
/* the current border values, change then call OnSetFont and then reset the */
/* border values */
/* */
/* This will increase the height of the whole status bar until the next */
/* OnSetFont (font change) for the status bar. */
/* */
/* In Barcore.cpp, the Height of the status bar is set in the OnSetFont */
/* method as follows: */
/* */
/* Height = = (tm.tmHeight - tm.tmInternalLeading) + */
/* CY_BORDER*4 (which is 2 extra on top, 2 */
/* on bottom) - rectSize.Height(); */
/* */
/* This is really */
/* Height = Height of Font + Border between Font and */
/* Pane edges + Border between Pane edges and */
/* Status bar window. */
/* */
/* tm.tmHeight - tm.tmInternalLeading is Font Height CY_BORDER*4 is border */
/* between font and pane edges rectSize.Height is Neg of Border between Pane */
/* and SBar rectSize is set to 0, then the deflated by the border size. */
/* Deflating from 0 => negative, and - negative gives us a positive amount. */
/* */
/* by default m_cyBottomBorder = m_cyTopBorder = 1 */
/******************************************************************************/
/* We only change the border sizes temporarily for the calculation of the */
/* status bar height. We really don't want to change the border sizes, but */
/* are just using them as a way to affect the size of the whole bar. */
/******************************************************************************/
LRESULT CStatBar::OnSetFont(WPARAM wParam, LPARAM lParam)
{
CRect rect;
int iTmpcyTopBorder = m_cyTopBorder;
int iTmpcyBottomBorder = m_cyBottomBorder;
m_cyTopBorder = m_cyBottomBorder = 2;
miSlackSpace = 0;
// Can't do this in MFC 4
// lResult = CStatusBar::OnSetFont(wParam, lParam); //initialize font height etc
rect.SetRectEmpty();
CalcInsideRect( rect, TRUE ); // will be negative size
int iBorder = CY_BORDER * 4 - rect.Height();
int iSize = m_iSizeY - iBorder;
int cyTallest = m_iBitmapHeight;
CDC dc;
if( dc.CreateIC( TEXT("DISPLAY"), NULL, NULL, NULL ) )
{
TEXTMETRIC tm;
tm.tmHeight=0;
CFont *font = CFont::FromHandle( (HFONT)wParam );
if ( font )
{
CFont *oldFont = dc.SelectObject(font);
if( dc.GetTextMetrics( &tm ) && tm.tmHeight > cyTallest )
cyTallest = tm.tmHeight;
if (oldFont)
dc.SelectObject(oldFont);
}
dc.DeleteDC();
}
if (cyTallest > iSize)
m_iSizeY = cyTallest + iBorder;
if (m_iBitmapHeight > iSize)
miSlackSpace = m_iBitmapHeight - iSize;
m_cyTopBorder = iTmpcyTopBorder;
m_cyBottomBorder = iTmpcyBottomBorder;
return 1L;
}
/******************************************************************************/
/* This routine is overloaded to allow us to paint the bitmaps in the panes. */
/* If this routine was not here, it would work fine, but no bitmaps would */
/* appear in the status indicator panes. */
/******************************************************************************/
void CStatBar::DoPaint( CDC* pDC )
{
BOOL bRC;
CString cstringText_Pane1;
CString cstringText_Pane2;
CRect rect_Pane1;
CRect rect_Pane2;
CRgn cRgn_Pane1;
CRgn cRgn_Pane2;
CBitmap* pOldBitmap;
UINT uiStyle_Pane1;
UINT uiStyle_Pane2;
UINT uiID;
int iPaneWidth;
HDC hdc = pDC->GetSafeHdc();
GetItemRect( 1, &rect_Pane1 ); // get pane rect
GetItemRect( 2, &rect_Pane2 ); // get pane rect
pDC->ExcludeClipRect( &rect_Pane1 ); // exclude pane rect from paint
pDC->ExcludeClipRect( &rect_Pane2 ); // exclude pane rect from paint
CStatusBar::DoPaint( pDC ); // Let Parent Class paint remainder of status bar
CFont* pfntOld = pDC->SelectObject( GetFont() );
GetPaneText( 1, cstringText_Pane1 ); // Get the Text for the Pane
GetPaneText( 2, cstringText_Pane2 ); // The status bar holds the text for us.
GetPaneInfo( 1, uiID, uiStyle_Pane1, iPaneWidth );
GetPaneInfo( 2, uiID, uiStyle_Pane2, iPaneWidth );
uiStyle_Pane1 = SBPS_NORMAL;
uiStyle_Pane2 = SBPS_NORMAL;
CDC srcDC; // select current bitmap into a compatible CDC
bRC = srcDC.CreateCompatibleDC( pDC );
ASSERT( bRC != FALSE );
if (bRC != FALSE)
{
// Set the Text and Background Colors for a Mono to Color Bitmap
// Conversion. These are also set in DrawStatusText, so should not
// have to reset them for the other bitmap/pane
COLORREF crTextColor = pDC->SetTextColor( GetSysColor( COLOR_BTNTEXT ) );
COLORREF crBkColor = pDC->SetBkColor ( GetSysColor( COLOR_BTNFACE ) );
bRC = cRgn_Pane1.CreateRectRgnIndirect( rect_Pane1 );
ASSERT( bRC != FALSE );
if (bRC != FALSE)
{
pDC->SelectClipRgn( &cRgn_Pane1 ); // set clip region to pane rect
pOldBitmap = srcDC.SelectObject( &m_posBitmap );
rect_Pane1.InflateRect( -CX_BORDER, -CY_BORDER ); // deflate => don't paint on the borders
pDC->BitBlt( rect_Pane1.left, rect_Pane1.top,
rect_Pane1.Width(), rect_Pane1.Height(),
&srcDC, 0, 0, SRCCOPY ); // BitBlt to pane rect
srcDC.SelectObject( pOldBitmap );
rect_Pane1.InflateRect( CX_BORDER, CY_BORDER ); // Inflate back for drawstatustext
// paint the borders and the text.
DrawStatusText( hdc, rect_Pane1, cstringText_Pane1, uiStyle_Pane1,
m_iBitmapWidth + 1 );
}
cRgn_Pane2.CreateRectRgnIndirect(rect_Pane2);
ASSERT( bRC != FALSE );
if (bRC != FALSE)
{
pDC->SelectClipRgn(&cRgn_Pane2); // set clip region to pane rect
pOldBitmap = srcDC.SelectObject(&m_sizeBitmap);
rect_Pane2.InflateRect(-CX_BORDER, -CY_BORDER); // deflate => don't paint on the borders
pDC->BitBlt(rect_Pane2.left, rect_Pane2.top, rect_Pane2.Width(),
rect_Pane2.Height(), &srcDC, 0, 0, SRCCOPY); // BitBlt to pane rect
srcDC.SelectObject(pOldBitmap);
rect_Pane2.InflateRect(CX_BORDER, CY_BORDER); // Inflate back for drawstatustext
// DrawStatusText will paint the borders and the text.
DrawStatusText(hdc, rect_Pane2, cstringText_Pane2, uiStyle_Pane2, m_iBitmapWidth+1);
}
pDC->SetTextColor( crTextColor );
pDC->SetBkColor ( crBkColor );
}
if (pfntOld != NULL)
pDC->SelectObject( pfntOld );
}
/******************************************************************************/
/* Partially taken from BARCORE.CPP DrawStatusText method of CStatusBar. */
/* Last parameter was added */
/* */
/* This will allow us to output the text indented the space amount for our */
/* bitmap. Normally, this routine puts the text left alligned to the pane. */
/******************************************************************************/
void PASCAL CStatBar::DrawStatusText( HDC hDC,
CRect const& rect,
LPCTSTR lpszText,
UINT nStyle,
int iIndentText )
{
ASSERT(hDC != NULL);
CBrush* cpBrushHilite;
CBrush* cpBrushShadow;
HBRUSH hbrHilite = NULL;
HBRUSH hbrShadow = NULL;
if (! (nStyle & SBPS_NOBORDERS))
{
if (nStyle & SBPS_POPOUT)
{
// reverse colors
cpBrushHilite = GetSysBrush( COLOR_BTNSHADOW );
cpBrushShadow = GetSysBrush( COLOR_BTNHIGHLIGHT );
}
else
{
// normal colors
cpBrushHilite = GetSysBrush( COLOR_BTNHIGHLIGHT );
cpBrushShadow = GetSysBrush( COLOR_BTNSHADOW );
}
hbrHilite = (HBRUSH)cpBrushHilite->GetSafeHandle();
hbrShadow = (HBRUSH)cpBrushShadow->GetSafeHandle();
}
// background is already grey
UINT nOpts = ETO_CLIPPED;
int nOldMode = SetBkMode ( hDC, OPAQUE );
COLORREF crTextColor = SetTextColor( hDC, GetSysColor( COLOR_BTNTEXT ) );
COLORREF crBkColor = SetBkColor ( hDC, GetSysColor( COLOR_BTNFACE ) );
// Draw the hilites
if (hbrHilite)
{
HGDIOBJ hOldBrush = SelectObject( hDC, hbrHilite );
if (hOldBrush)
{
PatBlt( hDC, rect.right, rect.bottom, -(rect.Width() - CX_BORDER),
-CY_BORDER, PATCOPY );
PatBlt( hDC, rect.right, rect.bottom, -CX_BORDER,
-(rect.Height() - CY_BORDER), PATCOPY );
SelectObject( hDC, hOldBrush );
}
}
if (hbrShadow)
{
HGDIOBJ hOldBrush = SelectObject( hDC, hbrShadow );
if (hOldBrush)
{
PatBlt( hDC, rect.left, rect.top, rect.Width(), CY_BORDER, PATCOPY );
PatBlt( hDC, rect.left, rect.top,
CX_BORDER, rect.Height(), PATCOPY );
SelectObject( hDC, hOldBrush );
}
}
// We need to adjust the rect for the ExtTextOut, and then adjust it back
// just support left justified text
if (lpszText != NULL && !(nStyle & SBPS_DISABLED))
{
CRect rectText( rect );
rectText.InflateRect( -2 * CX_BORDER, -CY_BORDER );
// adjust left edge for indented Text
rectText.left += iIndentText;
// align on bottom (since descent is more important than ascent)
SetTextAlign( hDC, TA_LEFT | TA_BOTTOM );
if (miSlackSpace > 0)
rectText.InflateRect( 0, -(miSlackSpace / 2) );
ExtTextOut( hDC, rectText.left, rectText.bottom,
nOpts, &rectText, lpszText, lstrlen( lpszText ), NULL );
}
SetTextColor( hDC, crTextColor );
SetBkColor ( hDC, crBkColor );
}
/******************************************************************************/
BOOL CStatBar::SetText(LPCTSTR szText)
{
BOOL bRC = TRUE;
if (theApp.InEmergencyState())
{
bRC = FALSE;
}
else
{
bRC = SetPaneText(0, szText);
}
return bRC;
}
/******************************************************************************/
BOOL CStatBar::SetPosition(const CPoint& pos)
{
BOOL bRC = TRUE;
int cch;
TCHAR szBuf [20];
cch = wsprintf(szBuf, TEXT("%d~%d"), pos.x, pos.y);
for (int i = 0; i < cch; i++)
if (szBuf[i] == TEXT('~'))
{
szBuf[i] = m_cstringPosSeparator[0];
break;
}
ASSERT (cch != 0);
if (cch != 0)
{
bRC = SetPaneText(1, szBuf);
}
else
{
bRC = FALSE;
}
return bRC;
}
/******************************************************************************/
BOOL CStatBar::SetSize(const CSize& size)
{
BOOL bRC = TRUE;
int cch;
TCHAR szBuf [20];
cch = wsprintf( szBuf, TEXT("%d~%d"), size.cx, size.cy );
for (int i = 0; i < cch; i++)
if (szBuf[i] == TEXT('~'))
{
szBuf[i] = m_cstringSizeSeparator[0];
break;
}
ASSERT (cch != 0);
if (cch != 0)
bRC = SetPaneText(2, szBuf);
else
bRC = FALSE;
return bRC;
}
/******************************************************************************/
BOOL CStatBar::ClearPosition()
{
BOOL bRC = TRUE;
bRC = SetPaneText(1, TEXT("")); // clear the position
return bRC;
}
/******************************************************************************/
BOOL CStatBar::ClearSize()
{
BOOL bRC = TRUE;
bRC = SetPaneText(2, TEXT("")); // clear the size
return bRC;
}
/******************************************************************************/
BOOL CStatBar::Reset()
{
return ClearPosition() && ClearSize();
}
/******************************************************************************/
void CStatBar::OnSysColorChange()
{
CStatusBar::OnSysColorChange();
InvalidateRect(NULL,FALSE);
}
/******************************************************************************/
void ClearStatusBarSize()
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->ClearSize();
}
/******************************************************************************/
void ClearStatusBarPosition()
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->ClearPosition();
}
/******************************************************************************/
void SetPrompt(LPCTSTR szPrompt, BOOL bRedrawNow)
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->SetText(szPrompt);
if (bRedrawNow)
g_pStatBarWnd->UpdateWindow();
}
/******************************************************************************/
void SetPrompt(UINT nStringID, BOOL bRedrawNow)
{
ASSERT(g_pStatBarWnd);
CString str;
VERIFY(str.LoadString(nStringID));
g_pStatBarWnd->SetText(str);
if (bRedrawNow)
g_pStatBarWnd->UpdateWindow();
}
/******************************************************************************/
void ShowStatusBar(BOOL bShow /* = TRUE */)
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE);
}
/******************************************************************************/
BOOL IsStatusBarVisible()
{
ASSERT(g_pStatBarWnd);
return (g_pStatBarWnd->GetStyle() & WS_VISIBLE) != 0;
}
/******************************************************************************/
int GetStatusBarHeight()
{
ASSERT(g_pStatBarWnd);
CRect rect;
g_pStatBarWnd->GetWindowRect(rect);
return rect.Height();
}
/******************************************************************************/
void InvalidateStatusBar(BOOL bErase /* = FALSE */)
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->Invalidate(bErase);
}
/******************************************************************************/
void ClearStatusBarPositionAndSize()
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->ClearSize();
g_pStatBarWnd->ClearPosition();
}
/******************************************************************************/
void ResetStatusBar()
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->Reset();
}
/******************************************************************************/
void SetStatusBarPosition(const CPoint& pos)
{
ASSERT(g_pStatBarWnd);
if ( ::IsWindow(g_pStatBarWnd->m_hWnd) )
g_pStatBarWnd->SetPosition(pos);
}
/******************************************************************************/
void SetStatusBarSize(const CSize& size)
{
ASSERT(g_pStatBarWnd);
if ( ::IsWindow( g_pStatBarWnd->m_hWnd) )
g_pStatBarWnd->SetSize(size);
}
/******************************************************************************/
void SetStatusBarPositionAndSize(const CRect& rect)
{
ASSERT(g_pStatBarWnd);
g_pStatBarWnd->SetPosition(((CRect&)rect).TopLeft());
g_pStatBarWnd->SetSize(rect.Size());
}
/******************************************************************************/
LRESULT CStatBar::OnSizeParent(WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = CStatusBar::OnSizeParent(wParam, lParam);
return(lRes);
}