www.pudn.com > NumericEdit_Demo.rar > NumericEdit.cpp


/* 
CNumericEdit - A clone of the spinedit control used in Jasc's Paint Shop Pro 
Contact : jg@jgsoftware.com 
Use the code for anything, just submit suggestions and bug fixes to above address. 
 
4/13/2004 - 1.0 Initial release 
 
4/20/2004 - 1.02 Bug fixes and some enhancements 
 
Fixed bug where the edit would only accept hex digits. Also now allow negative sign "-" to be entered  
Added NES_METER style to make the small bar under the edit field optional  
Control will now reconfigure itself when changing style bits  
Fixed max value bug. The full range is now accesible with the popup  
Added NES_LIVEUPDATE style. This style allows the control to notify it's parent during value tracking. Without this style, the parent is updated only at the end of tracking  
Demo has been updated to show the new features  
Added DDX_NumericEdit() function for DDX support  
Now using the active window caption color for the bar colors  
Changed hardcoded custom messages to use windows registered messages so as not to cause any conflict with other custom messages 
*/ 
 
#include "stdafx.h" 
#include "NumericEdit.h" 
 
void AFXAPI DDX_NumericEdit(CDataExchange* pDX, int nIDC, int& value) 
{ 
	pDX->PrepareCtrl(nIDC); 
  HWND hWndCtrl; 
  pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl); 
	if (pDX->m_bSaveAndValidate) 
		value = (int) ::SendMessage(hWndCtrl, NEM_GETPOS, 0, 0l); 
	else 
		::SendMessage(hWndCtrl, NEM_SETPOS, TRUE, value); 
} 
 
// CMyEdit 
 
IMPLEMENT_DYNAMIC(CMyEdit, CEdit) 
 
BEGIN_MESSAGE_MAP(CMyEdit, CEdit) 
  ON_WM_KEYDOWN() 
  ON_WM_CHAR() 
  ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange) 
  ON_WM_CTLCOLOR_REFLECT() 
END_MESSAGE_MAP() 
 
// CMyEdit message handlers 
 
//**************************************************************************** 
// CMyEdit::OnKeyDown - Intercepts pressed keys while focused and passes UP 
//                      and down to the parent.  
//**************************************************************************** 
 
void CMyEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{ 
  if (nChar == VK_UP || nChar == VK_DOWN) 
    GetParent()->SendMessage(WM_KEYDOWN,(WPARAM)nChar,MAKELPARAM(nRepCnt,nFlags)); 
  else 
    CEdit::OnKeyDown(nChar, nRepCnt, nFlags); 
} 
 
//**************************************************************************** 
// CMyEdit::OnChar - Only allows numbers and backspace 
//**************************************************************************** 
 
void CMyEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{ 
  if (!_istdigit(nChar) && (nChar != 8) & (nChar != _T('-'))) 
  { 
    MessageBeep(0); 
	  return; 
  } 
 
  CEdit::OnChar(nChar, nRepCnt, nFlags); 
} 
 
//**************************************************************************** 
// CMyEdit::OnEnChange - Converts current text contents to an int and passes 
//                       it to the parent using a private message. Then it 
//                       determines if it's out of range so that CtlColor() 
//                       knows what background color to return 
//**************************************************************************** 
 
void CMyEdit::OnEnChange() 
{ 
  CString str; 
  int     nMin, nMax; 
 
  GetWindowText(str); 
  int nValue = _tstoi(str); 
   
  GetParent()->SendMessage(NEM_GETRANGE,(WPARAM) &nMin,(LPARAM) &nMax); 
   
  BOOL fNewOverFlow = (nValue < nMin) || (nValue > nMax); 
  if (fNewOverFlow != m_fOverFlow) 
  { 
    m_fOverFlow = fNewOverFlow; 
    Invalidate(); 
  } 
 
  GetParent()->SendMessage(NEM_SETPOS,0,(LPARAM) nValue); 
} 
 
//**************************************************************************** 
// CMyEdit::CtlColor - Depending on the state of m_bOverflow, causes the edit 
//                     background to either show as default or the error color 
//**************************************************************************** 
 
HBRUSH CMyEdit::CtlColor(CDC* pDC, UINT /*nCtlColor*/) 
{ 
  pDC->SetBkMode(TRANSPARENT); 
   
  if (m_fOverFlow) 
    return m_brError; 
  else 
    return NULL; 
} 
 
//**************************************************************************** 
//**************************************************************************** 
//**************************************************************************** 
//**************************************************************************** 
 
// CMyButton 
 
static const UINT NEM_POPUPSTATECHANGE = ::RegisterWindowMessage(_T("NEM_POPUPSTATECHANGE-{B32E120B-ED89-420a-A757-19A978AFC2A9}")); 
static const UINT NEM_SHOWPOPUP = ::RegisterWindowMessage(_T("NEM_SHOWPOPUP-{84252E3C-DBD7-4fb6-A56A-160A0D00816A}")); 
 
#define PUSC_OPENING 0 
#define PUSC_CLOSING 1 
 
IMPLEMENT_DYNAMIC(CMyButton, CButton) 
 
BEGIN_MESSAGE_MAP(CMyButton, CButton) 
  ON_MESSAGE(BM_SETSTYLE,OnBnSetStyle) 
  ON_WM_LBUTTONDOWN() 
END_MESSAGE_MAP() 
 
// CMyButton message handlers 
 
//**************************************************************************** 
// CMyButton::OnBnSetStyle - Prevents the button from presenting itself with 
//                           a black border. A black border is normally used 
//                           to indicate the default button.  
//**************************************************************************** 
 
LRESULT CMyButton::OnBnSetStyle(WPARAM wParam,LPARAM lParam) 
{ 
  return DefWindowProc(BM_SETSTYLE, (wParam & ~BS_DEFPUSHBUTTON), lParam); 
} 
 
//**************************************************************************** 
// CMyButton::OnLButtonDown - Creates and displays a CTrackPopup window. The 
//                            message is NOT forwarded to the base class 
//                            because that would cause the button to capture 
//                            the mouse and we need to capture the mouse in 
//                            the popup window. SetState() is called to redraw 
//                            the button in the pressed state. 
//**************************************************************************** 
 
void CMyButton::OnLButtonDown(UINT nFlags, CPoint point) 
{ 
  CButton::OnLButtonDown(nFlags,point); 
  GetParent()->SendMessage(NEM_SHOWPOPUP); 
 
  SetState(TRUE); 
} 
 
//**************************************************************************** 
//**************************************************************************** 
//**************************************************************************** 
//**************************************************************************** 
 
// CMyTrackPopup 
 
#define THUMB_WIDTH 6 // Width of the track thumb 
 
IMPLEMENT_DYNAMIC(CMyTrackPopup, CWnd) 
 
BEGIN_MESSAGE_MAP(CMyTrackPopup, CWnd) 
  ON_WM_LBUTTONUP() 
  ON_WM_PAINT() 
  ON_WM_MOUSEMOVE() 
  ON_WM_SIZE() 
END_MESSAGE_MAP() 
 
//**************************************************************************** 
// CMyTrackPopup::Create - Creates the actual popup window while saving 
//                         nesassery values. Also calculates the x position of 
//                         the window so that the thumb will line up with the 
//                         mouse cursor. Finally call SetCapture() 
//**************************************************************************** 
 
BOOL CMyTrackPopup::Create(int x,int y,int nMin,int nMax,int nValue,CWnd* pParent) 
{ 
  CString sClassName; 
   
  m_nMin = nMin; 
  m_nMax = nMax; 
  m_nValue = nValue; 
  m_pNotify = pParent; 
 
  int nSBHeight = GetSystemMetrics(SM_CYHSCROLL); 
 
  sClassName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,::LoadCursor(NULL, IDC_SIZEWE),(HBRUSH)0); 
  if(!CreateEx(0,sClassName,0,WS_POPUP|WS_VISIBLE|WS_DLGFRAME,x,y,200,nSBHeight,pParent->GetSafeHwnd(),(HMENU) 0)) 
	{ 
		TRACE0("Failed to create CNumericEdit popup\n"); 
		return FALSE; 
	} 
 
  // Calculate x position 
  int nDlgBorderWidth = GetSystemMetrics(SM_CXDLGFRAME); 
  nValue-= nMin; 
  x-= (int)((m_dPixelValue * nValue) + 0.5); 
  x-= nDlgBorderWidth; 
  SetWindowPos(0,x,y,0,0,SWP_NOSIZE | SWP_NOZORDER); 
 
  m_pNotify->SendMessage(NEM_POPUPSTATECHANGE,PUSC_OPENING); 
 
  SetCapture(); 
   
  return TRUE; 
} 
 
// CMyButton message handlers 
 
//**************************************************************************** 
// CMyTrackPopup::OnPaint - Calculates and paints the bar and thumb 
//**************************************************************************** 
 
void CMyTrackPopup::OnPaint() 
{ 
  CPaintDC dc(this); // device context for painting 
 
  CRect rcRect; 
  GetClientRect(&rcRect); 
   
  int nXPos = (int)((m_dPixelValue * (double)(m_nValue - m_nMin))); 
   
  // Draw bar 
  dc.FillSolidRect(rcRect.left,rcRect.top,nXPos,rcRect.Height(),GetSysColor(COLOR_ACTIVECAPTION)); 
  dc.FillSolidRect(rcRect.left + nXPos + 1,rcRect.top,rcRect.Width() - nXPos,rcRect.Height(),GetSysColor(COLOR_BTNFACE)); 
   
  // Draw thumb 
  rcRect.left+= nXPos; 
  rcRect.right = rcRect.left + THUMB_WIDTH; 
  dc.FillSolidRect(&rcRect,GetSysColor(COLOR_BTNFACE)); 
  dc.DrawEdge(&rcRect,EDGE_RAISED,BF_RECT); 
} 
 
//**************************************************************************** 
// CMyTrackPopup::OnSize - Calculates the m_dPixelvalue private var. 
//**************************************************************************** 
 
void CMyTrackPopup::OnSize(UINT nType, int cx, int cy) 
{ 
  CWnd::OnSize(nType, cx, cy); 
 
  m_dPixelValue = (double)(cx - THUMB_WIDTH) / (double)(m_nMax - m_nMin); 
} 
 
//**************************************************************************** 
// CMyTrackPopup::OnLButtonUp - Releases the mouse and sends a closing message 
//                              to the pNotify window. Finally destroyes 
//                              itself and releases it's memory. 
//**************************************************************************** 
 
void CMyTrackPopup::OnLButtonUp(UINT nFlags, CPoint point) 
{ 
  ReleaseCapture(); 
   
  CWnd::OnLButtonUp(nFlags, point); 
  m_pNotify->SendMessage(NEM_POPUPSTATECHANGE,PUSC_CLOSING); 
   
  DestroyWindow(); 
  delete this; 
} 
 
//**************************************************************************** 
// CMyTrackPopup::OnMouseMove - Calculates new value and sends it to the 
//                              pNotify window. Also invalidates the bar area 
//                              causing a repaint. 
//**************************************************************************** 
 
void CMyTrackPopup::OnMouseMove(UINT nFlags, CPoint point) 
{ 
  CRect rcRect; 
  GetClientRect(&rcRect); 
   
  int nPos = point.x; 
  if (nPos < 0) nPos = 0; 
  if (nPos > rcRect.right - THUMB_WIDTH) nPos = rcRect.right - THUMB_WIDTH; 
  m_nValue = ((int)(((double)nPos) / m_dPixelValue)) + m_nMin; 
  InvalidateRect(&rcRect); 
  m_pNotify->SendMessage(NEM_SETPOS,0,(LPARAM)m_nValue); 
 
  CWnd::OnMouseMove(nFlags, point); 
} 
 
//**************************************************************************** 
//**************************************************************************** 
//**************************************************************************** 
//**************************************************************************** 
 
// CNumericEdit 
 
#define BARHEIGHT 3 // Height of the bar 
 
IMPLEMENT_DYNAMIC(CNumericEdit, CWnd) 
 
CNumericEdit::CNumericEdit() 
{ 
  m_nMin = 0; 
  m_nMax = 100; 
  m_nValue = 0; 
  m_fCaptured = FALSE; 
  m_fTracking = FALSE; 
} 
 
//**************************************************************************** 
// CNumericEdit::GetValue -  
//**************************************************************************** 
 
int CNumericEdit::GetValue() 
{ 
  return m_nValue; 
} 
 
//**************************************************************************** 
// CNumericEdit::SetValue -  
//**************************************************************************** 
 
void CNumericEdit::SetValue(int nValue) 
{ 
  static BOOL fInFunction = FALSE; 
   
  if (fInFunction) return; 
   
  if (nValue != m_nValue) 
  { 
    fInFunction = TRUE; 
     
    // 
    CString str; 
    str.Format(_T("%d"),nValue); 
     
    if (nValue < m_nMin) nValue = m_nMin; 
    if (nValue > m_nMax) nValue = m_nMax; 
    m_nValue = nValue; 
    m_wndEdit.SetWindowText(str); 
    int nLength = str.GetLength(); 
    m_wndEdit.SetSel(nLength,nLength); 
    m_wndSpinButton.SetPos(m_nValue); 
    InvalidateRect(&m_rcBar,FALSE); 
 
    if (!m_fTracking || (GetStyle() & NES_LIVEUPDATE)) 
      GetParent()->SendMessage(NEN_CHANGED,0,m_nValue); 
 
    fInFunction = FALSE; 
  } 
} 
 
//**************************************************************************** 
// CNumericEdit::GetReadOnly -  
//**************************************************************************** 
 
BOOL CNumericEdit::GetReadOnly() 
{ 
  return (m_wndEdit.GetStyle() & ES_READONLY) > 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::SetReadOnly -  
//**************************************************************************** 
 
void CNumericEdit::SetReadOnly(BOOL fReadOnly) 
{ 
  m_wndEdit.SetReadOnly(fReadOnly); 
} 
 
//**************************************************************************** 
// CNumericEdit::GetRange 
//**************************************************************************** 
 
void CNumericEdit::GetRange(int& nMin,int& nMax) 
{ 
  nMin = m_nMin; 
  nMax = m_nMax;   
} 
 
//**************************************************************************** 
// CNumericEdit::SetRange - 
//**************************************************************************** 
 
void CNumericEdit::SetRange(int nMin,int nMax) 
{ 
  if (nMin != m_nMin || nMax != m_nMax) 
  { 
    m_nMin = nMin; 
    m_nMax = nMax; 
    m_wndSpinButton.SetRange32(m_nMin,m_nMax); 
    if (m_nValue < m_nMin) m_nValue = m_nMin; 
    if (m_nValue < m_nMin) m_nValue = m_nMin; 
    CString str; 
    str.Format(_T("%d"),m_nValue); 
    m_wndEdit.SetWindowText(str); 
    int nLength = str.GetLength(); 
    m_wndEdit.SetSel(nLength,nLength); 
 
    m_dPixelValue = (double)m_rcBar.Width() / (double)(m_nMax - m_nMin); 
    InvalidateRect(&m_rcBar); 
  } 
} 
 
//**************************************************************************** 
// CNumericEdit::ResizeChildren -  
//**************************************************************************** 
 
void CNumericEdit::ResizeChildren(int cx,int cy) 
{ 
  int nWidth = GetSystemMetrics(SM_CXHSCROLL); 
  int nCurx = cx; 
   
  if (GetStyle() & NES_POPUP) 
  { 
    nCurx-= nWidth; 
    m_wndButton.MoveWindow(nCurx,0,nWidth,cy); 
  } 
  else 
    m_wndButton.MoveWindow(0,0,0,0); 
 
  if (GetStyle() & NES_SPIN) 
  { 
    nCurx-= nWidth; 
    m_wndSpinButton.MoveWindow(nCurx,0,nWidth,cy); 
  } 
  else 
    m_wndSpinButton.MoveWindow(0,0,0,0); 
 
  int nEditHeight; 
  if (GetStyle() & NES_METER)  
    nEditHeight= cy - BARHEIGHT - 1; 
  else 
    nEditHeight = cy; 
   
  m_wndEdit.MoveWindow(0,0,nCurx,nEditHeight); 
   
  m_rcBar.left = 0; 
  m_rcBar.top = cy - BARHEIGHT; 
  m_rcBar.right = nCurx; 
  m_rcBar.bottom = cy; 
 
  m_dPixelValue = (double)(nCurx) / (double)(m_nMax - m_nMin); 
} 
 
BEGIN_MESSAGE_MAP(CNumericEdit, CWnd) 
  ON_WM_PAINT() 
  ON_WM_SIZE() 
  ON_WM_CREATE() 
  ON_WM_LBUTTONDOWN() 
  ON_WM_MOUSEMOVE() 
  ON_WM_LBUTTONUP() 
  ON_WM_VSCROLL() 
  ON_WM_SETFOCUS() 
  ON_WM_KEYDOWN() 
  ON_WM_STYLECHANGED() 
  ON_REGISTERED_MESSAGE(NEM_GETPOS,OnGetPos) 
  ON_REGISTERED_MESSAGE(NEM_SETPOS,OnSetPos) 
  ON_REGISTERED_MESSAGE(NEM_GETRANGE,OnGetRange) 
  ON_REGISTERED_MESSAGE(NEM_SETRANGE,OnSetRange) 
  ON_REGISTERED_MESSAGE(NEM_GETREADONLY,OnGetReadOnly) 
  ON_REGISTERED_MESSAGE(NEM_SETREADONLY,OnSetReadOnly) 
  ON_REGISTERED_MESSAGE(NEM_SHOWPOPUP,OnShowPopup) 
  ON_REGISTERED_MESSAGE(NEM_POPUPSTATECHANGE,OnPopupStateChange) 
END_MESSAGE_MAP() 
 
// CNumericEdit message handlers 
 
//**************************************************************************** 
// CNumericEdit::Create - Creates actual window 
//**************************************************************************** 
 
BOOL CNumericEdit::Create(DWORD dwStyle,const CRect& rcRect,CWnd* pParent,UINT /*nID*/) 
{ 
	CString sClassName; 
   
  sClassName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,::LoadCursor(NULL, IDC_ARROW),(HBRUSH)0); 
  if(!CreateEx(WS_EX_CLIENTEDGE,sClassName,0,WS_CHILD | dwStyle, 
               rcRect.left,rcRect.top,rcRect.Width(),rcRect.Height(),pParent->GetSafeHwnd(),(HMENU) 0)) 
	{ 
		TRACE0("Failed to create CNumericEdit\n"); 
		return FALSE; 
	} 
   
  return TRUE; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnPaint - Draws bar and black line above it 
//**************************************************************************** 
 
void CNumericEdit::OnPaint() 
{ 
  CPaintDC dc(this); // device context for painting 
   
  CRect rcRect; 
  GetClientRect(&rcRect); 
   
  if (GetStyle() & NES_METER) 
  { 
    // Draw black line 
    dc.MoveTo(m_rcBar.left,m_rcBar.top - 1); 
    dc.LineTo(m_rcBar.right + 1,m_rcBar.top - 1); 
 
    int nXPos = (int) (m_dPixelValue * ((double)(m_nValue - m_nMin))); 
    dc.FillSolidRect(m_rcBar.left,m_rcBar.top,nXPos,m_rcBar.Height(),GetSysColor(COLOR_ACTIVECAPTION)); 
    dc.FillSolidRect(m_rcBar.left + nXPos + 1,m_rcBar.top,m_rcBar.Width() - nXPos,m_rcBar.Height(),GetSysColor(COLOR_BTNFACE)); 
  } 
} 
 
//**************************************************************************** 
// CNumericEdit::OnSize - Moves and sizes contained controls. Calculates bar 
//                        position and size. Calculates m_dPixelValue. 
//**************************************************************************** 
 
void CNumericEdit::OnSize(UINT nType, int cx, int cy) 
{ 
  CWnd::OnSize(nType, cx, cy); 
 
  ResizeChildren(cx,cy); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnCreate - Creates contained controls. 
//**************************************************************************** 
 
int CNumericEdit::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
  if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; 
 
  CRect r(0,0,0,0); 
  m_wndButton.Create(_T("v"),WS_CHILD|WS_VISIBLE,r,this,1); 
  m_wndEdit.Create(WS_CHILD|WS_VISIBLE,r,this,2); 
  m_wndEdit.SetWindowText(_T("0")); 
  m_wndSpinButton.Create(WS_CHILD|WS_VISIBLE|UDS_ARROWKEYS,r,this,3); 
  m_wndSpinButton.SetRange32(m_nMin,m_nMax); 
 
  return 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnLButtonDown - Sets new value calculated from clicked  
//                               position then captures mouse. 
//**************************************************************************** 
 
void CNumericEdit::OnLButtonDown(UINT nFlags, CPoint point) 
{ 
  if ((m_rcBar.PtInRect(point)) && (GetStyle() & NES_METER)) 
  { 
    int nNewValue = (int)((point.x) / m_dPixelValue); 
    SetValue(nNewValue + m_nMin); 
    SetCapture(); 
    m_fCaptured = TRUE; 
    m_fTracking = TRUE; 
  } 
 
  CWnd::OnLButtonDown(nFlags, point); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnMouseMove - Calculates new value. 
//**************************************************************************** 
 
void CNumericEdit::OnMouseMove(UINT nFlags, CPoint point) 
{ 
  if (m_fCaptured) 
  { 
    int nPos = point.x; 
    if (nPos < 0) nPos = 0; 
    if (nPos > m_rcBar.Width()) nPos = m_rcBar.Width(); 
    int nNewValue = (int)(nPos / m_dPixelValue); 
    SetValue(nNewValue + m_nMin); 
  } 
 
  CWnd::OnMouseMove(nFlags, point); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnLButtonUp - Releases mouse capture 
//**************************************************************************** 
 
void CNumericEdit::OnLButtonUp(UINT nFlags, CPoint point) 
{ 
  if (m_fCaptured) 
  { 
    ReleaseCapture(); 
    m_fCaptured = FALSE; 
    m_fTracking = FALSE; 
    GetParent()->SendMessage(NEN_CHANGED,0,m_nValue); 
  } 
 
  CWnd::OnLButtonUp(nFlags, point); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnVScroll - Handles WM_VSCROLL messages from contained 
//                           CSpinEditCtrl and sets as new value. 
//**************************************************************************** 
 
void CNumericEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{ 
  SetValue(nPos); 
 
  CWnd::OnVScroll(nSBCode, nPos, pScrollBar); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnSetFocus - Passes focus on the contained CEdit 
//**************************************************************************** 
 
void CNumericEdit::OnSetFocus(CWnd* pOldWnd) 
{ 
  CWnd::OnSetFocus(pOldWnd); 
 
  m_wndEdit.SetFocus(); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnKeyDown - Handles the UP and DOWN messages passed from 
//                           contained CEdit and adjusts value accordingly. 
//**************************************************************************** 
 
void CNumericEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{ 
  if (nChar == VK_UP && m_nValue < m_nMax) 
    SetValue(m_nValue + 1); 
  else 
    if (nChar == VK_DOWN && m_nValue > m_nMin) 
      SetValue(m_nValue - 1); 
  else 
    CWnd::OnKeyDown(nChar, nRepCnt, nFlags); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnStyleChanged - 
//**************************************************************************** 
 
void CNumericEdit::OnStyleChanged(int nWhich, LPSTYLESTRUCT lpStyleStruct) 
{ 
  if (nWhich == GWL_STYLE) 
  { 
    CRect rcRect; 
    GetClientRect(&rcRect); 
    ResizeChildren(rcRect.Width(),rcRect.Height()); 
    InvalidateRect(&m_rcBar); 
  } 
} 
 
//**************************************************************************** 
// CNumericEdit::OnGetPos - Handles NEM_GETPOS 
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnGetPos(WPARAM,LPARAM) 
{ 
  return m_nValue; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnSetPos - Handles NEM_SETPOS 
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnSetPos(WPARAM /*wParam*/,LPARAM nNewValue) 
{ 
  SetValue((int)nNewValue); 
   
  return 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnGetRange - Handles NEM_GETRANGE 
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnGetRange(WPARAM wParam,LPARAM lParam) 
{ 
  if (wParam) *((int*)wParam) = m_nMin; 
  if (lParam) *((int*)lParam) = m_nMax; 
   
  return 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnSetRange - Handles NEM_SETRANGE 
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnSetRange(WPARAM wParam,LPARAM lParam) 
{ 
  SetRange((int) wParam,(int) lParam); 
   
  return 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnGetReadOnly - Handles NEM_GETREADONLY 
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnGetReadOnly(WPARAM,LPARAM) 
{ 
  return (LRESULT) GetReadOnly(); 
} 
 
//**************************************************************************** 
// CNumericEdit::OnSetReadOnly - Handles NEM_SETREADONLY 
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnSetReadOnly(WPARAM wParam,LPARAM /*lParam*/) 
{ 
  SetReadOnly((BOOL)wParam); 
   
  return 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnShowPopup -  
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnShowPopup(WPARAM /*wParam*/,LPARAM /*lParam*/) 
{ 
  POINT point; 
  ::GetCursorPos(&point); 
  CMyTrackPopup* pTrackPopup = new CMyTrackPopup(); 
   
  CRect rcRect; 
  m_wndButton.GetWindowRect(rcRect); // Get button location to determine popup location 
  pTrackPopup->Create(point.x,rcRect.bottom + 4,m_nMin,m_nMax,m_nValue,this); 
 
  return 0; 
} 
 
//**************************************************************************** 
// CNumericEdit::OnPopupStateChange -  
//**************************************************************************** 
 
afx_msg LRESULT CNumericEdit::OnPopupStateChange(WPARAM wParam,LPARAM /*lParam*/) 
{ 
  m_fTracking = wParam == PUSC_OPENING; 
  if (!m_fTracking) 
  { 
    m_wndButton.SetState(FALSE); 
    GetParent()->SendMessage(NEN_CHANGED,0,m_nValue); 
    m_wndEdit.SetFocus(); 
  } 
 
  return 0; 
}