How to solve ncurses menu border misalignment - c

I'm using the following simple ncurses code to create a menu:
#include <menu.h>
#include <stdlib.h>
ITEM **it;
MENU *me;
WINDOW *win;
void quit(void)
{
int i;
unpost_menu(me);
free_menu(me);
for(i=0; i<=4; i++)
{
free_item(it[i]);
}
free(it);
delwin(win);
endwin();
}
int main(void)
{
int ch;
initscr();
atexit(quit);
clear();
noecho();
curs_set(0);
cbreak();
nl();
keypad(stdscr, TRUE);
start_color();
init_pair(1, COLOR_WHITE, COLOR_BLUE);
init_pair(2, COLOR_BLUE, COLOR_YELLOW);
bkgd(COLOR_PAIR(1));
it = (ITEM **)calloc(5, sizeof(ITEM *));
it[0] = new_item("M1", "Menueeintrag 1");
it[1] = new_item("M2", "Menueeintrag 2");
it[2] = new_item("M3", "Menueeintrag 3");
it[3] = new_item("Ende", "Programm beenden");
it[4] = 0;
me = new_menu(it);
win = newwin(8, 30, 5, 5);
set_menu_win (me, win);
set_menu_sub (me, derwin(win, 4, 28, 3, 2));
box(win, 0, 0);
mvwaddstr(win, 1, 2, "***** Testmenü *****");
set_menu_fore(me, COLOR_PAIR(1)|A_REVERSE);
set_menu_back(me, COLOR_PAIR(1));
wbkgd(win, COLOR_PAIR(2));
post_menu(me);
mvaddstr(14, 3, "Programm mittels Menü oder F1-Funktionstaste beenden");
refresh();
wrefresh(win);
while((ch=getch()) != KEY_F(1))
{
switch(ch)
{
case KEY_DOWN:
menu_driver(me, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(me, REQ_UP_ITEM);
break;
case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */
if(item_index(current_item(me)) == 3)
exit(0);
}
wrefresh(win);
}
return (0);
}
But at the positions where I put text there is always a weird misalignment. You can see it when looking at the border of the menu as well as at the right border of the terminal on the same height as the help text.
Screenshot of the resulting program

That umlaut on "Testmenü" tells the story: it is probably encoded as UTF-8, which uses two bytes:
252: 252 0374 0xfc text "\374" utf8 \303\274
If the locale settings are (for example) en_US, then that tells ncurses that the terminal doesn't use UTF-8, and it will assume that the string is actually ISO-8859-1. In that case, it counts both bytes of that character as separate cells on the screen.
Meanwhile, the terminal may be using UTF-8 encoding (and display the character as shown in the screenshot). But if the locale settings do not correspond to the terminal, you'll see odd stuff like that.

Related

Box passed window in ncurses.h

I'm having a hard time understanding the problem with a window in ncurses. I created a layout of several windows and want to have a function that will border a window. Look like this:
int main() {
use_env(TRUE);
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
WINDOW *win_corner = newwin(WCLINES, WCCOLS, WCX, WCY);
choose_lvl(win_corner);
...
}
int choose_lvl(WINDOW *win) {
box(win, 0, 0);
wrefresh(win);
refresh();
int c, curr_option = 0;
init_pair(1, COLOR_CYAN, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Choose your level");
...
}
It seems like box() doesnt have any effect at all - what could it be? My current theory is to suppose something wrong with the coordinates of the window.
refresh() refreshes the updates on stdscr. newwin() creates an independant window. A refresh on stdscr does not update the alternate window. The same without refresh() in choose_lvl() function would work fine as you would force update only on the alternate window.
You can also create a sub-window of stdscr with subwin() to make refresh() update the whole hierarchy:
#include <unistd.h>
#include <curses.h>
#define WCLINES 10
#define WCCOLS 80
#define WCX 4
#define WCY 4
int choose_lvl(WINDOW *win) {
box(win, 0, 0);
//wrefresh(win);
//refresh();
int c, curr_option = 0;
init_pair(1, COLOR_CYAN, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Choose your level");
refresh();
return 0;
}
int main() {
use_env(TRUE);
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
//WINDOW *win_corner = newwin(WCLINES, WCCOLS, WCX, WCY);
WINDOW *win_corner = subwin(stdscr, WCLINES, WCCOLS, WCX, WCY);
choose_lvl(win_corner);
// quick&dirty pause to suspend program execution
// right after the windows display
pause();
return 0;
}
Execution:
$ gcc win.c -lncurses
$ ./a.out
The result is:

Ncurses - wgetch(window) not showing output

I've been struggling to get any input from Ncurses working. The keyboard input works fine if I use stdscr rather than my custom window. However, if I use the stdscr, I get absolutely no output to the terminal.
Here is my compile argument:
gcc -o dungeon dungeon.c -lncursesw
Code in question:
setlocale(LC_ALL, "");
int key;
window = newwin(XLEN, YLEN, 0, 0);
keypad(window, TRUE);
initscr();
clear();
noecho();
cbreak();
refresh();
while (player.alive && !playerWin(monsters)){
key = wgetch(window);
if (key == 'y' || key == '7'){
player.alive = 0;
}
render(monsters);
refresh();
for(i = 0; i < numMonsters; i++){
moveMonsters(&monsters[i]);
}
monsterPlayerCollision(monsters);
int dead = monsterMonsterCollision(monsters);
if(dead){
monsters[dead].alive = 0;
}
dijkstraNon();
dijkstraTunnel();
clear();
usleep(3);
wrefresh(window);
}
Please let me know if there's anything I can do to clarify.

Accessing libraries and functions between multiple source files [duplicate]

This question already has answers here:
"Multiple definition", "first defined here" errors
(6 answers)
Closed 5 years ago.
I am running a program which makes use of the ncurses library to display windows in the terminal containing data being updated and inserted into its corresponding window from my main source file.
I have a separate file with its own header file which contains printf statements I would like to convert to ncurse functions. And display within the windows I created.
ncurses required some setup and made use of some small functions so im unsure how to use it within both files. I tried including it within my header file and linking to both my source files however I get multiple defenitions, first defined here errors.
Setup for ncurse windows within my main file:
/* Window defintion constants*/
#define PROTOPORT 36795 /* default protocol port number, booknumber */
#define QLEN 6 /* size of request queue */
#define MAXSIZE 256
#define NUMWINS 7
#define RES_BUF_SIZE 80
WINDOW *w[NUMWINS];
WINDOW *sw[NUMWINS];
WINDOW wh[NUMWINS];
void update_win(int i) {
touchwin(w[i]);
wrefresh(sw[i]);
}
/* add string to a window */
void wAddstr(int z, char c[255]);
void GUIshutdown(char * response) {
wmove(sw[4], 0, 0);
wclrtoeol(sw[4]);
wprintw(sw[4], "All finished. Press Enter to terminate the program.");
update_win(4);
wgetstr(sw[4], response);
/* End screen updating */
endwin();
echo();
}
//////////
int main(int argc, char *argv[]) {
/***********************************************/
/* setup ncurses for multiple windows */
/***********************************************/
setlocale(LC_ALL, ""); // this has to do with the character set to use
initscr();
cbreak();
noecho();
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
/* Clear screen before starting */
clear();
w[0] = newwin(0,0,0,0);
if (LINES != 43 || COLS != 132) {
move(0, 0);
addstr("Piggy3 requires a screen size of 132 columns and 43 rows");
move(1, 0);
addstr("Set screen size to 132 by 43 and try again");
move(2, 0);
addstr("Press enter to terminate program");
mvprintw(3,0,"%dx%d\n", COLS, LINES);
refresh();
getstr(response); // Pause so we can see the screen
endwin();
exit(EXIT_FAILURE);
}
/* create the 7 windows and the seven subwindows*/
for (a = 0; a < NUMWINS; a++) {
w[a] = newwin(WPOS[a][0], WPOS[a][1], WPOS[a][2], WPOS[a][3]);
sw[a] = subwin(w[a], WPOS[a][0] - 2, WPOS[a][1] - 2, WPOS[a][2] + 1, WPOS[a][3] + 1);
scrollok(sw[a], TRUE); // allows window to be automatically scrolled
wborder(w[a], 0, 0, 0, 0, 0, 0, 0, 0);
touchwin(w[a]);
wrefresh(w[a]);
wrefresh(sw[a]);
}
/***********************************************/
/* Windows */
/***********************************************/
/*
* Notes:
* sw[0] = upper left window,
* sw[1] = upper right window,
* sw[2] = bottom left window,
* sw[3] = bottom right window
* sw[4] = bottom command window
* sw[5] = bottom inputs window
* sw[6] = bottom errors menu.
*/
wmove(sw[0], 0, 0);
wprintw(sw[0], "This is the window where the data flowing from left to right ");
wprintw(sw[0], "will be displayed. Notice now we don't need to worry about when we reach the last ");
wprintw(sw[0], " position in the subwindow, we will just wrap around down to the next line of the subwindow");
wprintw(sw[0], " and can never mess up the border that is in the parent window");
wprintw(sw[inLeft], " Data coming from the left, head piggy\n");
wmove(sw[1], 4, 0);
waddstr(sw[1], "Data leaving right side");
wmove(sw[2], 4, 0);
waddstr(sw[2], "Data leaving the left side");
wmove(sw[3], 4, 0);
waddstr(sw[3], "Data arriving from the right");
wmove(sw[4], 0, 0);
waddstr(sw[4], "Commands: ");
wmove(sw[5], 0, 0);
waddstr(sw[5], "Data Entry: ");
wmove(sw[6], 0, 0);
waddstr(sw[6], "Errors: ");
for (int a = 0; a < NUMWINS; a++){
update_win(a);
}
wmove(sw[4], 0, 0);
wprintw(sw[4], "Press Enter to see the output in the upper left window scroll");
wgetstr(sw[4], response); // Pause so we can see the screen
wmove(sw[4], 0, 0);
wclrtoeol(sw[4]); // clears current line without clobbering borders
update_win(4);
}
You need header guards in your .h files.
#ifndef HEADER_FILE_NAME_H
#define HEADER_FILE_NAME_H
// include,definitions..
#endif //HEADER_FILE_NAME_H

Overwriting a Window

I'm making a program with ncurses that splits the screen into two windows. The top screen can accept input, and by pressing '#' it will move all the text down the the bottom window and wipe the top window. In my code I'm trying to use copywin() to replace the bottom window, but it will not paste the wording in the second window. This is what I have...
#include <ncurses.h>
int main(int argc, char *argv[])
{
// Declare variables for windows and sizes
WINDOW *top_win, *bottom_win;
int maxx, maxy, halfy, flag = 0, ch;
// Start curses
initscr();
noecho();
refresh();
// get the max x's and y's
getmaxyx(stdscr, maxy, maxx);
halfy = maxy >> 1;
// Start color
start_color();
init_pair(1, COLOR_BLACK, COLOR_WHITE);
init_pair(2, COLOR_WHITE, COLOR_CYAN);
init_pair(3, COLOR_RED, COLOR_WHITE);
// Make windows
top_win = newwin(halfy, maxx, 0, 0);
wbkgd(top_win, COLOR_PAIR(1));
wrefresh(top_win);
bottom_win = newwin(halfy, maxx, halfy, 0);
wbkgd(bottom_win, COLOR_PAIR(2));
wrefresh(bottom_win);
// Allow functions keys
keypad(top_win, TRUE);
keypad(bottom_win, TRUE);
// while loop to get input
while((ch = getch()) != '`')
{
if(ch == '#')
{
if(flag == 1)
{
flag = 0;
}
else
{
flag = 1;
}
}
else if(ch == '#')
{
//waddstr(bottom_win, "testing");
copywin(top_win, bottom_win, 0, 0, halfy, 0, halfy, maxx, TRUE);
//overwrite(top_win, bottom_win);
//werase(top_win);
}
else if(flag != 1)
{
waddch(top_win, ch | COLOR_PAIR(1));
}
else if(flag == 1)
{
waddch(top_win, ch | COLOR_PAIR(3));
}
wrefresh(top_win);
wrefresh(bottom_win);
}
// end curses
delwin(top_win);
delwin(bottom_win);
endwin();
return 0;
}
I know I can print to the window using the '#' character because of my commented out, testing statement. I've also just tried using overwrite(), but that didn't work either. Am I simply getting the arguments mixed up, or is it something else? Any Ideas? Thank you in advance!
copywin checks the given rows/columns, and decides that your destination rectangle doesn't lie completely within the destination window. Here's a quick fix for your program:
--- foo.c.orig 2017-02-13 16:13:12.000000000 -0500
+++ foo.c 2017-02-13 16:30:18.037987489 -0500
## -51,7 +51,7 ##
else if(ch == '#')
{
//waddstr(bottom_win, "testing");
- copywin(top_win, bottom_win, 0, 0, halfy, 0, halfy, maxx, TRUE);
+ copywin(top_win, bottom_win, 0, 0, 0, 0, halfy - 1, maxx - 1, TRUE);
//overwrite(top_win, bottom_win);
//werase(top_win);
}
## -73,4 +73,3 ##
endwin();
return 0;
}
Rows and columns are numbered from zero through the last row/column (which is one less than the window size), so I subtracted one from the dmaxrow and dmaxcol parameters. The fifth parameter dminrow was past the bottom of the window.
ncurses checks the parameters. Regarding compatibility and portability, running the same program with Solaris curses (changing "ncurses.h" to "curses.h") dumps core.
The manual page could be improved, but it's clear enough regarding colors:
only text where the two windows overlap is copied
I don't have a good explanation for why it works, but as long as xoff and yoff are at least 1 in the code below, the data from the upper window is copied to the lower window OK (and cleared from the upper window). The colour isn't copied. If either offset is 0, the data is not copied. The string testing is added at the top-left of the lower window — it can be omitted and the copied material is still OK.
#include <ncurses.h>
int main(void)
{
// Declare variables for windows and sizes
WINDOW *top_win, *bottom_win;
int maxx, maxy, halfy, flag = 0, ch;
// Start curses
initscr();
noecho();
refresh();
// get the max x's and y's
getmaxyx(stdscr, maxy, maxx);
halfy = maxy >> 1;
// Start color
start_color();
init_pair(1, COLOR_BLACK, COLOR_WHITE);
init_pair(2, COLOR_WHITE, COLOR_CYAN);
init_pair(3, COLOR_RED, COLOR_WHITE);
// Make windows
top_win = newwin(halfy, maxx, 0, 0);
wbkgd(top_win, COLOR_PAIR(1));
wrefresh(top_win);
bottom_win = newwin(halfy, maxx, halfy, 0);
wbkgd(bottom_win, COLOR_PAIR(2));
wrefresh(bottom_win);
// Allow functions keys
// keypad(top_win, TRUE);
// keypad(bottom_win, TRUE);
// while loop to get input
int xoff = 1;
int yoff = 1;
while ((ch = getch()) != '`')
{
if (ch == '#')
{
if (flag == 1)
{
flag = 0;
}
else
{
flag = 1;
}
}
else if (ch == '#')
{
waddstr(bottom_win, "testing");
// copywin(top_win, bottom_win, 0, 0, halfy, 0, halfy, maxx, TRUE);
copywin(top_win, bottom_win, 0, 0, yoff, xoff, halfy-yoff, maxx-xoff, TRUE);
// overwrite(top_win, bottom_win);
werase(top_win);
}
else if (flag != 1)
{
waddch(top_win, ch | COLOR_PAIR(1));
}
else if (flag == 1)
{
waddch(top_win, ch | COLOR_PAIR(3));
}
wrefresh(top_win);
wrefresh(bottom_win);
}
// end curses
delwin(top_win);
delwin(bottom_win);
endwin();
return 0;
}
Testing on Mac running macOS Sierra 10.12.3 with GCC 6.3.0, using the local -lncurses library.

Gnome Terminal cannot print the red color in a program using curses

I am trying to get into the ncurses library. I am dissapointed that the Gnome Terminal can print red via ANSI escape characters but not the predefined red from ncurses.
#include <curses.h>
void init_colors() {
int a;
for(a = 1; a < COLORS; a++) {
init_pair(a, a, COLOR_BLACK);
}
}
void print_colors() {
int a;
for(a = 1; a < COLORS; a++) {
attron(COLOR_PAIR(a));
mvprintw(a, 0, "color");
attroff(COLOR_PAIR(a));
}
}
int main() {
initscr();
cbreak();
noecho();
curs_set(0);
if(has_colors())
start_color();
init_colors();
print_colors();
getch();
endwin();
return 0;
}
This should print the word "color" in any default ncurses color, but the second line (init_pair should initialize the second COLOR_PAIR as red) is not printed at all. It seems that Gnome Terminal simply skip this line. How can I fix this?
This is a copy of another stackoverflow answer
#include <curses.h>
int main(void) {
initscr();
start_color();
init_pair(1, COLOR_BLACK, COLOR_RED);
init_pair(2, COLOR_BLACK, COLOR_GREEN);
attron(COLOR_PAIR(1));
printw("This should be printed in black with a red background!\n");
attron(COLOR_PAIR(2));
printw("And this in a green background!\n");
refresh();
getch();
endwin();
}
Notes
you need to call start_color() after initscr() to use color.
you have to use the COLOR_PAIR macro
to pass a color pair allocated with init_pair to attron et al.
you can't use the color pair 0.
you only have to call refresh() once,
and only if you want your output to be seen at that point,
and you're not calling an input function like getch().

Resources