summaryrefslogtreecommitdiff
path: root/freebsdtvision/lib/TEditor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'freebsdtvision/lib/TEditor.cc')
-rw-r--r--freebsdtvision/lib/TEditor.cc1144
1 files changed, 1144 insertions, 0 deletions
diff --git a/freebsdtvision/lib/TEditor.cc b/freebsdtvision/lib/TEditor.cc
new file mode 100644
index 0000000..7644fcc
--- /dev/null
+++ b/freebsdtvision/lib/TEditor.cc
@@ -0,0 +1,1144 @@
+/*
+ * TEditor.cc
+ *
+ * Turbo Vision - Version 2.0
+ *
+ * Copyright (c) 1994 by Borland International
+ * All Rights Reserved.
+ *
+ * Modified by Sergio Sigala <sergio@sigala.it>
+ * Modified again by Dmitrij Korovkin <tkf@glasnet.ru>
+ */
+
+#define Uses_TKeys
+#define Uses_TEditor
+#define Uses_TIndicator
+#define Uses_TEvent
+#define Uses_TScrollBar
+#define Uses_TFindDialogRec
+#define Uses_TReplaceDialogRec
+#define Uses_opstream
+#define Uses_ipstream
+#include <tvision/tv.h>
+
+#include <ctype.h>
+#include <string.h>
+
+/*
+ * SS: declarations fixed. See `asm.cc'.
+ */
+int countLines( void *buf, size_t count );
+size_t scan( const void *block, size_t size, const char *str );
+size_t iScan( const void *block, size_t size, const char *str );
+
+inline int isWordChar( int ch )
+{
+#ifndef __UNPATCHED
+ return isalnum((uchar)ch) || ch == '_';
+// ^^^^^- correction for extended ASCII.
+#else
+ return isalnum(ch) || ch == '_';
+#endif
+}
+
+const ushort firstKeys[] =
+{
+ 37,
+ kbCtrlA, cmWordLeft,
+ kbCtrlC, cmPageDown,
+ kbCtrlD, cmCharRight,
+ kbCtrlE, cmLineUp,
+ kbCtrlF, cmWordRight,
+ kbCtrlG, cmDelChar,
+ kbCtrlH, cmBackSpace,
+ kbCtrlK, 0xFF02,
+ kbCtrlL, cmSearchAgain,
+ kbCtrlM, cmNewLine,
+ kbCtrlO, cmIndentMode,
+ kbCtrlQ, 0xFF01,
+ kbCtrlR, cmPageUp,
+ kbCtrlS, cmCharLeft,
+ kbCtrlT, cmDelWord,
+ kbCtrlU, cmUndo,
+ kbCtrlV, cmInsMode,
+ kbCtrlX, cmLineDown,
+ kbCtrlY, cmDelLine,
+ kbLeft, cmCharLeft,
+ kbRight, cmCharRight,
+ kbCtrlLeft, cmWordLeft,
+ kbCtrlRight, cmWordRight,
+ kbHome, cmLineStart,
+ kbEnd, cmLineEnd,
+ kbUp, cmLineUp,
+ kbDown, cmLineDown,
+ kbPgUp, cmPageUp,
+ kbPgDn, cmPageDown,
+ kbCtrlPgUp, cmTextStart,
+ kbCtrlPgDn, cmTextEnd,
+ kbIns, cmInsMode,
+ kbDel, cmDelChar,
+ kbShiftIns, cmPaste,
+ kbShiftDel, cmCut,
+ kbCtrlIns, cmCopy,
+ kbCtrlDel, cmClear
+};
+
+const ushort quickKeys[] =
+{ 8,
+ 'A', cmReplace,
+ 'C', cmTextEnd,
+ 'D', cmLineEnd,
+ 'F', cmFind,
+ 'H', cmDelStart,
+ 'R', cmTextStart,
+ 'S', cmLineStart,
+ 'Y', cmDelEnd
+};
+
+const ushort blockKeys[] =
+{ 5,
+ 'B', cmStartSelect,
+ 'C', cmPaste,
+ 'H', cmHideSelect,
+ 'K', cmCopy,
+ 'Y', cmCut
+};
+
+const ushort *keyMap[] = { firstKeys, quickKeys, blockKeys };
+
+ushort defEditorDialog( int, ... );
+
+ushort scanKeyMap( const void *keyMap, ushort keyCode )
+{
+ register ushort *kM = (ushort *)keyMap;
+ uchar codeLow = keyCode & 0xff;
+ uchar codeHi = keyCode >> 8;
+
+ int n;
+
+ for (n = *kM++; n--; kM++)
+ {
+ uchar mapLow = *kM & 0xff;
+ uchar mapHi = *kM >> 8;
+ kM++;
+ ushort command = *kM;
+
+ if ((mapLow == codeLow) && ((mapHi == 0) || (mapHi == codeHi)))
+ return command;
+ };
+ return 0;
+}
+
+#define cpEditor "\x06\x07"
+
+TEditor::TEditor( const TRect& bounds,
+ TScrollBar *aHScrollBar,
+ TScrollBar *aVScrollBar,
+ TIndicator *aIndicator,
+ uint aBufSize ) :
+ TView( bounds ),
+ hScrollBar( aHScrollBar ),
+ vScrollBar( aVScrollBar ),
+ indicator( aIndicator ),
+ bufSize( aBufSize ),
+ canUndo( True ),
+ selecting( False ),
+ overwrite( False ),
+ autoIndent( False ) ,
+ lockCount( 0 ),
+ keyState( 0 )
+{
+ growMode = gfGrowHiX | gfGrowHiY;
+ options |= ofSelectable;
+ eventMask = evMouseDown | evKeyDown | evCommand | evBroadcast;
+ showCursor();
+ initBuffer();
+ if( buffer != 0 )
+ isValid = True;
+ else
+ {
+ editorDialog( edOutOfMemory );
+ bufSize = 0;
+ isValid = False;
+ }
+ setBufLen(0);
+}
+
+TEditor::~TEditor()
+{
+}
+
+void TEditor::shutDown()
+{
+ doneBuffer();
+ TView::shutDown();
+}
+
+void TEditor::changeBounds( const TRect& bounds )
+{
+ setBounds(bounds);
+ delta.x = max(0, min(delta.x, limit.x - size.x));
+ delta.y = max(0, min(delta.y, limit.y - size.y));
+ update(ufView);
+}
+
+uint TEditor::charPos( uint p, uint target )
+{
+ uint pos = 0;
+ while( p < target )
+ {
+ if( bufChar(p) == '\x9' )
+ pos |= 7;
+ pos++;
+ p++;
+ }
+ return pos;
+}
+
+uint TEditor::charPtr( uint p, uint target )
+{
+ uint pos = 0;
+ /* SS: changed */
+ while( (pos < target) && (p < bufLen) && (bufChar(p) != '\n') )
+ {
+ if( bufChar(p) == '\x09' )
+ pos |= 7;
+ pos++;
+ p++;
+ }
+ if( pos > target )
+ p--;
+ return p;
+}
+
+Boolean TEditor::clipCopy()
+{
+ Boolean res = False;
+ if( (clipboard != 0) && (clipboard != this) )
+ {
+ res = clipboard->insertFrom(this);
+ selecting = False;
+ update(ufUpdate);
+ }
+ return res;
+}
+
+void TEditor::clipCut()
+{
+ if( clipCopy() == True )
+ deleteSelect();
+}
+
+void TEditor::clipPaste()
+{
+ if( (clipboard != 0) && (clipboard != this) )
+ insertFrom(clipboard);
+}
+
+void TEditor::convertEvent( TEvent& event )
+{
+ if( event.what == evKeyDown )
+ {
+ if( (event.keyDown.controlKeyState & kbShift) != 0 &&
+ event.keyDown.charScan.scanCode >= 0x47 &&
+ event.keyDown.charScan.scanCode <= 0x51
+ )
+ event.keyDown.charScan.charCode = 0;
+
+ ushort key = event.keyDown.keyCode;
+ if( keyState != 0 )
+ {
+ if( (key & 0xFF) >= 0x01 && (key & 0xFF) <= 0x1A )
+ key += 0x40;
+ if( (key & 0xFF) >= 0x61 && (key & 0xFF) <= 0x7A )
+ key -= 0x20;
+ }
+ key = scanKeyMap(keyMap[keyState], key);
+ keyState = 0;
+ if( key != 0 )
+ if( (key & 0xFF00) == 0xFF00 )
+ {
+ keyState = (key & 0xFF);
+ clearEvent(event);
+ }
+ else
+ {
+ event.what = evCommand;
+ event.message.command = key;
+ }
+ }
+}
+
+Boolean TEditor::cursorVisible()
+{
+ return Boolean((curPos.y >= delta.y) && (curPos.y < delta.y + size.y));
+}
+
+void TEditor::deleteRange( uint startPtr,
+ uint endPtr,
+ Boolean delSelect
+ )
+{
+ if( hasSelection() == True && delSelect == True )
+ deleteSelect();
+ else
+ {
+ setSelect(curPtr, endPtr, True);
+ deleteSelect();
+ setSelect(startPtr, curPtr, False);
+ deleteSelect();
+ }
+}
+
+void TEditor::deleteSelect()
+{
+ insertText( 0, 0, False );
+}
+
+void TEditor::doneBuffer()
+{
+ delete buffer;
+}
+
+void TEditor::doSearchReplace()
+{
+ int i;
+ do {
+ i = cmCancel;
+ if( search(findStr, editorFlags) == False )
+ {
+ if( (editorFlags & (efReplaceAll | efDoReplace)) !=
+ (efReplaceAll | efDoReplace) )
+ editorDialog( edSearchFailed );
+ }
+ else
+ if( (editorFlags & efDoReplace) != 0 )
+ {
+ i = cmYes;
+ if( (editorFlags & efPromptOnReplace) != 0 )
+ {
+ TPoint c = makeGlobal( cursor );
+ i = editorDialog( edReplacePrompt, &c );
+ }
+ if( i == cmYes )
+ {
+ lock();
+ insertText( replaceStr, strlen(replaceStr), False);
+ trackCursor(False);
+ unlock();
+ }
+ }
+ } while( i != cmCancel && (editorFlags & efReplaceAll) != 0 );
+}
+
+void TEditor::doUpdate()
+{
+ if( updateFlags != 0 )
+ {
+ setCursor(curPos.x - delta.x, curPos.y - delta.y);
+ if( (updateFlags & ufView) != 0 )
+ drawView();
+ else
+ if( (updateFlags & ufLine) != 0 )
+ drawLines( curPos.y-delta.y, 1, lineStart(curPtr) );
+ if( hScrollBar != 0 )
+ hScrollBar->setParams(delta.x, 0, limit.x - size.x, size.x / 2, 1);
+ if( vScrollBar != 0 )
+ vScrollBar->setParams(delta.y, 0, limit.y - size.y, size.y - 1, 1);
+ if( indicator != 0 )
+ indicator->setValue(curPos, modified);
+ if( (state & sfActive) != 0 )
+ updateCommands();
+ updateFlags = 0;
+ }
+}
+
+void TEditor::draw()
+{
+ if( drawLine != delta.y )
+ {
+ drawPtr = lineMove( drawPtr, delta.y - drawLine );
+ drawLine = delta.y;
+ }
+ drawLines( 0, size.y, drawPtr );
+}
+
+/*Added again as a such a plug for backward compatibility with an old
+application*/
+#ifdef __RUSSIAN_LETTERS
+static unsigned KoiTable[128] =
+{
+ 192, 193, 194, 195, 196, 197, 198, 199, /* 0x80 - 0x87 */
+ 200, 201, 202, 203, 204, 205 ,206, 207, /* 0x88 - 0x8f */
+ 208, 209, 210, 211, 212, 213, 214, 215, /* 0x90 - 0x97 */
+ 216, 217, 218, 219, 220, 221, 222, 223, /* 0x98 - 0x9f */
+ 240, 241, 242, 243, 244, 245, 246, 247, /* 0xa0 - 0xa7 */
+ 248, 249, 250, 251, 252, 253, 254, 255, /* 0xa8 - 0xaf */
+ 176, 177, 178, 179, 180, 181, 182, 183, /* 0xb0 - 0xb7 */
+ 184, 185, 186, 187, 188, 189, 190, 191, /* 0xb8 - 0xbf */
+ 238, 160, 161, 230, 164, 165, 228, 163, /* 0xc0 - 0xc7 */
+ 229, 168, 169, 170, 171, 172, 173, 174, /* 0xc8 - 0xcf */
+ 175, 239, 224, 225, 226, 227, 166, 162, /* 0xd0 - 0xd7 */
+ 236, 235, 167, 232, 237, 233, 231, 234, /* 0xd8 - 0xdf */
+ 158, 128, 129, 150, 132, 133, 148, 131, /* 0xe0 - 0xe7 */
+ 149, 136, 137, 138, 139, 140, 141, 142, /* 0xe8 - 0xef */
+ 143, 159, 144, 145, 146, 147, 134, 130, /* 0xf0 - 0xf7 */
+ 156, 155, 135, 152, 157, 153, 151, 154 /* 0xf8 - 0xff */
+};
+#endif
+
+void TEditor::drawLines( int y, uint count, uint linePtr )
+{
+ ushort color = getColor(0x0201);
+ while( count-- > 0 )
+ {
+ ushort b[maxLineLength * 4];
+ formatLine( b, linePtr, delta.x+size.x, color );
+
+/*Added again as a such a plug for backward compatibility with an old
+application*/
+#ifdef __RUSSIAN_LETTERS
+ ushort *p = &b[delta.x];
+ for (int i = delta.x; i < size.x; i++, p++ )
+ {
+ int code = *p & 0xff; /* character is in the low byte */
+
+ if (code > 0x7f) *p = (*p & 0xff00) | KoiTable[code - 0x80];
+ }
+#endif
+ writeBuf(0, y, size.x, 1, &b[delta.x]);
+ linePtr = nextLine(linePtr);
+ y++;
+ }
+}
+
+void TEditor::find()
+{
+ TFindDialogRec findRec( findStr, editorFlags );
+ if( editorDialog( edFind, &findRec ) != cmCancel )
+ {
+ strcpy( findStr, findRec.find );
+ editorFlags = findRec.options & ~efDoReplace;
+ doSearchReplace();
+ }
+}
+
+uint TEditor::getMousePtr( TPoint m )
+{
+ TPoint mouse = makeLocal( m );
+ mouse.x = max(0, min(mouse.x, size.x - 1));
+ mouse.y = max(0, min(mouse.y, size.y - 1));
+ return charPtr(lineMove(drawPtr, mouse.y + delta.y - drawLine),
+ mouse.x + delta.x);
+}
+
+TPalette& TEditor::getPalette() const
+{
+ static TPalette palette( cpEditor, sizeof( cpEditor )-1 );
+ return palette;
+}
+
+void TEditor::checkScrollBar( const TEvent& event,
+ TScrollBar *p,
+ int& d
+ )
+{
+ if( (event.message.infoPtr == p) && (p->value != d) )
+ {
+ d = p->value;
+ update( ufView );
+ }
+}
+
+void TEditor::handleEvent( TEvent& event )
+{
+ TView::handleEvent( event );
+
+ Boolean centerCursor = Boolean(!cursorVisible());
+ uchar selectMode = 0;
+
+ if( selecting == True ||
+ (event.what & evMouse && (event.mouse.controlKeyState & kbShift) != 0) ||
+ (event.what & evKeyboard && (event.keyDown.controlKeyState & kbShift ) != 0)
+ )
+ selectMode = smExtend;
+
+ convertEvent( event );
+
+ switch( event.what )
+ {
+
+ case evMouseDown:
+ if( event.mouse.eventFlags & meDoubleClick )
+ selectMode |= smDouble;
+
+ do {
+ lock();
+ if( event.what == evMouseAuto )
+ {
+ TPoint mouse = makeLocal( event.mouse.where );
+ TPoint d = delta;
+ if( mouse.x < 0 )
+ d.x--;
+ if( mouse.x >= size.x )
+ d.x++;
+ if( mouse.y < 0 )
+ d.y--;
+ if( mouse.y >= size.y )
+ d.y++;
+ scrollTo(d.x, d.y);
+ }
+ setCurPtr(getMousePtr(event.mouse.where), selectMode);
+ selectMode |= smExtend;
+ unlock();
+ } while( mouseEvent(event, evMouseMove + evMouseAuto) );
+ break;
+
+ case evKeyDown:
+ if( event.keyDown.charScan.charCode == 9 ||
+ ( event.keyDown.charScan.charCode >= 32 && event.keyDown.charScan.charCode < 255 ) )
+ {
+ lock();
+ if( overwrite == True && hasSelection() == False )
+ if( curPtr != lineEnd(curPtr) )
+ selEnd = nextChar(curPtr);
+ insertText( &event.keyDown.charScan.charCode, 1, False);
+ trackCursor(centerCursor);
+ unlock();
+ }
+ else
+ return;
+ break;
+
+ case evCommand:
+ switch( event.message.command )
+ {
+ case cmFind:
+ find();
+ break;
+ case cmReplace:
+ replace();
+ break;
+ case cmSearchAgain:
+ doSearchReplace();
+ break;
+ default:
+ lock();
+ switch( event.message.command )
+ {
+ case cmCut:
+ clipCut();
+ break;
+ case cmCopy:
+ clipCopy();
+ break;
+ case cmPaste:
+ clipPaste();
+ break;
+ case cmUndo:
+ undo();
+ break;
+ case cmClear:
+ deleteSelect();
+ break;
+ case cmCharLeft:
+ setCurPtr(prevChar(curPtr), selectMode);
+ break;
+ case cmCharRight:
+ setCurPtr(nextChar(curPtr), selectMode);
+ break;
+ case cmWordLeft:
+ setCurPtr(prevWord(curPtr), selectMode);
+ break;
+ case cmWordRight:
+ setCurPtr(nextWord(curPtr), selectMode);
+ break;
+ case cmLineStart:
+ setCurPtr(lineStart(curPtr), selectMode);
+ break;
+ case cmLineEnd:
+ setCurPtr(lineEnd(curPtr), selectMode);
+ break;
+ case cmLineUp:
+ setCurPtr(lineMove(curPtr, -1), selectMode);
+ break;
+ case cmLineDown:
+ setCurPtr(lineMove(curPtr, 1), selectMode);
+ break;
+ case cmPageUp:
+ setCurPtr(lineMove(curPtr, -(size.y-1)), selectMode);
+ break;
+ case cmPageDown:
+ setCurPtr(lineMove(curPtr, size.y-1), selectMode);
+ break;
+ case cmTextStart:
+ setCurPtr(0, selectMode);
+ break;
+ case cmTextEnd:
+ setCurPtr(bufLen, selectMode);
+ break;
+ case cmNewLine:
+ newLine();
+ break;
+ case cmBackSpace:
+ deleteRange(prevChar(curPtr), curPtr, True);
+ break;
+ case cmDelChar:
+ deleteRange(curPtr, nextChar(curPtr), True);
+ break;
+ case cmDelWord:
+ deleteRange(curPtr, nextWord(curPtr), False);
+ break;
+ case cmDelStart:
+ deleteRange(lineStart(curPtr), curPtr, False);
+ break;
+ case cmDelEnd:
+ deleteRange(curPtr, lineEnd(curPtr), False);
+ break;
+ case cmDelLine:
+ deleteRange(lineStart(curPtr), nextLine(curPtr), False);
+ break;
+ case cmInsMode:
+ toggleInsMode();
+ break;
+ case cmStartSelect:
+ startSelect();
+ break;
+ case cmHideSelect:
+ hideSelect();
+ break;
+ case cmIndentMode:
+ autoIndent = Boolean(!autoIndent);
+ break;
+ default:
+ unlock();
+ return;
+ }
+ trackCursor(centerCursor);
+ unlock();
+ break;
+ }
+#ifndef __UNPATCHED
+ break;
+#endif
+ case evBroadcast:
+ switch( event.message.command )
+ {
+ case cmScrollBarChanged:
+ if ((event.message.infoPtr == hScrollBar) ||
+ (event.message.infoPtr == vScrollBar))
+ {
+ checkScrollBar( event, hScrollBar, delta.x );
+ checkScrollBar( event, vScrollBar, delta.y );
+ }
+ else
+ return;
+ break;
+ default:
+ return;
+ }
+ }
+ clearEvent(event);
+}
+
+Boolean TEditor::hasSelection()
+{
+ return Boolean(selStart != selEnd);
+}
+
+void TEditor::hideSelect()
+{
+ selecting = False;
+ setSelect(curPtr, curPtr, False);
+}
+
+void TEditor::initBuffer()
+{
+ buffer = new char[bufSize];
+}
+
+Boolean TEditor::insertBuffer( char *p,
+ uint offset,
+ uint length,
+ Boolean allowUndo,
+ Boolean selectText
+ )
+{
+ selecting = False;
+ uint selLen = selEnd - selStart;
+ if( selLen == 0 && length == 0 )
+ return True;
+
+ uint delLen = 0;
+ if( allowUndo == True )
+ if( curPtr == selStart )
+ delLen = selLen;
+ else
+ if( selLen > insCount )
+ delLen = selLen - insCount;
+
+ uint newSize = uint(bufLen + delCount - selLen + delLen) + length;
+
+ if( newSize > bufLen + delCount && setBufSize(newSize) == False )
+ {
+ editorDialog( edOutOfMemory );
+ selEnd = selStart;
+ return False;
+ }
+
+ uint selLines = countLines( &buffer[bufPtr(selStart)], selLen );
+ if( curPtr == selEnd )
+ {
+ if( allowUndo == True )
+ {
+ if( delLen > 0 )
+ memmove(
+ &buffer[curPtr + gapLen - delCount - delLen],
+ &buffer[selStart],
+ delLen
+ );
+ insCount -= selLen - delLen;
+ }
+ curPtr = selStart;
+ curPos.y -= selLines;
+ }
+ if( delta.y > curPos.y )
+ {
+ delta.y -= selLines;
+ if( delta.y < curPos.y )
+ delta.y = curPos.y;
+ }
+
+ if( length > 0 )
+ memmove(
+ &buffer[curPtr],
+ &p[offset],
+ length
+ );
+
+ uint lines = countLines( &buffer[curPtr], length );
+ curPtr += length;
+ curPos.y += lines;
+ drawLine = curPos.y;
+ drawPtr = lineStart(curPtr);
+ curPos.x = charPos(drawPtr, curPtr);
+ if( selectText == False )
+ selStart = curPtr;
+ selEnd = curPtr;
+ bufLen += length - selLen;
+ gapLen -= length - selLen;
+ if( allowUndo == True )
+ {
+ delCount += delLen;
+ insCount += length;
+ }
+ limit.y += lines - selLines;
+ delta.y = max(0, min(delta.y, limit.y - size.y));
+ if( isClipboard() == False )
+ modified = True;
+ setBufSize(bufLen + delCount);
+ if( selLines == 0 && lines == 0 )
+ update(ufLine);
+ else
+ update(ufView);
+ return True;
+}
+
+Boolean TEditor::insertFrom( TEditor *editor )
+{
+ uint pt = editor->bufPtr(editor->selStart);
+ return insertBuffer( editor->buffer,
+ pt,
+ editor->selEnd - editor->selStart,
+ canUndo,
+ isClipboard()
+ );
+}
+
+Boolean TEditor::insertText( const void *text, uint length,
+ Boolean selectText )
+{
+ return insertBuffer( (char *)text, 0, length, canUndo, selectText);
+}
+
+Boolean TEditor::isClipboard()
+{
+ return Boolean(clipboard == this);
+}
+
+uint TEditor::lineMove( uint p, int count )
+{
+ uint i = p;
+ p = lineStart(p);
+ uint pos = charPos(p, i);
+ while( count != 0 )
+ {
+ i = p;
+ if( count < 0 )
+ {
+ p = prevLine(p);
+ count++;
+ }
+ else
+ {
+ p = nextLine(p);
+ count--;
+ }
+ }
+ if( p != i )
+ p = charPtr(p, pos);
+ return p;
+}
+
+void TEditor::lock()
+{
+ lockCount++;
+}
+
+void TEditor::newLine()
+{
+ /* SS: changed */
+ const char nl[] = "\n";
+ uint p = lineStart(curPtr);
+ uint i = p;
+ while( i < curPtr &&
+ ( (buffer[i] == ' ') || (buffer[i] == '\x9'))
+ )
+ i++;
+ insertText(nl, 1, False);
+ if( autoIndent == True )
+ insertText( &buffer[p], i - p, False);
+}
+
+uint TEditor::nextLine( uint p )
+{
+ return nextChar(lineEnd(p));
+}
+
+uint TEditor::nextWord( uint p )
+{
+ while( p < bufLen && isWordChar(bufChar(p)) != 0 )
+ p = nextChar(p);
+ while( p < bufLen && isWordChar(bufChar(p)) == 0 )
+ p = nextChar(p);
+ return p;
+}
+
+uint TEditor::prevLine( uint p )
+{
+ return lineStart(prevChar(p));
+}
+
+uint TEditor::prevWord( uint p )
+{
+ while( p > 0 && isWordChar(bufChar(prevChar(p))) == 0 )
+ p = prevChar(p);
+ while( p > 0 && isWordChar(bufChar(prevChar(p))) != 0 )
+ p = prevChar(p);
+ return p;
+}
+
+void TEditor::replace()
+{
+ TReplaceDialogRec replaceRec( findStr, replaceStr, editorFlags );
+ if( editorDialog( edReplace, &replaceRec ) != cmCancel )
+ {
+ strcpy( findStr, replaceRec.find );
+ strcpy( replaceStr, replaceRec.replace );
+ editorFlags = replaceRec.options | efDoReplace;
+ doSearchReplace();
+ }
+
+}
+
+void TEditor::scrollTo( int x, int y )
+{
+ x = max(0, min(x, limit.x - size.x));
+ y = max(0, min(y, limit.y - size.y));
+ if( x != delta.x || y != delta.y )
+ {
+ delta.x = x;
+ delta.y = y;
+ update(ufView);
+ }
+}
+
+Boolean TEditor::search( const char *findStr, ushort opts )
+{
+ ulong pos = curPtr;
+ ulong i;
+ do {
+ if( (opts & efCaseSensitive) != 0 )
+ i = scan( &buffer[bufPtr(pos)], bufLen - pos, findStr);
+ else
+ i = iScan( &buffer[bufPtr(pos)], bufLen - pos, findStr);
+
+ if( i != sfSearchFailed )
+ {
+ i += pos;
+ if( (opts & efWholeWordsOnly) == 0 ||
+ !(
+ ( i != 0 && isWordChar(bufChar(i - 1)) != 0 ) ||
+ ( i + strlen(findStr) != bufLen &&
+ isWordChar(bufChar(i + strlen(findStr)))
+ )
+ ))
+ {
+ lock();
+ setSelect(i, i + strlen(findStr), False);
+ trackCursor(Boolean(!cursorVisible()));
+ unlock();
+ return True;
+ }
+ else
+ pos = i + 1;
+ }
+ } while( i != sfSearchFailed );
+ return False;
+}
+
+void TEditor::setBufLen( uint length )
+{
+ bufLen = length;
+ gapLen = bufSize - length;
+ selStart = 0;
+ selEnd = 0;
+ curPtr = 0;
+ delta.x = 0;
+ delta.y = 0;
+ curPos = delta;
+ limit.x = maxLineLength;
+ limit.y = countLines( &buffer[gapLen], bufLen ) + 1;
+ drawLine = 0;
+ drawPtr = 0;
+ delCount = 0;
+ insCount = 0;
+ modified = False;
+ update(ufView);
+}
+
+Boolean TEditor::setBufSize( uint newSize )
+{
+ return Boolean(newSize <= bufSize);
+}
+
+void TEditor::setCmdState( ushort command, Boolean enable )
+{
+ TCommandSet s;
+ s += command;
+ if( enable == True && (state & sfActive) != 0 )
+ enableCommands(s);
+ else
+ disableCommands(s);
+}
+
+void TEditor::setCurPtr( uint p, uchar selectMode )
+{
+ uint anchor;
+ if( (selectMode & smExtend) == 0 )
+ anchor = p;
+ else if( curPtr == selStart )
+ anchor = selEnd;
+ else
+ anchor = selStart;
+
+ if( p < anchor )
+ {
+ if( (selectMode & smDouble) != 0 )
+ {
+ p = prevLine(nextLine(p));
+ anchor = nextLine(prevLine(anchor));
+ }
+ setSelect(p, anchor, True);
+ }
+ else
+ {
+ if( (selectMode & smDouble) != 0 )
+ {
+ p = nextLine(p);
+ anchor = prevLine(nextLine(anchor));
+ }
+ setSelect(anchor, p, False);
+ }
+}
+
+void TEditor::setSelect( uint newStart, uint newEnd, Boolean curStart )
+{
+ uint p;
+ if( curStart != 0 )
+ p = newStart;
+ else
+ p = newEnd;
+
+ uchar flags = ufUpdate;
+
+ if( newStart != selStart || newEnd != selEnd )
+ if( newStart != newEnd || selStart != selEnd )
+ flags = ufView;
+
+ if( p != curPtr )
+ {
+ if( p > curPtr )
+ {
+ uint l = p - curPtr;
+ memmove( &buffer[curPtr], &buffer[curPtr + gapLen], l);
+ curPos.y += countLines(&buffer[curPtr], l);
+ curPtr = p;
+ }
+ else
+ {
+ uint l = curPtr - p;
+ curPtr = p;
+ curPos.y -= countLines(&buffer[curPtr], l);
+ memmove( &buffer[curPtr + gapLen], &buffer[curPtr], l);
+ }
+ drawLine = curPos.y;
+ drawPtr = lineStart(p);
+ curPos.x = charPos(drawPtr, p);
+ delCount = 0;
+ insCount = 0;
+ setBufSize(bufLen);
+ }
+ selStart = newStart;
+ selEnd = newEnd;
+ update(flags);
+}
+
+void TEditor::setState( ushort aState, Boolean enable )
+{
+ TView::setState(aState, enable);
+ switch( aState )
+ {
+ case sfActive:
+ if( hScrollBar != 0 )
+ hScrollBar->setState(sfVisible, enable);
+ if( vScrollBar != 0 )
+ vScrollBar->setState(sfVisible, enable);
+ if( indicator != 0 )
+ indicator->setState(sfVisible, enable);
+ updateCommands();
+ break;
+
+ case sfExposed:
+ if( enable == True )
+ unlock();
+ }
+}
+
+void TEditor::startSelect()
+{
+ hideSelect();
+ selecting = True;
+}
+
+void TEditor::toggleInsMode()
+{
+ overwrite = Boolean(!overwrite);
+ setState(sfCursorIns, Boolean(!getState(sfCursorIns)));
+}
+
+void TEditor::trackCursor( Boolean center )
+{
+ if( center == True )
+ scrollTo( curPos.x - size.x + 1, curPos.y - size.y / 2);
+ else
+ scrollTo( max(curPos.x - size.x + 1, min(delta.x, curPos.x)),
+ max(curPos.y - size.y + 1, min(delta.y, curPos.y)));
+}
+
+void TEditor::undo()
+{
+ if( delCount != 0 || insCount != 0 )
+ {
+ selStart = curPtr - insCount;
+ selEnd = curPtr;
+ ushort length = delCount;
+ delCount = 0;
+ insCount = 0;
+ insertBuffer(buffer, curPtr + gapLen - length, length, False, True);
+ }
+}
+
+void TEditor::unlock()
+{
+ if( lockCount > 0 )
+ {
+ lockCount--;
+ if( lockCount == 0 )
+ doUpdate();
+ }
+}
+
+void TEditor::update( uchar aFlags )
+{
+ updateFlags |= aFlags;
+ if( lockCount == 0 )
+ doUpdate();
+}
+
+void TEditor::updateCommands()
+{
+ setCmdState( cmUndo, Boolean( delCount != 0 || insCount != 0 ) );
+ if( isClipboard() == False )
+ {
+ setCmdState(cmCut, hasSelection());
+ setCmdState(cmCopy, hasSelection());
+ setCmdState(cmPaste,
+ Boolean(clipboard != 0 && (clipboard->hasSelection())) );
+ }
+ setCmdState(cmClear, hasSelection());
+ setCmdState(cmFind, True);
+ setCmdState(cmReplace, True);
+ setCmdState(cmSearchAgain, True);
+}
+
+Boolean TEditor::valid( ushort )
+{
+ return isValid;
+}
+
+#if !defined(NO_STREAMABLE)
+
+void TEditor::write( opstream& os )
+{
+ TView::write( os );
+ os << hScrollBar << vScrollBar << indicator
+ << bufSize << (int)canUndo;
+}
+
+void *TEditor::read( ipstream& is )
+{
+ TView::read( is );
+ int temp;
+ is >> hScrollBar >> vScrollBar >> indicator
+ >> bufSize >> temp;
+ canUndo = Boolean(temp);
+ selecting = False;
+ overwrite = False;
+ autoIndent = False;
+ lockCount = 0;
+ keyState = 0;
+ initBuffer();
+ if( buffer != 0 )
+ isValid = True;
+ else
+ {
+ TEditor::editorDialog( edOutOfMemory, 0 );
+ bufSize = 0;
+ }
+ lockCount = 0;
+ lock();
+ setBufLen( 0 );
+ return this;
+}
+
+TStreamable *TEditor::build()
+{
+ return new TEditor( streamableInit );
+}
+
+TEditor::TEditor( StreamableInit ) : TView( streamableInit )
+{
+}
+
+#endif