Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

435 lines
9.3 KiB
C

#ifdef _POWER_PROLOG_
static char sccsid[] = "@(#)40 1.8 src/bos/usr/ccs/lib/libcurses/mvcur.c, libcurses, bos411, 9428A410j 9/3/93 14:45:49";
/*
* COMPONENT_NAME: LIBCURSES
*
* FUNCTIONS: _ISMARK2
* _homefirst
* _mvhor
* _mvleft
* _mvrel
* _mvright
* _mvvert
* mvcur
*
*
* ORIGINS: 4
*
* SOURCE MATERIALS
*/
#endif /* _POWER_PROLOG_ */
/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/* #ident "@(#)curses:screen/mvcur.c 1.6" */
#include "curses_inc.h"
/*
* Cursor motion optimization routine. This routine takes as parameters
* the screen positions that the cursor is currently at, and the position
* you want it to be at, and it will move the cursor there very
* efficiently. It isn't really optimal, since several approximations
* are taken in the interests of efficiency and simplicity. The code
* here considers directly addressing the cursor, and also considers
* local motions using left, right, up, down, tabs, backtabs, vertical
* and horizontal addressing, and parameterized motions. It does not
* consider using home down, or taking advantage of automatic margins on
* any of the four directions. (Two of these directions, left and right,
* are well defined by the am and bw capabilities, but up and down are
* not defined, nor are tab or backtab off the ends.)
*
* General strategies considered:
* CA Direct Cursor Addressing
* LM Local Motions from the old position
* HR Home + Local Motions from upper left corner
* HDR Home Down + Local Motions from lower left corner
* CR CR + Local Motions from left margin
*
* Local Motions can include
* Up cuu, cuu1, vpa
* Down cud, cud1, vpa
* Left cul, cul1, hpa, bs, cbt
* Right cuf, cuf1, hpa, tab, char moved over
*/
/* This is called _ISMARK2 so it doesn't conflict with _ISMARK1 in wrefresh.c */
#define _ISMARK2(x) (mks[(x) / BITSPERBYTE] & (1<<((x) % BITSPERBYTE)))
#define H_UP -1
#define H_DO 1
static short Newy;
mvcur(cury, curx, newy, newx)
int cury, curx, newy, newx;
{
extern int _outch();
register int hu, /* cost home + relative */
hd, /* cost home-down + relative */
rl, /* cost relative */
cm; /* cost direct cursor motion */
/* obvious case */
if (cury == newy && curx == newx)
return (OK);
/* not in the right mode for cursor movement */
if (SP->fl_endwin)
return (ERR);
if (!move_standout_mode && curscr->_attrs && !SP->_mks)
_VIDS(A_NORMAL, curscr->_attrs);
if (!move_insert_mode && SP->phys_irm)
_OFFINSERT();
Newy = newy;
/* cost of using cm */
cm = _COST(Cursor_address);
rl = hd = hu = LARGECOST;
/* baudrate optimization */
if (cm < LARGECOST && SP->baud >= 2400 &&
cury >= 0 && cury < curscr->_maxy &&
curx >= 0 && curx < curscr->_maxx)
{
if (cursor_down && (newy == (cury + 1)) &&
((newx == curx) || (newx == 0 && carriage_return)))
{
if (newx != curx)
_PUTS(carriage_return, 1);
_PUTS(cursor_down, 1);
goto done;
}
/* fast horizontal move */
if (cury == newy && newx < curx-4 && newx > curx+4)
{
if (newx < curx)
rl = _mvleft(curx, newx, FALSE);
else
rl = _mvright(curx, newx, FALSE);
if (rl < cm)
{
if (newx < curx)
rl = _mvleft(curx, newx, TRUE);
else
rl = _mvright(curx, newx, TRUE);
goto done;
}
}
}
/* cost using relative movements */
if (rl >= LARGECOST &&
cury >= 0 && cury < curscr->_maxy &&
curx >= 0 && curx < curscr->_maxx)
rl = _mvrel(cury, curx, newy, newx, FALSE);
/* cost of homing to upper-left corner first */
if (cursor_home)
hu = _homefirst(newy, newx, H_UP, FALSE);
/* cost of homing to lower-left corner first */
if (cursor_to_ll)
hd = _homefirst(newy, newx, H_DO, FALSE);
/* can't do any one of them */
if (cm >= LARGECOST && rl >= LARGECOST && hu >= LARGECOST && hd >= LARGECOST)
return (ERR);
/* do the best one */
if (cm <= rl && cm <= hu && cm <= hd)
_PUTS(tparm(cursor_address, newy, newx), 1);
else
if (rl <= hu && rl <= hd)
(void) _mvrel(cury, curx, newy, newx, TRUE);
else
(void) _homefirst(newy, newx, hu <= hd ? H_UP : H_DO, TRUE);
done:
/* update cursor position */
curscr->_curx = newx;
curscr->_cury = newy;
return (OK);
}
/* Move by homing first. */
static
_homefirst(ny, nx, type, doit)
int ny, nx, type, doit;
{
extern int _outch();
register char *home;
register int cy, cost;
if (type == H_UP)
{
home = cursor_home;
cost = _COST(Cursor_home);
cy = 0;
}
else
{
home = cursor_to_ll;
cost = _COST(Cursor_to_ll);
cy = curscr->_maxy - 1;
}
if (!home)
return (LARGECOST);
if (!doit)
return (cost + _mvrel(cy, 0, ny, nx, FALSE));
_PUTS(home, 1);
return (_mvrel(cy, 0, ny, nx, TRUE));
}
/* Move relatively */
static
_mvrel(cy, cx, ny, nx, doit)
int cy, cx, ny, nx, doit;
{
register int cv, ch;
/* do in this order since _mvhor may need the curscr image */
cv = _mvvert(cy, ny, doit);
ch = _mvhor(cx, nx, doit);
return (cv + ch);
}
/* Move vertically */
static
_mvvert(cy, ny, doit)
int cy, ny, doit;
{
extern int _outch();
register char *ve;
register int dy, st_1, st_n, cv;
if (cy == ny)
goto out;
/* cost of stepwise movement */
if (cy < ny)
{
dy = ny-cy;
st_1 = _COST(Cursor_down) * dy;
st_n = _COST(Parm_down_cursor);
}
else
{
dy = cy-ny;
st_1 = _COST(Cursor_up) * dy;
st_n = _COST(Parm_up_cursor);
}
/* cost of using vertical move */
cv = _COST(Row_address);
/* if calculating cost only */
if (!doit)
return ((cv < st_1 && cv < st_n) ? cv : (st_n < st_1) ? st_n : st_1);
/* do it */
if (cv < st_1 && cv < st_n)
_PUTS(tparm(row_address, ny), 1);
else
if (st_n < st_1)
{
if (cy < ny)
_PUTS(tparm(parm_down_cursor, dy), 1);
else
_PUTS(tparm(parm_up_cursor, dy), 1);
}
else
{
if (cy < ny)
ve = cursor_down;
else
ve = cursor_up;
for (; dy > 0; --dy)
_PUTS(ve, 1);
}
out:
return (0);
}
/* Move horizontally */
static
_mvhor(cx, nx, doit)
int cx, nx, doit;
{
extern int _outch();
register int st, ch, hl;
if (cx == nx)
goto out;
/* cost using horizontal move */
ch = _COST(Row_address);
/* cost doing stepwise */
st = cx < nx ? _mvright(cx, nx, FALSE) : _mvleft(cx, nx, FALSE);
/* cost homeleft first */
hl = (_COST(Carriage_return) < LARGECOST) ?
_COST(Carriage_return) + _mvright(0, nx, FALSE) : LARGECOST;
if (!doit)
return ((ch < st && ch < hl) ? ch : (hl < st ? hl : st));
if (ch < st && ch < hl)
_PUTS(tparm(column_address, nx), 1);
else
if (hl < st)
{
_PUTS(carriage_return, 1);
(void) _mvright(0, nx, TRUE);
}
else
{
if (cx < nx)
(void) _mvright(cx, nx, TRUE);
else
(void) _mvleft(cx, nx, TRUE);
}
out:
return (0);
}
/* Move right. */
static
_mvright(cx, nx, doit)
int cx, nx, doit;
{
extern int _outch();
register chtype *scp;
register char *mks;
register int nt, tx, x, stcost;
if (!cursor_right && !parm_right_cursor)
return (LARGECOST);
scp = curscr->_y[Newy];
mks = magic_cookie_glitch >= 0 ? SP->_mks[Newy] : NULL;
if (cursor_right)
{
/* number of tabs used in stepwise movement */
nt = tab ? (nx / TABSIZE - cx / TABSIZE) : 0;
tx = (nt > 0) ? (cx / TABSIZE + nt) * TABSIZE : cx;
/* calculate stepwise cost */
stcost = nt * _COST(Tab);
for (x = tx; x < nx; ++x)
if ((!ceol_standout_glitch && !mks &&
_ATTR(scp[x]) == curscr->_attrs) ||
ceol_standout_glitch || (mks && !_ISMARK2(x)))
{
stcost += 1;
}
else
stcost += _COST(Cursor_right);
}
else
stcost = LARGECOST;
if (!doit)
return ((_COST(Parm_right_cursor) < stcost) ? _COST(Parm_right_cursor) : stcost);
/* actually move */
if (_COST(Parm_right_cursor) < stcost)
_PUTS(tparm(parm_right_cursor, nx-cx), 1);
else
{
if (SP->phys_irm)
_OFFINSERT();
for (; nt > 0; --nt)
_PUTS(tab, 1);
for (x = tx; x < nx; ++x)
if ((!ceol_standout_glitch && !mks &&
_ATTR(scp[x]) == curscr->_attrs) ||
ceol_standout_glitch || (mks && !_ISMARK2(x)))
{
_outch(_CHAR(scp[x]));
}
else
_PUTS(cursor_right, 1);
}
return (0);
}
/* Move left */
static
_mvleft(cx, nx, doit)
int cx, nx, doit;
{
extern int _outch();
register int tx, nt, x, stcost;
if (!cursor_left && !parm_left_cursor)
return (LARGECOST);
if (cursor_left)
{
/* stepwise cost */
tx = cx;
nt = 0;
if (back_tab)
{
/* the TAB position >= nx */
x = (nx % TABSIZE) ? (nx / TABSIZE + 1) * TABSIZE : nx;
/* # of tabs used and position after using them */
if (x < cx)
{
nt = (cx / TABSIZE - x / TABSIZE) + ((cx % TABSIZE) ? 1 : 0);
tx = x;
}
}
stcost = nt * _COST(Back_tab) + (tx-nx) * _COST(Cursor_left);
}
else
stcost = LARGECOST;
/* get cost only */
if (!doit)
return ((_COST(Parm_left_cursor) < stcost) ? _COST(Parm_left_cursor) : stcost);
/* doit */
if (_COST(Parm_left_cursor) < stcost)
_PUTS(tparm(parm_left_cursor, cx - nx), 1);
else
{
for (; nt > 0; --nt)
_PUTS(back_tab, 1);
for (; tx > nx; --tx)
_PUTS(cursor_left, 1);
}
return (0);
}