/* * Turn on the passed field options. */ int field_opts_on(FIELD *field, Form_Options options) { int i; FIELD *fp = (field == NULL) ? &_formi_default_field : field; /* not allowed to set opts if the field is the current one */ if ((field != NULL) && (field->parent != NULL) && (field->parent->cur_field == field->index)) return E_CURRENT; if ((options & O_STATIC) == O_STATIC) { for (i = 0; i < fp->nbuf; i++) { if (fp->buffers[i].length > fp->cols) fp->buffers[i].string[fp->cols] = '\0'; } } fp->opts |= options; /* if appropriate, redraw the field */ if ((field != NULL) && (field->parent != NULL) && (field->parent->posted == 1)) { _formi_redraw_field(field->parent, field->index); pos_form_cursor(field->parent); wrefresh(field->parent->scrwin); } return E_OK; }
/* draw_field_active_mark Draws marks before and after the active field. If prev is non-NULL we first remove the marks from the previous field. */ void draw_field_active_mark(const FIELD *cur, const FIELD *prev, WINDOW *formwin, FORM *form, const chtype ch) { int pos_x, pos_y, x, y, off_row, wrk_buff; /* safety */ if (!cur || !formwin || !form) return; /* if supplied we remove the previous marking */ if (prev) { if (field_info(prev, &y, &x, &pos_y, &pos_x, &off_row, &wrk_buff) < 0) return; mvwprintw(formwin, pos_y + 1, pos_x, " "); mvwprintw(formwin, pos_y + 1, pos_x + x + 3, " "); } /* draw our marking */ if (field_info(cur, &y, &x, &pos_y, &pos_x, &off_row, &wrk_buff) < 0) return; wattron(formwin, ch); mvwprintw(formwin, pos_y + 1, pos_x, ">"); mvwprintw(formwin, pos_y + 1, pos_x + x + 3, "<"); wattroff(formwin, ch); wrefresh(formwin); /* restore cursor position */ pos_form_cursor(form); return; }
inline void select_form() { pos_form_cursor(url_form); form_driver(url_form, ' '); form_driver(url_form, REQ_LEFT_CHAR); form_driver(url_form, REQ_DEL_CHAR); wrefresh(input_window); }
/* * Init all the field variables, perform wrapping and other tasks * after the field buffer is set. */ static int field_buffer_init(FIELD *field, int buffer, unsigned int len) { int status; char *newp; if (buffer == 0) { field->start_char = 0; field->start_line = 0; field->row_xpos = 0; field->cursor_xpos = 0; field->cursor_ypos = 0; field->row_count = 1; /* must be at least one row XXX need to shift old rows (if any) to free list??? */ field->alines->length = len; if ((newp = realloc(field->alines->string, (size_t) len + 1)) == NULL) return E_SYSTEM_ERROR; field->alines->string = newp; field->alines->allocated = len + 1; strlcpy(field->alines->string, field->buffers[buffer].string, (size_t) len + 1); field->alines->expanded = _formi_tab_expanded_length(field->alines->string, 0, field->alines->length); field->start_line = field->alines; field->cur_line = field->alines; /* we have to hope the wrap works - if it does not then the buffer is pretty much borked */ status = _formi_wrap_field(field, field->cur_line); if (status != E_OK) return status; /* * calculate the tabs for a single row field, the * multiline case is handled when the wrap is done. */ if (field->row_count == 1) _formi_calculate_tabs(field->alines); /* redraw the field to reflect the new contents. If the field * is attached.... */ if ((field->parent != NULL) && (field->parent->posted == 1)) { _formi_redraw_field(field->parent, field->index); /* make sure cursor goes back to current field */ pos_form_cursor(field->parent); } } return E_OK; }
/* * Post the form to the screen. */ int post_form(FORM *form) { int rows, cols, status; if (form == NULL) return E_BAD_ARGUMENT; if (form->posted == 1) return E_POSTED; if ((form->fields == NULL) || (form->fields[0] == NULL)) return E_NOT_CONNECTED; if (form->in_init == 1) return E_BAD_STATE; if (scale_form(form, &rows, &cols) != E_OK) return E_SYSTEM_ERROR; if ((form->scrwin != NULL) && ((rows > getmaxy(form->scrwin)) || (cols > getmaxx(form->scrwin)))) { return E_NO_ROOM; } form->in_init = 1; if (form->form_init != NULL) form->form_init(form); if (form->field_init != NULL) form->field_init(form); form->in_init = 0; _formi_pos_first_field(form); if ((status = _formi_draw_page(form)) != E_OK) return status; form->posted = 1; pos_form_cursor(form); return E_OK; }
/* * Turn off the passed field options. */ int field_opts_off(FIELD *field, Form_Options options) { FIELD *fp = (field == NULL) ? &_formi_default_field : field; /* not allowed to set opts if the field is the current one */ if ((field != NULL) && (field->parent != NULL) && (field->parent->cur_field == field->index)) return E_CURRENT; fp->opts &= ~options; /* if appropriate, redraw the field */ if ((field != NULL) && (field->parent != NULL) && (field->parent->posted == 1)) { _formi_redraw_field(field->parent, field->index); pos_form_cursor(field->parent); wrefresh(field->parent->scrwin); } return E_OK; }
/* * Create and initialize a new popup. popup_btn_action *must* be filled before * this call. * @param rows The number of rows for win_body * @param cols The number of lines for win_body * @param posy Position of the top left corner on the y axis * @param posx Position of the top left corner on the x axis * @param requests An array of strings to put in the form. This can be null: * only the title and the buttons will be present. * @param title A string to print in the popup. */ void popup_new(int rows, int cols, int posy, int posx, char **requests, char *title) { int i, cury = 0, curx = 1, tmp, nb_buttons, nb_fields; WINDOW *inner; win_body = newwin(rows, cols, posy, posx); assert(win_body != NULL && popup_btn_action != NULL); box(win_body, 0, 0); for (nb_buttons = 0; popup_btn_action[nb_buttons]; nb_buttons++); popup_items = malloc(sizeof(ITEM *) * (nb_buttons+1)); assert(popup_items != NULL); assert(popup_btn_action != NULL); for (i = 0; popup_btn_action[i]; i++) { popup_items[i] = new_item(popup_btn_action[i]->key, ""); assert(popup_items[i] != NULL); } popup_items[i] = NULL; popup_menu = new_menu(popup_items); win_menu = derwin(win_body, 3, cols-2, rows-4, 1); assert(popup_menu != NULL && win_menu != NULL); box(win_menu, 0, 0); set_menu_win(popup_menu, win_menu); set_menu_format(popup_menu, 1, nb_buttons); tmp = popup_menu->fcols * (popup_menu->namelen + popup_menu->spc_rows); tmp--; inner = derwin(win_menu, 1, tmp, 1, (cols-3-tmp)/2); assert(inner != NULL); set_menu_sub(popup_menu, inner); set_menu_mark(popup_menu, ""); assert(post_menu(popup_menu) == E_OK); mvwprintw(win_body, 1, 2, "%s", title); for (nb_fields = 0; requests && requests[nb_fields]; nb_fields++); if (nb_fields == 0) { popup_fields = NULL; popup_form = NULL; is_on_button = true; return; } popup_fields = malloc(sizeof(FIELD *) * (nb_fields+1)); assert(popup_fields != NULL); for (i = 0; i < nb_fields && requests[i]; i++) { if (i % 2 == 1) { popup_fields[i] = new_field(1, 41, cury, curx, 0, 0); assert(popup_fields[i] != NULL); set_field_buffer(popup_fields[i], 0, strdup(requests[i])); cury = cury+1; curx = 1; field_opts_on(popup_fields[i], O_ACTIVE); field_opts_on(popup_fields[i], O_EDIT); field_opts_off(popup_fields[i], O_STATIC); set_field_back(popup_fields[i], A_UNDERLINE); } else { popup_fields[i] = new_field(1, 45, cury, curx, 0, 0); assert(popup_fields[i] != NULL); set_field_buffer(popup_fields[i], 0, strdup(requests[i])); curx = strlen(requests[i]) + 2; field_opts_off(popup_fields[i], O_ACTIVE); field_opts_off(popup_fields[i], O_EDIT); } } popup_fields[i] = NULL; popup_form = new_form(popup_fields); assert(popup_form != NULL); win_form = derwin(win_body, rows-6, cols-2, 1, 1); assert(popup_form != NULL && win_form != NULL); assert(set_form_win(popup_form, win_form) == E_OK); int diff_rows = popup_form->cols - win_form->_maxx-2; /* * There isn't enough rows for the form so we resize win_body and * win_form to fit the form. * This resize isn't needed for the lines (as there is always fery few * of them). */ if (diff_rows > 0) { wresize(win_body, win_body->_maxy, win_body->_maxx + diff_rows); wresize(win_form, win_form->_maxy, win_form->_maxx - 2 + diff_rows); } inner = derwin(win_form, win_form->_maxy-2, win_form->_maxx, 2, 0); assert(inner != NULL); set_form_sub(popup_form, inner); assert(post_form(popup_form) == E_OK); is_on_button = false; set_menu_fore(popup_menu, A_NORMAL); // "hide" the button pos_form_cursor(popup_form); }
/* * This is called by main.c ncurses_action everytime a popup exists. * It's used to handle characters input in forms and button pressing. */ void popup_driver(int ch) { switch (ch) { case KEY_DOWN: if (is_on_button || !popup_form) break; if (popup_form->current == popup_fields[popup_form->maxfield-1]) switch_to_buttons(); else form_driver(popup_form, REQ_NEXT_FIELD); break; case KEY_UP: if (is_on_button) { if (!popup_form) break; is_on_button = false; set_menu_fore(popup_menu, A_NORMAL); // "hide" the button } else form_driver(popup_form, REQ_PREV_FIELD); break; case KEY_LEFT: if (is_on_button) menu_driver(popup_menu, REQ_LEFT_ITEM); else form_driver(popup_form, REQ_PREV_CHAR); break; case KEY_RIGHT: if (is_on_button) menu_driver(popup_menu, REQ_RIGHT_ITEM); else form_driver(popup_form, REQ_NEXT_CHAR); break; case 10: if (is_on_button) driver_buttons(current_item(popup_menu)); else switch_to_buttons(); break; // Delete the char before cursor case KEY_BACKSPACE: case 127: if (!is_on_button) form_driver(popup_form, REQ_DEL_PREV); break; // Delete the char under the cursor case KEY_DC: if (!is_on_button) form_driver(popup_form, REQ_DEL_CHAR); break; default: if (!is_on_button) form_driver(popup_form, ch); break; } if (popup_menu) { if (is_on_button) pos_menu_cursor(popup_menu); else pos_form_cursor(popup_form); } wrefresh(win_body); }
int form_driver(FORM *form, int c) { FIELD *fieldp; int update_page, update_field, old_field, old_page, status; int start_field; unsigned int pos; if (form == NULL) return E_BAD_ARGUMENT; if ((form->fields == NULL) || (*(form->fields) == NULL)) return E_INVALID_FIELD; if (form->posted != 1) return E_NOT_POSTED; if (form->in_init == 1) return E_BAD_STATE; old_field = start_field = form->cur_field; fieldp = form->fields[form->cur_field]; update_page = update_field = 0; status = E_OK; if (c < REQ_MIN_REQUEST) { if (isprint(c) || isblank(c)) { do { pos = fieldp->start_char + fieldp->row_xpos; /* check if we are allowed to edit this field */ if ((fieldp->opts & O_EDIT) != O_EDIT) return E_REQUEST_DENIED; if ((status = (_formi_add_char(fieldp, pos, c))) == E_REQUEST_DENIED) { /* * Need to check here if we * want to autoskip. we * call the form driver * recursively to pos us on * the next field and then * we loop back to ensure * the next field selected * can have data added to it */ if ((fieldp->opts & O_AUTOSKIP) != O_AUTOSKIP) return E_REQUEST_DENIED; status = form_driver(form, REQ_NEXT_FIELD); if (status != E_OK) return status; /* * check if we have looped * around all the fields. * This can easily happen if * all the fields are full. */ if (start_field == form->cur_field) return E_REQUEST_DENIED; old_field = form->cur_field; fieldp = form->fields[form->cur_field]; status = _formi_add_char(fieldp, fieldp->start_char + fieldp->cursor_xpos, c); } else if (status == E_INVALID_FIELD) /* char failed validation, just * return the status. */ return status; else if (status == E_NO_ROOM) /* we will get this if the line * wrapping fails. Deny the * request. */ return E_REQUEST_DENIED; } while (status != E_OK); update_field = (status == E_OK); } else return E_REQUEST_DENIED; } else { if (c > REQ_MAX_COMMAND) return E_UNKNOWN_COMMAND; if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) { /* first check the field we are in is ok */ if (_formi_validate_field(form) != E_OK) return E_INVALID_FIELD; if (form->field_term != NULL) form->field_term(form); /* * if we have a page movement then the form term * needs to be called too */ if ((c <= REQ_LAST_PAGE) && (form->form_term != NULL)) form->form_term(form); } switch (c) { case REQ_NEXT_PAGE: if (form->page < form->max_page) { old_page = form->page; form->page++; update_page = 1; if (_formi_pos_first_field(form) != E_OK) { form->page = old_page; status = E_REQUEST_DENIED; } } else status = E_REQUEST_DENIED; break; case REQ_PREV_PAGE: if (form->page > 0) { old_page = form->page; form->page--; update_page = 1; if (_formi_pos_first_field(form) != E_OK) { form->page = old_page; status = E_REQUEST_DENIED; } } else status = E_REQUEST_DENIED; break; case REQ_FIRST_PAGE: old_page = form->page; form->page = 0; update_page = 1; if (_formi_pos_first_field(form) != E_OK) { form->page = old_page; status = E_REQUEST_DENIED; } break; case REQ_LAST_PAGE: old_page = form->page; form->page = form->max_page - 1; update_page = 1; if (_formi_pos_first_field(form) != E_OK) { form->page = old_page; status = E_REQUEST_DENIED; } break; case REQ_NEXT_FIELD: status = _formi_pos_new_field(form, _FORMI_FORWARD, FALSE); update_field = 1; break; case REQ_PREV_FIELD: status = _formi_pos_new_field(form, _FORMI_BACKWARD, FALSE); update_field = 1; break; case REQ_FIRST_FIELD: form->cur_field = 0; update_field = 1; break; case REQ_LAST_FIELD: form->cur_field = form->field_count - 1; update_field = 1; break; case REQ_SNEXT_FIELD: status = _formi_pos_new_field(form, _FORMI_FORWARD, TRUE); update_field = 1; break; case REQ_SPREV_FIELD: status = _formi_pos_new_field(form, _FORMI_BACKWARD, TRUE); update_field = 1; break; case REQ_SFIRST_FIELD: fieldp = TAILQ_FIRST(&form->sorted_fields); form->cur_field = fieldp->index; update_field = 1; break; case REQ_SLAST_FIELD: fieldp = TAILQ_LAST(&form->sorted_fields, _formi_sort_head); form->cur_field = fieldp->index; update_field = 1; break; /* * The up, down, left and right field traversals * are rolled up into a single function, allow a * fall through to that function. */ case REQ_LEFT_FIELD: case REQ_RIGHT_FIELD: case REQ_UP_FIELD: case REQ_DOWN_FIELD: status = traverse_form_links(form, c); update_field = 1; break; /* the following commands modify the buffer, check if this is allowed first before falling through. */ case REQ_DEL_PREV: /* * need to check for the overloading of this * request. If overload flag set and we are * at the start of field this request turns * into a previous field request. Otherwise * fallthrough to the field handler. */ if ((form->opts & O_BS_OVERLOAD) == O_BS_OVERLOAD) { if ((fieldp->start_char == 0) && (fieldp->start_line == 0) && (fieldp->row_xpos == 0)) { update_field = _formi_manipulate_field(form, REQ_PREV_FIELD); break; } } /* FALLTHROUGH */ case REQ_NEW_LINE: /* * need to check for the overloading of this * request. If overload flag set and we are * at the start of field this request turns * into a next field request. Otherwise * fallthrough to the field handler. */ if ((form->opts & O_NL_OVERLOAD) == O_NL_OVERLOAD) { if ((fieldp->start_char == 0) && (fieldp->start_line == 0) && (fieldp->row_xpos == 0)) { update_field = _formi_manipulate_field(form, REQ_NEXT_FIELD); break; } } /* FALLTHROUGH */ case REQ_INS_CHAR: case REQ_INS_LINE: case REQ_DEL_CHAR: case REQ_DEL_LINE: case REQ_DEL_WORD: case REQ_CLR_EOL: case REQ_CLR_EOF: case REQ_CLR_FIELD: case REQ_OVL_MODE: case REQ_INS_MODE: /* check if we are allowed to edit the field and fall * through if we are. */ if ((form->fields[form->cur_field]->opts & O_EDIT) != O_EDIT) return E_REQUEST_DENIED; /* the following manipulate the field contents, bundle them into one function.... */ /* FALLTHROUGH */ case REQ_NEXT_CHAR: case REQ_PREV_CHAR: case REQ_NEXT_LINE: case REQ_PREV_LINE: case REQ_NEXT_WORD: case REQ_PREV_WORD: case REQ_BEG_FIELD: case REQ_END_FIELD: case REQ_BEG_LINE: case REQ_END_LINE: case REQ_LEFT_CHAR: case REQ_RIGHT_CHAR: case REQ_UP_CHAR: case REQ_DOWN_CHAR: case REQ_SCR_FLINE: case REQ_SCR_BLINE: case REQ_SCR_FPAGE: case REQ_SCR_BPAGE: case REQ_SCR_FHPAGE: case REQ_SCR_BHPAGE: case REQ_SCR_FCHAR: case REQ_SCR_BCHAR: case REQ_SCR_HFLINE: case REQ_SCR_HBLINE: case REQ_SCR_HFHALF: case REQ_SCR_HBHALF: update_field = _formi_manipulate_field(form, c); break; case REQ_VALIDATION: return _formi_validate_field(form); /* NOTREACHED */ break; case REQ_PREV_CHOICE: case REQ_NEXT_CHOICE: update_field = _formi_field_choice(form, c); /* reinit the cursor pos just in case */ if (update_field == 1) { _formi_init_field_xpos(fieldp); fieldp->row_xpos = 0; } break; default: /* should not need to do this, but.... */ return E_UNKNOWN_COMMAND; /* NOTREACHED */ break; } } /* call the field and form init functions if required. */ if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) { if (form->field_init != NULL) form->field_init(form); /* * if we have a page movement then the form init * needs to be called too */ if ((c <= REQ_LAST_PAGE) && (form->form_init != NULL)) form->form_init(form); /* * if there was an error just return now... */ if (status != E_OK) return status; /* if we have no error, reset the various offsets */ fieldp = form->fields[form->cur_field]; fieldp->start_char = 0; fieldp->start_line = fieldp->alines; fieldp->cur_line = fieldp->alines; fieldp->row_xpos = 0; fieldp->cursor_ypos = 0; _formi_init_field_xpos(fieldp); } if (update_field < 0) return update_field; if (update_field == 1) update_page |= _formi_update_field(form, old_field); if (update_page == 1) _formi_draw_page(form); pos_form_cursor(form); if ((update_page == 1) || (update_field == 1)) wrefresh(form->scrwin); return E_OK; }
int filter_input_box(const int debuglvl, struct vrmr_filter *filter) { WINDOW *ib_win = NULL; PANEL *my_panels[1]; FIELD *cur = NULL, *prev = NULL; FORM *my_form = NULL; int height = 0, width = 0, startx = 0, starty = 0, max_height = 0, max_width = 0, ch = 0, rows = 0, cols = 0, quit = 0; size_t i = 0; char not_defined = FALSE; /* init fields */ memset(&FiFi, 0, sizeof(struct FilterFields_)); /* set the window size */ getmaxyx(stdscr, max_height, max_width); height = 9; width = 48; /* print on the center of the screen */ starty = (max_height - height) / 2; startx = (max_width - width) / 2; /* create window */ ib_win = create_newwin(height, width, starty, startx, gettext("Filter"), vccnf.color_win); if(ib_win == NULL) { vrmr_error(-1, VR_ERR, gettext("creating window failed.")); return(-1); } my_panels[0] = new_panel(ib_win); if(my_panels[0] == NULL) { vrmr_error(-1, VR_ERR, gettext("creating panel failed.")); return(-1); } FiFi.n_fields = 2; FiFi.fields = (FIELD **)calloc(FiFi.n_fields + 1, sizeof(FIELD *)); if(FiFi.fields == NULL) { vrmr_error(-1, VR_ERR, gettext("calloc failed: %s (in: %s:%d)."), strerror(errno), __FUNC__, __LINE__); return(-1); } FiFi.string_fld = (FiFi.fields[0] = new_field(1, 31, 3, 4, 0, 0)); FiFi.check_fld = (FiFi.fields[1] = new_field(1, 1, 5, 5, 0, 0)); set_field_back(FiFi.string_fld, vccnf.color_win_rev); field_opts_off(FiFi.string_fld, O_AUTOSKIP); set_field_status(FiFi.string_fld, FALSE); set_field_buffer_wrap(debuglvl, FiFi.string_fld, 0, filter->str); set_field_back(FiFi.check_fld, vccnf.color_win); field_opts_off(FiFi.check_fld, O_AUTOSKIP); set_field_status(FiFi.check_fld, FALSE); set_field_buffer_wrap(debuglvl, FiFi.check_fld, 0, filter->neg ? "X" : " "); my_form = new_form(FiFi.fields); scale_form(my_form, &rows, &cols); keypad(ib_win, TRUE); set_form_win(my_form, ib_win); set_form_sub(my_form, derwin(ib_win, rows, cols, 1, 2)); post_form(my_form); /* XXX: we really should have a wrapper function to just print * in the middle of a window to prevent hacks like this. */ char *s = gettext("Enter filter (leave empty for no filter)"); mvwprintw(ib_win, 2, (width - StrLen(s))/2, s); mvwprintw(ib_win, 6, 6, "["); mvwprintw(ib_win, 6, 8, "]"); mvwprintw(ib_win, 6, 11, gettext("show lines that don't match")); update_panels(); doupdate(); if(!(cur = current_field(my_form))) { vrmr_error(-1, VR_INTERR, "NULL pointer (in: %s:%d).", __FUNC__, __LINE__); return(-1); } while(quit == 0) { /* draw nice markers */ draw_field_active_mark(cur, prev, ib_win, my_form, vccnf.color_win_mark|A_BOLD); not_defined = 0; /* get user input */ ch = wgetch(ib_win); if(cur == FiFi.check_fld) { if(nav_field_toggleX(debuglvl, my_form, ch) < 0) not_defined = 1; } else if(cur == FiFi.string_fld) { if(nav_field_simpletext(debuglvl, my_form, ch) < 0) not_defined = 1; } else { not_defined = 1; } /* the rest is handled here */ if(not_defined) { switch(ch) { case KEY_UP: form_driver(my_form, REQ_PREV_FIELD); form_driver(my_form, REQ_END_LINE); break; case KEY_DOWN: case 9: // tab form_driver(my_form, REQ_NEXT_FIELD); form_driver(my_form, REQ_END_LINE); break; case 10: // enter if(cur == FiFi.check_fld) { quit = 1; } else { form_driver(my_form, REQ_NEXT_FIELD); form_driver(my_form, REQ_END_LINE); } break; case 27: case KEY_F(10): case 'q': case 'Q': quit = 1; break; } } /* before we get the new 'cur', store cur in prev */ prev = cur; if(!(cur = current_field(my_form))) { vrmr_error(-1, VR_INTERR, "NULL pointer (in: %s).", __FUNC__); return(-1); } /* draw and set cursor */ wrefresh(ib_win); pos_form_cursor(my_form); } /* save here */ if(filter_save(debuglvl, filter) < 0) { vrmr_error(-1, VR_ERR, gettext("setting filter failed.")); } unpost_form(my_form); free_form(my_form); for(i=0; i < FiFi.n_fields; i++) { free_field(FiFi.fields[i]); } free(FiFi.fields); del_panel(my_panels[0]); destroy_win(ib_win); update_panels(); doupdate(); return(0); }