1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2006,2010 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include ".\splittercontrol.h"
25 static char THIS_FILE
[] = __FILE__
;
28 /////////////////////////////////////////////////////////////////////////////
31 // hCursor1 is for vertical one
32 // and hCursor2 is for horizontal one
33 static HCURSOR SplitterControl_hCursor1
= NULL
;
34 static HCURSOR SplitterControl_hCursor2
= NULL
;
36 CSplitterControl::CSplitterControl()
40 , m_bMouseOverControl(false)
48 CSplitterControl::~CSplitterControl()
53 BEGIN_MESSAGE_MAP(CSplitterControl
, CStatic
)
60 ON_MESSAGE(WM_MOUSELEAVE
, OnMouseLeave
)
63 /////////////////////////////////////////////////////////////////////////////
64 // CSplitterControl message handlers
67 // Set style for splitter control
68 // nStyle = SPS_VERTICAL or SPS_HORIZONTAL
69 int CSplitterControl::SetSplitterStyle(int nStyle
)
71 int m_nOldStyle
= m_nType
;
75 int CSplitterControl::GetSplitterStyle()
80 void CSplitterControl::OnPaint()
82 CPaintDC
dc(this); // device context for painting
84 GetClientRect(rcClient
);
85 if (m_bMouseOverControl
)
89 rcClient
.DeflateRect(1,1,1,1);
91 pen
.CreatePen(0, 1, GetSysColor(COLOR_3DSHADOW
));
92 pOP
= dc
.SelectObject(&pen
);
94 dc
.MoveTo(rcClient
.left
, rcClient
.top
);
95 dc
.LineTo(rcClient
.right
, rcClient
.top
);
96 dc
.MoveTo(rcClient
.left
, rcClient
.bottom
);
97 dc
.LineTo(rcClient
.right
, rcClient
.bottom
);
100 dc
.SelectObject(pOP
);
104 dc
.SetBkColor(GetSysColor(COLOR_3DFACE
));
105 dc
.ExtTextOut(0, 0, ETO_OPAQUE
, &rcClient
, NULL
, 0, NULL
);
109 void CSplitterControl::OnMouseMove(UINT nFlags
, CPoint point
)
118 GetParent()->ScreenToClient(&pt
);
130 GetParent()->ClientToScreen(&pt
);
135 if (!m_bMouseOverControl
)
138 Tme
.cbSize
= sizeof(TRACKMOUSEEVENT
);
139 Tme
.dwFlags
= TME_LEAVE
;
140 Tme
.hwndTrack
= m_hWnd
;
141 TrackMouseEvent(&Tme
);
143 m_bMouseOverControl
= true;
146 CStatic::OnMouseMove(nFlags
, point
);
149 LRESULT
CSplitterControl::OnMouseLeave(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
151 m_bMouseOverControl
= false;
156 BOOL
CSplitterControl::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
158 if (nHitTest
== HTCLIENT
)
160 (m_nType
== SPS_VERTICAL
)?(::SetCursor(SplitterControl_hCursor1
))
161 :(::SetCursor(SplitterControl_hCursor2
));
165 return CStatic::OnSetCursor(pWnd
, nHitTest
, message
);
168 void CSplitterControl::OnLButtonDown(UINT nFlags
, CPoint point
)
170 CStatic::OnLButtonDown(nFlags
, point
);
175 GetWindowRect(rcWnd
);
177 if (m_nType
== SPS_VERTICAL
)
178 m_nX
= rcWnd
.left
+ rcWnd
.Width() / 2;
181 m_nY
= rcWnd
.top
+ rcWnd
.Height() / 2;
183 if (m_nType
== SPS_VERTICAL
)
192 void CSplitterControl::OnLButtonUp(UINT nFlags
, CPoint point
)
196 ClientToScreen(&point
);
200 CPoint
pt(m_nX
, m_nY
);
201 m_bIsPressed
= FALSE
;
202 CWnd
*pOwner
= GetOwner();
203 if (pOwner
&& IsWindow(pOwner
->m_hWnd
))
207 pOwner
->GetClientRect(rc
);
208 pOwner
->ScreenToClient(&pt
);
211 if (m_nType
== SPS_VERTICAL
)
212 delta
= m_nX
- m_nSavePos
;
214 delta
= m_nY
- m_nSavePos
;
219 nmsp
.hdr
.hwndFrom
= m_hWnd
;
220 nmsp
.hdr
.idFrom
= GetDlgCtrlID();
221 nmsp
.hdr
.code
= SPN_SIZED
;
224 pOwner
->SendMessage(WM_NOTIFY
, nmsp
.hdr
.idFrom
, (LPARAM
)&nmsp
);
228 CStatic::OnLButtonUp(nFlags
, point
);
232 void CSplitterControl::DrawLine(CDC
* pDC
)
234 int nRop
= pDC
->SetROP2(R2_NOTXORPEN
);
238 GetWindowRect(rcWnd
);
240 pen
.CreatePen(0, 1, ::GetSysColor(COLOR_GRAYTEXT
));
241 CPen
*pOP
= pDC
->SelectObject(&pen
);
243 if (m_nType
== SPS_VERTICAL
)
245 pDC
->MoveTo(m_nX
- d
, rcWnd
.top
);
246 pDC
->LineTo(m_nX
- d
, rcWnd
.bottom
);
248 pDC
->MoveTo(m_nX
+ d
, rcWnd
.top
);
249 pDC
->LineTo(m_nX
+ d
, rcWnd
.bottom
);
251 else // m_nType == SPS_HORIZONTAL
253 pDC
->MoveTo(rcWnd
.left
, m_nY
- d
);
254 pDC
->LineTo(rcWnd
.right
, m_nY
- d
);
256 pDC
->MoveTo(rcWnd
.left
, m_nY
+ d
);
257 pDC
->LineTo(rcWnd
.right
, m_nY
+ d
);
260 pDC
->SelectObject(pOP
);
263 void CSplitterControl::MoveWindowTo(CPoint pt
)
268 pParent
= GetParent();
269 if (!pParent
|| !::IsWindow(pParent
->m_hWnd
))
272 pParent
->ScreenToClient(rc
);
273 if (m_nType
== SPS_VERTICAL
)
275 int nMidX
= (rc
.left
+ rc
.right
) / 2;
276 int dx
= pt
.x
- nMidX
;
277 rc
.OffsetRect(dx
, 0);
281 int nMidY
= (rc
.top
+ rc
.bottom
) / 2;
282 int dy
= pt
.y
- nMidY
;
283 rc
.OffsetRect(0, dy
);
288 void CSplitterControl::ChangeWidth(CWnd
*pWnd
, int dx
, DWORD dwFlag
)
290 CWnd
* pParent
= pWnd
->GetParent();
291 if (pParent
&& ::IsWindow(pParent
->m_hWnd
))
294 pWnd
->GetWindowRect(rcWnd
);
295 pParent
->ScreenToClient(rcWnd
);
296 if (dwFlag
== CW_LEFTALIGN
)
298 else if (dwFlag
== CW_RIGHTALIGN
)
300 pWnd
->MoveWindow(rcWnd
);
304 void CSplitterControl::ChangeHeight(CWnd
*pWnd
, int dy
, DWORD dwFlag
)
306 CWnd
* pParent
= pWnd
->GetParent();
307 if (pParent
&& ::IsWindow(pParent
->m_hWnd
))
310 pWnd
->GetWindowRect(rcWnd
);
311 pParent
->ScreenToClient(rcWnd
);
312 if (dwFlag
== CW_TOPALIGN
)
314 else if (dwFlag
== CW_BOTTOMALIGN
)
316 pWnd
->MoveWindow(rcWnd
);
320 void CSplitterControl::ChangePos(CWnd
* pWnd
, int dx
, int dy
)
322 CWnd
* pParent
= pWnd
->GetParent();
323 if (pParent
&& ::IsWindow(pParent
->m_hWnd
))
326 pWnd
->GetWindowRect(rcWnd
);
327 pParent
->ScreenToClient(rcWnd
);
328 rcWnd
.OffsetRect(-dx
, dy
);
330 pWnd
->MoveWindow(rcWnd
);
334 void CSplitterControl::SetRange(int nMin
, int nMax
)
340 // Set splitter range from (nRoot - nSubtraction) to (nRoot + nAddition)
342 // nRoot = <current position of the splitter>
343 void CSplitterControl::SetRange(int nSubtraction
, int nAddition
, int nRoot
)
348 GetWindowRect(rcWnd
);
349 if (m_nType
== SPS_VERTICAL
)
350 nRoot
= rcWnd
.left
+ rcWnd
.Width() / 2;
351 else // if m_nType == SPS_HORIZONTAL
352 nRoot
= rcWnd
.top
+ rcWnd
.Height() / 2;
354 m_nMin
= nRoot
- nSubtraction
;
355 m_nMax
= nRoot
+ nAddition
;
357 void CSplitterControl::PreSubclassWindow()
359 // Enable notifications - CStatic has this disabled by default
360 DWORD dwStyle
= GetStyle();
361 ::SetWindowLong(GetSafeHwnd(), GWL_STYLE
, dwStyle
| SS_NOTIFY
);
366 // Determine default type base on it's size.
367 m_nType
= (rc
.Width() < rc
.Height())?SPS_VERTICAL
:SPS_HORIZONTAL
;
369 if (!SplitterControl_hCursor1
)
371 SplitterControl_hCursor1
= AfxGetApp()->LoadStandardCursor(IDC_SIZEWE
);
372 SplitterControl_hCursor2
= AfxGetApp()->LoadStandardCursor(IDC_SIZENS
);
375 // force the splitter not to be splitted.
379 CStatic::PreSubclassWindow();
382 BOOL
CSplitterControl::OnEraseBkgnd(CDC
* /*pDC*/)