1 // ResizableComboBox.cpp : implementation file
\r
3 /////////////////////////////////////////////////////////////////////////////
\r
5 // Copyright (C) 2000-2004 by Paolo Messina
\r
6 // (http://www.geocities.com/ppescher - ppescher@hotmail.com)
\r
8 // The contents of this file are subject to the Artistic License (the "License").
\r
9 // You may not use this file except in compliance with the License.
\r
10 // You may obtain a copy of the License at:
\r
11 // http://www.opensource.org/licenses/artistic-license.html
\r
13 // If you find this code useful, credits would be nice!
\r
15 /////////////////////////////////////////////////////////////////////////////
\r
18 #include "ResizableComboBox.h"
\r
21 #define new DEBUG_NEW
\r
23 static char THIS_FILE[] = __FILE__;
\r
26 /////////////////////////////////////////////////////////////////////////////
\r
27 // CResizableComboBox
\r
29 CResizableComboBox::CResizableComboBox()
\r
31 m_bClipMaxHeight = TRUE;
\r
32 m_bIntegralHeight = TRUE;
\r
35 CResizableComboBox::~CResizableComboBox()
\r
37 if (m_ctrlListBox.GetSafeHwnd() != NULL)
\r
38 m_ctrlListBox.UnsubclassWindow();
\r
42 BEGIN_MESSAGE_MAP(CResizableComboBox, CComboBox)
\r
43 //{{AFX_MSG_MAP(CResizableComboBox)
\r
48 /////////////////////////////////////////////////////////////////////////////
\r
49 // CResizableComboBox message handlers
\r
51 HBRUSH CResizableComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
\r
53 HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
\r
55 if (nCtlColor == CTLCOLOR_LISTBOX)
\r
57 if (!(GetStyle() & CBS_SIMPLE)
\r
58 && (m_ctrlListBox.m_hWnd == NULL))
\r
60 TRACE("ComboLBox: 0x%08X\n", pWnd->m_hWnd);
\r
62 // attach to the owned listbox
\r
63 m_ctrlListBox.m_pOwnerCombo = this;
\r
64 m_ctrlListBox.SubclassWindow(pWnd->m_hWnd);
\r
71 LRESULT CResizableComboBox::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
\r
75 case CB_GETDROPPEDCONTROLRECT:
\r
76 *(LPRECT)lParam = m_rectDropDown;
\r
77 MapWindowPoints(NULL, (LPRECT)lParam);
\r
81 LRESULT lResult = CComboBox::WindowProc(message, wParam, lParam);
\r
83 // if listbox is attached, update horizontal extent
\r
87 case CB_INSERTSTRING:
\r
89 if (lResult != CB_ERR && lResult != CB_ERRSPACE)
\r
90 UpdateHorizontalExtent((LPCTSTR)lParam);
\r
94 if (lResult != CB_ERR && lResult != CB_ERRSPACE)
\r
95 InitHorizontalExtent();
\r
98 case CB_RESETCONTENT:
\r
99 InitHorizontalExtent();
\r
106 void CResizableComboBox::InitHorizontalExtent()
\r
108 CClientDC dc(this);
\r
109 CFont* pOldFont = dc.SelectObject(GetFont());
\r
114 int n = GetCount();
\r
115 for (int i=0; i<n; i++)
\r
118 int cx = dc.GetTextExtent(str).cx;
\r
119 if (cx > m_iExtent)
\r
123 SetHorizontalExtent(m_iExtent
\r
124 + LOWORD(GetDialogBaseUnits()));
\r
126 dc.SelectObject(pOldFont);
\r
129 void CResizableComboBox::UpdateHorizontalExtent(LPCTSTR szText)
\r
131 CClientDC dc(this);
\r
132 CFont* pOldFont = dc.SelectObject(GetFont());
\r
134 int cx = dc.GetTextExtent(szText, lstrlen(szText)).cx;
\r
135 if (cx > m_iExtent)
\r
139 SetHorizontalExtent(m_iExtent
\r
140 + LOWORD(GetDialogBaseUnits()));
\r
143 dc.SelectObject(pOldFont);
\r
146 void CResizableComboBox::PreSubclassWindow()
\r
148 ASSERT(GetStyle() & CBS_NOINTEGRALHEIGHT);
\r
150 InitHorizontalExtent();
\r
152 GetDroppedControlRect(&m_rectDropDown);
\r
153 ::MapWindowPoints(NULL, GetSafeHwnd(),
\r
154 (LPPOINT)&m_rectDropDown, 2);
\r
156 CComboBox::PreSubclassWindow();
\r
159 int CResizableComboBox::MakeIntegralHeight(const int height)
\r
161 int inth = height; // integral height (result)
\r
162 int availh = height; // available height
\r
163 int n = GetCount();
\r
165 DWORD dwStyle = GetStyle();
\r
167 if (!m_bIntegralHeight || n == 0)
\r
170 if (dwStyle & CBS_OWNERDRAWVARIABLE)
\r
172 inth = 0; // try to reach availh by integral steps
\r
174 // use items below the first visible
\r
175 for (i=GetTopIndex(); availh>0 && i<n; i++)
\r
177 int h = GetItemHeight(i);
\r
184 // to fill the remaining height, use items above
\r
185 for (i=GetTopIndex()-1; availh>0 && i>=0; i--)
\r
187 int h = GetItemHeight(i);
\r
194 // scroll into view
\r
197 if (!m_bClipMaxHeight) // it can be higher than all the items
\r
199 // to fill the remaining height, use last item
\r
200 int h = GetItemHeight(n-1);
\r
203 inth += availh - availh % h;
\r
209 // every item has the same height (take the first)
\r
210 int h = GetItemHeight(0);
\r
211 if (h != CB_ERR && n != CB_ERR)
\r
213 int rows = availh / h;
\r
214 // can't be higher than all the items
\r
215 if (m_bClipMaxHeight && rows > n)
\r
218 // scroll into view
\r
219 if (n - rows < GetTopIndex())
\r
220 SetTopIndex(n-rows);
\r