]> ncurses.scripts.mit.edu Git - ncurses.git/blob - ncurses/softscroll.c
ncurses 4.2
[ncurses.git] / ncurses / softscroll.c
1 /****************************************************************************
2  * Copyright (c) 1998 Free Software Foundation, Inc.                        *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Thomas E. Dickey <dickey@clark.net> 1997                        *
31  ****************************************************************************/
32 #include <curses.priv.h>
33 #include <term.h>
34
35 MODULE_ID("$Id: softscroll.c,v 1.6 1998/02/11 12:13:56 tom Exp $")
36
37 /*
38  * Compute indices for the given WINDOW, preparing it for scrolling.
39  *
40  * TODO (this implementation is only for proof-of-concept)
41  *      (a) ensure that curscr's oldindex values are cached properly so we
42  *          don't have to recompute them on each pass.
43  *      (b) investigate if there are gains to be made by iterating newscr's
44  *          row indices outward from the current position, rather than by
45  *          all rows.
46  */
47 static void compute_curscr(void)
48 {
49         int y, x, z;
50         for (y = 0; y < screen_lines; y++) {
51                 struct ldat *nline = &curscr->_line[y];
52                 int found = y;
53                 for (z = 0; z < y; z++) {
54                         int same = TRUE;
55                         struct ldat *oline = &curscr->_line[z];
56                         for (x = 0; x < screen_columns; x++) {
57                                 if (nline->text[x] != oline->text[x]) {
58                                         same = FALSE;
59                                         break;
60                                 }
61                         }
62                         if (same) {
63                                 found = z;
64                                 break;
65                         }
66                 }
67                 nline->oldindex = found;
68         }
69 }
70
71 static void compute_newscr(void)
72 {
73         int y, x, z;
74         for (y = 0; y < screen_lines; y++) {
75                 struct ldat *nline = &newscr->_line[y];
76                 int found = _NEWINDEX;
77                 for (z = 0; z < screen_lines; z++) {
78                         int same = TRUE;
79                         struct ldat *oline = &curscr->_line[z];
80                         for (x = 0; x < screen_columns; x++) {
81                                 if (nline->text[x] != oline->text[x]) {
82                                         same = FALSE;
83                                         break;
84                                 }
85                         }
86                         if (same) {
87                                 found = z;
88                                 break;
89                         }
90                 }
91                 nline->oldindex = found;
92         }
93 }
94
95 void
96 _nc_setup_scroll(void)
97 {
98 #ifdef TRACE
99         if (_nc_tracing & TRACE_UPDATE) {
100                 _tracef("_nc_setup_scroll");
101                 _nc_linedump();
102         }
103 #endif /* TRACE */
104         compute_curscr();
105         compute_newscr();
106 #ifdef TRACE
107         if (_nc_tracing & TRACE_UPDATE) {
108                 _tracef("..._nc_setup_scroll");
109                 _nc_linedump();
110         }
111 #endif
112 }
113
114 #define MINDISP         2
115 #define NEWNUM(n)       newscr->_line[n].oldindex
116 #define OLDNUM(n)       curscr->_line[n].oldindex
117
118 /*
119  * This performs essentially the same function as _nc_scroll_optimize(), but
120  * uses different assumptions about the .oldindex values.  More than one line
121  * may have the same .oldindex value.  We don't assume the values are ordered.
122  *
123  * (Neither algorithm takes into account the cost of constructing the lines
124  * which are scrolled)
125  */
126 void
127 _nc_perform_scroll(void)
128 {
129         int disp;
130         int row;
131         int top, bottom, maxdisp;
132         int partial;
133
134         /*
135          * Find the top/bottom lines that are different between curscr and
136          * newscr, limited by the terminal's ability to scroll portions of the
137          * screen.
138          *
139          * FIXME: this doesn't account for special cases of insert/delete line.
140          */
141         if (change_scroll_region
142          && (scroll_forward || parm_index)
143          && (scroll_reverse || parm_rindex)) {
144                 partial = TRUE;
145                 for (row = 0, top = -1; row < screen_lines; row++) {
146                         if (OLDNUM(row) != NEWNUM(row)) {
147                                 break;
148                         }
149                         top = row;
150                 }
151                 top++;
152
153                 for (row = screen_lines-1, bottom = screen_lines; row >= 0; row--) {
154                         if (OLDNUM(row) != NEWNUM(row)) {
155                                 break;
156                         }
157                         bottom = row;
158                 }
159                 bottom--;
160         } else {
161                 partial = FALSE;
162                 top     = 0;
163                 bottom  = screen_lines - 1;
164         }
165
166         maxdisp = (bottom - top + 1) / 2;
167         if (maxdisp < MINDISP)
168                 return;
169
170         T(("_nc_perform_scroll %d..%d (maxdisp=%d)", top, bottom, maxdisp));
171
172         for (disp = 1; disp < maxdisp; disp++) {
173                 int n;
174                 int fn, fwd = 0;
175                 int bn, bak = 0;
176                 int first, last;
177                 int moved;
178
179                 do {
180                         /* check for forward-movement */
181                         for (fn = top + disp; fn < screen_lines - disp; fn++) {
182                                 int eql = 0;
183                                 for (n = fn, fwd = 0; n < screen_lines; n++) {
184                                         if (NEWNUM(n) == _NEWINDEX
185                                          || NEWNUM(n) != OLDNUM(n-disp))
186                                                 break;
187                                         fwd++;
188                                         if (OLDNUM(n) == NEWNUM(n))
189                                                 eql++;
190                                 }
191                                 if (eql == fwd)
192                                         fwd = 0;
193                                 if (fwd >= disp)
194                                         break;
195                                 fwd = 0;
196                         }
197
198                         /* check for backward-movement */
199                         for (bn = top + disp; bn < screen_lines - disp; bn++) {
200                                 int eql = 0;
201                                 for (n = bn, bak = 0; n < screen_lines; n++) {
202                                         if (OLDNUM(n) == _NEWINDEX
203                                          || OLDNUM(n) != NEWNUM(n-disp))
204                                                 break;
205                                         bak++;
206                                         if (OLDNUM(n-disp) == NEWNUM(n-disp))
207                                                 eql++;
208                                 } 
209                                 if (eql == bak)
210                                         bak = 0;
211                                 if (bak >= disp)
212                                         break;
213                                 bak = 0;
214                         }
215
216                         /* choose only one, in case they overlap */
217                         if (fwd > bak) {
218                                 first = fn - disp;
219                                 last  = fn + fwd - 1;
220                                 moved = -disp;
221                         } else if (bak) {
222                                 first = bn - disp;
223                                 last  = bn + bak - 1;
224                                 moved = disp;
225                         } else {
226                                 break;
227                         }
228
229                         TR(TRACE_UPDATE | TRACE_MOVE, ("scroll [%d, %d] by %d", first, last, moved));
230                         if (_nc_scrolln(moved, first, last, screen_lines - 1) == ERR)
231                         {
232                                 TR(TRACE_UPDATE | TRACE_MOVE, ("unable to scroll"));
233                                 break;
234                         }
235
236                         /* If the scrolled text was at one end of the range
237                          * of changed lines, adjust the loop limits.
238                          */
239                         if (first == top)
240                                 top = last + 1;
241                         if (last == bottom)
242                                 bottom = first - 1;
243
244                         maxdisp = (bottom - top + 1) / 2;
245                         if (maxdisp < MINDISP)
246                                 return;
247
248                         /* In any case, mark the lines so we don't try to
249                          * use them in a subsequent scroll.
250                          */
251                         for (fn = first; fn <= last; fn++) {
252                                 OLDNUM(fn) =
253                                 NEWNUM(fn) = _NEWINDEX;
254                         }
255                 } while (partial);
256         }
257 }