You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
373 lines
13 KiB
C
373 lines
13 KiB
C
/* Demonstrates/tests panel library. Based loosely on example from
|
|
|
|
http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/panels.html
|
|
|
|
Should look like this when you run it (note that your editor
|
|
should be set to UTF-8; otherwise, you'll see some garbage) :
|
|
|
|
-------- Top of screen -----------
|
|
Hit 1-3 to move panels 1-3 to the top
|
|
Cursor keys move the top panel
|
|
Tab toggles display of top panel
|
|
Click on a panel to bring to top/send to bottom
|
|
Escape or q exits the program
|
|
r causes the panel to be repositioned at random
|
|
┌──────────────────────────────────────┐
|
|
│ ┌──────────────────────────────────────┐
|
|
│ │ ┌──────────────────────────────────────┐
|
|
│ │ │ │
|
|
│ │ │ │
|
|
│ │ │ │
|
|
│ │ │ │
|
|
│ │ │ Window 3 │
|
|
│ │ │ │
|
|
└────│ │ │
|
|
└────│ │
|
|
└──────────────────────────────────────┘
|
|
*/
|
|
|
|
#define PDC_NCMOUSE
|
|
#define _XOPEN_SOURCE_EXTENDED 1
|
|
|
|
#include <panel.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <locale.h>
|
|
|
|
#include "../demos/snprintf.c"
|
|
|
|
#if !defined( __PDCURSESMOD__) && !NCURSES_SP_FUNCS
|
|
/* Older ncurses may lack ceiling_panel() and ground_panel() */
|
|
|
|
PANEL *ceiling_panel( SCREEN *sp)
|
|
{
|
|
return( panel_below( NULL));
|
|
}
|
|
|
|
PANEL *ground_panel( SCREEN *sp)
|
|
{
|
|
return( panel_above( NULL));
|
|
}
|
|
#endif /* #ifndef NCURSES_SP_FUNCS */
|
|
|
|
/* To determine on which panel (if any) the mouse was clicked,
|
|
cycle through panel_below() until you find that (x, y) is within
|
|
the window extents, or you get a NULL panel. */
|
|
|
|
PANEL *panel_from_point( const int y, const int x)
|
|
{
|
|
PANEL *curr = NULL;
|
|
|
|
while( (curr = panel_below( curr)) != NULL)
|
|
{
|
|
WINDOW *win = panel_window( curr);
|
|
const int x0 = getbegx( win), y0 = getbegy( win);
|
|
|
|
if( x >= x0 && y >= y0 && x - x0 < getmaxx( win)
|
|
&& y - y0 < getmaxy( win))
|
|
return( curr);
|
|
}
|
|
return( NULL);
|
|
}
|
|
|
|
#ifdef WACS_S1
|
|
# define HAVE_WIDE 1
|
|
#endif
|
|
|
|
#ifdef HAVE_WIDE
|
|
|
|
#define CHOOSE( A, B) (B)
|
|
|
|
#define BOX_SD_RTEE CHOOSE( 0xb5, 0x2561)
|
|
#define BOX_DS_RTEE CHOOSE( 0xb6, 0x2562)
|
|
#define BOX_DS_URCORNER CHOOSE( 0xb7, 0x2556)
|
|
#define BOX_SD_URCORNER CHOOSE( 0xb8, 0x2555)
|
|
#define BOX_D_RTEE CHOOSE( 0xb9, 0x2563)
|
|
#define BOX_D_VLINE CHOOSE( 0xba, 0x2551)
|
|
#define BOX_D_URCORNER CHOOSE( 0xbb, 0x2557)
|
|
#define BOX_D_LRCORNER CHOOSE( 0xbc, 0x255D)
|
|
#define BOX_DS_LRCORNER CHOOSE( 0xbd, 0x255c)
|
|
#define BOX_SD_LRCORNER CHOOSE( 0xbe, 0x255b)
|
|
|
|
#define BOX_SD_LTEE CHOOSE( 0xc6, 0x255e)
|
|
#define BOX_DS_LTEE CHOOSE( 0xc7, 0x255f)
|
|
#define BOX_D_LLCORNER CHOOSE( 0xc8, 0x255A)
|
|
#define BOX_D_ULCORNER CHOOSE( 0xc9, 0x2554)
|
|
#define BOX_D_BTEE CHOOSE( 0xca, 0x2569)
|
|
#define BOX_D_TTEE CHOOSE( 0xcb, 0x2566)
|
|
#define BOX_D_LTEE CHOOSE( 0xcc, 0x2560)
|
|
#define BOX_D_HLINE CHOOSE( 0xcd, 0x2550)
|
|
#define BOX_D_PLUS CHOOSE( 0xce, 0x256C)
|
|
#define BOX_SD_BTEE CHOOSE( 0xcf, 0x2567)
|
|
|
|
#define BOX_DS_BTEE CHOOSE( 0xd0, 0x2568)
|
|
#define BOX_SD_TTEE CHOOSE( 0xd1, 0x2564)
|
|
#define BOX_DS_TTEE CHOOSE( 0xd2, 0x2565)
|
|
#define BOX_DS_LLCORNER CHOOSE( 0xd3, 0x2559)
|
|
#define BOX_SD_LLCORNER CHOOSE( 0xd4, 0x2558)
|
|
#define BOX_SD_ULCORNER CHOOSE( 0xd5, 0x2552)
|
|
#define BOX_DS_ULCORNER CHOOSE( 0xd6, 0x2553)
|
|
#define BOX_DS_PLUS CHOOSE( 0xd7, 0x256b)
|
|
#define BOX_SD_PLUS CHOOSE( 0xd8, 0x256a)
|
|
|
|
#define BOX_URROUNDED CHOOSE( 0xbf, 0x256e)
|
|
#define BOX_LLROUNDED CHOOSE( 0xc0, 0x2570)
|
|
#define BOX_LRROUNDED CHOOSE( 0xd9, 0x256f)
|
|
#define BOX_ULROUNDED CHOOSE( 0xda, 0x256d)
|
|
|
|
#define BOX_VLINE CHOOSE( 0xb3, 0x2502)
|
|
#define BOX_RTEE CHOOSE( 0xb4, 0x2524)
|
|
#define BOX_URCORNER CHOOSE( 0xbf, 0x2510)
|
|
#define BOX_LLCORNER CHOOSE( 0xc0, 0x2514)
|
|
#define BOX_LRCORNER CHOOSE( 0xd9, 0x2518)
|
|
#define BOX_ULCORNER CHOOSE( 0xda, 0x250c)
|
|
#define BOX_BTEE CHOOSE( 0xc1, 0x2534)
|
|
#define BOX_TTEE CHOOSE( 0xc2, 0x252c)
|
|
#define BOX_LTEE CHOOSE( 0xc3, 0x251c)
|
|
#define BOX_HLINE CHOOSE( 0xc4, 0x2500)
|
|
#define BOX_PLUS CHOOSE( 0xc5, 0x253c)
|
|
|
|
#define BOX_URROUNDED CHOOSE( 0xbf, 0x256e)
|
|
#define BOX_LLROUNDED CHOOSE( 0xc0, 0x2570)
|
|
#define BOX_LRROUNDED CHOOSE( 0xd9, 0x256f)
|
|
#define BOX_ULROUNDED CHOOSE( 0xda, 0x256d)
|
|
|
|
#define BOX_T_URCORNER CHOOSE( 0xbf, 0x2513)
|
|
#define BOX_T_LRCORNER CHOOSE( 0xd9, 0x251b)
|
|
#define BOX_T_ULCORNER CHOOSE( 0xda, 0x250f)
|
|
#define BOX_T_LLCORNER CHOOSE( 0xc0, 0x2517)
|
|
#define BOX_T_BTEE CHOOSE( 0xc1, 0x253b)
|
|
#define BOX_T_TTEE CHOOSE( 0xc2, 0x2533)
|
|
#define BOX_T_LTEE CHOOSE( 0xc3, 0x2523)
|
|
#define BOX_T_RTEE CHOOSE( 0xb4, 0x252b)
|
|
#define BOX_T_HLINE CHOOSE( 0xc4, 0x2501)
|
|
#define BOX_T_VLINE CHOOSE( 0xb3, 0x2503)
|
|
#define BOX_T_PLUS CHOOSE( 0xc5, 0x254b)
|
|
|
|
#define BOX_DOUBLED_V 1
|
|
#define BOX_DOUBLED_H 2
|
|
#define BOX_THICK 4
|
|
#define BOX_ROUNDED 8
|
|
|
|
static int _set_up_box( WINDOW *win, const int ls, const int rs,
|
|
const int ts, const int bs, const int tl, const int tr,
|
|
const int bl, const int br)
|
|
{
|
|
wchar_t x[8], string[2];
|
|
cchar_t c[8];
|
|
size_t i;
|
|
|
|
x[0] = (wchar_t)ls; x[1] = (wchar_t)rs;
|
|
x[2] = (wchar_t)ts; x[3] = (wchar_t)bs;
|
|
x[4] = (wchar_t)tl; x[5] = (wchar_t)tr;
|
|
x[6] = (wchar_t)bl; x[7] = (wchar_t)br;
|
|
string[1] = '\0';
|
|
for( i = 0; i < 8; i++)
|
|
{
|
|
string[0] = x[i];
|
|
setcchar( c + i, string, 0, 0, NULL);
|
|
}
|
|
return( wborder_set( win, c, c + 1, c + 2, c + 3, c + 4, c + 5, c + 6, c + 7));
|
|
}
|
|
|
|
static int _show_box( WINDOW *win, const int style)
|
|
{
|
|
switch( style)
|
|
{
|
|
case 0: /* 'normal' single-line */
|
|
_set_up_box( win, BOX_VLINE, BOX_VLINE, BOX_HLINE, BOX_HLINE,
|
|
BOX_ULCORNER, BOX_URCORNER, BOX_LLCORNER, BOX_LRCORNER);
|
|
break;
|
|
case BOX_DOUBLED_H:
|
|
_set_up_box( win, BOX_VLINE, BOX_VLINE, BOX_D_HLINE, BOX_D_HLINE,
|
|
BOX_SD_ULCORNER, BOX_SD_URCORNER, BOX_SD_LLCORNER, BOX_SD_LRCORNER);
|
|
break;
|
|
case BOX_DOUBLED_V:
|
|
_set_up_box( win, BOX_D_VLINE, BOX_D_VLINE, BOX_HLINE, BOX_HLINE,
|
|
BOX_DS_ULCORNER, BOX_DS_URCORNER, BOX_DS_LLCORNER, BOX_DS_LRCORNER);
|
|
break;
|
|
case BOX_DOUBLED_V | BOX_DOUBLED_H:
|
|
_set_up_box( win, BOX_D_VLINE, BOX_D_VLINE, BOX_D_HLINE, BOX_D_HLINE,
|
|
BOX_D_ULCORNER, BOX_D_URCORNER, BOX_D_LLCORNER, BOX_D_LRCORNER);
|
|
break;
|
|
case BOX_THICK:
|
|
_set_up_box( win, BOX_T_VLINE, BOX_T_VLINE, BOX_T_HLINE, BOX_T_HLINE,
|
|
BOX_T_ULCORNER, BOX_T_URCORNER, BOX_T_LLCORNER, BOX_T_LRCORNER);
|
|
break;
|
|
case BOX_ROUNDED:
|
|
_set_up_box( win, BOX_VLINE, BOX_VLINE, BOX_HLINE, BOX_HLINE,
|
|
BOX_ULROUNDED, BOX_URROUNDED, BOX_LLROUNDED, BOX_LRROUNDED);
|
|
break;
|
|
}
|
|
return( 0);
|
|
}
|
|
#else /* non-wide builds */
|
|
#define INTENTIONALLY_UNUSED_PARAMETER( param) (void)(param)
|
|
|
|
static int _show_box( WINDOW *win, const int style)
|
|
{
|
|
INTENTIONALLY_UNUSED_PARAMETER( style);
|
|
return( box( win, 0, 0));
|
|
}
|
|
#endif
|
|
|
|
int main( const int argc, const char **argv)
|
|
{
|
|
WINDOW *my_wins[3];
|
|
PANEL *my_panels[3];
|
|
int lines = 10, cols = 40, y = 8, x = 4, i, c = 0;
|
|
int box_style = 0;
|
|
SCREEN *screen_pointer;
|
|
|
|
setlocale(LC_ALL, (argc == 1 ? "" : argv[1]));
|
|
screen_pointer = newterm(NULL, stdout, stdin);
|
|
cbreak();
|
|
noecho();
|
|
keypad( stdscr, 1);
|
|
mousemask( ALL_MOUSE_EVENTS, NULL);
|
|
|
|
/* Create windows for the panels */
|
|
my_wins[0] = newwin(lines, cols, y, x);
|
|
my_wins[1] = newwin(lines, cols, y + 1, x + 5);
|
|
my_wins[2] = newwin(lines, cols, y + 2, x + 10);
|
|
|
|
/*
|
|
* Create borders around the windows so that you can see the effect
|
|
* of panels
|
|
*/
|
|
for(i = 0; i < 3; ++i)
|
|
_show_box(my_wins[i], box_style);
|
|
|
|
/* Attach a panel to each window */ /* Order is bottom up */
|
|
my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */
|
|
my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */
|
|
my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */
|
|
for( i = 0; i < 3; i++)
|
|
{
|
|
char text[20];
|
|
|
|
snprintf( text, sizeof( text), "Window %d", i + 1);
|
|
mvwaddstr( my_wins[i], 5, 5, text);
|
|
}
|
|
mvaddstr( 1, 1, "Hit 1-3 to move panels 1-3 to the top");
|
|
mvaddstr( 2, 1, "Cursor keys move the top panel");
|
|
mvaddstr( 3, 1, "Tab toggles display of top panel");
|
|
mvaddstr( 4, 1, "Click on a panel to bring to top/send to bottom");
|
|
#ifdef __PDCURSESMOD__
|
|
mvaddstr( 5, 1, "h, v toggle doubled horiz/vert lines");
|
|
#endif
|
|
mvaddstr( 6, 1, "Escape or q exits the program");
|
|
mvaddstr( 7, 1, "r causes the panel to be repositioned at random");
|
|
|
|
/* Update the stacking order. 2nd panel will be on top */
|
|
while( c != 27 && c != 'q')
|
|
{
|
|
PANEL *curr_top = ceiling_panel( NULL);
|
|
|
|
update_panels();
|
|
|
|
/* Show it on the screen */
|
|
doupdate();
|
|
|
|
c = getch();
|
|
switch( c)
|
|
{
|
|
case '1': case '2': case '3':
|
|
top_panel( my_panels[c - '1']);
|
|
break;
|
|
case 9:
|
|
if( curr_top)
|
|
{
|
|
#ifdef __PDCURSES__
|
|
if( panel_hidden( curr_top) == OK)
|
|
#else
|
|
if( panel_hidden( curr_top) == TRUE)
|
|
#endif
|
|
show_panel( curr_top);
|
|
else
|
|
hide_panel( curr_top);
|
|
}
|
|
break;
|
|
#ifdef HAVE_WIDE
|
|
case 'v':
|
|
case 'h':
|
|
case 't':
|
|
if( c == 't')
|
|
{
|
|
if( box_style == BOX_ROUNDED)
|
|
box_style = 0;
|
|
else if( box_style == BOX_THICK)
|
|
box_style = BOX_ROUNDED;
|
|
else
|
|
box_style = BOX_THICK;
|
|
}
|
|
else if( c == 'v')
|
|
box_style ^= BOX_DOUBLED_V;
|
|
else
|
|
box_style ^= BOX_DOUBLED_H;
|
|
for(i = 0; i < 3; ++i)
|
|
_show_box(my_wins[i], box_style);
|
|
update_panels();
|
|
break;
|
|
#endif
|
|
case KEY_LEFT: case KEY_RIGHT: case KEY_UP: case KEY_DOWN:
|
|
if( curr_top)
|
|
{
|
|
WINDOW *win = panel_window( curr_top);
|
|
|
|
x = getbegx( win);
|
|
y = getbegy( win);
|
|
if( c == KEY_LEFT)
|
|
x--;
|
|
if( c == KEY_RIGHT)
|
|
x++;
|
|
if( c == KEY_UP)
|
|
y--;
|
|
if( c == KEY_DOWN)
|
|
y++;
|
|
if( move_panel( curr_top, y, x) == ERR)
|
|
flash( );
|
|
}
|
|
break;
|
|
case 'r':
|
|
if( curr_top)
|
|
move_panel( curr_top, rand( ) % (LINES - lines), rand( ) % (COLS - cols));
|
|
break;
|
|
case KEY_MOUSE:
|
|
{
|
|
MEVENT mouse_event;
|
|
PANEL *clicked_on_panel;
|
|
|
|
getmouse( &mouse_event);
|
|
clicked_on_panel = panel_from_point( mouse_event.y, mouse_event.x);
|
|
if( clicked_on_panel)
|
|
{
|
|
if( clicked_on_panel == ceiling_panel( NULL)) /* it's already on top */
|
|
bottom_panel( clicked_on_panel);
|
|
else
|
|
top_panel( clicked_on_panel);
|
|
}
|
|
}
|
|
break;
|
|
case KEY_RESIZE:
|
|
resize_term( 0, 0);
|
|
break;
|
|
case 'q':
|
|
break;
|
|
default:
|
|
flash( );
|
|
break;
|
|
}
|
|
}
|
|
endwin();
|
|
for( i = 0; i < 3; ++i)
|
|
{
|
|
del_panel( my_panels[i]);
|
|
delwin( my_wins[i]);
|
|
}
|
|
/* Not really needed, but ensures Valgrind */
|
|
delscreen( screen_pointer); /* says all memory was freed */
|
|
return( 0);
|
|
}
|