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