2 Widgets for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2009, 2010, 2011
6 The Free Software Foundation, Inc.
9 Radek Doulik, 1994, 1995
10 Miguel de Icaza, 1994, 1995
12 Andrej Borsenkow, 1996
14 Andrew Borodin <aborodin@vmail.ru>, 2009, 2010
16 This file is part of the Midnight Commander.
18 The Midnight Commander is free software: you can redistribute it
19 and/or modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation, either version 3 of the License,
21 or (at your option) any later version.
23 The Midnight Commander is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 * \brief Source: WInput widget
39 #include <sys/types.h>
43 #include "lib/global.h"
45 #include "lib/tty/tty.h"
46 #include "lib/tty/mouse.h"
47 #include "lib/tty/key.h" /* XCTRL and ALT macros */
48 #include "lib/fileloc.h"
50 #include "lib/strutil.h"
52 #include "lib/keybind.h" /* global_keymap_t */
53 #include "lib/widget.h"
54 #include "lib/event.h" /* mc_event_raise() */
56 #include "input_complete.h"
58 /*** global variables ****************************************************************************/
62 const global_keymap_t
*input_map
= NULL
;
64 /*** file scope macro definitions ****************************************************************/
66 #define LARGE_HISTORY_BUTTON 1
68 #ifdef LARGE_HISTORY_BUTTON
69 #define HISTORY_BUTTON_WIDTH 3
71 #define HISTORY_BUTTON_WIDTH 1
74 #define should_show_history_button(in) \
75 (in->history != NULL && in->field_width > HISTORY_BUTTON_WIDTH * 2 + 1 \
76 && WIDGET (in)->owner != NULL)
78 /*** file scope type declarations ****************************************************************/
80 /*** file scope variables ************************************************************************/
82 /* Input widgets have a global kill ring */
83 /* Pointer to killed data */
84 static char *kill_buffer
= NULL
;
86 /*** file scope functions ************************************************************************/
87 /* --------------------------------------------------------------------------------------------- */
90 get_history_length (const GList
* history
)
94 for (; history
!= NULL
; history
= g_list_previous (history
))
100 /* --------------------------------------------------------------------------------------------- */
103 draw_history_button (WInput
* in
)
106 gboolean disabled
= (WIDGET (in
)->options
& W_DISABLED
) != 0;
108 if (g_list_next (in
->history_current
) == NULL
)
110 else if (g_list_previous (in
->history_current
) == NULL
)
115 widget_move (in
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
);
116 tty_setcolor (disabled
? DISABLED_COLOR
: in
->color
[WINPUTC_HISTORY
]);
118 #ifdef LARGE_HISTORY_BUTTON
119 tty_print_string ("[ ]");
120 widget_move (in
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1);
126 /* --------------------------------------------------------------------------------------------- */
129 input_set_markers (WInput
* in
, long m1
)
134 /* --------------------------------------------------------------------------------------------- */
137 input_mark_cmd (WInput
* in
, gboolean mark
)
141 in
->highlight
= FALSE
;
142 input_set_markers (in
, 0);
146 in
->highlight
= TRUE
;
147 input_set_markers (in
, in
->point
);
151 /* --------------------------------------------------------------------------------------------- */
154 input_eval_marks (WInput
* in
, long *start_mark
, long *end_mark
)
158 *start_mark
= min (in
->mark
, in
->point
);
159 *end_mark
= max (in
->mark
, in
->point
);
164 *start_mark
= *end_mark
= 0;
169 /* --------------------------------------------------------------------------------------------- */
172 delete_region (WInput
* in
, int x_first
, int x_last
)
174 int first
= min (x_first
, x_last
);
175 int last
= max (x_first
, x_last
);
178 input_mark_cmd (in
, FALSE
);
180 last
= str_offset_to_pos (in
->buffer
, last
);
181 first
= str_offset_to_pos (in
->buffer
, first
);
182 len
= strlen (&in
->buffer
[last
]) + 1;
183 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
185 in
->need_push
= TRUE
;
188 /* --------------------------------------------------------------------------------------------- */
191 do_show_hist (WInput
* in
)
196 len
= get_history_length (in
->history
);
198 r
= history_show (&in
->history
, WIDGET (in
),
199 g_list_position (in
->history_current
, in
->history
));
202 input_assign_text (in
, r
);
206 /* Has history cleaned up or not? */
207 if (len
!= get_history_length (in
->history
))
208 in
->history_changed
= TRUE
;
211 /* --------------------------------------------------------------------------------------------- */
213 * Strip password from incomplete url (just user:pass@host without VFS prefix).
215 * @param url partial URL
216 * @return newly allocated string without password
220 input_history_strip_password (char *url
)
222 char *at
, *delim
, *colon
;
224 at
= strrchr (url
, '@');
226 return g_strdup (url
);
228 /* TODO: handle ':' and '@' in password */
230 delim
= strstr (url
, VFS_PATH_URL_DELIMITER
);
232 colon
= strchr (delim
+ strlen (VFS_PATH_URL_DELIMITER
), ':');
234 colon
= strchr (url
, ':');
236 /* if 'colon' before 'at', 'colon' delimits user and password: user:password@host */
237 /* if 'colon' after 'at', 'colon' delimits host and port: user@host:port */
238 if (colon
!= NULL
&& colon
> at
)
242 return g_strdup (url
);
245 return g_strconcat (url
, at
, NULL
);
248 /* --------------------------------------------------------------------------------------------- */
251 push_history (WInput
* in
, const char *text
)
259 t
= g_strstrip (g_strdup (text
));
262 t
= g_strdup (empty
? "" : text
);
264 if (!empty
&& in
->history_name
!= NULL
&& in
->strip_password
)
267 We got string user:pass@host without any VFS prefixes
268 and vfs_path_to_str_flags (t, VPF_STRIP_PASSWORD) doesn't work.
269 Therefore we want to strip password in separate algorithm
271 char *url_with_stripped_password
;
273 url_with_stripped_password
= input_history_strip_password (t
);
275 t
= url_with_stripped_password
;
278 if (in
->history
== NULL
|| in
->history
->data
== NULL
|| strcmp (in
->history
->data
, t
) != 0 ||
281 in
->history
= list_append_unique (in
->history
, t
);
282 in
->history_current
= in
->history
;
283 in
->history_changed
= TRUE
;
288 in
->need_push
= FALSE
;
291 /* --------------------------------------------------------------------------------------------- */
294 move_buffer_backward (WInput
* in
, int start
, int end
)
299 str_len
= str_length (in
->buffer
);
300 if (start
>= str_len
|| end
> str_len
+ 1)
303 pos
= str_offset_to_pos (in
->buffer
, start
);
304 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
306 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
307 in
->buffer
[i
] = in
->buffer
[i
+ len
];
310 /* --------------------------------------------------------------------------------------------- */
313 insert_char (WInput
* in
, int c_code
)
321 if (input_eval_marks (in
, &m1
, &m2
))
322 delete_region (in
, m1
, m2
);
325 return MSG_NOT_HANDLED
;
327 if (in
->charpoint
>= MB_LEN_MAX
)
330 in
->charbuf
[in
->charpoint
] = c_code
;
333 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
337 in
->charpoint
= 0; /* broken multibyte char, skip */
341 in
->need_push
= TRUE
;
342 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
)
344 /* Expand the buffer */
345 size_t new_length
= in
->current_max_size
+ in
->field_width
+ in
->charpoint
;
346 char *narea
= g_try_renew (char, in
->buffer
, new_length
);
350 in
->current_max_size
= new_length
;
354 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
)
356 /* bytes from begin */
357 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
359 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
361 for (i
= rest_bytes
+ 1; i
> 0; i
--)
362 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] = in
->buffer
[ins_point
+ i
- 1];
364 memcpy (in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
372 /* --------------------------------------------------------------------------------------------- */
375 beginning_of_line (WInput
* in
)
381 /* --------------------------------------------------------------------------------------------- */
384 end_of_line (WInput
* in
)
386 in
->point
= str_length (in
->buffer
);
390 /* --------------------------------------------------------------------------------------------- */
393 backward_char (WInput
* in
)
397 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
399 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
403 /* --------------------------------------------------------------------------------------------- */
406 forward_char (WInput
* in
)
410 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
412 in
->point
+= str_cnext_noncomb_char (&act
);
416 /* --------------------------------------------------------------------------------------------- */
419 forward_word (WInput
* in
)
423 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
424 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
)))
429 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
))
436 /* --------------------------------------------------------------------------------------------- */
439 backward_word (WInput
* in
)
441 const char *p
, *p_tmp
;
443 for (p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
444 (p
!= in
->buffer
) && (p
[0] == '\0'); str_cprev_char (&p
), in
->point
--);
446 while (p
!= in
->buffer
)
450 if (!str_isspace (p
) && !str_ispunct (p
))
457 while (p
!= in
->buffer
)
460 if (str_isspace (p
) || str_ispunct (p
))
467 /* --------------------------------------------------------------------------------------------- */
470 backward_delete (WInput
* in
)
472 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
478 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
479 move_buffer_backward (in
, start
, in
->point
);
481 in
->need_push
= TRUE
;
485 /* --------------------------------------------------------------------------------------------- */
488 delete_char (WInput
* in
)
493 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
494 end
+= str_cnext_noncomb_char (&act
);
496 move_buffer_backward (in
, in
->point
, end
);
498 in
->need_push
= TRUE
;
501 /* --------------------------------------------------------------------------------------------- */
504 copy_region (WInput
* in
, int x_first
, int x_last
)
506 int first
= min (x_first
, x_last
);
507 int last
= max (x_first
, x_last
);
511 /* Copy selected files to clipboard */
512 mc_event_raise (MCEVENT_GROUP_FILEMANAGER
, "panel_save_curent_file_to_clip_file", NULL
);
513 /* try use external clipboard utility */
514 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
518 g_free (kill_buffer
);
520 first
= str_offset_to_pos (in
->buffer
, first
);
521 last
= str_offset_to_pos (in
->buffer
, last
);
523 kill_buffer
= g_strndup (in
->buffer
+ first
, last
- first
);
525 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_to_file", kill_buffer
);
526 /* try use external clipboard utility */
527 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
530 /* --------------------------------------------------------------------------------------------- */
533 kill_word (WInput
* in
)
535 int old_point
= in
->point
;
539 new_point
= in
->point
;
540 in
->point
= old_point
;
542 delete_region (in
, old_point
, new_point
);
543 in
->need_push
= TRUE
;
547 /* --------------------------------------------------------------------------------------------- */
550 back_kill_word (WInput
* in
)
552 int old_point
= in
->point
;
556 new_point
= in
->point
;
557 in
->point
= old_point
;
559 delete_region (in
, old_point
, new_point
);
560 in
->need_push
= TRUE
;
563 /* --------------------------------------------------------------------------------------------- */
568 if (kill_buffer
!= NULL
)
573 for (p
= kill_buffer
; *p
!= '\0'; p
++)
574 insert_char (in
, *p
);
579 /* --------------------------------------------------------------------------------------------- */
582 kill_line (WInput
* in
)
586 chp
= str_offset_to_pos (in
->buffer
, in
->point
);
587 g_free (kill_buffer
);
588 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
589 in
->buffer
[chp
] = '\0';
593 /* --------------------------------------------------------------------------------------------- */
596 clear_line (WInput
* in
)
598 in
->need_push
= TRUE
;
599 in
->buffer
[0] = '\0';
602 in
->highlight
= FALSE
;
606 /* --------------------------------------------------------------------------------------------- */
609 ins_from_clip (WInput
* in
)
612 ev_clipboard_text_from_file_t event_data
;
614 /* try use external clipboard utility */
615 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_from_ext_clip", NULL
);
617 event_data
.text
= &p
;
618 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_from_file", &event_data
);
623 for (pp
= p
; *pp
!= '\0'; pp
++)
624 insert_char (in
, *pp
);
630 /* --------------------------------------------------------------------------------------------- */
633 hist_prev (WInput
* in
)
637 if (in
->history
== NULL
)
641 push_history (in
, in
->buffer
);
643 prev
= g_list_previous (in
->history_current
);
646 input_assign_text (in
, (char *) prev
->data
);
647 in
->history_current
= prev
;
648 in
->history_changed
= TRUE
;
649 in
->need_push
= FALSE
;
653 /* --------------------------------------------------------------------------------------------- */
656 hist_next (WInput
* in
)
662 push_history (in
, in
->buffer
);
663 input_assign_text (in
, "");
667 if (in
->history
== NULL
)
670 next
= g_list_next (in
->history_current
);
673 input_assign_text (in
, "");
674 in
->history_current
= in
->history
;
678 input_assign_text (in
, (char *) next
->data
);
679 in
->history_current
= next
;
680 in
->history_changed
= TRUE
;
681 in
->need_push
= FALSE
;
685 /* --------------------------------------------------------------------------------------------- */
688 port_region_marked_for_delete (WInput
* in
)
690 in
->buffer
[0] = '\0';
696 /* --------------------------------------------------------------------------------------------- */
699 input_execute_cmd (WInput
* in
, unsigned long command
)
701 cb_ret_t res
= MSG_HANDLED
;
703 /* a highlight command like shift-arrow */
704 if (command
== CK_MarkLeft
|| command
== CK_MarkRight
||
705 command
== CK_MarkToWordBegin
|| command
== CK_MarkToWordEnd
||
706 command
== CK_MarkToHome
|| command
== CK_MarkToEnd
)
710 input_mark_cmd (in
, FALSE
); /* clear */
711 input_mark_cmd (in
, TRUE
); /* marking on */
722 input_mark_cmd (in
, FALSE
);
729 beginning_of_line (in
);
740 case CK_MarkToWordBegin
:
748 case CK_MarkToWordEnd
:
755 if (input_eval_marks (in
, &m1
, &m2
))
756 delete_region (in
, m1
, m2
);
759 backward_delete (in
);
763 port_region_marked_for_delete (in
);
764 else if (in
->highlight
)
767 if (input_eval_marks (in
, &m1
, &m2
))
768 delete_region (in
, m1
, m2
);
773 case CK_DeleteToWordEnd
:
776 case CK_DeleteToWordBegin
:
780 input_mark_cmd (in
, TRUE
);
783 delete_region (in
, in
->point
, in
->mark
);
792 copy_region (in
, in
->mark
, in
->point
);
795 copy_region (in
, in
->mark
, in
->point
);
796 delete_region (in
, in
->point
, in
->mark
);
817 res
= MSG_NOT_HANDLED
;
820 if (command
!= CK_MarkLeft
&& command
!= CK_MarkRight
&&
821 command
!= CK_MarkToWordBegin
&& command
!= CK_MarkToWordEnd
&&
822 command
!= CK_MarkToHome
&& command
!= CK_MarkToEnd
)
823 in
->highlight
= FALSE
;
828 /* --------------------------------------------------------------------------------------------- */
830 /* "history_load" event handler */
832 input_load_history (const gchar
* event_group_name
, const gchar
* event_name
,
833 gpointer init_data
, gpointer data
)
835 WInput
*in
= INPUT (init_data
);
836 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
837 const char *def_text
;
840 (void) event_group_name
;
843 in
->history
= history_load (ev
->cfg
, in
->history_name
);
844 in
->history_current
= in
->history
;
846 if (in
->init_text
== NULL
)
848 else if (in
->init_text
== INPUT_LAST_TEXT
)
850 if (in
->history
!= NULL
&& in
->history
->data
!= NULL
)
851 def_text
= (const char *) in
->history
->data
;
855 in
->init_text
= NULL
;
858 def_text
= in
->init_text
;
860 buffer_len
= strlen (def_text
);
861 buffer_len
= 1 + max ((size_t) in
->field_width
, buffer_len
);
862 in
->current_max_size
= buffer_len
;
863 if (buffer_len
> (size_t) in
->field_width
)
864 in
->buffer
= g_realloc (in
->buffer
, buffer_len
);
865 strcpy (in
->buffer
, def_text
);
866 in
->point
= str_length (in
->buffer
);
871 /* --------------------------------------------------------------------------------------------- */
873 /* "history_save" event handler */
875 input_save_history (const gchar
* event_group_name
, const gchar
* event_name
,
876 gpointer init_data
, gpointer data
)
878 WInput
*in
= INPUT (init_data
);
880 (void) event_group_name
;
883 if (!in
->is_password
&& (WIDGET (in
)->owner
->ret_value
!= B_CANCEL
))
885 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
887 push_history (in
, in
->buffer
);
888 if (in
->history_changed
)
889 history_save (ev
->cfg
, in
->history_name
, in
->history
);
890 in
->history_changed
= FALSE
;
896 /* --------------------------------------------------------------------------------------------- */
899 input_destroy (WInput
* in
)
903 fprintf (stderr
, "Internal error: null Input *\n");
907 input_free_completions (in
);
910 if (in
->history
!= NULL
)
912 /* history is already saved before this moment */
913 in
->history
= g_list_first (in
->history
);
914 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
915 g_list_free (in
->history
);
917 g_free (in
->history_name
);
920 input_free_completions (in
);
921 g_free (in
->init_text
);
923 g_free (kill_buffer
);
927 /* --------------------------------------------------------------------------------------------- */
930 input_event (Gpm_Event
* event
, void *data
)
932 WInput
*in
= INPUT (data
);
933 Widget
*w
= WIDGET (data
);
935 if (!mouse_global_in_widget (event
, w
))
936 return MOU_UNHANDLED
;
938 if ((event
->type
& GPM_DOWN
) != 0)
941 input_mark_cmd (in
, FALSE
);
944 if ((event
->type
& (GPM_DOWN
| GPM_DRAG
)) != 0)
948 local
= mouse_get_local (event
, w
);
950 dlg_select_widget (w
);
952 if (local
.x
>= in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1
953 && should_show_history_button (in
))
957 in
->point
= str_length (in
->buffer
);
958 if (local
.x
+ in
->term_first_shown
- 1 < str_term_width1 (in
->buffer
))
959 in
->point
= str_column_to_pos (in
->buffer
, local
.x
+ in
->term_first_shown
- 1);
962 input_update (in
, TRUE
);
965 /* A lone up mustn't do anything */
966 if (in
->highlight
&& (event
->type
& (GPM_UP
| GPM_DRAG
)) != 0)
969 if ((event
->type
& GPM_DRAG
) == 0)
970 input_mark_cmd (in
, TRUE
);
975 /* --------------------------------------------------------------------------------------------- */
978 * Callback for applying new options to input widget.
981 * @param options options set
982 * @param enable TRUE if specified options should be added, FALSE if options should be removed
985 input_set_options_callback (Widget
* w
, widget_options_t options
, gboolean enable
)
987 WInput
*in
= INPUT (w
);
989 widget_default_set_options_callback (w
, options
, enable
);
990 if (in
->label
!= NULL
)
991 widget_set_options (WIDGET (in
->label
), options
, enable
);
994 /* --------------------------------------------------------------------------------------------- */
995 /*** public functions ****************************************************************************/
996 /* --------------------------------------------------------------------------------------------- */
998 /** Create new instance of WInput object.
999 * @param y Y coordinate
1000 * @param x X coordinate
1001 * @param input_colors Array of used colors
1002 * @param width Widget width
1003 * @param def_text Default text filled in widget
1004 * @param histname Name of history
1005 * @param completion_flags Flags for specify type of completions
1006 * @return WInput object
1009 input_new (int y
, int x
, const int *input_colors
, int width
, const char *def_text
,
1010 const char *histname
, input_complete_t completion_flags
)
1015 in
= g_new (WInput
, 1);
1017 init_widget (w
, y
, x
, 1, width
, input_callback
, input_event
);
1018 w
->options
|= W_IS_INPUT
;
1019 w
->set_options
= input_set_options_callback
;
1021 memmove (in
->color
, input_colors
, sizeof (input_colors_t
));
1023 in
->field_width
= width
;
1025 in
->highlight
= FALSE
;
1026 in
->term_first_shown
= 0;
1027 in
->disable_update
= 0;
1029 in
->need_push
= TRUE
;
1030 in
->is_password
= FALSE
;
1032 in
->strip_password
= FALSE
;
1034 /* in->buffer will be corrected in "history_load" event handler */
1035 in
->current_max_size
= width
+ 1;
1036 in
->buffer
= g_new0 (char, in
->current_max_size
);
1039 in
->init_text
= (def_text
== INPUT_LAST_TEXT
) ? INPUT_LAST_TEXT
: g_strdup (def_text
);
1041 in
->completions
= NULL
;
1042 in
->completion_flags
= completion_flags
;
1044 /* prepare to history setup */
1046 in
->history_current
= NULL
;
1047 in
->history_changed
= FALSE
;
1048 in
->history_name
= NULL
;
1049 if ((histname
!= NULL
) && (*histname
!= '\0'))
1050 in
->history_name
= g_strdup (histname
);
1051 /* history will be loaded later */
1058 /* --------------------------------------------------------------------------------------------- */
1061 input_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1063 WInput
*in
= INPUT (w
);
1069 /* subscribe to "history_load" event */
1070 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
, NULL
);
1071 /* subscribe to "history_save" event */
1072 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
, NULL
);
1076 if (parm
== XCTRL ('q'))
1079 v
= input_handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1084 /* Keys we want others to handle */
1085 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1086 || parm
== KEY_F (10) || parm
== '\n')
1087 return MSG_NOT_HANDLED
;
1089 /* When pasting multiline text, insert literal Enter */
1090 if ((parm
& ~KEY_M_MASK
) == '\n')
1093 v
= input_handle_char (in
, '\n');
1098 return input_handle_char (in
, parm
);
1101 return input_execute_cmd (in
, parm
);
1107 input_update (in
, FALSE
);
1111 widget_move (in
, 0, str_term_width2 (in
->buffer
, in
->point
) - in
->term_first_shown
);
1115 /* unsubscribe from "history_load" event */
1116 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
);
1117 /* unsubscribe from "history_save" event */
1118 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
);
1123 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1127 /* --------------------------------------------------------------------------------------------- */
1129 /** Get default colors for WInput widget.
1130 * @return default colors
1133 input_get_default_colors (void)
1135 static input_colors_t standart_colors
;
1137 standart_colors
[WINPUTC_MAIN
] = INPUT_COLOR
;
1138 standart_colors
[WINPUTC_MARK
] = INPUT_MARK_COLOR
;
1139 standart_colors
[WINPUTC_UNCHANGED
] = INPUT_UNCHANGED_COLOR
;
1140 standart_colors
[WINPUTC_HISTORY
] = INPUT_HISTORY_COLOR
;
1142 return standart_colors
;
1145 /* --------------------------------------------------------------------------------------------- */
1148 input_set_origin (WInput
* in
, int x
, int field_width
)
1151 in
->field_width
= WIDGET (in
)->cols
= field_width
;
1152 input_update (in
, FALSE
);
1155 /* --------------------------------------------------------------------------------------------- */
1158 input_handle_char (WInput
* in
, int key
)
1161 unsigned long command
;
1165 input_free_completions (in
);
1166 v
= insert_char (in
, key
);
1167 input_update (in
, TRUE
);
1172 command
= keybind_lookup_keymap_command (input_map
, key
);
1174 if (command
== CK_IgnoreKey
)
1177 return MSG_NOT_HANDLED
;
1179 port_region_marked_for_delete (in
);
1180 input_free_completions (in
);
1181 v
= insert_char (in
, key
);
1185 if (command
!= CK_Complete
)
1186 input_free_completions (in
);
1187 input_execute_cmd (in
, command
);
1190 input_update (in
, TRUE
); /* needed to clear in->first */
1193 input_update (in
, TRUE
);
1197 /* --------------------------------------------------------------------------------------------- */
1199 /* This function is a test for a special input key used in complete.c */
1200 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1201 and 2 if it is a complete key */
1203 input_key_is_in_map (WInput
* in
, int key
)
1205 unsigned long command
;
1209 command
= keybind_lookup_keymap_command (input_map
, key
);
1210 if (command
== CK_IgnoreKey
)
1213 return (command
== CK_Complete
) ? 2 : 1;
1216 /* --------------------------------------------------------------------------------------------- */
1219 input_assign_text (WInput
* in
, const char *text
)
1221 input_free_completions (in
);
1222 g_free (in
->buffer
);
1223 in
->current_max_size
= strlen (text
) + 1;
1224 in
->buffer
= g_strndup (text
, in
->current_max_size
); /* was in->buffer->text */
1225 in
->point
= str_length (in
->buffer
);
1227 in
->need_push
= TRUE
;
1229 input_update (in
, TRUE
);
1232 /* --------------------------------------------------------------------------------------------- */
1234 /* Inserts text in input line */
1236 input_insert (WInput
* in
, const char *text
, gboolean insert_extra_space
)
1238 input_disable_update (in
);
1239 while (*text
!= '\0')
1240 input_handle_char (in
, (unsigned char) *text
++); /* unsigned extension char->int */
1241 if (insert_extra_space
)
1242 input_handle_char (in
, ' ');
1243 input_enable_update (in
);
1244 input_update (in
, TRUE
);
1247 /* --------------------------------------------------------------------------------------------- */
1250 input_set_point (WInput
* in
, int pos
)
1254 max_pos
= str_length (in
->buffer
);
1255 pos
= min (pos
, max_pos
);
1256 if (pos
!= in
->point
)
1257 input_free_completions (in
);
1260 input_update (in
, TRUE
);
1263 /* --------------------------------------------------------------------------------------------- */
1266 input_update (WInput
* in
, gboolean clear_first
)
1268 int has_history
= 0;
1274 if (should_show_history_button (in
))
1275 has_history
= HISTORY_BUTTON_WIDTH
;
1277 if (in
->disable_update
!= 0)
1280 buf_len
= str_length (in
->buffer
);
1281 pw
= str_term_width2 (in
->buffer
, in
->point
);
1283 /* Make the point visible */
1284 if ((pw
< in
->term_first_shown
) || (pw
>= in
->term_first_shown
+ in
->field_width
- has_history
))
1286 in
->term_first_shown
= pw
- (in
->field_width
/ 3);
1287 if (in
->term_first_shown
< 0)
1288 in
->term_first_shown
= 0;
1291 /* Adjust the mark */
1292 in
->mark
= min (in
->mark
, buf_len
);
1294 /* don't draw widget not put into dialog */
1295 if (WIDGET (in
)->owner
== NULL
)
1298 if (has_history
!= 0)
1299 draw_history_button (in
);
1301 if ((WIDGET (in
)->options
& W_DISABLED
) != 0)
1302 tty_setcolor (DISABLED_COLOR
);
1304 tty_setcolor (in
->color
[WINPUTC_UNCHANGED
]);
1306 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1308 widget_move (in
, 0, 0);
1310 if (!in
->is_password
)
1313 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
1314 in
->field_width
- has_history
));
1319 if (input_eval_marks (in
, &m1
, &m2
))
1321 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1322 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
,
1323 in
->field_width
- has_history
);
1324 tty_print_string (cp
);
1325 tty_setcolor (in
->color
[WINPUTC_MARK
]);
1326 if (m1
< in
->term_first_shown
)
1328 widget_move (in
, 0, 0);
1329 tty_print_string (str_term_substring
1330 (in
->buffer
, in
->term_first_shown
,
1331 m2
- in
->term_first_shown
));
1337 widget_move (in
, 0, m1
- in
->term_first_shown
);
1340 (in
->field_width
- has_history
) - (str_term_width2 (in
->buffer
, m1
) -
1341 in
->term_first_shown
));
1342 tty_print_string (str_term_substring (in
->buffer
, m1
, sel_width
));
1349 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, in
->field_width
- has_history
);
1350 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1351 for (i
= 0; i
< in
->field_width
- has_history
; i
++)
1353 if (i
< (buf_len
- in
->term_first_shown
) && cp
[0] != '\0')
1354 tty_print_char ('*');
1356 tty_print_char (' ');
1358 str_cnext_char (&cp
);
1366 /* --------------------------------------------------------------------------------------------- */
1369 input_enable_update (WInput
* in
)
1371 in
->disable_update
--;
1372 input_update (in
, FALSE
);
1375 /* --------------------------------------------------------------------------------------------- */
1378 input_disable_update (WInput
* in
)
1380 in
->disable_update
++;
1383 /* --------------------------------------------------------------------------------------------- */
1386 * Cleans the input line and adds the current text to the history
1388 * @param in the input line
1391 input_clean (WInput
* in
)
1393 push_history (in
, in
->buffer
);
1394 in
->need_push
= TRUE
;
1395 in
->buffer
[0] = '\0';
1399 in
->highlight
= FALSE
;
1400 input_free_completions (in
);
1401 input_update (in
, FALSE
);
1404 /* --------------------------------------------------------------------------------------------- */
1407 input_free_completions (WInput
* in
)
1409 g_strfreev (in
->completions
);
1410 in
->completions
= NULL
;
1413 /* --------------------------------------------------------------------------------------------- */