1 /* SLang Scrolling Window Routines */
2 /* Copyright (c) 1996, 1999, 2001, 2002 John E. Davis
3 * This file is part of the S-Lang library.
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Perl Artistic License.
7 */
8
9 #include "slinclud.h"
10
11 #include "slang.h"
12 #include "_slang.h"
13
find_window_bottom(SLscroll_Window_Type * win)14 static void find_window_bottom (SLscroll_Window_Type *win)
15 {
16 unsigned int nrows;
17 unsigned int hidden_mask;
18 SLscroll_Type *bot, *cline, *last_bot;
19 unsigned int row;
20
21 nrows = win->nrows;
22 hidden_mask = win->hidden_mask;
23 cline = win->current_line;
24
25 win->window_row = row = 0;
26 last_bot = bot = win->top_window_line;
27
28 while (row < nrows)
29 {
30 if (bot == cline)
31 win->window_row = row;
32
33 last_bot = bot;
34
35 if (bot == NULL)
36 break;
37
38 bot = bot->next;
39
40 if (hidden_mask)
41 {
42 while ((bot != NULL) && (bot->flags & hidden_mask))
43 bot = bot->next;
44 }
45
46 row++;
47 }
48
49 win->bot_window_line = last_bot;
50 }
51
find_top_to_recenter(SLscroll_Window_Type * win)52 static int find_top_to_recenter (SLscroll_Window_Type *win)
53 {
54 unsigned int nrows;
55 unsigned int hidden_mask;
56 SLscroll_Type *prev, *last_prev, *cline;
57
58 nrows = win->nrows;
59 cline = win->current_line;
60 hidden_mask = win->hidden_mask;
61
62 nrows = nrows / 2;
63
64 last_prev = prev = cline;
65
66 while (nrows && (prev != NULL))
67 {
68 nrows--;
69 last_prev = prev;
70 do
71 {
72 prev = prev->prev;
73 }
74 while (hidden_mask
75 && (prev != NULL)
76 && (prev->flags & hidden_mask));
77 }
78
79 if (prev == NULL) prev = last_prev;
80
81 win->top_window_line = prev;
82 find_window_bottom (win);
83
84 return 0;
85 }
86
87 #define HAS_BORDER_CODE 1
SLscroll_find_top(SLscroll_Window_Type * win)88 int SLscroll_find_top (SLscroll_Window_Type *win)
89 {
90 unsigned int i;
91 SLscroll_Type *cline, *prev, *next;
92 SLscroll_Type *top_window_line;
93 unsigned int nrows;
94 unsigned int hidden_mask;
95 int scroll_mode;
96 unsigned int border;
97
98 cline = win->current_line;
99 nrows = win->nrows;
100 scroll_mode = win->cannot_scroll;
101 border = win->border;
102 if (scroll_mode == 2)
103 border = 0;
104
105 if ((cline == NULL) || (nrows <= 1))
106 {
107 win->top_window_line = cline;
108 find_window_bottom (win);
109 return 0;
110 }
111
112 hidden_mask = win->hidden_mask;
113
114 /* Note: top_window_line might be a bogus pointer. This means that I cannot
115 * access it unless it really corresponds to a pointer in the buffer.
116 */
117 top_window_line = win->top_window_line;
118
119 if (top_window_line == NULL)
120 return find_top_to_recenter (win);
121
122 /* Chances are that the current line is visible in the window. This means
123 * that the top window line should be above it.
124 */
125 prev = cline;
126
127 i = 0;
128
129 while ((i < nrows) && (prev != NULL))
130 {
131 if (prev == top_window_line)
132 {
133 SLscroll_Type *twl = top_window_line;
134 int dir = 0;
135
136 if (i < border) dir = -1; else if (i + border >= nrows) dir = 1;
137
138 if (dir) while (border)
139 {
140 if (dir < 0) twl = twl->prev;
141 else twl = twl->next;
142
143 if (twl == NULL)
144 {
145 twl = top_window_line;
146 break;
147 }
148 if ((hidden_mask == 0)
149 || (0 == (twl->flags & hidden_mask)))
150 border--;
151 }
152
153 win->top_window_line = twl;
154 find_window_bottom (win);
155 return 0;
156 }
157
158 do
159 {
160 prev = prev->prev;
161 }
162 while (hidden_mask
163 && (prev != NULL)
164 && (prev->flags & hidden_mask));
165 i++;
166 }
167
168 /* Now check the borders of the window. Perhaps the current line lies
169 * outsider the border by a line. Only do this if terminal can scroll.
170 */
171
172 if (scroll_mode == 1)
173 return find_top_to_recenter (win);
174 else if (scroll_mode == -1)
175 scroll_mode = 0;
176
177 next = cline->next;
178 while (hidden_mask
179 && (next != NULL)
180 && (next->flags & hidden_mask))
181 next = next->next;
182
183 if ((next != NULL)
184 && (next == top_window_line))
185 {
186 /* The current line is one line above the window. This means user
187 * has moved up past the top of the window. If scroll_mode is set
188 * to scroll by pages, we need to do a page up.
189 */
190
191 win->top_window_line = cline;
192 find_window_bottom (win);
193
194 if (scroll_mode) return SLscroll_pageup (win);
195
196 return 0;
197 }
198
199 prev = cline->prev;
200
201 while (hidden_mask
202 && (prev != NULL)
203 && (prev->flags & hidden_mask))
204 prev = prev->prev;
205
206 if ((prev == NULL)
207 || (prev != win->bot_window_line))
208 return find_top_to_recenter (win);
209
210 /* It looks like cline is below window by one line. See what line should
211 * be at top to scroll it into view. Only do this unless we are scrolling
212 * by pages.
213 */
214 if (scroll_mode)
215 {
216 win->top_window_line = cline;
217 find_window_bottom (win);
218 return 0;
219 }
220
221 i = 2;
222 while ((i < nrows) && (prev != NULL))
223 {
224 do
225 {
226 prev = prev->prev;
227 }
228 while (hidden_mask
229 && (prev != NULL)
230 && (prev->flags & hidden_mask));
231 i++;
232 }
233
234 if (prev != NULL)
235 {
236 win->top_window_line = prev;
237 find_window_bottom (win);
238 return 0;
239 }
240
241 return find_top_to_recenter (win);
242 }
243
SLscroll_find_line_num(SLscroll_Window_Type * win)244 int SLscroll_find_line_num (SLscroll_Window_Type *win)
245 {
246 SLscroll_Type *cline, *l;
247 unsigned int n;
248 unsigned int hidden_mask;
249
250 if (win == NULL) return -1;
251
252 hidden_mask = win->hidden_mask;
253 cline = win->current_line;
254
255 n = 1;
256
257 l = win->lines;
258 while (l != cline)
259 {
260 if ((hidden_mask == 0)
261 || (0 == (l->flags & hidden_mask)))
262 n++;
263
264 l = l->next;
265 }
266
267 win->line_num = n;
268 n--;
269
270 while (l != NULL)
271 {
272 if ((hidden_mask == 0)
273 || (0 == (l->flags & hidden_mask)))
274 n++;
275 l = l->next;
276 }
277 win->num_lines = n;
278
279 return 0;
280 }
281
SLscroll_next_n(SLscroll_Window_Type * win,unsigned int n)282 unsigned int SLscroll_next_n (SLscroll_Window_Type *win, unsigned int n)
283 {
284 unsigned int i;
285 unsigned int hidden_mask;
286 SLscroll_Type *l, *cline;
287
288 if ((win == NULL)
289 || (NULL == (cline = win->current_line)))
290 return 0;
291
292 hidden_mask = win->hidden_mask;
293 l = cline;
294 i = 0;
295 while (i < n)
296 {
297 l = l->next;
298 while (hidden_mask
299 && (l != NULL) && (l->flags & hidden_mask))
300 l = l->next;
301
302 if (l == NULL)
303 break;
304
305 i++;
306 cline = l;
307 }
308
309 win->current_line = cline;
310 win->line_num += i;
311 return i;
312 }
313
SLscroll_prev_n(SLscroll_Window_Type * win,unsigned int n)314 unsigned int SLscroll_prev_n (SLscroll_Window_Type *win, unsigned int n)
315 {
316 unsigned int i;
317 unsigned int hidden_mask;
318 SLscroll_Type *l, *cline;
319
320 if ((win == NULL)
321 || (NULL == (cline = win->current_line)))
322 return 0;
323
324 hidden_mask = win->hidden_mask;
325 l = cline;
326 i = 0;
327 while (i < n)
328 {
329 l = l->prev;
330 while (hidden_mask
331 && (l != NULL) && (l->flags & hidden_mask))
332 l = l->prev;
333
334 if (l == NULL)
335 break;
336
337 i++;
338 cline = l;
339 }
340
341 win->current_line = cline;
342 win->line_num -= i;
343 return i;
344 }
345
SLscroll_pageup(SLscroll_Window_Type * win)346 int SLscroll_pageup (SLscroll_Window_Type *win)
347 {
348 SLscroll_Type *l, *top;
349 unsigned int nrows, hidden_mask;
350 unsigned int n;
351
352 if (win == NULL)
353 return -1;
354
355 (void) SLscroll_find_top (win);
356
357 nrows = win->nrows;
358
359 if ((NULL != (top = win->top_window_line))
360 && (nrows > 2))
361 {
362 n = 0;
363 hidden_mask = win->hidden_mask;
364 l = win->current_line;
365 while ((l != NULL) && (l != top))
366 {
367 l = l->prev;
368 if ((hidden_mask == 0)
369 || ((l != NULL) && (0 == (l->flags & hidden_mask))))
370 n++;
371 }
372
373 if (l != NULL)
374 {
375 unsigned int save_line_num;
376 int ret = 0;
377
378 win->current_line = l;
379 win->line_num -= n;
380
381 /* Compute a new top/bottom header */
382 save_line_num = win->line_num;
383
384 if ((0 == SLscroll_prev_n (win, nrows - 1))
385 && (n == 0))
386 ret = -1;
387
388 win->top_window_line = win->current_line;
389 win->current_line = l;
390 win->line_num = save_line_num;
391
392 find_window_bottom (win);
393 return ret;
394 }
395 }
396
397 if (nrows < 2) nrows++;
398 if (0 == SLscroll_prev_n (win, nrows - 1))
399 return -1;
400 return 0;
401 }
402
SLscroll_pagedown(SLscroll_Window_Type * win)403 int SLscroll_pagedown (SLscroll_Window_Type *win)
404 {
405 SLscroll_Type *l, *bot;
406 unsigned int nrows, hidden_mask;
407 unsigned int n;
408
409 if (win == NULL)
410 return -1;
411
412 (void) SLscroll_find_top (win);
413
414 nrows = win->nrows;
415
416 if ((NULL != (bot = win->bot_window_line))
417 && (nrows > 2))
418 {
419 n = 0;
420 hidden_mask = win->hidden_mask;
421 l = win->current_line;
422 while ((l != NULL) && (l != bot))
423 {
424 l = l->next;
425 if ((hidden_mask == 0)
426 || ((l != NULL) && (0 == (l->flags & hidden_mask))))
427 n++;
428 }
429
430 if (l != NULL)
431 {
432 win->current_line = l;
433 win->top_window_line = l;
434 win->line_num += n;
435
436 find_window_bottom (win);
437
438 if (n || (bot != win->bot_window_line))
439 return 0;
440
441 return -1;
442 }
443 }
444
445 if (nrows < 2) nrows++;
446 if (0 == SLscroll_next_n (win, nrows - 1))
447 return -1;
448 return 0;
449 }
450
451