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;
39 CResizableComboLBox::~CResizableComboLBox()
45 BEGIN_MESSAGE_MAP(CResizableComboLBox
, CWnd
)
46 //{{AFX_MSG_MAP(CResizableComboLBox)
51 ON_WM_CAPTURECHANGED()
52 ON_WM_WINDOWPOSCHANGING()
53 ON_WM_WINDOWPOSCHANGED()
57 /////////////////////////////////////////////////////////////////////////////
58 // CResizableComboLBox message handlers
60 void CResizableComboLBox::PreSubclassWindow()
62 CWnd::PreSubclassWindow();
67 BOOL
CResizableComboLBox::IsRTL()
69 return (GetExStyle() & WS_EX_LAYOUTRTL
);
72 void CResizableComboLBox::InitializeControl()
75 m_pOwnerCombo
->GetWindowRect(&rect
);
76 m_sizeAfterSizing
.cx
= rect
.Width();
77 m_sizeAfterSizing
.cy
= -rect
.Height();
78 m_pOwnerCombo
->GetDroppedControlRect(&rect
);
79 m_sizeAfterSizing
.cy
+= rect
.Height();
80 m_sizeMin
.cy
= m_sizeAfterSizing
.cy
-2;
82 // change window's style
83 ModifyStyleEx(0, m_dwAddToStyleEx
);
84 ModifyStyle(0, m_dwAddToStyle
, SWP_FRAMECHANGED
);
86 // count hscroll if present
87 if (GetStyle() & WS_HSCROLL
)
88 m_sizeAfterSizing
.cy
+= GetSystemMetrics(SM_CYHSCROLL
);
90 SetWindowPos(NULL
, 0, 0, m_sizeAfterSizing
.cx
, m_sizeAfterSizing
.cy
,
91 SWP_NOZORDER
|SWP_NOACTIVATE
|SWP_NOMOVE
);
94 void CResizableComboLBox::OnMouseMove(UINT nFlags
, CPoint point
)
97 MapWindowPoints(NULL
, &pt
, 1); // to screen coord
101 // since mouse is captured we need to change the cursor manually
102 LRESULT ht
= SendMessage(WM_NCHITTEST
, 0, MAKELPARAM(pt
.x
, pt
.y
));
103 SendMessage(WM_SETCURSOR
, (WPARAM
)m_hWnd
, MAKELPARAM(ht
, WM_MOUSEMOVE
));
105 CWnd::OnMouseMove(nFlags
, point
);
110 CRect rect
= m_rcBeforeSizing
;
111 CSize relMove
= pt
- m_ptBeforeSizing
;
116 rect
.bottom
+= relMove
.cy
;
119 rect
.bottom
+= relMove
.cy
;
120 rect
.right
+= relMove
.cx
;
123 rect
.right
+= relMove
.cx
;
126 rect
.bottom
+= relMove
.cy
;
127 rect
.left
+= relMove
.cx
;
130 rect
.left
+= relMove
.cx
;
134 // move window (if right-aligned it needs refresh)
135 UINT nCopyFlag
= (GetExStyle() & WS_EX_RIGHT
) ? SWP_NOCOPYBITS
: 0;
136 SetWindowPos(NULL
, rect
.left
, rect
.top
, rect
.Width(), rect
.Height(),
137 SWP_NOACTIVATE
|SWP_NOZORDER
|nCopyFlag
);
140 void CResizableComboLBox::OnLButtonDown(UINT nFlags
, CPoint point
)
143 MapWindowPoints(NULL
, &pt
, 1); // to screen coord
145 LRESULT ht
= SendMessage(WM_NCHITTEST
, 0, MAKELPARAM(pt
.x
, pt
.y
));
147 if (ht
== HTBOTTOM
|| ht
== HTRIGHT
|| ht
== HTBOTTOMRIGHT
148 || ht
== HTLEFT
|| ht
== HTBOTTOMLEFT
)
153 GetWindowRect(&m_rcBeforeSizing
);
154 m_ptBeforeSizing
= pt
;
157 CWnd::OnLButtonDown(nFlags
, point
);
160 void CResizableComboLBox::OnLButtonUp(UINT nFlags
, CPoint point
)
162 CWnd::OnLButtonUp(nFlags
, point
);
168 UINT
CResizableComboLBox::OnNcHitTest(CPoint point
)
170 LRESULT
CResizableComboLBox::OnNcHitTest(CPoint point
)
174 GetClientRect(&rcClient
);
175 MapWindowPoints(NULL
, &rcClient
);
177 // ask for default hit-test value
178 UINT_PTR ht
= CWnd::OnNcHitTest(point
);
180 // disable improper resizing (based on layout setting)
184 if (!IsRTL() && point
.y
> rcClient
.top
)
190 if (IsRTL() && point
.y
> rcClient
.top
)
197 if (!IsRTL() && point
.y
> rcClient
.bottom
)
203 if (IsRTL() && point
.y
> rcClient
.bottom
)
225 void CResizableComboLBox::OnCaptureChanged(CWnd
*pWnd
)
229 CWnd::OnCaptureChanged(pWnd
);
232 void CResizableComboLBox::EndSizing()
236 GetWindowRect(&rect
);
237 m_sizeAfterSizing
= rect
.Size();
240 void CResizableComboLBox::OnWindowPosChanging(WINDOWPOS FAR
* lpwndpos
)
244 // restore the size when the drop-down list becomes visible
245 lpwndpos
->cx
= m_sizeAfterSizing
.cx
;
246 lpwndpos
->cy
= m_sizeAfterSizing
.cy
;
248 ApplyLimitsToPos(lpwndpos
);
250 CWnd::OnWindowPosChanging(lpwndpos
);
253 void CResizableComboLBox::OnWindowPosChanged(WINDOWPOS FAR
* lpwndpos
)
255 // default implementation sends a WM_SIZE message
256 // that can change the size again to force integral height
258 // since we do that manually during resize, we should also
259 // update the horizontal scrollbar
260 SendMessage(WM_HSCROLL
, SB_ENDSCROLL
, 0);
262 GetWindowRect(&m_pOwnerCombo
->m_rectDropDown
);
263 ::MapWindowPoints(NULL
, m_pOwnerCombo
->GetSafeHwnd(),
264 (LPPOINT
)&m_pOwnerCombo
->m_rectDropDown
, 2);
266 CWnd::OnWindowPosChanged(lpwndpos
);
269 void CResizableComboLBox::ApplyLimitsToPos(WINDOWPOS
* lpwndpos
)
271 //TRACE(">H w(%d)\n", lpwndpos->cy);
272 // to adjust horizontally, use window rect
274 // min width can't be less than combo's
276 m_pOwnerCombo
->GetWindowRect(&rect
);
277 m_sizeMin
.cx
= rect
.Width();
279 // apply horizontal limits
280 if (lpwndpos
->cx
< m_sizeMin
.cx
)
281 lpwndpos
->cx
= m_sizeMin
.cx
;
283 // fix horizontal alignment
284 rect
= CRect(0, 0, lpwndpos
->cx
, lpwndpos
->cy
);
285 m_pOwnerCombo
->MapWindowPoints(NULL
, &rect
);
286 lpwndpos
->x
= rect
.left
;
288 // to adjust vertically, use client rect
291 rect
= CRect(CPoint(lpwndpos
->x
, lpwndpos
->y
),
292 CSize(lpwndpos
->cx
, lpwndpos
->cy
));
293 SendMessage(WM_NCCALCSIZE
, FALSE
, (LPARAM
)&rect
);
294 CSize sizeClient
= rect
.Size();
296 // apply vertical limits
297 if (sizeClient
.cy
< m_sizeMin
.cy
)
298 sizeClient
.cy
= m_sizeMin
.cy
;
300 //TRACE(">H c(%d)\n", sizeClient.cy);
301 // adjust height, if needed
302 sizeClient
.cy
= m_pOwnerCombo
->MakeIntegralHeight(sizeClient
.cy
);
303 //TRACE(">H c(%d)\n", sizeClient.cy);
305 // back to window rect
306 rect
= CRect(0, 0, 1, sizeClient
.cy
);
307 DWORD dwStyle
= GetStyle();
308 ::AdjustWindowRectEx(&rect
, dwStyle
, FALSE
, GetExStyle());
309 lpwndpos
->cy
= rect
.Height();
310 if (dwStyle
& WS_HSCROLL
)
311 lpwndpos
->cy
+= GetSystemMetrics(SM_CYHSCROLL
);
313 //TRACE("H c(%d) w(%d)\n", sizeClient.cy, lpwndpos->cy);