1

I am new to c coding and trying out this and that. Recently I stumbled over ncurses and am experimenting with it.

In Dan Gookin's "guide to programming with ncurses". I saw pads and their properties and functionality and now I want to archive the following:

I want to create a pad of a by far bigger size than the screen, respectively, an outcut of stdscr, so the screen shows parts of the pad. The advantage compared with other solutions is that I don't need to mess around with offsets. you can just call the function

prefresh(padname, y, x, min_y, min_x, max_y, max_y);

which refreshes the screen stdscr and shows a part of the before prepared pad content in a "cutout" from min_y,min_x to max_y,max_x. The offset to the upper left corner is y,x.

So later I want to move around the pad in both directions left-right and up-down. I filled a pad with some dummy data ("Eat my pants" and an incremented number) and moved it around with simple for-loops. It worked out smoothly, but I realized a flaw. At the edges of the pad the information is "cut" and I cannot find a solution to make the wrap. If the offset is negative, prefresh does just through ERR, and the screen stays empty, while if the offset is too big the left or the lower boundaries came into view. That is generally not a problem, but I want to archive a solution where I can get control over the content to make it become something like an edgeless object. So if moving the pad too the left the right side shall be moved into view while and vice versa. Same for up and down. So like a cylinder or a pseudo-ball in a game world.

Anybody an idea how to achieve that with a pad shown on the stdscr with ncurses in a C environment?

Here's my test file (the commented and the lower parts are for testing, respectively, only to check out how scrolling in subwindows works. You will see the lower boundary coming into view after pressing a few times any key.

#include <ncurses.h>

void draw_borders(WINDOW *screen); // some test on winndows only

int main(int argc, char *argv[]) {
   int parent_x, parent_y, new_x, new_y;
   int left_size = 10;  // bad name, means height of the lower windows
   initscr();
   noecho();
   curs_set(FALSE);

   // init color use and define two colorpairs
   start_color();
   init_pair(1,COLOR_WHITE,COLOR_BLUE);
   init_pair(2,COLOR_BLACK, COLOR_YELLOW);
   init_pair(3,COLOR_BLACK, COLOR_CYAN);

   // get our maximum window dimensions
   getmaxyx(stdscr, parent_y, parent_x);

   // set up initial windows
   // WINDOW *field = newwin(parent_y - left_size, parent_x, 0, 0);
   // but main screen will be stdscr showing an
   // outcut of a padn so init pad here bigger than a screen
   WINDOW *mainscreen;
   mainscreen = newpad(500,1000);
   if (mainscreen == NULL) {
       endwin();
       puts("Sorry, unable to allocate mainscreen");
       return 1;
   }
   addstr("Added the new pad. Filling.\n");

   // fill the pad
   for ( int i = 0 ; i < 500000 ; i++) {
       wprintw(mainscreen, " Eat my shorts %4d ", i);
   }
   addstr("Press key to update screen.\n");
   getch();

//    this is to checkout what happens if the right edge comes into view
//    for (int x = 1000-parent_x ; x < 1000-parent_x + 10; x++) {
//        prefresh(mainscreen, 0, x, 0 , 0, parent_y - left_size -1, parent_x-1);
//        // napms(100);
//        getch();
//    }

// lower edge coming into view
   for (int y = 0 ; y < 10 ; y++) {
       prefresh(mainscreen, 500 - parent_y + left_size + y,
                0, 0 , 0, parent_y - left_size -1, parent_x-1);
       // napms(100);
       getch();
   }

   // only to checkout how subwindows work
   WINDOW *left = newwin(left_size, parent_x/2, parent_y - left_size, 0);
   WINDOW *right = newwin(left_size, parent_x/2, parent_y - left_size, parent_x/2);
   WINDOW *subwindow;

   //assign color to windows
   //wbkgd(field,COLOR_PAIR(1));
   wbkgd(left,COLOR_PAIR(2));
   wbkgd(right,COLOR_PAIR(3));

   // draw our borders
   //draw_borders(field);
   draw_borders(left);
   draw_borders(right);

// simulate a loop
//    while(1) {
//        getmaxyx(stdscr, new_y, new_x);
//        if (new_y != parent_y || new_x != parent_x) {
//            parent_x = new_x;
//            parent_y = new_y;
//            wresize(field, new_y - left_size, new_x);
//            wresize(left, left_size, new_x/2);
//            wresize(right, left_size, new_x/2);
//
//            mvwin(left, new_y - left_size, 0);
//            mvwin(right, new_y - left_size, parent_x/2);
//
//
//
//            wclear(stdscr);
//            wclear(field);
//            wclear(left);
//            wclear(right);
//
//            draw_borders(field);
//            draw_borders(left);
//            draw_borders(right);
//
//        }

           // wresize(field,parent_y - left_size, parent_x);
           wresize(left, left_size, parent_x/2);
           wresize(right, left_size, parent_x/2);

           mvwin(left, parent_y - left_size, 0);
           mvwin(right, parent_y - left_size, parent_x/2);

           // wclear(stdscr);
           // wclear(field);
           wclear(left);
           wclear(right);

//            draw_borders(field);
//            draw_borders(left);
           draw_borders(right);


       // draw to our windows
       mvwprintw(left, 1, 1, "Left. ");
       mvwprintw(right, 1, 1, "Right");

       // refresh each window
       refresh();
//        wrefresh(field);
       wrefresh(left);
       wrefresh(right);

       subwindow = derwin(left, left_size-2, (parent_x/2)-2, 1, 1);
//      scroll newly setup subwindow or not
       scrollok(subwindow, TRUE);


       for (int i = 0 ; i < 20 ; i++) {
           waddstr(subwindow, "This is just some boring placeholder text. ");
           napms(100);
           wrefresh(subwindow);
       }

       for (int i = 0 ; i < 3 ; i++) {
           scroll(subwindow);
           napms(100);
           wrefresh(subwindow);
       }

       for (int i = 0 ; i < 1 ; i++) {
           wscrl(subwindow,-3);
           napms(100);
           wrefresh(subwindow);
       }

//    }
getch();
       // clean up
//        delwin(field);
       delwin(left);
       endwin();
return 0;
}

void draw_borders(WINDOW *screen) {

   int x, y, i; getmaxyx(screen, y, x);

   // 4 corners
   mvwprintw(screen, 0, 0, "+");
   mvwprintw(screen, y - 1, 0, "+");
   mvwprintw(screen, 0, x - 1, "+");
   mvwprintw(screen, y - 1, x - 1, "+");

   // sides
   for (i = 1; i < (y - 1); i++) {
       mvwprintw(screen, i, 0, "|");
       mvwprintw(screen, i, x - 1, "|");
   }

   // top and bottom
   for (i = 1; i < (x - 1); i++) {
       mvwprintw(screen, 0, i, "-");
       mvwprintw(screen, y - 1, i, "-");
   }
}

Jens
  • 69,818
  • 15
  • 125
  • 179
  • You could do that by inspecting the pad to find its actual non-blank limits, e.g., using [`winch`](https://invisible-island.net/ncurses/man/curs_inch.3x.html) for each row/column. – Thomas Dickey Dec 13 '20 at 14:35
  • I checked winch but I don‘t have a clue how that could help to wrap at the end of lines to the beginning. Can you explain in more detail? – jagottsicher Dec 13 '20 at 21:45
  • As I read it, you wanted to put a bound on the panning behavior (to avoid blank screens). Making a display scroll left/right through wrapped lines is complicated - see [this](https://github.com/ThomasDickey/vile-snapshots/blob/9330a2311bf4ae1ba306e3436427b9a1c24eb8c9/display.c#L1800) for example. – Thomas Dickey Dec 13 '20 at 23:25
  • See. Sorry, I didnt make clear enough what I want to achieve. English is a second language and I am missing the correct specific vocabulary. My pad has two dimensions widths and height. I can now place it perfectly behind a screen in a way to make every part visible. But if i place the pad to far left I want the spaces to be filled with content from the right (but negative values are not allowed at all). And when coming to the right side of the pad I would like the left part been shown. Same at the top and bottom. – jagottsicher Dec 14 '20 at 09:34

0 Answers0