How to use the move function under curses.h - c

It doesn't print at coordinates y=10, x=20.
#include <stdio.h>
#include <curses.h>
int main()
{
initscr();
refresh();
WINDOW *win;
wmove(win, 10, 20);
refresh();
printf("hi\n");
return 0;
}
When I execute it like this...
./a.out > op_file
This is what is op_file
[?1049h[1;24r(B[m[4l[?7h[H[2J-1
hi
Can someone explain...??

You must use initscr() function to initialize the screen and endwin() at the end to close the window...
If you move(), you must use refresh() or the cursor won't move physically.

To move the cursor to a new position on a window, use the function int wmove(WINDOW *win, int y, int x)
wmove(win, y, x);
where (x, y) are the coordinates of the new position in the window. If the window has nlines lines and ncolumns columns, then
0 <= y < nlines
0 <= x < ncolumns
Refresh. The actual cursor motion is not shown on the screen untill you do a wrefresh(win).
move(y, x) is equivalent to the wmove(stdscr, y, x).`
The move() and wmove() functions move the cursor associated with the current or specified window to (y, x) relative to the window's origin. This function does not move the terminal's cursor until the next refresh operation.
To move the logical cursor in the user-defined window my_window to the coordinates y = 5, x = 10, use :
#include <stdio.h>
#include <curses.h>
int main(){
refresh();//First refresh
WINDOW *my_window;
int a = wmove(my_window, 5, 10);
refresh();////Second refresh
printf("%d\n",a);
printf("hi\n");
return 0;
}

The output
[?1049h[1;24r(B[m[4l[?7h[H[2J-1
hi
shows the printable characters written. If you look at the complete text, e.g., in a text-editor, there'll be ASCII escape characters before the [ and ( characters since that's part of the escape sequence.
Your example doesn't show cursor movement (aside from the home position which you'd see as ^[[H near the end) because there's no reason for the curses library to actually move the cursor. If you had asked it to read a character, e.g., using getch, it would have to stop and decide where the cursor should be — and your wmove would do that — except that win is not initialized. The simplest thing to do is use stdscr (which is initialized by initscr).
The program quits curses calls without doing an endwin (which leaves the terminal in raw mode). The data does get written to the screen with the refresh call. The data written with printf happens to come out in the right order, but that's only coincidental since it does not use the same output buffering as ncurses.
Both of the other answers contain similar errors.

This works.
#include <stdio.h>
#include <curses.h>
int main()
{
initscr();
refresh();
WINDOW *win;
win = stdscr;
wmove(win, 10, 10);
refresh();
printf("hi\n");
return 0;
}
Thanks to #interjay.

Related

C/Ncurses how to wrap text in a textfield

I would like to wrap a short text in a Text Box in Ncurses, but somehow my text keeps going off screen. How can I wrap the text so it (automatically) goes to a new line when reaching the end of the screen on the right?
I tried playing with '\n' and setting limits but witout results. Any tips what I am doing wrong? See below code for what is going on.
Thanks from a beginner programmer.
#include <ncurses.h>
#include <string.h>
void text(WINDOW* textborder, int wymax, int wxmax, char text5[], int size)
{
for (int i=0;i<size;i++)
{
mvwaddch(textborder,2,i+i, text5[i]);
if (i==wxmax)
{
mvwaddch(textborder,2,i+i, '\n');
}
}
}
int main()
{
char text5[]={"Somebody is watching over us... controlling us. It's true, I tell you. It's true! We are merely sprites that dance at the beck and call of our button-pressing overlord. This is a video game. Don't you see? We are characters in a video game."};
int size;
size=strlen(text5);
int wymax; int wxmax;
initscr();
WINDOW* textborder=newwin(LINES/4, COLS, LINES-LINES/4, 0);
box(textborder,-1,-1);
getmaxyx(textborder, wymax,wxmax);
wxmax=wxmax-4;
text(textborder, wymax, wxmax, text5, size);
wgetch(textborder);
endwin();
return 0;
}
In theory the text should wrap itself. I think your issue may be coming from using mvwaddch, ch generally causes the text not to wrap. This may help Ncurses no-wrap mode when adding strings to window. Sorry I can't be more helpful :)
Applications that draw a box with a border in curses do this using two windows, one within the other. The outer box gets the border; the inner box gets the text. Text printed within the inner box does not affect the outer box.
For example, some of the demo/example programs in ncurses do this, e.g., test_addstr creates look (for the box) and show (for the text):
limit = LINES - 5;
if (level > 0) {
look = newwin(limit, COLS - (2 * (level - 1)), 0, level - 1);
work = newwin(limit - 2, COLS - (2 * level), 1, level);
show = newwin(4, COLS, limit + 1, 0);
box(look, 0, 0);
wnoutrefresh(look);
limit -= 2;
} else {
work = stdscr;
show = derwin(stdscr, 4, COLS, limit + 1, 0);
}
keypad(work, TRUE);

How do I can call initgraph more than one time?

Please look at the following code:
#include <stdio.h>
#include <graphics.h>
#include <conio.h>
using namespace std;
void drawrect()
{
int gdriver = IBM8514, gmode;
initgraph(&gdriver, &gmode, "");
rectangle(500, 500, 700, 700);
getch();
cleardevice();
closegraph();
}
int main()
{
int f=1;
while(f)
{
char c;
printf("Press \"e\" to end, and any other character to draw a rectangle");
scanf("%c",&c);
c=='e' ? f=0:f=1;
drawrect();
fflush(stdin);
}
}
at the first time when I run this program, It works correctly and draws a rectangle, but after the first time, the rectangle function doesn't work and the GUI screen is completely blank, While I've cleared and closed previous graphic
So why it doesn't work at second time?
You code has undefined behaviour. The call to initgraph
int gdriver = IBM8514, gmode;
initgraph(&gdriver, &gmode, "");
should pass a pointer to the graphics mode you want to use. This page describes the function and its arguments, and about the mode it says:
*graphmode is an integer that specifies the initial graphics mode (unless *graphdriver equals DETECT; in which case, *graphmode is set
by initgraph to the highest resolution available for the detected
driver). You can give *graphmode a value using a constant of the
graphics_modes enumeration type, which is defined in graphics.h and
listed below.
graphdriver and graphmode must be set to valid values from the
following tables, or you will get unpredictable results. The exception
is graphdriver = DETECT.
But you have not set the mode, and as the second paragraph quoted says, the result is unpredictable. This can be: working how you intended, not working, working strangely, or frying the processor.
So set the graphics mode you want to use with say
int gdriver = IBM8514, gmode = 0;
or whatever mode you need to use. Alternatively you can tell the system to detect for itself, in which case you can use
int gdriver = DETECT, gmode;
Init and close should be called just once and not be called in the drawrect but usually in the main instead ... also having getch in rendering routine makes no sense too...
I will not touch other issues here of your code as I am not coding console stuff for years and BGI even longer but I would start with reordering the code to this:
#include <stdio.h>
#include <graphics.h>
#include <conio.h>
using namespace std;
void drawrect()
{
rectangle(500, 500, 700, 700);
}
int main()
{
int f=1;
int gdriver = IBM8514, gmode;
initgraph(&gdriver, &gmode, "");
while(f)
{
char c;
printf("Press \"e\" to end, and any other character to draw a rectangle");
scanf("%c",&c);
c=='e' ? f=0:f=1;
drawrect();
getch();
fflush(stdin);
}
cleardevice();
closegraph();
}
Also in future address the library by its real name BGI because graphics.h has no meaning as almost all gfx api/libs got a file with that name ...

DDA Line Drawing Algorithm has errors

Why am I getting an error saying 'setPixel not defined' with this code?
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include<GL/glut.h>
inline int round(const float a)
{
return int (a+0.5);
}
void init(void)
{
glClearColor(0.0f,0.0f,1.0f,1.0f);
gluOrtho2D(0.0,200.0,0.0,200.0);
glMatrixMode(GL_PROJECTION);
}
void LineSegment(int xa, int ya,int xb,int yb)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
printf("Enter the initial value");
scanf("%d%d",&xa,&ya);
printf("Enter the final value");
scanf("%d%d",&xb,&yb);
int dx=xb-xa;
int dy=yb-ya;
int steps,k;
float xIncrement,yIncrement,x=xa,y=ya;
if(fabs(dx)>fabs(dy))
steps=fabs(dx);
else
steps=fabs(dy);
xIncrement=dx/(float)steps;
yIncrement=dy/(float)steps;
setPixel(round(x),round(y));
for(k=0;k<steps;k++);
{
x += xIncrement;
y += yIncrement;
setPixel(round(x),round(y));
}
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA);
glutCreateWindow("DDA Line Algorithm");
glutDisplayFunc(LineSegment);
init();
glutMainLoop();
return 0;
}
Because there is no setPixel method in OpenGL or GLUT and as far as I can see from your code, you do not define one either. OpenGL deals with rendering primitives like points, lines, triangels etc, but not directly with setting single pixels on the screen. Since it is unclear what you want to achieve some suggestions:
If you want to draw a line in OpenGL, use the appropriate methods like glBegin(GL_LINES), etc. (although they are deprecated and should not be used anymore.) or glDrawArrays(GL_LINES, ....
If the goal is to implement a dda software rasterizer, then you might have to write the pixels to a texture and then display this texture.
Because you haven't defined setPixel anywhere. It's not an OpenGL call. You need to write it yourself, and it should set pixels on a buffer (if you're using double buffering) which you then later use as an argument to glDrawPixels(), or a call to the display buffer using glVertex2i(x,y). You can see an example of both approaches here and here.
Also, your LineSegment function is broken. In OpenGL you call glutDisplayFunc to specify a function which is called as fast as possible to render the display. However, in this function you call scanf() to prompt the user for data - this is broken. You should prompt them once at the start, and then pass that data into the function (which will then run as often as possible once glutMainLoop is called).

How do I scroll a message across the terminal?

I'm trying to write a program to that acts as a marquee that uses the curses.h library to create a side-scrolling display.
What should happen is that my message "Hello" should appear to scroll from the right side of the terminal to the left, character by character.
"hello" should appear to scroll across the terminal like so:
| H| // fist frame of animation
| He| //2nd
| Hel| //3rd
...
| Hello | // some time in the middle of animation
|Hello | // finished.
Instead of appearing to scroll across the terminal my program simply outputs the "Hello" message on the left side of the terminal as if it is finished.
I thought that printing the appropriate number of spaces then the appropriate number of characters of the string each frame would work.
What am I doing wrong?
Below is my code so far:
#include <curses.h>
#include <string.h>
main()
{
char message[] = "Hello";
int max_y, max_x; // max dimensions of terminal window
int text_length;
int i,row=0,col=0,spaces=0;
// Get text length
text_length = strlen(message);
// Get terminal dimensions
getmaxyx(stdscr, max_y, max_x);
// num of spaces needed to print
spaces = max_x -1;
initscr(); // initialize curses
clear(); // clear screen to begin
while(1)
{
clear(); // clear last drawn iteration
move(5,col);
// print spaces as necessary
for(i=0;i<spaces;i++)
{
addch(' ');
}
refresh();
// print appropriate number of characters of the message
for(i=0;i<text_length || i<max_x; i++)
{
addch(message[i]);
}
refresh();
usleep(50000); // wait some time
spaces = spaces-1; //adjust spaces need for next iteration
}
}
The first problem is that you call getmaxyx() before initscr(). In this situation, stdscr has not been initialized, so the values returned by getmaxyx() are meaningless. (I get -1 for each value, aka ERR.)
That fixed, the program basically works, but prints junk after the "Hello" string. You can solve that by changing the for loop test, text_length || i<max_x, to text_length && i<max_x, although the result is still probably not quite what you want. But I'll leave it to you to figure that one out.
Finally, as a stylistic matter, I'd suggest using curses' own napms() function instead of usleep() (i.e., napms(50) instead of usleep(50000)). But if you do stick with usleep(), you should add #include <unistd.h> at the top.

ncurses write to window not displayed

I've got one function do_refresh which should draw some character in a window like this:
void do_refresh(WINDOW *w_game, int *xPos, int *yPos, char vector[], snake *snake){
mvwaddch(w_game, (*yPos), (*xPos), snake->headsym);// mv to new pos and place char
wrefresh(w_game);
}
The window w_game has also a panel pendant which lies on top of all other panels.
Before that function gets called, I let the user do non blocking input with getch() and timeout(0):
fflush(stdin);
key = getch();
if(key != ERR){ ...
only the first time I call do_refresh, the char gets drawn to the window, later nothing changes though xPos & yPos as well as all other parameters to mvwaddch are valid and change over the time.
Doing a redrawwin on the window causes a segfault, using wgetch(w_game) instead of getch() returns no input.
I would be very grateful if someone could at least link to a decent documentation what has to be considered when using wgetch instead and what it does different.
UPDATE
I found the solution to the problem, The function which sets up the panel stuff modifies the address of the windows!, you have to return the (new) destination of the pointer to main and reset it there like this:
...setup_panels(...){
return w_game; // my window
}
int main(...){
WINDOW *w_game;
[...]
w_game = setup_panels(...);
}

Resources