Merge branch 'git-for-windows-msys2'
[TortoiseGit.git] / ext / ResizableLib / ResizableComboLBox.cpp
blob788d6d9eeca585f2cdd44c4a39fbe2128b395b98
1 // ResizableComboLBox.cpp : implementation file
2 //
3 /////////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2000-2004 by Paolo Messina
6 // (http://www.geocities.com/ppescher - ppescher@hotmail.com)
7 //
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 /////////////////////////////////////////////////////////////////////////////
17 #include "stdafx.h"
18 #include "ResizableComboLBox.h"
19 #include "ResizableComboBox.h"
21 #ifdef _DEBUG
22 #define new DEBUG_NEW
23 #undef THIS_FILE
24 static char THIS_FILE[] = __FILE__;
25 #endif
27 /////////////////////////////////////////////////////////////////////////////
28 // CResizableComboLBox
30 CResizableComboLBox::CResizableComboLBox()
32 m_dwAddToStyle = WS_THICKFRAME;
33 m_dwAddToStyleEx = 0;//WS_EX_CLIENTEDGE;
34 m_bSizing = FALSE;
35 m_nHitTest = 0;
36 m_pOwnerCombo = NULL;
39 CResizableComboLBox::~CResizableComboLBox()
45 BEGIN_MESSAGE_MAP(CResizableComboLBox, CWnd)
46 //{{AFX_MSG_MAP(CResizableComboLBox)
47 ON_WM_MOUSEMOVE()
48 ON_WM_LBUTTONDOWN()
49 ON_WM_LBUTTONUP()
50 ON_WM_NCHITTEST()
51 ON_WM_CAPTURECHANGED()
52 ON_WM_WINDOWPOSCHANGING()
53 ON_WM_WINDOWPOSCHANGED()
54 //}}AFX_MSG_MAP
55 END_MESSAGE_MAP()
57 /////////////////////////////////////////////////////////////////////////////
58 // CResizableComboLBox message handlers
60 void CResizableComboLBox::PreSubclassWindow()
62 CWnd::PreSubclassWindow();
64 InitializeControl();
67 BOOL CResizableComboLBox::IsRTL()
69 return (GetExStyle() & WS_EX_LAYOUTRTL);
72 void CResizableComboLBox::InitializeControl()
74 CRect rect;
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)
96 CPoint pt = point;
97 MapWindowPoints(NULL, &pt, 1); // to screen coord
99 if (!m_bSizing)
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);
106 return;
109 // during resize
110 CRect rect = m_rcBeforeSizing;
111 CSize relMove = pt - m_ptBeforeSizing;
113 switch (m_nHitTest)
115 case HTBOTTOM:
116 rect.bottom += relMove.cy;
117 break;
118 case HTBOTTOMRIGHT:
119 rect.bottom += relMove.cy;
120 rect.right += relMove.cx;
121 break;
122 case HTRIGHT:
123 rect.right += relMove.cx;
124 break;
125 case HTBOTTOMLEFT:
126 rect.bottom += relMove.cy;
127 rect.left += relMove.cx;
128 break;
129 case HTLEFT:
130 rect.left += relMove.cx;
131 break;
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)
142 CPoint pt = 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)
150 // start resizing
151 m_bSizing = TRUE;
152 m_nHitTest = ht;
153 GetWindowRect(&m_rcBeforeSizing);
154 m_ptBeforeSizing = pt;
156 else
157 CWnd::OnLButtonDown(nFlags, point);
160 void CResizableComboLBox::OnLButtonUp(UINT nFlags, CPoint point)
162 CWnd::OnLButtonUp(nFlags, point);
164 EndSizing();
167 #if _MSC_VER < 1400
168 UINT CResizableComboLBox::OnNcHitTest(CPoint point)
169 #else
170 LRESULT CResizableComboLBox::OnNcHitTest(CPoint point)
171 #endif
173 CRect rcClient;
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)
181 switch (ht)
183 case HTTOPRIGHT:
184 if (!IsRTL() && point.y > rcClient.top)
185 ht = HTRIGHT;
186 else
187 ht = HTBORDER;
188 break;
189 case HTTOPLEFT:
190 if (IsRTL() && point.y > rcClient.top)
191 ht = HTLEFT;
192 else
193 ht = HTBORDER;
194 break;
196 case HTBOTTOMLEFT:
197 if (!IsRTL() && point.y > rcClient.bottom)
198 ht = HTBOTTOM;
199 else if (!IsRTL())
200 ht = HTBORDER;
201 break;
202 case HTBOTTOMRIGHT:
203 if (IsRTL() && point.y > rcClient.bottom)
204 ht = HTBOTTOM;
205 else if (IsRTL())
206 ht = HTBORDER;
207 break;
209 case HTLEFT:
210 if (!IsRTL())
211 ht = HTBORDER;
212 break;
213 case HTRIGHT:
214 if (IsRTL())
215 ht = HTBORDER;
216 break;
218 case HTTOP:
219 ht = HTBORDER;
222 return ht;
225 void CResizableComboLBox::OnCaptureChanged(CWnd *pWnd)
227 EndSizing();
229 CWnd::OnCaptureChanged(pWnd);
232 void CResizableComboLBox::EndSizing()
234 m_bSizing = FALSE;
235 CRect rect;
236 GetWindowRect(&rect);
237 m_sizeAfterSizing = rect.Size();
240 void CResizableComboLBox::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
242 if (!m_bSizing)
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
275 CRect rect;
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
290 // get 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);