/* $Id: tek.c,v 1.5 2009/12/01 14:49:51 rice Exp $ PLplot tektronix device & emulators driver. */ #include "plDevs.h" #if defined(PLD_xterm) || /* xterm */ \ defined(PLD_tek4010) || /* TEK 4010 */ \ defined(PLD_tek4010f) || /* ditto, file */ \ defined(PLD_tek4107) || /* TEK 4107 */ \ defined(PLD_tek4107f) || /* ditto, file */ \ defined(PLD_mskermit) || /* MS-kermit emulator */ \ defined(PLD_versaterm) || /* Versaterm emulator */ \ defined(PLD_vlt) || /* VLT emulator */ \ defined(PLD_conex) /* conex emulator 4010/4014/4105 */ #define NEED_PLDEBUG #include "plplotP.h" #include "drivers.h" #include "plevent.h" #include /* Device info */ const char* plD_DEVICE_INFO_tek = #if defined(PLD_conex) "conex:Conex vt320/tek emulator:1:tek:24:conex\n" #endif #if defined(PLD_mskermit) "mskermit:MS-Kermit emulator:1:tek:21:mskermit\n" #endif #if defined(PLD_tek4107t) "tek4107t:Tektronix Terminal (4105/4107):1:tek:20:tek4107t\n" #endif #if defined(PLD_tek4107f) "tek4107f:Tektronix File (4105/4107):0:tek:28:tek4107f\n" #endif #if defined(PLD_tekt) "tekt:Tektronix Terminal (4010):1:tek:19:tekt\n" #endif #if defined(PLD_tekf) "tekf:Tektronix File (4010):0:tek:27:tekf\n" #endif #if defined(PLD_versaterm) "versaterm:Versaterm vt100/tek emulator:1:tek:22:versaterm\n" #endif #if defined(PLD_vlt) "vlt:VLT vt100/tek emulator:1:tek:23:vlt\n" #endif #if defined(PLD_xterm) "xterm:Xterm Window:1:tek:18:xterm" #endif ; /* Prototype the driver entry points that will be used to initialize the dispatch table entries. */ void plD_init_xterm (PLStream *); void plD_init_tekt (PLStream *); void plD_init_tekf (PLStream *); void plD_init_tek4107t (PLStream *); void plD_init_tek4107f (PLStream *); void plD_init_mskermit (PLStream *); void plD_init_versaterm (PLStream *); void plD_init_vlt (PLStream *); void plD_init_conex (PLStream *); /* External generic entry points */ void plD_line_tek (PLStream *, short, short, short, short); void plD_polyline_tek (PLStream *, short *, short *, PLINT); void plD_eop_tek (PLStream *); void plD_bop_tek (PLStream *); void plD_tidy_tek (PLStream *); void plD_state_tek (PLStream *, PLINT); void plD_esc_tek (PLStream *, PLINT, void *); /* Static function prototypes */ static void WaitForPage (PLStream *pls); static void tek_init (PLStream *pls); static void tek_text (PLStream *pls); static void tek_graph (PLStream *pls); static void fill_polygon (PLStream *pls); static void GetCursor (PLStream *pls, PLGraphicsIn *ptr); static void encode_int (char *c, int i); static void encode_vector (char *c, int x, int y); static void decode_gin (char *c, PLGraphicsIn *gin); static void tek_vector (PLStream *pls, int x, int y); static void scolor (PLStream *pls, int icol, int r, int g, int b); static void setcmap (PLStream *pls); static void LookupEvent (PLStream *pls); static void InputEH (PLStream *pls); static void LocateEH (PLStream *pls); /* Stuff for handling tty cbreak mode */ #ifdef HAVE_TERMIOS_H #include #include static struct termios termios_cbreak, termios_reset; static enum { RESET, CBREAK } ttystate = RESET; static void tty_setup (void); static int tty_cbreak (void); static int tty_reset (void); static void tty_atexit (void); #else static void tty_setup (void) {} static int tty_cbreak (void) {return 0;} static int tty_reset (void) {return 0;} static void tty_atexit (void) {} #endif /* Pixel settings */ #define TEKX 1023 #define TEKY 779 /* Graphics control characters. */ #define RING_BELL "\007" /* ^G = 7 */ #define CLEAR_VIEW "\033\f" /* clear the view = ESC FF */ #define ALPHA_MODE "\037" /* Enter Alpha mode: US */ #define VECTOR_MODE "\035" /* Enter Vector mode: GS */ #define GIN_MODE "\033\032" /* Enter GIN mode: ESC SUB */ #define BYPASS_MODE "\033\030" /* Enter Bypass mode: ESC CAN */ #define XTERM_VTMODE "\033\003" /* End xterm-Tek mode: ESC ETX */ #define CANCEL "\033KC" /* Cancel */ /* Static vars */ enum {tek4010, tek4105, tek4107, xterm, mskermit, vlt, versaterm}; /* One of these holds the tek driver state information */ typedef struct { PLINT xold, yold; /* Coordinates of last point plotted */ int exit_eventloop; /* Break out of event loop */ int locate_mode; /* Set while in locate (pick) mode */ int curcolor; /* Current color index */ PLGraphicsIn gin; /* Graphics input structure */ } TekDev; /* color for MS-DOS Kermit v2.31 (and up) tektronix emulator * 0 = normal, 1 = bright * foreground color (30-37) = 30 + colors * where colors are 1=red, 2=green, 4=blue */ #ifdef PLD_mskermit static const char *kermit_color[15]= { "0;30","0;37", "0;32","0;36","0;31","0;35", "1;34","1;33","1;31","1;37", "1;35","1;32","1;36","0;34", "0;33"}; #endif static void tek_dispatch_init_helper( PLDispatchTable *pdt, const char *menustr, const char *devnam, int type, int seq, plD_init_fp init ) { #ifndef ENABLE_DYNDRIVERS pdt->pl_MenuStr = menustr; pdt->pl_DevName = devnam; #endif pdt->pl_type = type; pdt->pl_seq = seq; pdt->pl_init = init; pdt->pl_line = (plD_line_fp) plD_line_tek; pdt->pl_polyline = (plD_polyline_fp) plD_polyline_tek; pdt->pl_eop = (plD_eop_fp) plD_eop_tek; pdt->pl_bop = (plD_bop_fp) plD_bop_tek; pdt->pl_tidy = (plD_tidy_fp) plD_tidy_tek; pdt->pl_state = (plD_state_fp) plD_state_tek; pdt->pl_esc = (plD_esc_fp) plD_esc_tek; } void plD_dispatch_init_xterm ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Xterm Window", "xterm", plDevType_Interactive, 18, (plD_init_fp) plD_init_xterm ); } void plD_dispatch_init_tekt ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Tektronix Terminal (4010)", "tekt", plDevType_Interactive, 19, (plD_init_fp) plD_init_tekt ); } void plD_dispatch_init_tek4107t ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Tektronix Terminal (4105/4107)", "tek4107t", plDevType_Interactive, 20, (plD_init_fp) plD_init_tek4107t ); } void plD_dispatch_init_mskermit ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "MS-Kermit emulator", "mskermit", plDevType_Interactive, 21, (plD_init_fp) plD_init_mskermit ); } void plD_dispatch_init_versaterm( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Versaterm vt100/tek emulator", "versaterm", plDevType_Interactive, 22, (plD_init_fp) plD_init_versaterm ); } void plD_dispatch_init_vlt ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "VLT vt100/tek emulator", "vlt", plDevType_Interactive, 23, (plD_init_fp) plD_init_vlt ); } void plD_dispatch_init_conex ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Conex vt320/tek emulator", "conex", plDevType_Interactive, 24, (plD_init_fp) plD_init_conex ); } void plD_dispatch_init_tekf ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Tektronix File (4010)", "tekf", plDevType_FileOriented, 27, (plD_init_fp) plD_init_tekf ); } void plD_dispatch_init_tek4107f ( PLDispatchTable *pdt ) { tek_dispatch_init_helper( pdt, "Tektronix File (4105/4107)", "tek4107f", plDevType_FileOriented, 28, (plD_init_fp) plD_init_tek4107f ); } /*--------------------------------------------------------------------------*\ * plD_init_xterm() xterm * plD_init_tekt() Tek 4010 terminal * plD_init_tekf() Tek 4010 file * plD_init_tek4107t() Tek 4105/4107 terminal * plD_init_tek4107f() Tek 4105/4107 file * plD_init_mskermit() MS-Kermit emulator (DOS) * plD_init_vlt() VLT emulator (Amiga) * plD_init_versaterm() VersaTerm emulator (Mac) * plD_init_conex() Conex vt320/Tek 4105 emulator (DOS) * * These just set attributes for the particular tektronix device, then call * tek_init(). The following attributes can be set: * * pls->termin if a terminal device * pls->color if color (1), if only fixed colors (2) * pls->dev_fill0 if can handle solid area fill * pls->dev_fill1 if can handle pattern area fill \*--------------------------------------------------------------------------*/ void plD_init_xterm(PLStream *pls) { pls->dev_minor = xterm; pls->termin = 1; tek_init(pls); } void plD_init_tekt(PLStream *pls) { pls->termin = 1; plD_init_tekf(pls); } void plD_init_tekf(PLStream *pls) { pls->dev_minor = tek4010; tek_init(pls); } void plD_init_tek4107t(PLStream *pls) { pls->termin = 1; plD_init_tek4107f(pls); } void plD_init_tek4107f(PLStream *pls) { pls->dev_minor = tek4107; pls->color = 1; pls->dev_fill0 = 1; tek_init(pls); } void plD_init_mskermit(PLStream *pls) { pls->dev_minor = mskermit; pls->termin = 1; pls->color = 1; pls->dev_fill0 = 1; tek_init(pls); } void plD_init_vlt(PLStream *pls) { pls->dev_minor = vlt; pls->termin = 1; pls->color = 1; pls->dev_fill0 = 1; tek_init(pls); } void plD_init_versaterm(PLStream *pls) { pls->dev_minor = versaterm; pls->termin = 1; pls->color = 1; pls->dev_fill0 = 1; tek_init(pls); } void plD_init_conex(PLStream *pls) { pls->dev_minor = xterm; /* responds to xterm escape codes */ pls->termin = 1; pls->color = 2; /* only fixed colours */ tek_init(pls); } /*--------------------------------------------------------------------------*\ * tek_init() * * Generic tektronix device initialization. \*--------------------------------------------------------------------------*/ static void tek_init(PLStream *pls) { TekDev *dev; int xmin = 0; int xmax = TEKX; int ymin = 0; int ymax = TEKY; PLFLT pxlx = 4.771; PLFLT pxly = 4.653; pls->graphx = TEXT_MODE; /* Allocate and initialize device-specific data */ pls->dev = calloc(1, (size_t) sizeof(TekDev)); if (pls->dev == NULL) plexit("tek_init: Out of memory."); dev = (TekDev *) pls->dev; dev->curcolor = 1; dev->xold = PL_UNDEFINED; dev->yold = PL_UNDEFINED; plP_setpxl(pxlx, pxly); plP_setphy(xmin, xmax, ymin, ymax); /* Terminal/file initialization */ if (pls->termin) { pls->OutFile = stdout; tty_setup(); } else { plFamInit(pls); plOpenFile(pls); } switch (pls->dev_minor) { #ifdef PLD_tek4107 case tek4107: pls->graphx = GRAPHICS_MODE; fprintf(pls->OutFile, "\033%%!0"); /* set tek mode */ fprintf(pls->OutFile, "\033KN1"); /* clear the view */ fprintf(pls->OutFile, "\033LZ"); /* clear dialog buffer */ fprintf(pls->OutFile, "\033ML1"); /* set default color */ break; #endif /* PLD_tek4107 */ /* A sneaky hack: VLT sometimes has leftover panel information, causing * garbage at the beginning of a sequence of color fills. Since * there is no clear panel command, instead I set the fill color to the * same as background and issue an end panel command. */ #ifdef PLD_vlt case vlt:{ char fillcol[4]; tek_graph(pls); encode_int(fillcol, 0); fprintf(pls->OutFile, "\033MP%s\033LE", fillcol); break; } #endif /* PLD_vlt */ default: tek_graph(pls); } /* Initialize palette */ if ( pls->color & 0x01 ) { printf("\033TM111"); /* Switch to RGB colors */ setcmap(pls); } /* Finish initialization */ fprintf(pls->OutFile, VECTOR_MODE); /* Enter vector mode */ if (pls->termin) fprintf(pls->OutFile, CLEAR_VIEW);/* erase and home */ fflush(pls->OutFile); } /*--------------------------------------------------------------------------*\ * plD_line_tek() * * Draw a line from (x1,y1) to (x2,y2). \*--------------------------------------------------------------------------*/ void plD_line_tek(PLStream *pls, short xx1, short yy1, short xx2, short yy2) { TekDev *dev = (TekDev *) pls->dev; tek_graph(pls); /* If not continuation of previous line, begin a new one */ if (xx1 != dev->xold || yy1 != dev->yold) { pls->bytecnt += fprintf(pls->OutFile, VECTOR_MODE); tek_vector(pls, xx1, yy1); } /* Now send following point to complete line draw */ tek_vector(pls, xx2, yy2); dev->xold = xx2; dev->yold = yy2; } /*--------------------------------------------------------------------------*\ * plD_polyline_tek() * * Draw a polyline in the current color. \*--------------------------------------------------------------------------*/ void plD_polyline_tek(PLStream *pls, short *xa, short *ya, PLINT npts) { PLINT i; TekDev *dev = (TekDev *) pls->dev; short x = xa[0], y = ya[0]; tek_graph(pls); /* If not continuation of previous line, begin a new one */ if ( x != dev->xold || y != dev->yold ) { pls->bytecnt += fprintf(pls->OutFile, VECTOR_MODE); tek_vector(pls, x, y); } /* Now send following points to complete polyline draw */ for (i = 1; i < npts; i++) tek_vector(pls, xa[i], ya[i]); dev->xold = xa[npts-1]; dev->yold = ya[npts-1]; } /*--------------------------------------------------------------------------*\ * plD_eop_tek() * * End of page. User must hit a to continue (terminal output). \*--------------------------------------------------------------------------*/ void plD_eop_tek(PLStream *pls) { tek_graph(pls); if (pls->termin) { if ( ! pls->nopause) WaitForPage(pls); } fprintf(pls->OutFile, CLEAR_VIEW); /* erase and home */ } /*--------------------------------------------------------------------------*\ * plD_bop_tek() * * Set up for the next page. Advance to next family file if necessary * (file output). Devices that share graphics/alpha screens need a page * clear. \*--------------------------------------------------------------------------*/ void plD_bop_tek(PLStream *pls) { TekDev *dev = (TekDev *) pls->dev; dev->xold = PL_UNDEFINED; dev->yold = PL_UNDEFINED; if (pls->termin) { switch (pls->dev_minor) { case mskermit: fprintf(pls->OutFile, CLEAR_VIEW); /* erase and home */ break; } } else { plGetFam(pls); } pls->page++; /* Initialize palette */ if ( pls->color & 0x01 ) setcmap(pls); } /*--------------------------------------------------------------------------*\ * plD_tidy_tek() * * Close graphics file or otherwise clean up. \*--------------------------------------------------------------------------*/ void plD_tidy_tek(PLStream *pls) { if ( ! pls->termin) { fclose(pls->OutFile); } else { tek_text(pls); fflush(pls->OutFile); } } /*--------------------------------------------------------------------------*\ * tek_color() * * Change to specified color index. \*--------------------------------------------------------------------------*/ static void tek_color(PLStream *pls, int icol) { switch (pls->dev_minor) { #ifdef PLD_mskermit /* Is this really necessary? */ case mskermit: printf("\033[%sm", kermit_color[icol % 14] ); break; #endif default: pls->bytecnt += fprintf(pls->OutFile, "\033ML%c", icol + '0'); } } /*--------------------------------------------------------------------------*\ * plD_state_tek() * * Handle change in PLStream state (color, pen width, fill attribute, * etc). \*--------------------------------------------------------------------------*/ void plD_state_tek(PLStream *pls, PLINT op) { TekDev *dev = (TekDev *) pls->dev; switch (op) { case PLSTATE_WIDTH: break; case PLSTATE_COLOR0: if (pls->color) { int icol0 = pls->icol0; tek_graph(pls); if (icol0 != PL_RGB_COLOR) { dev->curcolor = icol0; tek_color(pls, icol0); } } break; case PLSTATE_COLOR1: if (pls->color) { int icol1, ncol1; tek_graph(pls); if ((ncol1 = MIN(16 - pls->ncol0, pls->ncol1)) < 1) break; icol1 = pls->ncol0 + (pls->icol1 * (ncol1-1)) / (pls->ncol1-1); dev->curcolor = icol1; tek_color(pls, icol1); } break; case PLSTATE_CMAP0: case PLSTATE_CMAP1: if ( pls->color & 0x01 ) setcmap(pls); break; } } /*--------------------------------------------------------------------------*\ * plD_esc_tek() * * Escape function. \*--------------------------------------------------------------------------*/ void plD_esc_tek(PLStream *pls, PLINT op, void *ptr) { switch (op) { case PLESC_TEXT: tek_text(pls); break; case PLESC_GRAPH: tek_graph(pls); break; case PLESC_FILL: fill_polygon(pls); break; case PLESC_GETC: GetCursor(pls, (PLGraphicsIn *) ptr); break; } } /*--------------------------------------------------------------------------*\ * GetCursor() * * Waits for a left button mouse event and returns coordinates. * xterm doesn't handle GIN. I think all the rest do. \*--------------------------------------------------------------------------*/ static void GetCursor(PLStream *pls, PLGraphicsIn *ptr) { #define MAX_GIN 10 char input_string[MAX_GIN]; int i = 0; plGinInit(ptr); if (pls->termin && pls->dev_minor != xterm) { tek_graph(pls); /* Enter GIN mode */ printf(GIN_MODE); fflush(stdout); /* Read & decode report */ while (++i < MAX_GIN && (input_string[i-1] = getchar()) != '\n') ; input_string[i-1] = '\0'; ptr->keysym = input_string[0]; decode_gin(&input_string[1], ptr); /* Switch out of GIN mode */ printf(VECTOR_MODE); } } /*--------------------------------------------------------------------------*\ * fill_polygon() * * Fill polygon described in points pls->dev_x[] and pls->dev_y[]. \*--------------------------------------------------------------------------*/ static void fill_polygon(PLStream *pls) { TekDev *dev = (TekDev *) pls->dev; int i; char fillcol[4], firstpoint[5]; if (pls->dev_npts < 1) return; tek_graph(pls); encode_int(fillcol, -dev->curcolor); encode_vector(firstpoint, pls->dev_x[0], pls->dev_y[0]); /* Select the fill pattern */ pls->bytecnt += fprintf(pls->OutFile, "\033MP%s", fillcol); /* Begin panel boundary */ /* Set pls->debug to see the boundary of each fill box -- cool! */ if (pls->debug) pls->bytecnt += fprintf(pls->OutFile, "\033LP%s1", firstpoint); else pls->bytecnt += fprintf(pls->OutFile, "\033LP%s0", firstpoint); /* Specify boundary (in vector mode) */ pls->bytecnt += fprintf(pls->OutFile, VECTOR_MODE); for (i = 1; i < pls->dev_npts; i++) tek_vector(pls, pls->dev_x[i], pls->dev_y[i]); /* End panel */ pls->bytecnt += fprintf(pls->OutFile, "\033LE"); } /*--------------------------------------------------------------------------*\ * tek_text() * * Switch to text screen (or alpha mode, for vanilla tek's). Restore * terminal to its original state, to better handle user input if * necessary. * * Note: xterm behaves strangely in the following circumstance: switch to * the text screen, print a string, and switch to the graphics screen, all * done in quick succession. The first character of the printed string * usually comes out blank -- but only apparently so, because if you force * a refresh of the screen in this area it will reappear. This is a * reproducible bug on the HP 720 under X11R5. If you insert a sleep(1) * after the switch to text screen or before the switch to graphics * screen, the string is printed correctly. I've been unable to find a * workaround for this problem (and I've tried, you can believe eet man). \*--------------------------------------------------------------------------*/ static void tek_text(PLStream *pls) { if (pls->termin && (pls->graphx == GRAPHICS_MODE)) { tty_reset(); pls->graphx = TEXT_MODE; switch (pls->dev_minor) { case xterm: printf("\033\003"); /* vt100 mode (xterm) = ESC ETX */ break; case mskermit: case vlt: printf("\033[?38l"); /* vt100 screen */ break; case versaterm: printf("\033%%!2"); /* vt100 screen */ break; case tek4107: printf("\033LV1"); /* set dialog visible */ printf("\033%%!1"); /* set ansi mode */ break; default: printf(ALPHA_MODE); /* enter alpha mode */ } fflush(stdout); } } /*--------------------------------------------------------------------------*\ * tek_graph() * * Switch to graphics screen. Also switch terminal to cbreak mode, to allow * single keystrokes to govern actions at end of page. \*--------------------------------------------------------------------------*/ static void tek_graph(PLStream *pls) { if (pls->termin && (pls->graphx == TEXT_MODE)) { tty_cbreak(); pls->graphx = GRAPHICS_MODE; switch (pls->dev_minor) { case xterm: case mskermit: case vlt: printf("\033[?38h"); /* switch to tek screen */ break; case versaterm: printf("\033%%!0"); /* switch to tek4107 screen */ break; case tek4107: printf("\033%%!0"); /* set tek mode */ printf(CLEAR_VIEW); /* clear screen */ printf("\033LV0"); /* set dialog invisible */ break; } } } /*--------------------------------------------------------------------------*\ * encode_int() * * Encodes a single int into standard tek integer format, storing into a * NULL-terminated character string (must be length 4 or greater). This * scheme does not work for negative integers less than 15. \*--------------------------------------------------------------------------*/ static void encode_int(char *c, int i) { int negative = 0; if (i > 0) { if (i & 0x7C00) /* are any of bits 10-14 set?*/ *c++ = ((i >> 10) & 0x1F) | 0x40; if (i & 0x03F0) /* are any of bits 4-9 set? */ *c++ = ((i >> 4) & 0x3F) | 0x40; } else { i = -i; negative = 1; } if (i & 0x000F) /* are any of bits 0-3 set? */ *c = (i & 0x0F) | 0x20; else /* if not, put in a space */ *c = 0x20; if ( ! negative) /* if positive, set sign bit */ *c |= 0x10; c++; *c = '\0'; /* NULL-terminate */ return; } /*--------------------------------------------------------------------------*\ * decode_gin() * * Decodes a GIN tek vector string into an xy pair of relative device * coordinates. It's best to not use absolute device coordinates since the * coordinate bounds are different depending on the report encoding used. * * Standard: * Extended: * * where holds the two low order bits for each coordinate. \*--------------------------------------------------------------------------*/ static void decode_gin(char *c, PLGraphicsIn *gin) { int x, y, lc = strlen(c); if (lc == 4) { x = ((c[0] & 0x1f) << 5) + ((c[1] & 0x1f) ); y = ((c[2] & 0x1f) << 5) + ((c[3] & 0x1f) ); gin->pX = x; gin->pY = y; gin->dX = x / (double) TEKX; gin->dY = y / (double) TEKY; } else if (lc == 5) { y = ((c[0] & 0x1f) << 7) + ((c[2] & 0x1f) << 2) + ((c[1] & 0x06) >> 2); x = ((c[3] & 0x1f) << 7) + ((c[4] & 0x1f) << 2) + ((c[1] & 0x03) ); gin->pX = x; gin->pY = y; gin->dX = x / (double) (TEKX << 2); gin->dY = y / (double) (TEKY << 2); } else { /* Illegal encoding */ gin->pX = 0; gin->pY = 0; gin->dY = 0; gin->dX = 0; } } /*--------------------------------------------------------------------------*\ * encode_vector() * * Encodes an xy vector (2 ints) into standard tek vector format, storing * into a NULL-terminated character string of length 5. Note that the y * coordinate always comes first. \*--------------------------------------------------------------------------*/ static void encode_vector(char *c, int x, int y) { c[0] = (y >> 5) + 0x20; /* hy */ c[1] = (y & 0x1f) + 0x60; /* ly */ c[2] = (x >> 5) + 0x20; /* hx */ c[3] = (x & 0x1f) + 0x40; /* lx */ c[4] = '\0'; /* NULL */ } /*--------------------------------------------------------------------------*\ * tek_vector() * * Issues a vector draw command, assuming we are in vector plot mode. XY * coordinates are encoded according to the standard xy encoding scheme. \*--------------------------------------------------------------------------*/ static void tek_vector(PLStream *pls, int x, int y) { char c[5]; encode_vector(c, x, y); pls->bytecnt += fprintf( pls->OutFile, "%s", c ); } /*--------------------------------------------------------------------------*\ * scolor() * * Sets a color by tek-encoded RGB values. Need to convert PLplot RGB * color range (0 to 255) to Tek RGB color range (0 to 100). \*--------------------------------------------------------------------------*/ static void scolor(PLStream *pls, int icol, int r, int g, int b) { char tek_col[4], tek_r[4], tek_g[4], tek_b[4]; encode_int(tek_col, icol); encode_int(tek_r, (100*r)/255); encode_int(tek_g, (100*g)/255); encode_int(tek_b, (100*b)/255); pls->bytecnt += fprintf(pls->OutFile, "\033TG14%s%s%s%s", tek_col, tek_r, tek_g, tek_b); } /*--------------------------------------------------------------------------*\ * setcmap() * * Sets up color palette. \*--------------------------------------------------------------------------*/ static void setcmap(PLStream *pls) { int i, ncol1 = MIN(16 - pls->ncol0, pls->ncol1); PLColor cmap1col; tek_graph(pls); /* Initialize cmap 0 colors */ for (i = 0; i < pls->ncol0; i++) scolor(pls, i, pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b); /* Initialize any remaining slots for cmap1 */ for (i = 0; i < ncol1; i++) { plcol_interp(pls, &cmap1col, i, ncol1); scolor(pls, i + pls->ncol0, cmap1col.r, cmap1col.g, cmap1col.b); } } /*--------------------------------------------------------------------------*\ * WaitForPage() * * This routine waits for the user to advance the plot, while handling * all other events. \*--------------------------------------------------------------------------*/ static void WaitForPage(PLStream *pls) { TekDev *dev = (TekDev *) pls->dev; printf(ALPHA_MODE); /* Switch to alpha mode (necessary) */ printf(RING_BELL); /* and ring bell */ printf(VECTOR_MODE); /* Switch out of alpha mode */ fflush(stdout); while ( ! dev->exit_eventloop) { LookupEvent(pls); if (dev->locate_mode) LocateEH(pls); else InputEH(pls); } dev->exit_eventloop = FALSE; } /*--------------------------------------------------------------------------*\ * LookupEvent() * * Fills in the PLGraphicsIn from an input event. \*--------------------------------------------------------------------------*/ static void LookupEvent(PLStream *pls) { TekDev *dev = (TekDev *) pls->dev; PLGraphicsIn *gin = &(dev->gin); if (dev->locate_mode) { GetCursor(pls, gin); } else { plGinInit(gin); gin->keysym = getchar(); } if (isprint(gin->keysym)) { gin->string[0] = gin->keysym; gin->string[1] = '\0'; } else { gin->string[0] = '\0'; } pldebug("LookupEvent", "Keycode %x, string: %s\n", gin->keysym, gin->string); } /*--------------------------------------------------------------------------*\ * LocateEH() * * Handles locate mode events. * * In locate mode: move cursor to desired location and select by pressing a * key or by clicking on the mouse (if available). Typically the world * coordinates of the selected point are reported. * * There are two ways to enter Locate mode -- via the API, or via a driver * command. The API entry point is the call plGetCursor(), which initiates * locate mode and does not return until input has been obtained. The * driver entry point is by entering a 'L' while the driver is waiting for * events. * * Locate mode input is reported in one of three ways: * 1. Through a returned PLGraphicsIn structure, when user has specified a * locate handler via (*pls->LocateEH). * 2. Through a returned PLGraphicsIn structure, when locate mode is invoked * by a plGetCursor() call. * 3. Through writes to stdout, when locate mode is invoked by a driver * command and the user has not supplied a locate handler. * * Hitting will at all times end locate mode. Other keys will * typically be interpreted as locator input. Selecting a point out of * bounds will end locate mode unless the user overrides with a supplied * Locate handler. \*--------------------------------------------------------------------------*/ static void LocateEH(PLStream *pls) { TekDev *dev = (TekDev *) pls->dev; PLGraphicsIn *gin = &(dev->gin); /* End locate mode on */ if (gin->keysym == PLK_Escape) { dev->locate_mode = 0; return; } /* Call user locate mode handler if provided */ if (pls->LocateEH != NULL) (*pls->LocateEH) (gin, pls->LocateEH_data, &dev->locate_mode); /* Use default procedure */ else { /* Try to locate cursor */ if (plTranslateCursor(gin)) { /* Successful, so send report to stdout */ pltext(); if (isprint(gin->keysym)) printf("%f %f %c\n", gin->wX, gin->wY, gin->keysym); else printf("%f %f\n", gin->wX, gin->wY); plgra(); } else { /* Selected point is out of bounds, so end locate mode */ dev->locate_mode = 0; } } } /*--------------------------------------------------------------------------*\ * InputEH() * * Event handler routine for xterm. Just reacts to keyboard input. * * In locate mode: move cursor to desired location and select by pressing a * key or by clicking on the mouse (if available). The world coordinates of * the selected point are output on the text screen. Terminate by picking a * point out of bounds, hitting page advance, or the escape key. If you * want to customize this, write an event handler to do it. \*--------------------------------------------------------------------------*/ static void InputEH(PLStream *pls) { TekDev *dev = (TekDev *) pls->dev; PLGraphicsIn *gin = &(dev->gin); /* Call user event handler. * Since this is called first, the user can disable all PLplot internal * event handling by setting gin->keysym to 0 and gin->string to '\0'. */ if (pls->KeyEH != NULL) (*pls->KeyEH) (gin, pls->KeyEH_data, &dev->exit_eventloop); /* Remaining internal event handling */ switch (gin->keysym) { case PLK_Linefeed: /* Advance to next page (i.e. terminate event loop) on a */ dev->exit_eventloop = TRUE; break; case 'Q': /* Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake) */ pls->nopause = TRUE; plexit(""); break; case 'L': /* Begin locate mode */ dev->locate_mode = 1; break; } } /*--------------------------------------------------------------------------*\ * tty cbreak-mode handlers * * Taken from "Advanced Programming in the UNIX(R) Environment", * by W. Richard Stevens. \*--------------------------------------------------------------------------*/ #ifdef HAVE_TERMIOS_H static void tty_setup(void) /* setup for terminal operations */ { if (tcgetattr(STDIN_FILENO, &termios_reset) < 0) { fprintf(stderr, "Unable to set up cbreak mode.\n"); return; } termios_cbreak = termios_reset; /* structure copy */ termios_cbreak.c_lflag &= ~(ICANON); /* canonical mode off */ termios_cbreak.c_cc[VMIN] = 1; /* 1 byte at a time */ termios_cbreak.c_cc[VTIME] = 0; /* no timer */ #ifdef STDC_HEADERS if (atexit(tty_atexit)) fprintf(stderr, "Unable to set up atexit handler.\n"); #endif return; } static int tty_cbreak(void) /* put terminal into a cbreak mode */ { if (ttystate != CBREAK) { if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_cbreak) < 0) return -1; ttystate = CBREAK; } return 0; } static int tty_reset(void) /* restore terminal's mode */ { if (ttystate != RESET) { if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_reset) < 0) return -1; ttystate = RESET; } return 0; } #ifdef STDC_HEADERS static void tty_atexit(void) /* exit handler */ { tty_reset(); } #endif /* STDC_HEADERS */ #endif /* HAVE_TERMIOS_H */ #else int pldummy_tek(void) {return 0;} #endif /* defined(PLD_xterm) || ... */