Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

516 lines
15 KiB

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
*
* TITLE: DBLLBOX.H
*
* VERSION: 1.0
*
* AUTHOR: ShaunIv
*
* DATE: 3/25/1999
*
* DESCRIPTION: Owner drawn listbox and combobox that do an icon plus a title and subtitle
*
*******************************************************************************/
#ifndef __DBLLBOX_H_INCLUDED
#define __DBLLBOX_H_INCLUDED
#include "simstr.h"
template <class T>
class CDoubleLineListBoxItem
{
private:
CSimpleString m_strTitle;
CSimpleString m_strSubTitle;
HICON m_hIcon;
T m_Data;
public:
CDoubleLineListBoxItem( const T &data, LPCTSTR pszTitle = NULL, LPCTSTR pszSubTitle = NULL, HICON hIcon = NULL );
CDoubleLineListBoxItem( const CDoubleLineListBoxItem &other );
CDoubleLineListBoxItem &operator=( const CDoubleLineListBoxItem &other );
CDoubleLineListBoxItem &Assign( const CSimpleString &strTitle, const CSimpleString &strSubTitle, HICON hIcon, const T &data );
~CDoubleLineListBoxItem(void);
CSimpleString Title(void) const;
CSimpleString SubTitle(void) const;
T Data(void) const;
HICON Icon(void) const;
HICON CopyIcon(void) const;
};
template <class T>
CDoubleLineListBoxItem<T>::CDoubleLineListBoxItem( const T &data, LPCTSTR pszTitle, LPCTSTR pszSubTitle, HICON hIcon )
: m_strTitle(),
m_strSubTitle(),
m_hIcon(NULL)
{
Assign( pszTitle, pszSubTitle, hIcon, data );
}
template <class T>
CDoubleLineListBoxItem<T>::CDoubleLineListBoxItem( const CDoubleLineListBoxItem &other )
: m_strTitle(),
m_strSubTitle(),
m_hIcon(NULL)
{
Assign( other.Title(), other.SubTitle(), other.CopyIcon(), other.Data() );
}
template <class T>
CDoubleLineListBoxItem<T> &CDoubleLineListBoxItem<T>::operator=( const CDoubleLineListBoxItem &other )
{
return( Assign( other.Title(), other.SubTitle(), other.CopyIcon(), other.Data() ));
}
template <class T>
CDoubleLineListBoxItem<T> &CDoubleLineListBoxItem<T>::Assign( const CSimpleString &strTitle, const CSimpleString &strSubTitle, HICON hIcon, const T &Data )
{
if (m_hIcon)
{
DestroyIcon( m_hIcon );
}
m_hIcon = hIcon;
m_strTitle = strTitle;
m_strSubTitle = strSubTitle;
m_Data = Data;
return(*this);
}
template <class T>
CDoubleLineListBoxItem<T>::~CDoubleLineListBoxItem(void)
{
if (m_hIcon)
{
DestroyIcon( m_hIcon );
m_hIcon = NULL;
m_strTitle = m_strSubTitle = TEXT("");
}
}
template <class T>
CSimpleString CDoubleLineListBoxItem<T>::Title(void) const
{
return(m_strTitle);
}
template <class T>
CSimpleString CDoubleLineListBoxItem<T>::SubTitle(void) const
{
return(m_strSubTitle);
}
template <class T>
T CDoubleLineListBoxItem<T>::Data(void) const
{
return(m_Data);
}
template <class T>
HICON CDoubleLineListBoxItem<T>::Icon(void) const
{
return(m_hIcon);
}
template <class T>
HICON CDoubleLineListBoxItem<T>::CopyIcon(void) const
{
return(m_hIcon ? ::CopyIcon(m_hIcon) : NULL );
}
template <class T>
class CDoubleLineListBox
{
private:
HWND m_hWnd;
HFONT m_hFontTitle;
HFONT m_hFontSubTitle;
SIZE m_sizeIcon;
BOOL m_bIsComboBox;
int m_nTitleTextHeight;
int m_nSubTitleTextHeight;
enum
{
c_AdditionalIconBorder = 3 // Additional border around icons
};
private:
// No implementation
CDoubleLineListBox( const CDoubleLineListBox & );
CDoubleLineListBox &operator=( const CDoubleLineListBox & );
public:
CDoubleLineListBox(void);
~CDoubleLineListBox(void);
void Destroy(void);
void AssignFonts( HFONT hFontTitle, HFONT hFontSubTitle );
void CreateDefaultFonts(void);
CDoubleLineListBox &Assign( HWND hWnd );
HWND Handle(void) const;
void Handle( HWND hWnd );
CDoubleLineListBox &operator=( HWND hWnd );
LRESULT AddItem( CDoubleLineListBoxItem<T> *pNewItem );
CDoubleLineListBoxItem<T> *GetItem( int nIndex );
void HandleDeleteItem( LPDELETEITEMSTRUCT pDeleteItem );
void HandleMeasureItem( LPMEASUREITEMSTRUCT pMeasureItem );
void HandleDrawItem( LPDRAWITEMSTRUCT pDrawItem );
int SetHorizontalExtent(void);
SIZE MeasureItem( int nIndex );
};
template <class T>
CDoubleLineListBox<T>::CDoubleLineListBox(void)
: m_hWnd(NULL),
m_hFontTitle(NULL),
m_hFontSubTitle(NULL),
m_bIsComboBox(false),
m_nTitleTextHeight(0),
m_nSubTitleTextHeight(0)
{
}
template <class T>
CDoubleLineListBox<T>::~CDoubleLineListBox(void)
{
Destroy();
}
template <class T>
void CDoubleLineListBox<T>::Destroy(void)
{
m_hWnd = NULL;
if (m_hFontTitle)
{
DeleteObject(m_hFontTitle);
m_hFontTitle = NULL;
}
if (m_hFontSubTitle)
{
DeleteObject(m_hFontSubTitle);
m_hFontSubTitle = NULL;
}
}
template <class T>
void CDoubleLineListBox<T>::AssignFonts( HFONT hFontTitle, HFONT hFontSubTitle )
{
if (m_hFontTitle)
{
DeleteObject(m_hFontTitle);
m_hFontTitle = NULL;
}
if (m_hFontSubTitle)
{
DeleteObject(m_hFontSubTitle);
m_hFontSubTitle = NULL;
}
m_hFontTitle = hFontTitle;
m_hFontSubTitle = hFontSubTitle;
HDC hDC = GetDC(NULL);
if (hDC)
{
HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(hDC,m_hFontTitle));
TEXTMETRIC TextMetric;
GetTextMetrics( hDC, &TextMetric );
m_nTitleTextHeight = TextMetric.tmHeight + TextMetric.tmExternalLeading;
SelectObject(hDC,m_hFontSubTitle);
GetTextMetrics( hDC, &TextMetric );
m_nSubTitleTextHeight = TextMetric.tmHeight + TextMetric.tmExternalLeading;
SelectObject( hDC, hOldFont );
ReleaseDC( NULL, hDC );
}
}
template <class T>
void CDoubleLineListBox<T>::CreateDefaultFonts(void)
{
HFONT hCurrFont = NULL, hFontTitle = NULL, hFontSubTitle = NULL;
if (m_hWnd && IsWindow(m_hWnd))
{
hCurrFont = reinterpret_cast<HFONT>(SendMessage(m_hWnd,WM_GETFONT,0,0));
}
if (!hCurrFont)
{
hCurrFont = reinterpret_cast<HFONT>(GetStockObject(ANSI_VAR_FONT));
}
if (hCurrFont)
{
LOGFONT lf;
if (GetObject( hCurrFont, sizeof(lf), &lf ))
{
lf.lfWeight = FW_BOLD;
hFontTitle = CreateFontIndirect(&lf);
lf.lfWeight = FW_NORMAL;
hFontSubTitle = CreateFontIndirect(&lf);
}
}
AssignFonts( hFontTitle, hFontSubTitle );
}
template <class T>
CDoubleLineListBox<T> &CDoubleLineListBox<T>::Assign( HWND hWnd )
{
Destroy();
m_hWnd = hWnd;
CreateDefaultFonts();
if (m_hWnd && IsWindow(m_hWnd))
{
TCHAR szClassName[MAX_PATH];
if (GetClassName( m_hWnd, szClassName, sizeof(szClassName)/sizeof(szClassName[0])))
{
m_bIsComboBox = (lstrcmpi( szClassName, TEXT("combobox") ) == 0);
}
}
return(*this);
}
template <class T>
HWND CDoubleLineListBox<T>::Handle(void) const
{
return(m_hWnd);
}
template <class T>
void CDoubleLineListBox<T>::Handle( HWND hWnd )
{
Assign(hWnd);
}
template <class T>
CDoubleLineListBox<T> &CDoubleLineListBox<T>::operator=( HWND hWnd )
{
return(Assign(hWnd));
}
template <class T>
LRESULT CDoubleLineListBox<T>::AddItem( CDoubleLineListBoxItem<T> *pNewItem )
{
LRESULT lResult = -1;
if (IsWindow(m_hWnd) && pNewItem)
{
lResult = SendMessage( m_hWnd, m_bIsComboBox ? CB_ADDSTRING : LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(pNewItem->Title().String()) );
if (lResult >= 0)
{
SendMessage( m_hWnd, m_bIsComboBox ? CB_SETITEMDATA : LB_SETITEMDATA, lResult, reinterpret_cast<LPARAM>(pNewItem) );
}
SetHorizontalExtent();
}
return(lResult);
}
template <class T>
CDoubleLineListBoxItem<T> *CDoubleLineListBox<T>::GetItem( int nIndex )
{
LRESULT lResult = 0;
if (IsWindow(m_hWnd))
{
lResult = SendMessage( m_hWnd, m_bIsComboBox ? CB_GETITEMDATA : LB_GETITEMDATA, nIndex, 0 );
if (lResult == CB_ERR || lResult == LB_ERR)
lResult = 0;
}
return(reinterpret_cast<CDoubleLineListBoxItem<T> *>(lResult));
}
// This must be called in response to WM_DELETEITEM
template <class T>
void CDoubleLineListBox<T>::HandleDeleteItem( LPDELETEITEMSTRUCT pDeleteItem )
{
if (pDeleteItem && IsWindow(m_hWnd) && pDeleteItem->hwndItem == m_hWnd)
{
CDoubleLineListBoxItem *pItem = reinterpret_cast<CDoubleLineListBoxItem *>(pDeleteItem->itemData);
if (pItem)
delete pItem;
}
}
// This must be called in response to WM_MEASUREITEM
template <class T>
void CDoubleLineListBox<T>::HandleMeasureItem( LPMEASUREITEMSTRUCT pMeasureItem )
{
if (pMeasureItem)
{
SIZE sizeItem = MeasureItem( pMeasureItem->itemID );
pMeasureItem->itemHeight = sizeItem.cy;
}
}
template <class T>
int CDoubleLineListBox<T>::SetHorizontalExtent(void)
{
if (IsWindow(m_hWnd))
{
int nMaxLength = 0;
LRESULT lCount = SendMessage( m_hWnd, m_bIsComboBox ? CB_GETCOUNT : LB_GETCOUNT, 0, 0 );
for (int i=0;i<(int)lCount;i++)
{
SIZE sizeItem = MeasureItem(i);
nMaxLength = (sizeItem.cx > nMaxLength) ? sizeItem.cx : nMaxLength;
}
SendMessage( m_hWnd, m_bIsComboBox ? CB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, nMaxLength, 0 );
return nMaxLength;
}
return 0;
}
// Return the width and height, in pixels, of an item
template <class T>
SIZE CDoubleLineListBox<T>::MeasureItem( int nIndex )
{
SIZE sizeItem =
{
GetSystemMetrics(SM_CXICON) + c_AdditionalIconBorder * 3 + 2,
GetSystemMetrics(SM_CYICON) + c_AdditionalIconBorder * 2 + 2
};
if (IsWindow(m_hWnd))
{
// Make sure we have valid fonts
if (!m_hFontTitle || !m_hFontSubTitle)
CreateDefaultFonts();
CDoubleLineListBoxItem<T> *pItem = GetItem(nIndex);
if (pItem)
{
HDC hDC = GetDC(m_hWnd);
if (hDC)
{
HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(hDC,m_hFontTitle));
// Calculate the size of the text rectangle for the title
RECT rcText;
ZeroMemory(&rcText,sizeof(rcText));
DrawTextEx( hDC, const_cast<LPTSTR>(pItem->Title().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX|DT_CALCRECT, NULL );
int nTitleWidth = rcText.right - rcText.left;
// Calculate the size of the text rectangle for the sub title
ZeroMemory(&rcText,sizeof(rcText));
SelectObject(hDC,m_hFontSubTitle);
DrawTextEx( hDC, const_cast<LPTSTR>(pItem->SubTitle().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX|DT_CALCRECT, NULL );
int nSubTitleWidth = rcText.right - rcText.left;
sizeItem.cx += (nTitleWidth > nSubTitleWidth) ? nTitleWidth : nSubTitleWidth;
SelectObject( hDC, hOldFont );
ReleaseDC( m_hWnd, hDC );
}
}
}
return(sizeItem);
}
// This must be called in response to WM_DRAWITEM
template <class T>
void CDoubleLineListBox<T>::HandleDrawItem( LPDRAWITEMSTRUCT pDrawItem )
{
if (pDrawItem && IsWindow(m_hWnd) && pDrawItem->hwndItem == m_hWnd)
{
// Make sure we have valid fonts
if (!m_hFontTitle || !m_hFontSubTitle)
CreateDefaultFonts();
RECT rcItem = pDrawItem->rcItem;
// Paint the background
if (ODS_SELECTED & pDrawItem->itemState)
{
if (IsWindowEnabled(pDrawItem->hwndItem))
{
FillRect( pDrawItem->hDC, &rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
}
else
{
FillRect( pDrawItem->hDC, &rcItem, GetSysColorBrush(COLOR_INACTIVECAPTION));
}
}
else
{
FillRect( pDrawItem->hDC, &rcItem, GetSysColorBrush(COLOR_WINDOW));
}
// Paint the focus rectangle
if (ODS_FOCUS & pDrawItem->itemState)
{
DrawFocusRect( pDrawItem->hDC, &rcItem );
}
// Shrink by one pixel, so we don't overwrite the focus rect
InflateRect( &rcItem, -1, -1 );
if (pDrawItem->itemData != -1)
{
CDoubleLineListBoxItem<T> *pItem = reinterpret_cast<CDoubleLineListBoxItem<T> *>(pDrawItem->itemData);
if (pItem)
{
// Draw the icon
DrawIconEx( pDrawItem->hDC, pDrawItem->rcItem.left+c_AdditionalIconBorder, pDrawItem->rcItem.top+c_AdditionalIconBorder, pItem->Icon(), GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0, NULL, DI_NORMAL );
// Move the left margin over to make room for the text
rcItem.left += GetSystemMetrics(SM_CXICON) + c_AdditionalIconBorder * 2;
// Set up the dc
COLORREF crOldTextColor;
if (IsWindowEnabled(pDrawItem->hwndItem))
{
if (ODS_SELECTED & pDrawItem->itemState)
crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT) );
else crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_WINDOWTEXT) );
}
else
{
if (ODS_SELECTED & pDrawItem->itemState)
crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_INACTIVECAPTIONTEXT) );
else crOldTextColor = SetTextColor( pDrawItem->hDC, GetSysColor(COLOR_GRAYTEXT) );
}
int nOldBkMode = SetBkMode( pDrawItem->hDC, TRANSPARENT );
HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(pDrawItem->hDC,m_hFontTitle));
// Calculate the text rectangle
RECT rcText = rcItem;
rcText.top += (((rcText.bottom - rcText.top)) - (m_nTitleTextHeight + m_nSubTitleTextHeight)) / 2;
rcText.bottom = rcText.top + m_nTitleTextHeight + m_nSubTitleTextHeight;
DrawTextEx( pDrawItem->hDC, const_cast<LPTSTR>(pItem->Title().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX, NULL );
// Get ready for the sub-title
SelectObject(pDrawItem->hDC,m_hFontSubTitle);
// Get the coords for the bottom text rect
rcText.top += m_nTitleTextHeight;
// Draw the text
DrawTextEx( pDrawItem->hDC, const_cast<LPTSTR>(pItem->SubTitle().String()), -1, &rcText, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOPREFIX, NULL );
// Restore the dc
SelectObject(pDrawItem->hDC,hOldFont);
SetBkMode( pDrawItem->hDC, nOldBkMode );
SetTextColor( pDrawItem->hDC, crOldTextColor );
}
}
}
}
#endif