Recall that a window is a rectangular area of the terminal screen on which you can write using the low-level ETI (curses) routines. You can create many windows on a screen, but if they overlap, portions of some windows intended to be hidden may nonetheless be visible when you use the low-level routines alone. To solve this problem, ETI uses the notion of a panel-a rectangle of text with depth.
Panels have depth only in relation to other panels and stdscr, which lies beneath all panels. The set of non-hidden panels comprises the ``deck'' of panels.
To use the panel routines, you specify
#include <panel.h>
in your C program files and compile and link with the command line
cc [ flags ] files -lpanel -lcurses [ libraries]
This function creates a new panel on top of all existing panels in the deck. Its argument is a pointer to a window.
SYNOPSIS PANEL *new_panel (window) WINDOW *window; /* curses window to be associated with new panel */
A pointer to the panel is returned if the panel is created; otherwise, the function returns NULL. The new_panel() operation fails if there is insufficient memory or if the window pointer argument is NULL. The window whose address is passed as an argument becomes associated with the panel. The size and location of the panel are the same as that of the low-level ETI (curses) window.
To create a panel, you create a window, save the pointer to it, and use the pointer as an argument to new_panel().
WINDOW *win; PANEL *pptr; win = newwin(2,6,0,3); pptr = new_panel(win); /* after execution, pptr stores pointer to new panel */
Note that the newly created panel does not automatically have any adornments such as titles or borders. If you want your panel to have them, you must call appropriate low-level ETI routines with the panel's window as the argument.
When you create a new panel, it is automatically placed on top of the panel deck. Later, when you call doupdate() to adjust the visibility of all panels, the top panel is completely visible. On lower levels, a portion of a panel is visible only when no region of another panel is above it. Where two panels overlap, the higher one hides the lower. (The higher one is the newer one if neither has changed its position in the panel deck because of calls to top_panel(), bottom_panel(), or show_panel() described below.) If the panels do not over-lap,the new panel is still logically above the old one. Their relative depth is not apparent until one of them is moved and overlaps the other.
This section explains how you can fetch pointers to panel windows, change the windows associated with panels, and move panel windows to new locations on the screen.
Each panel has a low-level ETI window associated with it. To retrieve a pointer to this window, you use the function panel_window().
SYNOPSIS WINDOW *panel_window(panel) PANEL *panel; /* Panel whose window pointer is returned */
The function returns NULL if the panel pointer argument is NULL.
In general, you may use this returned pointer as an argument to any standard low-level (curses) routine that takes a pointer to a window as an argument. For example, you can insert a character c at a location y,x in a panel window with the function mvwinsch(win,y,x,c), where win is the window pointer returned by panel_window9).
WINDOW *win; PANEL *panel; int y, x; chtype c; win = panel_window(panel); mvwinsch(win,y,x,c);
To replace a panel's pointer to a window with a pointer to another window, you call function replace_panel(). After the call, the panel remains at the same level within the panel deck.
SYNOPSIS int replace_panel (panel, window) PANEL *panel; /*Panel with window to be replaced */ WINDOW *window; /* New window pointer for panel */
This function returns OK if the operation is successful. If not, it returns ERR and leaves the original panel unchanged. Operation replace_panel() fails if the window pointer is NULL or there is insufficient memory.
To associate a panel with window win1 and later replace its window by win2, you can write the following:
WINDOW *win1, win2; PANEL *panel; panel = new_panel(win1); /* intervening processing with win1 as panel window */ replace_panel(panel, win2); /* change window associated with panel to win2 */
Once you have created additional windows with the low-level function newwin(), you in effect can reshape panel windows by using replace_panel(). To do so leaves the contents of the two windows unchanged.
You should not move a panel's window by calling the low-level function mvwin() directly. To update the screen correctly, the panels subsystem must know the location of all panel windows, but function mvwin() does not inform the panels subsystem of the window's new location. To move a panel's window, you must call the function move_panel(), which moves a panel and its associated window and informs the panels subsystem of the move.
SYNOPSIS int move_panel (panel, firstrow, firstcol) PANEL *panel; /* Panel to be moved */ int firstrow, firstcol; /* row/col of upper left corner of new location of window associated with panel */
Note that the screen coordinates you specify are those for the upper-left corner of the window in its new location. The panel may be moved to any location that the low-level ETI routines deem legitimate. In particular, a panel may be partly off the screen. The size, contents, and relative depth of the panel remain unchanged by move_panel().
Function move_panel() returns OK if the operation was successful, ERR otherwise. The move_panel() operation fails if the low-level ETI functions are unable to move the panel's window, or if there is insufficient memory to satisfy the request. In these cases, the original panel remains unchanged.
To move the panel pointed to by panel such that its upper- left corner is at row 22, column 45, you can write
PANEL *panel; move_panel(panel, 22, 45);
The relative depth of a panel can be changed by either pulling the panel to the top of the deck or by pushing it to the bottom. In either case, all other panels remain at the same depth relative to each other.
SYNOPSIS int top_panel(panel) PANEL *panel; int bottom_panel(panel) PANEL *panel;
Function top_panel() moves the panel pointed to by its argument to the top of the panel deck, while function bottom_panel() moves the panel to the bottom of the deck.
Both functions leave the size of the given panel, the contents of its associated window, and the relations of the other panels in the deck wholly intact. Both return OK if the operation is successful, ERR if not. The functions fail if the panel pointer argument is NULL or if the panel is hidden by a previous call to function hide_panel() described below.
To move the panel pointed to by panel1 to the top of the deck of panels and the panel pointed to by panel2 to the bottom of the deck, you can write the following:
PANEL *panel1, *panel2; top_panel(panel1); bottom_panel(panel2);
Function update_panels() makes all low-level curses calls (such as touchwin() and wnoutrefresh()) to update all panels so as to maintain proper depth relationships and to permit display only of the appropriate portions of panels.
SYNOPSIS void update_panels();
The function does not, however,actually refresh your terminal screen. To do that, you must make a call to doupdate() whenever you want to display your latest changes.
To avoid displaying text on hidden panels, you should not use the low-level routines wnoutrefresh() and wrefresh() when working with panels.
CAUTION: In general, do not use the low-level routines wnoutrefresh() or wrefresh to display a window associated with a panel. Instead, use function update_panels and function doupdate to display the entire deck of panels.
If you use the low-level routines wnoutrefresh() or wrefresh() for a window associated with a panel, it is not displayed properly unless it happens to be associated with the top panel in the deck or is not hidden at all by other panel windows.
Recall that panels are always above stdscr, the standard ETI window. When a panel is moved or deleted, stdscr is updated along with the visible panels to ensure that it appears beneath all panels. Although stdscr has depth relative to other panels, it is not a panel because panel operations like top_panel() and bottom_panel() do not apply.However, because stdscr rests beneath the deck of panels, you should always call update_panels() when you work with panels and change stdscr, even if you do not change any panels themselves.
Function wgetch() automatically calls wrefresh(). Hence, if echo mode is active, when you request input from a window associated with a panel, be sure that the window is totally unobscured.
In summary, to update all panels and display them with their proper depth relationship, you write:
WINDOW *win; update_panels(); doupdate();
Note finally that there is no way to display the updates to an obscured panel without displaying the changes to all panels.
ETI allows you to hide panels from the deck and later return them to it.
Panels may be temporarily hidden. This means that they are removed from the panel deck, but the memory allocated to them is not released.
SYNOPSIS int hide_panel(panel) PANEL *panel; /* Pointer to panel to be hidden */
Hidden panels are not refreshed to the screen, but you may nonetheless apply nearly all panel operations to them.
NOTE: Only the operations top_panel(), bottom_panel(), and hide_panel() itself may not be applied to hidden panels because their panel arguments must belong to the deck of panels.
When you want to return a hidden panel to the deck of panels, you use the function show_panel() described in the next section. When the panel is returned, it is placed on top of the deck.
To hide the panel pointed to by panel2 above, you write
PANEL *panel2; hide_panel(panel2);
Function hide_panel() returns OK if the operation is successful and ERR if its panel pointer argument is NULL.
If you use function hide_panel() wisely, your program's performance can increase. You can hide a panel temporarily if no portion of it is to be displayed for awhile. An example is the hiding of a pop-up message. Interim calls to function update_panels will then execute faster. More importantly,you do not incur the overhead of creating the pop-up message.
To enable you to check if a given panel is hidden, ETI provides the following function.
SYNOPSIS int panel_hidden (panel) PANEL *panel;
Function panel_hidden() returns a Boolean value (TRUE or FALSE)indicating whether or not its panel argument is hidden.
You might want to use this function before calling functions top_panel() or bottom_panel(), which do not operate on hidden panels. For example, to minimize the risk of having the error value ERR returned when moving a panel to the top of the deck, you can write
PANEL *panel; If (! panel_hidden (panel)) /* panel in deck ? */ top_panel (panel); /* move panel to top of deck */
This function is the opposite of function hide_panel(). It returns the hidden panel referenced in its argument to the top of the panel deck.
SYNOPSIS int show_panel (panel) PANEL *panel; /* Panel to return to top of deck */
Note that the panel must have been hidden by a previous hide_panel() call. The function returns OK if the operation is successful, and ERR if the panel pointer is NULL, if there is insufficient memory, or if the panel is not hidden.
To return, say, panel2 to the deck, you write
PANEL *panel2; show_panel(panel2);
The following functions return a pointer to the panel immediately above or below the given panel. They are helpful in walking the panel deck from top to bottom or vice versa.
SYNOPSIS PANEL *panel_above (panel) PANEL *panel; /* Get panel above this one */ PANEL *panel_below (panel) PANEL *panel; /* Get panel below this one */
Because hidden panels have no depth, they are excluded from these traversals.
Function panel_above() returns the panel immediately above the given panel. If its argument is NULL, it returns the bottommost panel. The function returns NULL if the given panel is on top or hidden, or if there are no visible panels.
Function panel_below() returns the panel immediately below the given panel. If its argument is NULL, it returns the topmost panel. The function returns NULL if the given panel is on the bottom of the deck of panels or hidden, or if there are no visible panels at all. There may be no visible panels at all if
If you want to do something to all panels or to search all of them for one with a particular attribute, you can place one of these functions in a loop. For example, to hide all panels (perhaps to display stdscr alone), you can write
{ PANEL *panel, *pnl; for (panel = panel_above (NULL); panel; panel = panel_above(pnl)) { pnl = panel; hide_panel(panel); } }
To enable your application program to associate arbitrary data with a given panel, the ETI panel subsystem automatically allocates a pointer associated with each newly created panel. Initially, the value of this user pointer is NULL. You can set its value to whatever you want or not use it at all.
SYNOPSIS int *set_panel_userptr (panel, ptr) PANEL *panel; /*Panel whose user pointer to set */ char *ptr; /* user- defined pointer */ char *panel_userptr (panel) PANEL *panel; /* Panel whose user pointer to fetch */
The user pointer has no meaning to the panels subsystem. Once the panel is created, the user pointer is neither changed nor accessed by the subsystem.
Function set_panel_userptr() sets the user pointer of a given panel to the value of your choice. The function returns OK if the operation is successful, and ERR if the panel pointer is NULL.
Function panel_userptr() returns the user pointer for a given panel. If the panel pointer is NULL, the function returns NULL.
You can use these routines to store and retrieve a pointer to an arbitrary structure that holds information for your application. For example, you might use them to store a title or, as in the following screen, create a hidden panel for pop-up messages.
Example Using Panel User Pointer
PANEL *msg_panel; char *message = "Pop-up Message Here"; /* initialize message */ int display_deck (show_it) int show_it; { WINDOW *w; int rows, cols; if (show_it) { show_panel (msg_panel); /* reinstate panel */ w = panel_window (msg_panel); /* fetch associated window */ getmaxyx (w, rows, cols); /* fetch window size */ /* center cursor */ wmove (w, (rows-1), ((cols-1) - strlen(message))/2); /* fetch and write pop-up message */ waddstr (w, panel_userptr (msg_panel)); } update_panels(); /* display deck with message, if called for */ doupdate(); if (show_it) hide_panel (msg_panel); /* hide panel again, if necessary */ } main() { int show_mess = FALSE; msg_panel = new_panel (newwin (10, 10, 5, 60)); set_panel_userptr (msg_panel, message); /*associate message with panel */ hide_panel (msg_panel); /* remove from visible deck */ /* if condition to display pop-up message is satisfied, set show_mess to TRUE */ display_deck (show_mess);
After creating a window and its associated panel, main() calls set_panel_userptr() to set the panel user pointer to point to the panel's pop-up message string. Function hide_panel() hides the panel from the deck so that it is not normally displayed. Later, the application-defined routine display_deck() checks if the message is to be displayed. If so, it calls show_panel() which returns the panel to the deck and enables the panel to become visible on the next update and refresh. The message string returned by panel_userptr() is then written to the panel window. Finally, update_panels() adjusts the relative visibility of all panels in the deck and doupdate refreshes the screen. If called for, the pop-up message is now visible.
The following function deletes a panel, but not its associated window. If you want to delete the window, you should use the low-level function delwin().
SYNOPSIS int del_panel (panel) PANEL *panel; /* Panel to be deleted */
The ETI panels subsystem assumes that the window associated with each panel always exists.
NOTE: If you want to delete a panel and its associated window, make sure that you delete the panel first, not the window. Your call to del_panel() should precede your call to delwin().
However, it is not necessary to delete a window after its associated panel is deleted: if you like, you may associate the window with another panel.
Function del_panel() returns OK if the operation was successful, ERR otherwise. The del_panel() operation fails if the panel pointer is NULL.
To delete the panel referenced by panel and its associated window referenced by win, you can write
PANEL *panel; WINDOW *win = panel_window(panel); del_panel(panel); delwin(win);