1 // ResizableComboLBox.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 "ResizableComboLBox.h"
\r
19 #include "ResizableComboBox.h"
\r
22 #define new DEBUG_NEW
\r
24 static char THIS_FILE[] = __FILE__;
\r
27 /////////////////////////////////////////////////////////////////////////////
\r
28 // CResizableComboLBox
\r
30 CResizableComboLBox::CResizableComboLBox()
\r
32 m_dwAddToStyle = WS_THICKFRAME;
\r
33 m_dwAddToStyleEx = 0;//WS_EX_CLIENTEDGE;
\r
37 CResizableComboLBox::~CResizableComboLBox()
\r
43 BEGIN_MESSAGE_MAP(CResizableComboLBox, CWnd)
\r
44 //{{AFX_MSG_MAP(CResizableComboLBox)
\r
49 ON_WM_CAPTURECHANGED()
\r
50 ON_WM_WINDOWPOSCHANGING()
\r
51 ON_WM_WINDOWPOSCHANGED()
\r
55 /////////////////////////////////////////////////////////////////////////////
\r
56 // CResizableComboLBox message handlers
\r
58 void CResizableComboLBox::PreSubclassWindow()
\r
60 CWnd::PreSubclassWindow();
\r
62 InitializeControl();
\r
65 BOOL CResizableComboLBox::IsRTL()
\r
67 return (GetExStyle() & WS_EX_LAYOUTRTL);
\r
70 void CResizableComboLBox::InitializeControl()
\r
73 m_pOwnerCombo->GetWindowRect(&rect);
\r
74 m_sizeAfterSizing.cx = rect.Width();
\r
75 m_sizeAfterSizing.cy = -rect.Height();
\r
76 m_pOwnerCombo->GetDroppedControlRect(&rect);
\r
77 m_sizeAfterSizing.cy += rect.Height();
\r
78 m_sizeMin.cy = m_sizeAfterSizing.cy-2;
\r
80 // change window's style
\r
81 ModifyStyleEx(0, m_dwAddToStyleEx);
\r
82 ModifyStyle(0, m_dwAddToStyle, SWP_FRAMECHANGED);
\r
84 // count hscroll if present
\r
85 if (GetStyle() & WS_HSCROLL)
\r
86 m_sizeAfterSizing.cy += GetSystemMetrics(SM_CYHSCROLL);
\r
88 SetWindowPos(NULL, 0, 0, m_sizeAfterSizing.cx, m_sizeAfterSizing.cy,
\r
89 SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);
\r
92 void CResizableComboLBox::OnMouseMove(UINT nFlags, CPoint point)
\r
95 MapWindowPoints(NULL, &pt, 1); // to screen coord
\r
99 // since mouse is captured we need to change the cursor manually
\r
100 LRESULT ht = SendMessage(WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
\r
101 SendMessage(WM_SETCURSOR, (WPARAM)m_hWnd, MAKELPARAM(ht, WM_MOUSEMOVE));
\r
103 CWnd::OnMouseMove(nFlags, point);
\r
108 CRect rect = m_rcBeforeSizing;
\r
109 CSize relMove = pt - m_ptBeforeSizing;
\r
111 switch (m_nHitTest)
\r
114 rect.bottom += relMove.cy;
\r
116 case HTBOTTOMRIGHT:
\r
117 rect.bottom += relMove.cy;
\r
118 rect.right += relMove.cx;
\r
121 rect.right += relMove.cx;
\r
124 rect.bottom += relMove.cy;
\r
125 rect.left += relMove.cx;
\r
128 rect.left += relMove.cx;
\r
132 // move window (if right-aligned it needs refresh)
\r
133 UINT nCopyFlag = (GetExStyle() & WS_EX_RIGHT) ? SWP_NOCOPYBITS : 0;
\r
134 SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(),
\r
135 SWP_NOACTIVATE|SWP_NOZORDER|nCopyFlag);
\r
138 void CResizableComboLBox::OnLButtonDown(UINT nFlags, CPoint point)
\r
141 MapWindowPoints(NULL, &pt, 1); // to screen coord
\r
143 LRESULT ht = SendMessage(WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
\r
145 if (ht == HTBOTTOM || ht == HTRIGHT || ht == HTBOTTOMRIGHT
\r
146 || ht == HTLEFT || ht == HTBOTTOMLEFT)
\r
151 GetWindowRect(&m_rcBeforeSizing);
\r
152 m_ptBeforeSizing = pt;
\r
155 CWnd::OnLButtonDown(nFlags, point);
\r
158 void CResizableComboLBox::OnLButtonUp(UINT nFlags, CPoint point)
\r
160 CWnd::OnLButtonUp(nFlags, point);
\r
165 #if _MSC_VER < 1400
\r
166 UINT CResizableComboLBox::OnNcHitTest(CPoint point)
\r
168 LRESULT CResizableComboLBox::OnNcHitTest(CPoint point)
\r
172 GetClientRect(&rcClient);
\r
173 MapWindowPoints(NULL, &rcClient);
\r
175 // ask for default hit-test value
\r
176 UINT_PTR ht = CWnd::OnNcHitTest(point);
\r
178 // disable improper resizing (based on layout setting)
\r
182 if (!IsRTL() && point.y > rcClient.top)
\r
188 if (IsRTL() && point.y > rcClient.top)
\r
195 if (!IsRTL() && point.y > rcClient.bottom)
\r
200 case HTBOTTOMRIGHT:
\r
201 if (IsRTL() && point.y > rcClient.bottom)
\r
223 void CResizableComboLBox::OnCaptureChanged(CWnd *pWnd)
\r
227 CWnd::OnCaptureChanged(pWnd);
\r
230 void CResizableComboLBox::EndSizing()
\r
234 GetWindowRect(&rect);
\r
235 m_sizeAfterSizing = rect.Size();
\r
238 void CResizableComboLBox::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
\r
242 // restore the size when the drop-down list becomes visible
\r
243 lpwndpos->cx = m_sizeAfterSizing.cx;
\r
244 lpwndpos->cy = m_sizeAfterSizing.cy;
\r
246 ApplyLimitsToPos(lpwndpos);
\r
248 CWnd::OnWindowPosChanging(lpwndpos);
\r
251 void CResizableComboLBox::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
\r
253 // default implementation sends a WM_SIZE message
\r
254 // that can change the size again to force integral height
\r
256 // since we do that manually during resize, we should also
\r
257 // update the horizontal scrollbar
\r
258 SendMessage(WM_HSCROLL, SB_ENDSCROLL, 0);
\r
260 GetWindowRect(&m_pOwnerCombo->m_rectDropDown);
\r
261 ::MapWindowPoints(NULL, m_pOwnerCombo->GetSafeHwnd(),
\r
262 (LPPOINT)&m_pOwnerCombo->m_rectDropDown, 2);
\r
264 CWnd::OnWindowPosChanged(lpwndpos);
\r
267 void CResizableComboLBox::ApplyLimitsToPos(WINDOWPOS* lpwndpos)
\r
269 //TRACE(">H w(%d)\n", lpwndpos->cy);
\r
270 // to adjust horizontally, use window rect
\r
272 // min width can't be less than combo's
\r
274 m_pOwnerCombo->GetWindowRect(&rect);
\r
275 m_sizeMin.cx = rect.Width();
\r
277 // apply horizontal limits
\r
278 if (lpwndpos->cx < m_sizeMin.cx)
\r
279 lpwndpos->cx = m_sizeMin.cx;
\r
281 // fix horizontal alignment
\r
282 rect = CRect(0, 0, lpwndpos->cx, lpwndpos->cy);
\r
283 m_pOwnerCombo->MapWindowPoints(NULL, &rect);
\r
284 lpwndpos->x = rect.left;
\r
286 // to adjust vertically, use client rect
\r
289 rect = CRect(CPoint(lpwndpos->x, lpwndpos->y),
\r
290 CSize(lpwndpos->cx, lpwndpos->cy));
\r
291 SendMessage(WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
\r
292 CSize sizeClient = rect.Size();
\r
294 // apply vertical limits
\r
295 if (sizeClient.cy < m_sizeMin.cy)
\r
296 sizeClient.cy = m_sizeMin.cy;
\r
298 //TRACE(">H c(%d)\n", sizeClient.cy);
\r
299 // adjust height, if needed
\r
300 sizeClient.cy = m_pOwnerCombo->MakeIntegralHeight(sizeClient.cy);
\r
301 //TRACE(">H c(%d)\n", sizeClient.cy);
\r
303 // back to window rect
\r
304 rect = CRect(0, 0, 1, sizeClient.cy);
\r
305 DWORD dwStyle = GetStyle();
\r
306 ::AdjustWindowRectEx(&rect, dwStyle, FALSE, GetExStyle());
\r
307 lpwndpos->cy = rect.Height();
\r
308 if (dwStyle & WS_HSCROLL)
\r
309 lpwndpos->cy += GetSystemMetrics(SM_CYHSCROLL);
\r
311 //TRACE("H c(%d) w(%d)\n", sizeClient.cy, lpwndpos->cy);
\r