>************************************************** >*-- Class: spntime >*-- ParentClass: spinner >*-- Time Spinner Class - can be configured to show seconds by setting the lShowSeconds property to true >* >Define Class spntime As spinner > > Height = 22 > Increment = 0.00 > SpinnerHighValue = 120000.00 > SpinnerLowValue = 1.00 > Width = 64 > Format = "RL" > nselstart = 0 > *-- Used to keep the current segment from losing focus if the user types in an invalid value for hours, minutes, or second > lsegmentisvalid = .T. > *-- to configure the control for use as a 24 hour or 12 hour clock > l24hour = .T. > Name = "spntime" > > *-- True if we are using seconds in the spinner > lshowseconds = .F. > > Procedure incrementhours > Lparameters tlDecrement > Local lnHours, lnRest, lnMin > With This > *********************************************************************** > *** Changed By.: Marcia G. Akins on 17 February 2007 > *** Reason.....: Make this configurable to use either a 12 or 24 hour clock > *********************************************************************** > lnMax = Val( Left( Transform( .SpinnerHighValue ), 2 ) ) > lnMin = Iif( .l24hour, 0, 1 ) > lnRest = .Value % Iif( .lshowseconds, 10000, 100 ) > If .lshowseconds > lnHours = Val( Left ( Padl ( Int( .Value ), 6, '0' ) , 2 ) ) > Else > lnHours = Val( Left ( Padl ( Int( .Value ), 4, '0' ) , 2 ) ) > Endif > If tlDecrement > lnHours = Iif( lnHours <= lnMin, lnMax, lnHours - 1 ) > Else > lnHours = Iif( lnHours >= lnMax, lnMin, lnHours + 1 ) > Endif > .Value = lnHours * Iif( .lshowseconds, 10000, 100 ) + lnRest > Endwith > Endproc > > Procedure incrementminutes > Lparameters tlDecrement > Local lcTime, lnMinutes, lcHours, lcSeconds > > With This > If .lshowseconds > lcTime = Padl ( Int( .Value ), 6, '0' ) > lnMinutes = Int ( Int( .Value ) % 10000 / 100 ) > lcSeconds = Right( Padl ( Int( .Value ), 6, '0' ), 2 ) > Else > lcTime = Padl ( Int( .Value ), 4, '0' ) > lnMinutes = Int( .Value ) % 100 > Endif > If tlDecrement > lnMinutes = Iif( lnMinutes = 00 Or lnMinutes > 59, 59, lnMinutes - 1 ) > Else > lnMinutes = Iif( lnMinutes > 58, 00, lnMinutes + 1 ) > Endif > .Value = Val( Left( lcTime, 2 ) + Padl( lnMinutes, 2, '0' ) ; > + Iif( .lshowseconds, Right( lcTime, 2 ), '' ) ) > Endwith > Endproc > > Procedure Setup > With This > *** Format the input mask depending on whether or not we are showing seconds > If .lshowseconds > .InputMask = "99:99:99" > .SpinnerHighValue = Iif( .l24hour, 235959, 120000 ) > .SpinnerLowValue = Iif( .l24hour, 0, 10000 ) > Else > .InputMask = "99:99" > .SpinnerHighValue = Iif( .l24hour, 2359, 1200 ) > .SpinnerLowValue = Iif( .l24hour, 0, 100 ) > Endif > Endwith > Endproc > > Procedure sethighlight > *** Hightlight either the hours, minutes, or seconds portion > With This > Do Case > Case Between( .SelStart, 0, 2 ) > .SelStart = 0 > Case Between( .SelStart, 3, 5 ) > .SelStart = 3 > Otherwise > .SelStart = Iif( .lshowseconds, 6, 0 ) > Endcase > .SelLength = 2 > .nselstart = .SelStart > Endwith > Endproc > > Procedure movehighlight > Lparameters nKeyCode > *** nKeyCode = 19 means we have pressed left arrow > *** otherwise, a right arrow was pressed > With This > Do Case > Case Between( .SelStart, 0, 2 ) > If .lshowseconds > .SelStart = Iif( nKeyCode = 19, 6, 3 ) > Else > .SelStart = 3 > Endif > Case Between( .SelStart, 3, 5 ) > If .lshowseconds > .SelStart = Iif( nKeyCode = 19, 0, 6 ) > Else > .SelStart = 0 > Endif > Otherwise > .SelStart = Iif( nKeyCode = 19, 3, 0 ) > Endcase > .SelLength = 2 > .nselstart = .SelStart > Endwith > Endproc > > Procedure changetime > Lparameters tlDecrement > *** when tlDecrement is true, we are decrementing the time, otherwise we are > *** incrementing. First, we must select which segment is being adjusted by > *** examining the previously saved value of nselstart > With This > Do Case > Case Between( .nselstart, 0, 2 ) > .incrementhours( tlDecrement ) > > Case Between( .nselstart, 3, 5 ) > .incrementminutes( tlDecrement ) > > Otherwise > If tlDecrement > .Value = Iif( Int( .Value % 100 ) = 0 Or Int( .Value % 100 ) > 59, Int( .Value / 100 ) * 100 + 59, .Value - 1 ) > Else > .Value = Iif( Int( .Value % 100 ) > 58, Int( .Value / 100 ) * 100, .Value + 1 ) > Endif > Endcase > .lsegmentisvalid = .T. > Endwith > Endproc > > *-- Used to validate current segment when the user types a value directly into the control > Procedure validatesegment > Local lnHours, lnMinutes, llRetVal, lnMax > *** Figure out which segment we are validating > *** and check for a legal value > With This > *********************************************************************** > *** Changed By.: Marcia G. Akins on 17 February 2007 > *** Reason.....: Make this configurable to use either a 12 or 24 hour clock > *********************************************************************** > lnMax = Val( Left( Transform( .SpinnerHighValue ), 2 ) ) > > Do Case > Case Between( .nselstart, 0, 2 ) > If .lshowseconds > lnHours = Val( Left ( Padl ( Int( .Value ), 6, '0' ) , 2 ) ) > Else > lnHours = Val( Left ( Padl ( Int( .Value ), 4, '0' ) , 2 ) ) > Endif > *********************************************************************** > *** Changed By.: Marcia G. Akins on 03 December 2006 > *** Reason.....: try to fix user surely keyboard behavior when the user tries > *** ...........: to type 08 directly into the hours portion of the control > *********************************************************************** > If .SelStart = 0 And lnHours = 0 > .lsegmentisvalid = .T. > Else > If Between( lnHours, 1, lnMax ) > .lsegmentisvalid = .T. > Else > .lsegmentisvalid = .F. > Messagebox( 'Hours must be between 1 and ' + Transform( lnMax ), 16, 'Invalid Time' ) > Endif > Endif > Case Between( .nselstart, 3, 5 ) > If .lshowseconds > lnMinutes = Int ( Int( .Value ) % 10000 / 100 ) > Else > lnMinutes = Int( .Value ) % 100 > Endif > If Between( lnMinutes, 0, 59 ) > .lsegmentisvalid = .T. > Else > .lsegmentisvalid = .F. > Messagebox( 'Minutes must be between 0 and 59', 16, 'Invalid Time' ) > Endif > Otherwise > If .lshowseconds > If Between( Int( .Value % 100 ), 0, 59 ) > .lsegmentisvalid = .T. > Else > .lsegmentisvalid = .F. > Messagebox( 'Seconds must be between 0 and 59', 16, 'Invalid Time' ) > Endif > Endif > Endcase > Endwith > Endproc > > *-- Required to type hours directly into the control whent he time value is 0 > Procedure initializehours > With This > If .Value < .SpinnerLowValue > .Value = .SpinnerLowValue > Endif > Endwith > Endproc > > *-- Used to handle keystrokes when the user is typing directly into the spinner > Procedure handlekey > Lparameters tnKeyCode > Local lcKey, lcLeft, lcRight, lnValue, lcValue, lnSelStart > lcLeft = [] > lcRight = [] > *** Get the Value from the spinner as a character string > If This.lshowseconds > lcValue = Padl ( Int( .Value ), 6, '0' ) > lcValue = Left( lcValue, 2 ) + [:] + Substr( lcValue, 3, 2 ) + [:] + Right( lcValue, 2 ) > Else > lcValue = Padl ( Int( .Value ), 4, '0' ) > lcValue = Left( lcValue, 2 ) + [:] + Right( lcValue, 2 ) > Endif > *** Get the replacement keystroke > lcKey = Chr( tnKeyCode ) > lnSelStart = This.SelStart > *** Now see where we have to replace the character > If lnSelStart > 0 > lcLeft = Left( lcValue, lnSelStart ) > Endif > If lnSelStart < Len( lcValue ) - 1 > lcRight = Substr( lcValue, lnSelStart + 2 ) > Endif > lcValue = lcLeft + lcKey + lcRight > lnValue = Val( Chrtran( lcValue, [:], [] ) ) > This.Value = lnValue > *** Set the insertion point appropriately > If lnSelStart = 0 > This.SelStart = 1 > Else > If lnSelStart = 3 > This.SelStart = 4 > Else > If lnSelStart = 6 > This.SelStart = 7 > Else > This.SelStart = lnSelStart > Endif > Endif > Endif > Endproc > > Procedure GotFocus > *** Set the highlight whether the user clicks on the control > *** or tabs into it > This.initializehours() > Spinner::GotFocus() > This.sethighlight() > Nodefault > Endproc > > Procedure DownClick > *** Decrement the appropriate portion of the spinner and reset the highligh > *** Passing .T. tells the changetime method to decrement to selected portion > *** of the spinner. Passing the changetime method .f. (or no paramters) results > *** in an increment of the selected portion > With This > .changetime( .T. ) > .SelStart = .nselstart > .SelLength = 2 > Endwith > Endproc > > Procedure UpClick > *** Increment the appropriate portion of the spinner and reset the highlight > With This > .changetime() > .SelStart = .nselstart > .SelLength = 2 > Endwith > Endproc > > Procedure KeyPress > Lparameters nKeyCode, nShiftAltCtrl > Local llDecrement > With This > Do Case > Case nKeyCode = 19 Or nKeyCode = 4 && Left and right arrow keys > If .lsegmentisvalid > .movehighlight( nKeyCode ) > Endif > Nodefault > > Case nKeyCode = 5 Or nKeyCode = 24 && Up or down arrow > If nKeyCode = 24 > llDecrement = .T. > Endif > .changetime( llDecrement ) > .SelStart = .nselstart > .SelLength = 2 > Nodefault > > Otherwise > *** So we don't mess up the formatted time > *** If we start typing numbers and Part of the value is selected, > *** we lose digits and the remaining ones shift > .SelLength = 0 > *** If we are typing a number directly into the control, > *** make sure it is a valid hours, minutes, or seconds value > If Between( nKeyCode, 48, 57 ) > .handlekey( nKeyCode ) > .validatesegment() > Nodefault > Endif > Endcase > Endwith > Endproc > > Procedure Init > If DoDefault() > This.Setup() > Endif > Endproc > > Procedure Click > With This > If .lsegmentisvalid > Spinner::Click() > .sethighlight() > Else > *** Don't let the user move out of the segement before > *** he fixes the bad input > .SelStart = .nselstart > .SelLength = 2 > Endif > Endwith > Nodefault > Endproc > > Procedure Valid > With This > .validatesegment() > If .lsegmentisvalid > Else > Return 0 > Endif > Endwith > Endproc >Enddefine >