This is VideoTextView.m in view mode; [Download] [Up]
/* (c) 1992 Dirk Schwarzhans, Matthias Braun
Use under the terms of the GNU General Public License */
#import "VideoTextView.h"
#import <appkit/color.h>
#import <appkit/nextstd.h>
#import <appkit/publicWraps.h>
#import <ctype.h>
#import <dpsclient/dpsNeXT.h>
#import <math.h>
#import <string.h>
#import "VTFontInit.h"
#import "VTFontProcs.h"
#import <appkit/Application.h>
static void flashHandler(DPSTimedEntry identification, double timeNow, void *data);
static int isVTalnum(int character, VTCharSet language);
@implementation VideoTextView
// **********************************************************
// Methoden die nicht von der Eltern-Klasse öbernommen werden
// **********************************************************
- initFrame:(const NXRect *)frameRect
{
int i;
[super initFrame:frameRect];
background = [[NXImage alloc] init];
foreground = [[NXImage alloc] init];
hiddenList = [[Storage alloc] initCount:10
elementSize:sizeof(CharSeq) description:@encode(CharSeq)];
flashingList = [[Storage alloc] initCount:10
elementSize:sizeof(CharSeq) description:@encode(CharSeq)];
for (i = 0; i < 128; i++)
{
convtab[i] = i;
}
convtab['@'] = '§'; convtab['['] = '…'; convtab['\\'] = '–'; convtab[']'] = 'š';
convtab['`'] = 'Ê'; convtab['{'] = 'Ù'; convtab['|'] = 'ö'; convtab['}'] = 'ö';
convtab['~'] = 'û'; convtab[0x7f] = '*';
dataValid = NO;
showHiddenText = NO;
allowFlashing = YES;
flashTimedEntry = (DPSTimedEntry)-1;
flashDelay = 0.75;
delegate = self;
selection.empty = YES;
searchOn2Click = YES;
pageRequested = NO;
[self setFontSize:24];
[self resetColorTab];
return self;
}
- free
{
if (flashTimedEntry != (DPSTimedEntry)-1)
DPSRemoveTimedEntry(flashTimedEntry);
[background free];
[foreground free];
[hiddenList free];
[flashingList free];
return [super free];
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
NXPoint point;
if (!dataValid)
{
PSsetgray(NX_WHITE);
NXRectFill(rects);
return self;
}
if (NXDrawingStatus != NX_DRAWING)
{
PSWVTFont1Init(); // der Drucker hat einen eigenen DSP-Kontext
PSWVTFont2Init();
PSWmakeVTFonts(fontSize);
[self generateImages:self :self hasAlpha:NO];
}
else
{
point.x = point.y = 0.0;
[background composite:NX_COPY toPoint:&point];
[foreground composite:NX_SOVER toPoint:&point];
[self drawSelection:&selection mode:YES];
if (!showHiddenText)
[self makeTextVisible:NO useList:hiddenList];
PSflushgraphics();
}
return self;
}
// ************************************************************
// Methoden zum Setzen und Abfragen der VideoTextView-Attribute
// ************************************************************
- (BOOL)acceptsFirstResponder
{
return YES;
}
- resetColorTab
{
colorTab[VT_BLACK] = NX_COLORBLACK;
colorTab[VT_RED] = NX_COLORRED;
colorTab[VT_GREEN] = NX_COLORGREEN;
colorTab[VT_YELLOW] = NX_COLORYELLOW;
colorTab[VT_BLUE] = NX_COLORBLUE;
colorTab[VT_MAGENTA] = NX_COLORMAGENTA;
colorTab[VT_CYAN] = NX_COLORCYAN;
colorTab[VT_WHITE] = NX_COLORWHITE;
[self generateImages:foreground :background hasAlpha:YES];
[self display];
return self;
}
- setColorTab:(NXColor *)newColors
{
int i;
for (i = 0; i < VT_COLORS; i++)
colorTab[i] = newColors[i];
[self generateImages:foreground :background hasAlpha:YES];
[self display];
return self;
}
- (const NXColor *)colorTab
{
return colorTab;
}
- setSearchOn2Click:(BOOL)mode
{
searchOn2Click = mode;
return self;
}
- (BOOL)searchOn2Click
{
return searchOn2Click;
}
- setFontSize:(float)points
{
NXRect rect;
fontSize = points;
// 0.9 = 900/1000 ist das VerhÙltnis der Grafikzeichenhöhe zu der in
// /FontMatrix angegebenen Einheit
lineHeight = fontSize * 0.9;
charWidth = fontSize * 0.6;
rect.origin.x = frame.origin.x;
rect.origin.y = frame.origin.y;
rect.size.width = floor(charWidth * COLUMNS);
rect.size.height = floor(lineHeight * ROWS);
[self setFrame:&rect];
[window sizeWindow:frame.size.width :frame.size.height];
// 0.15 = 150/1000 beginnen die Textzeichen öber der Basislinie der Zeile
line0_y = bounds.size.height - lineHeight + 0.15 * fontSize;
[background setSize:&(bounds.size)];
[foreground setSize:&(bounds.size)];
[self generateImages:foreground :background hasAlpha:YES];
return self;
}
- (float)fontSize
{
return fontSize;
}
- showHiddenText:(BOOL)mode
{
showHiddenText = mode;
[self lockFocus];
[self makeTextVisible:mode useList:hiddenList];
PSflushgraphics();
[self unlockFocus];
return self;
}
- (BOOL)textHidden
{
return showHiddenText;
}
- allowFlashing:(BOOL)mode
{
allowFlashing = mode;
if (mode == YES)
[self startFlashing];
else
[self stopFlashing];
return self;
}
- (BOOL)isFlashing
{
return allowFlashing;
}
- setDelegate:object
{
delegate = object;
return self;
}
- delegate
{
return delegate;
}
- (BOOL)hasSelection
{
return !selection.empty;
}
- setPageData:(const unsigned char *)newPage
{
int row, column;
const unsigned char *info;
VTChar current;
BOOL graphics;
BOOL holdGraphics;
BOOL separated;
unsigned char currentChar, lastChar;
pageRequested = NO;
selection.empty = YES;
[self stopFlashing];
[hiddenList empty];
[flashingList empty];
info = newPage + INFO_OFFSET;
for (row = 0; row < ROWS; row++)
{
// Werte för den Zeilenanfang
current.charColor = VT_WHITE;
current.bgndColor = VT_BLACK;
current.flashing = NO;
current.hidden = NO;
current.fontSize = NORMALSIZE;
current.font = TEXTFONT;
lastChar = ' ';
graphics = NO;
separated = NO;
holdGraphics = NO;
for (column = 0; column < COLUMNS; column++)
{
currentChar = VALIDBITS(newPage[row * COLUMNS + column]);
if (!ISCTRL(currentChar))
{
// Text oder Grafikzeichen
if (graphics && ISGRAPHICCHAR(currentChar))
{
current.charCode = currentChar;
if (separated)
current.font = SEPGRAPHFONT;
else
current.font = CONGRAPHFONT;
}
else
{
current.charCode = convtab[currentChar];
current.font = TEXTFONT;
}
}
else
{
// sofort wirkende Steuerzeichen
switch((VTCtrl)currentChar)
{
case BLACKBGND:
current.bgndColor = VT_BLACK;
break;
case NEWBGND:
current.bgndColor = current.charColor;
break;
case HOLDGRAPH:
holdGraphics = YES;
break;
case STEADY:
current.flashing = NO;
break;
case NORMAL:
current.fontSize = NORMALSIZE;
break;
case HIDE:
current.hidden = YES;
break;
default:
break;
}
if (holdGraphics && graphics && ISGRAPHICCHAR(lastChar))
current.charCode = lastChar;
else
current.charCode = ' ';
}
// Zuweisung der aktuellen Zeichendaten
decodedPage[row][column] = current;
// Auswertung von verzögert wirkenden Steuerzeichen
if (ISCTRL(currentChar))
{
switch((VTCtrl)currentChar)
{
case ALPHABLACK:
case ALPHARED:
case ALPHAGREEN:
case ALPHAYELLOW:
case ALPHABLUE:
case ALPHAMAGENTA:
case ALPHACYAN:
case ALPHAWHITE:
current.hidden = NO;
current.charColor = CTRL2COLOR(currentChar);
graphics = NO;
break;
case GRAPHBLACK:
case GRAPHRED:
case GRAPHGREEN:
case GRAPHYELLOW:
case GRAPHBLUE:
case GRAPHMAGENTA:
case GRAPHCYAN:
case GRAPHWHITE:
graphics = YES;
current.hidden = NO;
current.charColor = CTRL2COLOR(currentChar);
break;
case FLASH:
current.flashing = YES;
break;
case DOUBLE:
if (row != 23)
current.fontSize = DOUBLESIZE;
break;
case CONGRAPH:
separated = NO;
break;
case SEPGRAPH:
separated = YES;
break;
case RELEASEGRAPH:
holdGraphics = NO;
break;
default:
break;
}
}
lastChar = current.charCode;
} // endfor: column
} // endfor: row
// Bereinigung der Nachfolgezeile einer doppelt hohen Zeile
// d.h. Text ist immer ' '
// Hintergrundfarbe an jeder Position, wie eine Zeile höher
for (row = 1; row < ROWS; row++)
{
doubleTab[row] = doubleTab[row - 1] = 0;
for (column = 0; column < COLUMNS; column++)
if (decodedPage[row - 1][column].fontSize == DOUBLESIZE)
{
doubleTab[row] = 2;
doubleTab[row - 1] = 1;
break;
}
if (doubleTab[row])
{
for (column = 0; column < COLUMNS; column++)
{
decodedPage[row][column].bgndColor =
decodedPage[row - 1][column].bgndColor;
decodedPage[row][column].charCode = ' ';
}
row++;
}
}
// Einfögen der Text-Break-Informationen, die angeben, daû sich best. Modi
// im Vergleich zum vorhergehenden Zeichen verÙndert haben
// und Anlegen von Listen mit versteckten und blinkenden Text-Bereichen
{
BOOL lastFlash, lastHide;
CharSeq hideSeq, flashSeq;
for (row = 0; row < ROWS; row++)
{
decodedPage[row][0].textBreak = NO;
// Text-Break-Informationen erzeugen
for (column = 1; column < COLUMNS; column++)
{
if (decodedPage[row][column].charColor !=
decodedPage[row][column - 1].charColor ||
decodedPage[row][column].font !=
decodedPage[row][column - 1].font ||
decodedPage[row][column].fontSize !=
decodedPage[row][column - 1].fontSize)
decodedPage[row][column].textBreak = YES;
else
decodedPage[row][column].textBreak = NO;
}
// Flash- und Hidden-Listen anlegen
lastFlash = lastHide = NO;
for (column = 0; column < COLUMNS; column++)
{
if (lastFlash != decodedPage[row][column].flashing ||
column == COLUMNS - 1)
{
if (lastFlash)
{
flashSeq.empty = NO;
flashSeq.end.row = row;
flashSeq.end.column =
((column == COLUMNS - 1) ? COLUMNS : column);
[flashingList addElement:&flashSeq];
}
else
{
flashSeq.start.row = row;
flashSeq.start.column = column;
}
}
if (lastHide != decodedPage[row][column].hidden ||
column == COLUMNS - 1)
{
if (lastHide)
{
hideSeq.empty = NO;
hideSeq.end.row = row;
hideSeq.end.column =
((column == COLUMNS - 1) ? COLUMNS : column);
[hiddenList addElement:&hideSeq];
}
else
{
hideSeq.start.row = row;
hideSeq.start.column = column;
}
}
lastFlash = decodedPage[row][column].flashing;
lastHide = decodedPage[row][column].hidden;
} // endfor column
} // endfor row
} // Ende lokale Variablen
// Auswerten der Status-Informationen der Seite
language = (info[7] & 0xE) >> 1;
dataValid = YES;
[self generateImages:foreground :background hasAlpha:YES];
[self display];
[self startFlashing];
return self;
}
// *****************************************************
// interne Methoden zum Zeichnen und VerÙndern des Views
// *****************************************************
- generateImages:foregroundFocus :backgroundFocus hasAlpha:(BOOL)alphaMode
{
int row, column; // momentane Zeile, Spalte
VTChar *startChar; // mit gleichartigen Zeichen
char buffer[COLUMNS + 1]; // Speicher för max. eine Textzeile
int index; // Laufindex för 'buffer'
if (!dataValid)
return self;
PSWmakeVTFonts(fontSize);
// Hintergrund erzeugen
[backgroundFocus lockFocus];
PSsetgray(NX_WHITE);
PSsetalpha(1.0);
NXRectFill(&bounds);
for (row = 0; row < ROWS; row++)
{
PSWsetVTFont(CONGRAPHFONT);
PSmoveto(0.0, line0_y - row * lineHeight);
column = 0;
index = 0;
startChar = &(decodedPage[row][column]);
while (++column <= COLUMNS)
{
if (decodedPage[row][column].bgndColor != startChar->bgndColor
|| column == COLUMNS)
{
buffer[0] = 0x7f;;
buffer[++index] = 0;
NXSetColor(colorTab[startChar->bgndColor]);
PSshow(buffer);
if (column != COLUMNS)
{
index = 0;
startChar = &(decodedPage[row][column]);
}
}
else
buffer[++index] = 0x7f;
}
}
[backgroundFocus unlockFocus];
// Text und Grafik ausgeben
[foregroundFocus lockFocus];
if (alphaMode)
{
PSsetgray(NX_WHITE);
PSsetalpha(0.0);
NXRectFill(&bounds);
PSsetalpha(1.0);
}
for (row = 0; row < ROWS; row++)
{
PSmoveto(0.0, line0_y - row * lineHeight);
column = 0;
index = 0;
startChar = &(decodedPage[row][column]);
while (++column <= COLUMNS)
{
if (decodedPage[row][column].textBreak || column == COLUMNS)
{
buffer[0] = startChar->charCode;
buffer[++index] = 0;
NXSetColor(colorTab[startChar->charColor]);
if (startChar->fontSize == DOUBLESIZE)
{
PSrmoveto(0.0, -(lineHeight- 0.15 * fontSize));
PSWsetVTFontDouble(startChar->font);
PSshow(buffer);
PSrmoveto(0.0, (lineHeight - 0.15 * fontSize));
}
else
{
PSWsetVTFont(startChar->font);
PSshow(buffer);
}
if (column != COLUMNS)
{
index = 0;
startChar = &(decodedPage[row][column]);
}
}
else
buffer[++index] = decodedPage[row][column].charCode;
}
}
[foregroundFocus unlockFocus];
return self;
}
- makeTextVisible:(BOOL)mode useList:(Storage *)list
{
int i, count;
CharSeq *work;
NXRect rect;
count = [list count];
for (i = 0; i < count; i++)
{
work = [list elementAt:i];
rect.origin.x = work->start.column * charWidth;
rect.origin.y = [self bottomOfLine:work->start.row];
rect.size.width = (work->end.column - work->start.column) * charWidth;
rect.size.height = [self heightOfLine:work->start.row];
if (mode)
[foreground composite:NX_SOVER fromRect:&rect toPoint:&(rect.origin)];
else
[background composite:NX_COPY fromRect:&rect toPoint:&(rect.origin)];
}
return self;
}
- flashText
{
[self lockFocus];
switch(nextAction)
{
case FLASH_HIDE:
[self makeTextVisible:NO useList:flashingList];
nextAction = FLASH_SHOW;
break;
case FLASH_SHOW:
[self makeTextVisible:YES useList:flashingList];
nextAction = FLASH_HIDE;
break;
}
PSflushgraphics();
[self unlockFocus];
return self;
}
- startFlashing
{
if (flashTimedEntry == (DPSTimedEntry)-1 && [flashingList count] != 0 &&
allowFlashing == YES)
flashTimedEntry = DPSAddTimedEntry(flashDelay, flashHandler, self,
NX_BASETHRESHOLD);
nextAction = FLASH_HIDE;
return self;
}
- stopFlashing
{
if (flashTimedEntry != (DPSTimedEntry)-1)
{
DPSRemoveTimedEntry(flashTimedEntry);
flashTimedEntry = (DPSTimedEntry)-1;
if (nextAction == FLASH_SHOW)
[self flashText];
}
return self;
}
- drawSelection:(CharSeq *)sel mode:(BOOL)show
{
NXRect rects[3];
int rectCount;
int sCol, eCol;
if (sel->empty)
return self;
rectCount = 1;
if (sel->start.column < sel->end.column)
{
sCol = sel->start.column;
eCol = sel->end.column;
rects[0].origin.y = [self bottomOfLine:sel->end.row];
rects[0].size.height = [self topOfLine:sel->start.row] -
[self bottomOfLine:sel->end.row];
}
else
{
eCol = sel->start.column;
sCol = sel->end.column;
rects[0].origin.y = [self topOfLine:sel->end.row];
rects[0].size.height = [self bottomOfLine:sel->start.row] -
[self topOfLine:sel->end.row];
}
rects[0].origin.x = sCol * charWidth;
rects[0].size.width = (eCol - sCol) * charWidth;
// Start und Ende liegen in unterschiedlichen VideoText-Zeilen
if ([self topOfLine:sel->start.row] != [self topOfLine:sel->end.row])
{
rectCount = 3;
rects[1].origin.x = 0;
rects[1].origin.y = [self bottomOfLine:sel->end.row];
rects[1].size.width = sCol * charWidth;
rects[1].size.height = [self bottomOfLine:sel->start.row] -
[self bottomOfLine:sel->end.row];
rects[2].origin.x = eCol * charWidth;
rects[2].origin.y = [self topOfLine:sel->end.row];
rects[2].size.width = (COLUMNS - eCol) * charWidth;
rects[2].size.height = [self topOfLine:sel->start.row] -
[self topOfLine:sel->end.row];;
}
// ausgewÙhlten Bereich markieren bzw. Markierung löschen
PSsetgray(NX_LTGRAY);
while(rectCount--)
{
if (show)
NXRectFill(&rects[rectCount]);
else
[background composite:NX_COPY fromRect:&(rects[rectCount])
toPoint:&(rects[rectCount].origin)];
[foreground composite:NX_SOVER fromRect:&(rects[rectCount])
toPoint:&(rects[rectCount].origin)];
}
return self;
}
// *********************************************
// Methoden zum Verarbeiten von Maus-Ereignissen
// *********************************************
- mouseDown:(NXEvent *)event
{
Position currentPos;
int start, end, value;
int shift, alternate, control;
BOOL number;
[self stopFlashing];
currentPos.column = (int)floor((event->location.x) / charWidth);
currentPos.row = (int)floor(ROWS - (event->location.y) / lineHeight);
shift = (event->flags) & NX_SHIFTMASK;
alternate = (event->flags) & NX_ALTERNATEMASK;
control = (event->flags) & NX_CONTROLMASK;
[window addToEventMask:NX_LMOUSEDRAGGEDMASK];
[self lockFocus];
switch(clickCount = event->data.mouse.click)
{
case 1:
if (!alternate)
{
if (selection.empty == NO)
{
[self drawSelection:&selection mode:NO];
PSflushgraphics();
}
selection.empty = YES;
}
break;
case 2:
if (doubleTab[currentPos.row] == 2)
currentPos.row--;
if (decodedPage[currentPos.row][currentPos.column].font != TEXTFONT)
break;
if (isVTalnum(decodedPage[currentPos.row][currentPos.column].charCode, language))
{
start = currentPos.column;
while (start > 0 &&
isVTalnum(decodedPage[currentPos.row][start - 1].charCode, language) &&
decodedPage[currentPos.row][start - 1].font == TEXTFONT)
start--;
end = currentPos.column;
while (end < COLUMNS &&
isVTalnum(decodedPage[currentPos.row][end + 1].charCode, language) &&
decodedPage[currentPos.row][end + 1].font == TEXTFONT)
end++;
}
else
start = end = currentPos.column;
selection.empty = NO;
selection.appendCR = NO;
selection.start.row = selection.end.row = currentPos.row;
selection.start.column = start;
selection.end.column = end + 1;
[self drawSelection:&selection mode:YES];
PSflushgraphics();
// ggf. neue Seite suchen lassen
number = YES;
if ((shift && !searchOn2Click) || (!shift && searchOn2Click))
{
value = 0;
while (start <= end)
{
if (!isdigit(decodedPage[currentPos.row][start].charCode))
{
number = NO;
break;
}
value *= 10;
value += decodedPage[currentPos.row][start++].charCode - '0';
}
if (value >= 100 && value <= 899 && number)
{
if (control)
[delegate requestPage:value subpage:0 forWindow:nil];
else
[delegate requestPage:value subpage:0 forWindow:window];
pageRequested = YES;
}
}
break;
case 3:
selection.empty = NO;
selection.appendCR =YES;
selection.start.row = selection.end.row = currentPos.row;
selection.start.column = 0;
selection.end.column = COLUMNS;
[self drawSelection:&selection mode:YES];
PSflushgraphics();
break;
default:
return self;
break;
}
draggPos.row = currentPos.row;
draggPos.column = currentPos.column;
draggStart = selection.start;
[self unlockFocus];
return self;
}
- mouseUp:(NXEvent *)event;
{
[window removeFromEventMask:NX_LMOUSEDRAGGEDMASK];
if (selection.empty == NO && pageRequested == NO)
[delegate dontDisturb:YES];
else
[delegate dontDisturb:NO];
if (selection.empty == YES)
[self startFlashing];
return self;
}
- mouseDragged:(NXEvent *)event
{
Position currentPos;
CharSeq oldSelection;
BOOL flag;
if (clickCount != 1) // noch kein zeilen- bzw. wortweises Draggen möglich
return self;
[delegate dontDisturb:YES];
[self convertPoint:&(event->location) fromView:nil];
currentPos.column = (int)floor(((event->location.x) / charWidth));
currentPos.row = (int)floor((ROWS - (event->location.y) / lineHeight));
if (currentPos.row == draggPos.row && currentPos.column == draggPos.column &&
!selection.empty)
return self;
draggPos = currentPos;
selection.appendCR = NO;
oldSelection = selection;
if (selection.empty)
{
selection.empty = NO;
draggStart = currentPos;
}
if (currentPos.column < 0)
{
currentPos.column = 0;
flag = YES;
}
else
flag = NO;
if (currentPos.column >= COLUMNS)
{
currentPos.column = COLUMNS;
selection.appendCR = YES;
}
if ([self rowCol2Offset:¤tPos] < [self rowCol2Offset:&draggStart])
{
selection.start = currentPos;
selection.end = draggStart;
}
else
{
selection.start = draggStart;
selection.end = currentPos;
}
if (currentPos.row < 0)
{
selection.start.row = 0;
selection.start.column = 0;
}
if (currentPos.row >= ROWS)
{
selection.end.row = ROWS - 1;
selection.end.column = COLUMNS;
selection.appendCR = YES;
}
if (selection.end.column < COLUMNS && selection.start.row == draggStart.row &&
selection.start.column == draggStart.column && !flag)
selection.end.column++;
if (doubleTab[selection.start.row] == 2)
selection.start.row--;
if (doubleTab[selection.end.row] == 2)
selection.end.row--;
[self lockFocus];
[self drawSelection:&oldSelection mode:NO];
[self drawSelection:&selection mode:YES];
PSflushgraphics();
[self unlockFocus];
return self;
}
// *****************************************************
// weitere Methoden, die wir als FirstResponder anbieten
// *****************************************************
- copy:sender
{
const char *types[] = {NXAsciiPboardType, NULL};
if (selection.empty)
return nil;
[self writeSelectionToPasteboard:[Pasteboard new] types:types];
return self;
}
- cut:sender
{
[self copy:sender];
NXBeep();
return self;
}
- paste:sender
{
NXBeep();
return self;
}
- validRequestorForSendType:(NXAtom)sendType andReturnType:(NXAtom)returnType
{
if (returnType == NULL && sendType == NXPostScriptPboardType)
return self;
if (returnType == NULL && sendType == NXAsciiPboardType && !selection.empty)
return self;
return nil;
}
- (BOOL)writeSelectionToPasteboard:pasteboard types:(NXAtom *)types
{
NXStream *stream;
char *data;
int maxLength, length, row, column;
BOOL success;
success = NO;
do
{
if (*types == NXAsciiPboardType && !selection.empty)
{
[pasteboard declareTypes:&NXAsciiPboardType num:1 owner:self];
stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
row = selection.start.row;
column = selection.start.column;
do
{
if (decodedPage[row][column].font == TEXTFONT)
NXPutc(stream, decodedPage[row][column].charCode);
else
NXPutc(stream,' ');
if (++column >= COLUMNS)
{
if (row != selection.end.row || selection.appendCR)
NXPutc(stream, '\n');
row++;
column = 0;
}
}while (row < selection.end.row ||
(column < selection.end.column && row == selection.end.row));
NXGetMemoryBuffer(stream, &data, &length, &maxLength);
[pasteboard writeType:NXAsciiPboardType data:data length:length];
NXCloseMemory(stream, NX_FREEBUFFER);
success = YES;
}
if (*types == NXPostScriptPboardType)
{
[pasteboard declareTypes:&NXPostScriptPboard num:1 owner:self];
stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
[self copyPSCodeInside:&frame to:stream];
NXGetMemoryBuffer(stream, &data, &length, &maxLength);
[pasteboard writeType:NXPostScriptPboard data:data length:length];
NXCloseMemory(stream, NX_FREEBUFFER);
success = YES;
}
}while(*(++types) != NULL && !success);
return success;
}
- selectAll:sender
{
selection.empty = NO;
selection.appendCR = YES;
selection.start.row = selection.start.column = 0;
selection.end.row = ROWS - 1;
selection.end.column = COLUMNS;
[self lockFocus];
[self drawSelection:&selection mode:YES];
PSflushgraphics();
[self unlockFocus];
return self;
}
- clearSelection
{
if (selection.empty == YES)
return self;
[self lockFocus];
[self drawSelection:&selection mode:NO];
PSflushgraphics();
[self unlockFocus];
selection.empty = YES;
return self;
}
// ****************************************************
// interne Methoden zum berechnen von Zeichenpositionen
// ****************************************************
- (float)bottomOfLine:(int)row
{
if (doubleTab[row] == 1)
row++;
return bounds.size.height - lineHeight * (row + 1);
}
- (float)topOfLine:(int)row
{
if (doubleTab[row] == 2)
row--;
return bounds.size.height - lineHeight * row;
}
- (float)heightOfLine:(int)row
{
return [self topOfLine:row] - [self bottomOfLine:row];
}
- (int)rowCol2Offset:(Position *)pos
{
if (doubleTab[pos->row] == 2)
return pos->column + (pos->row - 1)* COLUMNS;
else
return pos->column + pos->row * COLUMNS;
}
// **********************************************************
// Dummy-Methoden för den Fall, daû kein delegate bekannt ist
// **********************************************************
- requestPage:(int)page subpage:(int)subpage forWindow:(Window *)window
{ return self; }
- dontDisturb:(BOOL)mode
{ return self; }
@end
// Wird durch einen 'timed entry' aufgerufen und erzeugt einen Objective-C Aufruf
static void flashHandler(DPSTimedEntry identification, double timeNow, void *data)
{
[(VideoTextView *)data flashText];
}
// erweiterte Routine, die auch Umlaute in Video-Text-Kodierung erkennt
// vorlÙufig nur för den deutschen Zeichensatz
static int isVTalnum(int character, VTCharSet language)
{
if (isalnum(character))
return YES;
if (language != GERMAN)
return NO;
switch(character)
{
case 0xD9: // Ù
case 0xF0: // ö
case 0xF6: // ö
case 0x85: // …
case 0x96: // –
case 0x9A: // š
case 0xFB: // û
return YES;
default:
return NO;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.