OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / Utils / MiscUI / SplitterControl.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2006,2008 - TortoiseSVN\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include ".\splittercontrol.h"\r
21 \r
22 #ifdef _DEBUG\r
23 #define new DEBUG_NEW\r
24 #undef THIS_FILE\r
25 static char THIS_FILE[] = __FILE__;\r
26 #endif\r
27 \r
28 /////////////////////////////////////////////////////////////////////////////\r
29 // CSplitterControl\r
30 \r
31 // hCursor1 is for vertical one\r
32 // and hCursor2 is for horizontal one\r
33 static HCURSOR SplitterControl_hCursor1 = NULL;\r
34 static HCURSOR SplitterControl_hCursor2 = NULL;\r
35 \r
36 CSplitterControl::CSplitterControl()\r
37 {\r
38         // Mouse is pressed down or not ?\r
39         m_bIsPressed = FALSE;   \r
40 \r
41         // Min and Max range of the splitter.\r
42         m_nMin = m_nMax = -1;\r
43         m_bMouseOverControl = false;\r
44 }\r
45 \r
46 CSplitterControl::~CSplitterControl()\r
47 {\r
48 }\r
49 \r
50 \r
51 BEGIN_MESSAGE_MAP(CSplitterControl, CStatic)\r
52         ON_WM_PAINT()\r
53         ON_WM_MOUSEMOVE()\r
54         ON_WM_SETCURSOR()\r
55         ON_WM_LBUTTONDOWN()\r
56         ON_WM_LBUTTONUP()\r
57         ON_WM_ERASEBKGND()\r
58         ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)\r
59 END_MESSAGE_MAP()\r
60 \r
61 /////////////////////////////////////////////////////////////////////////////\r
62 // CSplitterControl message handlers\r
63 \r
64 \r
65 // Set style for splitter control\r
66 // nStyle = SPS_VERTICAL or SPS_HORIZONTAL\r
67 int CSplitterControl::SetSplitterStyle(int nStyle)\r
68 {\r
69         int m_nOldStyle = m_nType;\r
70         m_nType = nStyle;\r
71         return m_nOldStyle;\r
72 }\r
73 int CSplitterControl::GetSplitterStyle()\r
74 {\r
75         return m_nType;\r
76 }\r
77 \r
78 void CSplitterControl::OnPaint() \r
79 {\r
80         CPaintDC dc(this); // device context for painting\r
81         CRect rcClient;\r
82         GetClientRect(rcClient);\r
83         if (m_bMouseOverControl)\r
84         {\r
85                 CPen pen, *pOP;\r
86 \r
87                 rcClient.DeflateRect(1,1,1,1);\r
88 \r
89                 pen.CreatePen(0, 1, GetSysColor(COLOR_3DSHADOW));\r
90                 pOP = dc.SelectObject(&pen);\r
91 \r
92                 dc.MoveTo(rcClient.left, rcClient.top);\r
93                 dc.LineTo(rcClient.right, rcClient.top);\r
94                 dc.MoveTo(rcClient.left, rcClient.bottom);\r
95                 dc.LineTo(rcClient.right, rcClient.bottom);\r
96 \r
97                 // Restore pen\r
98                 dc.SelectObject(pOP);   \r
99         }\r
100         else\r
101         {\r
102                 dc.SetBkColor(GetSysColor(COLOR_3DFACE));\r
103                 dc.ExtTextOut(0, 0, ETO_OPAQUE, &rcClient, NULL, 0, NULL);\r
104         }\r
105 }\r
106 \r
107 void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point) \r
108 {\r
109         if (m_bIsPressed)\r
110         {\r
111                 CWindowDC dc(NULL);\r
112                 DrawLine(&dc);\r
113                 \r
114                 CPoint pt = point;\r
115                 ClientToScreen(&pt);\r
116                 GetParent()->ScreenToClient(&pt);\r
117 \r
118                 if (pt.x < m_nMin)\r
119                         pt.x = m_nMin;\r
120                 if (pt.y < m_nMin)\r
121                         pt.y = m_nMin;\r
122 \r
123                 if (pt.x > m_nMax)\r
124                         pt.x = m_nMax;\r
125                 if (pt.y > m_nMax)\r
126                         pt.y = m_nMax;\r
127 \r
128                 GetParent()->ClientToScreen(&pt);\r
129                 m_nX = pt.x;\r
130                 m_nY = pt.y;\r
131                 DrawLine(&dc);\r
132         }\r
133         if (!m_bMouseOverControl)\r
134         {\r
135                 TRACKMOUSEEVENT Tme;\r
136                 Tme.cbSize = sizeof(TRACKMOUSEEVENT);\r
137                 Tme.dwFlags = TME_LEAVE;\r
138                 Tme.hwndTrack = m_hWnd;\r
139                 TrackMouseEvent(&Tme);\r
140 \r
141                 m_bMouseOverControl = true;\r
142                 Invalidate();\r
143         }\r
144         CStatic::OnMouseMove(nFlags, point);\r
145 }\r
146 \r
147 LRESULT CSplitterControl::OnMouseLeave(WPARAM /*wParam*/, LPARAM /*lParam*/)\r
148 {\r
149         m_bMouseOverControl = false;\r
150         Invalidate();\r
151         return 0;\r
152 }\r
153 \r
154 BOOL CSplitterControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) \r
155 {\r
156         if (nHitTest == HTCLIENT)\r
157         {\r
158                 (m_nType == SPS_VERTICAL)?(::SetCursor(SplitterControl_hCursor1))\r
159                         :(::SetCursor(SplitterControl_hCursor2));\r
160                 return 0;\r
161         }\r
162         else\r
163                 return CStatic::OnSetCursor(pWnd, nHitTest, message);\r
164 }\r
165 \r
166 void CSplitterControl::OnLButtonDown(UINT nFlags, CPoint point) \r
167 {\r
168         CStatic::OnLButtonDown(nFlags, point);\r
169         \r
170         m_bIsPressed = TRUE;\r
171         SetCapture();\r
172         CRect rcWnd;\r
173         GetWindowRect(rcWnd);\r
174         \r
175         if (m_nType == SPS_VERTICAL)\r
176                 m_nX = rcWnd.left + rcWnd.Width() / 2;  \r
177         \r
178         else\r
179                 m_nY = rcWnd.top  + rcWnd.Height() / 2;\r
180         \r
181         if (m_nType == SPS_VERTICAL)\r
182                 m_nSavePos = m_nX;\r
183         else\r
184                 m_nSavePos = m_nY;\r
185 \r
186         CWindowDC dc(NULL);\r
187         DrawLine(&dc);\r
188 }\r
189 \r
190 void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point) \r
191 {\r
192         if (m_bIsPressed)\r
193         {\r
194                 ClientToScreen(&point);\r
195                 CWindowDC dc(NULL);\r
196 \r
197                 DrawLine(&dc);\r
198                 CPoint pt(m_nX, m_nY);\r
199                 m_bIsPressed = FALSE;\r
200                 CWnd *pOwner = GetOwner();\r
201                 if (pOwner && IsWindow(pOwner->m_hWnd))\r
202                 {\r
203                         CRect rc;\r
204                         int delta;\r
205                         pOwner->GetClientRect(rc);\r
206                         pOwner->ScreenToClient(&pt);\r
207                         MoveWindowTo(pt);\r
208 \r
209                         if (m_nType == SPS_VERTICAL)\r
210                                 delta = m_nX - m_nSavePos;\r
211                         else\r
212                                 delta = m_nY - m_nSavePos;\r
213                         \r
214                         \r
215                         SPC_NMHDR nmsp;\r
216                 \r
217                         nmsp.hdr.hwndFrom = m_hWnd;\r
218                         nmsp.hdr.idFrom   = GetDlgCtrlID();\r
219                         nmsp.hdr.code     = SPN_SIZED;\r
220                         nmsp.delta = delta;\r
221 \r
222                         pOwner->SendMessage(WM_NOTIFY, nmsp.hdr.idFrom, (LPARAM)&nmsp);\r
223                 }\r
224         }\r
225 \r
226         CStatic::OnLButtonUp(nFlags, point);\r
227         ReleaseCapture();\r
228 }\r
229 \r
230 void CSplitterControl::DrawLine(CDC* pDC)\r
231 {\r
232         int nRop = pDC->SetROP2(R2_NOTXORPEN);\r
233 \r
234         CRect rcWnd;\r
235         int d = 1;\r
236         GetWindowRect(rcWnd);\r
237         CPen  pen;\r
238         pen.CreatePen(0, 1, ::GetSysColor(COLOR_GRAYTEXT));\r
239         CPen *pOP = pDC->SelectObject(&pen);\r
240         \r
241         if (m_nType == SPS_VERTICAL)\r
242         {\r
243                 pDC->MoveTo(m_nX - d, rcWnd.top);\r
244                 pDC->LineTo(m_nX - d, rcWnd.bottom);\r
245 \r
246                 pDC->MoveTo(m_nX + d, rcWnd.top);\r
247                 pDC->LineTo(m_nX + d, rcWnd.bottom);\r
248         }\r
249         else // m_nType == SPS_HORIZONTAL\r
250         {\r
251                 pDC->MoveTo(rcWnd.left, m_nY - d);\r
252                 pDC->LineTo(rcWnd.right, m_nY - d);\r
253                 \r
254                 pDC->MoveTo(rcWnd.left, m_nY + d);\r
255                 pDC->LineTo(rcWnd.right, m_nY + d);\r
256         }\r
257         pDC->SetROP2(nRop);\r
258         pDC->SelectObject(pOP);\r
259 }\r
260 \r
261 void CSplitterControl::MoveWindowTo(CPoint pt)\r
262 {\r
263         CRect rc;\r
264         GetWindowRect(rc);\r
265         CWnd* pParent;\r
266         pParent = GetParent();\r
267         if (!pParent || !::IsWindow(pParent->m_hWnd))\r
268                 return;\r
269 \r
270         pParent->ScreenToClient(rc);\r
271         if (m_nType == SPS_VERTICAL)\r
272         {       \r
273                 int nMidX = (rc.left + rc.right) / 2;\r
274                 int dx = pt.x - nMidX;\r
275                 rc.OffsetRect(dx, 0);\r
276         }\r
277         else\r
278         {       \r
279                 int nMidY = (rc.top + rc.bottom) / 2;\r
280                 int dy = pt.y - nMidY;\r
281                 rc.OffsetRect(0, dy);\r
282         }\r
283         MoveWindow(rc);\r
284 }\r
285 \r
286 void CSplitterControl::ChangeWidth(CWnd *pWnd, int dx, DWORD dwFlag)\r
287 {\r
288         CWnd* pParent = pWnd->GetParent();\r
289         if (pParent && ::IsWindow(pParent->m_hWnd))\r
290         {\r
291                 CRect rcWnd;\r
292                 pWnd->GetWindowRect(rcWnd);\r
293                 pParent->ScreenToClient(rcWnd);\r
294                 if (dwFlag == CW_LEFTALIGN)\r
295                         rcWnd.right += dx;\r
296                 else if (dwFlag == CW_RIGHTALIGN)\r
297                         rcWnd.left -= dx;\r
298                 pWnd->MoveWindow(rcWnd);\r
299         }\r
300 }\r
301 \r
302 void CSplitterControl::ChangeHeight(CWnd *pWnd, int dy, DWORD dwFlag)\r
303 {\r
304         CWnd* pParent = pWnd->GetParent();\r
305         if (pParent && ::IsWindow(pParent->m_hWnd))\r
306         {\r
307                 CRect rcWnd;\r
308                 pWnd->GetWindowRect(rcWnd);\r
309                 pParent->ScreenToClient(rcWnd);\r
310                 if (dwFlag == CW_TOPALIGN)\r
311                         rcWnd.bottom += dy;\r
312                 else if (dwFlag == CW_BOTTOMALIGN)\r
313                         rcWnd.top -= dy;\r
314                 pWnd->MoveWindow(rcWnd);\r
315         }\r
316 }\r
317 \r
318 void CSplitterControl::ChangePos(CWnd* pWnd, int dx, int dy)\r
319 {\r
320         CWnd* pParent = pWnd->GetParent();\r
321         if (pParent && ::IsWindow(pParent->m_hWnd))\r
322         {\r
323                 CRect rcWnd;\r
324                 pWnd->GetWindowRect(rcWnd);\r
325                 pParent->ScreenToClient(rcWnd);\r
326                 rcWnd.OffsetRect(-dx, dy);\r
327 \r
328                 pWnd->MoveWindow(rcWnd);\r
329         }       \r
330 }\r
331 \r
332 void CSplitterControl::SetRange(int nMin, int nMax)\r
333 {\r
334         m_nMin = nMin;\r
335         m_nMax = nMax;\r
336 }\r
337 \r
338 // Set splitter range from (nRoot - nSubtraction) to (nRoot + nAddition)\r
339 // If (nRoot < 0)\r
340 //              nRoot =  <current position of the splitter>\r
341 void CSplitterControl::SetRange(int nSubtraction, int nAddition, int nRoot)\r
342 {\r
343         if (nRoot < 0)\r
344         {\r
345                 CRect rcWnd;\r
346                 GetWindowRect(rcWnd);\r
347                 if (m_nType == SPS_VERTICAL)\r
348                         nRoot = rcWnd.left + rcWnd.Width() / 2;\r
349                 else // if m_nType == SPS_HORIZONTAL\r
350                         nRoot = rcWnd.top + rcWnd.Height() / 2;\r
351         }\r
352         m_nMin = nRoot - nSubtraction;\r
353         m_nMax = nRoot + nAddition;\r
354 }\r
355 void CSplitterControl::PreSubclassWindow()\r
356 {\r
357         // Enable notifications - CStatic has this disabled by default\r
358         DWORD dwStyle = GetStyle();\r
359         ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY);\r
360 \r
361         CRect rc;\r
362         GetClientRect(rc);\r
363 \r
364         // Determine default type base on it's size.\r
365         m_nType = (rc.Width() < rc.Height())?SPS_VERTICAL:SPS_HORIZONTAL;\r
366 \r
367         if (!SplitterControl_hCursor1)\r
368         {\r
369                 SplitterControl_hCursor1 = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);\r
370                 SplitterControl_hCursor2 = AfxGetApp()->LoadStandardCursor(IDC_SIZENS);\r
371         }\r
372 \r
373         // force the splitter not to be splitted.\r
374         SetRange(0, 0, -1);\r
375 \r
376 \r
377         CStatic::PreSubclassWindow();\r
378 }\r
379 \r
380 BOOL CSplitterControl::OnEraseBkgnd(CDC* /*pDC*/)\r
381 {\r
382         return TRUE;\r
383 }\r