1 /* Widgets for the Midnight Commander
3 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
6 Authors: 1994, 1995 Radek Doulik
7 1994, 1995 Miguel de Icaza
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 * \brief Source: widgets
41 #include <sys/types.h>
45 #include "../src/tty/tty.h"
46 #include "../src/tty/color.h"
47 #include "../src/tty/mouse.h"
48 #include "../src/tty/key.h" /* XCTRL and ALT macros */
52 #include "../src/mcconfig/mcconfig.h" /* for history loading and saving */
53 #include "wtools.h" /* For common_dialog_repaint() */
56 #define HISTORY_FILE_NAME ".mc/history"
58 /* number of bttons in buttonbar */
59 #define BUTTONBAR_LABELS_NUM 10
63 int visible
; /* Is it visible? */
64 int btn_width
; /* width of one button */
67 enum { BBFUNC_NONE
, BBFUNC_VOID
, BBFUNC_PTR
} tag
;
73 } labels
[BUTTONBAR_LABELS_NUM
];
77 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
79 Dlg_head
*h
= w
->parent
;
84 : DLG_HOT_NORMALC (h
))
91 parse_hotkey (const char *text
)
93 struct hotkey_t result
;
96 /* search for '&', that is not on the of text */
97 cp
= strchr (text
, '&');
98 if (cp
!= NULL
&& cp
[1] != '\0') {
99 result
.start
= g_strndup (text
, cp
- text
);
103 p
= str_cget_next_char (cp
);
104 result
.hotkey
= g_strndup (cp
, p
- cp
);
107 result
.end
= g_strdup (cp
);
109 result
.start
= g_strdup (text
);
110 result
.hotkey
= NULL
;
117 release_hotkey (const struct hotkey_t hotkey
)
119 g_free (hotkey
.start
);
120 g_free (hotkey
.hotkey
);
125 hotkey_width (const struct hotkey_t hotkey
)
129 result
= str_term_width1 (hotkey
.start
);
130 result
+= (hotkey
.hotkey
!= NULL
) ? str_term_width1 (hotkey
.hotkey
) : 0;
131 result
+= (hotkey
.end
!= NULL
) ? str_term_width1 (hotkey
.end
) : 0;
136 draw_hotkey (Widget
*w
, const struct hotkey_t hotkey
, gboolean focused
)
138 widget_selectcolor (w
, focused
, FALSE
);
139 tty_print_string (hotkey
.start
);
141 if (hotkey
.hotkey
!= NULL
) {
142 widget_selectcolor (w
, focused
, TRUE
);
143 tty_print_string (hotkey
.hotkey
);
144 widget_selectcolor (w
, focused
, FALSE
);
147 if (hotkey
.end
!= NULL
)
148 tty_print_string (hotkey
.end
);
151 static int button_event (Gpm_Event
*event
, void *);
156 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
158 WButton
*b
= (WButton
*) w
;
161 Dlg_head
*h
= b
->widget
.parent
;
166 * Don't let the default button steal Enter from the current
167 * button. This is a workaround for the flawed event model
168 * when hotkeys are sent to all widgets before the key is
169 * handled by the current widget.
171 if (parm
== '\n' && h
->current
== &b
->widget
) {
172 button_callback (w
, WIDGET_KEY
, ' ');
176 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
177 button_callback (w
, WIDGET_KEY
, ' ');
181 if (b
->text
.hotkey
!= NULL
) {
182 if (g_ascii_tolower ((gchar
)b
->text
.hotkey
[0]) ==
183 g_ascii_tolower ((gchar
)parm
)) {
184 button_callback (w
, WIDGET_KEY
, ' ');
188 return MSG_NOT_HANDLED
;
191 if (parm
!= ' ' && parm
!= '\n')
192 return MSG_NOT_HANDLED
;
195 stop
= (*b
->callback
) (b
->action
);
196 if (!b
->callback
|| stop
) {
197 h
->ret_value
= b
->action
;
218 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
224 if (msg
== WIDGET_UNFOCUS
)
226 else if (msg
== WIDGET_FOCUS
)
229 widget_selectcolor (w
, b
->selected
, FALSE
);
230 widget_move (w
, 0, 0);
234 tty_print_string ("[< ");
237 tty_print_string ("[ ");
240 tty_print_string ("[");
247 draw_hotkey (w
, b
->text
, b
->selected
);
251 tty_print_string (" >]");
254 tty_print_string (" ]");
257 tty_print_string ("]");
263 release_hotkey (b
->text
);
267 return default_proc (msg
, parm
);
272 button_event (Gpm_Event
*event
, void *data
)
276 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
277 Dlg_head
*h
=b
->widget
.parent
;
278 dlg_select_widget (b
);
279 if (event
->type
& GPM_UP
){
280 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
281 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
289 button_len (const struct hotkey_t text
, unsigned int flags
)
291 int ret
= hotkey_width (text
);
310 button_new (int y
, int x
, int action
, int flags
, const char *text
,
313 WButton
*b
= g_new (WButton
, 1);
315 b
->text
= parse_hotkey (text
);
317 init_widget (&b
->widget
, y
, x
, 1, button_len (b
->text
, flags
),
318 button_callback
, button_event
);
323 b
->callback
= callback
;
324 widget_want_hotkey (b
->widget
, 1);
325 b
->hotpos
= (b
->text
.hotkey
!= NULL
) ? str_term_width1 (b
->text
.start
) : -1;
331 button_get_text (WButton
*b
)
333 if (b
->text
.hotkey
!= NULL
)
334 return g_strconcat (b
->text
.start
, "&", b
->text
.hotkey
,
337 return g_strdup (b
->text
.start
);
341 button_set_text (WButton
*b
, const char *text
)
345 b->text = g_strdup (text);
346 b->widget.cols = button_len (text, b->flags);
347 button_scan_hotkey(b);
349 release_hotkey (b
->text
);
350 b
->text
= parse_hotkey (text
);
351 b
->widget
.cols
= button_len (b
->text
, b
->flags
);
352 dlg_redraw (b
->widget
.parent
);
356 /* Radio button widget */
357 static int radio_event (Gpm_Event
*event
, void *);
360 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
362 WRadio
*r
= (WRadio
*) w
;
364 Dlg_head
*h
= r
->widget
.parent
;
369 int i
, lp
= g_ascii_tolower ((gchar
)parm
);
371 for (i
= 0; i
< r
->count
; i
++) {
372 if (r
->texts
[i
].hotkey
!= NULL
) {
373 int c
= g_ascii_tolower ((gchar
)r
->texts
[i
].hotkey
[0]);
380 radio_callback (w
, WIDGET_KEY
, ' ');
385 return MSG_NOT_HANDLED
;
391 (*h
->callback
) (h
, DLG_ACTION
, 0);
392 radio_callback (w
, WIDGET_FOCUS
, ' ');
401 return MSG_NOT_HANDLED
;
405 if (r
->count
- 1 > r
->pos
) {
410 return MSG_NOT_HANDLED
;
413 (*h
->callback
) (h
, DLG_ACTION
, 0);
414 radio_callback (w
, WIDGET_FOCUS
, ' ');
415 widget_move (&r
->widget
, r
->pos
, 1);
421 for (i
= 0; i
< r
->count
; i
++) {
422 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
423 widget_selectcolor (w
, focused
, FALSE
);
424 widget_move (&r
->widget
, i
, 0);
425 tty_print_string ((r
->sel
== i
) ? "(*) " : "( ) ");
426 draw_hotkey (w
, r
->texts
[i
], focused
);
431 for (i
= 0; i
< r
->count
; i
++) {
432 release_hotkey (r
->texts
[i
]);
438 return default_proc (msg
, parm
);
443 radio_event (Gpm_Event
*event
, void *data
)
448 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
449 Dlg_head
*h
= r
->widget
.parent
;
451 r
->pos
= event
->y
- 1;
452 dlg_select_widget (r
);
453 if (event
->type
& GPM_UP
){
454 radio_callback (w
, WIDGET_KEY
, ' ');
455 radio_callback (w
, WIDGET_FOCUS
, 0);
456 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
464 radio_new (int y
, int x
, int count
, const char **texts
)
466 WRadio
*result
= g_new (WRadio
, 1);
469 /* Compute the longest string */
470 result
->texts
= g_new (struct hotkey_t
, count
);
473 for (i
= 0; i
< count
; i
++){
474 result
->texts
[i
] = parse_hotkey (texts
[i
]);
475 m
= hotkey_width (result
->texts
[i
]);
480 init_widget (&result
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
484 result
->count
= count
;
485 widget_want_hotkey (result
->widget
, 1);
491 /* Checkbutton widget */
493 static int check_event (Gpm_Event
*event
, void *);
496 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
498 WCheck
*c
= (WCheck
*) w
;
499 Dlg_head
*h
= c
->widget
.parent
;
503 if (c
->text
.hotkey
!= NULL
) {
504 if (g_ascii_tolower ((gchar
)c
->text
.hotkey
[0]) ==
505 g_ascii_tolower ((gchar
)parm
)) {
507 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
511 return MSG_NOT_HANDLED
;
515 return MSG_NOT_HANDLED
;
517 c
->state
^= C_CHANGE
;
518 (*h
->callback
) (h
, DLG_ACTION
, 0);
519 check_callback (w
, WIDGET_FOCUS
, ' ');
523 widget_move (&c
->widget
, 0, 1);
529 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
530 widget_move (&c
->widget
, 0, 0);
531 tty_print_string ((c
->state
& C_BOOL
) ? "[x] " : "[ ] ");
532 draw_hotkey (w
, c
->text
, msg
== WIDGET_FOCUS
);
536 release_hotkey (c
->text
);
540 return default_proc (msg
, parm
);
545 check_event (Gpm_Event
*event
, void *data
)
550 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
551 Dlg_head
*h
= c
->widget
.parent
;
553 dlg_select_widget (c
);
554 if (event
->type
& GPM_UP
){
555 check_callback (w
, WIDGET_KEY
, ' ');
556 check_callback (w
, WIDGET_FOCUS
, 0);
557 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
565 check_new (int y
, int x
, int state
, const char *text
)
567 WCheck
*c
= g_new (WCheck
, 1);
569 c
->text
= parse_hotkey (text
);
571 init_widget (&c
->widget
, y
, x
, 1, hotkey_width (c
->text
),
572 check_callback
, check_event
);
573 c
->state
= state
? C_BOOL
: 0;
574 widget_want_hotkey (c
->widget
, 1);
583 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
585 WLabel
*l
= (WLabel
*) w
;
586 Dlg_head
*h
= l
->widget
.parent
;
592 /* We don't want to get the focus */
594 return MSG_NOT_HANDLED
;
598 char *p
= l
->text
, *q
, c
= 0;
605 tty_setcolor (DEFAULT_COLOR
);
607 tty_setcolor (DLG_NORMALC (h
));
610 q
= strchr (p
, '\n');
616 widget_move (&l
->widget
, y
, 0);
617 tty_print_string (str_fit_to_term (p
, l
->widget
.cols
, J_LEFT
));
633 return default_proc (msg
, parm
);
638 label_set_text (WLabel
*label
, const char *text
)
640 int newcols
= label
->widget
.cols
;
643 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
644 return; /* Flickering is not nice */
646 g_free (label
->text
);
649 label
->text
= g_strdup (text
);
650 if (label
->auto_adjust_cols
) {
651 str_msg_term_size (text
, &newlines
, &newcols
);
652 if (newcols
> label
->widget
.cols
)
653 label
->widget
.cols
= newcols
;
654 if (newlines
> label
->widget
.lines
)
655 label
->widget
.lines
= newlines
;
657 } else label
->text
= NULL
;
659 if (label
->widget
.parent
)
660 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
662 if (newcols
< label
->widget
.cols
)
663 label
->widget
.cols
= newcols
;
667 label_new (int y
, int x
, const char *text
)
674 str_msg_term_size (text
, &lines
, &cols
);
676 l
= g_new (WLabel
, 1);
677 init_widget (&l
->widget
, y
, x
, lines
, cols
, label_callback
, NULL
);
678 l
->text
= (text
!= NULL
) ? g_strdup (text
) : NULL
;
679 l
->auto_adjust_cols
= 1;
681 widget_want_cursor (l
->widget
, 0);
686 /* Gauge widget (progress indicator) */
687 /* Currently width is hardcoded here for text mode */
691 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
693 WGauge
*g
= (WGauge
*) w
;
694 Dlg_head
*h
= g
->widget
.parent
;
696 if (msg
== WIDGET_INIT
)
699 /* We don't want to get the focus */
700 if (msg
== WIDGET_FOCUS
)
701 return MSG_NOT_HANDLED
;
703 if (msg
== WIDGET_DRAW
){
704 widget_move (&g
->widget
, 0, 0);
705 tty_setcolor (DLG_NORMALC (h
));
707 tty_printf ("%*s", gauge_len
, "");
709 int percentage
, columns
;
710 long total
= g
->max
, done
= g
->current
;
712 if (total
<= 0 || done
< 0) {
718 while (total
> 65535) {
722 percentage
= (200 * done
/ total
+ 1) / 2;
723 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
724 tty_print_char ('[');
725 tty_setcolor (GAUGE_COLOR
);
726 tty_printf ("%*s", (int) columns
, "");
727 tty_setcolor (DLG_NORMALC (h
));
728 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
733 return default_proc (msg
, parm
);
737 gauge_set_value (WGauge
*g
, int max
, int current
)
739 if (g
->current
== current
&& g
->max
== max
)
740 return; /* Do not flicker */
742 max
= 1; /* I do not like division by zero :) */
744 g
->current
= current
;
746 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
750 gauge_show (WGauge
*g
, int shown
)
752 if (g
->shown
== shown
)
755 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
759 gauge_new (int y
, int x
, int shown
, int max
, int current
)
761 WGauge
*g
= g_new (WGauge
, 1);
763 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
766 max
= 1; /* I do not like division by zero :) */
768 g
->current
= current
;
769 widget_want_cursor (g
->widget
, 0);
776 /* {{{ history button */
778 #define LARGE_HISTORY_BUTTON 1
780 #ifdef LARGE_HISTORY_BUTTON
781 # define HISTORY_BUTTON_WIDTH 3
783 # define HISTORY_BUTTON_WIDTH 1
786 #define should_show_history_button(in) \
787 (in->history && in->field_width > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
789 static void draw_history_button (WInput
* in
)
792 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
793 widget_move (&in
->widget
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
);
794 #ifdef LARGE_HISTORY_BUTTON
797 h
= in
->widget
.parent
;
798 tty_setcolor (NORMAL_COLOR
);
799 tty_print_string ("[ ]");
800 /* Too distracting: tty_setcolor (MARKED_COLOR); */
801 widget_move (&in
->widget
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1);
805 tty_setcolor (MARKED_COLOR
);
810 /* }}} history button */
813 /* Input widgets now have a global kill ring */
814 /* Pointer to killed data */
815 static char *kill_buffer
= 0;
818 update_input (WInput
*in
, int clear_first
)
822 int buf_len
= str_length (in
->buffer
);
826 if (should_show_history_button (in
))
827 has_history
= HISTORY_BUTTON_WIDTH
;
829 if (in
->disable_update
)
832 pw
= str_term_width2 (in
->buffer
, in
->point
);
834 /* Make the point visible */
835 if ((pw
< in
->term_first_shown
) ||
836 (pw
>= in
->term_first_shown
+ in
->field_width
- has_history
)) {
838 in
->term_first_shown
= pw
- (in
->field_width
/ 3);
839 if (in
->term_first_shown
< 0)
840 in
->term_first_shown
= 0;
843 /* Adjust the mark */
844 if (in
->mark
> buf_len
)
848 draw_history_button (in
);
850 tty_setcolor (in
->color
);
852 widget_move (&in
->widget
, 0, 0);
854 if (!in
->is_password
) {
855 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
856 in
->field_width
- has_history
));
859 for (i
= -in
->term_first_shown
; i
< in
->field_width
- has_history
; i
++){
861 tty_print_char ((cp
[0] != '\0') ? '*' : ' ');
863 if (cp
[0] != '\0') str_cnext_char (&cp
);
872 winput_set_origin (WInput
*in
, int x
, int field_width
)
875 in
->field_width
= in
->widget
.cols
= field_width
;
876 update_input (in
, 0);
879 /* {{{ history saving and loading */
881 int num_history_items_recorded
= 60;
884 This loads and saves the history of an input line to and from the
885 widget. It is called with the widgets history name on creation of the
886 widget, and returns the GList list. It stores histories in the file
887 ~/.mc/history in using the profile code.
889 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
890 function) then input_new assigns the default text to be the last text
891 entered, or "" if not found.
895 history_get (const char *input_name
)
905 if (!num_history_items_recorded
) /* this is how to disable */
907 if (!input_name
|| !*input_name
)
910 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
911 cfg
= mc_config_init (profile
);
913 /* get number of keys */
914 keys
= mc_config_get_keys (cfg
, input_name
, &keys_num
);
917 for (i
= 0; i
< keys_num
; i
++) {
918 char key_name
[BUF_TINY
];
919 g_snprintf (key_name
, sizeof (key_name
), "%lu", (unsigned long)i
);
920 this_entry
= mc_config_get_string (cfg
, input_name
, key_name
, "");
922 if (this_entry
&& *this_entry
)
923 hist
= list_append_unique (hist
, this_entry
);
926 mc_config_deinit (cfg
);
929 /* return pointer to the last entry in the list */
930 return g_list_last (hist
);
934 history_put (const char *input_name
, GList
*h
)
949 if (!num_history_items_recorded
) /* this is how to disable */
952 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
954 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
957 /* Make sure the history is only readable by the user */
958 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
963 /* go to end of list */
966 /* go back 60 places */
967 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
968 h
= g_list_previous (h
);
970 cfg
= mc_config_init(profile
);
973 mc_config_del_group(cfg
,input_name
);
975 /* dump histories into profile */
976 for (i
= 0; h
; h
= g_list_next (h
)) {
979 text
= (char *) h
->data
;
981 /* We shouldn't have null entries, but let's be sure */
983 char key_name
[BUF_TINY
];
984 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
985 mc_config_set_string(cfg
,input_name
, key_name
, text
);
989 mc_config_save_file (cfg
);
990 mc_config_deinit(cfg
);
994 /* }}} history saving and loading */
997 /* {{{ history display */
1002 return _(" History ");
1006 listbox_fwd (WListbox
*l
)
1008 if (l
->current
!= l
->list
->prev
)
1009 listbox_select_entry (l
, l
->current
->next
);
1011 listbox_select_first (l
);
1015 show_hist (GList
*history
, int widget_x
, int widget_y
)
1018 size_t maxlen
= str_term_width1 (i18n_htitle ()), i
, count
= 0;
1020 char *q
= NULL
, *r
= NULL
;
1021 Dlg_head
*query_dlg
;
1022 WListbox
*query_list
;
1028 z
= g_list_first (history
);
1031 if ((i
= str_term_width1 ((char *) hi
->data
)) > maxlen
)
1034 hi
= g_list_next (hi
);
1039 if (h
<= y
|| y
> LINES
- 6) {
1044 h
= min (h
, LINES
- y
);
1051 if ((w
= maxlen
+ 4) + x
> COLS
) {
1057 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
1058 i18n_htitle (), DLG_COMPACT
);
1059 query_list
= listbox_new (1, 1, h
- 2, w
- 2, NULL
);
1060 add_widget (query_dlg
, query_list
);
1066 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1067 0, (char *) hi
->data
, NULL
);
1068 hi
= g_list_next (hi
);
1070 listbox_select_last (query_list
);
1072 /* traverse backwards */
1073 hi
= g_list_last (history
);
1075 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1076 0, (char *) hi
->data
, NULL
);
1077 hi
= g_list_previous (hi
);
1081 if (run_dlg (query_dlg
) != B_CANCEL
) {
1082 listbox_get_current (query_list
, &q
, NULL
);
1086 destroy_dlg (query_dlg
);
1091 do_show_hist (WInput
* in
)
1094 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1096 assign_text (in
, r
);
1101 /* }}} history display */
1104 input_destroy (WInput
*in
)
1107 fprintf (stderr
, "Internal error: null Input *\n");
1114 if (!in
->is_password
) /* don't save passwords ;-) */
1115 history_put (in
->history_name
, in
->history
);
1117 in
->history
= g_list_first (in
->history
);
1118 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1119 g_list_free (in
->history
);
1122 g_free (in
->buffer
);
1123 free_completions (in
);
1124 g_free (in
->history_name
);
1128 input_disable_update (WInput
*in
)
1130 in
->disable_update
++;
1134 input_enable_update (WInput
*in
)
1136 in
->disable_update
--;
1137 update_input (in
, 0);
1140 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1143 push_history (WInput
*in
, const char *text
)
1146 /* input widget where urls with passwords are entered without any
1148 static const char *password_input_fields
[] = {
1149 N_(" Link to a remote machine "),
1150 N_(" FTP to machine "),
1151 N_(" SMB link to machine ")
1159 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1160 password_input_fields
[i
] = _(password_input_fields
[i
]);
1163 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1168 /* Avoid duplicated entries */
1169 in
->history
= g_list_last (in
->history
);
1170 if (!strcmp ((char *) in
->history
->data
, text
))
1174 t
= g_strdup (text
);
1176 if (in
->history_name
) {
1177 p
= in
->history_name
+ 3;
1178 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1179 if (strcmp (p
, password_input_fields
[i
]) == 0)
1181 if (i
< ELEMENTS (password_input_fields
))
1182 strip_password (t
, 0);
1184 strip_password (t
, 1);
1187 in
->history
= list_append_unique (in
->history
, t
);
1195 /* Cleans the input line and adds the current text to the history */
1197 new_input (WInput
*in
)
1200 push_history (in
, in
->buffer
);
1202 in
->buffer
[0] = '\0';
1206 free_completions (in
);
1207 update_input (in
, 0);
1211 move_buffer_backward (WInput
*in
, int start
, int end
)
1214 int str_len
= str_length (in
->buffer
);
1215 if (start
>= str_len
|| end
> str_len
+ 1) return;
1217 pos
= str_offset_to_pos (in
->buffer
, start
);
1218 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
1220 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
1221 in
->buffer
[i
] = in
->buffer
[i
+ len
];
1225 insert_char (WInput
*in
, int c_code
)
1231 return MSG_NOT_HANDLED
;
1233 if (in
->charpoint
>= MB_LEN_MAX
)
1236 in
->charbuf
[in
->charpoint
] = c_code
;
1239 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
1242 in
->charpoint
= 0; /* broken multibyte char, skip */
1247 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
){
1248 /* Expand the buffer */
1249 size_t new_length
= in
->current_max_size
+
1250 in
->field_width
+ in
->charpoint
;
1251 char *narea
= g_try_renew (char, in
->buffer
, new_length
);
1254 in
->current_max_size
= new_length
;
1258 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
) {
1259 /* bytes from begin */
1260 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
1262 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
1264 for (i
= rest_bytes
+ 1; i
> 0; i
--)
1265 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] =
1266 in
->buffer
[ins_point
+ i
- 1];
1268 memcpy(in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
1277 beginning_of_line (WInput
*in
)
1284 end_of_line (WInput
*in
)
1286 in
->point
= str_length (in
->buffer
);
1291 backward_char (WInput
*in
)
1293 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1295 if (in
->point
> 0) {
1296 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
1302 forward_char (WInput
*in
)
1304 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1305 if (act
[0] != '\0') {
1306 in
->point
+= str_cnext_noncomb_char (&act
);
1312 forward_word (WInput
* in
)
1314 const char *p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1316 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
))) {
1317 str_cnext_char (&p
);
1320 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
)) {
1321 str_cnext_char (&p
);
1327 backward_word (WInput
*in
)
1329 const char *p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1331 while ((p
!= in
->buffer
) && (p
[0] == '\0')) {
1336 while ((p
!= in
->buffer
) && (str_isspace (p
) || str_ispunct (p
))) {
1337 str_cprev_char (&p
);
1340 while ((p
!= in
->buffer
) && !str_isspace (p
) && !str_ispunct (p
)) {
1341 str_cprev_char (&p
);
1347 key_left (WInput
*in
)
1353 key_ctrl_left (WInput
*in
)
1359 key_right (WInput
*in
)
1365 key_ctrl_right (WInput
*in
)
1370 backward_delete (WInput
*in
)
1372 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1378 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
1379 move_buffer_backward(in
, start
, in
->point
);
1386 delete_char (WInput
*in
)
1388 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1389 int end
= in
->point
;
1391 end
+= str_cnext_noncomb_char (&act
);
1393 move_buffer_backward(in
, in
->point
, end
);
1399 copy_region (WInput
*in
, int x_first
, int x_last
)
1401 int first
= min (x_first
, x_last
);
1402 int last
= max (x_first
, x_last
);
1407 g_free (kill_buffer
);
1409 first
= str_offset_to_pos (in
->buffer
, first
);
1410 last
= str_offset_to_pos (in
->buffer
, last
);
1412 kill_buffer
= g_strndup(in
->buffer
+ first
, last
- first
);
1416 delete_region (WInput
*in
, int x_first
, int x_last
)
1418 int first
= min (x_first
, x_last
);
1419 int last
= max (x_first
, x_last
);
1424 last
= str_offset_to_pos (in
->buffer
, last
);
1425 first
= str_offset_to_pos (in
->buffer
, first
);
1426 len
= strlen (&in
->buffer
[last
]) + 1;
1427 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1433 kill_word (WInput
*in
)
1435 int old_point
= in
->point
;
1439 new_point
= in
->point
;
1440 in
->point
= old_point
;
1442 copy_region (in
, old_point
, new_point
);
1443 delete_region (in
, old_point
, new_point
);
1450 back_kill_word (WInput
*in
)
1452 int old_point
= in
->point
;
1456 new_point
= in
->point
;
1457 in
->point
= old_point
;
1459 copy_region (in
, old_point
, new_point
);
1460 delete_region (in
, old_point
, new_point
);
1465 set_mark (WInput
*in
)
1467 in
->mark
= in
->point
;
1471 kill_save (WInput
*in
)
1473 copy_region (in
, in
->mark
, in
->point
);
1477 kill_region (WInput
*in
)
1480 delete_region (in
, in
->point
, in
->mark
);
1491 for (p
= kill_buffer
; *p
; p
++)
1492 insert_char (in
, *p
);
1497 kill_line (WInput
*in
)
1499 int chp
= str_offset_to_pos (in
->buffer
, in
->point
);
1500 g_free (kill_buffer
);
1501 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
1502 in
->buffer
[chp
] = '\0';
1507 assign_text (WInput
*in
, const char *text
)
1509 free_completions (in
);
1510 g_free (in
->buffer
);
1511 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1512 in
->current_max_size
= strlen (in
->buffer
) + 1;
1513 in
->point
= str_length (in
->buffer
);
1520 hist_prev (WInput
*in
)
1525 if (in
->need_push
) {
1526 switch (push_history (in
, in
->buffer
)) {
1528 in
->history
= g_list_previous (in
->history
);
1531 if (in
->history
->prev
)
1532 in
->history
= g_list_previous (in
->history
);
1537 } else if (in
->history
->prev
)
1538 in
->history
= g_list_previous (in
->history
);
1541 assign_text (in
, (char *) in
->history
->data
);
1546 hist_next (WInput
*in
)
1548 if (in
->need_push
) {
1549 switch (push_history (in
, in
->buffer
)) {
1551 assign_text (in
, "");
1561 if (!in
->history
->next
) {
1562 assign_text (in
, "");
1566 in
->history
= g_list_next (in
->history
);
1567 assign_text (in
, (char *) in
->history
->data
);
1571 static const struct {
1573 void (*fn
)(WInput
*in
);
1576 { XCTRL('a'), beginning_of_line
},
1577 { KEY_HOME
, beginning_of_line
},
1578 { KEY_A1
, beginning_of_line
},
1579 { ALT ('<'), beginning_of_line
},
1580 { XCTRL('e'), end_of_line
},
1581 { KEY_END
, end_of_line
},
1582 { KEY_C1
, end_of_line
},
1583 { ALT ('>'), end_of_line
},
1584 { KEY_LEFT
, key_left
},
1585 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1586 { XCTRL('b'), backward_char
},
1587 { ALT('b'), backward_word
},
1588 { KEY_RIGHT
, key_right
},
1589 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1590 { XCTRL('f'), forward_char
},
1591 { ALT('f'), forward_word
},
1594 { KEY_BACKSPACE
, backward_delete
},
1595 { KEY_DC
, delete_char
},
1596 { ALT('d'), kill_word
},
1597 { ALT(KEY_BACKSPACE
), back_kill_word
},
1599 /* Region manipulation */
1601 { XCTRL('w'), kill_region
},
1602 { ALT('w'), kill_save
},
1603 { XCTRL('y'), yank
},
1604 { XCTRL('k'), kill_line
},
1607 { ALT('p'), hist_prev
},
1608 { ALT('n'), hist_next
},
1609 { ALT('h'), do_show_hist
},
1612 { ALT('\t'), complete
},
1617 /* This function is a test for a special input key used in complete.c */
1618 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1619 and 2 if it is a complete key */
1621 is_in_input_map (WInput
*in
, int c_code
)
1627 for (i
= 0; input_map
[i
].fn
; i
++)
1628 if (c_code
== input_map
[i
].key_code
) {
1629 if (input_map
[i
].fn
== complete
)
1638 port_region_marked_for_delete (WInput
*in
)
1640 in
->buffer
[0] = '\0';
1647 handle_char (WInput
*in
, int c_code
)
1652 v
= MSG_NOT_HANDLED
;
1655 free_completions (in
);
1656 v
= insert_char (in
, c_code
);
1657 update_input (in
, 1);
1662 for (i
= 0; input_map
[i
].fn
; i
++){
1663 if (c_code
== input_map
[i
].key_code
){
1664 if (input_map
[i
].fn
!= complete
)
1665 free_completions (in
);
1666 (*input_map
[i
].fn
)(in
);
1671 if (!input_map
[i
].fn
){
1673 return MSG_NOT_HANDLED
;
1675 port_region_marked_for_delete (in
);
1677 free_completions (in
);
1678 v
= insert_char (in
, c_code
);
1680 update_input (in
, 1);
1684 /* Inserts text in input line */
1686 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1688 input_disable_update (in
);
1690 handle_char (in
, *text
++);
1691 if (insert_extra_space
)
1692 handle_char (in
, ' ');
1693 input_enable_update (in
);
1694 update_input (in
, 1);
1698 input_set_point (WInput
*in
, int pos
)
1700 int max_pos
= str_length (in
->buffer
);
1704 if (pos
!= in
->point
)
1705 free_completions (in
);
1708 update_input (in
, 1);
1712 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1714 WInput
*in
= (WInput
*) w
;
1719 if (parm
== XCTRL ('q')) {
1721 v
= handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1726 /* Keys we want others to handle */
1727 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1728 || parm
== KEY_F (10) || parm
== XCTRL ('g') || parm
== '\n')
1729 return MSG_NOT_HANDLED
;
1731 /* When pasting multiline text, insert literal Enter */
1732 if ((parm
& ~KEY_M_MASK
) == '\n') {
1734 v
= handle_char (in
, '\n');
1739 return handle_char (in
, parm
);
1742 case WIDGET_UNFOCUS
:
1744 update_input (in
, 0);
1748 widget_move (&in
->widget
, 0, str_term_width2 (in
->buffer
, in
->point
)
1749 - in
->term_first_shown
);
1752 case WIDGET_DESTROY
:
1757 return default_proc (msg
, parm
);
1762 input_event (Gpm_Event
* event
, void *data
)
1766 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1767 dlg_select_widget (in
);
1769 if (event
->x
>= in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1
1770 && should_show_history_button (in
)) {
1773 in
->point
= str_length (in
->buffer
);
1774 if (event
->x
+ in
->term_first_shown
- 1 <
1775 str_term_width1 (in
->buffer
))
1777 in
->point
= str_column_to_pos (in
->buffer
, event
->x
1778 + in
->term_first_shown
- 1);
1781 update_input (in
, 1);
1787 input_new (int y
, int x
, int color
, int width
, const char *def_text
,
1788 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
1790 WInput
*in
= g_new (WInput
, 1);
1791 int initial_buffer_len
;
1793 init_widget (&in
->widget
, y
, x
, 1, width
, input_callback
, input_event
);
1797 in
->history_name
= 0;
1800 in
->history_name
= g_strdup (histname
);
1801 in
->history
= history_get (histname
);
1805 if (def_text
== NULL
)
1808 if (def_text
== INPUT_LAST_TEXT
) {
1811 if (in
->history
->data
)
1812 def_text
= (char *) in
->history
->data
;
1814 initial_buffer_len
= 1 + max ((size_t) width
, strlen (def_text
));
1815 in
->widget
.options
|= W_IS_INPUT
;
1816 in
->completions
= NULL
;
1817 in
->completion_flags
= completion_flags
;
1818 in
->current_max_size
= initial_buffer_len
;
1819 in
->buffer
= g_new (char, initial_buffer_len
);
1821 in
->field_width
= width
;
1823 in
->term_first_shown
= 0;
1824 in
->disable_update
= 0;
1827 in
->is_password
= 0;
1829 strcpy (in
->buffer
, def_text
);
1830 in
->point
= str_length (in
->buffer
);
1835 /* Listbox widget */
1837 /* Should draw the scrollbar, but currently draws only
1838 * indications that there is more information
1840 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1843 listbox_drawscroll (WListbox
*l
)
1847 int max_line
= l
->height
-1;
1849 /* Are we at the top? */
1850 widget_move (&l
->widget
, 0, l
->width
);
1851 if (l
->list
== l
->top
)
1852 tty_print_one_vline ();
1854 tty_print_char ('^');
1856 /* Are we at the bottom? */
1857 widget_move (&l
->widget
, max_line
, l
->width
);
1858 top
= listbox_cdiff (l
->list
, l
->top
);
1859 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1860 tty_print_one_vline ();
1862 tty_print_char ('v');
1864 /* Now draw the nice relative pointer */
1866 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1870 for (i
= 1; i
< max_line
; i
++){
1871 widget_move (&l
->widget
, i
, l
->width
);
1873 tty_print_one_vline ();
1875 tty_print_char ('*');
1880 listbox_draw (WListbox
*l
, int focused
)
1885 Dlg_head
*h
= l
->widget
.parent
;
1886 int normalc
= DLG_NORMALC (h
);
1891 selc
= DLG_FOCUSC (h
);
1893 selc
= DLG_HOT_FOCUSC (h
);
1897 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1899 /* Display the entry */
1900 if (e
== l
->current
&& sel_line
== -1){
1902 tty_setcolor (selc
);
1904 tty_setcolor (normalc
);
1906 widget_move (&l
->widget
, i
, 0);
1908 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1914 tty_print_string (str_fit_to_term (text
, l
->width
- 2, J_LEFT_FIT
));
1916 l
->cursor_y
= sel_line
;
1919 tty_setcolor (normalc
);
1920 listbox_drawscroll (l
);
1924 /* Returns the number of items between s and e,
1925 must be on the same linked list */
1927 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1931 for (count
= 0; s
!= e
; count
++)
1937 listbox_check_hotkey (WListbox
*l
, int key
)
1949 /* If we didn't find anything, return */
1950 if (i
&& e
== l
->list
)
1953 if (e
->hotkey
== key
)
1961 /* Selects the last entry and scrolls the list to the bottom */
1963 listbox_select_last (WListbox
*l
)
1966 l
->current
= l
->top
= l
->list
->prev
;
1967 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1968 l
->top
= l
->top
->prev
;
1969 l
->pos
= l
->count
- 1;
1972 /* Selects the first entry and scrolls the list to the top */
1974 listbox_select_first (WListbox
*l
)
1976 l
->current
= l
->top
= l
->list
;
1981 listbox_remove_list (WListbox
*l
)
1990 while (l
->count
--) {
1996 l
->pos
= l
->count
= 0;
1997 l
->list
= l
->top
= l
->current
= 0;
2001 * bor 30.10.96: added force flag to remove *last* entry as well
2002 * bor 30.10.96: corrected selection bug if last entry was removed
2006 listbox_remove_current (WListbox
*l
, int force
)
2010 /* Ok, note: this won't allow for emtpy lists */
2011 if (!force
&& (!l
->count
|| l
->count
== 1))
2018 l
->current
->next
->prev
= l
->current
->prev
;
2019 l
->current
->prev
->next
= l
->current
->next
;
2020 if (p
->next
== l
->list
) {
2021 l
->current
= p
->prev
;
2025 l
->current
= p
->next
;
2028 l
->list
= l
->top
= p
->next
;
2031 l
->list
= l
->top
= l
->current
= 0;
2038 /* Makes *e the selected entry (sets current and pos) */
2040 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
2049 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
2057 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
2058 l
->top
= l
->top
->next
;
2060 l
->top
= l
->current
;
2066 /* If we are unable to find it, set decent values */
2067 l
->current
= l
->top
= l
->list
;
2071 /* Selects from base the pos element */
2073 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
2075 WLEntry
*last
= l
->list
->prev
;
2088 listbox_back (WListbox
*l
)
2091 listbox_select_entry (l
, l
->current
->prev
);
2093 listbox_select_last (l
);
2096 /* Return MSG_HANDLED if we want a redraw */
2098 listbox_key (WListbox
*l
, int key
)
2102 cb_ret_t j
= MSG_NOT_HANDLED
;
2105 return MSG_NOT_HANDLED
;
2111 listbox_select_first (l
);
2117 listbox_select_last (l
);
2132 for (i
= 0; ((i
< l
->height
- 1)
2133 && (l
->current
!= l
->list
->prev
)); i
++) {
2141 for (i
= 0; ((i
< l
->height
- 1)
2142 && (l
->current
!= l
->list
)); i
++) {
2148 return MSG_NOT_HANDLED
;
2152 listbox_destroy (WListbox
*l
)
2154 WLEntry
*n
, *p
= l
->list
;
2157 for (i
= 0; i
< l
->count
; i
++){
2166 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2168 WListbox
*l
= (WListbox
*) w
;
2171 Dlg_head
*h
= l
->widget
.parent
;
2178 if ((e
= listbox_check_hotkey (l
, parm
)) != NULL
) {
2181 listbox_select_entry (l
, e
);
2183 (*h
->callback
) (h
, DLG_ACTION
, l
->pos
);
2186 action
= (*l
->cback
) (l
);
2188 action
= LISTBOX_DONE
;
2190 if (action
== LISTBOX_DONE
) {
2191 h
->ret_value
= B_ENTER
;
2196 return MSG_NOT_HANDLED
;
2199 if ((ret_code
= listbox_key (l
, parm
)) != MSG_NOT_HANDLED
) {
2200 listbox_draw (l
, 1);
2201 (*h
->callback
) (h
, DLG_ACTION
, l
->pos
);
2206 widget_move (&l
->widget
, l
->cursor_y
, 0);
2207 (*h
->callback
) (h
, DLG_ACTION
, l
->pos
);
2211 case WIDGET_UNFOCUS
:
2213 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2216 case WIDGET_DESTROY
:
2217 listbox_destroy (l
);
2221 return default_proc (msg
, parm
);
2226 listbox_event (Gpm_Event
*event
, void *data
)
2232 Dlg_head
*h
= l
->widget
.parent
;
2235 if (event
->type
& GPM_DOWN
)
2236 dlg_select_widget (l
);
2239 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2240 if (event
->x
< 0 || event
->x
>= l
->width
)
2243 for (i
= -event
->y
; i
>= 0; i
--)
2245 else if (event
->y
> l
->height
)
2246 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2249 listbox_select_entry (l
,
2250 listbox_select_pos (l
, l
->top
,
2253 /* We need to refresh ourselves since the dialog manager doesn't */
2254 /* know about this event */
2255 listbox_callback (w
, WIDGET_DRAW
, 0);
2261 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2264 if (event
->x
< 0 || event
->x
>= l
->width
)
2266 if (event
->y
< 1 || event
->y
> l
->height
)
2269 dlg_select_widget (l
);
2270 listbox_select_entry (l
,
2271 listbox_select_pos (l
, l
->top
,
2275 action
= (*l
->cback
) (l
);
2277 action
= LISTBOX_DONE
;
2279 if (action
== LISTBOX_DONE
) {
2280 h
->ret_value
= B_ENTER
;
2289 listbox_new (int y
, int x
, int height
, int width
, lcback callback
)
2291 WListbox
*l
= g_new (WListbox
, 1);
2293 init_widget (&l
->widget
, y
, x
, height
, width
,
2294 listbox_callback
, listbox_event
);
2296 l
->list
= l
->top
= l
->current
= 0;
2304 l
->cback
= callback
;
2305 l
->allow_duplicates
= 1;
2306 l
->scrollbar
= !tty_is_slow ();
2307 widget_want_hotkey (l
->widget
, 1);
2312 /* Listbox item adding function. They still lack a lot of functionality */
2314 /* 1.11.96 bor: added pos argument to control placement of new entry */
2316 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2324 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2326 e
->prev
= l
->list
->prev
;
2327 l
->list
->prev
->next
= e
;
2329 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2330 e
->next
= l
->current
;
2331 e
->prev
= l
->current
->prev
;
2332 l
->current
->prev
->next
= e
;
2333 l
->current
->prev
= e
;
2334 if (l
->list
== l
->current
) { /* move list one position down */
2338 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2339 e
->prev
= l
->current
;
2340 e
->next
= l
->current
->next
;
2341 l
->current
->next
->prev
= e
;
2342 l
->current
->next
= e
;
2343 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2344 WLEntry
*w
= l
->list
;
2346 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2348 if (w
->next
== l
->list
) {
2364 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2365 const char *text
, void *data
)
2372 if (!l
->allow_duplicates
)
2373 if (listbox_search_text (l
, text
))
2376 entry
= g_new (WLEntry
, 1);
2377 entry
->text
= g_strdup (text
);
2379 entry
->hotkey
= hotkey
;
2381 listbox_append_item (l
, entry
, pos
);
2386 /* Selects the nth entry in the listbox */
2388 listbox_select_by_number (WListbox
*l
, int n
)
2390 if (l
->list
!= NULL
)
2391 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2395 listbox_search_text (WListbox
*l
, const char *text
)
2404 if(!strcmp (e
->text
, text
))
2407 } while (e
!=l
->list
);
2412 /* Returns the current string text as well as the associated extra data */
2414 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2420 if (string
&& l
->current
)
2421 *string
= l
->current
->text
;
2422 if (extra
&& l
->current
)
2423 *extra
= l
->current
->data
;
2426 /* returns TRUE if a function has been called, FALSE otherwise. */
2428 buttonbar_call (WButtonBar
*bb
, int i
)
2430 switch (bb
->labels
[i
].tag
) {
2434 bb
->labels
[i
].u
.fn_void ();
2437 bb
->labels
[i
].u
.fn_ptr (bb
->labels
[i
].data
);
2443 /* calculate width of one button, width is never lesser than 7 */
2445 buttonbat_get_button_width ()
2447 int result
= COLS
/ BUTTONBAR_LABELS_NUM
;
2448 return (result
>= 7) ? result
: 7;
2453 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2455 WButtonBar
*bb
= (WButtonBar
*) w
;
2461 return MSG_NOT_HANDLED
;
2464 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2465 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2467 return MSG_NOT_HANDLED
;
2471 widget_move (&bb
->widget
, 0, 0);
2472 tty_setcolor (DEFAULT_COLOR
);
2473 bb
->btn_width
= buttonbat_get_button_width ();
2474 tty_printf ("%-*s", bb
->widget
.cols
, "");
2476 for (i
= 0; i
< COLS
/ bb
->btn_width
&& i
< BUTTONBAR_LABELS_NUM
; i
++) {
2477 widget_move (&bb
->widget
, 0, i
* bb
->btn_width
);
2478 tty_setcolor (DEFAULT_COLOR
);
2479 tty_printf ("%2d", i
+ 1);
2480 tty_setcolor (SELECTED_COLOR
);
2481 text
= (bb
->labels
[i
].text
!= NULL
) ? bb
->labels
[i
].text
: "";
2482 tty_print_string (str_fit_to_term (text
, bb
->btn_width
- 2, J_CENTER_LEFT
));
2487 case WIDGET_DESTROY
:
2488 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2489 g_free (bb
->labels
[i
].text
);
2493 return default_proc (msg
, parm
);
2498 buttonbar_event (Gpm_Event
*event
, void *data
)
2500 WButtonBar
*bb
= data
;
2503 if (!(event
->type
& GPM_UP
))
2507 button
= (event
->x
- 1) / bb
->btn_width
;
2508 if (button
< BUTTONBAR_LABELS_NUM
)
2509 buttonbar_call (bb
, button
);
2514 buttonbar_new (int visible
)
2517 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2519 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2520 buttonbar_callback
, buttonbar_event
);
2522 bb
->visible
= visible
;
2523 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++){
2524 bb
->labels
[i
].text
= NULL
;
2525 bb
->labels
[i
].tag
= BBFUNC_NONE
;
2527 widget_want_hotkey (bb
->widget
, 1);
2528 widget_want_cursor (bb
->widget
, 0);
2529 bb
->btn_width
= buttonbat_get_button_width ();
2535 set_label_text (WButtonBar
* bb
, int index
, const char *text
)
2537 g_free (bb
->labels
[index
- 1].text
);
2539 bb
->labels
[index
- 1].text
= g_strdup (text
);
2542 /* Find ButtonBar widget in the dialog */
2544 find_buttonbar (Dlg_head
*h
)
2548 bb
= (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2553 buttonbar_clear_label (Dlg_head
*h
, int idx
)
2555 WButtonBar
*bb
= find_buttonbar (h
);
2560 set_label_text (bb
, idx
, "");
2561 bb
->labels
[idx
- 1].tag
= BBFUNC_NONE
;
2565 buttonbar_set_label_data (Dlg_head
*h
, int idx
, const char *text
,
2566 buttonbarfn cback
, void *data
)
2568 WButtonBar
*bb
= find_buttonbar (h
);
2573 assert (cback
!= (buttonbarfn
) 0);
2574 set_label_text (bb
, idx
, text
);
2575 bb
->labels
[idx
- 1].tag
= BBFUNC_PTR
;
2576 bb
->labels
[idx
- 1].u
.fn_ptr
= cback
;
2577 bb
->labels
[idx
- 1].data
= data
;
2581 buttonbar_set_label (Dlg_head
*h
, int idx
, const char *text
, voidfn cback
)
2583 WButtonBar
*bb
= find_buttonbar (h
);
2588 assert (cback
!= (voidfn
) 0);
2589 set_label_text (bb
, idx
, text
);
2590 bb
->labels
[idx
- 1].tag
= BBFUNC_VOID
;
2591 bb
->labels
[idx
- 1].u
.fn_void
= cback
;
2595 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2597 bb
->visible
= visible
;
2601 buttonbar_redraw (Dlg_head
*h
)
2603 WButtonBar
*bb
= find_buttonbar (h
);
2608 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2612 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2614 WGroupbox
*g
= (WGroupbox
*) w
;
2621 return MSG_NOT_HANDLED
;
2624 tty_setcolor (COLOR_NORMAL
);
2625 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2626 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2629 tty_setcolor (COLOR_HOT_NORMAL
);
2630 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2631 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2632 tty_print_string (g
->title
);
2635 case WIDGET_DESTROY
:
2640 return default_proc (msg
, parm
);
2645 groupbox_new (int y
, int x
, int height
, int width
, const char *title
)
2647 WGroupbox
*g
= g_new (WGroupbox
, 1);
2649 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2651 g
->widget
.options
&= ~W_WANT_CURSOR
;
2652 widget_want_hotkey (g
->widget
, 0);
2654 /* Strip existing spaces, add one space before and after the title */
2657 t
= g_strstrip (g_strdup (title
));
2658 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);