Filter Library Camera Interface Physics

ControlNumSpinCtrl.cpp

00001 /*
00002  * ControlNumSpinCtrl.cpp - a spin control for real numbers.
00003  *
00004  * This file is part of the Camera Filter Library.
00005  * Computer Aided Measurement Environment for Realtime Atomic imaging (Camera)
00006  *
00007  * Copyright (C) 2004-2005, Leiden Probe Microscopy.
00008  * Copyright (C) 2004-2005, Universiteit Leiden.
00009  *
00010  * This spin control is based on:
00011  * CNumSpinCtrl - a simple numeric spin control, By Damir Valiulin
00012  * See http://www.codeproject.com/miscctrl/numspinctrl.asp
00013  *
00014  * Authors: Martin J. Moene (original)
00015  *
00016  * $Id: ControlNumSpinCtrl.cpp 150 2005-04-25 09:02:30Z moene $
00017  */
00018 
00019 #include "stdafx.h"                     // for common (pre-compiled) headers
00020 //#include <cfl/stdafx.h>                 // for common (pre-compiled) headers
00021 #include <cfl/ControlNumSpinCtrl.h>     // header
00022 
00023 #pragma warning( push, 3 )              // header file limits requires warning level 3
00024 
00025 #include <cmath>                        // for fabs() etc.
00026 #include <limits>                       // for numeric_limits<>
00027 
00028 #pragma warning( pop )
00029 
00030 #ifdef _DEBUG
00031 #define new DEBUG_NEW
00032 #undef THIS_FILE
00033 static char THIS_FILE[] = __FILE__;
00034 #endif
00035 
00036 #define EPSILON std::numeric_limits<double>::epsilon()
00037 
00038 IMPLEMENT_DYNAMIC( CNumSpinCtrl, CSpinButtonCtrl )
00039 
00040 /**
00041  * destructor.
00042  */
00043 
00044 CNumSpinCtrl::~CNumSpinCtrl()
00045 {
00046    ; // do nothing
00047 }
00048 
00049 /**
00050  * default constructor.
00051  */
00052 
00053 CNumSpinCtrl::CNumSpinCtrl() :
00054    m_Delta ( 1 ),
00055    m_MinVal( 0 ),
00056    m_MaxVal( 100 ),
00057    m_IntRange( 100 ),
00058    m_csFormat( _T( "%g" ) )
00059 {
00060    ; // do nothing
00061 }
00062 
00063 /**
00064  * obtain the lower and higher limits and the delta value.
00065  */
00066 
00067 void CNumSpinCtrl::GetRangeAndDelta( real_type& lower, real_type& upper, real_type& delta )
00068 {
00069    lower = m_MinVal;
00070    upper = m_MaxVal;
00071    delta = m_Delta;
00072 }
00073 
00074 /**
00075  * set the lower and higher limits and the delta value.
00076  */
00077 
00078 void CNumSpinCtrl::SetRangeAndDelta( real_type lower, real_type upper, real_type delta )
00079 {
00080    m_MinVal = lower;
00081    m_MaxVal = upper;
00082    m_Delta  = delta;
00083 
00084    // reversed min/max is not implemented, although it's probably easy:
00085 
00086    if ( Q_INVALID( m_MaxVal < m_MinVal && "m_MaxVal < m_MinVal" ) )
00087    {
00088       return;
00089    }
00090 
00091    // avoid division by zero:
00092 
00093    if ( m_Delta == 0.0 )
00094    {
00095       return;
00096    }
00097 
00098    // Figure out the integer range to use, so that acceleration can work properly:
00099 
00100    double range = fabs( ( m_MaxVal - m_MinVal ) / m_Delta );
00101 
00102    if ( range > static_cast<double>( UD_MAXVAL ) )
00103    {
00104       m_IntRange = UD_MAXVAL;
00105    }
00106    else
00107    {
00108       m_IntRange = static_cast<int>( range );
00109    }
00110 
00111    CSpinButtonCtrl::SetRange32( 0, m_IntRange );
00112 
00113    // Set integer position:
00114 
00115    SetIntPos( GetPos() );
00116 }
00117 
00118 /**
00119  * set the new position.
00120  */
00121 
00122 void CNumSpinCtrl::SetPos( double val )
00123 {
00124    if ( val < m_MinVal || val > m_MaxVal )
00125    {
00126       return;
00127    }
00128 
00129    SetValueForBuddy( val );
00130    SetIntPos       ( val );
00131 }
00132 
00133 /**
00134  * the current position.
00135  */
00136 
00137 double CNumSpinCtrl::GetPos()
00138 {
00139    CWnd* pEdit = GetBuddy();
00140 
00141    if ( Q_INVALID( NULL == pEdit && "GetPos: Auto buddy is unset" ) )
00142    {
00143       return 0.0;
00144    }
00145 
00146    double val = ::strtod( c_str_ptr( *pEdit ), NULL );
00147 
00148    if ( val < m_MinVal )
00149    {
00150       return m_MinVal;
00151    }
00152    else if ( val > m_MaxVal )
00153    {
00154       return m_MaxVal;
00155 
00156    }
00157 
00158    return val;
00159 }
00160 
00161 /**
00162  * set the printf-like format string (NULL yields "%g").
00163  */
00164 
00165 void CNumSpinCtrl::SetFormat( LPCTSTR lpszFormatString /* = NULL */ )
00166 {
00167    if ( lpszFormatString == NULL )
00168    {
00169       m_csFormat.Empty ();
00170    }
00171    else
00172    {
00173       m_csFormat = lpszFormatString;
00174    }
00175 }
00176 
00177 /**
00178  *  focus this control and select its contents.
00179  */
00180 
00181 void CNumSpinCtrl::Select()
00182 {
00183    CEdit* pEdit = static_cast<CEdit*>( GetBuddy() );
00184 
00185    if ( Q_INVALID( NULL == pEdit && "Select: Auto buddy is unset" ) )
00186    {
00187       return;
00188    }
00189 
00190    pEdit->SetFocus();
00191    pEdit->SetSel( 0, -1 );
00192 }
00193 
00194 /**
00195  * allow other necessary subclassing to occur before the window is subclassed.
00196  */
00197 
00198 void CNumSpinCtrl::PreSubclassWindow()
00199 {
00200    CSpinButtonCtrl::PreSubclassWindow();
00201    InitSpinCtrl();
00202 }
00203 
00204 /**
00205  * check that Set-Buddy-Integer is unset and set the control's range via SetRangeAndDelta().
00206  */
00207 
00208 void CNumSpinCtrl::InitSpinCtrl()
00209 {
00210    // require Set-Buddy-Integer unset, otherwise control won't work properly!
00211 
00212    // ModifyStyle (UDS_SETBUDDYINT, UDS_ARROWKEYS); // doesn't work
00213 
00214    if ( Q_INVALID( 0 != ( GetStyle () & UDS_SETBUDDYINT ) && "require Set-Buddy-Integer unset" ) )
00215    {
00216       return;
00217    }
00218 
00219    // set default values:
00220 
00221    SetRangeAndDelta( m_MinVal, m_MaxVal, m_Delta );
00222 }
00223 
00224 /**
00225  * set the underlying SpinButtonCtrl's position.
00226  */
00227 
00228 void CNumSpinCtrl::SetIntPos( real_type pos )
00229 {
00230    // avoid division by zero:
00231 
00232    if ( m_MaxVal == m_MinVal )
00233    {
00234       return;
00235    }
00236 
00237    int int_pos;
00238 
00239    if ( pos < m_MinVal )
00240    {
00241       int_pos = 0;
00242    }
00243    else if ( pos > m_MaxVal )
00244    {
00245       int_pos = m_IntRange;
00246    }
00247    else
00248    {
00249       // where in the range is current position?
00250 
00251       double pos_in_range = ( pos - m_MinVal ) / ( m_MaxVal - m_MinVal );
00252 
00253       int_pos = static_cast<int>( m_IntRange * pos_in_range + 0.5 );
00254    }
00255 
00256    CSpinButtonCtrl::SetPos( int_pos );
00257 }
00258 
00259 /**
00260  * set the contents of the buddy edit control.
00261  */
00262 
00263 void CNumSpinCtrl::SetValueForBuddy( real_type val )
00264 {
00265    CWnd* pEdit = GetBuddy();
00266 
00267    if ( Q_INVALID( NULL == pEdit && "SetValueForBuddy: Auto buddy is unset" ) )
00268    {
00269       return;
00270    }
00271 
00272    CString str;
00273    if ( m_csFormat.IsEmpty() )
00274    {
00275       str.Format( _T( "%g" ), val );
00276    }
00277    else
00278    {
00279       str.Format( m_csFormat, val );
00280    }
00281 
00282    pEdit->SetWindowText( str );
00283 }
00284 
00285 /*
00286  * the message map
00287  */
00288 
00289 BEGIN_MESSAGE_MAP(CNumSpinCtrl, CSpinButtonCtrl)
00290    //{{AFX_MSG_MAP(CNumSpinCtrl)
00291    ON_WM_CREATE()
00292    ON_NOTIFY_REFLECT_EX(UDN_DELTAPOS, OnDeltapos)
00293    //}}AFX_MSG_MAP
00294 END_MESSAGE_MAP()
00295 
00296 /**
00297  * handle create message, calls InitSpinCtrl().
00298  */
00299 
00300 int CNumSpinCtrl::OnCreate( LPCREATESTRUCT lpCreateStruct )
00301 {
00302    if ( -1 == CSpinButtonCtrl::OnCreate(lpCreateStruct) )
00303    {
00304       return -1;
00305    }
00306 
00307    InitSpinCtrl();
00308 
00309    return 0;
00310 }
00311 
00312 /**
00313  * handle position-change message, set buddy contents via SetValueForBuddy().
00314  */
00315 
00316 BOOL CNumSpinCtrl::OnDeltapos( NMHDR* pNMHDR, LRESULT* pResult )
00317 {
00318    NM_UPDOWN* pUD = (NM_UPDOWN*)pNMHDR;
00319 
00320    double val = GetPos() + m_Delta * pUD->iDelta;
00321 
00322    const bool can_wrap = ( UDS_WRAP & GetStyle() );
00323 
00324    /*
00325     * spin up or down:
00326     */
00327 
00328    if ( pUD->iDelta < 0 )               // spin down
00329    {
00330       double abs_eps = fabs( EPSILON * max( val, m_MinVal ) );
00331 
00332       if ( abs_eps < EPSILON )
00333       {
00334          abs_eps = EPSILON;
00335       }
00336 
00337       if ( m_MinVal - val > abs_eps )
00338       {
00339          if ( can_wrap )
00340          {
00341             val = m_MaxVal;
00342          }
00343          else
00344          {
00345             val = m_MinVal;
00346          }
00347       }
00348    }
00349    else                                 // spin up
00350    {
00351       double abs_eps = fabs( EPSILON * max( val, m_MaxVal ) );
00352 
00353       if ( abs_eps < EPSILON )
00354       {
00355          abs_eps = EPSILON;
00356       }
00357 
00358       if ( val - m_MaxVal > abs_eps )
00359       {
00360          if ( can_wrap )
00361          {
00362             val = m_MinVal;
00363          }
00364          else
00365          {
00366             val = m_MaxVal;
00367          }
00368       }
00369    }
00370 
00371    SetValueForBuddy( val );
00372 
00373    // pass back Ok and let parent process this notification too:
00374 
00375    *pResult = 0;
00376 
00377    return FALSE;
00378 }
00379 
00380 /*
00381  * end of file
00382  */
00383 

Camera Filter Library documentation © 2004-2007 by Leiden Probe Microscopy