1 /* Input field widget implementation. */
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "elinks.h"
12
13 #include "bfu/button.h"
14 #include "bfu/dialog.h"
15 #include "bfu/inpfield.h"
16 #include "bfu/inphist.h"
17 #include "bfu/msgbox.h"
18 #include "bfu/text.h"
19 #include "config/kbdbind.h"
20 #include "intl/gettext/libintl.h"
21 #include "osdep/osdep.h"
22 #include "session/session.h"
23 #include "terminal/draw.h"
24 #include "terminal/kbd.h"
25 #include "terminal/mouse.h"
26 #include "terminal/terminal.h"
27 #include "terminal/window.h"
28 #include "util/color.h"
29 #include "util/memlist.h"
30 #include "util/memory.h"
31
32 #define INPUTFIELD_HEIGHT 1
33
34 #define INPUTFIELD_FLOATLABEL_PADDING 1
35
36 #define INPUTFIELD_FLOAT_SEPARATOR ":"
37 #define INPUTFIELD_FLOAT_SEPARATOR_LEN 1
38
39 void
add_dlg_field_do(struct dialog * dlg,enum widget_type type,unsigned char * label,int min,int max,widget_handler_T * handler,int datalen,void * data,struct input_history * history,enum inpfield_flags flags)40 add_dlg_field_do(struct dialog *dlg, enum widget_type type, unsigned char *label,
41 int min, int max, widget_handler_T *handler,
42 int datalen, void *data,
43 struct input_history *history, enum inpfield_flags flags)
44 {
45 struct widget *widget = &dlg->widgets[dlg->number_of_widgets++];
46
47 widget->type = type;
48 widget->text = label;
49 widget->handler = handler;
50 widget->datalen = datalen;
51 widget->data = data;
52
53 widget->info.field.history = history;
54 widget->info.field.flags = flags;
55 widget->info.field.min = min;
56 widget->info.field.max = max;
57 }
58
59 widget_handler_status_T
check_number(struct dialog_data * dlg_data,struct widget_data * widget_data)60 check_number(struct dialog_data *dlg_data, struct widget_data *widget_data)
61 {
62 struct widget *widget = widget_data->widget;
63 char *end;
64 long l;
65
66 errno = 0;
67 l = strtol(widget_data->cdata, &end, 10);
68
69 if (errno || !*widget_data->cdata || *end) {
70 info_box(dlg_data->win->term, 0,
71 N_("Bad number"), ALIGN_CENTER,
72 N_("Number expected in field"));
73 return EVENT_NOT_PROCESSED;
74 }
75
76 if (l < widget->info.field.min || l > widget->info.field.max) {
77 info_box(dlg_data->win->term, MSGBOX_FREE_TEXT,
78 N_("Bad number"), ALIGN_CENTER,
79 msg_text(dlg_data->win->term,
80 N_("Number should be in the range from %d to %d."),
81 widget->info.field.min, widget->info.field.max));
82 return EVENT_NOT_PROCESSED;
83 }
84
85 return EVENT_PROCESSED;
86 }
87
88 widget_handler_status_T
check_nonempty(struct dialog_data * dlg_data,struct widget_data * widget_data)89 check_nonempty(struct dialog_data *dlg_data, struct widget_data *widget_data)
90 {
91 unsigned char *p;
92
93 for (p = widget_data->cdata; *p; p++)
94 if (*p > ' ')
95 return EVENT_PROCESSED;
96
97 info_box(dlg_data->win->term, 0,
98 N_("Bad string"), ALIGN_CENTER,
99 N_("Empty string not allowed"));
100
101 return EVENT_NOT_PROCESSED;
102 }
103
104 void
dlg_format_field(struct terminal * term,struct widget_data * widget_data,int x,int * y,int w,int * rw,enum format_align align)105 dlg_format_field(struct terminal *term,
106 struct widget_data *widget_data,
107 int x, int *y, int w, int *rw, enum format_align align)
108 {
109 static int max_label_width;
110 static int *prev_y; /* Assert the uniqueness of y */ /* TODO: get rid of this !! --Zas */
111 unsigned char *label = widget_data->widget->text;
112 struct color_pair *text_color = NULL;
113 int label_width = 0;
114 int float_label = widget_data->widget->info.field.flags & (INPFIELD_FLOAT|INPFIELD_FLOAT2);
115
116 if (label && *label && float_label) {
117 label_width = strlen(label);
118 if (prev_y == y) {
119 int_lower_bound(&max_label_width, label_width);
120 } else {
121 max_label_width = label_width;
122 prev_y = y;
123 }
124
125 /* Right align the floating label up against the
126 * input field */
127 x += max_label_width - label_width;
128 w -= max_label_width - label_width;
129 }
130
131 if (label && *label) {
132 if (term) text_color = get_bfu_color(term, "dialog.text");
133
134 dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT);
135 }
136
137 /* XXX: We want the field and label on the same line if the terminal
138 * width allows it. */
139 if (label && *label && float_label) {
140 if (widget_data->widget->info.field.flags & INPFIELD_FLOAT) {
141 (*y) -= INPUTFIELD_HEIGHT;
142 dlg_format_text_do(term, INPUTFIELD_FLOAT_SEPARATOR,
143 x + label_width, y, w, rw,
144 text_color, ALIGN_LEFT);
145 w -= INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
146 x += INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
147 }
148
149 /* FIXME: Is 5 chars for input field enough? --jonas */
150 if (label_width < w - 5) {
151 (*y) -= INPUTFIELD_HEIGHT;
152 w -= label_width;
153 x += label_width;
154 }
155 }
156
157 if (rw) int_lower_bound(rw, int_min(w, DIALOG_MIN_WIDTH));
158
159 set_box(&widget_data->box, x, *y, w, INPUTFIELD_HEIGHT);
160
161 (*y) += INPUTFIELD_HEIGHT;
162 }
163
164 static widget_handler_status_T
input_field_cancel(struct dialog_data * dlg_data,struct widget_data * widget_data)165 input_field_cancel(struct dialog_data *dlg_data, struct widget_data *widget_data)
166 {
167 void (*fn)(void *) = widget_data->widget->data;
168 void *data = dlg_data->dlg->udata2;
169
170 if (fn) fn(data);
171
172 return cancel_dialog(dlg_data, widget_data);
173 }
174
175 static widget_handler_status_T
input_field_ok(struct dialog_data * dlg_data,struct widget_data * widget_data)176 input_field_ok(struct dialog_data *dlg_data, struct widget_data *widget_data)
177 {
178 void (*fn)(void *, unsigned char *) = widget_data->widget->data;
179 void *data = dlg_data->dlg->udata2;
180 unsigned char *text = dlg_data->widgets_data->cdata;
181
182 if (check_dialog(dlg_data)) return EVENT_NOT_PROCESSED;
183
184 if (widget_has_history(dlg_data->widgets_data))
185 add_to_input_history(dlg_data->dlg->widgets->info.field.history,
186 text, 1);
187
188 if (fn) fn(data, text);
189
190 return cancel_dialog(dlg_data, widget_data);
191 }
192
193 void
input_field(struct terminal * term,struct memory_list * ml,int intl,unsigned char * title,unsigned char * text,unsigned char * okbutton,unsigned char * cancelbutton,void * data,struct input_history * history,int l,unsigned char * def,int min,int max,widget_handler_T * check,void (* fn)(void *,unsigned char *),void (* cancelfn)(void *))194 input_field(struct terminal *term, struct memory_list *ml, int intl,
195 unsigned char *title,
196 unsigned char *text,
197 unsigned char *okbutton,
198 unsigned char *cancelbutton,
199 void *data, struct input_history *history, int l,
200 unsigned char *def, int min, int max,
201 widget_handler_T *check,
202 void (*fn)(void *, unsigned char *),
203 void (*cancelfn)(void *))
204 {
205 struct dialog *dlg;
206 unsigned char *field;
207
208 if (intl) {
209 title = _(title, term);
210 text = _(text, term);
211 okbutton = _(okbutton, term);
212 cancelbutton = _(cancelbutton, term);
213 }
214
215 #define INPUT_WIDGETS_COUNT 3
216 dlg = calloc_dialog(INPUT_WIDGETS_COUNT, l);
217 if (!dlg) return;
218
219 /* @field is automatically cleared by calloc() */
220 field = get_dialog_offset(dlg, INPUT_WIDGETS_COUNT);
221
222 if (def) {
223 int defsize = strlen(def) + 1;
224
225 memcpy(field, def, (defsize > l) ? l - 1 : defsize);
226 }
227
228 dlg->title = title;
229 dlg->layouter = generic_dialog_layouter;
230 dlg->layout.fit_datalen = 1;
231 dlg->udata2 = data;
232
233 add_dlg_field(dlg, text, min, max, check, l, field, history);
234
235 add_dlg_button(dlg, okbutton, B_ENTER, input_field_ok, fn);
236 add_dlg_button(dlg, cancelbutton, B_ESC, input_field_cancel, cancelfn);
237
238 add_dlg_end(dlg, INPUT_WIDGETS_COUNT);
239
240 add_to_ml(&ml, dlg, NULL);
241 do_dialog(term, dlg, ml);
242 }
243
244 void
input_dialog(struct terminal * term,struct memory_list * ml,unsigned char * title,unsigned char * text,void * data,struct input_history * history,int l,unsigned char * def,int min,int max,widget_handler_T * check,void (* fn)(void *,unsigned char *),void (* cancelfn)(void *))245 input_dialog(struct terminal *term, struct memory_list *ml,
246 unsigned char *title,
247 unsigned char *text,
248 void *data, struct input_history *history, int l,
249 unsigned char *def, int min, int max,
250 widget_handler_T *check,
251 void (*fn)(void *, unsigned char *),
252 void (*cancelfn)(void *))
253 {
254 input_field(term, ml, 1, title, text, N_("~OK"), N_("~Cancel"),
255 data, history, l,
256 def, min, max,
257 check, fn, cancelfn);
258 }
259
260 static widget_handler_status_T
display_field_do(struct dialog_data * dlg_data,struct widget_data * widget_data,int hide)261 display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
262 int hide)
263 {
264 struct terminal *term = dlg_data->win->term;
265 struct color_pair *color;
266 int sel = is_selected_widget(dlg_data, widget_data);
267
268 int_bounds(&widget_data->info.field.vpos,
269 widget_data->info.field.cpos - widget_data->box.width + 1,
270 widget_data->info.field.cpos);
271 int_lower_bound(&widget_data->info.field.vpos, 0);
272
273 color = get_bfu_color(term, "dialog.field");
274 if (color)
275 draw_box(term, &widget_data->box, ' ', 0, color);
276
277 color = get_bfu_color(term, "dialog.field-text");
278 if (color) {
279 int len = strlen(widget_data->cdata + widget_data->info.field.vpos);
280 int w = int_min(len, widget_data->box.width);
281
282 if (!hide) {
283 draw_text(term, widget_data->box.x, widget_data->box.y,
284 widget_data->cdata + widget_data->info.field.vpos, w,
285 0, color);
286 } else {
287 struct box box;
288
289 copy_box(&box, &widget_data->box);
290 box.width = w;
291
292 draw_box(term, &box, '*', 0, color);
293 }
294 }
295
296 if (sel) {
297 int x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos;
298
299 set_cursor(term, x, widget_data->box.y, 0);
300 set_window_ptr(dlg_data->win, widget_data->box.x, widget_data->box.y);
301 }
302
303 return EVENT_PROCESSED;
304 }
305
306 static widget_handler_status_T
display_field(struct dialog_data * dlg_data,struct widget_data * widget_data)307 display_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
308 {
309 return display_field_do(dlg_data, widget_data, 0);
310 }
311
312 static widget_handler_status_T
display_field_pass(struct dialog_data * dlg_data,struct widget_data * widget_data)313 display_field_pass(struct dialog_data *dlg_data, struct widget_data *widget_data)
314 {
315 return display_field_do(dlg_data, widget_data, 1);
316 }
317
318 static widget_handler_status_T
init_field(struct dialog_data * dlg_data,struct widget_data * widget_data)319 init_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
320 {
321 if (widget_has_history(widget_data)) {
322 struct input_history_entry *entry;
323
324 foreach (entry, widget_data->widget->info.field.history->entries) {
325 int datalen = strlen(entry->data);
326 struct input_history_entry *new_entry;
327
328 /* One byte is reserved in struct input_history_entry. */
329 new_entry = mem_alloc(sizeof(*new_entry) + datalen);
330 if (!new_entry) continue;
331
332 memcpy(new_entry->data, entry->data, datalen + 1);
333 add_to_list(widget_data->info.field.history, new_entry);
334 }
335 }
336
337 widget_data->info.field.cpos = strlen(widget_data->cdata);
338 return EVENT_PROCESSED;
339 }
340
341 static int
field_prev_history(struct widget_data * widget_data)342 field_prev_history(struct widget_data *widget_data)
343 {
344 if (widget_has_history(widget_data)
345 && (void *) widget_data->info.field.cur_hist->prev != &widget_data->info.field.history) {
346 widget_data->info.field.cur_hist = widget_data->info.field.cur_hist->prev;
347 dlg_set_history(widget_data);
348 return 1;
349 }
350 return 0;
351 }
352
353 static int
field_next_history(struct widget_data * widget_data)354 field_next_history(struct widget_data *widget_data)
355 {
356 if (widget_has_history(widget_data)
357 && (void *) widget_data->info.field.cur_hist != &widget_data->info.field.history) {
358 widget_data->info.field.cur_hist = widget_data->info.field.cur_hist->next;
359 dlg_set_history(widget_data);
360 return 1;
361 }
362 return 0;
363 }
364
365 static widget_handler_status_T
mouse_field(struct dialog_data * dlg_data,struct widget_data * widget_data)366 mouse_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
367 {
368 struct term_event *ev = dlg_data->term_event;
369
370 if (!check_mouse_position(ev, &widget_data->box))
371 return EVENT_NOT_PROCESSED;
372
373 /* Handle navigation through history (if any) using up/down mouse wheel */
374 switch (get_mouse_button(ev)) {
375 case B_WHEEL_UP:
376 if (check_mouse_action(ev, B_DOWN)) {
377 if (field_prev_history(widget_data)) {
378 select_widget(dlg_data, widget_data);
379 return EVENT_PROCESSED;
380 }
381 }
382 return EVENT_NOT_PROCESSED;
383
384 case B_WHEEL_DOWN:
385 if (check_mouse_action(ev, B_DOWN)) {
386 if (field_next_history(widget_data)) {
387 select_widget(dlg_data, widget_data);
388 return EVENT_PROCESSED;
389 }
390 }
391 return EVENT_NOT_PROCESSED;
392 }
393
394 /* Place text cursor at mouse position and focus the widget. */
395 widget_data->info.field.cpos = widget_data->info.field.vpos
396 + ev->info.mouse.x - widget_data->box.x;
397 int_upper_bound(&widget_data->info.field.cpos, strlen(widget_data->cdata));
398
399 select_widget(dlg_data, widget_data);
400 return EVENT_PROCESSED;
401 }
402
403 static widget_handler_status_T
kbd_field(struct dialog_data * dlg_data,struct widget_data * widget_data)404 kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
405 {
406 struct window *win = dlg_data->win;
407 struct terminal *term = win->term;
408 struct term_event *ev = dlg_data->term_event;
409 action_id_T action_id;
410
411 action_id = kbd_action(KEYMAP_EDIT, ev, NULL);
412 if (action_id != -1
413 && !action_is_anonymous_safe(KEYMAP_EDIT, action_id)
414 && get_cmd_opt_bool("anonymous"))
415 return EVENT_NOT_PROCESSED;
416
417 switch (action_id) {
418 case ACT_EDIT_UP:
419 if (!widget_has_history(widget_data))
420 return EVENT_NOT_PROCESSED;
421
422 if (field_prev_history(widget_data)) {
423 goto display_field;
424 }
425 break;
426
427 case ACT_EDIT_DOWN:
428 if (!widget_has_history(widget_data))
429 return EVENT_NOT_PROCESSED;
430
431 if (field_next_history(widget_data)) {
432 goto display_field;
433 }
434 break;
435
436 case ACT_EDIT_RIGHT:
437 if (widget_data->info.field.cpos < strlen(widget_data->cdata))
438 widget_data->info.field.cpos++;
439 goto display_field;
440
441 case ACT_EDIT_LEFT:
442 if (widget_data->info.field.cpos > 0)
443 widget_data->info.field.cpos--;
444 goto display_field;
445
446 case ACT_EDIT_HOME:
447 widget_data->info.field.cpos = 0;
448 goto display_field;
449
450 case ACT_EDIT_END:
451 widget_data->info.field.cpos = strlen(widget_data->cdata);
452 goto display_field;
453
454 case ACT_EDIT_BACKSPACE:
455 if (widget_data->info.field.cpos) {
456 memmove(widget_data->cdata + widget_data->info.field.cpos - 1,
457 widget_data->cdata + widget_data->info.field.cpos,
458 strlen(widget_data->cdata) - widget_data->info.field.cpos + 1);
459 widget_data->info.field.cpos--;
460 }
461 goto display_field;
462
463 case ACT_EDIT_DELETE:
464 {
465 int cdata_len = strlen(widget_data->cdata);
466
467 if (widget_data->info.field.cpos >= cdata_len) goto display_field;
468
469 memmove(widget_data->cdata + widget_data->info.field.cpos,
470 widget_data->cdata + widget_data->info.field.cpos + 1,
471 cdata_len - widget_data->info.field.cpos + 1);
472 goto display_field;
473 }
474
475 case ACT_EDIT_KILL_TO_BOL:
476 memmove(widget_data->cdata,
477 widget_data->cdata + widget_data->info.field.cpos,
478 strlen(widget_data->cdata + widget_data->info.field.cpos) + 1);
479 widget_data->info.field.cpos = 0;
480 goto display_field;
481
482 case ACT_EDIT_KILL_TO_EOL:
483 widget_data->cdata[widget_data->info.field.cpos] = 0;
484 goto display_field;
485
486 case ACT_EDIT_COPY_CLIPBOARD:
487 /* Copy to clipboard */
488 set_clipboard_text(widget_data->cdata);
489 return EVENT_PROCESSED;
490
491 case ACT_EDIT_CUT_CLIPBOARD:
492 /* Cut to clipboard */
493 set_clipboard_text(widget_data->cdata);
494 widget_data->cdata[0] = 0;
495 widget_data->info.field.cpos = 0;
496 goto display_field;
497
498 case ACT_EDIT_PASTE_CLIPBOARD:
499 {
500 /* Paste from clipboard */
501 unsigned char *clipboard = get_clipboard_text();
502
503 if (!clipboard) goto display_field;
504
505 safe_strncpy(widget_data->cdata, clipboard, widget_data->widget->datalen);
506 widget_data->info.field.cpos = strlen(widget_data->cdata);
507 mem_free(clipboard);
508 goto display_field;
509 }
510
511 case ACT_EDIT_AUTO_COMPLETE:
512 if (!widget_has_history(widget_data))
513 return EVENT_NOT_PROCESSED;
514
515 do_tab_compl(dlg_data, &widget_data->info.field.history);
516 goto display_field;
517
518 case ACT_EDIT_AUTO_COMPLETE_FILE:
519 if (!widget_has_history(widget_data))
520 return EVENT_NOT_PROCESSED;
521
522 do_tab_compl_file(dlg_data, &widget_data->info.field.history);
523 goto display_field;
524
525 case ACT_EDIT_AUTO_COMPLETE_UNAMBIGUOUS:
526 if (!widget_has_history(widget_data))
527 return EVENT_NOT_PROCESSED;
528
529 do_tab_compl_unambiguous(dlg_data, &widget_data->info.field.history);
530 goto display_field;
531
532 case ACT_EDIT_REDRAW:
533 redraw_terminal_cls(term);
534 return EVENT_PROCESSED;
535
536 default:
537 if (check_kbd_textinput_key(ev)) {
538 unsigned char *text = widget_data->cdata;
539 int textlen = strlen(text);
540
541 if (textlen >= widget_data->widget->datalen - 1)
542 goto display_field;
543
544 /* Shift to position of the cursor */
545 textlen -= widget_data->info.field.cpos;
546 text += widget_data->info.field.cpos++;
547
548 memmove(text + 1, text, textlen + 1);
549 *text = get_kbd_key(ev);
550
551 goto display_field;
552 }
553 }
554 return EVENT_NOT_PROCESSED;
555
556 display_field:
557 display_widget(dlg_data, widget_data);
558 redraw_from_window(dlg_data->win);
559 return EVENT_PROCESSED;
560 }
561
562
563 static widget_handler_status_T
clear_field(struct dialog_data * dlg_data,struct widget_data * widget_data)564 clear_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
565 {
566 widget_data->info.field.cpos = 0;
567
568 if (widget_data->widget->datalen)
569 memset(widget_data->cdata, 0, widget_data->widget->datalen);
570
571 return EVENT_PROCESSED;
572 }
573
574 struct widget_ops field_ops = {
575 display_field,
576 init_field,
577 mouse_field,
578 kbd_field,
579 NULL,
580 clear_field,
581 };
582
583 struct widget_ops field_pass_ops = {
584 display_field_pass,
585 init_field,
586 mouse_field,
587 kbd_field,
588 NULL,
589 clear_field,
590 };
591
592
593 /* Input lines */
594
595 static void
input_line_layouter(struct dialog_data * dlg_data)596 input_line_layouter(struct dialog_data *dlg_data)
597 {
598 struct input_line *input_line = dlg_data->dlg->udata;
599 struct session *ses = input_line->ses;
600 struct window *win = dlg_data->win;
601 int y = win->term->height - 1
602 - ses->status.show_status_bar
603 - ses->status.show_tabs_bar;
604
605 dlg_format_field(win->term, dlg_data->widgets_data, 0,
606 &y, win->term->width, NULL, ALIGN_LEFT);
607 }
608
609 static widget_handler_status_T
input_line_event_handler(struct dialog_data * dlg_data)610 input_line_event_handler(struct dialog_data *dlg_data)
611 {
612 struct input_line *input_line = dlg_data->dlg->udata;
613 input_line_handler_T handler = input_line->handler;
614 enum edit_action action_id;
615 struct widget_data *widget_data = dlg_data->widgets_data;
616 struct term_event *ev = dlg_data->term_event;
617
618 /* Noodle time */
619 switch (ev->ev) {
620 case EVENT_KBD:
621 action_id = kbd_action(KEYMAP_EDIT, ev, NULL);
622
623 /* Handle some basic actions such as quiting for empty buffers */
624 switch (action_id) {
625 case ACT_EDIT_ENTER:
626 case ACT_EDIT_NEXT_ITEM:
627 case ACT_EDIT_PREVIOUS_ITEM:
628 if (widget_has_history(widget_data))
629 add_to_input_history(widget_data->widget->info.field.history,
630 input_line->buffer, 1);
631 break;
632
633 case ACT_EDIT_BACKSPACE:
634 if (!*input_line->buffer)
635 goto cancel_input_line;
636 break;
637
638 case ACT_EDIT_CANCEL:
639 goto cancel_input_line;
640
641 default:
642 break;
643 }
644
645 /* First let the input field do its business */
646 kbd_field(dlg_data, widget_data);
647 break;
648
649 case EVENT_MOUSE:
650 #ifdef CONFIG_MOUSE
651 if (ev->info.mouse.y != dlg_data->win->y) {
652 delete_window_ev(dlg_data->win, ev);
653 return EVENT_PROCESSED;
654 }
655 #endif /* CONFIG_MOUSE */
656 return EVENT_NOT_PROCESSED;
657
658 case EVENT_REDRAW:
659 /* Try to catch the redraw event initiated by the history
660 * completion and only respond if something was actually
661 * updated. Meaning we have new data in the line buffer that
662 * should be propagated to the line handler. */
663 if (!widget_has_history(widget_data)
664 || widget_data->info.field.cpos <= 0
665 || widget_data->info.field.cpos <= strlen(input_line->buffer))
666 return EVENT_NOT_PROCESSED;
667
668 /* Fall thru */
669
670 case EVENT_RESIZE:
671 action_id = ACT_EDIT_REDRAW;
672 break;
673
674 default:
675 return EVENT_NOT_PROCESSED;
676 }
677
678 update_dialog_data(dlg_data);
679
680 send_action_to_handler:
681 /* Then pass it on to the specialized handler */
682 switch (handler(input_line, action_id)) {
683 case INPUT_LINE_CANCEL:
684 cancel_input_line:
685 cancel_dialog(dlg_data, widget_data);
686 break;
687
688 case INPUT_LINE_REWIND:
689 /* This is stolen kbd_field() handling for ACT_EDIT_BACKSPACE */
690 memmove(widget_data->cdata + widget_data->info.field.cpos - 1,
691 widget_data->cdata + widget_data->info.field.cpos,
692 strlen(widget_data->cdata) - widget_data->info.field.cpos + 1);
693 widget_data->info.field.cpos--;
694
695 update_dialog_data(dlg_data);
696
697 goto send_action_to_handler;
698
699 case INPUT_LINE_PROCEED:
700 break;
701 }
702
703 /* Hack: We want our caller to perform its redrawing routine,
704 * even if we did process the event here. */
705 if (action_id == ACT_EDIT_REDRAW) return EVENT_NOT_PROCESSED;
706
707 /* Completely bypass any further dialog event handling */
708 return EVENT_PROCESSED;
709 }
710
711 void
input_field_line(struct session * ses,unsigned char * prompt,void * data,struct input_history * history,input_line_handler_T handler)712 input_field_line(struct session *ses, unsigned char *prompt, void *data,
713 struct input_history *history, input_line_handler_T handler)
714 {
715 struct dialog *dlg;
716 unsigned char *buffer;
717 struct input_line *input_line;
718
719 assert(ses);
720
721 dlg = calloc_dialog(INPUT_LINE_WIDGETS, sizeof(*input_line));
722 if (!dlg) return;
723
724 input_line = (void *) get_dialog_offset(dlg, INPUT_LINE_WIDGETS);
725 input_line->ses = ses;
726 input_line->data = data;
727 input_line->handler = handler;
728 buffer = input_line->buffer;
729
730 dlg->handle_event = input_line_event_handler;
731 dlg->layouter = input_line_layouter;
732 dlg->layout.only_widgets = 1;
733 dlg->udata = input_line;
734
735 add_dlg_field_float2(dlg, prompt, 0, 0, NULL, INPUT_LINE_BUFFER_SIZE,
736 buffer, history);
737
738 do_dialog(ses->tab->term, dlg, getml(dlg, NULL));
739 }
740