// DDPicture.cpp : Implementation of CDDPicture
//
// Author : David Shepherd
// Copyright (c) 2003, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include ".\DDPicture.h"
/////////////////////////////////////////////////////////////////////////////
// CDDPicture
CDDPicture::CDDPicture()
{
// initialise everything
m_bWindowOnly=TRUE;
m_Reserved0=0;
m_Reserved1=0;
m_BackColor=MAKE_OLE_COLOR(COLOR_BTNFACE);
m_PictureAlign=ddcpPictureAlignCenter;
m_SizeToFit=VARIANT_FALSE;
m_BorderStyle=ddcpBorderStyleNone;
}
HRESULT CDDPicture::FinalConstruct()
{
IMP_BEGIN
// create the default picture
m_spPictureDisp=CreateDefaultPicture();
IMP_END
return RetVal;
}
void CDDPicture::FinalRelease()
{
}
const TCHAR* CDDPicture::GetObjectFriendlyName()
{
// return the object friendly name
return _T("DDPicture");
}
HRESULT CDDPicture::OnPictureAlignChanging(ddcpPictureAlign newVal)
{
IMP_BEGIN
// check the new value is valid
if(newVal < ddcpPictureAlign_First or newVal > ddcpPictureAlign_Last)
{
throw CHResult(E_INVALIDARG);
}
IMP_END
return RetVal;
}
HRESULT CDDPicture::OnBorderStyleChanging(ddcpBorderStyle newVal)
{
IMP_BEGIN
// check the new value is valid
if(newVal < ddcpBorderStyle_First or newVal > ddcpBorderStyle_Last)
{
throw CHResult(E_INVALIDARG);
}
IMP_END
return RetVal;
}
void CDDPicture::DrawBorder(CDCHandle hDC,CRect Rect)
{
// save the device context state
CAutoDCState AutoDCState(hDC);
// get the draw edge type
UINT DrawEdgeType=0;
switch(m_BorderStyle)
{
// none
case ddcpBorderStyleNone:
break;
// sunken
case ddcpBorderStyleSunken:
DrawEdgeType=EDGE_SUNKEN;
break;
// raised
case ddcpBorderStyleRaised:
DrawEdgeType=EDGE_RAISED;
break;
// etched
case ddcpBorderStyleEtched:
DrawEdgeType=EDGE_ETCHED;
break;
// bump
case ddcpBorderStyleBump:
DrawEdgeType=EDGE_BUMP;
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
// draw the border
if(DrawEdgeType)
{
if(hDC.DrawEdge(Rect,DrawEdgeType,BF_RECT)==FALSE)
{
throw std::exception();
}
}
}
void CDDPicture::DrawPicture(CDCHandle hDC,CRect Rect)
{
// create GDI object wrappers
// this must be done before the device context state is saved
CRgn Rgn;
// save the device context state
CAutoDCState AutoDCState(hDC);
// ensure we do not draw outside the designated rectangle
if(Rgn.CreateRectRgnIndirect(Rect)==NULL)
{
throw std::exception();
}
if(hDC.SelectClipRgn(Rgn)==ERROR)
{
throw std::exception();
}
// fill in the background
COLORREF BackColor=RGB(0,0,0);
if(!SUCCEEDED(OleTranslateColor(m_BackColor,NULL,&BackColor)))
{
throw std::exception();
}
hDC.FillSolidRect(Rect,BackColor);
// determine if there is a picture to draw
CComQIPtr<IPicture> spPicture(m_spPictureDisp);
if(spPicture==NULL)
{
throw std::exception();
}
short PicType=PICTYPE_UNINITIALIZED;
if(!SUCCEEDED(spPicture->get_Type(&PicType)))
{
throw std::exception();
}
if(PicType!=PICTYPE_UNINITIALIZED and PicType!=PICTYPE_NONE)
{
// get the picture size
OLE_XSIZE_HIMETRIC Width=0;
if(!SUCCEEDED(spPicture->get_Width(&Width)))
{
throw std::exception();
}
OLE_YSIZE_HIMETRIC Height=0;
if(!SUCCEEDED(spPicture->get_Height(&Height)))
{
throw std::exception();
}
// convert to pixels
CSize PixelSize(Width,Height);
hDC.HIMETRICtoDP(&PixelSize);
// get the picture rectangle
CRect PictureRect(Rect.TopLeft(),PixelSize);
// adjust the horizontal position based on the picture align
long dx=0;
switch(m_PictureAlign)
{
// left
case ddcpPictureAlignTopLeft:
case ddcpPictureAlignMiddleLeft:
case ddcpPictureAlignBottomLeft:
break;
// middle
case ddcpPictureAlignTopMiddle:
case ddcpPictureAlignCenter:
case ddcpPictureAlignBottomMiddle:
dx=(Rect.Width()-PictureRect.Width())/2; // horizontal offset
break;
// right
case ddcpPictureAlignTopRight:
case ddcpPictureAlignMiddleRight:
case ddcpPictureAlignBottomRight:
dx=Rect.Width()-PictureRect.Width(); // horizontal offset
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
PictureRect.OffsetRect(dx,0);
// adjust the vertical position based on the picture align
long dy=0;
switch(m_PictureAlign)
{
// top
case ddcpPictureAlignTopLeft:
case ddcpPictureAlignTopMiddle:
case ddcpPictureAlignTopRight:
break;
// middle
case ddcpPictureAlignMiddleLeft:
case ddcpPictureAlignCenter:
case ddcpPictureAlignMiddleRight:
dy=(Rect.Height()-PictureRect.Height())/2; // vertical offset
break;
// bottom
case ddcpPictureAlignBottomLeft:
case ddcpPictureAlignBottomMiddle:
case ddcpPictureAlignBottomRight:
dy=Rect.Height()-PictureRect.Height(); // vertical offset
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
PictureRect.OffsetRect(0,dy);
// adjust the size and position based on the size to fit
if(m_SizeToFit)
{
PictureRect=Rect;
}
// draw the picture
// this will fail if the source or destination size is zero
if(PictureRect.Width()!=0 and PictureRect.Height()!=0 and
Width!=0 and Height!=0)
{
if(!SUCCEEDED(spPicture->Render(hDC,
PictureRect.left,PictureRect.top,
PictureRect.Width(),PictureRect.Height(),
0,Height,Width,-Height,NULL)))
{
throw std::exception();
}
}
}
}
HRESULT CDDPicture::OnDraw(ATL_DRAWINFO& di)
{
IMP_BEGIN
// device context wrapper
CDCHandle hDC(di.hdcDraw);
// bounding rectangle
CRect Rect=*(RECT*)di.prcBounds;
// create GDI object wrappers
// this must be done before the memory device context state is saved
CBitmap Bitmap;
// create the memory device context
CDC dcMem;
if(dcMem.CreateCompatibleDC(hDC)==NULL)
{
throw CHResult(E_FAIL);
}
// save the memory device context state
CAutoDCState AutoDCState(dcMem);
// create the bitmap and select it into the memory device context
if(Bitmap.CreateCompatibleBitmap(hDC,Rect.Width(),Rect.Height())==NULL)
{
throw CHResult(E_FAIL);
}
if(dcMem.SelectBitmap(Bitmap)==NULL)
{
throw CHResult(E_FAIL);
}
// map coordinates to the control
if(dcMem.SetWindowOrg(Rect.left,Rect.top)==FALSE)
{
throw CHResult(E_FAIL);
}
// draw the border
CRect BorderRect=Rect;
DrawBorder(CDCHandle(dcMem),BorderRect);
// get the area in which to draw the picture
CRect PictureRect=Rect;
if( m_BorderStyle==ddcpBorderStyleSunken or
m_BorderStyle==ddcpBorderStyleRaised or
m_BorderStyle==ddcpBorderStyleEtched or
m_BorderStyle==ddcpBorderStyleBump)
{
if(PictureRect.Width() < 4 or PictureRect.Height() < 4)
{
PictureRect.SetRectEmpty(); // there is no room for the picture
}
else
{
PictureRect.InflateRect(-2,-2); // there is room for the picture
}
}
// draw the picture
DrawPicture(CDCHandle(dcMem),PictureRect);
// update the screen
if(hDC.BitBlt(
Rect.left,Rect.top,Rect.Width(),Rect.Height(),
dcMem,Rect.left,Rect.top,SRCCOPY)==FALSE)
{
throw CHResult(E_FAIL);
}
IMP_END
return RetVal;
}
LRESULT CDDPicture::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// to prevent flicker do not erase the background
return TRUE;
}
STDMETHODIMP CDDPicture::SetClientSite(IOleClientSite *pClientSite)
{
IMP_BEGIN
// call the base class
HRESULT hr=IOleObjectImpl<CDDPicture>::SetClientSite(pClientSite);
if(!SUCCEEDED(hr))
{
throw CHResult(hr);
}
// set the background color based on the container ambient properties
OLE_COLOR BackColor=RGB(0,0,0);
if(SUCCEEDED(GetAmbientBackColor(BackColor)))
{
(void)put_BackColor(BackColor);
}
IMP_END
return RetVal;
}