xref: /openbsd-src/lib/libcurses/base/lib_pad.c (revision 92dd1ec0a89df25171bc5d61a3d95ea1a68cef0b)
1 /*	$OpenBSD: lib_pad.c,v 1.1 1999/01/18 19:09:55 millert Exp $	*/
2 
3 /****************************************************************************
4  * Copyright (c) 1998 Free Software Foundation, Inc.                        *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /****************************************************************************
32  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34  ****************************************************************************/
35 
36 
37 /*
38  * lib_pad.c
39  * newpad	-- create a new pad
40  * pnoutrefresh -- refresh a pad, no update
41  * pechochar	-- add a char to a pad and refresh
42  */
43 
44 #include <curses.priv.h>
45 
46 MODULE_ID("$From: lib_pad.c,v 1.27 1998/06/28 00:10:16 tom Exp $")
47 
48 WINDOW *newpad(int l, int c)
49 {
50 WINDOW *win;
51 chtype *ptr;
52 int i;
53 
54 	T((T_CALLED("newpad(%d, %d)"), l, c));
55 
56 	if (l <= 0 || c <= 0)
57 		returnWin(0);
58 
59 	if ((win = _nc_makenew(l,c,0,0,_ISPAD)) == NULL)
60 		returnWin(0);
61 
62 	for (i = 0; i < l; i++) {
63 	    if_USE_SCROLL_HINTS(win->_line[i].oldindex = _NEWINDEX);
64 	    if ((win->_line[i].text = typeCalloc(chtype, ((size_t)c))) == 0) {
65 		_nc_freewin(win);
66 		returnWin(0);
67 	    }
68 	    for (ptr = win->_line[i].text; ptr < win->_line[i].text + c; )
69 		*ptr++ = ' ';
70 	}
71 
72 	returnWin(win);
73 }
74 
75 WINDOW *subpad(WINDOW *orig, int l, int c, int begy, int begx)
76 {
77 WINDOW	*win = (WINDOW *)0;
78 
79 	T((T_CALLED("subpad(%d, %d)"), l, c));
80 
81 	if (orig) {
82 	  if (!(orig->_flags & _ISPAD) || ((win = derwin(orig, l, c, begy, begx)) == NULL))
83 	    returnWin(0);
84 	}
85 	returnWin(win);
86 }
87 
88 int prefresh(WINDOW *win, int pminrow, int pmincol,
89 	int sminrow, int smincol, int smaxrow, int smaxcol)
90 {
91 	T((T_CALLED("prefresh()")));
92 	if (pnoutrefresh(win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol) != ERR
93 	 && doupdate() != ERR) {
94 		returnCode(OK);
95 	}
96 	returnCode(ERR);
97 }
98 
99 int pnoutrefresh(WINDOW *win, int pminrow, int pmincol,
100 	int sminrow, int smincol, int smaxrow, int smaxcol)
101 {
102 const	int my_len = 2;	/* parameterize the threshold for hardscroll */
103 short	i, j;
104 short	m, n;
105 short	pmaxrow;
106 short	pmaxcol;
107 short	displaced;
108 bool	wide;
109 
110 	T((T_CALLED("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d)"),
111 		win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol));
112 
113 	if (win == 0)
114 		returnCode(ERR);
115 
116 	if (!(win->_flags & _ISPAD))
117 		returnCode(ERR);
118 
119 	/* negative values are interpreted as zero */
120 	if (pminrow < 0) pminrow = 0;
121 	if (pmincol < 0) pmincol = 0;
122 	if (sminrow < 0) sminrow = 0;
123 	if (smincol < 0) smincol = 0;
124 
125 	pmaxrow = pminrow + smaxrow - sminrow;
126 	pmaxcol = pmincol + smaxcol - smincol;
127 
128 	T((" pminrow + smaxrow - sminrow %d, win->_maxy %d", pmaxrow, win->_maxy));
129 	T((" pmincol + smaxcol - smincol %d, win->_maxx %d", pmaxcol, win->_maxx));
130 
131 	/*
132 	 * Trim the caller's screen size back to the actual limits.
133 	 */
134 	if (pmaxrow > win->_maxy) {
135 		smaxrow -= (pmaxrow - win->_maxy);
136 		pmaxrow = pminrow + smaxrow - sminrow;
137 	}
138 	if (pmaxcol > win->_maxx) {
139 		smaxcol -= (pmaxcol - win->_maxx);
140 		pmaxcol = pmincol + smaxcol - smincol;
141 	}
142 
143 	if (smaxrow > screen_lines
144 	 || smaxcol > screen_columns
145 	 || sminrow > smaxrow
146 	 || smincol > smaxcol)
147 		returnCode(ERR);
148 
149 	T(("pad being refreshed"));
150 
151 	if (win->_pad._pad_y >= 0) {
152 		displaced = pminrow - win->_pad._pad_y
153 			  -(sminrow - win->_pad._pad_top);
154 		T(("pad being shifted by %d line(s)", displaced));
155 	} else
156 		displaced = 0;
157 
158 	/*
159 	 * For pure efficiency, we'd want to transfer scrolling information
160 	 * from the pad to newscr whenever the window is wide enough that
161 	 * its update will dominate the cost of the update for the horizontal
162 	 * band of newscr that it occupies.  Unfortunately, this threshold
163 	 * tends to be complex to estimate, and in any case scrolling the
164 	 * whole band and rewriting the parts outside win's image would look
165 	 * really ugly.  So.  What we do is consider the pad "wide" if it
166 	 * either (a) occupies the whole width of newscr, or (b) occupies
167 	 * all but at most one column on either vertical edge of the screen
168 	 * (this caters to fussy people who put boxes around full-screen
169 	 * windows).  Note that changing this formula will not break any code,
170 	 * merely change the costs of various update cases.
171 	 */
172 	wide = (smincol < my_len && smaxcol > (newscr->_maxx - my_len));
173 
174 	for (i = pminrow, m = sminrow + win->_yoffset;
175 		i <= pmaxrow && m <= newscr->_maxy;
176 			i++, m++) {
177 		register struct ldat	*nline = &newscr->_line[m];
178 		register struct ldat	*oline = &win->_line[i];
179 
180 		for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) {
181 			if (oline->text[j] != nline->text[n]) {
182 				nline->text[n] = oline->text[j];
183 				CHANGED_CELL(nline,n);
184 			}
185 		}
186 
187 #if USE_SCROLL_HINTS
188 		if (wide) {
189 		    int nind = m + displaced;
190 		    if (oline->oldindex < 0
191 		     || nind < sminrow
192 		     || nind > smaxrow) {
193 			nind = _NEWINDEX;
194 		    } else if (displaced) {
195 			register struct ldat *pline = &curscr->_line[nind];
196 			for (j = 0; j <= my_len; j++) {
197 			    int k = newscr->_maxx - j;
198 			    if (pline->text[j] != nline->text[j]
199 			     || pline->text[k] != nline->text[k]) {
200 				nind = _NEWINDEX;
201 				break;
202 			    }
203 			}
204 		    }
205 
206 		    nline->oldindex = nind;
207 		}
208 #endif /* USE_SCROLL_HINTS */
209 		oline->firstchar = oline->lastchar = _NOCHANGE;
210 		if_USE_SCROLL_HINTS(oline->oldindex = i);
211 	}
212 
213 	/*
214 	 * Clean up debris from scrolling or resizing the pad, so we do not
215 	 * accidentally pick up the index value during the next call to this
216 	 * procedure.  The only rows that should have an index value are those
217 	 * that are displayed during this cycle.
218 	 */
219 #if USE_SCROLL_HINTS
220 	for (i = pminrow-1; (i >= 0) && (win->_line[i].oldindex >= 0); i--)
221 		win->_line[i].oldindex = _NEWINDEX;
222 	for (i = pmaxrow+1; (i <= win->_maxy) && (win->_line[i].oldindex >= 0); i++)
223 		win->_line[i].oldindex = _NEWINDEX;
224 #endif
225 
226 	win->_begx = smincol;
227 	win->_begy = sminrow;
228 
229 	if (win->_clear) {
230 	    win->_clear = FALSE;
231 	    newscr->_clear = TRUE;
232 	}
233 
234 	/*
235 	 * Use the pad's current position, if it will be visible.
236 	 * If not, don't do anything; it's not an error.
237 	 */
238 	if (win->_leaveok == FALSE
239 	 && win->_cury  >= pminrow
240 	 && win->_curx  >= pmincol
241 	 && win->_cury  <= pmaxrow
242 	 && win->_curx  <= pmaxcol) {
243 		newscr->_cury = win->_cury - pminrow + win->_begy + win->_yoffset;
244 		newscr->_curx = win->_curx - pmincol + win->_begx;
245 	}
246 	win->_flags &= ~_HASMOVED;
247 
248 	/*
249 	 * Update our cache of the line-numbers that we displayed from the pad.
250 	 * We will use this on subsequent calls to this function to derive
251 	 * values to stuff into 'oldindex[]' -- for scrolling optimization.
252 	 */
253 	win->_pad._pad_y      = pminrow;
254 	win->_pad._pad_x      = pmincol;
255 	win->_pad._pad_top    = sminrow;
256 	win->_pad._pad_left   = smincol;
257 	win->_pad._pad_bottom = smaxrow;
258 	win->_pad._pad_right  = smaxcol;
259 
260 	returnCode(OK);
261 }
262 
263 int pechochar(WINDOW *pad, const chtype ch)
264 {
265 	T((T_CALLED("pechochar(%p, %s)"), pad, _tracechtype(ch)));
266 
267 	if (pad == 0)
268 	  returnCode(ERR);
269 
270 	if (!(pad->_flags & _ISPAD))
271 		returnCode(wechochar(pad,ch));
272 
273 	waddch(pad, ch);
274 	prefresh(pad, pad->_pad._pad_y,
275 		      pad->_pad._pad_x,
276 		      pad->_pad._pad_top,
277 		      pad->_pad._pad_left,
278 		      pad->_pad._pad_bottom,
279 		      pad->_pad._pad_right);
280 
281 	returnCode(OK);
282 }
283