1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 /*LINTLIBRARY*/
41
42 #include <sys/types.h>
43 #include "curses_inc.h"
44
45 /*
46 * Cursor motion optimization routine. This routine takes as parameters
47 * the screen positions that the cursor is currently at, and the position
48 * you want it to be at, and it will move the cursor there very
49 * efficiently. It isn't really optimal, since several approximations
50 * are taken in the interests of efficiency and simplicity. The code
51 * here considers directly addressing the cursor, and also considers
52 * local motions using left, right, up, down, tabs, backtabs, vertical
53 * and horizontal addressing, and parameterized motions. It does not
54 * consider using home down, or taking advantage of automatic margins on
55 * any of the four directions. (Two of these directions, left and right,
56 * are well defined by the am and bw capabilities, but up and down are
57 * not defined, nor are tab or backtab off the ends.)
58 *
59 * General strategies considered:
60 * CA Direct Cursor Addressing
61 * LM Local Motions from the old position
62 * HR Home + Local Motions from upper left corner
63 * HDR Home Down + Local Motions from lower left corner
64 * CR CR + Local Motions from left margin
65 *
66 * Local Motions can include
67 * Up cuu, cuu1, vpa
68 * Down cud, cud1, vpa
69 * Left cul, cul1, hpa, bs, cbt
70 * Right cuf, cuf1, hpa, tab, char moved over
71 */
72
73 /* This is called _ISMARK2 so it doesn't conflict with _ISMARK1 in wrefresh.c */
74
75 #define _ISMARK2(x) (mks[(x) / BITSPERBYTE] & (1<<((x) % BITSPERBYTE)))
76
77 #define H_UP -1
78 #define H_DO 1
79
80 static int Newy;
81 static int _homefirst(int, int, int, int),
82 _mvrel(int, int, int, int, int),
83 _mvvert(int, int, int), _mvhor(int, int, int),
84 _mvright(int, int, int), _mvleft(int, int, int);
85
86 int
mvcur(int cury,int curx,int newy,int newx)87 mvcur(int cury, int curx, int newy, int newx)
88 {
89 int hu, /* cost home + relative */
90 hd, /* cost home-down + relative */
91 rl, /* cost relative */
92 cm; /* cost direct cursor motion */
93
94 /* obvious case */
95 if (cury == newy && curx == newx)
96 return (OK);
97
98 /* not in the right mode for cursor movement */
99 if (SP->fl_endwin)
100 return (ERR);
101
102 if (!move_standout_mode && curscr->_attrs && !SP->_mks)
103 _VIDS(A_NORMAL, curscr->_attrs);
104
105 if (!move_insert_mode && SP->phys_irm)
106 _OFFINSERT();
107
108 Newy = newy;
109
110 /* cost of using cm */
111 cm = _COST(Cursor_address);
112
113 rl = hd = hu = LARGECOST;
114
115 /* baudrate optimization */
116 if (cm < LARGECOST && SP->baud >= 2400 &&
117 cury >= 0 && cury < curscr->_maxy &&
118 curx >= 0 && curx < curscr->_maxx) {
119 if (cursor_down && (newy == (cury + 1)) &&
120 ((newx == curx) || (newx == 0 && carriage_return))) {
121 if (newx != curx)
122 _PUTS(carriage_return, 1);
123 _PUTS(cursor_down, 1);
124 goto done;
125 }
126
127 /* fast horizontal move */
128 if (cury == newy && newx < curx - 4 && newx > curx + 4) {
129 if (newx < curx)
130 rl = _mvleft(curx, newx, FALSE);
131 else
132 rl = _mvright(curx, newx, FALSE);
133 if (rl < cm) {
134 if (newx < curx)
135 rl = _mvleft(curx, newx, TRUE);
136 else
137 rl = _mvright(curx, newx, TRUE);
138 goto done;
139 }
140 }
141 }
142
143 /* cost using relative movements */
144 if (rl >= LARGECOST && cury >= 0 && cury < curscr->_maxy &&
145 curx >= 0 && curx < curscr->_maxx)
146 rl = _mvrel(cury, curx, newy, newx, FALSE);
147
148 /* cost of homing to upper-left corner first */
149 if (cursor_home)
150 hu = _homefirst(newy, newx, H_UP, FALSE);
151
152 /* cost of homing to lower-left corner first */
153 if (cursor_to_ll)
154 hd = _homefirst(newy, newx, H_DO, FALSE);
155
156 /* can't do any one of them */
157 if (cm >= LARGECOST && rl >= LARGECOST && hu >= LARGECOST &&
158 hd >= LARGECOST)
159 return (ERR);
160
161 /* do the best one */
162 if (cm <= rl && cm <= hu && cm <= hd)
163 _PUTS(tparm_p2(cursor_address, newy, newx), 1);
164 else
165 if (rl <= hu && rl <= hd)
166 (void) _mvrel(cury, curx, newy, newx, TRUE);
167 else
168 (void) _homefirst(newy, newx, hu <= hd ?
169 H_UP : H_DO, TRUE);
170
171 done:
172 /* update cursor position */
173 /*LINTED*/
174 curscr->_curx = (short) newx;
175 /*LINTED*/
176 curscr->_cury = (short) newy;
177
178 return (OK);
179 }
180
181 /* Move by homing first. */
182
183 static int
_homefirst(int ny,int nx,int type,int doit)184 _homefirst(int ny, int nx, int type, int doit)
185 {
186 char *home;
187 int cy, cost;
188
189 if (type == H_UP) {
190 home = cursor_home;
191 cost = _COST(Cursor_home);
192 cy = 0;
193 } else {
194 home = cursor_to_ll;
195 cost = _COST(Cursor_to_ll);
196 cy = curscr->_maxy - 1;
197 }
198
199 if (!home)
200 return (LARGECOST);
201 if (!doit)
202 return (cost + _mvrel(cy, 0, ny, nx, FALSE));
203
204 _PUTS(home, 1);
205 return (_mvrel(cy, 0, ny, nx, TRUE));
206 }
207
208 /* Move relatively */
209
210 static int
_mvrel(int cy,int cx,int ny,int nx,int doit)211 _mvrel(int cy, int cx, int ny, int nx, int doit)
212 {
213 int cv, ch;
214
215 /* do in this order since _mvhor may need the curscr image */
216 cv = _mvvert(cy, ny, doit);
217 ch = _mvhor(cx, nx, doit);
218
219 return (cv + ch);
220 }
221
222 /* Move vertically */
223
224 static int
_mvvert(int cy,int ny,int doit)225 _mvvert(int cy, int ny, int doit)
226 {
227 char *ve;
228 int dy, st_1, st_n, cv;
229
230 if (cy == ny)
231 goto out;
232
233 /* cost of stepwise movement */
234 if (cy < ny) {
235 dy = ny-cy;
236 st_1 = _COST(Cursor_down) * dy;
237 st_n = _COST(Parm_down_cursor);
238 } else {
239 dy = cy-ny;
240 st_1 = _COST(Cursor_up) * dy;
241 st_n = _COST(Parm_up_cursor);
242 }
243
244 /* cost of using vertical move */
245 cv = _COST(Row_address);
246
247 /* if calculating cost only */
248 if (!doit)
249 return ((cv < st_1 && cv < st_n) ? cv :
250 (st_n < st_1) ? st_n : st_1);
251
252 /* do it */
253 if (cv < st_1 && cv < st_n)
254 _PUTS(tparm_p1(row_address, ny), 1);
255 else
256 if (st_n < st_1) {
257 if (cy < ny)
258 _PUTS(tparm_p1(parm_down_cursor, dy), 1);
259 else
260 _PUTS(tparm_p1(parm_up_cursor, dy), 1);
261 } else {
262 if (cy < ny)
263 ve = cursor_down;
264 else
265 ve = cursor_up;
266 for (; dy > 0; --dy)
267 _PUTS(ve, 1);
268 }
269
270 out:
271 return (0);
272 }
273
274 /* Move horizontally */
275
276 static int
_mvhor(int cx,int nx,int doit)277 _mvhor(int cx, int nx, int doit)
278 {
279 int st, ch, hl;
280
281 if (cx == nx)
282 goto out;
283
284 /* cost using horizontal move */
285 ch = _COST(Row_address);
286
287 /* cost doing stepwise */
288 st = cx < nx ? _mvright(cx, nx, FALSE) : _mvleft(cx, nx, FALSE);
289
290 /* cost homeleft first */
291 hl = (_COST(Carriage_return) < LARGECOST) ?
292 _COST(Carriage_return) + _mvright(0, nx, FALSE) : LARGECOST;
293
294 if (!doit)
295 return ((ch < st && ch < hl) ? ch : (hl < st ? hl : st));
296
297 if (ch < st && ch < hl)
298 _PUTS(tparm_p1(column_address, nx), 1);
299 else
300 if (hl < st) {
301 _PUTS(carriage_return, 1);
302 (void) _mvright(0, nx, TRUE);
303 } else {
304 if (cx < nx)
305 (void) _mvright(cx, nx, TRUE);
306 else
307 (void) _mvleft(cx, nx, TRUE);
308 }
309 out:
310 return (0);
311 }
312
313 /* Move right. */
314
315 static int
_mvright(int cx,int nx,int doit)316 _mvright(int cx, int nx, int doit)
317 {
318 chtype *scp;
319 char *mks;
320 int nt, tx, x, stcost, iscont;
321
322 if (!cursor_right && !parm_right_cursor)
323 return (LARGECOST);
324
325 scp = curscr->_y[Newy];
326 mks = magic_cookie_glitch >= 0 ? SP->_mks[Newy] : NULL;
327
328 if (cursor_right) {
329 /* number of tabs used in stepwise movement */
330 nt = tab ? (nx / TABSIZE - cx / TABSIZE) : 0;
331 tx = (nt > 0) ? (cx / TABSIZE + nt) * TABSIZE : cx;
332
333 /* calculate stepwise cost */
334 stcost = nt * _COST(Tab);
335 iscont = 0;
336 for (x = tx; x < nx; ++x) {
337 if (iscont == 0 && !ISCBIT(scp[x]))
338 iscont = 1;
339 if ((!ceol_standout_glitch && !mks &&
340 _ATTR(scp[x]) == curscr->_attrs) ||
341 ceol_standout_glitch || (mks && !_ISMARK2(x))) {
342 if (!ISMBIT(scp[x]))
343 stcost += 1;
344 else if (iscont && !(nx - x == 1 && nx <
345 curscr->_maxx && ISCBIT(scp[nx])))
346 stcost += 1;
347 else
348 stcost += _COST(Cursor_right);
349 } else
350 stcost += _COST(Cursor_right);
351 }
352 } else
353 stcost = LARGECOST;
354
355 if (!doit)
356 return ((_COST(Parm_right_cursor) < stcost) ?
357 _COST(Parm_right_cursor) : stcost);
358
359 /* actually move */
360 if (_COST(Parm_right_cursor) < stcost)
361 _PUTS(tparm_p1(parm_right_cursor, nx-cx), 1);
362 else {
363 if (SP->phys_irm)
364 _OFFINSERT();
365 for (; nt > 0; --nt)
366 _PUTS(tab, 1);
367 iscont = 0;
368 for (x = tx; x < nx; ++x) {
369 if (iscont == 0 && !ISCBIT(scp[x]))
370 iscont = 1;
371 if ((!ceol_standout_glitch && !mks &&
372 _ATTR(scp[x]) == curscr->_attrs) ||
373 ceol_standout_glitch || (mks && !_ISMARK2(x))) {
374 if (!ISMBIT(scp[x]))
375 (void) _outwch(_CHAR(scp[x]));
376 else if (iscont && !(nx - x == 1 &&
377 nx < curscr->_maxx && ISCBIT(scp[nx])))
378 (void) _outwch(_CHAR(scp[x]));
379 else
380 _PUTS(cursor_right, 1);
381 } else
382 _PUTS(cursor_right, 1);
383 }
384 }
385
386 return (0);
387 }
388
389 /* Move left */
390
391 static int
_mvleft(int cx,int nx,int doit)392 _mvleft(int cx, int nx, int doit)
393 {
394 int tx, nt, x, stcost;
395
396 if (!cursor_left && !parm_left_cursor)
397 return (LARGECOST);
398
399 if (cursor_left) {
400 /* stepwise cost */
401 tx = cx;
402 nt = 0;
403 if (back_tab) {
404 /* the TAB position >= nx */
405 x = (nx % TABSIZE) ? (nx / TABSIZE + 1) * TABSIZE : nx;
406
407 /* # of tabs used and position after using them */
408 if (x < cx) {
409 nt = (cx / TABSIZE - x / TABSIZE) +
410 ((cx % TABSIZE) ? 1 : 0);
411 tx = x;
412 }
413 }
414 stcost = nt * _COST(Back_tab) + (tx-nx) * _COST(Cursor_left);
415 } else
416 stcost = LARGECOST;
417
418 /* get cost only */
419 if (!doit)
420 return ((_COST(Parm_left_cursor) < stcost) ?
421 _COST(Parm_left_cursor) : stcost);
422
423 /* doit */
424 if (_COST(Parm_left_cursor) < stcost)
425 _PUTS(tparm_p1(parm_left_cursor, cx - nx), 1);
426 else {
427 for (; nt > 0; --nt)
428 _PUTS(back_tab, 1);
429 for (; tx > nx; --tx)
430 _PUTS(cursor_left, 1);
431 }
432
433 return (0);
434 }
435