aboutsummaryrefslogtreecommitdiff
path: root/sys/gio/cursor/rcursor.x
blob: cc7dc739eb6aa8e07d18ba5eaa25750788fd7a22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include	<ctype.h>
include	<ttset.h>
include	<gio.h>
include	<gki.h>
include	"gtr.h"
include	"grc.h"

define	SZ_CHARCON	5
define	MARKLEN		0.01

# Cursor step algorithm parameters.

define	MAX_STEP	0.1		# max cursor step size, cursor motions
define	MIN_STEP	0.002		# min cursor step size, cursor motions
define	LARGER_STEP	2.0		# factor by which step size is increased
define	SMALLER_STEP	0.5		# factor by step size is decreased
define	NSTEP		2		# number of steps before larger step
define	MANUAL_STEP	5.0		# gear ratio for F/V cursor control
define	SLOW		1		# for fast/slow algorithm
define	FAST		2

# Zoom parameters.

define	X_ZOOMFACTOR	0.5		# zoom factors
define	Y_ZOOMFACTOR	0.5
#define	X_ZOOMFACTOR	0.666		# zoom factors
#define	Y_ZOOMFACTOR	0.666

# Roam factors.

define	X_ROAM		0.333		# fraction of the current window
define	Y_ROAM		0.333		# fraction of the current window


# RCURSOR -- Read the position of a cursor.  This is the main entry point to
# cursor mode/cursor input from the CL; we are called by the QUERY procedure
# of the CL when a cursor type parameter is read.  The cursor position is
# returned as a string of the form
#
#	x y wcs key stringval
#
# where the "stringval" field may be absent if not appropriate for a given key.
# If EOF is returned the cursor value string is undefined.

int procedure rcursor (stream, outstr, maxch)

int	stream			# graphics stream
char	outstr[ARB]		# encoded cursor value (output)
int	maxch

bool	cminit
int	xroam[9], yroam[9]
pointer	rc, tr, sp, lbuf, ip
char	charcon[SZ_CHARCON], ch
real	x1, x2, y1, y2, xt, yt, v[10]
real	lx1, lx2, ly1, ly2, aspect_ratio
real	x, y, rx, ry, xw, yw, dx, dy, xc, yc
int	junk, key, nukey, last_zoom, i, wcs, ppos, ucasein, raster

bool	ttygetb()
pointer	grc_open()
int	envfind(), ctocc(), oscmd(), gtr_readcursor(), grc_readtty()
int	grc_cursor(), grc_command(), grc_selectwcs(), grc_mapkey(), ttstati()
real	ttygetr()

errchk	grc_text, grc_readtty, grc_writecursor
errchk	grc_init, grc_open, grc_command, grc_cursor, grc_message
errchk	grc_readcursor, grc_mapkey, grc_redraw, envfind

data	xroam /1,0,-1,1,0,-1,1,0,-1/
data	yroam /1,1,1,0,0,0,-1,-1,-1/
data	rc /NULL/
define	done_ 91
define	coloncmd_ 92

begin
	call smark (sp)
	call salloc (lbuf, SZ_COMMAND, TY_CHAR)

	# Allocate and initialize the RCURSOR descriptor.
	if (rc == NULL) {
	    call grc_init (rc)
	    cminit = true
	} else
	    cminit = false

	# Open or reopen the graphics kernel.
	tr = grc_open ("", APPEND, stream, rc)

	# Process CMINIT command string, if present in environment.  This is
	# only done once.

	if (cminit) {
	    if (envfind ("cminit", Memc[lbuf], SZ_COMMAND) > 0) {
		ip = lbuf
		while (IS_WHITE(Memc[ip]) || Memc[ip] == '.')
		    ip = ip + 1
		junk = grc_command (rc, stream, 0.,0.,0,0.,0., Memc[ip])
	    }
	    cminit = false
	}

	# If the graphics device does not permit input, i.e., does not have
	# a cursor, return EOF.

	if (!ttygetb (TR_TTY(tr), "in")) {
	    x = 0; y = 0
	    key = EOF
	    goto done_
	}

	# Determine if input keys are to be mapped to lower case by default,
	# i.e., ucasein mode has been set for the terminal driver.

	ucasein = ttstati (STDIN, TT_UCASEIN)

	last_zoom = 3
	ppos = NO

	# Enter cursor mode loop.  The loop terminates when a non cursor mode
	# keystroke is typed.

	while (grc_cursor (rc, stream, key,x,y, raster,rx,ry, ppos) != EOF) {
	    Memc[lbuf] = EOS

	    # As a rule, no processing is performed on escaped keys.  The only
	    # exception is when ucasein mode is set in the terminal driver,
	    # causing upper case input to be mapped to lower case.  This mapping
	    # is disabled in a raw mode cursor read, hence we must perform the
	    # mapping explicitly here, returning a lower case key to the
	    # applications program.  Unescaped upper case input keystrokes will
	    # be intercepted by cursor mode when ucasein mode is in effect.

	    if (key == '\\') {
		junk = gtr_readcursor (stream, key, x, y, raster, rx, ry)
		if (ucasein == YES && IS_UPPER(key))
		    key = TO_LOWER (key)
		break
	    }

	    # Map keystroke.  If the keystroke maps to a null value the key
	    # is not recognized as a cursor mode keystroke and we exit.

	    if (grc_mapkey (rc, key, nukey) == NULL)
		break

	    switch (nukey) {
	    case 'M':
		# Move the feature under the cursor to the center of the
		# screen without changing the scaling.

		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, x1, x2, y1, y2)
		xw = (x2 - x1) / 2.
		yw = (y2 - y1) / 2.
		call gtr_ptran (stream, xc-xw, xc+xw, yc-yw, yc+yw)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call grc_restorecurpos (stream, xc, yc)

	    case 'Z':
		# Zoom in in both X and Y.
		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, x1, x2, y1, y2)
		xw = (x2 - x1) * X_ZOOMFACTOR / 2.
		yw = (y2 - y1) * Y_ZOOMFACTOR / 2.
		call gtr_ptran (stream, xc-xw, xc+xw, yc-yw, yc+yw)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call grc_restorecurpos (stream, xc, yc)
		last_zoom = 3

	    case 'X':
		# Zoom in in X.
		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, x1, x2, y1, y2)
		xw = (x2 - x1) * X_ZOOMFACTOR / 2.
		call gtr_ptran (stream, xc-xw, xc+xw, y1, y2)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call grc_restorecurpos (stream, xc, yc)
		last_zoom = 1

	    case 'Y':
		# Zoom in in Y.
		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, x1, x2, y1, y2)
		yw = (y2 - y1) * Y_ZOOMFACTOR / 2.
		call gtr_ptran (stream, x1, x2, yc-yw, yc+yw)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call grc_restorecurpos (stream, xc, yc)
		last_zoom = 2

	    case '>':
		# Zoom in in Y by setting the upper limit of the viewport
		# to the cursor Y position.

		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, lx1, lx2, ly1, ly2)
		call gtr_ptran (stream, lx1, lx2, ly1,  yc)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call gtr_writecursor (stream, x, 0.5)
		last_zoom = 'E'

	    case '<':
		# Zoom in in Y by setting the lower limit of the viewport
		# to the cursor Y position.

		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, lx1, lx2, ly1, ly2)
		call gtr_ptran (stream, lx1, lx2,  yc, ly2)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call gtr_writecursor (stream, x, 0.5)
		last_zoom = 'E'

	    case 'E':
		# Expand by marking corners of new viewport.  If the range is
		# small in either X or Y only the other axis will be expanded.

		call gtr_gtran (stream, lx1, lx2, ly1, ly2)
		call grc_scrtondc (x, y, x1, y1)
		call grc_message (stream, "again:")
		junk = grc_cursor (rc, stream, key,x2,y2, raster,rx,ry, ppos)
		call grc_scrtondc (x2, y2, x2, y2)

		if (x1 > x2)
		    { xt = x2;  x2 = x1;  x1 = xt }
		if (y1 > y2)
		    { yt = y2;  y2 = y1;  y1 = yt }

		if (abs (x1 - x2) < .01)
		    call gtr_ptran (stream, lx1, lx2, y1, y2)
		else if (abs (y1 - y2) < .01)
		    call gtr_ptran (stream, x1, x2, ly1, ly2)
		else
		    call gtr_ptran (stream, x1, x2, y1, y2)

		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call gtr_writecursor (stream, 0.5, 0.5)
		last_zoom = 'E'

	    case 'P':
		# Zoom out.
		call grc_scrtondc (x, y, xc, yc)
		call gtr_gtran (stream, x1, x2, y1, y2)

		if (last_zoom == 'E') {
		    call gtr_ptran (stream, lx1, lx2, ly1, ly2)
		    lx1 = x1; lx2 = x2; ly1 = y1; ly2 = y2
		} else {
		    if (last_zoom == 1 || last_zoom == 3) {
			xw = (x2 - x1) / X_ZOOMFACTOR / 2.
			x1 = xc - xw
			x2 = xc + xw
		    }
		    if (last_zoom == 2 || last_zoom == 3) {
			yw = (y2 - y1) / Y_ZOOMFACTOR / 2.
			y1 = yc - yw
			y2 = yc + yw
		    }
		    call gtr_ptran (stream, x1, x2, y1, y2)
		}

		call grc_redraw (rc, stream, x, y, raster, rx, ry)
		call grc_restorecurpos (stream, xc, yc)

	    case 'W':
		# Select and fix WCS to be used for scr->wcs coordinate
		# transformations.

		call grc_scrtondc (x, y, xc, yc)
		TR_WCS(tr) = grc_selectwcs (tr, raster, xc, yc)

	    case 'C':
		# Running tally of cursor position.
		#if (ppos == NO) {
		#    call grc_pcursor (stream, x, y, raster, rx, ry)
		#    ppos = YES
		#} else {
		#    call grc_message (stream, "\n\n")
		#    ppos = NO
		#}

		call grc_pcursor (stream, x, y, raster, rx, ry)

	    case 'D':
		# Draw a line by marking the endpoints.
		call grc_scrtondc (x, y, v[1], v[2])
		call grc_message (stream, "again:")
		junk = grc_cursor (rc, stream, key,x2,y2, raster,rx,ry, ppos)
		call grc_scrtondc (x2, y2, v[3], v[4])
		call grc_polyline (stream, v, 2)

	    case 'T':
		# Draw a text string.
		if (grc_readtty (stream, "text: ", Memc[lbuf], SZ_COMMAND) <= 0)
		    next
		call grc_scrtondc (x, y, xc, yc)
		call grc_text (stream, xc, yc, Memc[lbuf])

	    case 'A':
		# Draw and label the axes of the viewport.
		call grc_axes (stream, x, y, raster, rx, ry)

	    case 'B':
		# Backup one instruction in the frame buffer.
		call gtr_backup (stream)

	    case 'U':
		# Undo the last frame buffer edit.
		call gtr_undo (stream)

	    case 'R':
		# Redraw the screen.
		call grc_redraw (rc, stream, x, y, raster, rx, ry)

	    case '0':
		# Reset and redraw.
		call gtr_ptran (stream, 0., 1., 0., 1.)
		call gtr_writecursor (stream, .5, .5)
		call grc_redraw (rc, stream, x, y, raster, rx, ry)

	    case '5':
		# Redraw (null roam request).
		call grc_redraw (rc, stream, x, y, raster, rx, ry)

	    case '1','2','3','4','6','7','8','9':
		# Roam.
		i = TO_INTEG (key)
		if (xroam[i] != 0 || yroam[i] != 0) {
		    call gtr_gtran (stream, x1, x2, y1, y2)
		    dx = (x2 - x1) * X_ROAM * xroam[i]
		    dy = (y2 - y1) * Y_ROAM * yroam[i]
		    call gtr_ptran (stream, x1+dx, x2+dx, y1+dy, y2+dy)
		    call grc_redraw (rc, stream, x, y, raster, rx, ry)
		}

	    case ':':
		# Enter a colon command string and terminate cursor mode.

		# Get the string value.
		if (grc_readtty (stream, ":", Memc[lbuf], SZ_COMMAND) <= 0)
		    next

		# All cursor mode commands must begin with a ".".  An osescape
		# begins with an "!".

		if (Memc[lbuf] == '!') {
		    call gtr_page (STDERR, stream)
		    if (oscmd (Memc[lbuf+1], "", "", "") == ERR)
			call fprintf (STDERR, "\7")
		    call gtr_waitpage (STDERR, stream)
		    
		} else if (Memc[lbuf] == '.') {
		    # Save viewport for 'P'.
coloncmd_
		    call gtr_gtran (stream, lx1, lx2, ly1, ly2)
		    last_zoom = 'E'

		    TR_WAITPAGE(tr) = NO
		    if (grc_command (rc, stream, x, y, raster, rx, ry,
			    Memc[lbuf+1]) == EOF) {
			key = EOF
			goto done_
		    }

		    # The following is a no-op for most colon commands.
		    if (TR_WAITPAGE(tr) == YES)
			call gtr_waitpage (STDERR, stream)
		} else
		    break

	    case '=':
		# Shorthand for :.snap.  The latter must be used once to
		# set the plotter device, else the default stdplot device
		# will be used.

		call strcpy (".snap", Memc[lbuf], SZ_COMMAND)
		goto coloncmd_

	    default:
		call fprintf (STDERR, "\007")
	    }
	}

	# Mark the cursor position if markcur enabled.
	if (RC_MARKCUR(rc) == YES && key != EOF) {
	    call grc_scrtondc (x, y, xc, yc)
	    aspect_ratio = ttygetr (TR_TTY(tr), "ar")
	    if (aspect_ratio < .001)
		aspect_ratio = 1.0

	    v[1]  = xc - MARKLEN * aspect_ratio
	    v[2]  = yc
	    v[3]  = xc + MARKLEN * aspect_ratio
	    v[4]  = yc
	    v[5]  = xc
	    v[6]  = yc
	    v[7]  = xc
	    v[8]  = yc - MARKLEN
	    v[9]  = xc
	    v[10] = yc + MARKLEN
	    call grc_polyline (stream, v, 5)
	}

	# Close the workstation, leave graphics mode, position alpha cursor to
	# lower left corner of graphics terminal.

	call grc_close (stream, rc)

	# Encode the cursor value as a string for the CL.
done_
	if (key != EOF) {
	    if (key == ' ')
		call strcpy ("\\40", charcon, SZ_CHARCON)
	    else {
		ch = char (key)
		junk = ctocc (ch, charcon, SZ_CHARCON)
	    }
	    call grc_scrtowcs (stream, x, y, raster, rx, ry, xc, yc, wcs)

	    call sprintf (outstr, maxch, "%g %g %d %s %s\n")
		call pargr (xc)
		call pargr (yc)
		call pargi (wcs)
		call pargstr (charcon)
		call pargstr (Memc[lbuf])
	} else
	    outstr[1] = EOS

	call sfree (sp)
	return (key)
end


# GRC_CURSOR -- Read the position of a cursor in screen coordinates.  Recognizes
# the cursor movement keystrokes H, J, K, and L, exiting only when some other
# keystroke is received.  The cursor movement algorithm is initialized upon
# entry.  Two algorithms are provided for controlling the cursor step size.
# The first algorithm (automatic control) starts with a large initial step
# size.  In the vicinity of a feature the cursor will overshoot the feature
# and the user will step back in the opposite direction, causing the step size
# to be decreased, rapidly converging to the desired position.  Several steps
# in the same direction cause the large step size to be restored.  The second
# algorithm (manual control) uses the F and V keys to directly control the step
# size.

int procedure grc_cursor (rc, stream, key, x, y, raster, rx, ry, ppos)

pointer	rc			#I rcursor descriptor
int	stream			#I graphics stream
int	key			#O keystroke typed
real	x, y			#O cursor screen coordinates
int	raster			#O raster number
real	rx, ry			#O cursor raster coordinates
int	ppos			#I print cursor position flag

int	speed
int	xdir, ydir, nukey
real	xstep, ystep, newx, newy

bool	ttygetb()
pointer	gtr_gtty()
int	gtr_readcursor(), grc_mapkey()
errchk	gtr_readcursor, gtr_writecursor

begin
	# Reset the cursor step size to the default.
	xstep = MAX_STEP
	ystep = MAX_STEP
	xdir  = 0
	ydir  = 0
	speed = 0

	while (gtr_readcursor (stream, key, x, y, raster, rx, ry) != EOF) {
	    if (grc_mapkey (rc, key, nukey) == NULL)
		break

	    newx = x
	    newy = y

	    switch (nukey) {
	    case 'F':
		# Faster.
		xstep = min (MAX_STEP, xstep * MANUAL_STEP)
		ystep = min (MAX_STEP, ystep * MANUAL_STEP)
		speed = FAST

	    case 'V':
		# Slower.
		xstep = max (MIN_STEP, xstep / MANUAL_STEP)
		ystep = max (MIN_STEP, ystep / MANUAL_STEP)
		speed = SLOW

	    case 'H':
		# Step cursor left.
		if (speed == 0)
		    if (xdir < -NSTEP) {
			xstep = MAX_STEP
			xdir = -1
		    } else if (xdir > 0) {
			xstep = max (MIN_STEP, xstep * SMALLER_STEP)
			xdir = -1
		    } else
			xdir = xdir - 1
		newx = newx - xstep
		call gtr_writecursor (stream, newx, newy)

	    case 'J':
		# Step cursor down.
		if (speed == 0)
		    if (ydir < -NSTEP) {
			ystep = MAX_STEP
			ydir = -1
		    } else if (ydir > 0) {
			ystep = max (MIN_STEP, ystep * SMALLER_STEP)
			ydir = -1
		    } else
			ydir = ydir - 1
		newy = newy - ystep
		call gtr_writecursor (stream, newx, newy)

	    case 'K':
		# Step cursor up.
		if (speed == 0)
		    if (ydir > NSTEP) {
			ystep = MAX_STEP
			ydir = 1
		    } else if (ydir < 0) {
			ystep = max (MIN_STEP, ystep * SMALLER_STEP)
			ydir = 1
		    } else
			ydir = ydir + 1
		newy = newy + ystep
		call gtr_writecursor (stream, newx, newy)

	    case 'L':
		# Step cursor right.
		if (speed == 0)
		    if (xdir > NSTEP) {
			xstep = MAX_STEP
			xdir = 1
		    } else if (xdir < 0) {
			xstep = max (MIN_STEP, xstep * SMALLER_STEP)
			xdir = 1
		    } else
			xdir = xdir + 1
		newx = newx + xstep
		call gtr_writecursor (stream, newx, newy)
	    
	    default:
		break
	    }

	    # We assume the cursor may have moved if the WC capability exists
	    # for this device.

	    if (ttygetb (gtr_gtty (stream), "WC")) {
		x = newx
		y = newy
	    }

	    # Print the cursor position.
	    if (ppos == YES)
		call grc_pcursor (stream, x, y, raster, rx, ry)
	}

	return (key)
end


# GRC_MAPKEY -- Map keystroke.  If the keystroke maps to a null value the key
# is not recognized as a cursor mode keystroke and we exit.  Note that if case
# sensitivity is disabled, KEYS comparisions must be made in upper case but
# only lower case is to be returned to the calling program.

int procedure grc_mapkey (rc, key, nukey)

pointer	rc			#I rcursor descriptor
int	key			#U raw key value
int	nukey			#O mapped key value

begin
	nukey = max(1, min(MAX_KEYS, key))
	if (RC_CASE(rc) == NO && IS_LOWER(nukey))
	    nukey = TO_UPPER(nukey)

	nukey = RC_KEYS(rc,nukey)
	if (nukey == NULL) {
	    # Not a cursor mode key.
	    if (RC_CASE(rc) == NO && IS_UPPER(nukey))
		key = TO_LOWER(key)
	} else if (IS_LOWER(nukey))
	    nukey = TO_UPPER(nukey)

	return (nukey)
end


# GRC_RESTORECURPOS -- Restore the cursor position in NDC coordinates
# regardless of the current workstation transformation.

procedure grc_restorecurpos (stream, x, y)

int	stream			# graphics stream
real	x, y			# new cursor position in NDC coords
real	sx, sy
include	"gtr.com"

begin
	call grc_ndctoscr (x, y, sx, sy)
	call gtr_writecursor (stream, sx, sy)
end


# GRC_READTTY -- Read from the terminal via the graphics kernel.  If the
# kernel already has message data buffered we merely return that data,
# otherwise we issue the prompt given and interactively read the data.

int procedure grc_readtty (stream, prompt, obuf, maxch)

int	stream			#I graphics stream
char	prompt[ARB]		#I prompt, if read is interactive
char	obuf[ARB]		#O output buffer
int	maxch			#I max chars out

bool	issue_prompt
int	nchars, index
int	stg_msglen(), stg_readtty()
int	stridxs(), strlen()

begin
	issue_prompt = (stg_msglen(STDIN) <= 0)
	if (issue_prompt)
	    call stg_putline (STDERR, prompt)

	nchars = stg_readtty (STDIN, obuf, maxch)
	index = stridxs ("\n", obuf)
	if (index > 0)
	    obuf[index] = EOS
	nchars = strlen (obuf)

	if (issue_prompt && nchars == 0)
	    call grc_message (stream, "\n\n")

	return (nchars)
end


# GRC_MESSAGE -- Write a message on the status line at the bottom of the
# screen.  If the string is not newline terminated the terminal is left in
# status line text mode.  To clear the status line and force the terminal
# back into graphics mode, output the string "\n\n".

procedure grc_message (stream, message)

int	stream			# graphics stream
char	message[ARB]		# message to be printed

begin
	call stg_putline (STDERR, message)
end


# GRC_PCURSOR -- Convert the cursor position in screen coordinates to world
# coordinates and print on the standard output.

procedure grc_pcursor (stream, sx, sy, raster, rx, ry)

int	stream			#I graphics stream
real	sx, sy			#I screen coords of cursor
int	raster			#I raster number
real	rx, ry			#I raster coords of cursor

int	wcs
real	xc, yc
pointer	sp, lbuf

begin
	call smark (sp)
	call salloc (lbuf, SZ_LINE, TY_CHAR)

	call grc_scrtowcs (stream, sx, sy, raster, rx, ry, xc, yc, wcs)
	if (abs(xc) > 1 && abs(xc) < 10000 && abs(yc) > 1 && abs(yc) < 10000)
	    call sprintf (Memc[lbuf], SZ_LINE, "%10.3f %10.3f  \n")
	else
	    call sprintf (Memc[lbuf], SZ_LINE, "%12.7g %12.7g  \n")
	call pargr (xc)
	call pargr (yc)

	call stg_putline (STDERR, Memc[lbuf])
	call sfree (sp)
end