Does anyone know how to use ncurses?

I have been trying to read the "how to" but I am completely baffled.

I have made some decent progress with a server/chat program I have made, and I have been testing it with a friend over the internet. It works okay, but blocking IO makes it difficult, and had to resort with new messages being displayed after you send something. As you can imagine it's not ideal.


I have an interface I would like, very simple:


********************************************************************************
* This is the chat room                                     * Nicknames of     *
*                                                           * connected peers  *
* Messages that have been sent will come up within this     *                  *
* box                                                       *                  *
*                                                           *                  *
* Megatron_ : Hello                                         *                  *
* SomePeer  : Hey                                           *                  *
*                                                           *                  *
* The text should scroll up as it reaches the end of the    *                  *
* box                                                       *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
*                                                           *                  *
********************************************************************************
* Text to be entered and sent                                                  *
*                                                                              *
********************************************************************************



I would greatly appreciate some help.

My code is in C++ but the library requires me to use C style IO, such as printw() and scanw() ( They're equivalent of printf() scanf() ).

This will probably require for me to change both the server and client code to cooperate with ncurses.

Anyone have any ideas?
Last edited on
This is my current code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <ncurses.h>

void DrawBorder();

int main()
{
	initscr();
	cbreak();
	noecho();
	nodelay(stdscr,TRUE);
	keypad(stdscr,TRUE);

	start_color();
	init_pair(1,COLOR_BLACK,COLOR_BLUE);
	init_pair(2,COLOR_BLACK,COLOR_RED);
	init_pair(3,COLOR_RED,COLOR_WHITE);

	DrawBorder();

	WINDOW* ROOM;
	WINDOW* PEERS;
	WINDOW* INPUT;

	// newwin(rows,cols,y_org,x_org)
	ROOM = newwin(18,59,1,1);
	box(ROOM,'*','*');
	wbkgd(ROOM,COLOR_PAIR(1));
	mvwaddstr(ROOM, 1,1, "Chat box\n");

	PEERS = newwin(18,18,1,60);
	box(PEERS,'*','*');
	wbkgd(PEERS,COLOR_PAIR(2));
	mvwaddstr(PEERS, 1,1, "Peer list:\n");

	INPUT = newwin(4,77,19,1);
	box(INPUT,'*','*');
	wbkgd(INPUT,COLOR_PAIR(3));
	mvwprintw(INPUT,1,1, "Message: ");

	int c;
	c = getch();
	char* input;
	do
	{
		/*touchwin(ROOM);
		touchwin(PEERS);
		*/
		wrefresh(PEERS);
		wrefresh(ROOM);		
		wrefresh(INPUT);

		echo();
		//wscanw(INPUT,"%s",input); // Can't get window input to work ATM
		noecho();

		touchwin(INPUT);
		
		c = getch();
		
	}
	while(c != KEY_F(1));

	nodelay(stdscr,FALSE);
	getch();
	delwin(ROOM);
	delwin(PEERS);
	delwin(INPUT);
	endwin();

	return 0;
}

void DrawBorder()
{
	clear();
	box(stdscr,'*','*');
}
You could create a custom stream buffer class that wraps over the ncurses api.
If you are unfamiliar with the the C++ iostreams library, it would require a bit of learning.
Understanding the architecture of one of the most well-designed libraries would also be extremely rewarding.

Tutorial: http://www.mr-edd.co.uk/blog/beginners_guide_streambuf

The Boost iostreams library makes the task much easier:
http://www.boost.org/doc/libs/1_57_0/libs/iostreams/doc/tutorial/writing_devices.html

Recommended reading:
http://www.amazon.com/Standard-IOStreams-Locales-Programmers-Reference/dp/0321585585
Last edited on
Thanks for the links J, I'll try and do some reading.

My problem is I have a time limit, I've been volunteering for an IT company and I am really trying to show my worth.


I am going to try and write a light wrapper around the ncurses functions, like so:

A menu that highlights it's current selection;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Menu
{
private:
	WINDOW* frame;
	std::vector<std::string> fields;
	unsigned int width;
	unsigned int height;
	std::string title;
	int choice;
public:
	Menu(unsigned int h, unsigned int w, unsigned int sy, unsigned int sx, std::string t)
	: height(h), width(w), title(t), choice(0)
	{
		frame = newwin(h,w,sy,sx);
		box(frame,'*','*');
		Draw();
	}
	~Menu()
	{
		box(frame,' ',' ');
		wclear(frame);
		delwin(frame);
	}
	void AddField(std::string f) { fields.push_back(f); Draw(); }
	void Draw()
	{
		wclear(frame);
		box(frame,'*','*');
		wmove(frame, 0,2);
		waddstr(frame,title.c_str());
		unsigned int spacing = 2;
		for(unsigned int i = 0; i < fields.size(); i++)
		{
			if(spacing > height-1) continue;
			if(i == choice)
			{
				wattron(frame, A_REVERSE);
				mvwprintw(frame, spacing, 2, "%s", fields[i].c_str());
				wattroff(frame, A_REVERSE);
			}
			else mvwprintw(frame, spacing, 2, "%s", fields[i].c_str());
			spacing += 2;
		}
	}
	void Refresh() { wrefresh(frame); }
	unsigned int MaxFields() { return fields.size(); }
	void SetChoice(int c)
	{
		choice = c;
		Draw();
	}
	WINDOW* operator()() { return frame; }
};



Yesterday this worked fine, yet I have changed something today while putting to of these objects on the screen, now the menu doesn't show up till a key has been pressed, and the other doesn't show up at all. Even though they are the same objects with the same operations. Getting really annoyed terminal IO is this complicated. If I do figure this out I will try and write a C++ wrapper for this nonsense.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
int main()
{
	initscr();
	cbreak();
	noecho();
	start_color();
	clear();

	nodelay(stdscr,TRUE);
	keypad(stdscr,TRUE);

	Menu MyMenu(10,20,0,0,"Hello World");
	Menu AMenu(5,10,20,20,"Database");
	
	MyMenu.AddField("Start");
	MyMenu.AddField("Load");
	MyMenu.AddField("Save");
	MyMenu.AddField("(F1) Quit");

	int key = 0; int choice = 0;
	while(key != KEY_F(1))
	{
		MyMenu.Refresh(); // I call refresh before getch() The object is drawn in constructor
		AMenu.Refresh();  // In theory these should show before I need to press a key
		refresh();
		key = getch();
		switch(key)
		{
			case KEY_UP:
							mvprintw(20,20,"Pressed up");
							choice--;

							if(choice < 0) choice = MyMenu.MaxFields()-1;
							else if(choice >= MyMenu.MaxFields()) choice = 0;
							
							MyMenu.SetChoice(choice);
							refresh();

							break;
			case KEY_DOWN:
							mvprintw(20,20,"Pressed down");
							choice++;
							
							if(choice >= MyMenu.MaxFields()) choice = 0;
							else if(choice < 0) choice = MyMenu.MaxFields()-1;
							
							MyMenu.SetChoice(choice);
							refresh();

							break;

			case KEY_ENTER: // Enter key does not work for me for some reason
							mvprintw(20,20,"You selected option %d", &choice);
							refresh();
			default: break;
		}
	}
	getch();
	endwin();
	return 0;
}



If anyone has experience with ncurses I'd really appreciate a response.


EDIT:

Very peculiar, I have the refresh the windows after getch(). They both show up now.
Last edited on
Topic archived. No new replies allowed.