OSDN Git Service

Fix merge miss branch info
[tortoisegit/TortoiseGitJp.git] / ext / ResizableLib / ResizableComboLBox.cpp
1 // ResizableComboLBox.cpp : implementation file\r
2 //\r
3 /////////////////////////////////////////////////////////////////////////////\r
4 //\r
5 // Copyright (C) 2000-2004 by Paolo Messina\r
6 // (http://www.geocities.com/ppescher - ppescher@hotmail.com)\r
7 //\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
12 //\r
13 // If you find this code useful, credits would be nice!\r
14 //\r
15 /////////////////////////////////////////////////////////////////////////////\r
16 \r
17 #include "stdafx.h"\r
18 #include "ResizableComboLBox.h"\r
19 #include "ResizableComboBox.h"\r
20 \r
21 #ifdef _DEBUG\r
22 #define new DEBUG_NEW\r
23 #undef THIS_FILE\r
24 static char THIS_FILE[] = __FILE__;\r
25 #endif\r
26 \r
27 /////////////////////////////////////////////////////////////////////////////\r
28 // CResizableComboLBox\r
29 \r
30 CResizableComboLBox::CResizableComboLBox()\r
31 {\r
32         m_dwAddToStyle = WS_THICKFRAME;\r
33         m_dwAddToStyleEx = 0;//WS_EX_CLIENTEDGE;\r
34         m_bSizing = FALSE;\r
35 }\r
36 \r
37 CResizableComboLBox::~CResizableComboLBox()\r
38 {\r
39 \r
40 }\r
41 \r
42 \r
43 BEGIN_MESSAGE_MAP(CResizableComboLBox, CWnd)\r
44         //{{AFX_MSG_MAP(CResizableComboLBox)\r
45         ON_WM_MOUSEMOVE()\r
46         ON_WM_LBUTTONDOWN()\r
47         ON_WM_LBUTTONUP()\r
48         ON_WM_NCHITTEST()\r
49         ON_WM_CAPTURECHANGED()\r
50         ON_WM_WINDOWPOSCHANGING()\r
51         ON_WM_WINDOWPOSCHANGED()\r
52         //}}AFX_MSG_MAP\r
53 END_MESSAGE_MAP()\r
54 \r
55 /////////////////////////////////////////////////////////////////////////////\r
56 // CResizableComboLBox message handlers\r
57 \r
58 void CResizableComboLBox::PreSubclassWindow() \r
59 {\r
60         CWnd::PreSubclassWindow();\r
61 \r
62         InitializeControl();\r
63 }\r
64 \r
65 BOOL CResizableComboLBox::IsRTL()\r
66 {\r
67         return (GetExStyle() & WS_EX_LAYOUTRTL);\r
68 }\r
69 \r
70 void CResizableComboLBox::InitializeControl()\r
71 {\r
72         CRect rect;\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
79 \r
80         // change window's style\r
81         ModifyStyleEx(0, m_dwAddToStyleEx);\r
82         ModifyStyle(0, m_dwAddToStyle, SWP_FRAMECHANGED);\r
83 \r
84         // count hscroll if present\r
85         if (GetStyle() & WS_HSCROLL)\r
86                 m_sizeAfterSizing.cy += GetSystemMetrics(SM_CYHSCROLL);\r
87 \r
88         SetWindowPos(NULL, 0, 0, m_sizeAfterSizing.cx, m_sizeAfterSizing.cy,\r
89                 SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);\r
90 }\r
91 \r
92 void CResizableComboLBox::OnMouseMove(UINT nFlags, CPoint point) \r
93 {\r
94         CPoint pt = point;\r
95         MapWindowPoints(NULL, &pt, 1);  // to screen coord\r
96 \r
97         if (!m_bSizing)\r
98         {\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
102 \r
103                 CWnd::OnMouseMove(nFlags, point);\r
104                 return;\r
105         }\r
106 \r
107         // during resize\r
108         CRect rect = m_rcBeforeSizing;\r
109         CSize relMove = pt - m_ptBeforeSizing;\r
110 \r
111         switch (m_nHitTest)\r
112         {\r
113         case HTBOTTOM:\r
114                 rect.bottom += relMove.cy;\r
115                 break;\r
116         case HTBOTTOMRIGHT:\r
117                 rect.bottom += relMove.cy;\r
118                 rect.right += relMove.cx;\r
119                 break;\r
120         case HTRIGHT:\r
121                 rect.right += relMove.cx;\r
122                 break;\r
123         case HTBOTTOMLEFT:\r
124                 rect.bottom += relMove.cy;\r
125                 rect.left += relMove.cx;\r
126                 break;\r
127         case HTLEFT:\r
128                 rect.left += relMove.cx;\r
129                 break;\r
130         }\r
131 \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
136 }\r
137 \r
138 void CResizableComboLBox::OnLButtonDown(UINT nFlags, CPoint point) \r
139 {\r
140         CPoint pt = point;\r
141         MapWindowPoints(NULL, &pt, 1);  // to screen coord\r
142 \r
143         LRESULT ht = SendMessage(WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));\r
144 \r
145         if (ht == HTBOTTOM || ht == HTRIGHT || ht == HTBOTTOMRIGHT\r
146                 || ht == HTLEFT || ht == HTBOTTOMLEFT)\r
147         {\r
148                 // start resizing\r
149                 m_bSizing = TRUE;\r
150                 m_nHitTest = ht;\r
151                 GetWindowRect(&m_rcBeforeSizing);\r
152                 m_ptBeforeSizing = pt;\r
153         }\r
154         else\r
155                 CWnd::OnLButtonDown(nFlags, point);\r
156 }\r
157 \r
158 void CResizableComboLBox::OnLButtonUp(UINT nFlags, CPoint point) \r
159 {\r
160         CWnd::OnLButtonUp(nFlags, point);\r
161 \r
162         EndSizing();\r
163 }\r
164 \r
165 #if _MSC_VER < 1400\r
166 UINT CResizableComboLBox::OnNcHitTest(CPoint point) \r
167 #else\r
168 LRESULT CResizableComboLBox::OnNcHitTest(CPoint point) \r
169 #endif\r
170 {\r
171         CRect rcClient;\r
172         GetClientRect(&rcClient);\r
173         MapWindowPoints(NULL, &rcClient);\r
174 \r
175         // ask for default hit-test value\r
176         UINT_PTR ht = CWnd::OnNcHitTest(point);\r
177 \r
178         // disable improper resizing (based on layout setting)\r
179         switch (ht)\r
180         {\r
181         case HTTOPRIGHT:\r
182                 if (!IsRTL() && point.y > rcClient.top)\r
183                         ht = HTRIGHT;\r
184                 else\r
185                         ht = HTBORDER;\r
186                 break;\r
187         case HTTOPLEFT:\r
188                 if (IsRTL() && point.y > rcClient.top)\r
189                         ht = HTLEFT;\r
190                 else\r
191                         ht = HTBORDER;\r
192                 break;\r
193 \r
194         case HTBOTTOMLEFT:\r
195                 if (!IsRTL() && point.y > rcClient.bottom)\r
196                         ht = HTBOTTOM;\r
197                 else if (!IsRTL())\r
198                         ht = HTBORDER;\r
199                 break;\r
200         case HTBOTTOMRIGHT:\r
201                 if (IsRTL() && point.y > rcClient.bottom)\r
202                         ht = HTBOTTOM;\r
203                 else if (IsRTL())\r
204                         ht = HTBORDER;\r
205                 break;\r
206 \r
207         case HTLEFT:\r
208                 if (!IsRTL())\r
209                         ht = HTBORDER;\r
210                 break;\r
211         case HTRIGHT:\r
212                 if (IsRTL())\r
213                         ht = HTBORDER;\r
214                 break;\r
215 \r
216         case HTTOP:\r
217                 ht = HTBORDER;\r
218         }\r
219 \r
220         return ht;\r
221 }\r
222 \r
223 void CResizableComboLBox::OnCaptureChanged(CWnd *pWnd) \r
224 {\r
225         EndSizing();\r
226 \r
227         CWnd::OnCaptureChanged(pWnd);\r
228 }\r
229 \r
230 void CResizableComboLBox::EndSizing()\r
231 {\r
232         m_bSizing = FALSE;\r
233         CRect rect;\r
234         GetWindowRect(&rect);\r
235         m_sizeAfterSizing = rect.Size();\r
236 }\r
237 \r
238 void CResizableComboLBox::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) \r
239 {\r
240         if (!m_bSizing)\r
241         {\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
245         }\r
246         ApplyLimitsToPos(lpwndpos);\r
247 \r
248         CWnd::OnWindowPosChanging(lpwndpos);\r
249 }\r
250 \r
251 void CResizableComboLBox::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) \r
252 {\r
253         // default implementation sends a WM_SIZE message\r
254         // that can change the size again to force integral height\r
255 \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
259 \r
260         GetWindowRect(&m_pOwnerCombo->m_rectDropDown);\r
261         ::MapWindowPoints(NULL, m_pOwnerCombo->GetSafeHwnd(),\r
262                 (LPPOINT)&m_pOwnerCombo->m_rectDropDown, 2);\r
263 \r
264         CWnd::OnWindowPosChanged(lpwndpos);\r
265 }\r
266 \r
267 void CResizableComboLBox::ApplyLimitsToPos(WINDOWPOS* lpwndpos)\r
268 {\r
269         //TRACE(">H w(%d)\n", lpwndpos->cy);\r
270         // to adjust horizontally, use window rect\r
271 \r
272         // min width can't be less than combo's\r
273         CRect rect;\r
274         m_pOwnerCombo->GetWindowRect(&rect);\r
275         m_sizeMin.cx = rect.Width();\r
276 \r
277         // apply horizontal limits\r
278         if (lpwndpos->cx < m_sizeMin.cx)\r
279                 lpwndpos->cx = m_sizeMin.cx;\r
280 \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
285 \r
286         // to adjust vertically, use client rect\r
287 \r
288         // get 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
293 \r
294         // apply vertical limits\r
295         if (sizeClient.cy < m_sizeMin.cy)\r
296                 sizeClient.cy = m_sizeMin.cy;\r
297 \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
302 \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
310 \r
311         //TRACE("H c(%d) w(%d)\n", sizeClient.cy, lpwndpos->cy);\r
312 }\r
313 \r