1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2006,2008 - TortoiseSVN
\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
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
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
20 #include ".\splittercontrol.h"
\r
23 #define new DEBUG_NEW
\r
25 static char THIS_FILE[] = __FILE__;
\r
28 /////////////////////////////////////////////////////////////////////////////
\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
36 CSplitterControl::CSplitterControl()
\r
38 // Mouse is pressed down or not ?
\r
39 m_bIsPressed = FALSE;
\r
41 // Min and Max range of the splitter.
\r
42 m_nMin = m_nMax = -1;
\r
43 m_bMouseOverControl = false;
\r
46 CSplitterControl::~CSplitterControl()
\r
51 BEGIN_MESSAGE_MAP(CSplitterControl, CStatic)
\r
58 ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
\r
61 /////////////////////////////////////////////////////////////////////////////
\r
62 // CSplitterControl message handlers
\r
65 // Set style for splitter control
\r
66 // nStyle = SPS_VERTICAL or SPS_HORIZONTAL
\r
67 int CSplitterControl::SetSplitterStyle(int nStyle)
\r
69 int m_nOldStyle = m_nType;
\r
73 int CSplitterControl::GetSplitterStyle()
\r
78 void CSplitterControl::OnPaint()
\r
80 CPaintDC dc(this); // device context for painting
\r
82 GetClientRect(rcClient);
\r
83 if (m_bMouseOverControl)
\r
87 rcClient.DeflateRect(1,1,1,1);
\r
89 pen.CreatePen(0, 1, GetSysColor(COLOR_3DSHADOW));
\r
90 pOP = dc.SelectObject(&pen);
\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
98 dc.SelectObject(pOP);
\r
102 dc.SetBkColor(GetSysColor(COLOR_3DFACE));
\r
103 dc.ExtTextOut(0, 0, ETO_OPAQUE, &rcClient, NULL, 0, NULL);
\r
107 void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point)
\r
111 CWindowDC dc(NULL);
\r
115 ClientToScreen(&pt);
\r
116 GetParent()->ScreenToClient(&pt);
\r
128 GetParent()->ClientToScreen(&pt);
\r
133 if (!m_bMouseOverControl)
\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
141 m_bMouseOverControl = true;
\r
144 CStatic::OnMouseMove(nFlags, point);
\r
147 LRESULT CSplitterControl::OnMouseLeave(WPARAM /*wParam*/, LPARAM /*lParam*/)
\r
149 m_bMouseOverControl = false;
\r
154 BOOL CSplitterControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
\r
156 if (nHitTest == HTCLIENT)
\r
158 (m_nType == SPS_VERTICAL)?(::SetCursor(SplitterControl_hCursor1))
\r
159 :(::SetCursor(SplitterControl_hCursor2));
\r
163 return CStatic::OnSetCursor(pWnd, nHitTest, message);
\r
166 void CSplitterControl::OnLButtonDown(UINT nFlags, CPoint point)
\r
168 CStatic::OnLButtonDown(nFlags, point);
\r
170 m_bIsPressed = TRUE;
\r
173 GetWindowRect(rcWnd);
\r
175 if (m_nType == SPS_VERTICAL)
\r
176 m_nX = rcWnd.left + rcWnd.Width() / 2;
\r
179 m_nY = rcWnd.top + rcWnd.Height() / 2;
\r
181 if (m_nType == SPS_VERTICAL)
\r
186 CWindowDC dc(NULL);
\r
190 void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point)
\r
194 ClientToScreen(&point);
\r
195 CWindowDC dc(NULL);
\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
205 pOwner->GetClientRect(rc);
\r
206 pOwner->ScreenToClient(&pt);
\r
209 if (m_nType == SPS_VERTICAL)
\r
210 delta = m_nX - m_nSavePos;
\r
212 delta = m_nY - m_nSavePos;
\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
222 pOwner->SendMessage(WM_NOTIFY, nmsp.hdr.idFrom, (LPARAM)&nmsp);
\r
226 CStatic::OnLButtonUp(nFlags, point);
\r
230 void CSplitterControl::DrawLine(CDC* pDC)
\r
232 int nRop = pDC->SetROP2(R2_NOTXORPEN);
\r
236 GetWindowRect(rcWnd);
\r
238 pen.CreatePen(0, 1, ::GetSysColor(COLOR_GRAYTEXT));
\r
239 CPen *pOP = pDC->SelectObject(&pen);
\r
241 if (m_nType == SPS_VERTICAL)
\r
243 pDC->MoveTo(m_nX - d, rcWnd.top);
\r
244 pDC->LineTo(m_nX - d, rcWnd.bottom);
\r
246 pDC->MoveTo(m_nX + d, rcWnd.top);
\r
247 pDC->LineTo(m_nX + d, rcWnd.bottom);
\r
249 else // m_nType == SPS_HORIZONTAL
\r
251 pDC->MoveTo(rcWnd.left, m_nY - d);
\r
252 pDC->LineTo(rcWnd.right, m_nY - d);
\r
254 pDC->MoveTo(rcWnd.left, m_nY + d);
\r
255 pDC->LineTo(rcWnd.right, m_nY + d);
\r
257 pDC->SetROP2(nRop);
\r
258 pDC->SelectObject(pOP);
\r
261 void CSplitterControl::MoveWindowTo(CPoint pt)
\r
266 pParent = GetParent();
\r
267 if (!pParent || !::IsWindow(pParent->m_hWnd))
\r
270 pParent->ScreenToClient(rc);
\r
271 if (m_nType == SPS_VERTICAL)
\r
273 int nMidX = (rc.left + rc.right) / 2;
\r
274 int dx = pt.x - nMidX;
\r
275 rc.OffsetRect(dx, 0);
\r
279 int nMidY = (rc.top + rc.bottom) / 2;
\r
280 int dy = pt.y - nMidY;
\r
281 rc.OffsetRect(0, dy);
\r
286 void CSplitterControl::ChangeWidth(CWnd *pWnd, int dx, DWORD dwFlag)
\r
288 CWnd* pParent = pWnd->GetParent();
\r
289 if (pParent && ::IsWindow(pParent->m_hWnd))
\r
292 pWnd->GetWindowRect(rcWnd);
\r
293 pParent->ScreenToClient(rcWnd);
\r
294 if (dwFlag == CW_LEFTALIGN)
\r
296 else if (dwFlag == CW_RIGHTALIGN)
\r
298 pWnd->MoveWindow(rcWnd);
\r
302 void CSplitterControl::ChangeHeight(CWnd *pWnd, int dy, DWORD dwFlag)
\r
304 CWnd* pParent = pWnd->GetParent();
\r
305 if (pParent && ::IsWindow(pParent->m_hWnd))
\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
314 pWnd->MoveWindow(rcWnd);
\r
318 void CSplitterControl::ChangePos(CWnd* pWnd, int dx, int dy)
\r
320 CWnd* pParent = pWnd->GetParent();
\r
321 if (pParent && ::IsWindow(pParent->m_hWnd))
\r
324 pWnd->GetWindowRect(rcWnd);
\r
325 pParent->ScreenToClient(rcWnd);
\r
326 rcWnd.OffsetRect(-dx, dy);
\r
328 pWnd->MoveWindow(rcWnd);
\r
332 void CSplitterControl::SetRange(int nMin, int nMax)
\r
338 // Set splitter range from (nRoot - nSubtraction) to (nRoot + nAddition)
\r
340 // nRoot = <current position of the splitter>
\r
341 void CSplitterControl::SetRange(int nSubtraction, int nAddition, int nRoot)
\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
352 m_nMin = nRoot - nSubtraction;
\r
353 m_nMax = nRoot + nAddition;
\r
355 void CSplitterControl::PreSubclassWindow()
\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
364 // Determine default type base on it's size.
\r
365 m_nType = (rc.Width() < rc.Height())?SPS_VERTICAL:SPS_HORIZONTAL;
\r
367 if (!SplitterControl_hCursor1)
\r
369 SplitterControl_hCursor1 = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
\r
370 SplitterControl_hCursor2 = AfxGetApp()->LoadStandardCursor(IDC_SIZENS);
\r
373 // force the splitter not to be splitted.
\r
374 SetRange(0, 0, -1);
\r
377 CStatic::PreSubclassWindow();
\r
380 BOOL CSplitterControl::OnEraseBkgnd(CDC* /*pDC*/)
\r