home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 12 / CD_ASCQ_12_0294.iso / maj / 535 / tinplong.cpp < prev    next >
C/C++ Source or Header  |  1993-07-29  |  7KB  |  279 lines

  1. /*-----------------------------------------------------------------------
  2. TInputLong is a derivitave of TInputLine designed to accept long integer
  3. numeric input.  Since both the upper and lower limit of acceptable numeric
  4. input can be set, TInputLong may be used for short integer or unsigned shorts
  5. as well.  Option flag bits allow optional hex input and display.  A blank
  6. field may optionally be rejected or interpreted as zero.
  7.  
  8. Data Members
  9.  
  10. ushort ilOptions;
  11.    the options (see constructor discussion).
  12.  
  13. long lLim, uLim;
  14.    the lower and upper limits.
  15.  
  16.  
  17. Member functions
  18.  
  19. TInputLong( const TRect& bounds, int aMaxLen, long lowerLim,
  20.             long upperLim, ushort flags, const char* labelName = 0 ) :
  21.  
  22.   Creats a TInputLong control.  Flags may be a combination of:
  23.  
  24.   ilHex = 1,          //will enable hex input with leading '0x'
  25.   ilBlankEqZero = 2,  //No input (blank) will be interpreted as '0'
  26.   ilDisplayHex = 4;   //Number displayed as hex when possible
  27.  
  28.   The optional labelName adds an identifier to any range error message.
  29.   Normally, this would be the same string as the field's label (minus
  30.   the '~'s).
  31.  
  32.  
  33. virtual void TInputLong::write( opstream& os );
  34. virtual void *TInputLong::read( ipstream& is );
  35. static TStreamable *build();
  36. TInputLong( StreamableInit streamableInit);
  37.  
  38. virtual ushort dataSize();
  39. virtual void getData( void *rec );
  40. virtual void setData( void *rec );
  41.  
  42.   The transfer methods.  dataSize is sizeof(long) and rec should be
  43.   the address of a long.
  44.  
  45.  
  46. virtual Boolean rangeCheck();
  47.  
  48.   Returns True if the entered string evaluates to a number >= lowerLim and
  49.   <= upperLim.
  50.  
  51.  
  52. virtual void error();
  53.  
  54.   error is called when rangeCheck fails.  It displays a messagebox
  55.   indicating the allowable range.  The optional labelName parameter in the
  56.   constructor is worked into the message to help identify the field.
  57.  
  58.  
  59. virtual void  handleEvent( TEvent& event );
  60.  
  61.   handleEvent() filters out characters which are not appropriate to numeric
  62.   input.  Tab and Shift Tab cause a call to rangeCheck() and a call to error()
  63.   if rangeCheck() returns false.  The input must be valid to Tab from the
  64.   view.  There's no attempt made to stop moving to another view with the mouse.
  65.  
  66.  
  67. virtual Boolean valid( ushort command );
  68.  
  69.   if TInputLine.valid() is true and Cmd is neither cmValid or cmCancel, valid
  70.   then calls rangeCheck().  If rangeCheck() is false, then error() is called
  71.   and valid() returns False.
  72.  
  73. ------------------------------------------------------------------------*/
  74.  
  75. //#define Uses_TKeys
  76. #define Uses_TInputLong
  77. #define Uses_TInputLine
  78. #define Uses_TDrawBuffer
  79. #define Uses_TEvent
  80. #define Uses_opstream
  81. #define Uses_ipstream
  82. #define Uses_MsgBox
  83. #include <tv.h>
  84. #include <stdlib.h>
  85. #include <tkeys.h>
  86. #include "tinplong.h"
  87.  
  88. #if !defined( __CTYPE_H )
  89. #include <ctype.h>
  90. #endif  // __CTYPE_H
  91.  
  92. #if !defined( __STRING_H )
  93. #include <String.h>
  94. #endif  // __STRING_H
  95.  
  96. #if !defined( __DOS_H )
  97. #include <Dos.h>
  98. #endif  // __DOS_H
  99.  
  100. char * formHexStr(char *s, long L)
  101. {
  102.     if (L < 0)
  103.       {
  104.        s[0] = '-';  s[1] = '0';  s[2] = 'x';
  105.        ltoa(-L, &s[3], 16);
  106.       }
  107.     else
  108.       {s[0] = '0';  s[1] = 'x';
  109.        ltoa(L, &s[2], 16);
  110.       }
  111.     return s;
  112. }
  113.  
  114. TInputLong::TInputLong( const TRect& bounds, int aMaxLen, long lowerLim,
  115.             long upperLim, ushort flags, const char* labelName ) :
  116.     TInputLine(bounds, aMaxLen),
  117.     lLim (lowerLim),
  118.     uLim(upperLim),
  119.     ilOptions(flags),
  120.     label(newStr(labelName))
  121.  
  122. {
  123.    if (ilOptions & ilDisplayHex)
  124.        ilOptions |= ilHex;
  125.    if (ilOptions & ilBlankEqZero)
  126.        strcpy(data, "0");
  127. }
  128.  
  129. TInputLong::~TInputLong()
  130. {
  131.     if (label) delete label;
  132. }
  133.  
  134.  
  135. ushort TInputLong::dataSize()
  136. {
  137.     return sizeof(long);
  138. }
  139.  
  140. void TInputLong::getData( void *rec )
  141. {
  142.    long L;
  143.    if (data[0] == '\0' && (ilOptions & ilBlankEqZero))
  144.      strcpy(data, "0");
  145.    if ( (ilHex & ilOptions) && (strchr(data, 'X') || strchr(data, 'x')) )
  146.       L = strtol(data, 0, 16);
  147.    else L = strtol(data, 0, 10);
  148.    *(long*)rec = L;
  149. }
  150.  
  151. void  TInputLong::handleEvent( TEvent& event )
  152. {
  153.     if (event.what == evKeyDown)
  154.       {switch (event.keyDown.keyCode)
  155.     {
  156.     case kbTab:
  157.     case kbShiftTab:
  158.        if (!rangeCheck())
  159.         {error();
  160.          selectAll(True);
  161.          clearEvent(event);
  162.         }
  163.        break;
  164.     }
  165.       }
  166.     if (event.keyDown.charScan.charCode)
  167.       {
  168.     int ch = toupper(event.keyDown.charScan.charCode);
  169.     switch (ch)
  170.       {
  171.       case '-' : if ( !(lLim < 0 && (curPos == 0 || selEnd > 0)) )
  172.             clearEvent(event); break;
  173.       case 'X' : if ( (ilOptions & ilHex) &&
  174.              (curPos == 1 && data[0] == '0')
  175.               || (curPos == 2 && data[0] == '-' && data[1] == '0') );
  176.              else clearEvent(event);
  177.              break;
  178.       case 'A' :
  179.       case 'B' :
  180.       case 'C' :
  181.       case 'D' :
  182.       case 'E' :
  183.       case 'F' : if (!strchr(data, 'X') && !strchr(data, 'x') )
  184.             clearEvent(event);
  185.              break;
  186.       default : if ((ch < '0' || ch > '9') && (ch < 1 || ch > 0x1B))
  187.             clearEvent(event);
  188.             break;
  189.       }
  190.       }
  191.     TInputLine::handleEvent(event);
  192. }
  193.  
  194. void TInputLong::setData( void *rec )
  195. {
  196.     char s[40];
  197.     long L = *(long*)rec;
  198.     if (L > uLim) L = uLim;
  199.     else if (L < lLim) L = lLim;
  200.     if (ilOptions & ilDisplayHex)
  201.     formHexStr(s, L);
  202.     else ltoa(L, s, 10);
  203.     memcpy( data, s, maxLen );
  204.     data[maxLen] = EOS;
  205.     selectAll( True );
  206. }
  207.  
  208. Boolean TInputLong::rangeCheck()
  209. {
  210.    long L;
  211.    char *endptr;
  212.    if (data[0] == '\0')
  213.      if (ilOptions & ilBlankEqZero)
  214.        strcpy(data, "0");
  215.      else return False;
  216.    if ( (ilHex & ilOptions) && (strchr(data, 'X') || strchr(data, 'x')) )
  217.       L = strtol(data, &endptr, 16);
  218.    else L = strtol(data, &endptr, 10);
  219.    return Boolean( (L >= lLim) && (L <= uLim) && (*endptr == 0) );
  220. }
  221.  
  222. void TInputLong::error()
  223. #define SIZE 60
  224. {  char sl[40], su[40], s[SIZE];
  225.    if (label == 0)  s[0] = '\0';
  226.    else  {
  227.       strcpy(s, "\"");
  228.       strncat(s, label, SIZE-4);
  229.       strcat(s, "\"\n");
  230.       }
  231.    if (ilHex & ilOptions)
  232.      messageBox(mfError | mfOKButton, "%sValue not within range %ld(%s) to %ld(%s)",
  233.         s, lLim, formHexStr(sl, lLim), uLim, formHexStr(su, uLim));
  234.    else
  235.      messageBox(mfError | mfOKButton, "%sValue not within range %ld to %ld",
  236.         s, lLim, uLim);
  237. }
  238.  
  239. Boolean TInputLong::valid(ushort command)
  240. {
  241.    Boolean rslt = TInputLine::valid(command);
  242.    if (rslt && (command != 0) && (command != cmCancel))
  243.      {rslt = rangeCheck();
  244.       if (!rslt)
  245.     {error();
  246.      select();
  247.      selectAll(True);
  248.     }
  249.      }
  250.    return rslt;
  251. }
  252.  
  253. void TInputLong::write( opstream& os )
  254. {
  255.     TInputLine::write( os );
  256.     os << ilOptions << lLim << uLim;
  257.     os.writeString(label);
  258. }
  259.  
  260. void *TInputLong::read( ipstream& is )
  261. {
  262.     TInputLine::read( is );
  263.     is >> ilOptions >> lLim >> uLim;
  264.     label = is.readString();
  265.     return this;
  266. }
  267.  
  268. TStreamable *TInputLong::build()
  269. {
  270.     return new TInputLong( streamableInit );
  271. }
  272.  
  273. TInputLong::TInputLong( StreamableInit ) : TInputLine( streamableInit )
  274. {
  275. }
  276.  
  277. const char * const near TInputLong::name = "TInputLong";
  278.  
  279.