/* * textview.cc * * Turbo Vision - Version 2.0 * * Copyright (c) 1994 by Borland International * All Rights Reserved. * * Modified by Sergio Sigala * Modified by Max Okumoto */ #define Uses_TTextDevice #define Uses_TTerminal #define Uses_otstream #include #include using std::ostream; using std::streamsize; TTextDevice::TTextDevice( const TRect& bounds, TScrollBar *aHScrollBar, TScrollBar *aVScrollBar) : TScroller(bounds,aHScrollBar,aVScrollBar) { } TTerminal::TTerminal( const TRect& bounds, TScrollBar *aHScrollBar, TScrollBar *aVScrollBar, ushort aBufSize ) : TTextDevice(bounds, aHScrollBar, aVScrollBar), queFront( 0 ), #ifndef __UNPATCHED queBack( 0 ), curLineWidth( 0 ) // Added for horizontal cursor tracking. #else queBack( 0 ) #endif { growMode = gfGrowHiX + gfGrowHiY; bufSize = min( 32000U, aBufSize ); buffer = new char[ bufSize ]; setLimit( 0, 1 ); setCursor( 0, 0 ); showCursor(); } TTerminal::~TTerminal() { delete buffer; } void TTerminal::bufDec( ushort& val ) { if (val == 0) val = bufSize - 1; else val--; } void TTerminal::bufInc( ushort& val ) { if( ++val >= bufSize ) val = 0; } Boolean TTerminal::canInsert( ushort amount ) { long T = (queFront < queBack) ? ( queFront + amount ) : ( long(queFront) - bufSize + amount); // cast needed so we get // signed comparison return Boolean( queBack > T ); } void TTerminal::draw() { short i; ushort begLine, endLine; #ifndef __UNPATCHED char s[ maxViewWidth+1 ]; // KRW: Bug Fix/Enhancement: 95/01/05 // Do *NOT* attempt to display more // than maxViewWidth chars // ** assume size.x <= maxViewWidth ** #else char s[256]; #endif ushort bottomLine; bottomLine = size.y + delta.y; if( limit.y > bottomLine ) { endLine = prevLines( queFront, limit.y - bottomLine ); bufDec( endLine ); } else endLine = queFront; if( limit.y > size.y ) i = size.y - 1; else { for( i = limit.y; i <= size.y - 1; i++ ) writeChar(0, i, ' ', 1, size.x); i = limit.y - 1; } for( ; i >= 0; i-- ) { #ifndef __UNPATCHED // KRW: Bug fix/enhancement - handle any length line by only copying // to s those characters to be displayed, which we assume will // be < maxViewWidth // This whole block rewritten memset( s, ' ', size.x ); // must display blanks if no characters! begLine = prevLines(endLine, 1); if (endLine >= begLine) { // Entire string to be displayed is in one fragment, not // wrapped around the end of the buffer int fragmentLength = int( endLine - begLine ); if (fragmentLength > delta.x) { fragmentLength -= delta.x; fragmentLength = min( size.x, fragmentLength ); memcpy( s, &buffer[begLine+delta.x], fragmentLength ); } } else { // Extract first fragment into s int deltaLeft = delta.x; int firstFragmentLength = int( bufSize - begLine ); if (firstFragmentLength > delta.x) { deltaLeft = 0; firstFragmentLength -= delta.x; firstFragmentLength = min( size.x, firstFragmentLength ); memcpy( s, &buffer[begLine+delta.x], firstFragmentLength ); } else { deltaLeft -= firstFragmentLength; firstFragmentLength = 0; } // Extract second fragment into s if ((endLine > deltaLeft) && (firstFragmentLength < size.x)) { int secondFragmentLength = endLine - deltaLeft; secondFragmentLength = min(size.x-firstFragmentLength,secondFragmentLength); memcpy( &s[ firstFragmentLength ], &buffer[ deltaLeft ], secondFragmentLength ); } } s[ size.x ] = EOS; writeStr( 0, i, s, 1 ); endLine = begLine; bufDec( endLine ); #else begLine = prevLines(endLine, 1); if (endLine >= begLine) { int T = int( endLine - begLine ); memcpy( s, &buffer[begLine], T ); s[T] = EOS; } else { int T = int( bufSize - begLine); memcpy( s, &buffer[begLine], T ); memcpy( s+T, buffer, endLine ); s[T+endLine] = EOS; } if( delta.x >= strlen(s) ) *s = EOS; else strcpy( s, &s[delta.x] ); writeStr( 0, i, s, 1 ); writeChar( strlen(s), i, ' ', 1, size.x ); endLine = begLine; bufDec( endLine ); #endif } } ushort TTerminal::nextLine( ushort pos ) { if( pos != queFront ) { while( buffer[pos] != '\n' && pos != queFront ) bufInc(pos); if( pos != queFront ) bufInc( pos ); } return pos; } int TTerminal::do_sputn( const char *s, int count ) { #ifndef __UNPATCHED ushort screenWidth = limit.x; ushort screenLines = limit.y; // BUG FIX - Mon 07/25/94 - EFW: Made TTerminal adjust horizontal // scrollbar limit too. /* SS: stupid thing */ ushort i; for(i = 0; i < count; i++, curLineWidth++) if(s[i] == '\n') { screenLines++; // Check width when an LF is seen. if(curLineWidth > screenWidth) screenWidth = curLineWidth; // Reset width for the next line. curLineWidth = 0; } // One last check for width for cases where whole lines aren't // received, maybe just a character or two. if(curLineWidth > screenWidth) screenWidth = curLineWidth; #else ushort screenLines = limit.y; for( ushort i = 0; i < count; i++ ) if( s[i] == '\n' ) screenLines++; #endif while( !canInsert( count ) ) { queBack = nextLine( queBack ); screenLines--; } if( queFront + count >= bufSize ) { i = bufSize - queFront; memcpy( &buffer[queFront], s, i ); memcpy( buffer, &s[i], count - i ); queFront = count - i; } else { memcpy( &buffer[queFront], s, count ); queFront += count; } #ifndef __UNPATCHED setLimit( screenWidth, screenLines ); #else setLimit( limit.x, screenLines ); #endif scrollTo( 0, screenLines + 1 ); i = prevLines( queFront, 1 ); if( i <= queFront ) i = queFront - i; else i = bufSize - (i - queFront); setCursor( i, screenLines - delta.y - 1 ); drawView(); return count; } Boolean TTerminal::queEmpty() { return Boolean( queBack == queFront ); } TerminalBuf::TerminalBuf(TTerminal *tt): term(tt) { } int TerminalBuf::overflow(int c) { streamsize n = pptr() - pbase(); if (n > 0 && sync() == EOF) return EOF; if (c != EOF) { char b = c; term->do_sputn(&b, sizeof(b)); } pbump(-n); return 0; } int TerminalBuf::sync() { streamsize n = pptr() - pbase(); if (n > 0) term->do_sputn(pbase(), n); return 0; } otstream::otstream( TTerminal *tt ): ostream(&buf), buf(tt) { }