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