home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tv20cpp.zip / src / TInputLine.cpp < prev    next >
C/C++ Source or Header  |  1999-05-26  |  14KB  |  535 lines

  1. /*
  2.  * TInputLine.cc
  3.  *
  4.  * Turbo Vision - Version 2.0
  5.  *
  6.  * Copyright (c) 1994 by Borland International
  7.  * All Rights Reserved.
  8.  *
  9.  * Modified by Sergio Sigala <ssigala@globalnet.it>
  10.  */
  11.  
  12. #define Uses_TGroup
  13. #define Uses_TKeys
  14. #define Uses_TInputLine
  15. #define Uses_TDrawBuffer
  16. #define Uses_TEvent
  17. #define Uses_TValidator
  18. #define Uses_opstream
  19. #define Uses_ipstream
  20. #include <tvision/tv.h>
  21.  
  22. #include <ctype.h>
  23. #include <string.h>
  24.  
  25. const int CONTROL_Y = 25;
  26.  
  27. char hotKey( const char *s )
  28. {
  29.     char *p;
  30.  
  31.     if( (p = strchr( (char *) s, '~' )) != 0 )
  32.         {
  33.         if( hab == NULLHANDLE )
  34.         return toupper(p[1]);
  35.       else
  36.         return WinUpperChar( hab, Codepage, Country, p[1] );
  37.       }
  38.     else
  39.         return 0;
  40. }
  41.  
  42. #define cpInputLine "\x13\x13\x14\x15"
  43.  
  44. TInputLine::TInputLine( const TRect& bounds, int aMaxLen, TValidator *aValid ) :
  45.     TView(bounds),
  46.     data( new char[aMaxLen] ),
  47.     maxLen( aMaxLen-1 ),
  48.     curPos( 0 ),
  49.     firstPos( 0 ),
  50.     selStart( 0 ),
  51.     selEnd( 0 ),
  52.     validator( aValid ),
  53. #ifndef __UNPATCHED
  54.     oldData( new char[aMaxLen] ),
  55.     anchor( -1 ),
  56.     oldAnchor( -1 )
  57. #else
  58.     oldData( new char[aMaxLen] )
  59. #endif
  60. {
  61.     state |= sfCursorVis;
  62.     options |= ofSelectable | ofFirstClick;
  63.     *data = EOS;
  64. }
  65.  
  66. TInputLine::~TInputLine()
  67. {
  68.     delete data;
  69.     delete oldData;
  70.     destroy(validator);
  71. }
  72.  
  73. Boolean TInputLine::canScroll( int delta )
  74. {
  75.     if( delta < 0 )
  76.         return Boolean( firstPos > 0 );
  77.     else
  78.         if( delta > 0 )
  79. //            return Boolean( strlen(data) - firstPos + 2 > size.x ); /* XXX */
  80.             return Boolean( (int)strlen(data) - firstPos + 2 > size.x ); /* XXX */
  81.         else
  82.             return False;
  83. }
  84.  
  85. ushort TInputLine::dataSize()
  86. {
  87.     ushort dSize = 0;
  88.  
  89.     if (validator)
  90.         dSize = validator->transfer(data, NULL, vtDataSize);
  91.     if (dSize == 0)
  92.         dSize = maxLen + 1;
  93.     return dSize;
  94. }
  95.  
  96. void TInputLine::draw()
  97. {
  98.     int l, r;
  99.     TDrawBuffer b;
  100.  
  101.     uchar color = (state & sfFocused) ? getColor( 2 ) : getColor( 1 );
  102.  
  103.     b.moveChar( 0, ' ', color, size.x );
  104.     char buf[256];
  105.     strncpy( buf, data+firstPos, size.x - 2 );
  106.     buf[size.x - 2 ] = EOS;
  107.     b.moveStr( 1, buf, color );
  108.  
  109.     if( canScroll(1) )
  110.         b.moveChar( size.x-1, rightArrow, getColor(4), 1 );
  111.     if( (state & sfSelected) != 0 )
  112.         {
  113.         if( canScroll(-1) )
  114.             b.moveChar( 0, leftArrow, getColor(4), 1 );
  115.         l = selStart - firstPos;
  116.         r = selEnd - firstPos;
  117.         l = max( 0, l );
  118.         r = min( size.x - 2, r );
  119.         if (l <  r)
  120.             b.moveChar( l+1, 0, getColor(3), r - l );
  121.         }
  122.     writeLine( 0, 0, size.x, size.y, b );
  123.     setCursor( curPos-firstPos+1, 0);
  124. }
  125.  
  126. void TInputLine::getData( void *rec )
  127. {
  128.     if ((validator == 0) || (validator->transfer(data, rec, vtGetData) == 0))
  129.         memcpy( rec, data, dataSize() );
  130. }
  131.  
  132. TPalette& TInputLine::getPalette() const
  133. {
  134.     static TPalette palette( cpInputLine, sizeof( cpInputLine )-1 );
  135.     return palette;
  136. }
  137.  
  138. int TInputLine::mouseDelta( TEvent& event )
  139. {
  140.     TPoint mouse = makeLocal( event.mouse.where );
  141.  
  142.     if( mouse.x <= 0 )
  143.         return -1;
  144.     else
  145.         if( mouse.x >= size.x - 1 )
  146.             return 1;
  147.         else
  148.             return 0;
  149. }
  150.  
  151. int TInputLine::mousePos( TEvent& event )
  152. {
  153.     TPoint mouse = makeLocal( event.mouse.where );
  154.     mouse.x = max( mouse.x, 1 );
  155.     int pos = mouse.x + firstPos - 1;
  156.     pos = max( pos, 0 );
  157.     pos = min( pos, strlen(data) );
  158.     return pos;
  159. }
  160.  
  161. void  TInputLine::deleteSelect()
  162. {
  163.     if( selStart < selEnd )
  164.         {
  165.         strcpy( data+selStart, data+selEnd );
  166.         curPos = selStart;
  167.         }
  168. }
  169.  
  170. void TInputLine::adjustSelectBlock()
  171. {
  172. #ifndef __UNPATCHED
  173.     if(anchor < 0)
  174.         selEnd = selStart = 0;
  175.     else
  176. #endif
  177.     if (curPos < anchor)
  178.         {
  179.         selStart = curPos;
  180.         selEnd =  anchor;
  181.         }
  182.     else
  183.         {
  184.         selStart = anchor;
  185.         selEnd = curPos;
  186.         }
  187. }
  188.  
  189. void TInputLine::saveState()
  190. {
  191.     if (validator)
  192.         {
  193.         strcpy(oldData,data);
  194.         oldCurPos = curPos;
  195.         oldFirstPos = firstPos;
  196.         oldSelStart = selStart;
  197.         oldSelEnd = selEnd;
  198. #ifndef __UNPATCHED
  199.     oldAnchor = anchor;
  200. #endif
  201.         }
  202. }
  203.  
  204. void TInputLine::restoreState()
  205. {
  206.     if (validator)
  207.         {
  208.         strcpy(data, oldData);
  209.         curPos = oldCurPos;
  210.         firstPos = oldFirstPos;
  211.         selStart = oldSelStart;
  212.         selEnd = oldSelEnd;
  213. #ifndef __UNPATCHED
  214.     anchor = oldAnchor;
  215. #endif
  216.         }
  217. }
  218.  
  219. Boolean TInputLine::checkValid(Boolean noAutoFill)
  220. {
  221.     int oldLen;
  222.     char *newData;
  223.  
  224.     if (validator)
  225.         {
  226.         oldLen = strlen(data);
  227.         newData = new char[256];
  228.         strcpy(newData, data);
  229.         if (!validator->isValidInput(newData, noAutoFill))
  230.             {
  231.                 restoreState();
  232.                 delete newData;
  233.                 return False;
  234.             }
  235.         else
  236.             {
  237. //            if (strlen(newData) > maxLen)    /* XXX */
  238.             if ((int)strlen(newData) > maxLen)    /* XXX */
  239.                 newData[maxLen] = 0;
  240.             strcpy(data,newData);
  241. //            if ((curPos >= oldLen) && (strlen(data) > oldLen)) /* XXX */
  242.             if ((curPos >= oldLen) && ((int)strlen(data) > oldLen)) /* XXX */
  243.                 curPos = strlen(data);
  244.             delete newData;
  245.             return True;
  246.             }
  247.         }
  248.     else
  249.         return True;
  250. }
  251.  
  252.  
  253. void TInputLine::handleEvent( TEvent& event )
  254. {
  255. #ifndef __UNPATCHED
  256.     // Boolean extendBlock;
  257. #else
  258.     Boolean extendBlock;
  259. #endif
  260.     /* Home, Left Arrow, Right Arrow, End, Ctrl-Left Arrow, Ctrl-Right Arrow */
  261.     static char padKeys[] = {0x47,0x4b,0x4d,0x4f,0x73,0x74, 0};
  262.     TView::handleEvent(event);
  263.  
  264.     int delta, i;
  265.     if( (state & sfSelected) != 0 )
  266.         switch( event.what )
  267.             {
  268.             case evMouseDown:
  269.                 if( canScroll(delta = mouseDelta(event)) )
  270.                     do  {
  271.                         if( canScroll(delta) )
  272.                             {
  273.                             firstPos += delta;
  274.                             drawView();
  275.                             }
  276.                         } while( mouseEvent( event, evMouseAuto ) );
  277.                 else if (event.mouse.eventFlags & meDoubleClick)
  278.                     selectAll(True);
  279.                 else
  280.                     {
  281.                     anchor =  mousePos(event);
  282.                     do  {
  283.                         if( event.what == evMouseAuto)
  284.                             {
  285.                             delta = mouseDelta(event);
  286.                             if (canScroll(delta))
  287.                                 firstPos += delta;
  288.                             }
  289.                         curPos = mousePos(event);
  290.                         adjustSelectBlock();
  291.                         drawView();
  292.                         }
  293.                         while (mouseEvent(event,evMouseMove | evMouseAuto));
  294.                     }
  295.                 clearEvent(event);
  296.                 break;
  297.             case evKeyDown:
  298.                 saveState();
  299.         /*
  300.          * Some things that caused strange effects are fixed.
  301.          * Date: Sun Feb 23 15:15:49 MET 1997
  302.          */
  303.  
  304.         /* SS: save the value so it can be used by other objects */
  305.  
  306.         int oldKeyCode = event.keyDown.keyCode;
  307.                 event.keyDown.keyCode = ctrlToArrow(event.keyDown.keyCode);
  308.  
  309.         /* SS: scanCode must be non zero */
  310.  
  311.         if (event.keyDown.charScan.scanCode != 0 &&
  312.             strchr(padKeys, event.keyDown.charScan.scanCode ) &&
  313.                     (event.keyDown.controlKeyState & kbShift) != 0
  314.                   )
  315.                     {
  316.                     event.keyDown.charScan.charCode = 0;
  317. #ifndef __UNPATCHED
  318.                     if(anchor < 0)
  319.                         anchor = curPos;
  320.                 }
  321.                 else
  322.             anchor = -1;
  323. #else
  324.                     if (curPos == selEnd)
  325.                         anchor = selStart;
  326.                     else
  327.                         anchor = selEnd;
  328.                     extendBlock = True;
  329.                     }
  330.                 else
  331.                     extendBlock = False;
  332. #endif
  333.                 switch( event.keyDown.keyCode )
  334.                     {
  335.                     case kbLeft:
  336.                         if( curPos > 0 )
  337.                             curPos--;
  338.                         break;
  339.                     case kbRight:
  340. //                        if( curPos < strlen(data) ) /* XXX */
  341.                         if( curPos < (int)strlen(data) ) /* XXX */
  342.                             curPos++;
  343.                         break;
  344.                     case kbHome:
  345.                         curPos =  0;
  346.                         break;
  347.                     case kbEnd:
  348.                         curPos = strlen(data);
  349.                         break;
  350.                     case kbBack:
  351.                         if( curPos > 0 )
  352.                             {
  353.                             strcpy( data+curPos-1, data+curPos );
  354.                             curPos--;
  355.                             if( firstPos > 0 )
  356.                                 firstPos--;
  357.                             checkValid(True);
  358.                             }
  359.                         break;
  360.                     case kbDel:
  361.                         if( selStart == selEnd )
  362. //                            if( curPos < strlen(data) ) /* XXX */
  363.                             if( curPos < (int)strlen(data) ) /* XXX */
  364.                                 {
  365.                                 selStart = curPos;
  366.                                 selEnd = curPos + 1;
  367.                                 }
  368.                         deleteSelect();
  369.                         checkValid(True);
  370.                         break;
  371.                     case kbIns:
  372.                         setState(sfCursorIns, Boolean(!(state & sfCursorIns)));
  373.                         break;
  374.                     default:
  375.                         if( event.keyDown.charScan.charCode >= ' ' )
  376.                             {
  377.                             deleteSelect();
  378.                             if( (state & sfCursorIns) != 0 )
  379.                                 /* The following must be a signed comparison! */
  380.                                 if( curPos < (int) strlen(data) )
  381.                                     strcpy( data + curPos, data + curPos + 1 );
  382.  
  383.                             if( checkValid(True) )
  384.                                 {
  385. //                                if( strlen(data) < maxLen ) /* XXX */
  386.                                 if( (int)strlen(data) < maxLen ) /* XXX */
  387.                                     {
  388.                                     if( firstPos > curPos )
  389.                                         firstPos = curPos;
  390.                                     memmove( data+curPos+1, data+curPos, strlen(data+curPos)+1 );
  391.                                     data[curPos++] = event.keyDown.charScan.charCode;
  392.                                     }
  393.                                 checkValid(False);
  394.                                 }
  395.                             }
  396.                         else if( event.keyDown.charScan.charCode == CONTROL_Y)
  397.                             {
  398.                             *data = EOS;
  399.                             curPos = 0;
  400.                             }
  401.                             else
  402.                 {
  403.                 /* SS: restore the old value before exit */
  404.  
  405.                 event.keyDown.keyCode = oldKeyCode;
  406.                 return;
  407.                 }
  408.                     }
  409. #ifndef __UNPATCHED
  410.         adjustSelectBlock();
  411. #else
  412.                 if (extendBlock)
  413.                     adjustSelectBlock();
  414.                 else
  415.                     {
  416.                     selStart = 0;
  417.                     selEnd = 0;
  418.                     }
  419. #endif
  420.                 if( firstPos > curPos )
  421.                     firstPos = curPos;
  422.                 i = curPos - size.x + 2;
  423.                 if( firstPos < i )
  424.                     firstPos = i;
  425.                 drawView();
  426.                 clearEvent( event );
  427.                 break;
  428.             }
  429. }
  430.  
  431. void TInputLine::selectAll( Boolean enable )
  432. {
  433.     selStart = 0;
  434.     if( enable )
  435.         curPos = selEnd = strlen(data);
  436.     else
  437.         curPos = selEnd = 0;
  438.     firstPos = max( 0, curPos-size.x+2 );
  439. #ifndef __UNPATCHED
  440.     anchor = 0;                   //<----- This sets anchor to avoid deselect
  441.     drawView();                   //       on initial selection
  442. #else
  443.     drawView();
  444. #endif
  445. }
  446.  
  447. void TInputLine::setData( void *rec )
  448. {
  449.     if ((validator == 0) || (validator->transfer(data,rec,vtSetData)==0))
  450.         {
  451.         memcpy( data, rec, dataSize()-1 );
  452.         data[dataSize()-1] = EOS;
  453.         }
  454.     selectAll( True );
  455. }
  456.  
  457. void TInputLine::setState( ushort aState, Boolean enable )
  458. {
  459.     TView::setState( aState, enable );
  460.     if( aState == sfSelected ||
  461.         ( aState == sfActive && (state & sfSelected) != 0 )
  462.       )
  463.         selectAll( enable );
  464. }
  465.  
  466. void TInputLine::setValidator( TValidator* aValid )
  467. {
  468.     if (validator!=0)
  469.       destroy(validator);
  470.  
  471.     validator = aValid;
  472. }
  473.  
  474. #if !defined(NO_STREAMABLE)
  475.  
  476. void TInputLine::write( opstream& os )
  477. {
  478.     TView::write( os );
  479.     os << maxLen << curPos << firstPos
  480.        << selStart << selEnd;
  481.     os.writeString( data);
  482.     os << validator;
  483. }
  484.  
  485. void *TInputLine::read( ipstream& is )
  486. {
  487.     TView::read( is );
  488.     is >> maxLen >> curPos >> firstPos
  489.        >> selStart >> selEnd;
  490.     data = new char[maxLen + 1];
  491.     oldData = new char[maxLen + 1];
  492.     is.readString(data, maxLen+1);
  493.     state |= sfCursorVis;
  494. //    is >> validator; /* XXX */
  495.     is >> (void*&) validator; /* XXX */
  496. #ifndef __UNPATCHED
  497.     // options |= ofSelectable | ofFirstClick;
  498. #else
  499.     options |= ofSelectable | ofFirstClick;
  500. #endif
  501.     return this;
  502. }
  503.  
  504. TStreamable *TInputLine::build()
  505. {
  506.     return new TInputLine( streamableInit );
  507. }
  508.  
  509. TInputLine::TInputLine( StreamableInit ) : TView( streamableInit )
  510. {
  511. }
  512.  
  513. #endif
  514.  
  515. Boolean TInputLine::valid(ushort cmd)
  516. {
  517.     if (validator)
  518.         {
  519.         if (cmd == cmValid)
  520.             return Boolean(validator->status == vsOk);
  521.         else if (cmd != cmCancel)
  522.             if (!validator->validate(data))
  523.                 {
  524. #ifndef __UNPATCHED
  525.                 // owner->current = 0;
  526. #else
  527.                 owner->current = 0;
  528. #endif
  529.                 select();
  530.                 return False;
  531.                 }
  532.         }
  533.     return True;
  534. }
  535.