1 /* Input field widget implementation. */
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"
19 #include "config/kbdbind.h"
20 #include "intl/charsets.h"
21 #include "intl/gettext/libintl.h"
22 #include "osdep/osdep.h"
23 #include "session/session.h"
24 #include "terminal/draw.h"
25 #include "terminal/kbd.h"
26 #include "terminal/mouse.h"
27 #include "terminal/terminal.h"
28 #include "terminal/window.h"
29 #include "util/color.h"
30 #include "util/memlist.h"
31 #include "util/memory.h"
33 #define INPUTFIELD_HEIGHT 1
35 #define INPUTFIELD_FLOATLABEL_PADDING 1
37 #define INPUTFIELD_FLOAT_SEPARATOR ":"
38 #define INPUTFIELD_FLOAT_SEPARATOR_LEN 1
41 add_dlg_field_do(struct dialog
*dlg
, enum widget_type type
, unsigned char *label
,
42 int min
, int max
, widget_handler_T
*handler
,
43 int datalen
, void *data
,
44 struct input_history
*history
, enum inpfield_flags flags
)
46 struct widget
*widget
= &dlg
->widgets
[dlg
->number_of_widgets
++];
50 widget
->handler
= handler
;
51 widget
->datalen
= datalen
;
54 widget
->info
.field
.history
= history
;
55 widget
->info
.field
.flags
= flags
;
56 widget
->info
.field
.min
= min
;
57 widget
->info
.field
.max
= max
;
60 widget_handler_status_T
61 check_number(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
63 struct widget
*widget
= widget_data
->widget
;
68 l
= strtol(widget_data
->cdata
, &end
, 10);
70 if (errno
|| !*widget_data
->cdata
|| *end
) {
71 info_box(dlg_data
->win
->term
, 0,
72 N_("Bad number"), ALIGN_CENTER
,
73 N_("Number expected in field"));
74 return EVENT_NOT_PROCESSED
;
77 if (l
< widget
->info
.field
.min
|| l
> widget
->info
.field
.max
) {
78 info_box(dlg_data
->win
->term
, MSGBOX_FREE_TEXT
,
79 N_("Bad number"), ALIGN_CENTER
,
80 msg_text(dlg_data
->win
->term
,
81 N_("Number should be in the range from %d to %d."),
82 widget
->info
.field
.min
, widget
->info
.field
.max
));
83 return EVENT_NOT_PROCESSED
;
86 return EVENT_PROCESSED
;
89 widget_handler_status_T
90 check_nonempty(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
94 for (p
= widget_data
->cdata
; *p
; p
++)
96 return EVENT_PROCESSED
;
98 info_box(dlg_data
->win
->term
, 0,
99 N_("Bad string"), ALIGN_CENTER
,
100 N_("Empty string not allowed"));
102 return EVENT_NOT_PROCESSED
;
106 dlg_format_field(struct dialog_data
*dlg_data
,
107 struct widget_data
*widget_data
,
108 int x
, int *y
, int w
, int *rw
, enum format_align align
, int format_only
)
110 struct terminal
*term
= dlg_data
->win
->term
;
111 static int max_label_width
;
112 static int *prev_y
; /* Assert the uniqueness of y */ /* TODO: get rid of this !! --Zas */
113 unsigned char *label
= widget_data
->widget
->text
;
114 struct color_pair
*text_color
= NULL
;
116 int float_label
= widget_data
->widget
->info
.field
.flags
& (INPFIELD_FLOAT
|INPFIELD_FLOAT2
);
118 if (label
&& *label
&& float_label
) {
119 label_width
= strlen(label
);
121 int_lower_bound(&max_label_width
, label_width
);
123 max_label_width
= label_width
;
127 /* Right align the floating label up against the
129 x
+= max_label_width
- label_width
;
130 w
-= max_label_width
- label_width
;
133 if (label
&& *label
) {
134 if (!format_only
) text_color
= get_bfu_color(term
, "dialog.text");
136 dlg_format_text_do(dlg_data
, label
, x
, y
, w
, rw
, text_color
, ALIGN_LEFT
, format_only
);
139 /* XXX: We want the field and label on the same line if the terminal
140 * width allows it. */
141 if (label
&& *label
&& float_label
) {
142 if (widget_data
->widget
->info
.field
.flags
& INPFIELD_FLOAT
) {
143 (*y
) -= INPUTFIELD_HEIGHT
;
144 dlg_format_text_do(dlg_data
, INPUTFIELD_FLOAT_SEPARATOR
,
145 x
+ label_width
, y
, w
, rw
,
146 text_color
, ALIGN_LEFT
, format_only
);
147 w
-= INPUTFIELD_FLOAT_SEPARATOR_LEN
+ INPUTFIELD_FLOATLABEL_PADDING
;
148 x
+= INPUTFIELD_FLOAT_SEPARATOR_LEN
+ INPUTFIELD_FLOATLABEL_PADDING
;
151 /* FIXME: Is 5 chars for input field enough? --jonas */
152 if (label_width
< w
- 5) {
153 (*y
) -= INPUTFIELD_HEIGHT
;
159 if (rw
) int_lower_bound(rw
, int_min(w
, DIALOG_MIN_WIDTH
));
161 set_box(&widget_data
->box
, x
, *y
, w
, INPUTFIELD_HEIGHT
);
163 (*y
) += INPUTFIELD_HEIGHT
;
166 static widget_handler_status_T
167 input_field_cancel(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
169 void (*fn
)(void *) = widget_data
->widget
->data
;
170 void *data
= dlg_data
->dlg
->udata2
;
174 return cancel_dialog(dlg_data
, widget_data
);
177 static widget_handler_status_T
178 input_field_ok(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
180 void (*fn
)(void *, unsigned char *) = widget_data
->widget
->data
;
181 void *data
= dlg_data
->dlg
->udata2
;
182 unsigned char *text
= dlg_data
->widgets_data
->cdata
;
184 if (check_dialog(dlg_data
)) return EVENT_NOT_PROCESSED
;
186 if (widget_has_history(dlg_data
->widgets_data
))
187 add_to_input_history(dlg_data
->dlg
->widgets
->info
.field
.history
,
190 if (fn
) fn(data
, text
);
192 return cancel_dialog(dlg_data
, widget_data
);
196 input_field(struct terminal
*term
, struct memory_list
*ml
, int intl
,
197 unsigned char *title
,
199 unsigned char *okbutton
,
200 unsigned char *cancelbutton
,
201 void *data
, struct input_history
*history
, int l
,
202 unsigned char *def
, int min
, int max
,
203 widget_handler_T
*check
,
204 void (*fn
)(void *, unsigned char *),
205 void (*cancelfn
)(void *))
208 unsigned char *field
;
211 title
= _(title
, term
);
212 text
= _(text
, term
);
213 okbutton
= _(okbutton
, term
);
214 cancelbutton
= _(cancelbutton
, term
);
217 #define INPUT_WIDGETS_COUNT 3
218 dlg
= calloc_dialog(INPUT_WIDGETS_COUNT
, l
);
221 /* @field is automatically cleared by calloc() */
222 field
= get_dialog_offset(dlg
, INPUT_WIDGETS_COUNT
);
225 int defsize
= strlen(def
) + 1;
227 memcpy(field
, def
, (defsize
> l
) ? l
- 1 : defsize
);
231 dlg
->layouter
= generic_dialog_layouter
;
232 dlg
->layout
.fit_datalen
= 1;
235 add_dlg_field(dlg
, text
, min
, max
, check
, l
, field
, history
);
237 add_dlg_button(dlg
, okbutton
, B_ENTER
, input_field_ok
, fn
);
238 add_dlg_button(dlg
, cancelbutton
, B_ESC
, input_field_cancel
, cancelfn
);
240 add_dlg_end(dlg
, INPUT_WIDGETS_COUNT
);
242 add_to_ml(&ml
, (void *) dlg
, (void *) NULL
);
243 do_dialog(term
, dlg
, ml
);
247 input_dialog(struct terminal
*term
, struct memory_list
*ml
,
248 unsigned char *title
,
250 void *data
, struct input_history
*history
, int l
,
251 unsigned char *def
, int min
, int max
,
252 widget_handler_T
*check
,
253 void (*fn
)(void *, unsigned char *),
254 void (*cancelfn
)(void *))
256 /* [gettext_accelerator_context(input_dialog)] */
257 input_field(term
, ml
, 1, title
, text
, N_("~OK"), N_("~Cancel"),
260 check
, fn
, cancelfn
);
263 static widget_handler_status_T
264 display_field_do(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
,
267 struct terminal
*term
= dlg_data
->win
->term
;
268 struct color_pair
*color
;
269 int sel
= is_selected_widget(dlg_data
, widget_data
);
271 int len
= 0, left
= 0;
272 #endif /* CONFIG_UTF8 */
276 unsigned char *t
= widget_data
->cdata
;
277 int p
= widget_data
->info
.field
.cpos
;
279 len
= utf8_ptr2cells(t
, &t
[p
]);
280 int_bounds(&left
, len
- widget_data
->box
.width
+ 1, len
);
281 int_lower_bound(&left
, 0);
282 widget_data
->info
.field
.vpos
= utf8_cells2bytes(t
, left
, NULL
);
284 #endif /* CONFIG_UTF8 */
286 int_bounds(&widget_data
->info
.field
.vpos
,
287 widget_data
->info
.field
.cpos
- widget_data
->box
.width
+ 1,
288 widget_data
->info
.field
.cpos
);
289 int_lower_bound(&widget_data
->info
.field
.vpos
, 0);
292 color
= get_bfu_color(term
, "dialog.field");
294 draw_box(term
, &widget_data
->box
, ' ', 0, color
);
296 color
= get_bfu_color(term
, "dialog.field-text");
298 unsigned char *text
= widget_data
->cdata
+ widget_data
->info
.field
.vpos
;
302 if (term
->utf8_cp
&& !hide
)
303 len
= utf8_ptr2cells(text
, NULL
);
304 else if (term
->utf8_cp
)
305 len
= utf8_ptr2chars(text
, NULL
);
307 #endif /* CONFIG_UTF8 */
309 w
= int_min(len
, widget_data
->box
.width
);
314 w
= utf8_cells2bytes(text
, w
, NULL
);
315 #endif /* CONFIG_UTF8 */
316 draw_dlg_text(dlg_data
, widget_data
->box
.x
, widget_data
->box
.y
,
321 copy_box(&box
, &widget_data
->box
);
324 draw_box(term
, &box
, '*', 0, color
);
333 x
= widget_data
->box
.x
+ len
- left
;
335 #endif /* CONFIG_UTF8 */
336 x
= widget_data
->box
.x
+ widget_data
->info
.field
.cpos
- widget_data
->info
.field
.vpos
;
338 set_cursor(term
, x
, widget_data
->box
.y
, 0);
339 set_window_ptr(dlg_data
->win
, widget_data
->box
.x
, widget_data
->box
.y
);
342 return EVENT_PROCESSED
;
345 static widget_handler_status_T
346 display_field(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
348 return display_field_do(dlg_data
, widget_data
, 0);
351 static widget_handler_status_T
352 display_field_pass(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
354 return display_field_do(dlg_data
, widget_data
, 1);
357 static widget_handler_status_T
358 init_field(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
360 if (widget_has_history(widget_data
)) {
361 struct input_history_entry
*entry
;
363 foreach (entry
, widget_data
->widget
->info
.field
.history
->entries
) {
364 int datalen
= strlen(entry
->data
);
365 struct input_history_entry
*new_entry
;
367 /* One byte is reserved in struct input_history_entry. */
368 new_entry
= mem_alloc(sizeof(*new_entry
) + datalen
);
369 if (!new_entry
) continue;
371 memcpy(new_entry
->data
, entry
->data
, datalen
+ 1);
372 add_to_list(widget_data
->info
.field
.history
, new_entry
);
376 widget_data
->info
.field
.cpos
= strlen(widget_data
->cdata
);
377 return EVENT_PROCESSED
;
381 field_prev_history(struct widget_data
*widget_data
)
383 if (widget_has_history(widget_data
)
384 && (void *) widget_data
->info
.field
.cur_hist
->prev
!= &widget_data
->info
.field
.history
) {
385 widget_data
->info
.field
.cur_hist
= widget_data
->info
.field
.cur_hist
->prev
;
386 dlg_set_history(widget_data
);
393 field_next_history(struct widget_data
*widget_data
)
395 if (widget_has_history(widget_data
)
396 && (void *) widget_data
->info
.field
.cur_hist
!= &widget_data
->info
.field
.history
) {
397 widget_data
->info
.field
.cur_hist
= widget_data
->info
.field
.cur_hist
->next
;
398 dlg_set_history(widget_data
);
404 static widget_handler_status_T
405 mouse_field(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
407 struct term_event
*ev
= dlg_data
->term_event
;
409 if (!check_mouse_position(ev
, &widget_data
->box
))
410 return EVENT_NOT_PROCESSED
;
412 /* Handle navigation through history (if any) using up/down mouse wheel */
413 switch (get_mouse_button(ev
)) {
415 if (check_mouse_action(ev
, B_DOWN
)) {
416 if (field_prev_history(widget_data
)) {
417 select_widget(dlg_data
, widget_data
);
418 return EVENT_PROCESSED
;
421 return EVENT_NOT_PROCESSED
;
424 if (check_mouse_action(ev
, B_DOWN
)) {
425 if (field_next_history(widget_data
)) {
426 select_widget(dlg_data
, widget_data
);
427 return EVENT_PROCESSED
;
430 return EVENT_NOT_PROCESSED
;
433 /* Place text cursor at mouse position and focus the widget. */
434 widget_data
->info
.field
.cpos
= widget_data
->info
.field
.vpos
435 + ev
->info
.mouse
.x
- widget_data
->box
.x
;
436 int_upper_bound(&widget_data
->info
.field
.cpos
, strlen(widget_data
->cdata
));
438 select_widget(dlg_data
, widget_data
);
439 return EVENT_PROCESSED
;
442 static widget_handler_status_T
443 kbd_field(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
445 struct window
*win
= dlg_data
->win
;
446 struct terminal
*term
= win
->term
;
447 struct term_event
*ev
= dlg_data
->term_event
;
448 action_id_T action_id
;
450 action_id
= kbd_action(KEYMAP_EDIT
, ev
, NULL
);
452 && !action_is_anonymous_safe(KEYMAP_EDIT
, action_id
)
453 && get_cmd_opt_bool("anonymous"))
454 return EVENT_NOT_PROCESSED
;
458 if (!widget_has_history(widget_data
))
459 return EVENT_NOT_PROCESSED
;
461 if (field_prev_history(widget_data
)) {
467 if (!widget_has_history(widget_data
))
468 return EVENT_NOT_PROCESSED
;
470 if (field_next_history(widget_data
)) {
476 if (widget_data
->info
.field
.cpos
< strlen(widget_data
->cdata
)) {
479 unsigned char *next
= widget_data
->cdata
+ widget_data
->info
.field
.cpos
;
480 unsigned char *end
= strchr((const char *)next
, '\0');
482 utf8_to_unicode(&next
, end
);
483 widget_data
->info
.field
.cpos
= (int)(next
- widget_data
->cdata
);
485 #endif /* CONFIG_UTF8 */
487 widget_data
->info
.field
.cpos
++;
493 if (widget_data
->info
.field
.cpos
> 0)
494 widget_data
->info
.field
.cpos
--;
496 if (widget_data
->info
.field
.cpos
&& term
->utf8_cp
) {
497 unsigned char *t
= widget_data
->cdata
;
498 unsigned char *t2
= t
;
499 int p
= widget_data
->info
.field
.cpos
;
500 unsigned char tmp
= t
[p
];
505 widget_data
->info
.field
.cpos
= (int)(t2
- t
);
508 #endif /* CONFIG_UTF8 */
512 widget_data
->info
.field
.cpos
= 0;
516 widget_data
->info
.field
.cpos
= strlen(widget_data
->cdata
);
519 case ACT_EDIT_BACKSPACE
:
521 if (widget_data
->info
.field
.cpos
&& term
->utf8_cp
) {
522 /* XXX: stolen from src/viewer/text/form.c */
523 /* FIXME: This isn't nice. We remove last byte
524 * from UTF-8 character to detect
525 * character before it. */
526 unsigned char *text
= widget_data
->cdata
;
527 unsigned char *end
= widget_data
->cdata
+ widget_data
->info
.field
.cpos
- 1;
529 int old
= widget_data
->info
.field
.cpos
;
532 data
= utf8_to_unicode(&text
, end
);
533 if (data
== UCS_NO_CHAR
)
537 widget_data
->info
.field
.cpos
= (int)(text
- widget_data
->cdata
);
538 if (old
!= widget_data
->info
.field
.cpos
) {
541 text
= widget_data
->cdata
;
542 length
= strlen(text
+ old
) + 1;
543 memmove(text
+ widget_data
->info
.field
.cpos
, text
+ old
, length
);
547 #endif /* CONFIG_UTF8 */
548 if (widget_data
->info
.field
.cpos
) {
549 memmove(widget_data
->cdata
+ widget_data
->info
.field
.cpos
- 1,
550 widget_data
->cdata
+ widget_data
->info
.field
.cpos
,
551 strlen(widget_data
->cdata
) - widget_data
->info
.field
.cpos
+ 1);
552 widget_data
->info
.field
.cpos
--;
556 case ACT_EDIT_DELETE
:
558 int cdata_len
= strlen(widget_data
->cdata
);
560 if (widget_data
->info
.field
.cpos
>= cdata_len
) goto display_field
;
564 unsigned char *end
= widget_data
->cdata
+ cdata_len
;
565 unsigned char *text
= widget_data
->cdata
+ widget_data
->info
.field
.cpos
;
566 unsigned char *old
= text
;
568 utf8_to_unicode(&text
, end
);
571 (int)(end
- text
) + 1);
575 #endif /* CONFIG_UTF8 */
576 memmove(widget_data
->cdata
+ widget_data
->info
.field
.cpos
,
577 widget_data
->cdata
+ widget_data
->info
.field
.cpos
+ 1,
578 cdata_len
- widget_data
->info
.field
.cpos
+ 1);
582 case ACT_EDIT_KILL_TO_BOL
:
583 memmove(widget_data
->cdata
,
584 widget_data
->cdata
+ widget_data
->info
.field
.cpos
,
585 strlen(widget_data
->cdata
+ widget_data
->info
.field
.cpos
) + 1);
586 widget_data
->info
.field
.cpos
= 0;
589 case ACT_EDIT_KILL_TO_EOL
:
590 widget_data
->cdata
[widget_data
->info
.field
.cpos
] = 0;
593 case ACT_EDIT_KILL_WORD_BACK
:
595 int cdata_len
= strlen(widget_data
->cdata
);
596 int start
= widget_data
->info
.field
.cpos
;
598 while (start
> 0 && isspace(widget_data
->cdata
[start
- 1]))
600 while (start
> 0 && !isspace(widget_data
->cdata
[start
- 1]))
603 memmove(widget_data
->cdata
+ start
,
604 widget_data
->cdata
+ widget_data
->info
.field
.cpos
,
605 cdata_len
- widget_data
->info
.field
.cpos
+ 1);
607 widget_data
->info
.field
.cpos
= start
;
612 case ACT_EDIT_MOVE_BACKWARD_WORD
:
613 while (widget_data
->info
.field
.cpos
> 0 && isspace(widget_data
->cdata
[widget_data
->info
.field
.cpos
- 1]))
614 --widget_data
->info
.field
.cpos
;
615 while (widget_data
->info
.field
.cpos
> 0 && !isspace(widget_data
->cdata
[widget_data
->info
.field
.cpos
- 1]))
616 --widget_data
->info
.field
.cpos
;
620 case ACT_EDIT_MOVE_FORWARD_WORD
:
621 while (isspace(widget_data
->cdata
[widget_data
->info
.field
.cpos
]))
622 ++widget_data
->info
.field
.cpos
;
623 while (widget_data
->cdata
[widget_data
->info
.field
.cpos
] && !isspace(widget_data
->cdata
[widget_data
->info
.field
.cpos
]))
624 ++widget_data
->info
.field
.cpos
;
625 while (isspace(widget_data
->cdata
[widget_data
->info
.field
.cpos
]))
626 ++widget_data
->info
.field
.cpos
;
630 case ACT_EDIT_COPY_CLIPBOARD
:
631 /* Copy to clipboard */
632 set_clipboard_text(widget_data
->cdata
);
633 return EVENT_PROCESSED
;
635 case ACT_EDIT_CUT_CLIPBOARD
:
636 /* Cut to clipboard */
637 set_clipboard_text(widget_data
->cdata
);
638 widget_data
->cdata
[0] = 0;
639 widget_data
->info
.field
.cpos
= 0;
642 case ACT_EDIT_PASTE_CLIPBOARD
:
644 /* Paste from clipboard */
645 unsigned char *clipboard
= get_clipboard_text();
647 if (!clipboard
) goto display_field
;
649 safe_strncpy(widget_data
->cdata
, clipboard
, widget_data
->widget
->datalen
);
650 widget_data
->info
.field
.cpos
= strlen(widget_data
->cdata
);
655 case ACT_EDIT_AUTO_COMPLETE
:
656 if (!widget_has_history(widget_data
))
657 return EVENT_NOT_PROCESSED
;
659 do_tab_compl(dlg_data
, &widget_data
->info
.field
.history
);
662 case ACT_EDIT_AUTO_COMPLETE_FILE
:
663 if (!widget_has_history(widget_data
))
664 return EVENT_NOT_PROCESSED
;
666 do_tab_compl_file(dlg_data
, &widget_data
->info
.field
.history
);
669 case ACT_EDIT_AUTO_COMPLETE_UNAMBIGUOUS
:
670 if (!widget_has_history(widget_data
))
671 return EVENT_NOT_PROCESSED
;
673 do_tab_compl_unambiguous(dlg_data
, &widget_data
->info
.field
.history
);
676 case ACT_EDIT_REDRAW
:
677 redraw_terminal_cls(term
);
678 return EVENT_PROCESSED
;
681 if (check_kbd_textinput_key(ev
)) {
682 unsigned char *text
= widget_data
->cdata
;
683 int textlen
= strlen(text
);
685 /* Both get_kbd_key(ev) and @text
686 * are in the terminal's charset. */
687 const int inslen
= 1;
688 #else /* CONFIG_UTF8 */
689 const unsigned char *ins
;
692 /* get_kbd_key(ev) is UCS-4, and @text
693 * is in the terminal's charset. */
694 ins
= u2cp_no_nbsp(get_kbd_key(ev
),
695 get_terminal_codepage(term
));
696 inslen
= strlen(ins
);
697 #endif /* CONFIG_UTF8 */
699 if (textlen
>= widget_data
->widget
->datalen
- inslen
)
702 /* Shift to position of the cursor */
703 textlen
-= widget_data
->info
.field
.cpos
;
704 text
+= widget_data
->info
.field
.cpos
;
706 memmove(text
+ inslen
, text
, textlen
+ 1);
708 memcpy(text
, ins
, inslen
);
709 #else /* !CONFIG_UTF8 */
710 *text
= get_kbd_key(ev
);
711 #endif /* !CONFIG_UTF8 */
712 widget_data
->info
.field
.cpos
+= inslen
;
716 return EVENT_NOT_PROCESSED
;
719 display_widget(dlg_data
, widget_data
);
720 redraw_windows(REDRAW_IN_FRONT_OF_WINDOW
, dlg_data
->win
);
721 return EVENT_PROCESSED
;
725 static widget_handler_status_T
726 clear_field(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
728 widget_data
->info
.field
.cpos
= 0;
730 if (widget_data
->widget
->datalen
)
731 memset(widget_data
->cdata
, 0, widget_data
->widget
->datalen
);
733 return EVENT_PROCESSED
;
736 const struct widget_ops field_ops
= {
745 const struct widget_ops field_pass_ops
= {
758 input_line_layouter(struct dialog_data
*dlg_data
)
760 struct input_line
*input_line
= dlg_data
->dlg
->udata
;
761 struct session
*ses
= input_line
->ses
;
762 struct window
*win
= dlg_data
->win
;
763 int y
= win
->term
->height
- 1
764 - ses
->status
.show_status_bar
765 - ses
->status
.show_tabs_bar
;
767 dlg_format_field(dlg_data
, dlg_data
->widgets_data
, 0,
768 &y
, win
->term
->width
, NULL
, ALIGN_LEFT
, 0);
771 static widget_handler_status_T
772 input_line_event_handler(struct dialog_data
*dlg_data
)
774 struct input_line
*input_line
= dlg_data
->dlg
->udata
;
775 input_line_handler_T handler
= input_line
->handler
;
776 enum edit_action action_id
;
777 struct widget_data
*widget_data
= dlg_data
->widgets_data
;
778 struct term_event
*ev
= dlg_data
->term_event
;
783 action_id
= kbd_action(KEYMAP_EDIT
, ev
, NULL
);
785 /* Handle some basic actions such as quiting for empty buffers */
788 case ACT_EDIT_NEXT_ITEM
:
789 case ACT_EDIT_PREVIOUS_ITEM
:
790 if (widget_has_history(widget_data
))
791 add_to_input_history(widget_data
->widget
->info
.field
.history
,
792 input_line
->buffer
, 1);
795 case ACT_EDIT_BACKSPACE
:
796 if (!*input_line
->buffer
)
797 goto cancel_input_line
;
800 case ACT_EDIT_CANCEL
:
801 goto cancel_input_line
;
807 /* First let the input field do its business */
808 kbd_field(dlg_data
, widget_data
);
813 if (ev
->info
.mouse
.y
!= dlg_data
->win
->y
) {
814 delete_window_ev(dlg_data
->win
, ev
);
815 return EVENT_PROCESSED
;
817 #endif /* CONFIG_MOUSE */
818 return EVENT_NOT_PROCESSED
;
821 /* Try to catch the redraw event initiated by the history
822 * completion and only respond if something was actually
823 * updated. Meaning we have new data in the line buffer that
824 * should be propagated to the line handler. */
825 if (!widget_has_history(widget_data
)
826 || widget_data
->info
.field
.cpos
<= 0
827 || widget_data
->info
.field
.cpos
<= strlen(input_line
->buffer
))
828 return EVENT_NOT_PROCESSED
;
833 action_id
= ACT_EDIT_REDRAW
;
837 return EVENT_NOT_PROCESSED
;
840 update_dialog_data(dlg_data
);
842 send_action_to_handler
:
843 /* Then pass it on to the specialized handler */
844 switch (handler(input_line
, action_id
)) {
845 case INPUT_LINE_CANCEL
:
847 cancel_dialog(dlg_data
, widget_data
);
850 case INPUT_LINE_REWIND
:
851 /* This is stolen kbd_field() handling for ACT_EDIT_BACKSPACE */
852 memmove(widget_data
->cdata
+ widget_data
->info
.field
.cpos
- 1,
853 widget_data
->cdata
+ widget_data
->info
.field
.cpos
,
854 strlen(widget_data
->cdata
) - widget_data
->info
.field
.cpos
+ 1);
855 widget_data
->info
.field
.cpos
--;
857 update_dialog_data(dlg_data
);
859 /* Set action_id to -2 to signal to the handler that it should
860 * not report errors or take any action except to search. */
862 goto send_action_to_handler
;
864 case INPUT_LINE_PROCEED
:
868 /* Hack: We want our caller to perform its redrawing routine,
869 * even if we did process the event here. */
870 if (action_id
== ACT_EDIT_REDRAW
) return EVENT_NOT_PROCESSED
;
872 /* Completely bypass any further dialog event handling */
873 return EVENT_PROCESSED
;
877 input_field_line(struct session
*ses
, unsigned char *prompt
, void *data
,
878 struct input_history
*history
, input_line_handler_T handler
)
881 unsigned char *buffer
;
882 struct input_line
*input_line
;
886 dlg
= calloc_dialog(INPUT_LINE_WIDGETS
, sizeof(*input_line
));
889 input_line
= (void *) get_dialog_offset(dlg
, INPUT_LINE_WIDGETS
);
890 input_line
->ses
= ses
;
891 input_line
->data
= data
;
892 input_line
->handler
= handler
;
893 buffer
= input_line
->buffer
;
895 dlg
->handle_event
= input_line_event_handler
;
896 dlg
->layouter
= input_line_layouter
;
897 dlg
->layout
.only_widgets
= 1;
898 dlg
->udata
= input_line
;
900 add_dlg_field_float2(dlg
, prompt
, 0, 0, NULL
, INPUT_LINE_BUFFER_SIZE
,
903 do_dialog(ses
->tab
->term
, dlg
, getml(dlg
, (void *) NULL
));