summaryrefslogtreecommitdiffstats
path: root/lib/libforms/fields.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libforms/fields.c')
-rw-r--r--lib/libforms/fields.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/lib/libforms/fields.c b/lib/libforms/fields.c
new file mode 100644
index 0000000..3656834
--- /dev/null
+++ b/lib/libforms/fields.c
@@ -0,0 +1,520 @@
+/*-
+ * 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 <ctype.h>
+#include <err.h>
+#include <ncurses.h>
+#include <forms.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "internal.h"
+
+int done=0;
+
+int
+init_field(struct Field *field)
+{
+ struct Tuple *tuple;
+ struct Field *def;
+ int i;
+ int len, lim;
+
+ tuple = form_get_tuple(field->defname, FT_FIELD_DEF);
+ if (!tuple) {
+ warnx("Field definition not found -- skipping field");
+ return (-1);
+ }
+
+ def = (struct Field *)tuple->addr;
+ field->height = def->height;
+ field->width = def->width;
+ field->attr = def->attr;
+ field->selattr = def->selattr;
+ field->type = def->type;
+ switch (field->type) {
+ case FF_INPUT:
+ field->field.input = malloc(sizeof (struct InputField));
+ if (!field->field.input) {
+ warnx("Couldn't allocate memory for input field");
+ return (-1);
+ }
+ field->field.input->limit = def->field.input->limit;
+
+ /* Force height to one regardless, at least for now :-) */
+ field->height = 1;
+ if (!field->width && !field->field.input->limit) {
+ field->width = strlen(def->field.input->label);
+ field->field.input->limit = field->width;
+ } else if (!field->width)
+ field->width = field->field.input->limit;
+ else if (!field->field.input->limit)
+ field->field.input->limit = field->width;
+ if (field->field.input->limit < field->width)
+ field->width = field->field.input->limit;
+
+ field->field.input->input = malloc(field->field.input->limit + 1);
+ if (!field->field.input->input) {
+ warnx("Couldn't allocate memory for input field text");
+ return (-1);
+ }
+ field->field.input->label = malloc(strlen(def->field.input->label)+1);
+ if (!field->field.input->label) {
+ warnx("Couldn't allocate memory for input field label");
+ return (-1);
+ }
+ strncpy(field->field.input->label,
+ def->field.input->label,
+ strlen(def->field.input->label) + 1);
+ field->field.input->lbl_flag = def->field.input->lbl_flag;
+
+ /*
+ * If it's a label then clear the input string
+ * otherwise copy the default there.
+ */
+ 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;
+ }
+ break;
+ case FF_TEXT:
+ field->field.text = malloc(sizeof (struct TextField));
+ if (!field->field.text) {
+ warnx("Couldn't allocate memory for text field");
+ return (FS_ERROR);
+ }
+ if (!field->width)
+ field->width = strlen(def->field.text->text);
+ field->field.text->text = malloc(field->width + 1);
+ if (!field->field.text->text) {
+ warnx("Couldn't allocate memory for text field text");
+ return (FS_ERROR);
+ } else
+ strncpy(field->field.text->text,
+ def->field.text->text,
+ field->width + 1);
+ if (!field->height)
+ calc_field_height(field, field->field.text->text);
+ break;
+ case FF_MENU:
+ field->field.menu = malloc(sizeof (struct MenuField));
+ if (!field->field.menu) {
+ warnx("Couldn't allocate memory for menu field");
+ return (FS_ERROR);
+ }
+ field->field.menu->no_options = 0;
+ field->height = 1;
+ lim = 0;
+ for (i=0; i < def->field.menu->no_options; i++) {
+ field->field.menu->no_options =
+ add_menu_option(field->field.menu,
+ def->field.menu->options[i]);
+ if (!field->field.menu->no_options) {
+ warnx("Couldn't add menu option");
+ return (FS_ERROR);
+ }
+ len = strlen(def->field.menu->options[i]);
+ if (len > lim)
+ lim = len;
+ }
+ if (!field->width)
+ field->width = lim;
+ break;
+ case FF_ACTION:
+ field->field.action = malloc(sizeof (struct ActionField));
+ if (!field->field.action) {
+ warnx("Couldn't allocate memory for action field");
+ return (FS_ERROR);
+ }
+ if (!field->width)
+ field->width = strlen(def->field.action->text);
+ field->field.action->text = malloc(field->width + 1);
+ if (!field->field.action->text) {
+ warnx("Couldn't allocate memory for text field text");
+ return (FS_ERROR);
+ } else
+ strncpy(field->field.action->text,
+ def->field.action->text,
+ field->width + 1);
+ if (!field->height)
+ calc_field_height(field, field->field.action->text);
+ field->field.action->fn = def->field.action->fn;
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+void
+display_field(WINDOW *window, struct Field *field)
+{
+ wattrset(window, field->attr);
+ wmove(window, field->y, field->x);
+ switch (field->type) {
+ case FF_TEXT:
+ display_text(window, field);
+ break;
+ case FF_MENU:
+ display_menu(window, field);
+ break;
+ case FF_INPUT:
+ display_input(window, field);
+ break;
+ case FF_ACTION:
+ display_action(window, field);
+ break;
+ case FF_UNKNOWN:
+ default:
+ break;
+ }
+ wattrset(window, 0);
+ wrefresh(window);
+}
+
+void
+display_text(WINDOW *window, struct Field *field)
+{
+
+ if (print_string(window, field->y, field->x, field->height,
+ field->width, field->field.text->text) == ERR)
+ print_status("Illegal scroll in print_string");
+}
+
+void
+display_input(WINDOW *window, struct Field *field)
+{
+ if (field->field.input->lbl_flag) {
+ if (print_string(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(window, field->y, field->x, field->height,
+ field->width, field->field.input->input) == ERR)
+ print_status("Illegal scroll in print_string");
+}
+
+void
+display_menu(WINDOW *window, struct Field *field)
+{
+ if (print_string(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");
+}
+
+void
+display_action(WINDOW *window, struct Field *field)
+{
+ if (print_string(window, field->y, field->x, field->height,
+ field->width,
+ field->field.action->text) == ERR)
+ print_status("Illegal scroll in print_string");
+}
+
+int
+do_action(struct Form *form)
+{
+ struct Field *field = form->current_field;
+ struct Tuple *tuple;
+ int ch;
+ void (* fn)();
+
+ display_action(form->window, field);
+ wmove(form->window, field->y, field->x);
+
+ for (;;) {
+
+ ch = wgetch(form->window);
+
+ if (ch == FK_ACCEPT) {
+ tuple = form_get_tuple(field->field.action->fn, FT_FUNC);
+ if (!tuple) {
+ print_status("No function bound to action");
+ beep();
+ continue;
+ } else {
+ fn = tuple->addr;
+ (*fn)(form);
+ return (FS_OK);
+ }
+ } else
+ ch = do_key_bind(form, ch);
+
+ if (ch == FS_OK)
+ return (FS_OK);
+ else if (ch == FS_ERROR)
+ continue;
+ }
+}
+
+int
+do_menu(struct Form *form)
+{
+ struct Field *field = form->current_field;
+ int ch;
+
+
+ for (;;) {
+
+ display_menu(form->window, field);
+ wmove(form->window, field->y, field->x);
+
+ ch = wgetch(form->window);
+
+ switch (ch) {
+ case ' ':
+ print_status("");
+ field->field.menu->selected++;
+ if (field->field.menu->selected >= field->field.menu->no_options)
+ field->field.menu->selected = 0;
+ break;
+ default:
+ ch = do_key_bind(form, ch);
+ break;
+ }
+
+ if (ch == FS_OK)
+ return (FS_OK);
+ else if (ch == FS_ERROR) {
+ beep();
+ continue;
+ } else {
+ print_status("Hit the space bar to toggle through options");
+ beep();
+ continue;
+ }
+ }
+}
+
+int
+do_field(struct Form *form)
+{
+ struct Field *field = form->current_field;
+ int status;
+
+ switch (field->type) {
+ case FF_TEXT:
+ status = FS_OK;
+ display_text(form->window, field);
+ break;
+ case FF_INPUT:
+ status = do_input(form);
+ break;
+ case FF_MENU:
+ status = do_menu(form);
+ break;
+ case FF_ACTION:
+ status = do_action(form);
+ break;
+ default:
+ status = FF_UNKNOWN;
+ beep();
+ print_status("Unknown field type");
+ form->current_field = form->prev_field;
+ break;
+ }
+
+ return (status);
+}
+
+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);
+}
+
+
+int
+do_input(struct Form *form)
+{
+ struct Field *field = form->current_field;
+ int len;
+ int disp_off=0, abspos=0, cursor = 0;
+ unsigned int ch;
+
+#define DISPOFF ((len < field->width) ? 0 : len - field->width)
+#define CURSPOS ((len < field->width) ? len : field->width)
+
+ len = strlen(field->field.input->input);
+ display_input(form->window, field);
+
+ cursor = CURSPOS;
+ abspos = cursor;
+
+ for (;;) {
+
+ wmove(form->window, field->y, field->x+cursor);
+ wrefresh(form->window);
+
+ ch = wgetch(form->window);
+ ch = do_key_bind(form, ch);
+
+ /*
+ * If there was a valid motion command then we've
+ * moved to a new field so just return. If the motion
+ * command was invalid then just go around and get another
+ * keystroke. Otherwise, it was not a motion command.
+ */
+
+ if (ch == FS_OK)
+ return (FS_OK);
+ else if (ch == FS_ERROR)
+ continue;
+
+ print_status("");
+
+ if (field->field.input->lbl_flag) {
+ field->field.input->lbl_flag = 0;
+ }
+ if ((ch == FK_CHOME) || (ch == '')) {
+ disp_off = 0;
+ cursor = 0;
+ abspos = 0;
+ } else if ((ch == FK_CEND) || (ch == '')) {
+ disp_off = DISPOFF;
+ abspos = len;
+ cursor = CURSPOS;
+ } else if (ch == FK_CDEL) {
+ if (!(len-abspos))
+ beep();
+ else {
+ bcopy(field->field.input->input+abspos+1,
+ field->field.input->input+abspos,
+ len - abspos);
+ --len;
+ }
+ } else if ((ch == FK_CLEFT) || (ch == FK_CBS) || (ch == '')) {
+ if (!abspos)
+ beep();
+ else {
+ if (ch == FK_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 == FK_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);
+ }
+}
+
+void
+exit_form(struct Form *form)
+{
+ form->status = FS_EXIT;
+}
+
+void
+cancel_form(struct Form *form)
+{
+ form->status = FS_CANCEL;
+}
OpenPOWER on IntegriCloud