| /* 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; |
| } |
| } |