Click here to Skip to main content
15,896,440 members
Articles / Desktop Programming / WTL

Form Designer

26 Jul 2021CPOL24 min read 352.2K   82.5K   230  
Component for adding scriptable forms capabilities to an application.
// ValuePicker.cpp: implementation of the CValuePicker class.
//
// Author : David Shepherd
//			Copyright (c) 2002, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ValuePicker.h"

/////////////////////////////////////////////////////////////////////////////
// CValuePickerValue

CValuePickerValue::CValuePickerValue()
{
	// initialise everything
}

CValuePickerValue::~CValuePickerValue()
{
	// clean up
}

/////////////////////////////////////////////////////////////////////////////
// CValuePicker

CValuePicker::CValuePicker() : m_List(this,VP_MSG_MAP_LIST)
{
	// initialise everything
	m_RunMessageLoop=TRUE;
}

CValuePicker::~CValuePicker()
{
	// clean up
}

CFontHandle CValuePicker::GetFont()
{
	// return the value picker font
	CFontHandle hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
	if(hFont==NULL)
	{
		throw std::exception();
	}
	return hFont;
}

void CValuePicker::SetSizeAndPosition(const CPoint &TopRight,DWORD Width)
{
	// get the list box item height
	DWORD ItemHeight=m_List.GetItemHeight(0);
	if(ItemHeight==LB_ERR)
	{
		throw std::exception();
	}
	// get the required list box height
	DWORD ListBoxHeight=min(8,m_Values.size())*ItemHeight;
	// allow room for the border
	ListBoxHeight+=2*GetSystemMetrics(SM_CYBORDER);

	// get the value picker rect
	CRect ValuePickerRect(0,0,Width,ListBoxHeight);
	// position the top right corner
	ValuePickerRect.OffsetRect(
		TopRight.x-ValuePickerRect.right+1,TopRight.y-ValuePickerRect.top);
	// prevent screen overrun
	CRect ScreenRect(
		0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
	// todo : allow for the task bar
	ValuePickerRect=ForceRectIntoRect(ScreenRect,ValuePickerRect);

	// size and position the value picker
	if(SetWindowPos(NULL,ValuePickerRect,SWP_NOZORDER)==FALSE)
	{
		throw std::exception();
	}
}

void CValuePicker::SelectStartValue()
{
	// select the initial value
	for(long l=0; l<(long)m_Values.size(); l++)
	{
		// compare values
		if(m_Values[l].m_Value!=m_Value)
		{
			continue;
		}
		// found a match
		if(m_List.SetCurSel(l)==LB_ERR)
		{
			throw std::exception();
		}
		break;	// done
	}
}

BOOL CValuePicker::PickValue(const CWindow &Parent,const CPoint &TopRight,DWORD Width)
{
TRY
	// reinitialise everything to allow object reuse
	m_RunMessageLoop=TRUE;
	// create the value picker window (invisible)
	if(Create(Parent,CRect(0,0,0,0),_T(""),WS_POPUP|WS_CLIPCHILDREN)==NULL)
	{
		throw std::exception();
	}
	// size and position the value picker
	SetSizeAndPosition(TopRight,Width);
	// select the initial value
	SelectStartValue();
	// show the value picker
	(void)ShowWindow(SW_SHOW);
	// run the message loop
	while(m_RunMessageLoop)
	{
		// get the next message
		// todo : check for the WM_QUIT message
		MSG Message;
		(void)GetMessage(&Message,NULL,0,0);
		// process the message
		(void)TranslateMessage(&Message);
		(void)DispatchMessage(&Message);
	}
CATCH_ALL
	// clean up
	if(IsWindow())
	{
		(void)DestroyWindow();
	}
	return Caught ? FALSE : TRUE;	// return TRUE on success
}

LRESULT CValuePicker::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// create the list box
	if(m_List.Create(*this,CRect(0,0,0,0),_T(""),
		// standard window styles
		WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|
		// list box styles
		LBS_NOTIFY|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED,
		// extended window styles
		0,
		// id
		VP_IDC_LIST)==NULL)
	{
		throw std::exception();
	}
	// add all values to the list box
	for(long l=0; l<(long)m_Values.size(); l++)
	{
		// add by vector index
		LRESULT Result=m_List.AddString((LPCTSTR)l);
		if(Result==LB_ERR or Result==LB_ERRSPACE)
		{
			throw std::exception();
		}
	}
CATCH_ALL
	return Caught ? -1 : 0;	// fail creation on error
}

LRESULT CValuePicker::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// get the client rect
	CRect ClientRect(0,0,0,0);
	if(GetClientRect(ClientRect)==FALSE)
	{
		throw std::exception();
	}
	// size the list box to fill the entire client area
	if(m_List.SetWindowPos(NULL,ClientRect,SWP_NOZORDER)==FALSE)
	{
		throw std::exception();
	}
CATCH_ALL
	return 0;
}

LRESULT CValuePicker::OnMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// should be for the list box
	ATLASSERT(wParam==VP_IDC_LIST);

	// get the measure item struct
	MEASUREITEMSTRUCT *pMeasureItemStruct=(MEASUREITEMSTRUCT *)lParam;
	// initialise the item height to something sensible
	DWORD MinItemHeight=8;
	pMeasureItemStruct->itemHeight=MinItemHeight;
	// create the display information context
	CDC dc=CreateIC(_T("Display"),NULL,NULL,NULL);
	if(dc==NULL)
	{
		throw std::exception();
	}
	// get the font height
	LOGFONT lf;
	if(GetObject(GetFont(),sizeof(LOGFONT),&lf)==0)
	{
		throw std::exception();
	}
	DWORD FontHeight=abs(lf.lfHeight);
	// set the item height
	DWORD ItemHeight=max(MinItemHeight,POINT_SIZE_TO_PIXELS(dc,FontHeight));
	pMeasureItemStruct->itemHeight=ItemHeight;
CATCH_ALL
	return TRUE;
}

LRESULT CValuePicker::OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	USES_CONVERSION;

	// should be for the list box
	ATLASSERT(wParam==VP_IDC_LIST);

	// get the draw item struct
	DRAWITEMSTRUCT *pDrawItemStruct=(DRAWITEMSTRUCT *)lParam;
	// wrap the device context and save the state
	CDCHandle hDC=pDrawItemStruct->hDC;
	CAutoDCState AutoDCState(hDC);
	// get the item rect
	CRect ItemRect=pDrawItemStruct->rcItem;
	// determine if the item is selected
	BOOL IsSelected=
		(pDrawItemStruct->itemState & ODS_SELECTED) ? TRUE : FALSE;

	// get the item value
	CValuePickerValue Value=m_Values[pDrawItemStruct->itemData];

	// set the font
	if(hDC.SelectFont(GetFont())==NULL)
	{
		throw std::exception();
	}
	// set the background color
	COLORREF BackColor=GetSysColor(
		IsSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW);
	if(hDC.SetBkColor(BackColor)==CLR_INVALID)
	{
		throw std::exception();
	}
	// set the foreground color
	COLORREF ForeColor=GetSysColor(
		IsSelected ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT);
	if(hDC.SetTextColor(ForeColor)==CLR_INVALID)
	{
		throw std::exception();
	}
	// fill in the background
	hDC.FillSolidRect(ItemRect,BackColor);
	// draw the value name
	if(hDC.DrawText(W2CT(Value.m_Name.c_str()),
		-1,ItemRect,DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
	{
		throw std::exception();
	}
CATCH_ALL
	return TRUE;
}

LRESULT CValuePicker::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// if the window is being deactivated
	if(LOWORD(wParam)==WA_INACTIVE)
	{
		// get the window being activated
		CWindow ActiveWindow=(HWND)lParam;
		// if the value picker is no longer active
		if(ActiveWindow!=*this and ActiveWindow!=m_List)
		{
			// hide the value picker immediately
			(void)ShowWindow(SW_HIDE);
			// shut down
			m_RunMessageLoop=FALSE;
		}
	}
CATCH_ALL
	return 0;
}

LRESULT CValuePicker::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
	// get the window receiving focus
	CWindow FocusWindow=(HWND)wParam;
	// if the value picker no longer has the focus
	if(FocusWindow!=*this and FocusWindow!=m_List)
	{
		// hide the value picker immediately
		(void)ShowWindow(SW_HIDE);
		// shut down
		m_RunMessageLoop=FALSE;
	}
CATCH_ALL
	return 0;
}

LRESULT CValuePicker::OnSelChangeList(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
	// get the selected item
	DWORD ItemIndex=m_List.GetCurSel();
	if(ItemIndex==LB_ERR)
	{
		throw std::exception();
	}
	// update the value
	m_Value=m_Values[ItemIndex].m_Value;
	// shut down
	m_RunMessageLoop=FALSE;
CATCH_ALL
	return 0;
}

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