xref: /original-bsd/usr.bin/window/wwscroll.c (revision e74403ba)
1 #ifndef lint
2 static	char *sccsid = "@(#)wwscroll.c	3.11 83/12/02";
3 #endif
4 
5 #include "ww.h"
6 #include "tt.h"
7 
8 wwscroll(w, n)
9 register struct ww *w;
10 int n;
11 {
12 	register dir;
13 	register top;
14 
15 	if (n == 0)
16 		return;
17 	dir = n < 0 ? -1 : 1;
18 	top = w->ww_b.t - n;
19 	if (top > w->ww_w.t)
20 		top = w->ww_w.t;
21 	else if (top + w->ww_b.nr < w->ww_w.b)
22 		top = w->ww_w.b - w->ww_b.nr;
23 	n = abs(top - w->ww_b.t);
24 	if (n < w->ww_i.nr) {
25 		while (--n >= 0) {
26 			(void) wwscroll1(w, w->ww_i.t, w->ww_i.b, dir, 0);
27 			w->ww_buf += dir;
28 			w->ww_b.t -= dir;
29 			w->ww_b.b -= dir;
30 		}
31 	} else {
32 		w->ww_buf -= top - w->ww_b.t;
33 		w->ww_b.t = top;
34 		w->ww_b.b = top + w->ww_b.nr;
35 		wwredrawwin(w);
36 	}
37 }
38 
39 /*
40  * Scroll one line, between 'row1' and 'row2', in direction 'dir'.
41  * Don't adjust ww_scroll.
42  * And don't redraw 'leaveit' lines.
43  */
44 wwscroll1(w, row1, row2, dir, leaveit)
45 register struct ww *w;
46 int row1, row2, dir;
47 int leaveit;
48 {
49 	register i;
50 	int row1x, row2x;
51 	int nvis;
52 	int nvismax;
53 	int deleted = 0;
54 
55 	/*
56 	 * See how many lines on the screen are affected.
57 	 * And calculate row1x, row2x, and left at the same time.
58 	 */
59 	for (i = row1; i < row2 && w->ww_nvis[i] == 0; i++)
60 		;
61 	if (i >= row2)			/* can't do any fancy stuff */
62 		goto out;
63 	row1x = i;
64 	for (i = row2 - 1; i >= row1 && w->ww_nvis[i] == 0; i--)
65 		;
66 	if (i <= row1x)
67 		goto out;		/* just one line is easy */
68 	row2x = i + 1;
69 
70 	/*
71 	 * See how much of this window is visible.
72 	 */
73 	nvismax = wwncol * (row2x - row1x);
74 	nvis = 0;
75 	for (i = row1x; i < row2x; i++)
76 		nvis += w->ww_nvis[i];
77 
78 	/*
79 	 * If it's a good idea to use delete and insert line
80 	 * and the terminal can, then do it.
81 	 */
82 	if (nvis > nvismax / 2 && tt.tt_delline && tt.tt_insline) {
83 		register union ww_char *tmp;
84 		register union ww_char **cpp, **cqq;
85 
86 		/*
87 		 * Don't worry about retain when scrolling down.
88 		 * But do worry when scrolling up.  For hp2621.
89 		 */
90 		if (dir > 0) {
91 			(*tt.tt_move)(row1x, 0);
92 			(*tt.tt_delline)();
93 			if (row2x < wwnrow) {
94 				(*tt.tt_move)(row2x - 1, 0);
95 				(*tt.tt_insline)();
96 			}
97 			/*
98 			 * Fix up the old screen.
99 			 */
100 			cpp = &wwos[row1x];
101 			cqq = cpp + 1;
102 			tmp = *cpp;
103 			for (i = row2x - row1x; --i > 0;)
104 				*cpp++ = *cqq++;
105 			*cpp = tmp;
106 		} else {
107 			if (tt.tt_retain || row2x != wwnrow) {
108 				(*tt.tt_move)(row2x - 1, 0);
109 				(*tt.tt_delline)();
110 			}
111 			(*tt.tt_move)(row1x, 0);
112 			(*tt.tt_insline)();
113 			/*
114 			 * Fix up the old screen.
115 			 */
116 			cpp = &wwos[row2x];
117 			cqq = cpp - 1;
118 			tmp = *cqq;
119 			for (i = row2x - row1x; --i > 0;)
120 				*--cpp = *--cqq;
121 			*cqq = tmp;
122 		}
123 		for (i = wwncol; --i >= 0;)
124 			tmp++->c_w = ' ';
125 		deleted++;
126 	}
127 
128 	/*
129 	 * Fix the new screen.
130 	 */
131 	if (nvis == nvismax) {
132 		/*
133 		 * Can shift whole lines.
134 		 */
135 		if (dir > 0) {
136 			{
137 				register union ww_char *tmp;
138 				register union ww_char **cpp, **cqq;
139 
140 				cpp = &wwns[row1x];
141 				cqq = cpp + 1;
142 				tmp = *cpp;
143 				for (i = row2x - row1x; --i > 0;)
144 					*cpp++ = *cqq++;
145 				*cpp = tmp;
146 			}
147 			if (deleted) {
148 				register char *p, *q;
149 
150 				p = &wwtouched[row1x];
151 				q = p + 1;
152 				for (i = row2x - row1x; --i > 0;)
153 					*p++ = *q++;
154 				*p |= WWU_TOUCHED;
155 			} else {
156 				register char *p;
157 
158 				p = &wwtouched[row1x];
159 				for (i = row2x - row1x; --i >= 0;)
160 					*p++ |= WWU_MAJOR|WWU_TOUCHED;
161 			}
162 			wwredrawwin1(w, row1, row1x, dir);
163 			wwredrawwin1(w, row2x - 1, row2 - leaveit, dir);
164 		} else {
165 			{
166 				register union ww_char *tmp;
167 				register union ww_char **cpp, **cqq;
168 
169 				cpp = &wwns[row2x];
170 				cqq = cpp - 1;
171 				tmp = *cqq;
172 				for (i = row2x - row1x; --i > 0;)
173 					*--cpp = *--cqq;
174 				*cqq = tmp;
175 			}
176 			if (deleted) {
177 				register char *p, *q;
178 
179 				p = &wwtouched[row2x];
180 				q = p - 1;
181 				for (i = row2x - row1x; --i > 0;)
182 					*--p = *--q;
183 				*q |= WWU_MAJOR|WWU_TOUCHED;
184 			} else {
185 				register char *p;
186 
187 				p = &wwtouched[row1x];
188 				for (i = row2x - row1x; --i >= 0;)
189 					*p++ |= WWU_TOUCHED;
190 			}
191 			wwredrawwin1(w, row1 + leaveit, row1x + 1, dir);
192 			wwredrawwin1(w, row2x, row2, dir);
193 		}
194 	} else {
195 out:
196 		if (dir > 0)
197 			wwredrawwin1(w, row1, row2 - leaveit, dir);
198 		else
199 			wwredrawwin1(w, row1 + leaveit, row2, dir);
200 	}
201 	return deleted;
202 }
203