/*
* TInputLine.cc
*
* Turbo Vision - Version 2.0
*
* Copyright (c) 1994 by Borland International
* All Rights Reserved.
*
* Modified by Sergio Sigala <sergio@sigala.it>
*/
#define Uses_TGroup
#define Uses_TKeys
#define Uses_TInputLine
#define Uses_TDrawBuffer
#define Uses_TEvent
#define Uses_TValidator
#define Uses_opstream
#define Uses_ipstream
#include <tvision/tv.h>
#include <ctype.h>
#include <string.h>
const int CONTROL_Y = 25;
char hotKey( const char *s )
{
char *p;
if( (p = strchr( (char *) s, '~' )) != 0 )
return toupper((uchar)(p[1]));
else
return 0;
}
#define cpInputLine "\x13\x13\x14\x15"
TInputLine::TInputLine( const TRect& bounds, int aMaxLen, TValidator *aValid ) :
TView(bounds),
data( new char[aMaxLen] ),
maxLen( aMaxLen-1 ),
curPos( 0 ),
firstPos( 0 ),
selStart( 0 ),
selEnd( 0 ),
validator( aValid ),
anchor( -1 ),
#ifndef __UNPATCHED
oldAnchor( -1 ),
#endif
oldData( new char[aMaxLen] )
{
state |= sfCursorVis;
options |= ofSelectable | ofFirstClick;
*data = EOS;
}
TInputLine::~TInputLine()
{
delete data;
delete oldData;
destroy(validator);
}
Boolean TInputLine::canScroll( int delta )
{
if( delta < 0 )
return Boolean( firstPos > 0 );
else
if( delta > 0 )
return Boolean( (int)strlen(data) - firstPos + 2 > size.x );
else
return False;
}
ushort TInputLine::dataSize()
{
ushort dSize = 0;
if (validator)
dSize = validator->transfer(data, NULL, vtDataSize);
if (dSize == 0)
dSize = maxLen + 1;
return dSize;
}
void TInputLine::draw()
{
int l, r;
TDrawBuffer b;
uchar color = (state & sfFocused) ? getColor( 2 ) : getColor( 1 );
b.moveChar( 0, ' ', color, size.x );
char buf[256];
strncpy( buf, data+firstPos, size.x - 2 );
buf[size.x - 2 ] = EOS;
b.moveStr( 1, buf, color );
if( canScroll(1) )
b.moveChar( size.x-1, rightArrow, getColor(4), 1 );
if( (state & sfSelected) != 0 )
{
if( canScroll(-1) )
b.moveChar( 0, leftArrow, getColor(4), 1 );
l = selStart - firstPos;
r = selEnd - firstPos;
l = max( 0, l );
r = min( size.x - 2, r );
if (l < r)
b.moveChar( l+1, 0, getColor(3), r - l );
}
writeLine( 0, 0, size.x, size.y, b );
setCursor( curPos-firstPos+1, 0);
}
void TInputLine::getData( void *rec )
{
if ((validator == 0) || (validator->transfer(data, rec, vtGetData) == 0))
memcpy( rec, data, dataSize() );
}
TPalette& TInputLine::getPalette() const
{
static TPalette palette( cpInputLine, sizeof( cpInputLine )-1 );
return palette;
}
int TInputLine::mouseDelta( TEvent& event )
{
TPoint mouse = makeLocal( event.mouse.where );
if( mouse.x <= 0 )
return -1;
else
if( mouse.x >= size.x - 1 )
return 1;
else
return 0;
}
int TInputLine::mousePos( TEvent& event )
{
TPoint mouse = makeLocal( event.mouse.where );
mouse.x = max( mouse.x, 1 );
int pos = mouse.x + firstPos - 1;
pos = max( pos, 0 );
pos = min( pos, strlen(data) );
return pos;
}
void TInputLine::deleteSelect()
{
if( selStart < selEnd )
{
strcpy( data+selStart, data+selEnd );
curPos = selStart;
}
}
void TInputLine::adjustSelectBlock()
{
#ifndef __UNPATCHED
if(anchor < 0)
selEnd = selStart = 0;
else
#endif
if (curPos < anchor)
{
selStart = curPos;
selEnd = anchor;
}
else
{
selStart = anchor;
selEnd = curPos;
}
}
void TInputLine::saveState()
{
if (validator)
{
strcpy(oldData,data);
oldCurPos = curPos;
oldFirstPos = firstPos;
oldSelStart = selStart;
oldSelEnd = selEnd;
#ifndef __UNPATCHED
oldAnchor = anchor;
#endif
}
}
void TInputLine::restoreState()
{
if (validator)
{
strcpy(data, oldData);
curPos = oldCurPos;
firstPos = oldFirstPos;
selStart = oldSelStart;
selEnd = oldSelEnd;
#ifndef __UNPATCHED
anchor = oldAnchor;
#endif
}
}
Boolean TInputLine::checkValid(Boolean noAutoFill)
{
int oldLen;
char *newData;
if (validator)
{
oldLen = strlen(data);
newData = new char[256];
strcpy(newData, data);
if (!validator->isValidInput(newData, noAutoFill))
{
restoreState();
delete newData;
return False;
}
else
{
if ((int)strlen(newData) > maxLen)
newData[maxLen] = 0;
strcpy(data,newData);
if ((curPos >= oldLen) && ((int)strlen(data) > oldLen))
curPos = strlen(data);
delete newData;
return True;
}
}
else
return True;
}
void TInputLine::handleEvent( TEvent& event )
{
#ifndef __UNPATCHED
// Boolean extendBlock;
#else
Boolean extendBlock;
#endif
/* Home, Left Arrow, Right Arrow, End, Ctrl-Left Arrow, Ctrl-Right Arrow */
static char padKeys[] = {0x47,0x4b,0x4d,0x4f,0x73,0x74, 0};
TView::handleEvent(event);
int delta, i;
if( (state & sfSelected) != 0 )
switch( event.what )
{
case evMouseDown:
if( canScroll(delta = mouseDelta(event)) )
do {
if( canScroll(delta) )
{
firstPos += delta;
drawView();
}
} while( mouseEvent( event, evMouseAuto ) );
else if (event.mouse.eventFlags & meDoubleClick)
selectAll(True);
else
{
anchor = mousePos(event);
do {
if( event.what == evMouseAuto)
{
delta = mouseDelta(event);
if (canScroll(delta))
firstPos += delta;
}
curPos = mousePos(event);
adjustSelectBlock();
drawView();
}
while (mouseEvent(event,evMouseMove | evMouseAuto));
}
clearEvent(event);
break;
case evKeyDown:
saveState();
/* SS: save the value so it can be used by other objects */
int oldKeyCode = event.keyDown.keyCode;
event.keyDown.keyCode = ctrlToArrow(event.keyDown.keyCode);
/* SS: scanCode must be non zero */
if (event.keyDown.charScan.scanCode != 0 &&
strchr(padKeys, event.keyDown.charScan.scanCode ) &&
(event.keyDown.controlKeyState & kbShift) != 0
)
{
event.keyDown.charScan.charCode = 0;
#ifndef __UNPATCHED
if(anchor < 0)
anchor = curPos;
}
else
anchor = -1;
#else
if (curPos == selEnd)
anchor = selStart;
else
anchor = selEnd;
extendBlock = True;
}
else
extendBlock = False;
#endif
switch( event.keyDown.keyCode )
{
case kbLeft:
if( curPos > 0 )
curPos--;
break;
case kbRight:
if( curPos < (int)strlen(data) )
curPos++;
break;
case kbHome:
curPos = 0;
break;
case kbEnd:
curPos = strlen(data);
break;
case kbBack:
if( curPos > 0 )
{
strcpy( data+curPos-1, data+curPos );
curPos--;
if( firstPos > 0 )
firstPos--;
checkValid(True);
}
break;
case kbDel:
if( selStart == selEnd )
if( curPos < (int)strlen(data) )
{
selStart = curPos;
selEnd = curPos + 1;
}
deleteSelect();
checkValid(True);
break;
case kbIns:
setState(sfCursorIns, Boolean(!(state & sfCursorIns)));
break;
default:
if( event.keyDown.charScan.charCode >= ' ' )
{
deleteSelect();
if( (state & sfCursorIns) != 0 )
/* The following must be a signed comparison! */
if( curPos < (int) strlen(data) )
strcpy( data + curPos, data + curPos + 1 );
if( checkValid(True) )
{
if( (int)strlen(data) < maxLen )
{
if( firstPos > curPos )
firstPos = curPos;
memmove( data+curPos+1, data+curPos, strlen(data+curPos)+1 );
data[curPos++] = event.keyDown.charScan.charCode;
}
checkValid(False);
}
}
else if( event.keyDown.charScan.charCode == CONTROL_Y)
{
*data = EOS;
curPos = 0;
}
else
{
/* SS: restore the old value before exit */
event.keyDown.keyCode = oldKeyCode;
return;
}
}
#ifndef __UNPATCHED
adjustSelectBlock();
#else
if (extendBlock)
adjustSelectBlock();
else
{
selStart = 0;
selEnd = 0;
}
#endif
if( firstPos > curPos )
firstPos = curPos;
i = curPos - size.x + 2;
if( firstPos < i )
firstPos = i;
drawView();
clearEvent( event );
break;
}
}
void TInputLine::selectAll( Boolean enable )
{
selStart = 0;
if( enable )
curPos = selEnd = strlen(data);
else
curPos = selEnd = 0;
firstPos = max( 0, curPos-size.x+2 );
#ifndef __UNPATCHED
anchor = 0; //<----- This sets anchor to avoid deselect
drawView(); // on initial selection
#else
drawView();
#endif
}
void TInputLine::setData( void *rec )
{
if ((validator == 0) || (validator->transfer(data,rec,vtSetData)==0))
{
memcpy( data, rec, dataSize()-1 );
data[dataSize()-1] = EOS;
}
selectAll( True );
}
void TInputLine::setState( ushort aState, Boolean enable )
{
TView::setState( aState, enable );
if( aState == sfSelected ||
( aState == sfActive && (state & sfSelected) != 0 )
)
selectAll( enable );
}
void TInputLine::setValidator( TValidator* aValid )
{
if (validator!=0)
destroy(validator);
validator = aValid;
}
#if !defined(NO_STREAMABLE)
void TInputLine::write( opstream& os )
{
TView::write( os );
os << maxLen << curPos << firstPos
<< selStart << selEnd;
os.writeString( data);
os << validator;
}
void *TInputLine::read( ipstream& is )
{
TView::read( is );
is >> maxLen >> curPos >> firstPos
>> selStart >> selEnd;
data = new char[maxLen + 1];
oldData = new char[maxLen + 1];
is.readString(data, maxLen+1);
state |= sfCursorVis;
// is >> validator; /* XXX */
is >> (void*&) validator; /* XXX */
#ifndef __UNPATCHED
// options |= ofSelectable | ofFirstClick;
#else
options |= ofSelectable | ofFirstClick;
#endif
return this;
}
TStreamable *TInputLine::build()
{
return new TInputLine( streamableInit );
}
TInputLine::TInputLine( StreamableInit ) : TView( streamableInit )
{
}
#endif
Boolean TInputLine::valid(ushort cmd)
{
if (validator)
{
if (cmd == cmValid)
return Boolean(validator->status == vsOk);
else if (cmd != cmCancel)
if (!validator->validate(data))
{
#ifndef __UNPATCHED
// owner->current = 0;
#else
owner->current = 0;
#endif
select();
return False;
}
}
return True;
}
syntax highlighted by Code2HTML, v. 0.9.1