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