Click here to Skip to main content
15,892,537 members
Articles / Desktop Programming / WTL

Form Designer

26 Jul 2021CPOL24 min read 351.9K   82.5K   230  
Component for adding scriptable forms capabilities to an application.
// 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;
}

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
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions