--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pdcurses/panel.c Sat Jan 09 17:41:21 2016 +0200 @@ -0,0 +1,630 @@ +/* Public Domain Curses */ + +#include <curspriv.h> + +RCSID("$Id: panel.c,v 1.8 2008/07/14 12:35:23 wmcbrine Exp $") + +/*man-start************************************************************** + + Name: panel + + Synopsis: + int bottom_panel(PANEL *pan); + int del_panel(PANEL *pan); + int hide_panel(PANEL *pan); + int move_panel(PANEL *pan, int starty, int startx); + PANEL *new_panel(WINDOW *win); + PANEL *panel_above(const PANEL *pan); + PANEL *panel_below(const PANEL *pan); + int panel_hidden(const PANEL *pan); + const void *panel_userptr(const PANEL *pan); + WINDOW *panel_window(const PANEL *pan); + int replace_panel(PANEL *pan, WINDOW *win); + int set_panel_userptr(PANEL *pan, const void *uptr); + int show_panel(PANEL *pan); + int top_panel(PANEL *pan); + void update_panels(void); + + Description: + The panel library is built using the curses library, and any + program using panels routines must call one of the curses + initialization routines such as initscr(). A program using these + routines must be linked with the panels and curses libraries. + The header <panel.h> includes the header <curses.h>. + + The panels package gives the applications programmer a way to + have depth relationships between curses windows; a curses window + is associated with every panel. The panels routines allow curses + windows to overlap without making visible the overlapped + portions of underlying windows. The initial curses window, + stdscr, lies beneath all panels. The set of currently visible + panels is the 'deck' of panels. + + The panels package allows the applications programmer to create + panels, fetch and set their associated windows, shuffle panels + in the deck, and manipulate panels in other ways. + + bottom_panel() places pan at the bottom of the deck. The size, + location and contents of the panel are unchanged. + + del_panel() deletes pan, but not its associated winwow. + + hide_panel() removes a panel from the deck and thus hides it + from view. + + move_panel() moves the curses window associated with pan, so + that its upper lefthand corner is at the supplied coordinates. + (Do not use mvwin() on the window.) + + new_panel() creates a new panel associated with win and returns + the panel pointer. The new panel is placed at the top of the + deck. + + panel_above() returns a pointer to the panel in the deck above + pan, or NULL if pan is the top panel. If the value of pan passed + is NULL, this function returns a pointer to the bottom panel in + the deck. + + panel_below() returns a pointer to the panel in the deck below + pan, or NULL if pan is the bottom panel. If the value of pan + passed is NULL, this function returns a pointer to the top panel + in the deck. + + panel_hidden() returns OK if pan is hidden and ERR if it is not. + + panel_userptr() - Each panel has a user pointer available for + maintaining relevant information. This function returns a + pointer to that information previously set up by + set_panel_userptr(). + + panel_window() returns a pointer to the curses window associated + with the panel. + + replace_panel() replaces the current window of pan with win. + + set_panel_userptr() - Each panel has a user pointer available + for maintaining relevant information. This function sets the + value of that information. + + show_panel() makes a previously hidden panel visible and places + it back in the deck on top. + + top_panel() places pan on the top of the deck. The size, + location and contents of the panel are unchanged. + + update_panels() refreshes the virtual screen to reflect the + depth relationships between the panels in the deck. The user + must use doupdate() to refresh the physical screen. + + Return Value: + Each routine that returns a pointer to an object returns NULL if + an error occurs. Each panel routine that returns an integer, + returns OK if it executes successfully and ERR if it does not. + + Portability X/Open BSD SYS V + bottom_panel - - Y + del_panel - - Y + hide_panel - - Y + move_panel - - Y + new_panel - - Y + panel_above - - Y + panel_below - - Y + panel_hidden - - Y + panel_userptr - - Y + panel_window - - Y + replace_panel - - Y + set_panel_userptr - - Y + show_panel - - Y + top_panel - - Y + update_panels - - Y + + Credits: + Original Author - Warren Tucker <wht@n4hgf.mt-park.ga.us> + +**man-end****************************************************************/ + +#include <panel.h> +#include <stdlib.h> + +PANEL *_bottom_panel = (PANEL *)0; +PANEL *_top_panel = (PANEL *)0; +PANEL _stdscr_pseudo_panel = { (WINDOW *)0 }; + +#ifdef PANEL_DEBUG + +static void dPanel(char *text, PANEL *pan) +{ + PDC_LOG(("%s id=%s b=%s a=%s y=%d x=%d", text, pan->user, + pan->below ? pan->below->user : "--", + pan->above ? pan->above->user : "--", + pan->wstarty, pan->wstartx)); +} + +static void dStack(char *fmt, int num, PANEL *pan) +{ + char s80[80]; + + sprintf(s80, fmt, num, pan); + PDC_LOG(("%s b=%s t=%s", s80, _bottom_panel ? _bottom_panel->user : "--", + _top_panel ? _top_panel->user : "--")); + + if (pan) + PDC_LOG(("pan id=%s", pan->user)); + + pan = _bottom_panel; + + while (pan) + { + dPanel("stk", pan); + pan = pan->above; + } +} + +/* debugging hook for wnoutrefresh */ + +static void Wnoutrefresh(PANEL *pan) +{ + dPanel("wnoutrefresh", pan); + wnoutrefresh(pan->win); +} + +static void Touchpan(PANEL *pan) +{ + dPanel("Touchpan", pan); + touchwin(pan->win); +} + +static void Touchline(PANEL *pan, int start, int count) +{ + char s80[80]; + + sprintf(s80, "Touchline s=%d c=%d", start, count); + dPanel(s80, pan); + touchline(pan->win, start, count); +} + +#else /* PANEL_DEBUG */ + +#define dPanel(text, pan) +#define dStack(fmt, num, pan) +#define Wnoutrefresh(pan) wnoutrefresh((pan)->win) +#define Touchpan(pan) touchwin((pan)->win) +#define Touchline(pan, start, count) touchline((pan)->win, start, count) + +#endif /* PANEL_DEBUG */ + +static bool _panels_overlapped(PANEL *pan1, PANEL *pan2) +{ + if (!pan1 || !pan2) + return FALSE; + + return ((pan1->wstarty >= pan2->wstarty && pan1->wstarty < pan2->wendy) + || (pan2->wstarty >= pan1->wstarty && pan2->wstarty < pan1->wendy)) + && ((pan1->wstartx >= pan2->wstartx && pan1->wstartx < pan2->wendx) + || (pan2->wstartx >= pan1->wstartx && pan2->wstartx < pan1->wendx)); +} + +static void _free_obscure(PANEL *pan) +{ + PANELOBS *tobs = pan->obscure; /* "this" one */ + PANELOBS *nobs; /* "next" one */ + + while (tobs) + { + nobs = tobs->above; + free((char *)tobs); + tobs = nobs; + } + pan->obscure = (PANELOBS *)0; +} + +static void _override(PANEL *pan, int show) +{ + int y; + PANEL *pan2; + PANELOBS *tobs = pan->obscure; /* "this" one */ + + if (show == 1) + Touchpan(pan); + else if (!show) + { + Touchpan(pan); + Touchpan(&_stdscr_pseudo_panel); + } + else if (show == -1) + while (tobs && (tobs->pan != pan)) + tobs = tobs->above; + + while (tobs) + { + if ((pan2 = tobs->pan) != pan) + for (y = pan->wstarty; y < pan->wendy; y++) + if ((y >= pan2->wstarty) && (y < pan2->wendy) && + ((is_linetouched(pan->win, y - pan->wstarty)) || + (is_linetouched(stdscr, y)))) + Touchline(pan2, y - pan2->wstarty, 1); + + tobs = tobs->above; + } +} + +static void _calculate_obscure(void) +{ + PANEL *pan, *pan2; + PANELOBS *tobs; /* "this" one */ + PANELOBS *lobs; /* last one */ + + pan = _bottom_panel; + + while (pan) + { + if (pan->obscure) + _free_obscure(pan); + + lobs = (PANELOBS *)0; + pan2 = _bottom_panel; + + while (pan2) + { + if (_panels_overlapped(pan, pan2)) + { + if ((tobs = malloc(sizeof(PANELOBS))) == NULL) + return; + + tobs->pan = pan2; + dPanel("obscured", pan2); + tobs->above = (PANELOBS *)0; + + if (lobs) + lobs->above = tobs; + else + pan->obscure = tobs; + + lobs = tobs; + } + + pan2 = pan2->above; + } + + _override(pan, 1); + pan = pan->above; + } +} + +/* check to see if panel is in the stack */ + +static bool _panel_is_linked(const PANEL *pan) +{ + PANEL *pan2 = _bottom_panel; + + while (pan2) + { + if (pan2 == pan) + return TRUE; + + pan2 = pan2->above; + } + + return FALSE; +} + +/* link panel into stack at top */ + +static void _panel_link_top(PANEL *pan) +{ +#ifdef PANEL_DEBUG + dStack("<lt%d>", 1, pan); + if (_panel_is_linked(pan)) + return; +#endif + pan->above = (PANEL *)0; + pan->below = (PANEL *)0; + + if (_top_panel) + { + _top_panel->above = pan; + pan->below = _top_panel; + } + + _top_panel = pan; + + if (!_bottom_panel) + _bottom_panel = pan; + + _calculate_obscure(); + dStack("<lt%d>", 9, pan); +} + +/* link panel into stack at bottom */ + +static void _panel_link_bottom(PANEL *pan) +{ +#ifdef PANEL_DEBUG + dStack("<lb%d>", 1, pan); + if (_panel_is_linked(pan)) + return; +#endif + pan->above = (PANEL *)0; + pan->below = (PANEL *)0; + + if (_bottom_panel) + { + _bottom_panel->below = pan; + pan->above = _bottom_panel; + } + + _bottom_panel = pan; + + if (!_top_panel) + _top_panel = pan; + + _calculate_obscure(); + dStack("<lb%d>", 9, pan); +} + +static void _panel_unlink(PANEL *pan) +{ + PANEL *prev; + PANEL *next; + +#ifdef PANEL_DEBUG + dStack("<u%d>", 1, pan); + if (!_panel_is_linked(pan)) + return; +#endif + _override(pan, 0); + _free_obscure(pan); + + prev = pan->below; + next = pan->above; + + /* if non-zero, we will not update the list head */ + + if (prev) + { + prev->above = next; + if(next) + next->below = prev; + } + else if (next) + next->below = prev; + + if (pan == _bottom_panel) + _bottom_panel = next; + + if (pan == _top_panel) + _top_panel = prev; + + _calculate_obscure(); + + pan->above = (PANEL *)0; + pan->below = (PANEL *)0; + dStack("<u%d>", 9, pan); + +} + +/************************************************************************ + * The following are the public functions for the panels library. * + ************************************************************************/ + +int bottom_panel(PANEL *pan) +{ + if (!pan) + return ERR; + + if (pan == _bottom_panel) + return OK; + + if (_panel_is_linked(pan)) + hide_panel(pan); + + _panel_link_bottom(pan); + + return OK; +} + +int del_panel(PANEL *pan) +{ + if (pan) + { + if (_panel_is_linked(pan)) + hide_panel(pan); + + free((char *)pan); + return OK; + } + + return ERR; +} + +int hide_panel(PANEL *pan) +{ + if (!pan) + return ERR; + + if (!_panel_is_linked(pan)) + { + pan->above = (PANEL *)0; + pan->below = (PANEL *)0; + return ERR; + } + + _panel_unlink(pan); + + return OK; +} + +int move_panel(PANEL *pan, int starty, int startx) +{ + WINDOW *win; + int maxy, maxx; + + if (!pan) + return ERR; + + if (_panel_is_linked(pan)) + _override(pan, 0); + + win = pan->win; + + if (mvwin(win, starty, startx) == ERR) + return ERR; + + getbegyx(win, pan->wstarty, pan->wstartx); + getmaxyx(win, maxy, maxx); + pan->wendy = pan->wstarty + maxy; + pan->wendx = pan->wstartx + maxx; + + if (_panel_is_linked(pan)) + _calculate_obscure(); + + return OK; +} + +PANEL *new_panel(WINDOW *win) +{ + PANEL *pan = malloc(sizeof(PANEL)); + + if (!_stdscr_pseudo_panel.win) + { + _stdscr_pseudo_panel.win = stdscr; + _stdscr_pseudo_panel.wstarty = 0; + _stdscr_pseudo_panel.wstartx = 0; + _stdscr_pseudo_panel.wendy = LINES; + _stdscr_pseudo_panel.wendx = COLS; + _stdscr_pseudo_panel.user = "stdscr"; + _stdscr_pseudo_panel.obscure = (PANELOBS *)0; + } + + if (pan) + { + int maxy, maxx; + + pan->win = win; + pan->above = (PANEL *)0; + pan->below = (PANEL *)0; + getbegyx(win, pan->wstarty, pan->wstartx); + getmaxyx(win, maxy, maxx); + pan->wendy = pan->wstarty + maxy; + pan->wendx = pan->wstartx + maxx; +#ifdef PANEL_DEBUG + pan->user = "new"; +#else + pan->user = (char *)0; +#endif + pan->obscure = (PANELOBS *)0; + show_panel(pan); + } + + return pan; +} + +PANEL *panel_above(const PANEL *pan) +{ + return pan ? pan->above : _bottom_panel; +} + +PANEL *panel_below(const PANEL *pan) +{ + return pan ? pan->below : _top_panel; +} + +int panel_hidden(const PANEL *pan) +{ + if (!pan) + return ERR; + + return _panel_is_linked(pan) ? ERR : OK; +} + +const void *panel_userptr(const PANEL *pan) +{ + return pan ? pan->user : NULL; +} + +WINDOW *panel_window(const PANEL *pan) +{ + PDC_LOG(("panel_window() - called\n")); + + return pan->win; +} + +int replace_panel(PANEL *pan, WINDOW *win) +{ + int maxy, maxx; + + if (!pan) + return ERR; + + if (_panel_is_linked(pan)) + _override(pan, 0); + + pan->win = win; + getbegyx(win, pan->wstarty, pan->wstartx); + getmaxyx(win, maxy, maxx); + pan->wendy = pan->wstarty + maxy; + pan->wendx = pan->wstartx + maxx; + + if (_panel_is_linked(pan)) + _calculate_obscure(); + + return OK; +} + +int set_panel_userptr(PANEL *pan, const void *uptr) +{ + if (!pan) + return ERR; + + pan->user = uptr; + return OK; +} + +int show_panel(PANEL *pan) +{ + if (!pan) + return ERR; + + if (pan == _top_panel) + return OK; + + if (_panel_is_linked(pan)) + hide_panel(pan); + + _panel_link_top(pan); + + return OK; +} + +int top_panel(PANEL *pan) +{ + return show_panel(pan); +} + +void update_panels(void) +{ + PANEL *pan; + + PDC_LOG(("update_panels() - called\n")); + + pan = _bottom_panel; + + while (pan) + { + _override(pan, -1); + pan = pan->above; + } + + if (is_wintouched(stdscr)) + Wnoutrefresh(&_stdscr_pseudo_panel); + + pan = _bottom_panel; + + while (pan) + { + if (is_wintouched(pan->win) || !pan->above) + Wnoutrefresh(pan); + + pan = pan->above; + } +}