pdcurses/panel.c

changeset 97
2d43f05b284c
equal deleted inserted replaced
96:5314ebdcb38d 97:2d43f05b284c
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 }

mercurial