1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2002-2011 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
54 const char *inputhelp
= {
55 "UP/DOWN/LEFT/RIGHT - position cursor (multiline)\n" \
56 " UP/CTRL-P - previous input history\n" \
57 " DOWN/CTRL-N - next input history\n" \
58 " HOME/CTRL-A - move cursor to the beginning of line\n" \
59 " END/CTRL-E - move cursor to the end of line\n" \
60 " CTRL-B/W - move cursor to previous/next word\n" \
61 " CTRL-X - delete word under cursor\n" \
62 " CTRL-K - delete from cursor to end of line\n" \
63 " CTRL-U - clear entire input field\n" \
64 " BACKSPACE - delete previous character\n" \
65 " ESCAPE - quit without changes\n" \
66 " ENTER - quit with changes"
69 static struct input_history_s
{
71 struct input_history_s
*next
;
72 struct input_history_s
*prev
;
73 struct input_history_s
*head
;
74 } *input_history
[INPUT_HIST_MAX
];
76 static void add_input_history(int which
, const char *str
)
78 struct input_history_s
*new;
79 struct input_history_s
*p
= NULL
;
81 if (!str
|| !*str
|| which
< 0)
84 if (input_history
[which
])
85 for (p
= input_history
[which
]->head
; p
->next
; p
= p
->next
);
87 new = calloc(1, sizeof(struct input_history_s
));
88 new->str
= strdup(str
);
98 input_history
[which
] = p
? p
->next
: new;
101 static bool validate_pgn_tag_name(int c
, const void *arg
)
103 if (!isalnum(c
) && c
!= '_')
109 static bool validate_pgn_date(int c
, const void *arg
)
111 if (!isdigit(c
) && c
!= '.' && c
!= '?')
117 static bool validate_pgn_round(int c
, const void *arg
)
119 if (!isdigit(c
) && c
!= '.' && c
!= '-' && c
!= '?')
125 static bool validate_pgn_result(int c
, const void *arg
)
127 if (c
!= '1' && c
!= '0' && c
!= '2' && c
!= '*' && c
!= '/' && c
!= '-')
133 static int get_input(WIN
*win
)
135 struct input_s
*in
= win
->data
;
137 struct input_data_s
*data
= in
->data
;
141 window_draw_title(win
->w
, win
->title
, in
->w
, CP_INPUT_TITLE
,
145 for (i
= 0; in
->extra
[i
]; i
++)
146 window_draw_prompt(win
->w
, in
->lines
+ 2 + i
, in
->w
, in
->extra
[i
],
149 window_draw_prompt(win
->w
, in
->lines
+ 2 + i
, in
->w
, INPUT_HELP_PROMPT
,
153 window_draw_prompt(win
->w
, in
->lines
+ 2, in
->w
, INPUT_HELP_PROMPT
,
156 if (in
->func
&& in
->c
&& win
->c
== in
->c
) {
163 form_driver(in
->f
, REQ_DEL_WORD
);
166 form_driver(in
->f
, REQ_PREV_WORD
);
169 form_driver(in
->f
, REQ_NEXT_WORD
);
173 form_driver(in
->f
, REQ_BEG_LINE
);
177 form_driver(in
->f
, REQ_END_LINE
);
180 form_driver(in
->f
, REQ_CLR_EOL
);
183 form_driver(in
->f
, REQ_CLR_FIELD
);
186 message(INPUT_HELP_TITLE
, ANYKEY
, "%s", inputhelp
);
189 form_driver(in
->f
, REQ_LEFT_CHAR
);
192 form_driver(in
->f
, REQ_RIGHT_CHAR
);
196 if (in
->hist
>= 0 && input_history
[in
->hist
] && in
->lines
== 1) {
197 set_field_buffer(in
->fields
[0], 0, input_history
[in
->hist
]->str
);
198 form_driver(in
->f
, REQ_END_LINE
);
200 if (!input_history
[in
->hist
]->prev
)
201 input_history
[in
->hist
] = input_history
[in
->hist
]->head
;
203 input_history
[in
->hist
] = input_history
[in
->hist
]->prev
;
208 form_driver(in
->f
, REQ_UP_CHAR
);
212 if (in
->hist
>= 0 && input_history
[in
->hist
] && in
->lines
== 1) {
213 if (!input_history
[in
->hist
]->next
) {
214 set_field_buffer(in
->fields
[0], 0, NULL
);
215 form_driver(in
->f
, REQ_CLR_FIELD
);
219 input_history
[in
->hist
] = input_history
[in
->hist
]->next
;
220 set_field_buffer(in
->fields
[0], 0, input_history
[in
->hist
]->str
);
221 form_driver(in
->f
, REQ_END_LINE
);
225 form_driver(in
->f
, REQ_DOWN_CHAR
);
229 form_driver(in
->f
, REQ_DEL_PREV
);
232 tmp
= field_buffer(in
->fields
[0], 0);
238 tmp
= (in
->buf
[0]) ? in
->buf
: NULL
;
241 form_driver(in
->f
, (win
->c
& A_CHARTEXT
));
245 form_driver(in
->f
, REQ_VALIDATION
);
253 strncpy(in
->buf
, tmp
, sizeof(in
->buf
));
262 free_field(in
->fields
[0]);
265 for (i
= 0; in
->extra
[i
]; i
++)
271 data
->str
= (in
->buf
[0]) ? strdup(in
->buf
) : NULL
;
274 add_input_history(in
->hist
, in
->buf
);
277 free_fieldtype(in
->ft
);
284 * This function prompts for input. The init argument is the initial value.
285 * The lines argument is how many lines the field is. If zero, then it is
286 * dynamically determined based on the init argument or INPUT_WIDTH if init is
289 * The reset argument is whether pressing ESC returns the initial value or
292 * The extra_help argument is an extra line of help prompt normally used with
293 * the custom_func argument. The custom_func argument is a pointer to a
294 * function of type void which takes one pointer-to-void argument. This
295 * function is called when the ckey argument is pressed.
297 * The efunc parameter is the function that is ran when the window is done
298 * getting input or NULL. This function is ran just before the window is
301 * The type argument is the type of validation for the input defined in
302 * common.h. Remaining arguments are values for the type argument. See
303 * field_type(3X) for validation types.
305 * FIXME form validation is buggy (integers).
307 WIN
*construct_input(const char *title
, const char *init
, int lines
, int reset
,
308 const char *extra_help
, input_func
*func
, void *arg
, int key
,
309 struct input_data_s
*id
, int history
, int type
, ...)
313 int l
= (lines
> 0) ? lines
: 1;
315 FIELDTYPE
*ft
= NULL
;
319 in
= Calloc(1, sizeof(struct input_s
));
323 char *tmp
= strdup(extra_help
);
325 in
->extra
= split_str(tmp
, "\n", &eh
, &in
->w
, 0);
337 in
->lines
= (lines
) ? lines
: 1;
338 win
= window_create(title
, in
->h
, in
->w
, CALCPOSY(in
->h
), CALCPOSX(in
->w
),
339 get_input
, in
, id
->efunc
);
344 in
->fields
[0] = new_field(in
->lines
, in
->w
- 2, 0, 0, 0, 0);
348 case FIELD_TYPE_PGN_ROUND
:
349 ft
= new_fieldtype(NULL
, validate_pgn_round
);
350 set_field_type(in
->fields
[0], ft
);
352 case FIELD_TYPE_PGN_RESULT
:
353 ft
= new_fieldtype(NULL
, validate_pgn_result
);
354 set_field_type(in
->fields
[0], ft
);
356 case FIELD_TYPE_PGN_DATE
:
357 ft
= new_fieldtype(NULL
, validate_pgn_date
);
358 set_field_type(in
->fields
[0], ft
);
360 case FIELD_TYPE_PGN_TAG_NAME
:
361 ft
= new_fieldtype(NULL
, validate_pgn_tag_name
);
362 set_field_type(in
->fields
[0], ft
);
364 case FIELD_TYPE_ALNUM
:
365 set_field_type(in
->fields
[0], TYPE_ALNUM
, va_arg(ap
, int));
367 case FIELD_TYPE_ALPHA
:
368 set_field_type(in
->fields
[0], TYPE_ALPHA
, va_arg(ap
, int));
370 case FIELD_TYPE_ENUM
:
371 set_field_type(in
->fields
[0], TYPE_ENUM
, va_arg(ap
, char **),
372 va_arg(ap
, int), va_arg(ap
, int));
374 case FIELD_TYPE_INTEGER
:
375 set_field_type(in
->fields
[0], TYPE_INTEGER
, va_arg(ap
, int),
376 va_arg(ap
, long), va_arg(ap
, long));
378 case FIELD_TYPE_NUMERIC
:
379 set_field_type(in
->fields
[0], TYPE_NUMERIC
, va_arg(ap
, int),
380 va_arg(ap
, double), va_arg(ap
, double));
382 case FIELD_TYPE_REGEXP
:
383 set_field_type(in
->fields
[0], TYPE_REGEXP
, va_arg(ap
, char *));
386 #ifdef HAVE_TYPE_IPV4
387 case FIELD_TYPE_IPV4
:
388 set_field_type(in
->fields
[0], TYPE_IPV4
);
392 set_field_type(in
->fields
[0], NULL
);
399 strncpy(in
->buf
, init
, sizeof(in
->buf
));
400 set_field_buffer(in
->fields
[0], 0, init
);
406 field_opts_off(in
->fields
[0], O_STATIC
);
409 set_field_buffer(in
->fields
[0], 0, in
->buf
);
411 field_opts_off(in
->fields
[0], O_BLANK
|O_AUTOSKIP
);
412 in
->fields
[1] = NULL
;
413 in
->f
= new_form(in
->fields
);
414 form_opts_off(in
->f
, O_BS_OVERLOAD
);
415 set_form_win(in
->f
, win
->w
);
416 in
->sw
= derwin(win
->w
, in
->lines
, in
->w
- 2, 2, 1);
417 set_form_sub(in
->f
, in
->sw
);
419 form_driver(in
->f
, REQ_END_FIELD
);
420 keypad(win
->w
, TRUE
);
422 wbkgd(win
->w
, CP_INPUT_WINDOW
);