1
/*===========================================================================
2
Copyright (C) 1986-2009 European Southern Observatory (ESO)
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; either version 2 of
7
the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public
15
License along with this program; if not, write to the Free
16
Software Foundation, Inc., 675 Massachusetss Ave, Cambridge,
19
Corresponding concerning ESO-MIDAS should be addressed as follows:
20
Internet e-mail: midas@eso.org
21
Postal address: European Southern Observatory
22
Data Management Division
23
Karl-Schwarzschild-Strasse 2
24
D 85748 Garching bei Muenchen
26
===========================================================================*/
28
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
31
.IDENTIFICATION tvcursor.c
32
.AUTHOR Francois Ochsenbein [ESO-IPG]
34
.KEYWORDS Terminal Independant i/o Package.
35
.ENVIRONMENT TermWindows
36
.COMMENTS This module includes functions to define and perform
37
scrolling, and cursor movements.
40
$$\begin{tabular}{|lp{30em}|} \hline
41
{\tt cm} & Move cursor to specified position \\
42
{\tt ff} & Form-feed \\
43
{\tt ho} & Move cursor to home (\ie [0,0]) position\\
44
{\tt cs} & Define a scrolling region \\
45
{\tt sf} & Scroll forwards (up) \\
46
{\tt sr} & Scroll reverse (down) \\
50
.VERSION 1.0 07-Jul-1986: Creation
51
.VERSION 1.1 23-Oct-1986 Flag the move to a newline, to ensure
52
that correct attributes are set even with HP's
53
(attributes end with end-of-line).
54
Take care of cursor move if a scrolling region
55
exists: reset first the scrolling region.
56
(added tv_sr0 to do this)
58
.VERSION 1.2 26-Nov-1986 Remove bug in tv_sr0
60
.VERSION 2.0 03-Dec-1986 New terminal-independant graphic characters
61
with output buffering version.
62
.VERSION 2.1 11-Jun-1987 Version '2'. Improvements for hard terminals.
63
.VERSION 2.2 23-Jun-1987 Adapted to UNIX and Minimal Implementation.
64
.VERSION 2.3 04-Dec-1987 Save and Get Cursor also save Attribute
65
.VERSION 3.0 20-Mar-1988 Version '3' of TermWindows.
66
.VERSION 3.1 06-Oct-1989 Be sure that tv_sr0 RESETS the scrolling region.
67
.VERSION 3.2 23-May-1990 Hard terminals up movement does nothing...
70
----------------------------------------------------------------------------*/
72
#define DEBUG 0 /* For debugging only */
74
#define PM_LEVEL LEVEL_TV
76
#define TW_MACROS 0 /* Don't use TermWindows Macros */
78
#define TW_STRUCT 0 /* Do not use window Structures */
81
extern int tv_buffer(), tv_where(), tv_goto(), tv_out();
82
extern int tv_attr(), tv_mvc(), tv_open(), tv_sr0();
83
extern int tv_nl(), tv_send(), tv_imode(), tv_il(), tv_delay();
85
extern int tu_format();
87
extern int pm_enter(), pm_iexit();
90
MID_EXTERN TERM *terms ;
92
#define SEND(p) tv_send(p,1)
95
# define TERMTEST if(!terms->version) tv_gopen();\
98
# define TERMTEST if(!terms->version) tv_gopen()
101
#define FINISH goto FIN
102
#define ENTER_TV(x) static int state_buffer; \
103
ENTER(x); TERMTEST; \
104
state_buffer = tv_buffer(1);
105
#define EXIT_TV(f) FIN: \
106
tv_buffer(state_buffer); \
110
MID_STATIC char ch=EOS;
111
MID_STATIC int type=0;
114
/* Macros just to improve readibility */
115
#define newl new_pos[0]
116
#define newc new_pos[1]
117
#define oldl old_pos[0]
118
#define oldc old_pos[1]
119
#define curl (terms->pos[0])
120
#define curc (terms->pos[1])
121
#define diml (terms->dim[0])
122
#define dimc (terms->dim[1])
123
#define BUFS (terms->bufs)
128
/*==========================================================================
130
*==========================================================================*/
131
static int tv_cm(line, col)
133
.PURPOSE Position the cursor using direct cursor addressing
134
.RETURNS OK / NOK (no direct addressing)
135
.REMARKS NO DELAY IS SENT HERE (for optimization).
136
NO TEST on validy of line and col.
137
*** For internal use ***. Not Traced.
139
int line; /* IN: Line number to move to */
140
int col; /* IN: Column number to move to */
142
short int new_pos[2];
147
status = tv_out(BUFS, tu_format(BUFS, terms->tt_cm, new_pos));
148
/* tv_delay(terms->tt_cm); */
153
/*==========================================================================
155
*==========================================================================*/
156
int tv_range(coo, limits)
158
.PURPOSE Verify and updates the cursor position versus limits.
159
Lines are numbered from 0 at the top of the screen; columns are
160
numbered from 0 at the left margin of the screen.
161
.RETURNS OK / NOK (cursor position modified)
164
short int coo[2]; /* MOD: Cursor position (line, col) to verify */
165
short int limits[2]; /* IN: Limits of the screen */
171
if(coo[0] < 0) { coo[0] = 0; s = NOK;}
172
if(coo[1] < 0) { coo[1] = 0; s = NOK;}
174
if(coo[0] >= limits[0]) { coo[0] = limits[0]-1; s = NOK;}
175
if(coo[1] >= limits[1]) { coo[1] = limits[1]-1; s = NOK;}
180
/*==========================================================================
182
*==========================================================================*/
185
.PURPOSE Returns the cursor position, as a number of characters
187
.RETURNS Position, in range [0, lines*cols]
191
return (terms->pos[0]*terms->dim[1] + terms->pos[1]);
194
/*==========================================================================
196
*==========================================================================*/
199
.PURPOSE Restore the cursor position.
202
-----------------------------------------------------------------------*/
203
TVSAVE *saved; /* IN: Old position + attribute */
207
status = tv_goto(saved->pos[0], saved->pos[1]);
208
tv_attr(saved->attr);
214
/*==========================================================================
216
*==========================================================================*/
219
.PURPOSE Save the current cursor position.
223
TVSAVE *saved; /* OUT: Current position + attribute */
225
saved->pos[0] = terms->pos[0];
226
saved->pos[1] = terms->pos[1];
227
saved->attr = terms->attr;
232
/*==========================================================================
234
*==========================================================================*/
237
.PURPOSE Position the cursor to a specified byte position.
238
Position are numbered from 0 at the top left corner to N-1 at bottom
240
.RETURNS Actual position
243
int pos; /* IN: Position to move to */
248
N = J * terms->dim[0];
255
/*==========================================================================
257
*==========================================================================*/
258
int tv_goto(line, col)
260
.PURPOSE Position the cursor to a specified line and column position on the screen.
261
Lines are numbered from 0 at the top of the screen; columns are
262
numbered from 0 at the left margin of the screen.
263
If full screen is not asked for, no test is performed on the
264
validity of line and column.
265
.RETURNS OK / NOK (not possible, e.g. up on a hard terminal)
266
.REMARKS An attempt to position the cursor off the screen will place it
268
NO DELAY IS SENT HERE. (for optimization)
270
int line; /* IN: Line number to move to */
271
int col; /* IN: Column number to move to */
273
short int new_pos[2];
274
short int old_pos[2];
280
tv_where(old_pos); /* Save current position */
283
tv_range(new_pos, terms->dim); /* Verify cursor within screen */
286
TRACE_ED_I("Old line ",oldl);
287
TRACE_ED_I(" ... col ",oldc);
288
TRACE_ED_I("Moving to line ",line);
289
TRACE_ED_I(" ... col ",col);
292
/* Optimize for move on the same line */
295
{ n = newc - oldc; /* Displacement */
296
if ( n == 0 ) FINISH; /* No move */
297
if ( (n > -3) && (n < 3) )
298
{ status = tv_mvc(_RIGHT_, n);
302
else terms->standout |= ChangedLine;
304
if ( (newl < terms->scregion[0]) || (newl > terms->scregion[1]) )
305
tv_sr0(); /* Reset scrolling region */
308
/* Optimize for a move to the left margin */
311
{ status = tv_out("\r",1);
315
if (newl == (oldl+1))
321
/* Cursor addressing capability MUST exist in Minimal Implementation */
324
status = tv_cm(newl, newc);
329
{ status = tv_cm(newl, newc);
335
/* Unknown terminal: use right-left, up-down mouvements ---
336
* but Optimize for move on the same line to the right */
339
{ n = newc - oldc; /* Displacement */
341
{ status = tv_mvc(_RIGHT_, n);
346
status = tv_out("\r",1); /* Go first to left margin */
349
n = newl - oldl; /* ... then move down ... */
355
/* ... move up if required... */
356
if(n) status = tv_mvc(_UP_, -n);
357
/* ... finally, move right */
358
status = tv_mvc(_RIGHT_, newc);
364
/*======================================================================
366
*======================================================================*/
369
.PURPOSE Move the cursor to home position
371
.REMARKS Minimal implementation: use goto(0,0)
375
MID_REGISTER char *p;
380
if (terms->scregion[0]) /* Reset scrolling region */
383
#if (TW_LEVEL == 0) /* Minimal Implementation */
386
#else /* --Full Implementation */
387
/* Look if "ho" possibility exists */
396
/* If up movements not available,
397
simply issue a newline
400
if(*terms->tt_ptr[_UP_] == 0)
403
/* Use up movements . Note that zt_mvc takes care of the
404
* existance or not of up movements. */
406
tv_out("\r",1); /* Go first to left margin */
408
status = tv_mvc(_UP_, curl);
414
/*======================================================================
416
*======================================================================*/
417
int tv_mvc(direction,times)
419
.PURPOSE Move the cursor n times in the specified direction: up, down,
420
right, left or newline.
421
.RETURNS OK / NOK (not possible, e.g. up on a hard terminal)
422
.REMARKS A negative number of times asks for the opposite direction.
423
If full screen is not asked for, no test on the number of
424
of cursor mouvements is performed.
425
--- Minimal Implementation: cursor movements ALWAYS exist.
427
int direction; /* IN: The direction of the displacement */
428
int times; /* IN: Number of times to move */
430
short int old_pos[2];
431
MID_RSTATIC short int step[2] = {-1, 1};
437
TRACE_ED_I("Moving to direction: ",direction);
438
TRACE_ED_I(".... times: ",times);
443
if (times == 0) FINISH;
445
tv_where(old_pos); /* Save current position */
446
init_attr = terms->attr_init;
448
tv_range(terms->pos, terms->dim); /* Test the cursor position */
450
k = direction >> 1; /* Lead to Horiz., Vert. or */
454
terms->standout |= ChangedLine;
456
n = times * step[direction & 1];
458
tv_range(terms->pos, terms->dim);
459
if (k == _HORIZONTAL_) n = curc - oldc;
461
default: /* _NEWLINE_ is assumed */
462
if ( (n = times) < 0) FINISH;
463
while (--n>=0) tv_nl();
466
k <<= 1; /* Final Direction */
471
#if (TW_LEVEL > 0) /* ==> Full Implementation */
473
{ case _UP_ : /* New line for hard terminals: Nothing */
474
if(*terms->tt_ptr[_UP_] == 0)
481
case _DOWN_ : /* Use newlines if cap' doesn't exist */
482
if (*terms->tt_ptr[_DOWN_] == 0)
485
while (--n >= 0) tv_nl();
492
case _LEFT_ : /* When capability doesn't exist, use \r
493
* then move to the right */
494
if (*terms->tt_ptr[_LEFT_] == 0)
496
n = curc; /* Blanks to move */
497
k = _RIGHT_; /* Next op. is RIGHT */
501
case _RIGHT_: /* Test if blank is used --- if so, don't
502
* forget to use standard attribute ! */
503
if (*(terms->tt_ptr[_RIGHT_] + 4) == ' ')
504
init_attr = terms->attr, tv_attr((int)terms->attr_init);
510
/* Send n times the sequence */
511
status = tv_send(terms->tt_ptr[k], n);
513
if (terms->attr_init != init_attr) /* If blanks used for _RIGHT_ */
519
/*==========================================================================
521
*==========================================================================*/
524
.PURPOSE New line, i.e. position the cursor to the beginning of the next line.
526
.REMARKS The cursor position is at the beginning of the next line.
527
The insert mode is switched off.
531
unsigned char old_attr;
538
/* First, switch off the insert mode if set */
543
curc = 0; /* The beginning of a line */
544
p = terms->tt_ptr[_NEWLINE_];
545
old_attr = terms->attr;
546
tv_attr(terms->attr_init);
549
if (curl >= diml) curl = diml -1;
557
/*======================================================================
559
*======================================================================*/
560
int tv_scroll(direction, times)
562
.PURPOSE Scroll n lines in the specified (_UP_ or _DOWN_) direction.
563
.RETURNS OK / NOK (always NOK in minimal implementation)
564
.REMARKS A negative number of times asks for the opposite direction. _UP_
567
int direction; /* IN: The direction of the displacement */
568
int times; /* IN: Number of lines to scroll */
570
#if (TW_LEVEL == 0) /* ===> Minimal Implementation */
572
#else /* ===> FULL Implementation */
577
ENTER_TV("tv_scroll");
580
TRACE_ED_I("Scrolling lines: ",times);
585
if (times == 0) FINISH;
589
if (times < 0) /* Change direction */
593
tv_cus(&saved); /* Save cursor position */
595
/* If no scrolling capability exist: move
596
to top or bottom of screen, and use
597
- down mouvements to scroll up
598
- insert lines to scroll down */
604
if (p) status = tv_send(p,n);
605
else status = tv_il(n);
608
{ tv_goto(terms->dim[0]-1, 0);
611
if (p) status = tv_send(p,n);
612
else status = tv_send(terms->tt_ptr[_DOWN_], n);
615
tv_cur(&saved); /* Restore Cursor */
621
/*==========================================================================
623
*==========================================================================*/
626
.PURPOSE Defines a scrolling region on the terminal between
628
Lines are numbered from 0 at the top of the screen.
629
.RETURNS OK, or NOK (capability does not exist)
630
.REMARKS On return, the cursor is at the left margin within the
632
It does not move if NOK is returned, or if the scrolling
633
region did not change.
635
int l1; /* IN: Upper line of the scrolling region */
636
int l2; /* IN: Lower line of the scrolling region */
639
short int scroll_lim[2];
644
p = SearchCap("cs"); /* Null pointer if terminal doesn't allow to
645
define scrolling regions */
649
terms->scregion[0] = 0; terms->scregion[1] = diml-1;
653
scroll_lim[0] = MIN(l1,l2);
654
scroll_lim[1] = MAX(l1,l2);
656
if(scroll_lim[0] < 0) scroll_lim[0] = 0;
657
if(scroll_lim[1] >= diml) scroll_lim[1] = diml-1;
659
if ( (terms->scregion[0] != scroll_lim[0]) ||
660
(terms->scregion[1] != scroll_lim[1]) )
662
if_not(status = tv_out(BUFS,tu_format(BUFS,p,scroll_lim)))
664
if_not(status = tv_delay(p)) FINISH;
665
terms->scregion[0] = scroll_lim[0];
666
terms->scregion[1] = scroll_lim[1];
668
if (curl < scroll_lim[0]) curl = scroll_lim[0];
669
if (curl > scroll_lim[1]) curl = scroll_lim[1];
671
if (*terms->tt_cm) /* If cursor addressing exists, use it */
679
/*==========================================================================
681
*==========================================================================*/
684
.PURPOSE Redefines the complete screen as the scrolling region.
685
.RETURNS OK / NOK (no change in scrolling region)
686
.REMARKS On return, cursor is at home position if OK returned,
692
/* Set the current scrolling region to (0,0) to force
693
a change in the tv_sr routine */
695
terms->scregion[0] = 0, terms->scregion[1] = 0;
697
status = tv_sr(0, diml-1);
703
/*==========================================================================
705
*==========================================================================*/
708
.PURPOSE Returns the current cursor position.
710
.REMARKS The position is adjusted within the screen limits.
713
short int coo[2]; /* OUT: current position: line (0=top), col (0=left) */
717
/* if (terms->flags & TERM_am);
718
else tv_range(coo, terms->dim);
720
tv_range(coo, terms->dim);