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