00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "stdafx.h"
00020
00021 #include <cfl/ControlNumSpinCtrl.h>
00022
00023 #pragma warning( push, 3 ) // header file limits requires warning level 3
00024
00025 #include <cmath>
00026 #include <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
00042
00043
00044 CNumSpinCtrl::~CNumSpinCtrl()
00045 {
00046 ;
00047 }
00048
00049
00050
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 ;
00061 }
00062
00063
00064
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
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
00085
00086 if ( Q_INVALID( m_MaxVal < m_MinVal && "m_MaxVal < m_MinVal" ) )
00087 {
00088 return;
00089 }
00090
00091
00092
00093 if ( m_Delta == 0.0 )
00094 {
00095 return;
00096 }
00097
00098
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
00114
00115 SetIntPos( GetPos() );
00116 }
00117
00118
00119
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
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
00163
00164
00165 void CNumSpinCtrl::SetFormat( LPCTSTR lpszFormatString )
00166 {
00167 if ( lpszFormatString == NULL )
00168 {
00169 m_csFormat.Empty ();
00170 }
00171 else
00172 {
00173 m_csFormat = lpszFormatString;
00174 }
00175 }
00176
00177
00178
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
00196
00197
00198 void CNumSpinCtrl::PreSubclassWindow()
00199 {
00200 CSpinButtonCtrl::PreSubclassWindow();
00201 InitSpinCtrl();
00202 }
00203
00204
00205
00206
00207
00208 void CNumSpinCtrl::InitSpinCtrl()
00209 {
00210
00211
00212
00213
00214 if ( Q_INVALID( 0 != ( GetStyle () & UDS_SETBUDDYINT ) && "require Set-Buddy-Integer unset" ) )
00215 {
00216 return;
00217 }
00218
00219
00220
00221 SetRangeAndDelta( m_MinVal, m_MaxVal, m_Delta );
00222 }
00223
00224
00225
00226
00227
00228 void CNumSpinCtrl::SetIntPos( real_type pos )
00229 {
00230
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
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
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
00287
00288
00289 BEGIN_MESSAGE_MAP(CNumSpinCtrl, CSpinButtonCtrl)
00290
00291 ON_WM_CREATE()
00292 ON_NOTIFY_REFLECT_EX(UDN_DELTAPOS, OnDeltapos)
00293
00294 END_MESSAGE_MAP()
00295
00296
00297
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
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
00326
00327
00328 if ( pUD->iDelta < 0 )
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
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
00374
00375 *pResult = 0;
00376
00377 return FALSE;
00378 }
00379
00380
00381
00382
00383