Change-Id: If881ec130833c7e7e62caa3d31e350a531f5bc8e Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-on: http://review.coreboot.org/12398 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
		
			
				
	
	
		
			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;
 | |
|     }
 | |
| }
 |