freebsd-skq/lib/libforms/forms.c
Paul Richards 8c490a36b0 Implemented height field for text fields so they can now be more than
one line long.

Fixed a bug in the input field with cursor positioning at the end of
the field.

Make the print_status function available to apps so they can print
status messages.

Updated the example for the new fib parser.
1995-02-01 04:06:37 +00:00

503 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*-
* Copyright (c) 1995
* Paul Richards. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* verbatim and that no modifications are made prior to this
* point in the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Paul Richards.
* 4. The name Paul Richards may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <forms.h>
#include <ncurses.h>
#include "internal.h"
unsigned int f_keymap[] = {
KEY_UP, /* F_UP */
KEY_DOWN, /* F_DOWN */
9, /* F_RIGHT */
8, /* F_LEFT */
10, /* F_NEXT */
KEY_LEFT, /* F_CLEFT */
KEY_RIGHT, /* F_CRIGHT */
KEY_HOME, /* F_CHOME */
KEY_END, /* F_CEND */
263, /* F_CBS */
330, /* F_CDEL */
10 /* F_ACCEPT */
};
int done=0;
int
initfrm(struct form *form)
{
struct field *field = &form->field[0];
int i;
if (has_colors()) {
start_color();
if (form->color_table)
for (i=0; form->color_table[i].f != -1; i++) {
init_pair(i+1, form->color_table[i].f, form->color_table[i].b);
}
}
cbreak();
noecho();
if (!form->height)
form->height = LINES;
if (!form->width)
form->width = COLS;
form->window = newwin(form->height, form->width, form->y, form->x);
if (!form->window) {
print_status("Couldn't open window, closing form");
return (ERR);
}
form->no_fields = 0;
keypad(form->window, TRUE);
while (field->type != F_END) {
if (field->type == F_INPUT) {
field->field.input->input = malloc(field->field.input->limit);
if (!field->field.input->input){
print_status("Couldn't allocate memory, closing form");
endfrm(form);
return (ERR);
}
/*
* If it's a label then clear the input string
* otherwise copy the default string to the input string.
*/
if (field->field.input->lbl_flag)
field->field.input->input[0] = '\0';
else if (field->field.input->label) {
strncpy(field->field.input->input,
field->field.input->label,
field->field.input->limit);
field->field.input->input[field->field.input->limit] = 0;
}
} else if ((field->type != F_TEXT) && (field->type != F_MENU) &&
(field->type != F_ACTION)) {
print_status("Unknown field type, closing form");
endfrm(form);
return (ERR);
}
form->no_fields++;
field = &form->field[form->no_fields];
}
form->current_field = form->start_field;
show_form(form);
return (OK);
}
void
endfrm(struct form *form)
{
struct field *field = &form->field[0];
int i;
delwin(form->window);
for (i=0; i < form->no_fields; i++) {
if (field->type == F_INPUT)
free(field->field.input->input);
field = &form->field[i];
}
}
int
update_form(struct form *form)
{
show_form(form);
if (form->current_field == -1)
return (F_CANCEL);
wattrset(form->window, form->field[form->current_field].selattr);
switch (form->field[form->current_field].type) {
case F_MENU:
field_menu(form);
break;
case F_INPUT:
field_input(form);
break;
case F_ACTION:
field_action(form);
break;
case F_TEXT:
default:
print_status("Error, current field is invalid");
return (F_CANCEL);
}
wattrset(form->window, 0);
return (done);
}
static void
show_form(struct form *form)
{
int i;
int y, x;
wattrset(form->window, form->attr);
for (y = 0; y < form->height; y++)
for (x = 0; x < form->width; x++)
mvwaddch(form->window, y, x, ' ');
for (i=0; i < form->no_fields; i++) {
wattrset(form->window, form->field[i].attr);
wmove(form->window, form->field[i].y, form->field[i].x);
switch (form->field[i].type) {
case F_TEXT:
disp_text(form, i);
break;
case F_MENU:
disp_menu(form, i);
break;
case F_INPUT:
disp_input(form,i);
break;
case F_ACTION:
disp_action(form,i);
break;
case F_END:
default:
break;
}
}
wattrset(form->window, 0);
wrefresh(form->window);
}
static void
disp_text(struct form *form, int index)
{
struct field *field = &form->field[index];
if (print_string(form->window, field->y, field->x, field->height,
field->width, field->field.text->text) == ERR)
print_status("Illegal scroll in print_string");
}
static void
disp_input(struct form *form, int index)
{
struct field *field = &form->field[index];
if (field->field.input->lbl_flag) {
if (print_string(form->window, field->y, field->x, field->height,
field->width, field->field.input->label) == ERR)
print_status("Illegal scroll in print_string");
} else
if (print_string(form->window, field->y, field->x, field->height,
field->width, field->field.input->input) == ERR)
print_status("Illegal scroll in print_string");
}
static void
disp_menu(struct form *form, int index)
{
struct field *field = &form->field[index];
if (print_string(form->window, field->y, field->x, field->height,
field->width,
field->field.menu->options[field->field.menu->selected]) == ERR)
print_status("Illegal scroll in print_string");
}
static void
disp_action(struct form *form, int index)
{
struct field *field = &form->field[index];
if (print_string(form->window, field->y, field->x, field->height,
field->width,
field->field.action->text) == ERR)
print_status("Illegal scroll in print_string");
}
static void
field_action(struct form *form)
{
struct field *field = &form->field[form->current_field];
int ch;
for (;;) {
disp_action(form, form->current_field);
wmove(form->window, field->y, field->x);
ch = wgetch(form->window);
if (ch == F_ACCEPT) {
(*field->field.action->fn)();
return;
} else if (!next_field(form, ch))
beep();
else
return;
}
}
static void
field_menu(struct form *form)
{
struct field *field = &form->field[form->current_field];
int ch;
for (;;) {
disp_menu(form, form->current_field);
wmove(form->window, field->y, field->x);
switch (ch = wgetch(form->window)) {
case ' ':
print_status("");
field->field.menu->selected++;
if (field->field.menu->selected >= field->field.menu->no_options)
field->field.menu->selected = 0;
break;
default:
if (!next_field(form, ch)) {
print_status("Hit the space bar to toggle through options");
beep();
} else
return;
}
}
}
static int
next_field(struct form *form, int ch)
{
struct field *field = &form->field[form->current_field];
if (ch == F_UP) {
if (field->up == -1) {
print_status("Can't go up from here");
return (0);
} else
form->current_field = field->up;
} else if (ch == F_DOWN) {
if (field->down == -1) {
print_status("Can't go down from here");
return (0);
} else
form->current_field = field->down;
} else if (ch == F_NEXT) {
if (field->next == -1) {
print_status("Can't go to next from here");
return (0);
} else
form->current_field = field->next;
} else if (ch == F_RIGHT) {
if (field->right == -1) {
print_status("Can't go right from here");
return (0);
} else
form->current_field = field->right;
} else if (ch == F_LEFT) {
if (field->left == -1) {
print_status("Can't go left from here");
return (0);
} else
form->current_field = field->left;
} else
return (0);
print_status("");
return (1);
}
static int
print_string(WINDOW *window, int y, int x,
int height, int fwidth, char *string)
{
int len;
int width;
if (!string)
len = -1;
len = strlen(string);
if (wmove(window, y, x) == ERR)
return (ERR);
while (height--) {
width = fwidth;
while (width--) {
if (len-- > 0) {
if (waddch(window, *string++) == ERR)
return (ERR);
} else
if (waddch(window, ' ') == ERR)
return (ERR);
}
if (wmove(window, ++y, x) == ERR)
return (ERR);
}
return (OK);
}
void
print_status(char *msg)
{
if (wmove(stdscr, LINES-1, 0) == ERR) {
endwin();
exit(1);
}
wclrtoeol(stdscr);
wstandout(stdscr);
if (wprintw(stdscr, "%s",
msg) == ERR) {
endwin();
exit(1);
}
wstandend(stdscr);
wrefresh(stdscr);
}
void
field_input(struct form *form)
{
struct field *field = &form->field[form->current_field];
int len;
int ch;
int disp_off=0, abspos=0, cursor = 0;
#define DISPOFF ((len < field->width) ? 0 : len - field->width)
#define CURSPOS ((len < field->width) ? len : field->width)
len = strlen(field->field.input->input);
disp_input(form, form->current_field);
cursor = CURSPOS;
abspos = cursor;
for(;;) {
wmove(form->window, field->y, field->x+cursor);
wrefresh(form->window);
ch = wgetch(form->window);
if (next_field(form, ch)) {
print_string(form->window, field->y, field->x,
field->height, field->width,
field->field.input->input+DISPOFF);
return;
}
if (field->field.input->lbl_flag) {
field->field.input->lbl_flag = 0;
}
if ((ch == F_CHOME) || (ch == '')) {
disp_off = 0;
cursor = 0;
abspos = 0;
} else if ((ch == F_CEND) || (ch == '')) {
disp_off = DISPOFF;
abspos = len;
cursor = CURSPOS;
} else if (ch == F_CDEL) {
if (!(len-abspos))
beep();
else {
bcopy(field->field.input->input+abspos+1,
field->field.input->input+abspos,
len - abspos);
--len;
}
} else if ((ch == F_CLEFT) || (ch == F_CBS) || (ch == '')) {
if (!abspos)
beep();
else {
if (ch == F_CBS) {
bcopy(field->field.input->input+abspos,
field->field.input->input+abspos-1,
len-abspos+1);
--len;
}
--abspos;
--cursor;
if ((disp_off) && (cursor < 0)) {
--disp_off;
++cursor;
}
}
} else if ((ch == F_CRIGHT) || (ch == '')) {
if (abspos == len)
beep();
else {
++abspos;
if (++cursor == field->width) {
++disp_off;
--cursor;
}
}
} else if ((isprint(ch)) && (len < field->field.input->limit)){
bcopy(field->field.input->input+abspos,
field->field.input->input+abspos+1, len-abspos+1);
field->field.input->input[abspos++] = ch;
len++;
if (++cursor > field->width) {
++disp_off;
--cursor;
}
} else {
beep();
}
print_string(form->window, field->y, field->x, field->height,
field->width, field->field.input->input+disp_off);
}
/* Not Reached */
}
void
exit_form(void)
{
done = F_DONE;
}
void
cancel_form(void)
{
done = F_CANCEL;
}