PLplot: tek.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
tek.c
Go to the documentation of this file.
1 // $Id: tek.c 11282 2010-10-28 16:26:09Z airwin $
2 //
3 // PLplot tektronix device & emulators driver.
4 //
5 #include "plDevs.h"
6
7 #if defined ( PLD_xterm ) || /* xterm */ \
8 defined ( PLD_tek4010 ) || /* TEK 4010 */ \
9 defined ( PLD_tek4010f ) || /* ditto, file */ \
10 defined ( PLD_tek4107 ) || /* TEK 4107 */ \
11 defined ( PLD_tek4107f ) || /* ditto, file */ \
12 defined ( PLD_mskermit ) || /* MS-kermit emulator */ \
13 defined ( PLD_versaterm ) || /* Versaterm emulator */ \
14 defined ( PLD_vlt ) || /* VLT emulator */ \
15 defined ( PLD_conex ) // conex emulator 4010/4014/4105
16
17 #define NEED_PLDEBUG
18 #include "plplotP.h"
19 #include "drivers.h"
20 #include "plevent.h"
21
22 #include <ctype.h>
23
24 // Device info
25
26 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_tek =
27 #if defined ( PLD_conex )
28 "conex:Conex vt320/tek emulator:1:tek:24:conex\n"
29 #endif
30 #if defined ( PLD_mskermit )
31 "mskermit:MS-Kermit emulator:1:tek:21:mskermit\n"
32 #endif
33 #if defined ( PLD_tek4107t )
34 "tek4107t:Tektronix Terminal (4105/4107):1:tek:20:tek4107t\n"
35 #endif
36 #if defined ( PLD_tek4107f )
37 "tek4107f:Tektronix File (4105/4107):0:tek:28:tek4107f\n"
38 #endif
39 #if defined ( PLD_tekt )
40 "tekt:Tektronix Terminal (4010):1:tek:19:tekt\n"
41 #endif
42 #if defined ( PLD_tekf )
43 "tekf:Tektronix File (4010):0:tek:27:tekf\n"
44 #endif
45 #if defined ( PLD_versaterm )
46 "versaterm:Versaterm vt100/tek emulator:1:tek:22:versaterm\n"
47 #endif
48 #if defined ( PLD_vlt )
49 "vlt:VLT vt100/tek emulator:1:tek:23:vlt\n"
50 #endif
51 #if defined ( PLD_xterm )
52 "xterm:Xterm Window:1:tek:18:xterm\n"
53 #endif
54 ;
55
56 // Prototype the driver entry points that will be used to initialize the
57 // dispatch table entries.
58
59 void plD_init_xterm( PLStream * );
60 void plD_init_tekt( PLStream * );
61 void plD_init_tekf( PLStream * );
62 void plD_init_tek4107t( PLStream * );
63 void plD_init_tek4107f( PLStream * );
64 void plD_init_mskermit( PLStream * );
65 void plD_init_versaterm( PLStream * );
66 void plD_init_vlt( PLStream * );
67 void plD_init_conex( PLStream * );
68
69 // External generic entry points
70
71 void plD_line_tek( PLStream *, short, short, short, short );
72 void plD_polyline_tek( PLStream *, short *, short *, PLINT );
73 void plD_eop_tek( PLStream * );
74 void plD_bop_tek( PLStream * );
75 void plD_tidy_tek( PLStream * );
76 void plD_state_tek( PLStream *, PLINT );
77 void plD_esc_tek( PLStream *, PLINT, void * );
78
79 // Static function prototypes
80
81 static void WaitForPage( PLStream *pls );
82 static void tek_init( PLStream *pls );
83 static void tek_text( PLStream *pls );
84 static void tek_graph( PLStream *pls );
85 static void fill_polygon( PLStream *pls );
86 static void GetCursor( PLStream *pls, PLGraphicsIn *ptr );
87 static void encode_int( char *c, int i );
88 static void encode_vector( char *c, int x, int y );
89 static void decode_gin( char *c, PLGraphicsIn *gin );
90 static void tek_vector( PLStream *pls, int x, int y );
91 static void scolor( PLStream *pls, int icol, int r, int g, int b );
92 static void setcmap( PLStream *pls );
93
94 static void LookupEvent( PLStream *pls );
95 static void InputEH( PLStream *pls );
96 static void LocateEH( PLStream *pls );
97
98 // Stuff for handling tty cbreak mode
99
100 #ifdef HAVE_TERMIOS_H
101 #include <termios.h>
102 #include <unistd.h>
103 static struct termios termios_cbreak, termios_reset;
104 static enum { RESET, CBREAK } ttystate = RESET;
105 static void tty_setup( void );
106 static int tty_cbreak( void );
107 static int tty_reset( void );
108 static void tty_atexit( void );
109 #else
110 static void tty_setup( void )
111 {
112 }
113 static int tty_cbreak( void )
114 {
115 return 0;
116 }
117 static int tty_reset( void )
118 {
119 return 0;
120 }
121 static void tty_atexit( void )
122 {
123 }
124 #endif
125
126 // Pixel settings
127
128 #define TEKX 1023
129 #define TEKY 779
130
131 // Graphics control characters.
132
133 #define RING_BELL "\007" // ^G = 7
134 #define CLEAR_VIEW "\033\f" // clear the view = ESC FF
135
136 #define ALPHA_MODE "\037" // Enter Alpha mode: US
137 #define VECTOR_MODE "\035" // Enter Vector mode: GS
138 #define GIN_MODE "\033\032" // Enter GIN mode: ESC SUB
139 #define BYPASS_MODE "\033\030" // Enter Bypass mode: ESC CAN
140 #define XTERM_VTMODE "\033\003" // End xterm-Tek mode: ESC ETX
141 #define CANCEL "\033KC" // Cancel
142
143 // Static vars
144
145 enum { tek4010, tek4105, tek4107, xterm, mskermit, vlt, versaterm };
146
147 // One of these holds the tek driver state information
148
149 typedef struct
150 {
151 PLINT xold, yold; // Coordinates of last point plotted
152 int exit_eventloop; // Break out of event loop
153 int locate_mode; // Set while in locate (pick) mode
154 int curcolor; // Current color index
155 PLGraphicsIn gin; // Graphics input structure
156 } TekDev;
157
158 // color for MS-DOS Kermit v2.31 (and up) tektronix emulator
159 // 0 = normal, 1 = bright
160 // foreground color (30-37) = 30 + colors
161 // where colors are 1=red, 2=green, 4=blue
162 //
163 #ifdef PLD_mskermit
164 static char *kermit_color[15] = {
165 "0;30", "0;37",
166 "0;32", "0;36","0;31", "0;35",
167 "1;34", "1;33","1;31", "1;37",
168 "1;35", "1;32","1;36", "0;34",
169 "0;33"
170 };
171 #endif
172
173 static void tek_dispatch_init_helper( PLDispatchTable *pdt,
174 char *menustr, char *devnam,
175 int type, int seq, plD_init_fp init )
176 {
177 #ifndef ENABLE_DYNDRIVERS
178 pdt->pl_MenuStr = menustr;
179 pdt->pl_DevName = devnam;
180 #endif
181 pdt->pl_type = type;
182 pdt->pl_seq = seq;
183 pdt->pl_init = init;
184 pdt->pl_line = (plD_line_fp) plD_line_tek;
185 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_tek;
186 pdt->pl_eop = (plD_eop_fp) plD_eop_tek;
187 pdt->pl_bop = (plD_bop_fp) plD_bop_tek;
188 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_tek;
189 pdt->pl_state = (plD_state_fp) plD_state_tek;
190 pdt->pl_esc = (plD_esc_fp) plD_esc_tek;
191 }
192
193 void plD_dispatch_init_xterm( PLDispatchTable *pdt )
194 {
195 tek_dispatch_init_helper( pdt,
196 "Xterm Window", "xterm",
197 plDevType_Interactive, 18,
198 (plD_init_fp) plD_init_xterm );
199 }
200
201 void plD_dispatch_init_tekt( PLDispatchTable *pdt )
202 {
203 tek_dispatch_init_helper( pdt,
204 "Tektronix Terminal (4010)", "tekt",
205 plDevType_Interactive, 19,
206 (plD_init_fp) plD_init_tekt );
207 }
208
209 void plD_dispatch_init_tek4107t( PLDispatchTable *pdt )
210 {
211 tek_dispatch_init_helper( pdt,
212 "Tektronix Terminal (4105/4107)", "tek4107t",
213 plDevType_Interactive, 20,
214 (plD_init_fp) plD_init_tek4107t );
215 }
216
217 void plD_dispatch_init_mskermit( PLDispatchTable *pdt )
218 {
219 tek_dispatch_init_helper( pdt,
220 "MS-Kermit emulator", "mskermit",
221 plDevType_Interactive, 21,
222 (plD_init_fp) plD_init_mskermit );
223 }
224
225 void plD_dispatch_init_versaterm( PLDispatchTable *pdt )
226 {
227 tek_dispatch_init_helper( pdt,
228 "Versaterm vt100/tek emulator", "versaterm",
229 plDevType_Interactive, 22,
230 (plD_init_fp) plD_init_versaterm );
231 }
232
233 void plD_dispatch_init_vlt( PLDispatchTable *pdt )
234 {
235 tek_dispatch_init_helper( pdt,
236 "VLT vt100/tek emulator", "vlt",
237 plDevType_Interactive, 23,
238 (plD_init_fp) plD_init_vlt );
239 }
240
241 void plD_dispatch_init_conex( PLDispatchTable *pdt )
242 {
243 tek_dispatch_init_helper( pdt,
244 "Conex vt320/tek emulator", "conex",
245 plDevType_Interactive, 24,
246 (plD_init_fp) plD_init_conex );
247 }
248
249 void plD_dispatch_init_tekf( PLDispatchTable *pdt )
250 {
251 tek_dispatch_init_helper( pdt,
252 "Tektronix File (4010)", "tekf",
253 plDevType_FileOriented, 27,
254 (plD_init_fp) plD_init_tekf );
255 }
256
257 void plD_dispatch_init_tek4107f( PLDispatchTable *pdt )
258 {
259 tek_dispatch_init_helper( pdt,
260 "Tektronix File (4105/4107)", "tek4107f",
261 plDevType_FileOriented, 28,
262 (plD_init_fp) plD_init_tek4107f );
263 }
264
265 //--------------------------------------------------------------------------
266 // plD_init_xterm() xterm
267 // plD_init_tekt() Tek 4010 terminal
268 // plD_init_tekf() Tek 4010 file
269 // plD_init_tek4107t() Tek 4105/4107 terminal
270 // plD_init_tek4107f() Tek 4105/4107 file
271 // plD_init_mskermit() MS-Kermit emulator (DOS)
272 // plD_init_vlt() VLT emulator (Amiga)
273 // plD_init_versaterm() VersaTerm emulator (Mac)
274 // plD_init_conex() Conex vt320/Tek 4105 emulator (DOS)
275 //
276 // These just set attributes for the particular tektronix device, then call
277 // tek_init(). The following attributes can be set:
278 //
279 // pls->termin if a terminal device
280 // pls->color if color (1), if only fixed colors (2)
281 // pls->dev_fill0 if can handle solid area fill
282 // pls->dev_fill1 if can handle pattern area fill
283 //--------------------------------------------------------------------------
284
285 void
286 plD_init_xterm( PLStream *pls )
287 {
288 pls->dev_minor = xterm;
289 pls->termin = 1;
290 tek_init( pls );
291 }
292
293 void
294 plD_init_tekt( PLStream *pls )
295 {
296 pls->termin = 1;
297 plD_init_tekf( pls );
298 }
299
300 void
301 plD_init_tekf( PLStream *pls )
302 {
303 pls->dev_minor = tek4010;
304 tek_init( pls );
305 }
306
307 void
308 plD_init_tek4107t( PLStream *pls )
309 {
310 pls->termin = 1;
311 plD_init_tek4107f( pls );
312 }
313
314 void
315 plD_init_tek4107f( PLStream *pls )
316 {
317 pls->dev_minor = tek4107;
318 pls->color = 1;
319 pls->dev_fill0 = 1;
320 tek_init( pls );
321 }
322
323 void
324 plD_init_mskermit( PLStream *pls )
325 {
326 pls->dev_minor = mskermit;
327 pls->termin = 1;
328 pls->color = 1;
329 pls->dev_fill0 = 1;
330 tek_init( pls );
331 }
332
333 void
334 plD_init_vlt( PLStream *pls )
335 {
336 pls->dev_minor = vlt;
337 pls->termin = 1;
338 pls->color = 1;
339 pls->dev_fill0 = 1;
340 tek_init( pls );
341 }
342
343 void
344 plD_init_versaterm( PLStream *pls )
345 {
346 pls->dev_minor = versaterm;
347 pls->termin = 1;
348 pls->color = 1;
349 pls->dev_fill0 = 1;
350 tek_init( pls );
351 }
352
353 void
354 plD_init_conex( PLStream *pls )
355 {
356 pls->dev_minor = xterm; // responds to xterm escape codes
357 pls->termin = 1;
358 pls->color = 2; // only fixed colours
359 tek_init( pls );
360 }
361
362 //--------------------------------------------------------------------------
363 // tek_init()
364 //
365 // Generic tektronix device initialization.
366 //--------------------------------------------------------------------------
367
368 static void
369 tek_init( PLStream *pls )
370 {
371 TekDev *dev;
372 int xmin = 0;
373 int xmax = TEKX;
374 int ymin = 0;
375 int ymax = TEKY;
376
377 PLFLT pxlx = 4.771;
378 PLFLT pxly = 4.653;
379
380 pls->graphx = TEXT_MODE;
381
382 // Allocate and initialize device-specific data
383
384 pls->dev = calloc( 1, (size_t) sizeof ( TekDev ) );
385 if ( pls->dev == NULL )
386 plexit( "tek_init: Out of memory." );
387
388 dev = (TekDev *) pls->dev;
389
390 dev->curcolor = 1;
391 dev->xold = PL_UNDEFINED;
392 dev->yold = PL_UNDEFINED;
393
394 plP_setpxl( pxlx, pxly );
395 plP_setphy( xmin, xmax, ymin, ymax );
396
397 // Terminal/file initialization
398
399 if ( pls->termin )
400 {
401 pls->OutFile = stdout;
402 tty_setup();
403 }
404 else
405 {
406 plFamInit( pls );
407 plOpenFile( pls );
408 }
409
410 switch ( pls->dev_minor )
411 {
412 #ifdef PLD_tek4107
413 case tek4107:
414 pls->graphx = GRAPHICS_MODE;
415 fprintf( pls->OutFile, "\033%%!0" ); // set tek mode
416 fprintf( pls->OutFile, "\033KN1" ); // clear the view
417 fprintf( pls->OutFile, "\033LZ" ); // clear dialog buffer
418 fprintf( pls->OutFile, "\033ML1" ); // set default color
419 break;
420 #endif // PLD_tek4107
421
422 // A sneaky hack: VLT sometimes has leftover panel information, causing
423 // garbage at the beginning of a sequence of color fills. Since
424 // there is no clear panel command, instead I set the fill color to the
425 // same as background and issue an end panel command.
426 //
427 #ifdef PLD_vlt
428 case vlt: {
429 char fillcol[4];
430 tek_graph( pls );
431 encode_int( fillcol, 0 );
432 fprintf( pls->OutFile, "\033MP%s\033LE", fillcol );
433 break;
434 }
435 #endif // PLD_vlt
436
437 default:
438 tek_graph( pls );
439 }
440
441 // Initialize palette
442
443 if ( pls->color & 0x01 )
444 {
445 printf( "\033TM111" ); // Switch to RGB colors
446 setcmap( pls );
447 }
448
449 // Finish initialization
450
451 fprintf( pls->OutFile, VECTOR_MODE ); // Enter vector mode
452 if ( pls->termin )
453 fprintf( pls->OutFile, CLEAR_VIEW ); // erase and home
454
455 fflush( pls->OutFile );
456 }
457
458 //--------------------------------------------------------------------------
459 // plD_line_tek()
460 //
461 // Draw a line from (x1,y1) to (x2,y2).
462 //--------------------------------------------------------------------------
463
464 void
465 plD_line_tek( PLStream *pls, short x1, short y1, short x2, short y2 )
466 {
467 TekDev *dev = (TekDev *) pls->dev;
468
469 tek_graph( pls );
470
471 // If not continuation of previous line, begin a new one
472
473 if ( x1 != dev->xold || y1 != dev->yold )
474 {
475 pls->bytecnt += fprintf( pls->OutFile, VECTOR_MODE );
476 tek_vector( pls, x1, y1 );
477 }
478
479 // Now send following point to complete line draw
480
481 tek_vector( pls, x2, y2 );
482
483 dev->xold = x2;
484 dev->yold = y2;
485 }
486
487 //--------------------------------------------------------------------------
488 // plD_polyline_tek()
489 //
490 // Draw a polyline in the current color.
491 //--------------------------------------------------------------------------
492
493 void
494 plD_polyline_tek( PLStream *pls, short *xa, short *ya, PLINT npts )
495 {
496 PLINT i;
497 TekDev *dev = (TekDev *) pls->dev;
498 short x = xa[0], y = ya[0];
499
500 tek_graph( pls );
501
502 // If not continuation of previous line, begin a new one
503
504 if ( x != dev->xold || y != dev->yold )
505 {
506 pls->bytecnt += fprintf( pls->OutFile, VECTOR_MODE );
507 tek_vector( pls, x, y );
508 }
509
510 // Now send following points to complete polyline draw
511
512 for ( i = 1; i < npts; i++ )
513 tek_vector( pls, xa[i], ya[i] );
514
515 dev->xold = xa[npts - 1];
516 dev->yold = ya[npts - 1];
517 }
518
519 //--------------------------------------------------------------------------
520 // plD_eop_tek()
521 //
522 // End of page. User must hit a <CR> to continue (terminal output).
523 //--------------------------------------------------------------------------
524
525 void
526 plD_eop_tek( PLStream *pls )
527 {
528 tek_graph( pls );
529
530 if ( pls->termin )
531 {
532 if ( !pls->nopause )
533 WaitForPage( pls );
534 }
535 fprintf( pls->OutFile, CLEAR_VIEW ); // erase and home
536 }
537
538 //--------------------------------------------------------------------------
539 // plD_bop_tek()
540 //
541 // Set up for the next page. Advance to next family file if necessary
542 // (file output). Devices that share graphics/alpha screens need a page
543 // clear.
544 //--------------------------------------------------------------------------
545
546 void
547 plD_bop_tek( PLStream *pls )
548 {
549 TekDev *dev = (TekDev *) pls->dev;
550
551 dev->xold = PL_UNDEFINED;
552 dev->yold = PL_UNDEFINED;
553
554 if ( pls->termin )
555 {
556 switch ( pls->dev_minor )
557 {
558 case mskermit:
559 fprintf( pls->OutFile, CLEAR_VIEW ); // erase and home
560 break;
561 }
562 }
563 else
564 {
565 plGetFam( pls );
566 }
567 pls->page++;
568
569 // Initialize palette
570
571 if ( pls->color & 0x01 )
572 setcmap( pls );
573 }
574
575 //--------------------------------------------------------------------------
576 // plD_tidy_tek()
577 //
578 // Close graphics file or otherwise clean up.
579 //--------------------------------------------------------------------------
580
581 void
582 plD_tidy_tek( PLStream *pls )
583 {
584 if ( !pls->termin )
585 {
586 plCloseFile( pls );
587 }
588 else
589 {
590 tek_text( pls );
591 fflush( pls->OutFile );
592 }
593 }
594
595 //--------------------------------------------------------------------------
596 // tek_color()
597 //
598 // Change to specified color index.
599 //--------------------------------------------------------------------------
600
601 static void
602 tek_color( PLStream *pls, int icol )
603 {
604 switch ( pls->dev_minor )
605 {
606 #ifdef PLD_mskermit // Is this really necessary?
607 case mskermit:
608 printf( "\033[%sm", kermit_color[icol % 14] );
609 break;
610 #endif
611 default:
612 pls->bytecnt += fprintf( pls->OutFile, "\033ML%c", icol + '0' );
613 }
614 }
615
616 //--------------------------------------------------------------------------
617 // plD_state_tek()
618 //
619 // Handle change in PLStream state (color, pen width, fill attribute,
620 // etc).
621 //--------------------------------------------------------------------------
622
623 void
624 plD_state_tek( PLStream *pls, PLINT op )
625 {
626 TekDev *dev = (TekDev *) pls->dev;
627
628 switch ( op )
629 {
630 case PLSTATE_WIDTH:
631 break;
632
633 case PLSTATE_COLOR0:
634 if ( pls->color )
635 {
636 int icol0 = pls->icol0;
637 tek_graph( pls );
638 if ( icol0 != PL_RGB_COLOR )
639 {
640 dev->curcolor = icol0;
641 tek_color( pls, icol0 );
642 }
643 }
644 break;
645
646 case PLSTATE_COLOR1:
647 if ( pls->color )
648 {
649 int icol1, ncol1;
650 tek_graph( pls );
651 if ( ( ncol1 = MIN( 16 - pls->ncol0, pls->ncol1 ) ) < 1 )
652 break;
653
654 icol1 = pls->ncol0 + ( pls->icol1 * ( ncol1 - 1 ) ) / ( pls->ncol1 - 1 );
655 dev->curcolor = icol1;
656 tek_color( pls, icol1 );
657 }
658 break;
659
660 case PLSTATE_CMAP0:
661 case PLSTATE_CMAP1:
662 if ( pls->color & 0x01 )
663 setcmap( pls );
664
665 break;
666 }
667 }
668
669 //--------------------------------------------------------------------------
670 // plD_esc_tek()
671 //
672 // Escape function.
673 //--------------------------------------------------------------------------
674
675 void
676 plD_esc_tek( PLStream *pls, PLINT op, void *ptr )
677 {
678 switch ( op )
679 {
680 case PLESC_TEXT:
681 tek_text( pls );
682 break;
683
684 case PLESC_GRAPH:
685 tek_graph( pls );
686 break;
687
688 case PLESC_FILL:
689 fill_polygon( pls );
690 break;
691
692 case PLESC_GETC:
693 GetCursor( pls, (PLGraphicsIn *) ptr );
694 break;
695 }
696 }
697
698 //--------------------------------------------------------------------------
699 // GetCursor()
700 //
701 // Waits for a left button mouse event and returns coordinates.
702 // xterm doesn't handle GIN. I think all the rest do.
703 //--------------------------------------------------------------------------
704
705 static void
706 GetCursor( PLStream *pls, PLGraphicsIn *ptr )
707 {
708 #define MAX_GIN 10
709 char input_string[MAX_GIN];
710 int i = 0;
711
712 plGinInit( ptr );
713
714 if ( pls->termin && pls->dev_minor != xterm )
715 {
716 tek_graph( pls );
717
718 // Enter GIN mode
719
720 printf( GIN_MODE );
721 fflush( stdout );
722
723 // Read & decode report
724
725 while ( ++i < MAX_GIN && ( input_string[i - 1] = getchar() ) != '\n' )
726 ;
727
728 input_string[i - 1] = '\0';
729 ptr->keysym = input_string[0];
730 decode_gin( &input_string[1], ptr );
731
732 // Switch out of GIN mode
733
734 printf( VECTOR_MODE );
735 }
736 }
737
738 //--------------------------------------------------------------------------
739 // fill_polygon()
740 //
741 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
742 //--------------------------------------------------------------------------
743
744 static void
745 fill_polygon( PLStream *pls )
746 {
747 TekDev *dev = (TekDev *) pls->dev;
748 int i;
749 char fillcol[4], firstpoint[5];
750
751 if ( pls->dev_npts < 1 )
752 return;
753
754 tek_graph( pls );
755
756 encode_int( fillcol, -dev->curcolor );
757 encode_vector( firstpoint, pls->dev_x[0], pls->dev_y[0] );
758
759 // Select the fill pattern
760
761 pls->bytecnt += fprintf( pls->OutFile, "\033MP%s", fillcol );
762
763 // Begin panel boundary
764 // Set pls->debug to see the boundary of each fill box -- cool!
765
766 if ( pls->debug )
767 pls->bytecnt += fprintf( pls->OutFile, "\033LP%s1", firstpoint );
768 else
769 pls->bytecnt += fprintf( pls->OutFile, "\033LP%s0", firstpoint );
770
771 // Specify boundary (in vector mode)
772
773 pls->bytecnt += fprintf( pls->OutFile, VECTOR_MODE );
774 for ( i = 1; i < pls->dev_npts; i++ )
775 tek_vector( pls, pls->dev_x[i], pls->dev_y[i] );
776
777 // End panel
778
779 pls->bytecnt += fprintf( pls->OutFile, "\033LE" );
780 }
781
782 //--------------------------------------------------------------------------
783 // tek_text()
784 //
785 // Switch to text screen (or alpha mode, for vanilla tek's). Restore
786 // terminal to its original state, to better handle user input if
787 // necessary.
788 //
789 // Note: xterm behaves strangely in the following circumstance: switch to
790 // the text screen, print a string, and switch to the graphics screen, all
791 // done in quick succession. The first character of the printed string
792 // usually comes out blank -- but only apparently so, because if you force
793 // a refresh of the screen in this area it will reappear. This is a
794 // reproducible bug on the HP 720 under X11R5. If you insert a sleep(1)
795 // after the switch to text screen or before the switch to graphics
796 // screen, the string is printed correctly. I've been unable to find a
797 // workaround for this problem (and I've tried, you can believe eet man).
798 //--------------------------------------------------------------------------
799
800 static void
801 tek_text( PLStream *pls )
802 {
803 if ( pls->termin && ( pls->graphx == GRAPHICS_MODE ) )
804 {
805 tty_reset();
806 pls->graphx = TEXT_MODE;
807 switch ( pls->dev_minor )
808 {
809 case xterm:
810 printf( "\033\003" ); // vt100 mode (xterm) = ESC ETX
811 break;
812
813 case mskermit:
814 case vlt:
815 printf( "\033[?38l" ); // vt100 screen
816 break;
817
818 case versaterm:
819 printf( "\033%%!2" ); // vt100 screen
820 break;
821
822 case tek4107:
823 printf( "\033LV1" ); // set dialog visible
824 printf( "\033%%!1" ); // set ansi mode
825 break;
826
827 default:
828 printf( ALPHA_MODE ); // enter alpha mode
829 }
830 fflush( stdout );
831 }
832 }
833
834 //--------------------------------------------------------------------------
835 // tek_graph()
836 //
837 // Switch to graphics screen. Also switch terminal to cbreak mode, to allow
838 // single keystrokes to govern actions at end of page.
839 //--------------------------------------------------------------------------
840
841 static void
842 tek_graph( PLStream *pls )
843 {
844 if ( pls->termin && ( pls->graphx == TEXT_MODE ) )
845 {
846 tty_cbreak();
847 pls->graphx = GRAPHICS_MODE;
848 switch ( pls->dev_minor )
849 {
850 case xterm:
851 case mskermit:
852 case vlt:
853 printf( "\033[?38h" ); // switch to tek screen
854 break;
855
856 case versaterm:
857 printf( "\033%%!0" ); // switch to tek4107 screen
858 break;
859
860 case tek4107:
861 printf( "\033%%!0" ); // set tek mode
862 printf( CLEAR_VIEW ); // clear screen
863 printf( "\033LV0" ); // set dialog invisible
864 break;
865 }
866 }
867 }
868
869 //--------------------------------------------------------------------------
870 // encode_int()
871 //
872 // Encodes a single int into standard tek integer format, storing into a
873 // NULL-terminated character string (must be length 4 or greater). This
874 // scheme does not work for negative integers less than 15.
875 //--------------------------------------------------------------------------
876
877 static void
878 encode_int( char *c, int i )
879 {
880 int negative = 0;
881
882 if ( i > 0 )
883 {
884 if ( i & 0x7C00 ) // are any of bits 10-14 set?
885 *c++ = ( ( i >> 10 ) & 0x1F ) | 0x40;
886 if ( i & 0x03F0 ) // are any of bits 4-9 set?
887 *c++ = ( ( i >> 4 ) & 0x3F ) | 0x40;
888 }
889 else
890 {
891 i = -i;
892 negative = 1;
893 }
894
895 if ( i & 0x000F ) // are any of bits 0-3 set?
896 *c = ( i & 0x0F ) | 0x20;
897 else // if not, put in a space
898 *c = 0x20;
899
900 if ( !negative ) // if positive, set sign bit
901 *c |= 0x10;
902
903 c++; *c = '\0'; // NULL-terminate
904 return;
905 }
906
907 //--------------------------------------------------------------------------
908 // decode_gin()
909 //
910 // Decodes a GIN tek vector string into an xy pair of relative device
911 // coordinates. It's best to not use absolute device coordinates since the
912 // coordinate bounds are different depending on the report encoding used.
913 //
914 // Standard: <HiX><LoX><HiY><LoY>
915 // Extended: <HiY><Extra><LoY><HiX><LoX>
916 //
917 // where <Extra> holds the two low order bits for each coordinate.
918 //--------------------------------------------------------------------------
919
920 static void
921 decode_gin( char *c, PLGraphicsIn *gin )
922 {
923 int x, y, lc = strlen( c );
924
925 if ( lc == 4 )
926 {
927 x = ( ( c[0] & 0x1f ) << 5 ) +
928 ( ( c[1] & 0x1f ) );
929
930 y = ( ( c[2] & 0x1f ) << 5 ) +
931 ( ( c[3] & 0x1f ) );
932
933 gin->pX = x;
934 gin->pY = y;
935 gin->dX = x / (double) TEKX;
936 gin->dY = y / (double) TEKY;
937 }
938 else if ( lc == 5 )
939 {
940 y = ( ( c[0] & 0x1f ) << 7 ) +
941 ( ( c[2] & 0x1f ) << 2 ) +
942 ( ( c[1] & 0x06 ) >> 2 );
943
944 x = ( ( c[3] & 0x1f ) << 7 ) +
945 ( ( c[4] & 0x1f ) << 2 ) +
946 ( ( c[1] & 0x03 ) );
947
948 gin->pX = x;
949 gin->pY = y;
950 gin->dX = x / (double) ( TEKX << 2 );
951 gin->dY = y / (double) ( TEKY << 2 );
952 }
953 else // Illegal encoding
954 {
955 gin->pX = 0;
956 gin->pY = 0;
957 gin->dY = 0;
958 gin->dX = 0;
959 }
960 }
961
962 //--------------------------------------------------------------------------
963 // encode_vector()
964 //
965 // Encodes an xy vector (2 ints) into standard tek vector format, storing
966 // into a NULL-terminated character string of length 5. Note that the y
967 // coordinate always comes first.
968 //--------------------------------------------------------------------------
969
970 static void
971 encode_vector( char *c, int x, int y )
972 {
973 c[0] = ( y >> 5 ) + 0x20; // hy
974 c[1] = ( y & 0x1f ) + 0x60; // ly
975 c[2] = ( x >> 5 ) + 0x20; // hx
976 c[3] = ( x & 0x1f ) + 0x40; // lx
977 c[4] = '\0'; // NULL
978 }
979
980 //--------------------------------------------------------------------------
981 // tek_vector()
982 //
983 // Issues a vector draw command, assuming we are in vector plot mode. XY
984 // coordinates are encoded according to the standard xy encoding scheme.
985 //--------------------------------------------------------------------------
986
987 static void
988 tek_vector( PLStream *pls, int x, int y )
989 {
990 char c[5];
991
992 encode_vector( c, x, y );
993 pls->bytecnt += fprintf( pls->OutFile, "%s", c );
994 }
995
996 //--------------------------------------------------------------------------
997 // scolor()
998 //
999 // Sets a color by tek-encoded RGB values. Need to convert PLplot RGB
1000 // color range (0 to 255) to Tek RGB color range (0 to 100).
1001 //--------------------------------------------------------------------------
1002
1003 static void
1004 scolor( PLStream *pls, int icol, int r, int g, int b )
1005 {
1006 char tek_col[4], tek_r[4], tek_g[4], tek_b[4];
1007
1008 encode_int( tek_col, icol );
1009 encode_int( tek_r, ( 100 * r ) / 255 );
1010 encode_int( tek_g, ( 100 * g ) / 255 );
1011 encode_int( tek_b, ( 100 * b ) / 255 );
1012
1013 pls->bytecnt += fprintf( pls->OutFile, "\033TG14%s%s%s%s",
1014 tek_col, tek_r, tek_g, tek_b );
1015 }
1016
1017 //--------------------------------------------------------------------------
1018 // setcmap()
1019 //
1020 // Sets up color palette.
1021 //--------------------------------------------------------------------------
1022
1023 static void
1024 setcmap( PLStream *pls )
1025 {
1026 int i, ncol1 = MIN( 16 - pls->ncol0, pls->ncol1 );
1027 PLColor cmap1col;
1028
1029 tek_graph( pls );
1030
1031 // Initialize cmap 0 colors
1032
1033 for ( i = 0; i < pls->ncol0; i++ )
1034 scolor( pls, i, pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b );
1035
1036 // Initialize any remaining slots for cmap1
1037
1038 for ( i = 0; i < ncol1; i++ )
1039 {
1040 plcol_interp( pls, &cmap1col, i, ncol1 );
1041 scolor( pls, i + pls->ncol0, cmap1col.r, cmap1col.g, cmap1col.b );
1042 }
1043 }
1044
1045 //--------------------------------------------------------------------------
1046 // WaitForPage()
1047 //
1048 // This routine waits for the user to advance the plot, while handling
1049 // all other events.
1050 //--------------------------------------------------------------------------
1051
1052 static void
1053 WaitForPage( PLStream *pls )
1054 {
1055 TekDev *dev = (TekDev *) pls->dev;
1056
1057 printf( ALPHA_MODE ); // Switch to alpha mode (necessary)
1058 printf( RING_BELL ); // and ring bell
1059 printf( VECTOR_MODE ); // Switch out of alpha mode
1060 fflush( stdout );
1061
1062 while ( !dev->exit_eventloop )
1063 {
1064 LookupEvent( pls );
1065 if ( dev->locate_mode )
1066 LocateEH( pls );
1067 else
1068 InputEH( pls );
1069 }
1070 dev->exit_eventloop = FALSE;
1071 }
1072
1073 //--------------------------------------------------------------------------
1074 // LookupEvent()
1075 //
1076 // Fills in the PLGraphicsIn from an input event.
1077 //--------------------------------------------------------------------------
1078
1079 static void
1080 LookupEvent( PLStream *pls )
1081 {
1082 TekDev *dev = (TekDev *) pls->dev;
1083 PLGraphicsIn *gin = &( dev->gin );
1084
1085 if ( dev->locate_mode )
1086 {
1087 GetCursor( pls, gin );
1088 }
1089 else
1090 {
1091 plGinInit( gin );
1092 gin->keysym = getchar();
1093 }
1094
1095 if ( isprint( gin->keysym ) )
1096 {
1097 gin->string[0] = gin->keysym;
1098 gin->string[1] = '\0';
1099 }
1100 else
1101 {
1102 gin->string[0] = '\0';
1103 }
1104
1105 pldebug( "LookupEvent",
1106 "Keycode %x, string: %s\n", gin->keysym, gin->string );
1107 }
1108
1109 //--------------------------------------------------------------------------
1110 // LocateEH()
1111 //
1112 // Handles locate mode events.
1113 //
1114 // In locate mode: move cursor to desired location and select by pressing a
1115 // key or by clicking on the mouse (if available). Typically the world
1116 // coordinates of the selected point are reported.
1117 //
1118 // There are two ways to enter Locate mode -- via the API, or via a driver
1119 // command. The API entry point is the call plGetCursor(), which initiates
1120 // locate mode and does not return until input has been obtained. The
1121 // driver entry point is by entering a 'L' while the driver is waiting for
1122 // events.
1123 //
1124 // Locate mode input is reported in one of three ways:
1125 // 1. Through a returned PLGraphicsIn structure, when user has specified a
1126 // locate handler via (*pls->LocateEH).
1127 // 2. Through a returned PLGraphicsIn structure, when locate mode is invoked
1128 // by a plGetCursor() call.
1129 // 3. Through writes to stdout, when locate mode is invoked by a driver
1130 // command and the user has not supplied a locate handler.
1131 //
1132 // Hitting <Escape> will at all times end locate mode. Other keys will
1133 // typically be interpreted as locator input. Selecting a point out of
1134 // bounds will end locate mode unless the user overrides with a supplied
1135 // Locate handler.
1136 //--------------------------------------------------------------------------
1137
1138 static void
1139 LocateEH( PLStream *pls )
1140 {
1141 TekDev *dev = (TekDev *) pls->dev;
1142 PLGraphicsIn *gin = &( dev->gin );
1143
1144 // End locate mode on <Escape>
1145
1146 if ( gin->keysym == PLK_Escape )
1147 {
1148 dev->locate_mode = 0;
1149 return;
1150 }
1151
1152 // Call user locate mode handler if provided
1153
1154 if ( pls->LocateEH != NULL )
1155 ( *pls->LocateEH )( gin, pls->LocateEH_data, &dev->locate_mode );
1156
1157 // Use default procedure
1158
1159 else
1160 {
1161 // Try to locate cursor
1162
1163 if ( plTranslateCursor( gin ) )
1164 {
1165 // Successful, so send report to stdout
1166
1167 pltext();
1168 if ( isprint( gin->keysym ) )
1169 printf( "%f %f %c\n", gin->wX, gin->wY, gin->keysym );
1170 else
1171 printf( "%f %f\n", gin->wX, gin->wY );
1172
1173 plgra();
1174 }
1175 else
1176 {
1177 // Selected point is out of bounds, so end locate mode
1178
1179 dev->locate_mode = 0;
1180 }
1181 }
1182 }
1183
1184 //--------------------------------------------------------------------------
1185 // InputEH()
1186 //
1187 // Event handler routine for xterm. Just reacts to keyboard input.
1188 //
1189 // In locate mode: move cursor to desired location and select by pressing a
1190 // key or by clicking on the mouse (if available). The world coordinates of
1191 // the selected point are output on the text screen. Terminate by picking a
1192 // point out of bounds, hitting page advance, or the escape key. If you
1193 // want to customize this, write an event handler to do it.
1194 //--------------------------------------------------------------------------
1195
1196 static void
1197 InputEH( PLStream *pls )
1198 {
1199 TekDev *dev = (TekDev *) pls->dev;
1200 PLGraphicsIn *gin = &( dev->gin );
1201
1202 // Call user event handler.
1203 // Since this is called first, the user can disable all PLplot internal
1204 // event handling by setting gin->keysym to 0 and gin->string to '\0'.
1205 //
1206 if ( pls->KeyEH != NULL )
1207 ( *pls->KeyEH )( gin, pls->KeyEH_data, &dev->exit_eventloop );
1208
1209 // Remaining internal event handling
1210
1211 switch ( gin->keysym )
1212 {
1213 case PLK_Linefeed:
1214 // Advance to next page (i.e. terminate event loop) on a <eol>
1215 dev->exit_eventloop = TRUE;
1216 break;
1217
1218 case 'Q':
1219 // Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake)
1220 pls->nopause = TRUE;
1221 plexit( "" );
1222 break;
1223
1224 case 'L':
1225 // Begin locate mode
1226 dev->locate_mode = 1;
1227 break;
1228 }
1229 }
1230
1231 //--------------------------------------------------------------------------
1232 // tty cbreak-mode handlers
1233 //
1234 // Taken from "Advanced Programming in the UNIX(R) Environment",
1235 // by W. Richard Stevens.
1236 //--------------------------------------------------------------------------
1237
1238 #ifdef HAVE_TERMIOS_H
1239
1240 static void
1241 tty_setup( void ) // setup for terminal operations
1242 {
1243 if ( tcgetattr( STDIN_FILENO, &termios_reset ) < 0 )
1244 {
1245 fprintf( stderr, "Unable to set up cbreak mode.\n" );
1246 return;
1247 }
1248
1249 termios_cbreak = termios_reset; // structure copy
1250
1251 termios_cbreak.c_lflag &= ~( ICANON ); // canonical mode off
1252 termios_cbreak.c_cc[VMIN] = 1; // 1 byte at a time
1253 termios_cbreak.c_cc[VTIME] = 0; // no timer
1254
1255 #ifdef STDC_HEADERS
1256 if ( atexit( tty_atexit ) )
1257 fprintf( stderr, "Unable to set up atexit handler.\n" );
1258 #endif
1259 return;
1260 }
1261
1262 static int
1263 tty_cbreak( void ) // put terminal into a cbreak mode
1264 {
1265 if ( ttystate != CBREAK )
1266 {
1267 if ( tcsetattr( STDIN_FILENO, TCSAFLUSH, &termios_cbreak ) < 0 )
1268 return -1;
1269
1270 ttystate = CBREAK;
1271 }
1272 return 0;
1273 }
1274
1275 static int
1276 tty_reset( void ) // restore terminal's mode
1277 {
1278 if ( ttystate != RESET )
1279 {
1280 if ( tcsetattr( STDIN_FILENO, TCSAFLUSH, &termios_reset ) < 0 )
1281 return -1;
1282
1283 ttystate = RESET;
1284 }
1285 return 0;
1286 }
1287
1288 static void
1289 tty_atexit( void ) // exit handler
1290 {
1291 tty_reset();
1292 }
1293
1294 #endif // HAVE_TERMIOS_H
1295
1296 #else
1297 int pldummy_tek()
1298 {
1299 return 0;
1300 }
1301
1302 #endif // defined(PLD_xterm) || ...