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.