Skip to content

Instantly share code, notes, and snippets.

@alan-mushi
Created July 11, 2014 12:38
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save alan-mushi/bdc831e0c33ad5db8025 to your computer and use it in GitHub Desktop.
Save alan-mushi/bdc831e0c33ad5db8025 to your computer and use it in GitHub Desktop.
This is a simple example of "scrolling" form with ncurses. It use "page" to allow forms with more fields than your window can print.
/*
* This is a simple example of "scrolling" form with ncurses.
* It use "page" to allow forms with more fields than your window can print.
*
* It prints a "label" (inactive field) and a regular field and let you
* "scroll" pages of the form.
*
* How to compile:
* gcc -o test scrolling_form.c -lform -lncurses
*/
#include <ncurses/form.h> // this includes <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
WINDOW *wbody, *inner;
FIELD **field;
FORM *form;
int nb_field; // how many fields you want (modify it in main())
int cur_y = 1, cur_x = 1; // current y and x for the inner window
char str_label[7], str_field[6];
char cur_ch_label = 'A', cur_ch_field = 'a';
int lines = 21, cur_page = 0;
/*
+----------------------------------+ <-- wbody
|+--------------------------------+ <-- inner
|| ^ ||
|| | ||
|| | ||
|| | ||
|| | lines ||
|| | ||
|| | ||
|| | ||
|| v ||
|+--------------------------------+|
+----------------------------------+
*/
// We free everything here
void quit() {
int i;
unpost_form(form);
for (i = 0; i < nb_field; i++) {
free(field_buffer(field[i], 0));
free_field(field[i]);
}
free_form(form);
delwin(wbody);
delwin(inner);
}
char* get_next_str_field() {
int i;
if (str_field[0] != '\0')
cur_ch_field++;
for (i = 0; i < 4; i++)
str_field[i] = cur_ch_field;
str_field[5] = '\0';
return str_field;
}
char* get_next_str_label() {
int i;
if (str_label[0] != '\0')
cur_ch_label++;
for (i = 0; i < 5; i++)
str_label[i] = cur_ch_label;
str_label[5] = ':';
str_label[6] = '\0';
return str_label;
}
/*
* Create nb_field fields, one as a label, one as an active field e.g.:
* [label]: [field]
*/
void create_nb_fields() {
int i;
field = calloc(nb_field, sizeof(FIELD *));
if (!field) // No memory for you !
assert(1);
for (i = 0; i < nb_field-1; i++, cur_y += 2) {
// label
field[i] = new_field(1, 20, cur_y, cur_x, 0, 0);
field_opts_on(field[i], O_VISIBLE);
field_opts_off(field[i], O_EDIT);
field_opts_off(field[i], O_ACTIVE);
set_field_buffer(field[i], 0, get_next_str_label());
i++;
/*
* This is a nasty tric:
* I check if we wrote at the tail of the inner window,
* if so, I move the field where it belongs (head of
* the inner window).
*/
if (cur_y % lines == 0) {
cur_y = 1;
set_new_page(field[i-1], TRUE);
move_field(field[i-1], cur_y, cur_x);
}
// field
field[i] = new_field(1, 20, cur_y, cur_x + 10, 0, 0);
set_field_back(field[i], A_UNDERLINE);
field_opts_on(field[i], O_VISIBLE);
field_opts_on(field[i], O_ACTIVE);
field_opts_off(field[i], O_EDIT);
set_field_buffer(field[i], 0, get_next_str_field());
}
field[nb_field-1] = NULL;
}
int main() {
int ch;
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
// This is required to init get_next_str_XXXX
str_label[0] = '\0';
str_field[0] = '\0';
wbody = newwin(lines + 2, 44, 1, 1);
box(wbody, 0, 0);
keypad(wbody, TRUE);
nb_field = 43; // this is too much fields for the window
create_nb_fields();
form = new_form(field);
// Check the doc here:
// http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/forms.html#FORMWINDOWS
set_form_win(form, wbody);
inner = derwin(wbody, lines, 42, 1 ,1);
set_form_sub(form, inner);
post_form(form);
mvprintw(LINES - 4, 0, "Use F1 to quit");
mvprintw(LINES - 3, 0, "Use PAGE_UP, PAGE_DOWN to switch between pages");
mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
refresh();
while ((ch = wgetch(wbody)) != KEY_F(1)) {
switch (ch) {
case KEY_DOWN:
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
/*
* This is where you want to look to see how
* to "scroll" to the next/previous page.
*/
case KEY_NPAGE:
form_driver(form, REQ_NEXT_PAGE);
set_form_page(form, ++cur_page);
break;
case KEY_PPAGE:
form_driver(form, REQ_PREV_PAGE);
set_form_page(form, --cur_page);
break;
}
}
quit();
endwin();
return 0;
}
@desana
Copy link

desana commented Apr 21, 2015

Thank you, this code has been really helpful. This type of scrolling is exactly what I need to do:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment