0

I am experimenting with the code below in an attempt to learn how to use and control a scrolling pad. when the Z key is pressed the pad scrolls up which is good. The problem is that it "smears" as it does so. As it scrolls up the bottom line "9-9-9-9-9-" copies itself to every part of the pad that it touches as it moves. How do I stop it from doing that?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <ncurses.h>

int main() {

    int key=0, a=0, b=0, c=0, d=0, e=0, f=0;
    WINDOW *mypad;

    initscr();          /* Start curses mode        */
    cbreak();           /* Line buffering disabled, Pass on everything to me */
    timeout(0);         /* wait for user input */   
    noecho();
    keypad(stdscr, TRUE);       /* I need those nifty Function keys     */
    start_color();

    mypad = newpad(10, 10);

    waddstr(mypad, "0-0-0-0-0-");
    waddstr(mypad, "1-1-1-1-1-");
    waddstr(mypad, "2-2-2-2-2-");
    waddstr(mypad, "3-3-3-3-3-");
    waddstr(mypad, "4-4-4-4-4-");
    waddstr(mypad, "5-5-5-5-5-");
    waddstr(mypad, "6-6-6-6-6-");
    waddstr(mypad, "7-7-7-7-7-");
    waddstr(mypad, "8-8-8-8-8-");
    waddstr(mypad, "9-9-9-9-9-");


    prefresh(mypad, 0, 0, 0, 3, 9, 12);
    scrollok(mypad, TRUE);

    a=0;
    b=0;
    c=0;
    d=3;
    e=9;
    f=12;

    key=-1;
    while(key!='q')
    {
        key = wgetch(mypad);
        if(key=='a') { a--; }
        if(key=='z') { a++; }
        if(key=='s') { b--; }
        if(key=='x') { b++; }
        if(key=='d') { c--; }
        if(key=='c') { c++; }
        if(key=='f') { d--; }
        if(key=='v') { d++; }
        if(key=='g') { e--; }
        if(key=='b') { e++; }
        if(key=='h') { f--; }
        if(key=='n') { f++; }

        prefresh(mypad, a, b, c, d, e, f);
    }

    delwin(mypad);
    endwin();

    return 0;
}
Hakachukai
  • 90
  • 6

2 Answers2

0

This doesn't answer why the pad was smearing, but it does answer the original intent of the problem, which was how to get some text to be able to move around and scroll off screen without loosing anything.

ok,so after much more reading, testing and googling... apparently the answer has a two parts:

A. Pads don't scroll, only windows scroll.

B. Windows do scroll, but not the way that you think. When a window scrolls, any text that falls off the edge of the window is lost forever ( not what I want ).

It looks like the answer is that you have to buffer the chars yourself because Ncurses doesn't.

So... I came up with this which does work

A,S,D,F keys make the window scroll. Q quits.

Change window_width and window_height vars in main to make the window any size you want.

Ofcourse you can also print whatever text you want.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <ncurses.h>

chtype **initialize_screen_buffer(chtype **input_buffer, int window_width, int window_height)
{
    int size=0, i=0, j=0;

    //Allocate mem for the base pointer
    size=sizeof(chtype*)*window_width;
    input_buffer=calloc(size,1);
    if( input_buffer==NULL ) { fprintf(stderr, "\ninitialize_screen_buffer:> Failed to allocate %d bytes of memory for input_buffer\n", size); exit(1); }

    //Allocate mem for all of the columb pointers
    for(i=0; i<window_width; i++)
    {
        size=sizeof(chtype*)*window_height;
        input_buffer[i]=calloc(size,1);
        if( input_buffer[i]==NULL ) { fprintf(stderr, "\ninitialize_screen_buffer:> Failed to allocate %d bytes of memory for input_buffer[%d]\n", size, i); exit(1); }
    }

    return input_buffer;
}

void free_screen_buffer(chtype **input_buffer, int window_width, int window_height)
{
    int size=0, i=0, j=0;

    //Allocate mem for all of the columb pointers
    for(i=0; i < window_width; i++)
    {
        free(input_buffer[i]);
    }

    //Allocate mem for the base pointer
    free(input_buffer);
}


void copy_window_to_buffer(WINDOW *mywin, chtype **input_buffer, int window_width, int window_height)
{
    int x=0, y=0;

    //start from the beginning
    wmove(mywin, 0, 0 );

    //Copy all chars and from the given window into the buffer
    for(x=0; x < window_width; x++)
    {
        for(y=0; y < window_height; y++)
        {
            input_buffer[x][y]=(chtype)mvwinch(mywin, y, x);
        }
    }
}

void copy_buffer_to_window(WINDOW *mywin, chtype **input_buffer, int window_width, int window_height, int x_offset, int y_offset)
{
    int x=0, y=0;

    //start from the beginning

    //Copy all chars and from the given window into the buffer
    for(x=0; x < window_width; x++)
    {
        for(y=0; y < window_height; y++)
        {
            mvwaddch(mywin, y + y_offset, x + x_offset, input_buffer[x][y]);
        }
    }
}


int main() {

    WINDOW *mywin;
    int key=0, window_width=15, window_height=15, size=0, i=0, j=0, x_offset=0, y_offset=0;
    chtype **screen_buffer;


    screen_buffer=initialize_screen_buffer(screen_buffer, window_width, window_height);

    initscr();          /* Start curses mode        */
    cbreak();           /* Line buffering disabled, Pass on everything to me */
    timeout(0);         /* wait for user input */   
    noecho();
    keypad(stdscr, TRUE);       /* I need those nifty Function keys     */
    start_color();

    mywin = newwin(window_width, window_height, 0, 0);

    waddstr(mywin, "0-0-0-0-0-\n");
    waddstr(mywin, "1-1-1-1-1-\n");
    waddstr(mywin, "2-2-2-2-2-\n");
    waddstr(mywin, "3-3-3-3-3-\n");
    waddstr(mywin, "4-4-4-4-4-\n");
    waddstr(mywin, "5-5-5-5-5-\n");
    waddstr(mywin, "6-6-6-6-6-\n");
    waddstr(mywin, "7-7-7-7-7-\n");
    waddstr(mywin, "8-8-8-8-8-\n");
    waddstr(mywin, "9-9-9-9-9-\n");

    wrefresh(mywin);

    copy_window_to_buffer(mywin, screen_buffer, window_width, window_height);

    key=-1;
    while(key!='q')
    {
        key = wgetch(mywin);
        if(key=='w') { y_offset--; }
        if(key=='s') { y_offset++; }
        if(key=='a') {  x_offset--;  }
        if(key=='d') {  x_offset++; }

        wclear(mywin);
        copy_buffer_to_window(mywin, screen_buffer, window_width, window_height, x_offset, y_offset);
        wrefresh(mywin);
    }

    delwin(mywin);
    endwin();
    free_screen_buffer(screen_buffer, window_width, window_height);

    return 0;
}

This does solve the problem of making a window scroll in all directions with no text loss, but it has a problem. It is static. It's a snapshot of the window that you have in front of your face at that moment. It doesn't allow for adding more lines of text without overwriting old lines.

The next step would be to add some re-allocation so that as text is added, the screen buffer will grow so that it can hold that extra text

Hakachukai
  • 90
  • 6
0

When your example gets z, the call to prefresh changes minrow, which tells ncurses to start displaying the corresponding row from the pad. But the pad is only 10 lines long, and ncurses stops displaying from that source when it gets to the end of the pad. That happens to fall short of the previous location, which is left untouched.

You could provide a pad which is longer than the viewport, or use one of the clearing operations such as clrtoeol() or clrtobot() to tidy up.

This is not specific to ncurses; the behavior of pads dates back to SVr3 in the mid-1980s (see Portability notes in the manual).

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105