631 lines
15 KiB
C
631 lines
15 KiB
C
|
/* 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;
|
||
|
}
|
||
|
}
|