Click here to Skip to main content
15,893,668 members
Articles / Desktop Programming / WTL

Form Designer

26 Jul 2021CPOL24 min read 352K   82.5K   230  
Component for adding scriptable forms capabilities to an application.
// DDComboBox.cpp : Implementation of CDDComboBox
//
// Author : David Shepherd
//			Copyright (c) 2003, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include ".\DDComboBox.h"

/////////////////////////////////////////////////////////////////////////////
// CDDComboBox

#pragma warning(push)
#pragma warning(disable: 4355) // 'this' : used in base member initializer list
CDDComboBox::CDDComboBox() : m_ctlComboBox(_T("ComboBox"), this, 1)
#pragma warning(pop)
{
	// initialise everything
	m_bWindowOnly=TRUE;
	m_Reserved0=0;
	m_Reserved1=0;
	m_Enabled=VARIANT_TRUE;
	m_FillColor=MAKE_OLE_COLOR(COLOR_BTNFACE);
	m_BackColor=MAKE_OLE_COLOR(COLOR_WINDOW);
	m_ForeColor=MAKE_OLE_COLOR(COLOR_WINDOWTEXT);
	m_Sorted=VARIANT_FALSE;
	m_hAccel=NULL;
}

HRESULT CDDComboBox::FinalConstruct()
{
IMP_BEGIN
	// create the background brush
	CreateBackgroundBrush(m_BackColor);
	// create the default font
	m_spFontDisp=CreateDefaultFont();
IMP_END
	return RetVal;
}

void CDDComboBox::FinalRelease()
{
}

const TCHAR* CDDComboBox::GetObjectFriendlyName()
{
	// return the object friendly name
	return _T("DDComboBox");
}

HRESULT CDDComboBox::OnBackColorChanging(OLE_COLOR newVal)
{
IMP_BEGIN
	// create the background brush
	// if this fails the background color will remain unchanged
	CreateBackgroundBrush(newVal);
IMP_END
	return RetVal;
}

void CDDComboBox::OnEnabledChanged()
{
TRY
	// update the combo box
	// this is done indirectly by enabling the parent window
	if(IsWindow())
	{
		(void)EnableWindow(VB2B(m_Enabled));
	}
CATCH_ALL
}

void CDDComboBox::OnBackColorChanged()
{
TRY
	// update the combo box
	if(m_ctlComboBox.IsWindow())
	{
		(void)m_ctlComboBox.Invalidate();
	}
CATCH_ALL
}

void CDDComboBox::OnForeColorChanged()
{
TRY
	// update the combo box
	if(m_ctlComboBox.IsWindow())
	{
		(void)m_ctlComboBox.Invalidate();
	}
CATCH_ALL
}

void CDDComboBox::CreateBackgroundBrush(OLE_COLOR BackColor)
{
	// create the background brush
	COLORREF RGBBackColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(BackColor,NULL,&RGBBackColor)))
	{
		throw std::exception();
	}
	CBrush Brush;
	if(Brush.CreateSolidBrush(RGBBackColor)==NULL)
	{
		throw std::exception();
	}
	if(m_BackBrush!=NULL)
	{
		(void)m_BackBrush.DeleteObject();
	}
	m_BackBrush.Attach(Brush.Detach());
}

HRESULT CDDComboBox::OnDraw(ATL_DRAWINFO& di)
{
IMP_BEGIN
	// device context wrapper
	CDCHandle hDC(di.hdcDraw);
	// bounding rectangle
	CRect Rect=*(RECT*)di.prcBounds;
	// fill in the background
	COLORREF RGBFillColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(m_FillColor,NULL,&RGBFillColor)))
	{
		throw CHResult(E_FAIL);
	}
	hDC.FillSolidRect(Rect,RGBFillColor);
IMP_END
	return RetVal;
}

BOOL CDDComboBox::PreTranslateAccelerator(LPMSG pMsg, HRESULT& hRet)
{
	// this will be set TRUE if the key press was handled
	BOOL Handled=FALSE;
TRY
	// if the combo box has focus
	if((GetFocus()==m_ctlComboBox or m_ctlComboBox.IsChild(GetFocus())) and
		// and this is a key down message
		pMsg->message==WM_KEYDOWN)
	{
		// get shift key modifiers
		BOOL Ctrl  = (GetKeyState(VK_CONTROL) & 0x80000000) ? TRUE : FALSE;
		BOOL Shift = (GetKeyState(VK_SHIFT  ) & 0x80000000) ? TRUE : FALSE;
		BOOL Alt   = (GetKeyState(VK_MENU   ) & 0x80000000) ? TRUE : FALSE;

		// the tab key is ignored since it is not valid for a combo box

		// arrow key
		if(	pMsg->wParam==VK_LEFT  or
			pMsg->wParam==VK_RIGHT or
			pMsg->wParam==VK_UP	   or
			pMsg->wParam==VK_DOWN  or
			// other navigation
			pMsg->wParam==VK_HOME  or
			pMsg->wParam==VK_END   or
			pMsg->wParam==VK_PRIOR or
			pMsg->wParam==VK_NEXT  or
			// del
			pMsg->wParam==VK_DELETE)
		{
			(void)SendMessage(pMsg->hwnd,
				pMsg->message,pMsg->wParam,pMsg->lParam);
			Handled=TRUE;
		}
		// cut / copy / paste / undo
		if(Handled==FALSE)
		{
			if(::TranslateAccelerator(*this,m_hAccel,pMsg)!=0)
			{
				Handled=TRUE;
			}
		}
	}
	// if the key press was handled
	if(Handled)
	{
		// signal success
		hRet=S_OK;
	}
CATCH_ALL
	return Handled;
}

LRESULT CDDComboBox::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// create the combo box
	if(m_ctlComboBox.Create(*this,CRect(0,0,0,0),_T(""),
		// standard window styles
		WS_CHILD|WS_VISIBLE|WS_VSCROLL|
		// combo box styles
		CBS_AUTOHSCROLL|CBS_DROPDOWN|CBS_HASSTRINGS|
		// combo box styles that can only be applied at creation time
		(m_Sorted ? CBS_SORT : 0),
		// extended styles
		0,
		// id
		IDC_COMBOBOX)==NULL)
	{
		throw std::exception();
	}
	// update the combo box
	if(!SUCCEEDED(put_Enabled(m_Enabled)))
	{
		throw std::exception();
	}
	if(!SUCCEEDED(put_Font(m_spFontDisp)))
	{
		throw std::exception();
	}
	// load the combo box accelerators
	m_hAccel=LoadAccelerators(_pModule->GetResourceInstance(),
		MAKEINTRESOURCE(IDA_DDCOMBOBOX));
	if(m_hAccel==NULL)
	{
		throw std::exception();
	}
CATCH_ALL
	return Caught ? -1 : 0;
}

LRESULT CDDComboBox::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// generated by the ATL control wizard
	LRESULT lRes = CComControl<CDDComboBox>::OnSetFocus(uMsg, wParam, lParam, bHandled);
	if (m_bInPlaceActive)
	{
		if(!IsChild(::GetFocus()))
			m_ctlComboBox.SetFocus();
	}
	return lRes;
}

LRESULT CDDComboBox::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// to prevent flicker do not erase the background
	return TRUE;
}

LRESULT CDDComboBox::OnCtlColorComboBox(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// wrap the device context
	CDCHandle hDC=(HDC)wParam;
	// set the background color
	COLORREF RGBBackColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(m_BackColor,NULL,&RGBBackColor)))
	{
		throw std::exception();
	}
	if(hDC.SetBkColor(RGBBackColor)==CLR_INVALID)
	{
		throw std::exception();
	}
	// set the foreground color
	COLORREF RGBForeColor=RGB(0,0,0);
	if(!SUCCEEDED(OleTranslateColor(m_ForeColor,NULL,&RGBForeColor)))
	{
		throw std::exception();
	}
	if(hDC.SetTextColor(RGBForeColor)==CLR_INVALID)
	{
		throw std::exception();
	}
CATCH_ALL
	// return the background brush
	// todo : recover correctly if an exception is thrown
	return (LRESULT)(HBRUSH)m_BackBrush;
}

LRESULT CDDComboBox::OnFireSelectionChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	PROPERTY_CHANGED(DISPID_TEXT)
	// fire the selection change event
	__raise SelectionChange();
CATCH_ALL
	return 0;
}

LRESULT CDDComboBox::OnComboBoxEditChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	PROPERTY_CHANGED(DISPID_TEXT)
	// fire the edit change event
	__raise EditChange();
CATCH_ALL
	return 0;
}

LRESULT CDDComboBox::OnComboBoxSelChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	// ensure the edit portion of the combo box is updated before firing the
	// selection change event
	(void)PostMessage(WM_FIRE_SELECTION_CHANGE);
CATCH_ALL
	return 0;
}

LRESULT CDDComboBox::OnCut(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	// cut
	if(m_ctlComboBox.IsWindow())
	{
		(void)m_ctlComboBox.SendMessage(WM_CUT);
	}
CATCH_ALL
	return 0;
}

LRESULT CDDComboBox::OnCopy(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	// copy
	if(m_ctlComboBox.IsWindow())
	{
		(void)m_ctlComboBox.SendMessage(WM_COPY);
	}
CATCH_ALL
	return 0;
}

LRESULT CDDComboBox::OnPaste(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	// paste
	if(m_ctlComboBox.IsWindow())
	{
		(void)m_ctlComboBox.SendMessage(WM_PASTE);
	}
CATCH_ALL
	return 0;
}

LRESULT CDDComboBox::OnUndo(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	// todo : implement this by sending WM_UNDO to the edit box
	ATLASSERT(FALSE);
CATCH_ALL
	return 0;
}

STDMETHODIMP CDDComboBox::SetClientSite(IOleClientSite *pClientSite)
{
IMP_BEGIN
	// call the base class
	HRESULT hr=IOleObjectImpl<CDDComboBox>::SetClientSite(pClientSite);
	if(!SUCCEEDED(hr))
	{
		throw CHResult(hr);
	}
	// set the fill color based on the container ambient properties
	OLE_COLOR FillColor=RGB(0,0,0);
	if(SUCCEEDED(GetAmbientBackColor(FillColor)))
	{
		(void)put_FillColor(FillColor);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::SetObjectRects(LPCRECT prcPos,LPCRECT prcClip)
{
	// generated by the ATL control wizard
	IOleInPlaceObjectWindowlessImpl<CDDComboBox>::SetObjectRects(prcPos, prcClip);
	int cx, cy;
	cx = prcPos->right - prcPos->left;
	cy = prcPos->bottom - prcPos->top;
	::SetWindowPos(m_ctlComboBox.m_hWnd, NULL, 0,
		0, cx, 200/*changed from cy*/, SWP_NOZORDER | SWP_NOACTIVATE);
	return S_OK;
}

STDMETHODIMP CDDComboBox::get_Font(IFontDisp** pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the font
	*pVal=m_spFontDisp;
	if(*pVal!=NULL)	// add ref it
	{
		(void)(*pVal)->AddRef();
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::put_Font(IFontDisp* newVal)
{
IMP_BEGIN
REQUEST_EDIT(DISPID_FONT)
	// check parameters
	if(newVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// clone the passed font and delegate to putref_Font
	if(!SUCCEEDED(putref_Font(CloneFont(newVal))))
	{
		throw CHResult(E_FAIL);
	}
PROPERTY_CHANGED(DISPID_FONT)
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::putref_Font(IFontDisp* newVal)
{
IMP_BEGIN
REQUEST_EDIT(DISPID_FONT)
	// check parameters
	if(newVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// set the font
	CComQIPtr<IFont> spFont(newVal);
	if(spFont==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CFontHandle hFont=NULL;
	if(!SUCCEEDED(spFont->get_hFont(&hFont.m_hFont)))
	{
		throw CHResult(E_FAIL);
	}
	if(m_ctlComboBox.IsWindow())
	{
		m_ctlComboBox.SetFont(hFont);
	}
	m_spFontDisp=newVal;
PROPERTY_CHANGED(DISPID_FONT)
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::get_Text(BSTR* pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// check the combo box is created
	if(m_ctlComboBox.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// get the text
	if(m_ctlComboBox.GetWindowText(pVal)==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// todo : update m_Text
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::put_Text(BSTR newVal)
{
IMP_BEGIN
// request edit can not be applied to this property since the
// combo box text can be changed by the user at any time
	USES_CONVERSION;
	// check the combo box is created
	if(m_ctlComboBox.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// set the text
	if(m_ctlComboBox.SetWindowText(W2CT(BSTR2W(newVal)))==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// todo : update m_Text
PROPERTY_CHANGED(DISPID_TEXT)
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::AddItem(BSTR Text)
{
IMP_BEGIN
	USES_CONVERSION;
	// check parameters
	if(wcslen(BSTR2W(Text))==0)
	{
		throw CHResult(E_INVALIDARG);
	}
	// check the combo box is created
	if(m_ctlComboBox.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// wrap the combo box
	CComboBox ComboBox(m_ctlComboBox);
	// ensure the item does not already exist
	LONG Ix=ComboBox.FindStringExact(-1,W2CT(BSTR2W(Text)));
	if(Ix!=CB_ERR)
	{
		throw CHResult(E_FAIL);
	}
	// add the item
	Ix=ComboBox.AddString(W2CT(BSTR2W(Text)));
	if(Ix==CB_ERR or Ix==CB_ERRSPACE)
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::RemoveItem(BSTR Text)
{
IMP_BEGIN
	USES_CONVERSION;
	// check parameters
	if(wcslen(BSTR2W(Text))==0)
	{
		throw CHResult(E_INVALIDARG);
	}
	// check the combo box is created
	if(m_ctlComboBox.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// wrap the combo box
	CComboBox ComboBox(m_ctlComboBox);
	// ensure the item exists
	LONG Ix=ComboBox.FindStringExact(-1,W2CT(BSTR2W(Text)));
	if(Ix==CB_ERR)
	{
		throw CHResult(E_FAIL);
	}
	// remove the item
	if(ComboBox.DeleteString(Ix)==CB_ERR)
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::Clear()
{
IMP_BEGIN
	// check the combo box is created
	if(m_ctlComboBox.IsWindow()==FALSE)
	{
		throw CHResult(E_FAIL);
	}
	// wrap the combo box
	CComboBox ComboBox(m_ctlComboBox);
	// clear the combo box
	ComboBox.ResetContent();
IMP_END
	return RetVal;
}

STDMETHODIMP CDDComboBox::get__Default(BSTR* pVal)
{
	// delegate to the required default property
	return get_Text(pVal);
}

STDMETHODIMP CDDComboBox::put__Default(BSTR newVal)
{
	// delegate to the required default property
	return put_Text(newVal);
}

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