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