1 /* PDCurses */
2 
3 #include <curspriv.h>
4 
5 /*man-start**************************************************************
6 
7 panel
8 -----
9 
10 ### Synopsis
11 
12     int bottom_panel(PANEL *pan);
13     int del_panel(PANEL *pan);
14     int hide_panel(PANEL *pan);
15     int move_panel(PANEL *pan, int starty, int startx);
16     PANEL *new_panel(WINDOW *win);
17     PANEL *panel_above(const PANEL *pan);
18     PANEL *panel_below(const PANEL *pan);
19     int panel_hidden(const PANEL *pan);
20     const void *panel_userptr(const PANEL *pan);
21     WINDOW *panel_window(const PANEL *pan);
22     int replace_panel(PANEL *pan, WINDOW *win);
23     int set_panel_userptr(PANEL *pan, const void *uptr);
24     int show_panel(PANEL *pan);
25     int top_panel(PANEL *pan);
26     void update_panels(void);
27 
28 ### Description
29 
30    For historic reasons, and for compatibility with other versions of
31    curses, the panel functions are prototyped in a separate header,
32    panel.h. In many implementations, they're also in a separate library,
33    but PDCurses incorporates them.
34 
35    The panel functions provide a way to have depth relationships between
36    curses windows. Panels can overlap without making visible the
37    overlapped portions of underlying windows. The initial curses window,
38    stdscr, lies beneath all panels. The set of currently visible panels
39    is the 'deck' of panels.
40 
41    You can create panels, fetch and set their associated windows,
42    shuffle panels in the deck, and manipulate them in other ways.
43 
44    bottom_panel() places pan at the bottom of the deck. The size,
45    location and contents of the panel are unchanged.
46 
47    del_panel() deletes pan, but not its associated winwow.
48 
49    hide_panel() removes a panel from the deck and thus hides it from
50    view.
51 
52    move_panel() moves the curses window associated with pan, so that its
53    upper lefthand corner is at the supplied coordinates. (Don't use
54    mvwin() on the window.)
55 
56    new_panel() creates a new panel associated with win and returns the
57    panel pointer. The new panel is placed at the top of the deck.
58 
59    panel_above() returns a pointer to the panel in the deck above pan,
60    or NULL if pan is the top panel. If the value of pan passed is NULL,
61    this function returns a pointer to the bottom panel in the deck.
62 
63    panel_below() returns a pointer to the panel in the deck below pan,
64    or NULL if pan is the bottom panel. If the value of pan passed is
65    NULL, this function returns a pointer to the top panel in the deck.
66 
67    panel_hidden() returns OK if pan is hidden and ERR if it is not.
68 
69    panel_userptr() - Each panel has a user pointer available for
70    maintaining relevant information. This function returns a pointer to
71    that information previously set up by set_panel_userptr().
72 
73    panel_window() returns a pointer to the curses window associated with
74    the panel.
75 
76    replace_panel() replaces the current window of pan with win.
77 
78    set_panel_userptr() - Each panel has a user pointer available for
79    maintaining relevant information. This function sets the value of
80    that information.
81 
82    show_panel() makes a previously hidden panel visible and places it
83    back in the deck on top.
84 
85    top_panel() places pan on the top of the deck. The size, location and
86    contents of the panel are unchanged.
87 
88    update_panels() refreshes the virtual screen to reflect the depth
89    relationships between the panels in the deck. The user must use
90    doupdate() to refresh the physical screen.
91 
92 ### Return Value
93 
94    Each routine that returns a pointer to an object returns NULL if an
95    error occurs. Each panel routine that returns an integer, returns OK
96    if it executes successfully and ERR if it does not.
97 
98 ### Portability
99                              X/Open  ncurses  NetBSD
100     bottom_panel                -       Y       Y
101     del_panel                   -       Y       Y
102     hide_panel                  -       Y       Y
103     move_panel                  -       Y       Y
104     new_panel                   -       Y       Y
105     panel_above                 -       Y       Y
106     panel_below                 -       Y       Y
107     panel_hidden                -       Y       Y
108     panel_userptr               -       Y       Y
109     panel_window                -       Y       Y
110     replace_panel               -       Y       Y
111     set_panel_userptr           -       Y       Y
112     show_panel                  -       Y       Y
113     top_panel                   -       Y       Y
114     update_panels               -       Y       Y
115 
116   Credits:
117     Original Author - Warren Tucker <wht@n4hgf.mt-park.ga.us>
118 
119 **man-end****************************************************************/
120 
121 #include <panel.h>
122 #include <stdlib.h>
123 
124 PANEL *_bottom_panel = (PANEL *)0;
125 PANEL *_top_panel = (PANEL *)0;
126 PANEL _stdscr_pseudo_panel = { (WINDOW *)0 };
127 
128 #ifdef PANEL_DEBUG
129 
dPanel(char * text,PANEL * pan)130 static void dPanel(char *text, PANEL *pan)
131 {
132     PDC_LOG(("%s id=%s b=%s a=%s y=%d x=%d", text, pan->user,
133              pan->below ? pan->below->user : "--",
134              pan->above ? pan->above->user : "--",
135              pan->wstarty, pan->wstartx));
136 }
137 
dStack(char * fmt,int num,PANEL * pan)138 static void dStack(char *fmt, int num, PANEL *pan)
139 {
140     char s80[80];
141 
142     sprintf(s80, fmt, num, pan);
143     PDC_LOG(("%s b=%s t=%s", s80, _bottom_panel ? _bottom_panel->user : "--",
144              _top_panel    ? _top_panel->user    : "--"));
145 
146     if (pan)
147         PDC_LOG(("pan id=%s", pan->user));
148 
149     pan = _bottom_panel;
150 
151     while (pan)
152     {
153         dPanel("stk", pan);
154         pan = pan->above;
155     }
156 }
157 
158 /* debugging hook for wnoutrefresh */
159 
Wnoutrefresh(PANEL * pan)160 static void Wnoutrefresh(PANEL *pan)
161 {
162     dPanel("wnoutrefresh", pan);
163     wnoutrefresh(pan->win);
164 }
165 
Touchpan(PANEL * pan)166 static void Touchpan(PANEL *pan)
167 {
168     dPanel("Touchpan", pan);
169     touchwin(pan->win);
170 }
171 
Touchline(PANEL * pan,int start,int count)172 static void Touchline(PANEL *pan, int start, int count)
173 {
174     char s80[80];
175 
176     sprintf(s80, "Touchline s=%d c=%d", start, count);
177     dPanel(s80, pan);
178     touchline(pan->win, start, count);
179 }
180 
181 #else   /* PANEL_DEBUG */
182 
183 #define dPanel(text, pan)
184 #define dStack(fmt, num, pan)
185 #define Wnoutrefresh(pan) wnoutrefresh((pan)->win)
186 #define Touchpan(pan) touchwin((pan)->win)
187 #define Touchline(pan, start, count) touchline((pan)->win, start, count)
188 
189 #endif  /* PANEL_DEBUG */
190 
_panels_overlapped(PANEL * pan1,PANEL * pan2)191 static bool _panels_overlapped(PANEL *pan1, PANEL *pan2)
192 {
193     if (!pan1 || !pan2)
194         return FALSE;
195 
196     return ((pan1->wstarty >= pan2->wstarty && pan1->wstarty < pan2->wendy)
197          || (pan2->wstarty >= pan1->wstarty && pan2->wstarty < pan1->wendy))
198         && ((pan1->wstartx >= pan2->wstartx && pan1->wstartx < pan2->wendx)
199          || (pan2->wstartx >= pan1->wstartx && pan2->wstartx < pan1->wendx));
200 }
201 
_free_obscure(PANEL * pan)202 static void _free_obscure(PANEL *pan)
203 {
204     PANELOBS *tobs = pan->obscure;  /* "this" one */
205     PANELOBS *nobs;                 /* "next" one */
206 
207     while (tobs)
208     {
209         nobs = tobs->above;
210         free((char *)tobs);
211         tobs = nobs;
212     }
213     pan->obscure = (PANELOBS *)0;
214 }
215 
_override(PANEL * pan,int show)216 static void _override(PANEL *pan, int show)
217 {
218     int y;
219     PANEL *pan2;
220     PANELOBS *tobs = pan->obscure;      /* "this" one */
221 
222     if (show == 1)
223         Touchpan(pan);
224     else if (!show)
225     {
226         Touchpan(pan);
227         Touchpan(&_stdscr_pseudo_panel);
228     }
229     else if (show == -1)
230         while (tobs && (tobs->pan != pan))
231             tobs = tobs->above;
232 
233     while (tobs)
234     {
235         if ((pan2 = tobs->pan) != pan)
236             for (y = pan->wstarty; y < pan->wendy; y++)
237                 if ((y >= pan2->wstarty) && (y < pan2->wendy) &&
238                    ((is_linetouched(pan->win, y - pan->wstarty)) ||
239                     (is_linetouched(stdscr, y))))
240                     Touchline(pan2, y - pan2->wstarty, 1);
241 
242         tobs = tobs->above;
243     }
244 }
245 
_calculate_obscure(void)246 static void _calculate_obscure(void)
247 {
248     PANEL *pan, *pan2;
249     PANELOBS *tobs;     /* "this" one */
250     PANELOBS *lobs;     /* last one */
251 
252     pan = _bottom_panel;
253 
254     while (pan)
255     {
256         if (pan->obscure)
257             _free_obscure(pan);
258 
259         lobs = (PANELOBS *)0;
260         pan2 = _bottom_panel;
261 
262         while (pan2)
263         {
264             if (_panels_overlapped(pan, pan2))
265             {
266                 if ((tobs = malloc(sizeof(PANELOBS))) == NULL)
267                     return;
268 
269                 tobs->pan = pan2;
270                 dPanel("obscured", pan2);
271                 tobs->above = (PANELOBS *)0;
272 
273                 if (lobs)
274                     lobs->above = tobs;
275                 else
276                     pan->obscure = tobs;
277 
278                 lobs  = tobs;
279             }
280 
281             pan2 = pan2->above;
282         }
283 
284         _override(pan, 1);
285         pan = pan->above;
286     }
287 }
288 
289 /* check to see if panel is in the stack */
290 
_panel_is_linked(const PANEL * pan)291 static bool _panel_is_linked(const PANEL *pan)
292 {
293     PANEL *pan2 = _bottom_panel;
294 
295     while (pan2)
296     {
297         if (pan2 == pan)
298             return TRUE;
299 
300         pan2 = pan2->above;
301     }
302 
303     return FALSE;
304 }
305 
306 /* link panel into stack at top */
307 
_panel_link_top(PANEL * pan)308 static void _panel_link_top(PANEL *pan)
309 {
310 #ifdef PANEL_DEBUG
311     dStack("<lt%d>", 1, pan);
312     if (_panel_is_linked(pan))
313         return;
314 #endif
315     pan->above = (PANEL *)0;
316     pan->below = (PANEL *)0;
317 
318     if (_top_panel)
319     {
320         _top_panel->above = pan;
321         pan->below = _top_panel;
322     }
323 
324     _top_panel = pan;
325 
326     if (!_bottom_panel)
327         _bottom_panel = pan;
328 
329     _calculate_obscure();
330     dStack("<lt%d>", 9, pan);
331 }
332 
333 /* link panel into stack at bottom */
334 
_panel_link_bottom(PANEL * pan)335 static void _panel_link_bottom(PANEL *pan)
336 {
337 #ifdef PANEL_DEBUG
338     dStack("<lb%d>", 1, pan);
339     if (_panel_is_linked(pan))
340         return;
341 #endif
342     pan->above = (PANEL *)0;
343     pan->below = (PANEL *)0;
344 
345     if (_bottom_panel)
346     {
347         _bottom_panel->below = pan;
348         pan->above = _bottom_panel;
349     }
350 
351     _bottom_panel = pan;
352 
353     if (!_top_panel)
354         _top_panel = pan;
355 
356     _calculate_obscure();
357     dStack("<lb%d>", 9, pan);
358 }
359 
_panel_unlink(PANEL * pan)360 static void _panel_unlink(PANEL *pan)
361 {
362     PANEL *prev;
363     PANEL *next;
364 
365 #ifdef PANEL_DEBUG
366     dStack("<u%d>", 1, pan);
367     if (!_panel_is_linked(pan))
368         return;
369 #endif
370     _override(pan, 0);
371     _free_obscure(pan);
372 
373     prev = pan->below;
374     next = pan->above;
375 
376     /* if non-zero, we will not update the list head */
377 
378     if (prev)
379     {
380         prev->above = next;
381         if(next)
382             next->below = prev;
383     }
384     else if (next)
385         next->below = prev;
386 
387     if (pan == _bottom_panel)
388         _bottom_panel = next;
389 
390     if (pan == _top_panel)
391         _top_panel = prev;
392 
393     _calculate_obscure();
394 
395     pan->above = (PANEL *)0;
396     pan->below = (PANEL *)0;
397     dStack("<u%d>", 9, pan);
398 
399 }
400 
401 /************************************************************************
402  *   The following are the public functions for the panels library.     *
403  ************************************************************************/
404 
bottom_panel(PANEL * pan)405 int bottom_panel(PANEL *pan)
406 {
407     if (!pan)
408         return ERR;
409 
410     if (pan == _bottom_panel)
411         return OK;
412 
413     if (_panel_is_linked(pan))
414         hide_panel(pan);
415 
416     _panel_link_bottom(pan);
417 
418     return OK;
419 }
420 
del_panel(PANEL * pan)421 int del_panel(PANEL *pan)
422 {
423     if (pan)
424     {
425         if (_panel_is_linked(pan))
426             hide_panel(pan);
427 
428         free((char *)pan);
429         return OK;
430     }
431 
432     return ERR;
433 }
434 
hide_panel(PANEL * pan)435 int hide_panel(PANEL *pan)
436 {
437     if (!pan)
438         return ERR;
439 
440     if (!_panel_is_linked(pan))
441     {
442         pan->above = (PANEL *)0;
443         pan->below = (PANEL *)0;
444         return ERR;
445     }
446 
447     _panel_unlink(pan);
448 
449     return OK;
450 }
451 
move_panel(PANEL * pan,int starty,int startx)452 int move_panel(PANEL *pan, int starty, int startx)
453 {
454     WINDOW *win;
455     int maxy, maxx;
456 
457     if (!pan)
458         return ERR;
459 
460     if (_panel_is_linked(pan))
461         _override(pan, 0);
462 
463     win = pan->win;
464 
465     if (mvwin(win, starty, startx) == ERR)
466         return ERR;
467 
468     getbegyx(win, pan->wstarty, pan->wstartx);
469     getmaxyx(win, maxy, maxx);
470     pan->wendy = pan->wstarty + maxy;
471     pan->wendx = pan->wstartx + maxx;
472 
473     if (_panel_is_linked(pan))
474         _calculate_obscure();
475 
476     return OK;
477 }
478 
new_panel(WINDOW * win)479 PANEL *new_panel(WINDOW *win)
480 {
481     PANEL *pan;
482 
483     if (!win)
484         return (PANEL *)NULL;
485 
486     pan  = malloc(sizeof(PANEL));
487 
488     if (!_stdscr_pseudo_panel.win)
489     {
490         _stdscr_pseudo_panel.win = stdscr;
491         _stdscr_pseudo_panel.wstarty = 0;
492         _stdscr_pseudo_panel.wstartx = 0;
493         _stdscr_pseudo_panel.wendy = LINES;
494         _stdscr_pseudo_panel.wendx = COLS;
495         _stdscr_pseudo_panel.user = "stdscr";
496         _stdscr_pseudo_panel.obscure = (PANELOBS *)0;
497     }
498 
499     if (pan)
500     {
501         int maxy, maxx;
502 
503         pan->win = win;
504         pan->above = (PANEL *)0;
505         pan->below = (PANEL *)0;
506         getbegyx(win, pan->wstarty, pan->wstartx);
507         getmaxyx(win, maxy, maxx);
508         pan->wendy = pan->wstarty + maxy;
509         pan->wendx = pan->wstartx + maxx;
510 #ifdef PANEL_DEBUG
511         pan->user = "new";
512 #else
513         pan->user = (char *)0;
514 #endif
515         pan->obscure = (PANELOBS *)0;
516         show_panel(pan);
517     }
518 
519     return pan;
520 }
521 
panel_above(const PANEL * pan)522 PANEL *panel_above(const PANEL *pan)
523 {
524     return pan ? pan->above : _bottom_panel;
525 }
526 
panel_below(const PANEL * pan)527 PANEL *panel_below(const PANEL *pan)
528 {
529     return pan ? pan->below : _top_panel;
530 }
531 
panel_hidden(const PANEL * pan)532 int panel_hidden(const PANEL *pan)
533 {
534     if (!pan)
535         return ERR;
536 
537     return _panel_is_linked(pan) ? ERR : OK;
538 }
539 
panel_userptr(const PANEL * pan)540 const void *panel_userptr(const PANEL *pan)
541 {
542     return pan ? pan->user : NULL;
543 }
544 
panel_window(const PANEL * pan)545 WINDOW *panel_window(const PANEL *pan)
546 {
547     PDC_LOG(("panel_window() - called\n"));
548 
549     if (!pan)
550         return (WINDOW *)NULL;
551 
552     return pan->win;
553 }
554 
replace_panel(PANEL * pan,WINDOW * win)555 int replace_panel(PANEL *pan, WINDOW *win)
556 {
557     int maxy, maxx;
558 
559     if (!pan)
560         return ERR;
561 
562     if (_panel_is_linked(pan))
563         _override(pan, 0);
564 
565     pan->win = win;
566     getbegyx(win, pan->wstarty, pan->wstartx);
567     getmaxyx(win, maxy, maxx);
568     pan->wendy = pan->wstarty + maxy;
569     pan->wendx = pan->wstartx + maxx;
570 
571     if (_panel_is_linked(pan))
572         _calculate_obscure();
573 
574     return OK;
575 }
576 
set_panel_userptr(PANEL * pan,const void * uptr)577 int set_panel_userptr(PANEL *pan, const void *uptr)
578 {
579     if (!pan)
580         return ERR;
581 
582     pan->user = uptr;
583     return OK;
584 }
585 
show_panel(PANEL * pan)586 int show_panel(PANEL *pan)
587 {
588     if (!pan)
589         return ERR;
590 
591     if (pan == _top_panel)
592         return OK;
593 
594     if (_panel_is_linked(pan))
595         hide_panel(pan);
596 
597     _panel_link_top(pan);
598 
599     return OK;
600 }
601 
top_panel(PANEL * pan)602 int top_panel(PANEL *pan)
603 {
604     return show_panel(pan);
605 }
606 
update_panels(void)607 void update_panels(void)
608 {
609     PANEL *pan;
610 
611     PDC_LOG(("update_panels() - called\n"));
612 
613     pan = _bottom_panel;
614 
615     while (pan)
616     {
617         _override(pan, -1);
618         pan = pan->above;
619     }
620 
621     if (is_wintouched(stdscr))
622         Wnoutrefresh(&_stdscr_pseudo_panel);
623 
624     pan = _bottom_panel;
625 
626     while (pan)
627     {
628         if (is_wintouched(pan->win) || !pan->above)
629             Wnoutrefresh(pan);
630 
631         pan = pan->above;
632     }
633 }
634