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