Thank you for the interesting question. First of all, we improved the image mode enumeration with adding two new constants for proportional image stretching:
enum e_ImageMode_t
{
eAlign = 0, // The image is aligned according to the text aligning styles (the __EGCS_TA_HORZ_xxx and __EGCS_TA_VERT_xxx styles)
eTile = 1, // The image is repeated until the entire available area is filled.
eStretch = 2, // The image is stretched to fit all the available area.
eTouchInside = 3, // Stretch the image proportionally and touch inside.
eTouchOutside = 4, // Stretch the image proportionally and touch outside.
};
Second, we modified the following method:
void CExtLabel::DoPaint(
CDC * pDC,
CRect & rcClient
)
{
ASSERT_VALID( this );
ASSERT_VALID( pDC );
CExtMemoryDC dc( pDC, &rcClient );
CRgn rgnClient;
if( rgnClient.CreateRectRgnIndirect( &rcClient ) )
dc.SelectClipRgn( &rgnClient );
OnEraseBackground( dc, rcClient );
DWORD dwWndStyle = GetStyle();
DWORD dwWndType = (dwWndStyle&SS_TYPEMASK);
bool bCenterImage = ( (dwWndStyle&SS_CENTERIMAGE) != 0 );
if( ! m_bmp.IsEmpty() )
{
bool bSmootherAsPossible = true;
e_ImageMode_t eImageMode = GetImageMode();
if( eImageMode == eStretch )
m_bmp.AlphaBlendSkinParts( dc.GetSafeHdc(), rcClient, CRect(0,0,0,0), CExtBitmap::__EDM_STRETCH, true, bSmootherAsPossible );
else if( eImageMode == eTouchInside || eImageMode == eTouchOutside )
{
CRect rcTouchSurface = rcClient;
CExtMemoryDC dcTouch( &dc, rcTouchSurface, CExtMemoryDC::MDCOPT_TO_MEMORY|CExtMemoryDC::MDCOPT_FILL_BITS|CExtMemoryDC::MDCOPT_RTL_COMPATIBILITY );
if( dcTouch.GetSafeHdc() )
{
CSize sizeTouchSrc = rcTouchSurface.Size();
CSize sizeBmp = m_bmp.GetSize();
double lfAspectX = double(rcTouchSurface.Width()) / double(sizeBmp.cx);
double lfAspectY = double(rcTouchSurface.Height()) / double(sizeBmp.cy);
double lfAspect = ( eImageMode == eTouchInside ) ? ( min( lfAspectX, lfAspectY ) ) : ( max( lfAspectX, lfAspectY ) );
CSize sizeNew( LONG(double(sizeBmp.cx)*lfAspect), LONG(double(sizeBmp.cy)*lfAspect) );
CRect rcTouchDst( rcTouchSurface.left, rcTouchSurface.top, rcTouchSurface.left + sizeNew.cx, rcTouchSurface.top + sizeNew.cy );
if( eImageMode == eTouchInside )
{
if( sizeNew.cx > sizeTouchSrc.cx )
rcTouchDst.OffsetRect( ( sizeNew.cx - sizeTouchSrc.cx ) / 2, 0 );
if( sizeNew.cy > sizeTouchSrc.cy )
rcTouchDst.OffsetRect( 0, ( sizeNew.cy - sizeTouchSrc.cy ) / 2 );
}
else
{
rcTouchDst.OffsetRect( - ( sizeNew.cx - sizeTouchSrc.cx ) / 2, 0 );
rcTouchDst.OffsetRect( 0, - ( sizeNew.cy - sizeTouchSrc.cy ) / 2 );
}
INT nOldStretchBltMode = bSmootherAsPossible ? ( ::GetStretchBltMode( dcTouch.m_hDC ) ) : ( COLORONCOLOR ) ;
if( bSmootherAsPossible )
::SetStretchBltMode( dcTouch.m_hDC, ( g_PaintManager.m_bIsWinNT ) ? HALFTONE : COLORONCOLOR );
m_bmp.AlphaBlend( dcTouch.m_hDC, rcTouchDst );
if( bSmootherAsPossible )
::SetStretchBltMode( dcTouch.m_hDC, nOldStretchBltMode );
}
}
else if( eImageMode == eTile )
m_bmp.AlphaBlendSkinParts( dc.GetSafeHdc(), rcClient, CRect(0,0,0,0), CExtBitmap::__EDM_TILE, true, bSmootherAsPossible );
else if( eImageMode == eAlign )
{
CSize szSize = m_bmp.GetSize();
CRect rcDst( rcClient.left, rcClient.top, rcClient.left + szSize.cx, rcClient.top + szSize.cy );
bool bCenterHorizontally = false;
switch( dwWndType )
{
case SS_RIGHT: rcDst.OffsetRect( rcClient.right - rcDst.right, 0 ); break;
case SS_CENTER: bCenterHorizontally = true; break;
default: /* all the other types assumed as left */ break;
}
if( bCenterHorizontally )
rcDst.OffsetRect( ( (rcClient.right - rcClient.left) - (rcDst.right - rcDst.left) ) / 2, 0 );
if( bCenterImage )
rcDst.OffsetRect( 0, ( (rcClient.bottom - rcClient.top) - (rcDst.bottom - rcDst.top) ) / 2 );
CRect rcSrc( 0, 0, szSize.cx, szSize.cy );
rcDst.top = max( rcDst.top, rcClient.top );
rcDst.left = max( rcDst.left, rcClient.left );
rcDst.bottom = min( rcDst.bottom, rcClient.bottom );
rcDst.right = min( rcDst.right, rcClient.right );
if( ::RectVisible( dc.GetSafeHdc(), &rcDst ) )
{
INT nOldStretchBltMode = bSmootherAsPossible ? ( ::GetStretchBltMode( dc.m_hDC ) ) : ( COLORONCOLOR );
if( bSmootherAsPossible )
::SetStretchBltMode( dc.m_hDC, ( g_PaintManager.m_bIsWinNT ) ? HALFTONE : COLORONCOLOR );
m_bmp.AlphaBlend( dc.m_hDC, rcDst, rcSrc );
if( bSmootherAsPossible )
::SetStretchBltMode( dc.m_hDC, nOldStretchBltMode );
}
}
}
else if( dwWndType == SS_ICON )
{
HICON hIcon = GetIcon();
if( hIcon != NULL )
{
CExtCmdIcon _icon;
_icon.AssignFromHICON( hIcon, true );
CSize szIcon = _icon.GetSize();
int nOffsetX = bCenterImage ? (rcClient.Width() - szIcon.cx) / 2 : 0;
int nOffsetY = bCenterImage ? (rcClient.Height() - szIcon.cy) / 2 : 0;
_icon.Paint(
PmBridge_GetPM(), dc.GetSafeHdc(), rcClient.left + nOffsetX, rcClient.top + nOffsetY, -1, -1,
IsWindowEnabled() ? CExtCmdIcon::__PAINT_NORMAL : CExtCmdIcon::__PAINT_DISABLED
);
}
}
else
{
CExtSafeString strText;
int nTextLen = GetWindowTextLength();
if( nTextLen > 0 )
{
GetWindowText( strText.GetBuffer( nTextLen + 2 ), nTextLen + 1 );
strText.ReleaseBuffer();
}
if( strText.GetLength() > 0 )
{
DWORD dwDrawTextFlags = 0;
switch( dwWndType )
{
case SS_RIGHT: dwDrawTextFlags = DT_RIGHT; break;
case SS_CENTER: dwDrawTextFlags = DT_CENTER; break;
case SS_LEFTNOWORDWRAP: dwDrawTextFlags = DT_LEFT; break;
default: /* all the other types assumed as left */ dwDrawTextFlags = DT_LEFT; break;
} // switch( dwWndType )
if( strText.Find( _T(’\t’) ) != -1 ) // do tabs expanding
dwDrawTextFlags |= DT_EXPANDTABS;
if( (dwWndType == SS_SIMPLE)
|| (dwWndStyle&(SS_CENTERIMAGE|SS_ENDELLIPSIS|SS_PATHELLIPSIS)) != 0
)
{
dwDrawTextFlags |= DT_SINGLELINE;
if( (dwWndStyle&SS_CENTERIMAGE) != 0 )
dwDrawTextFlags |= DT_VCENTER;
if( (dwWndStyle&SS_ENDELLIPSIS) != 0 )
dwDrawTextFlags |= DT_END_ELLIPSIS;
if( (dwWndStyle&SS_PATHELLIPSIS) != 0 )
dwDrawTextFlags |= DT_PATH_ELLIPSIS;
}
else
dwDrawTextFlags |= DT_WORDBREAK;
if( dwWndType == SS_LEFTNOWORDWRAP )
dwDrawTextFlags &= ~(DT_WORDBREAK|DT_SINGLELINE);
if( (dwWndStyle&SS_NOPREFIX) != 0 )
dwDrawTextFlags |= DT_NOPREFIX;
bool bEnabled = IsWindowEnabled() ? true : false;
OnDrawLabelText( dc, rcClient, strText, dwDrawTextFlags, bEnabled );
} // if( strText.GetLength() > 0 )
}
PmBridge_GetPM()->OnPaintSessionComplete( this );
if( rgnClient.GetSafeHandle() != NULL )
dc.SelectClipRgn( &rgnClient );
}
Third, we modified the following method:
void CExtGridCellPictureBase::OnPaintText(
const RECT & rcCellText,
const CExtGridWnd & wndGrid,
CDC & dc,
LONG nVisibleColNo,
LONG nVisibleRowNo,
LONG nColNo,
LONG nRowNo,
INT nColType,
INT nRowType,
const RECT & rcCellExtra,
const RECT & rcCell,
const RECT & rcVisibleRange,
DWORD dwAreaFlags,
DWORD dwHelperPaintFlags
) const
{
ASSERT_VALID( this );
ASSERT_VALID( (&wndGrid) );
ASSERT( dc.GetSafeHdc() != NULL );
if( ! dc.RectVisible(&rcCellText) )
return;
wndGrid; nVisibleColNo; nVisibleRowNo; nColNo; nRowNo; nColType; nRowType; rcCellExtra; rcCell; rcVisibleRange; dwAreaFlags; dwHelperPaintFlags;
if( IsInvisible() || IsUndefined() || IsEmpty() )
return;
const CExtBitmap * pBmpBuffer = BitmapGetBuffer();
if( pBmpBuffer == NULL || pBmpBuffer->IsEmpty() )
return;
if( ( dwHelperPaintFlags & __EGCPF_SIMPLIFIED_RENDERING_TARGET ) != 0 )
{
CRect rcX( rcCellExtra );
CExtMemoryDC dcX( &dc, &rcX );
OnPaintText( rcCellText, wndGrid, dcX, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, rcCellExtra, rcCell, rcVisibleRange, dwAreaFlags, dwHelperPaintFlags&(~__EGCPF_SIMPLIFIED_RENDERING_TARGET) );
return;
}
bool bSmootherAsPossible = true;
if( m_eImageMode == eStretch )
{
CRect rcStretch = rcCellText;
rcStretch.InflateRect( 2, 0 );
pBmpBuffer->AlphaBlendSkinParts( dc.GetSafeHdc(), rcStretch, CRect(0,0,0,0), CExtBitmap::__EDM_STRETCH, true, bSmootherAsPossible );
}
else if( m_eImageMode == eTouchInside || m_eImageMode == eTouchOutside )
{
CRect rcTouchSurface = rcCellText;
CExtMemoryDC dcTouch( &dc, rcTouchSurface, CExtMemoryDC::MDCOPT_TO_MEMORY|CExtMemoryDC::MDCOPT_FILL_BITS|CExtMemoryDC::MDCOPT_RTL_COMPATIBILITY );
if( dcTouch.GetSafeHdc() )
{
CSize sizeTouchSrc = rcTouchSurface.Size();
CSize sizeBmp = pBmpBuffer->GetSize();
double lfAspectX = double(rcTouchSurface.Width()) / double(sizeBmp.cx);
double lfAspectY = double(rcTouchSurface.Height()) / double(sizeBmp.cy);
double lfAspect = ( m_eImageMode == eTouchInside ) ? ( min( lfAspectX, lfAspectY ) ) : ( max( lfAspectX, lfAspectY ) );
CSize sizeNew( LONG(double(sizeBmp.cx)*lfAspect), LONG(double(sizeBmp.cy)*lfAspect) );
CRect rcTouchDst( rcTouchSurface.left, rcTouchSurface.top, rcTouchSurface.left + sizeNew.cx, rcTouchSurface.top + sizeNew.cy );
if( m_eImageMode == eTouchInside )
{
if( sizeNew.cx > sizeTouchSrc.cx )
rcTouchDst.OffsetRect( ( sizeNew.cx - sizeTouchSrc.cx ) / 2, 0 );
if( sizeNew.cy > sizeTouchSrc.cy )
rcTouchDst.OffsetRect( 0, ( sizeNew.cy - sizeTouchSrc.cy ) / 2 );
}
else
{
rcTouchDst.OffsetRect( - ( sizeNew.cx - sizeTouchSrc.cx ) / 2, 0 );
rcTouchDst.OffsetRect( 0, - ( sizeNew.cy - sizeTouchSrc.cy ) / 2 );
}
INT nOldStretchBltMode = bSmootherAsPossible ? ( ::GetStretchBltMode( dcTouch.m_hDC ) ) : ( COLORONCOLOR ) ;
if( bSmootherAsPossible )
::SetStretchBltMode( dcTouch.m_hDC, ( g_PaintManager.m_bIsWinNT ) ? HALFTONE : COLORONCOLOR );
pBmpBuffer->AlphaBlend( dcTouch.m_hDC, rcTouchDst );
if( bSmootherAsPossible )
::SetStretchBltMode( dcTouch.m_hDC, nOldStretchBltMode );
}
}
else if( m_eImageMode == eTile )
pBmpBuffer->AlphaBlendSkinParts( dc.GetSafeHdc(), rcCellText, CRect(0,0,0,0), CExtBitmap::__EDM_TILE, true, bSmootherAsPossible );
else if( m_eImageMode == eAlign )
{
CSize szSize = pBmpBuffer->GetSize();
CRect rcDst( rcCellText.left, rcCellText.top, rcCellText.left + szSize.cx, rcCellText.top + szSize.cy );
DWORD dwCellStyle = GetStyle();
switch( (dwCellStyle&__EGCS_TA_HORZ_MASK) )
{
case __EGCS_TA_HORZ_BY_TYPE:
case __EGCS_TA_HORZ_LEFT:
break;
case __EGCS_TA_HORZ_RIGHT:
rcDst.OffsetRect( rcCellText.right - rcDst.right, 0 );
break;
case __EGCS_TA_HORZ_CENTER:
rcDst.OffsetRect( ( (rcCellText.right - rcCellText.left) - (rcDst.right - rcDst.left) ) / 2, 0 );
break;
#ifdef _DEBUG
default:
ASSERT( FALSE );
break;
#endif // _DEBUG
}
switch( (dwCellStyle&__EGCS_TA_VERT_MASK) )
{
case __EGCS_TA_VERT_BY_TYPE:
case __EGCS_TA_VERT_TOP:
break;
case __EGCS_TA_VERT_BOTTOM:
rcDst.OffsetRect( 0, rcCellText.bottom - rcDst.bottom );
break;
case __EGCS_TA_VERT_MIDDLE:
rcDst.OffsetRect( 0, ( (rcCellText.bottom - rcCellText.top) - (rcDst.bottom - rcDst.top) ) / 2 );
break;
#ifdef _DEBUG
default:
ASSERT( FALSE );
break;
#endif // _DEBUG
}
CRect rcSrc( 0, 0, szSize.cx, szSize.cy );
rcDst.top = max( rcDst.top, rcCellText.top );
rcDst.left = max( rcDst.left, rcCellText.left );
rcDst.bottom = min( rcDst.bottom, rcCellText.bottom );
rcDst.right = min( rcDst.right, rcCellText.right );
if( ::RectVisible( dc.GetSafeHdc(), &rcDst ) )
{
INT nOldStretchBltMode = bSmootherAsPossible ? ( ::GetStretchBltMode( dc.m_hDC ) ) : ( COLORONCOLOR ) ;
if( bSmootherAsPossible )
::SetStretchBltMode( dc.m_hDC, ( g_PaintManager.m_bIsWinNT ) ? HALFTONE : COLORONCOLOR );
pBmpBuffer->AlphaBlend( dc.m_hDC, rcDst, rcSrc );
if( bSmootherAsPossible )
::SetStretchBltMode( dc.m_hDC, nOldStretchBltMode );
}
}
}
Now both the label control and picture cell support proportional image resizing.