|
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 |
|
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 |
|
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 |
|
165 static void Wnoutrefresh(PANEL *pan) |
|
166 { |
|
167 dPanel("wnoutrefresh", pan); |
|
168 wnoutrefresh(pan->win); |
|
169 } |
|
170 |
|
171 static void Touchpan(PANEL *pan) |
|
172 { |
|
173 dPanel("Touchpan", pan); |
|
174 touchwin(pan->win); |
|
175 } |
|
176 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
522 PANEL *panel_above(const PANEL *pan) |
|
523 { |
|
524 return pan ? pan->above : _bottom_panel; |
|
525 } |
|
526 |
|
527 PANEL *panel_below(const PANEL *pan) |
|
528 { |
|
529 return pan ? pan->below : _top_panel; |
|
530 } |
|
531 |
|
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 |
|
540 const void *panel_userptr(const PANEL *pan) |
|
541 { |
|
542 return pan ? pan->user : NULL; |
|
543 } |
|
544 |
|
545 WINDOW *panel_window(const PANEL *pan) |
|
546 { |
|
547 PDC_LOG(("panel_window() - called\n")); |
|
548 |
|
549 return pan->win; |
|
550 } |
|
551 |
|
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 |
|
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 |
|
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 |
|
599 int top_panel(PANEL *pan) |
|
600 { |
|
601 return show_panel(pan); |
|
602 } |
|
603 |
|
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 } |