xref: /original-bsd/usr.bin/window/wwscroll.c (revision 04ace372)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)wwscroll.c	3.22 (Berkeley) 05/11/89";
20 #endif /* not lint */
21 
22 #include "ww.h"
23 #include "tt.h"
24 
25 wwscroll(w, n)
26 register struct ww *w;
27 int n;
28 {
29 	register dir;
30 	register top;
31 
32 	if (n == 0)
33 		return;
34 	dir = n < 0 ? -1 : 1;
35 	top = w->ww_b.t - n;
36 	if (top > w->ww_w.t)
37 		top = w->ww_w.t;
38 	else if (top + w->ww_b.nr < w->ww_w.b)
39 		top = w->ww_w.b - w->ww_b.nr;
40 	n = abs(top - w->ww_b.t);
41 	if (n < w->ww_i.nr) {
42 		while (--n >= 0) {
43 			(void) wwscroll1(w, w->ww_i.t, w->ww_i.b, dir, 0);
44 			w->ww_buf += dir;
45 			w->ww_b.t -= dir;
46 			w->ww_b.b -= dir;
47 		}
48 	} else {
49 		w->ww_buf -= top - w->ww_b.t;
50 		w->ww_b.t = top;
51 		w->ww_b.b = top + w->ww_b.nr;
52 		wwredrawwin(w);
53 	}
54 }
55 
56 /*
57  * Scroll one line, between 'row1' and 'row2', in direction 'dir'.
58  * Don't adjust ww_scroll.
59  * And don't redraw 'leaveit' lines.
60  */
61 wwscroll1(w, row1, row2, dir, leaveit)
62 register struct ww *w;
63 int row1, row2, dir;
64 int leaveit;
65 {
66 	register i;
67 	int row1x, row2x;
68 	int nvis;
69 	int nvismax;
70 	int scrolled = 0;
71 
72 	/*
73 	 * See how many lines on the screen are affected.
74 	 * And calculate row1x, row2x, and left at the same time.
75 	 */
76 	for (i = row1; i < row2 && w->ww_nvis[i] == 0; i++)
77 		;
78 	if (i >= row2)			/* can't do any fancy stuff */
79 		goto out;
80 	row1x = i;
81 	for (i = row2 - 1; i >= row1 && w->ww_nvis[i] == 0; i--)
82 		;
83 	if (i <= row1x)
84 		goto out;		/* just one line is easy */
85 	row2x = i + 1;
86 
87 	/*
88 	 * See how much of this window is visible.
89 	 */
90 	nvismax = wwncol * (row2x - row1x);
91 	nvis = 0;
92 	for (i = row1x; i < row2x; i++)
93 		nvis += w->ww_nvis[i];
94 
95 	/*
96 	 * If it's a good idea to scroll and the terminal can, then do it.
97 	 */
98 	if (nvis < nvismax / 2)
99 		goto no_scroll;		/* not worth it */
100 	if ((dir > 0 ? tt.tt_scroll_down == 0 : tt.tt_scroll_up == 0) ||
101 	    (tt.tt_scroll_top != row1x || tt.tt_scroll_bot != row2x - 1) &&
102 	    tt.tt_setscroll == 0)
103 		if (tt.tt_delline == 0 || tt.tt_insline == 0)
104 			goto no_scroll;
105 	xxscroll(dir, row1x, row2x);
106 	scrolled = 1;
107 	/*
108 	 * Fix up the old screen.
109 	 */
110 	{
111 		register union ww_char *tmp;
112 		register union ww_char **cpp, **cqq;
113 
114 		if (dir > 0) {
115 			cpp = &wwos[row1x];
116 			cqq = cpp + 1;
117 			tmp = *cpp;
118 			for (i = row2x - row1x; --i > 0;)
119 				*cpp++ = *cqq++;
120 			*cpp = tmp;
121 		} else {
122 			cpp = &wwos[row2x];
123 			cqq = cpp - 1;
124 			tmp = *cqq;
125 			for (i = row2x - row1x; --i > 0;)
126 				*--cpp = *--cqq;
127 			*cqq = tmp;
128 		}
129 		for (i = wwncol; --i >= 0;)
130 			tmp++->c_w = ' ';
131 	}
132 
133 no_scroll:
134 	/*
135 	 * Fix the new screen.
136 	 */
137 	if (nvis == nvismax) {
138 		/*
139 		 * Can shift whole lines.
140 		 */
141 		if (dir > 0) {
142 			{
143 				register union ww_char *tmp;
144 				register union ww_char **cpp, **cqq;
145 
146 				cpp = &wwns[row1x];
147 				cqq = cpp + 1;
148 				tmp = *cpp;
149 				for (i = row2x - row1x; --i > 0;)
150 					*cpp++ = *cqq++;
151 				*cpp = tmp;
152 			}
153 			if (scrolled) {
154 				register char *p, *q;
155 
156 				p = &wwtouched[row1x];
157 				q = p + 1;
158 				for (i = row2x - row1x; --i > 0;)
159 					*p++ = *q++;
160 				*p |= WWU_TOUCHED;
161 			} else {
162 				register char *p;
163 
164 				p = &wwtouched[row1x];
165 				for (i = row2x - row1x; --i >= 0;)
166 					*p++ |= WWU_TOUCHED;
167 			}
168 			wwredrawwin1(w, row1, row1x, dir);
169 			wwredrawwin1(w, row2x - 1, row2 - leaveit, dir);
170 		} else {
171 			{
172 				register union ww_char *tmp;
173 				register union ww_char **cpp, **cqq;
174 
175 				cpp = &wwns[row2x];
176 				cqq = cpp - 1;
177 				tmp = *cqq;
178 				for (i = row2x - row1x; --i > 0;)
179 					*--cpp = *--cqq;
180 				*cqq = tmp;
181 			}
182 			if (scrolled) {
183 				register char *p, *q;
184 
185 				p = &wwtouched[row2x];
186 				q = p - 1;
187 				for (i = row2x - row1x; --i > 0;)
188 					*--p = *--q;
189 				*q |= WWU_TOUCHED;
190 			} else {
191 				register char *p;
192 
193 				p = &wwtouched[row1x];
194 				for (i = row2x - row1x; --i >= 0;)
195 					*p++ |= WWU_TOUCHED;
196 			}
197 			wwredrawwin1(w, row1 + leaveit, row1x + 1, dir);
198 			wwredrawwin1(w, row2x, row2, dir);
199 		}
200 	} else {
201 		if (scrolled) {
202 			register char *p;
203 
204 			p = &wwtouched[row1x];
205 			for (i = row2x - row1x; --i >= 0;)
206 				*p++ |= WWU_TOUCHED;
207 		}
208 out:
209 		if (dir > 0)
210 			wwredrawwin1(w, row1, row2 - leaveit, dir);
211 		else
212 			wwredrawwin1(w, row1 + leaveit, row2, dir);
213 	}
214 	return scrolled;
215 }
216