// 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;
}