ncurses 4.2
[ncurses.git] / panel / panel.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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1995                    *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  ****************************************************************************/
33
34 /* panel.c -- implementation of panels library, some core routines */
35 #include "panel.priv.h"
36
37 MODULE_ID("$Id: panel.c,v 1.15 1998/02/11 12:14:01 tom Exp $")
38
39 #ifdef TRACE
40 #ifndef TRACE_TXT
41 const char *_nc_my_visbuf(const void *ptr)
42 {
43         char temp[20];
44         if (ptr != 0)
45                 sprintf(temp, "ptr:%p", ptr);
46         else
47                 strcpy(temp, "<null>");
48         return _nc_visbuf(temp);
49 }
50 #endif
51 #endif
52
53
54 /*+-------------------------------------------------------------------------
55         dPanel(text,pan)
56 --------------------------------------------------------------------------*/
57 #ifdef TRACE
58 void
59 _nc_dPanel(const char *text, const PANEL *pan)
60 {
61         _tracef("%s id=%s b=%s a=%s y=%d x=%d",
62                 text, USER_PTR(pan->user),
63                 (pan->below) ?  USER_PTR(pan->below->user) : "--",
64                 (pan->above) ?  USER_PTR(pan->above->user) : "--",
65                 pan->wstarty, pan->wstartx);
66 }
67 #endif
68
69 /*+-------------------------------------------------------------------------
70         dStack(fmt,num,pan)
71 --------------------------------------------------------------------------*/
72 #ifdef TRACE
73 void
74 _nc_dStack(const char *fmt, int num, const PANEL *pan)
75 {
76   char s80[80];
77
78   sprintf(s80,fmt,num,pan);
79   _tracef("%s b=%s t=%s",s80,
80           (_nc_bottom_panel) ?  USER_PTR(_nc_bottom_panel->user) : "--",
81           (_nc_top_panel)    ?  USER_PTR(_nc_top_panel->user)    : "--");
82   if(pan)
83     _tracef("pan id=%s", USER_PTR(pan->user));
84   pan = _nc_bottom_panel;
85   while(pan)
86     {
87       dPanel("stk",pan);
88       pan = pan->above;
89     }
90 }
91 #endif
92
93 /*+-------------------------------------------------------------------------
94         Wnoutrefresh(pan) - debugging hook for wnoutrefresh
95 --------------------------------------------------------------------------*/
96 #ifdef TRACE
97 void
98 _nc_Wnoutrefresh(const PANEL *pan)
99 {
100   dPanel("wnoutrefresh",pan);
101   wnoutrefresh(pan->win);
102 }
103 #endif
104
105 /*+-------------------------------------------------------------------------
106         Touchpan(pan)
107 --------------------------------------------------------------------------*/
108 #ifdef TRACE
109 void
110 _nc_Touchpan(const PANEL *pan)
111 {
112   dPanel("Touchpan",pan);
113   touchwin(pan->win);
114 }
115 #endif
116
117 /*+-------------------------------------------------------------------------
118         Touchline(pan,start,count)
119 --------------------------------------------------------------------------*/
120 #ifdef TRACE
121 void
122 _nc_Touchline(const PANEL *pan, int start, int count)
123 {
124   char s80[80];
125   sprintf(s80,"Touchline s=%d c=%d",start,count);
126   dPanel(s80,pan);
127   touchline(pan->win,start,count);
128 }
129 #endif
130
131 /*+-------------------------------------------------------------------------
132         __panels_overlapped(pan1,pan2) - check panel overlapped
133 --------------------------------------------------------------------------*/
134 static INLINE bool
135 __panels_overlapped(register const PANEL *pan1, register const PANEL *pan2)
136 {
137   if(!pan1 || !pan2)
138     return(FALSE);
139
140   dBug(("__panels_overlapped %s %s", USER_PTR(pan1->user), USER_PTR(pan2->user)));
141   /* pan1 intersects with pan2 ? */
142   if( (((pan1->wstarty >= pan2->wstarty) && (pan1->wstarty < pan2->wendy)) ||
143        ((pan2->wstarty >= pan1->wstarty) && (pan2->wstarty < pan1->wendy))) &&
144       (((pan1->wstartx >= pan2->wstartx) && (pan1->wstartx < pan2->wendx)) ||
145        ((pan2->wstartx >= pan1->wstartx) && (pan2->wstartx < pan1->wendx)))
146       ) return(TRUE);
147   else {
148     dBug(("  no"));
149     return(FALSE);
150   }
151 }
152
153 /*+-------------------------------------------------------------------------
154         _nc_free_obscure(pan)
155 --------------------------------------------------------------------------*/
156 void
157 _nc_free_obscure(PANEL *pan)
158 {
159   PANELCONS *tobs = pan->obscure;                       /* "this" one */
160   PANELCONS *nobs;                                      /* "next" one */
161
162   while(tobs)
163     {
164       nobs = tobs->above;
165       free((char *)tobs);
166       tobs = nobs;
167     }
168   pan->obscure = (PANELCONS *)0;
169 }
170
171 /*+-------------------------------------------------------------------------
172         __override(pan,show)
173 --------------------------------------------------------------------------*/
174 void
175 _nc_override(const PANEL *pan, int show)
176 {
177   int y;
178   PANEL *pan2;
179   PANELCONS *tobs = pan->obscure;                          /* "this" one */
180
181   dBug(("_nc_override %s,%d", USER_PTR(pan->user),show));
182
183   switch (show)
184     {
185     case P_TOUCH:
186       Touchpan(pan);
187       /* The following while loop will now mark all panel window lines
188        * obscured by use or obscuring us as touched, so they will be
189        * updated.
190        */
191       break;
192     case P_UPDATE:
193       while(tobs && (tobs->pan != pan))
194         tobs = tobs->above;
195       /* The next loop will now only go through the panels obscuring pan;
196        * it updates all the lines in the obscuring panels in sync. with
197        * the lines touched in pan itself. This is called in update_panels()
198        * in a loop from the bottom_panel to the top_panel, resulting in
199        * the desired update effect.
200        */
201       break;
202     default:
203       return;
204     }
205
206   while(tobs)
207     {
208       if((pan2 = tobs->pan) != pan) {
209         dBug(("test obs pan=%s pan2=%s", USER_PTR(pan->user), USER_PTR(pan2->user)));
210         for(y = pan->wstarty; y < pan->wendy; y++) {
211           if( (y >= pan2->wstarty) && (y < pan2->wendy) &&
212               ((is_linetouched(pan->win,y - pan->wstarty) == TRUE)) )
213             Touchline(pan2,y - pan2->wstarty,1);
214         }
215       }
216       tobs = tobs->above;
217     }
218 }
219
220 /*+-------------------------------------------------------------------------
221         __calculate_obscure()
222 --------------------------------------------------------------------------*/
223 void
224 _nc_calculate_obscure(void)
225 {
226   PANEL *pan;
227   PANEL *pan2;
228   PANELCONS *tobs;                      /* "this" one */
229   PANELCONS *lobs = (PANELCONS *)0;     /* last one */
230
231   pan = _nc_bottom_panel;
232   while(pan)
233     {
234       if(pan->obscure)
235         _nc_free_obscure(pan);
236       dBug(("--> __calculate_obscure %s", USER_PTR(pan->user)));
237       lobs = (PANELCONS *)0;            /* last one */
238       pan2 = _nc_bottom_panel;
239       /* This loop builds a list of panels obsured by pan or obscuring
240          pan; pan itself is in the list; all panels before pan are
241          obscured by pan, all panels after pan are obscuring pan. */
242       while(pan2)
243         {
244           if(__panels_overlapped(pan,pan2))
245             {
246               if(!(tobs = (PANELCONS *)malloc(sizeof(PANELCONS))))
247                 return;
248               tobs->pan = pan2;
249               dPanel("obscured",pan2);
250               tobs->above = (PANELCONS *)0;
251               if(lobs)
252                 lobs->above = tobs;
253               else
254                 pan->obscure = tobs;
255               lobs  = tobs;
256             }
257           pan2 = pan2->above;
258         }
259       _nc_override(pan,P_TOUCH);
260       pan = pan->above;
261     }
262 }
263
264 /*+-------------------------------------------------------------------------
265         _nc_panel_is_linked(pan) - check to see if panel is in the stack
266 --------------------------------------------------------------------------*/
267 bool
268 _nc_panel_is_linked(const PANEL *pan)
269 {
270   /* This works! The only case where it would fail is, when the list has
271      only one element. But this could only be the pseudo panel at the bottom */
272   return ( ((pan->above!=(PANEL *)0) ||
273             (pan->below!=(PANEL *)0) ||
274             (pan==_nc_bottom_panel)) ? TRUE : FALSE );
275 }
276
277
278 /*+-------------------------------------------------------------------------
279         __panel_link_bottom(pan) - link panel into stack at bottom
280 --------------------------------------------------------------------------*/
281 void
282 _nc_panel_link_bottom(PANEL *pan)
283 {
284 #ifdef TRACE
285   dStack("<lb%d>",1,pan);
286   if(_nc_panel_is_linked(pan))
287     return;
288 #endif
289
290   pan->above = (PANEL *)0;
291   pan->below = (PANEL *)0;
292   if(_nc_bottom_panel)
293     { /* the stdscr pseudo panel always stays real bottom;
294          so we insert after bottom panel*/
295       pan->below = _nc_bottom_panel;
296       pan->above = _nc_bottom_panel->above;
297       if (pan->above)
298         pan->above->below = pan;
299       _nc_bottom_panel->above = pan;
300     }
301   else
302     _nc_bottom_panel = pan;
303   if(!_nc_top_panel)
304     _nc_top_panel = pan;
305   assert(_nc_bottom_panel == _nc_stdscr_pseudo_panel);
306   _nc_calculate_obscure();
307   dStack("<lb%d>",9,pan);
308 }