text: // SplitterControl.cpp : implementation file
  //
  
  #include "stdafx.h"
  #include "SplitterControl.h"
  
  #ifdef _DEBUG
  #define new DEBUG_NEW
  #undef THIS_FILE
  static char THIS_FILE[] = __FILE__;
  #endif
  
  /////////////////////////////////////////////////////////////////////////////
  // CSplitterControl
  
  // hCursor1 is for vertiacal one
  // and hCursor2 is for horizontal one
  static HCURSOR SplitterControl_hCursor1 = NULL;
  static HCURSOR SplitterControl_hCursor2 = NULL;
  
  CSplitterControl::CSplitterControl()
  {
  	// Mouse is pressed down or not ?
  	m_bIsPressed = FALSE;	
  
  	// Min and Max range of the splitter.
  	m_nMin = m_nMax = -1;
  }
  
  CSplitterControl::~CSplitterControl()
  {
  }
  
  
  BEGIN_MESSAGE_MAP(CSplitterControl, CStatic)
  	//{{AFX_MSG_MAP(CSplitterControl)
  	ON_WM_PAINT()
  	ON_WM_MOUSEMOVE()
  	ON_WM_SETCURSOR()
  	ON_WM_LBUTTONDOWN()
  	ON_WM_LBUTTONUP()
  	//}}AFX_MSG_MAP
  END_MESSAGE_MAP()
  
  /////////////////////////////////////////////////////////////////////////////
  // CSplitterControl message handlers
  
  /****************************************************
  *	Create(DWORD dwStyle, const CRect& rect, CWnd* pParent, nID)
  *	Use this function instead of the CStatic::Create function
  * Parameters: No need to explain (see MSDN (:-) )
  *
  ****************************************************/
  void CSplitterControl::Create(DWORD dwStyle, const CRect &rect, CWnd *pParent, UINT nID)
  {
  	CRect rc = rect;
  	dwStyle |= SS_NOTIFY;
  	
  	// Determine default type base on it's size.
  	m_nType = (rc.Width() < rc.Height())?
  					SPS_VERTICAL:
  					SPS_HORIZONTAL;
  	
  	if (m_nType == SPS_VERTICAL)
  		rc.right = rc.left + 5;
  	else // SPS_HORIZONTAL
  		rc.bottom = rc.top + 5;
  	
  	CStatic::Create("", dwStyle, rc, pParent, nID);
  	
  	if (!SplitterControl_hCursor1)
  	{
  		SplitterControl_hCursor1 = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
  		SplitterControl_hCursor2 = AfxGetApp()->LoadStandardCursor(IDC_SIZENS);
  	}
  	
  	// force the splitter not to be splited.
  	SetRange(0, 0, -1);
  }
  
  // Set style for splitter control
  // nStyle = SPS_VERTICAL or SPS_HORIZONTAL
  int CSplitterControl::SetStyle(int nStyle)
  {
  	int m_nOldStyle = m_nType;
  	m_nType = nStyle;
  	return m_nOldStyle;
  }
  int CSplitterControl::GetStyle()
  {
  	return m_nType;
  }
  
  void CSplitterControl::OnPaint() 
  {
  	CPaintDC dc(this); // device context for painting
  	CRect rcClient;
  	GetClientRect(rcClient);
  	
  	CBrush br, *pOB;
  	CPen pen, *pOP;
  
  	//dc.Draw3dRect(rcClient, GetSysColor(COLOR_BTNHIGHLIGHT), GetSysColor(COLOR_BTNSHADOW));	
  	rcClient.DeflateRect(1,1,1,1);
  	
  	pen.CreatePen(0, 1, RGB(200, 200, 200));
  	br.CreateSolidBrush(RGB(200, 220, 220));
  	pOB = dc.SelectObject(&br);
  	pOP = dc.SelectObject(&pen);
  	
  	//dc.Rectangle(rcClient);
  
  	// Restore pen and brush
  	DeleteObject(dc.SelectObject(pOB));
  	DeleteObject(dc.SelectObject(pOP));
  }
  
  void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point) 
  {
  	if (m_bIsPressed)
  	{
  		CWindowDC dc(NULL);
  		DrawLine(&dc, m_nX, m_nY);
  		
  		CPoint pt = point;
  		ClientToScreen(&pt);
  		GetParent()->ScreenToClient(&pt);
  
  		if (pt.x < m_nMin)
  			pt.x = m_nMin;
  		if (pt.y < m_nMin)
  			pt.y = m_nMin;
  
  		if (pt.x > m_nMax)
  			pt.x = m_nMax;
  		if (pt.y > m_nMax)
  			pt.y = m_nMax;
  
  		GetParent()->ClientToScreen(&pt);
  		m_nX = pt.x;
  		m_nY = pt.y;
  		DrawLine(&dc, m_nX, m_nY);
  	}
  	CStatic::OnMouseMove(nFlags, point);
  }
  
  BOOL CSplitterControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
  {
  	if (nHitTest == HTCLIENT)
  	{
  		(m_nType == SPS_VERTICAL)?(::SetCursor(SplitterControl_hCursor1))
  			:(::SetCursor(SplitterControl_hCursor2));
  		return 0;
  	}
  	else
  		return CStatic::OnSetCursor(pWnd, nHitTest, message);
  }
  
  void CSplitterControl::OnLButtonDown(UINT nFlags, CPoint point) 
  {
  	CStatic::OnLButtonDown(nFlags, point);
  	
  	m_bIsPressed = TRUE;
  	SetCapture();
  	CRect rcWnd;
  	GetWindowRect(rcWnd);
  	
  	if (m_nType == SPS_VERTICAL)
  		m_nX = rcWnd.left + rcWnd.Width() / 2;	
  	
  	else
  		m_nY = rcWnd.top  + rcWnd.Height() / 2;
  	
  	if (m_nType == SPS_VERTICAL)
  		m_nSavePos = m_nX;
  	else
  		m_nSavePos = m_nY;
  
  	CWindowDC dc(NULL);
  	DrawLine(&dc, m_nX, m_nY);
  }
  
  void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point) 
  {
  	if (m_bIsPressed)
  	{
  		ClientToScreen(&point);
  		CWindowDC dc(NULL);
  
  		DrawLine(&dc, m_nX, m_nY);
  		CPoint pt(m_nX, m_nY);
  		m_bIsPressed = FALSE;
  		CWnd *pOwner = GetOwner();
  		if (pOwner && IsWindow(pOwner->m_hWnd))
  		{
  			CRect rc;
  			int delta;
  			pOwner->GetClientRect(rc);
  			pOwner->ScreenToClient(&pt);
  			MoveWindowTo(pt);
  
  			if (m_nType == SPS_VERTICAL)
  				delta = m_nX - m_nSavePos;
  			else
  				delta = m_nY - m_nSavePos;
  			
  			
  			SPC_NMHDR nmsp;
  		
  			nmsp.hdr.hwndFrom = m_hWnd;
  			nmsp.hdr.idFrom   = GetDlgCtrlID();
  			nmsp.hdr.code     = SPN_SIZED;
  			nmsp.delta = delta;
  
  			pOwner->SendMessage(WM_NOTIFY, nmsp.hdr.idFrom, (LPARAM)&nmsp);
  		}
  	}
  
  	CStatic::OnLButtonUp(nFlags, point);
  	ReleaseCapture();
  }
  
  void CSplitterControl::DrawLine(CDC* pDC, int x, int y)
  {
  	int nRop = pDC->SetROP2(R2_NOTXORPEN);
  
  	CRect rcWnd;
  	int d = 1;
  	GetWindowRect(rcWnd);
  	CPen  pen;
  	pen.CreatePen(0, 1, RGB(200, 200, 200));
  	CPen *pOP = pDC->SelectObject(&pen);
  	
  	if (m_nType == SPS_VERTICAL)
  	{
  		pDC->MoveTo(m_nX - d, rcWnd.top);
  		pDC->LineTo(m_nX - d, rcWnd.bottom);
  
  		pDC->MoveTo(m_nX + d, rcWnd.top);
  		pDC->LineTo(m_nX + d, rcWnd.bottom);
  	}
  	else // m_nType == SPS_HORIZONTAL
  	{
  		pDC->MoveTo(rcWnd.left, m_nY - d);
  		pDC->LineTo(rcWnd.right, m_nY - d);
  		
  		pDC->MoveTo(rcWnd.left, m_nY + d);
  		pDC->LineTo(rcWnd.right, m_nY + d);
  	}
  	pDC->SetROP2(nRop);
  	pDC->SelectObject(pOP);
  }
  
  void CSplitterControl::MoveWindowTo(CPoint pt)
  {
  	CRect rc;
  	GetWindowRect(rc);
  	CWnd* pParent;
  	pParent = GetParent();
  	if (!pParent || !::IsWindow(pParent->m_hWnd))
  		return;
  
  	pParent->ScreenToClient(rc);
  	if (m_nType == SPS_VERTICAL)
  	{	
  		int nMidX = (rc.left + rc.right) / 2;
  		int dx = pt.x - nMidX;
  		rc.OffsetRect(dx, 0);
  	}
  	else
  	{	
  		int nMidY = (rc.top + rc.bottom) / 2;
  		int dy = pt.y - nMidY;
  		rc.OffsetRect(0, dy);
  	}
  	MoveWindow(rc);
  }
  
  void CSplitterControl::ChangeWidth(CWnd *pWnd, int dx, DWORD dwFlag)
  {
  	CWnd* pParent = pWnd->GetParent();
  	if (pParent && ::IsWindow(pParent->m_hWnd))
  	{
  		CRect rcWnd;
  		pWnd->GetWindowRect(rcWnd);
  		pParent->ScreenToClient(rcWnd);
  		if (dwFlag == CW_LEFTALIGN)
  			rcWnd.right += dx;
  		else if (dwFlag == CW_RIGHTALIGN)
  			rcWnd.left -= dx;
  		pWnd->MoveWindow(rcWnd);
  	}
  }
  
  void CSplitterControl::ChangeHeight(CWnd *pWnd, int dy, DWORD dwFlag)
  {
  	CWnd* pParent = pWnd->GetParent();
  	if (pParent && ::IsWindow(pParent->m_hWnd))
  	{
  		CRect rcWnd;
  		pWnd->GetWindowRect(rcWnd);
  		pParent->ScreenToClient(rcWnd);
  		if (dwFlag == CW_TOPALIGN)
  			rcWnd.bottom += dy;
  		else if (dwFlag == CW_BOTTOMALIGN)
  			rcWnd.top -= dy;
  		pWnd->MoveWindow(rcWnd);
  	}
  }
  
  void CSplitterControl::ChangePos(CWnd* pWnd, int dx, int dy)
  {
  	CWnd* pParent = pWnd->GetParent();
  	if (pParent && ::IsWindow(pParent->m_hWnd))
  	{
  		CRect rcWnd;
  		pWnd->GetWindowRect(rcWnd);
  		pParent->ScreenToClient(rcWnd);
  		rcWnd.OffsetRect(-dx, dy);
  
  		pWnd->MoveWindow(rcWnd);
  	}	
  }
  
  void CSplitterControl::SetRange(int nMin, int nMax)
  {
  	m_nMin = nMin;
  	m_nMax = nMax;
  }
  
  // Set splitter range from (nRoot - nSubtraction) to (nRoot + nAddition)
  // If (nRoot < 0)
  //		nRoot =  <current position of the splitter>
  void CSplitterControl::SetRange(int nSubtraction, int nAddition, int nRoot)
  {
  	if (nRoot < 0)
  	{
  		CRect rcWnd;
  		GetWindowRect(rcWnd);
  		if (m_nType == SPS_VERTICAL)
  			nRoot = rcWnd.left + rcWnd.Width() / 2;
  		else // if m_nType == SPS_HORIZONTAL
  			nRoot = rcWnd.top + rcWnd.Height() / 2;
  	}
  	m_nMin = nRoot - nSubtraction;
  	m_nMax = nRoot + nAddition;
  }