Reputation: 87
I've built a generic wrapper for the curses form object to use with a large simulation project that I'm working on.
Basically, I instantiate an generic_form object, add some fields and their
descriptions to it, and then give it focus and get user input with a fill_form()
routine.
Because each generic_form
object can be used more than once, that is, that fill_form() may be called more than once per instantiation, I need to clear the field buffers at the beginning of the fill_form() routine. Currently, I'm using this at the beginning of the routine:
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
However, it throws a floating point exception at the set_field_buffer
line on the second call to the fill_form() routine. Moreover, the set_field_buffer
line doesn't seem to actually be doing anything, at least not clearing the buffer, because without calling free_field at the end of the routine, and instead in the object destructor, the fields buffers remain the same on each subsequent call.
Here's the entirety of the (ugly, in-development) fill_form() routine for brevity:
void generic_form::fill_form()
{
//fields.push_back(NULL);
if (fields.size() == 1)
{
fields.push_back(NULL);
form = new_form(static_cast<FIELD**>(fields.data()));
fields.erase((fields.end() - 1));
assert(fields.size() == 1);
}
else
{
form = new_form(static_cast<FIELD**>(fields.data()));
}
WINDOW* form_win = derwin(screen, fields.size() + 1, largest_desc + 6, ypos,
xpos);
set_form_win(form, form_win);
set_form_sub(form, form_win);
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
post_form(form);
for (int x = 0; x < descriptions.size(); x++)
{
mvwprintw(form_win, x, 0, descriptions.at(x).c_str());
}
wmove(form_win, 0, largest_desc + 1);
touchwin(screen);
wrefresh(form_win);
/* Loop through to get user requests */
int ch;
while((ch = getch()) != '\n')//KEY_F(1))
{ switch(ch)
{
case KEY_DOWN:
/* Go to next field */
form_driver(form, REQ_NEXT_FIELD);
/* Go to the end of the present buffer */
/* Leaves nicely at the last character */
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
/* Go to previous field */
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
/* If this is a normal character, it gets */
/* Printed */
form_driver(form, ch);
break;
}
}
form_driver(form, REQ_VALIDATION);
for (int x = 0; x < fields.size() && first_run; x++)
{
//store the int_inputs from the forms
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_INTEGER))
{
int_inputs.push_back(std::atoi(field_buffer((fields.at(x)), 0)));
}
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_ALPHA))
{
str_inputs.push_back(field_buffer((fields.at(x)), 0));
}
}
first_run = false;
/* Un post form and free the memory */
unpost_form(form);
free_form(form);
for (int x = 0; x < fields.size(); x++)
{
free_field(fields.at(x));
}
delwin(form_win);
}
Long story short/TLDR: How to I clear or reset a field buffer in ncurses, without deleting and re-adding it?
Upvotes: 2
Views: 1851
Reputation: 11
You can clean field buffer using form_driver ()
Excerpt man form_driver
REQ_CLR_EOL
Clear to end of line from cursor.
REQ_CLR_EOF
Clear to end of field from cursor.
REQ_CLR_FIELD
Clear the entire field.
To elaborate this a bit more :-), I'm using code similar to following for clearing fields:
#include <stdio.h>
#include <stdlib.h>
#include <form.h>
enum f_name_l
{
f_name, f_surname, f_last
};
int main (void)
{
int ch = 0, i = 0;
FIELD *field[3], *save_field;
FORM *my_form;
initscr ();
start_color ();
noecho ();
raw ();
keypad (stdscr, TRUE);
refresh ();
field[f_name] = new_field (1, 10, 0, 25, 0, 0);
field[f_surname] = new_field (1, 10, 2, 25, 0, 0);
field[f_last] = NULL;
set_field_back (field[f_name], A_UNDERLINE);
set_field_back (field[f_surname], A_UNDERLINE);
my_form = new_form (field);
post_form (my_form);
// Form labels
mvprintw (0, 1, "Name: ");
mvprintw (2, 1, "Surname: ");
mvprintw (4, 1, "F5 to clear active field. F6 to clear form.");
pos_form_cursor (my_form);
refresh ();
// ^q to exit
while ((ch = getch ()) != 17)
{
switch (ch)
{
case KEY_UP:
form_driver (my_form, REQ_PREV_FIELD);
break;
case KEY_DOWN:
form_driver (my_form, REQ_NEXT_FIELD);
break;
case KEY_F(5):
form_driver (my_form, REQ_CLR_FIELD);
break;
case KEY_F(6):
save_field = current_field (my_form);
for (i = 0; i < f_last; i++)
{
set_current_field (my_form, field[i]);
form_driver (my_form, REQ_CLR_FIELD);
}
set_current_field (my_form, save_field);
break;
default:
form_driver (my_form, ch);
break;
}
form_driver (my_form, REQ_VALIDATION);
}
endwin ();
return EXIT_SUCCESS;
}
But seeing post from Thomas Dickey I start to feel like my life is a lie :-).
Upvotes: 1