************************************************** *-- Class: spntime (f:\wwnew\libs\basectrl.vcx) *-- ParentClass: spnbase (f:\wwnew\libs\basectrl.vcx) *-- BaseClass: spinner *-- Time Stamp: 03/22/04 05:25:03 PM *-- Time Spinner Class - can be configured to show seconds by setting the lShowSeconds property to true * DEFINE CLASS spntime AS spnbase Increment = 0.00 SpinnerHighValue = 235959.00 SpinnerLowValue = 0.00 Width = 132 Format = "RL" *-- Saves original controlsoource since it is a character string ccontrolsource = "" 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. Name = "spntimebase" *-- True if we are using seconds in the spinner lshowseconds = .F. PROCEDURE incrementhours LPARAMETERS tlDecrement LOCAL lnHours, lnRest WITH This 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 = 00 OR lnHours > 23, 23, lnHours - 1 ) ELSE lnHours = IIF( lnHours > 22, 00, 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" ELSE .InputMask = "99:99" ENDIF .RefreshSpinner() 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 *-- Update the control source if this is a bound control PROCEDURE updatecontrolsource LOCAL lcTable, lcField, lcValue, lcTemp WITH This *** Parse out the name of the table and the name of the field in cControlSource IF ! EMPTY( .cControlSource ) *** If This is a bound control, set save table and field bound to *** Parse out the name of the table if the ControlSource is prefaced by an alias IF '.' $ .cControlSource lcTable = LEFT( .cControlSource, AT( '.', .cControlSource ) - 1 ) lcField = SUBSTR( .cControlSource, AT( '.', .cControlSource ) + 1 ) ELSE *** assume the alias is the current selected alias. This is a little dangerous, but if it is *** a bad assumption, the program will blow up very quickly in development mode *** giving the developer a very clear indication of what is wrong once he checks out *** the problem in the debugger lcTable = ALIAS() lcField = .cControlSource ENDIF *** Now convert the numeric value of the spinner to the character value required by the *** controlSource (if it is bound) and format it with colons. You must take into account *** whether or not we are displaying seconds in the spinner lcTemp = IIF( .lShowSeconds, PADL( INT ( .Value ), 6, '0' ), PADL( INT ( .Value ), 4, '0' ) ) lcValue = LEFT( lcTemp, 2 ) + ':' + SUBSTR( lcTemp, 3, 2 ) + ; IIF( .lShowSeconds, ':' + RIGHT( lcTemp, 2 ), '' ) *** Lots of people bind controls to form properties, so let's just check here to see if our *** alias is ThisForm. If it is, we will assume that we are bound to a form property IF UPPER( lcTable ) = 'THISFORM' STORE lcValue TO ( .cControlSource ) ELSE REPLACE ( lcField ) WITH lcValue IN ( lcTable ) ENDIF ENDIF ENDWITH ENDPROC *-- IF this is a bound control, update the value of the spinner from its cControlSource PROCEDURE refreshspinner *** SInce the spinner must be bound to a numeric value, if it is bound, *** use the cControlSource property instead *** initialize the control's value WITH This IF ! EMPTY( .cControlSource ) .Value = IIF( .lSHowSeconds, VAL( STRTRAN( EVAL( .cControlSource ), ':', '' ) ), ; VAL( STRTRAN( LEFT ( EVAL( .cControlSource ), 5 ), ':', '' ) ) ) ELSE .Value = IIF( .lShowSeconds, VAL( STRTRAN( TIME(), ':', '' ) ), ; VAL( STRTRAN( LEFT( TIME(), 5), ':', '' ) ) ) ENDIF ENDWITH ENDPROC *-- Used to validate current segment when the user types a value directly into the control PROCEDURE validatesegment LOCAL lnHours, lnMinutes, llRetVal *** Figure out which segment we are validating *** and check for a legal value WITH This 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 IF BETWEEN( lnHours, 0, 23 ) .lSegmentIsValid = .T. ELSE .lSegmentIsValid = .F. MESSAGEBOX( 'Hours must be between 0 and 23', 16, 'Invalid Time' ) 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 PROCEDURE GotFocus *** Set the highlight whether the user clicks on the control *** or tabs into it 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 IF .lSegmentIsValid .ChangeTime( .T. ) ENDIF .SelStart = .nSelStart .SelLength = 2 ENDWITH ENDPROC PROCEDURE UpClick *** Increment the appropriate portion of the spinner and reset the highlight WITH This IF .lSegmentIsValid .ChangeTime() ENDIF .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 ) Spinner::KeyPress( nKeyCode, nShiftAltCtrl ) .ValidateSegment() IF ! .lSegmentIsValid .SelStart = .nSelStart .SelLength = 2 ENDIF 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 Refresh DODEFAULT() This.RefreshSpinner() ENDPROC PROCEDURE Valid WITH This IF .lSegmentIsValid .UpdateControlSource() ELSE RETURN 0 ENDIF ENDWITH ENDPROC ENDDEFINE * *-- EndDefine: spntime **************************************************