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/skin/skin.h"
47 #include "../src/tty/mouse.h"
48 #include "../src/tty/key.h" /* XCTRL and ALT macros */
49 #include "../src/mcconfig/mcconfig.h" /* for history loading and saving */
51 #include "../vfs/vfs.h"
58 #include "cmddef.h" /* CK_ cmd name const */
59 #include "keybind.h" /* global_keymap_t */
61 #include "panel.h" /* current_panel */
63 const global_keymap_t
*input_map
;
66 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
68 Dlg_head
*h
= w
->parent
;
73 : DLG_HOT_NORMALC (h
))
80 parse_hotkey (const char *text
)
82 struct hotkey_t result
;
85 /* search for '&', that is not on the of text */
86 cp
= strchr (text
, '&');
87 if (cp
!= NULL
&& cp
[1] != '\0') {
88 result
.start
= g_strndup (text
, cp
- text
);
92 p
= str_cget_next_char (cp
);
93 result
.hotkey
= g_strndup (cp
, p
- cp
);
96 result
.end
= g_strdup (cp
);
98 result
.start
= g_strdup (text
);
106 release_hotkey (const struct hotkey_t hotkey
)
108 g_free (hotkey
.start
);
109 g_free (hotkey
.hotkey
);
114 hotkey_width (const struct hotkey_t hotkey
)
118 result
= str_term_width1 (hotkey
.start
);
119 result
+= (hotkey
.hotkey
!= NULL
) ? str_term_width1 (hotkey
.hotkey
) : 0;
120 result
+= (hotkey
.end
!= NULL
) ? str_term_width1 (hotkey
.end
) : 0;
125 draw_hotkey (Widget
*w
, const struct hotkey_t hotkey
, gboolean focused
)
127 widget_selectcolor (w
, focused
, FALSE
);
128 tty_print_string (hotkey
.start
);
130 if (hotkey
.hotkey
!= NULL
) {
131 widget_selectcolor (w
, focused
, TRUE
);
132 tty_print_string (hotkey
.hotkey
);
133 widget_selectcolor (w
, focused
, FALSE
);
136 if (hotkey
.end
!= NULL
)
137 tty_print_string (hotkey
.end
);
141 /* Default callback for widgets */
143 default_proc (widget_msg_t msg
, int parm
)
158 return MSG_NOT_HANDLED
;
162 static int button_event (Gpm_Event
*event
, void *);
167 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
169 WButton
*b
= (WButton
*) w
;
172 Dlg_head
*h
= b
->widget
.parent
;
177 * Don't let the default button steal Enter from the current
178 * button. This is a workaround for the flawed event model
179 * when hotkeys are sent to all widgets before the key is
180 * handled by the current widget.
182 if (parm
== '\n' && h
->current
== &b
->widget
) {
183 button_callback (w
, WIDGET_KEY
, ' ');
187 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
188 button_callback (w
, WIDGET_KEY
, ' ');
192 if (b
->text
.hotkey
!= NULL
) {
193 if (g_ascii_tolower ((gchar
)b
->text
.hotkey
[0]) ==
194 g_ascii_tolower ((gchar
)parm
)) {
195 button_callback (w
, WIDGET_KEY
, ' ');
199 return MSG_NOT_HANDLED
;
202 if (parm
!= ' ' && parm
!= '\n')
203 return MSG_NOT_HANDLED
;
206 stop
= (*b
->callback
) (b
->action
);
207 if (!b
->callback
|| stop
) {
208 h
->ret_value
= b
->action
;
229 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
235 if (msg
== WIDGET_UNFOCUS
)
237 else if (msg
== WIDGET_FOCUS
)
240 widget_selectcolor (w
, b
->selected
, FALSE
);
241 widget_move (w
, 0, 0);
245 tty_print_string ("[< ");
248 tty_print_string ("[ ");
251 tty_print_string ("[");
258 draw_hotkey (w
, b
->text
, b
->selected
);
262 tty_print_string (" >]");
265 tty_print_string (" ]");
268 tty_print_string ("]");
274 release_hotkey (b
->text
);
278 return default_proc (msg
, parm
);
283 button_event (Gpm_Event
*event
, void *data
)
287 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
288 Dlg_head
*h
= b
->widget
.parent
;
289 dlg_select_widget (b
);
290 if (event
->type
& GPM_UP
){
291 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
292 h
->callback (h
, &b
->widget
, DLG_POST_KEY
, ' ', NULL
);
300 button_get_len (const WButton
*b
)
302 int ret
= hotkey_width (b
->text
);
321 button_new (int y
, int x
, int action
, int flags
, const char *text
,
324 WButton
*b
= g_new (WButton
, 1);
328 b
->text
= parse_hotkey (text
);
330 init_widget (&b
->widget
, y
, x
, 1, button_get_len (b
),
331 button_callback
, button_event
);
334 b
->callback
= callback
;
335 widget_want_hotkey (b
->widget
, 1);
336 b
->hotpos
= (b
->text
.hotkey
!= NULL
) ? str_term_width1 (b
->text
.start
) : -1;
342 button_get_text (const WButton
*b
)
344 if (b
->text
.hotkey
!= NULL
)
345 return g_strconcat (b
->text
.start
, "&", b
->text
.hotkey
,
346 b
->text
.end
, (char *) NULL
);
348 return g_strdup (b
->text
.start
);
352 button_set_text (WButton
*b
, const char *text
)
354 release_hotkey (b
->text
);
355 b
->text
= parse_hotkey (text
);
356 b
->widget
.cols
= button_get_len (b
);
357 dlg_redraw (b
->widget
.parent
);
361 /* Radio button widget */
362 static int radio_event (Gpm_Event
*event
, void *);
365 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
367 WRadio
*r
= (WRadio
*) w
;
369 Dlg_head
*h
= r
->widget
.parent
;
374 int lp
= g_ascii_tolower ((gchar
)parm
);
376 for (i
= 0; i
< r
->count
; i
++) {
377 if (r
->texts
[i
].hotkey
!= NULL
) {
378 int c
= g_ascii_tolower ((gchar
)r
->texts
[i
].hotkey
[0]);
385 radio_callback (w
, WIDGET_KEY
, ' ');
390 return MSG_NOT_HANDLED
;
396 h
->callback (h
, w
, DLG_ACTION
, 0, NULL
);
397 radio_callback (w
, WIDGET_FOCUS
, ' ');
406 return MSG_NOT_HANDLED
;
410 if (r
->count
- 1 > r
->pos
) {
415 return MSG_NOT_HANDLED
;
418 h
->callback (h
, w
, DLG_ACTION
, 0, NULL
);
419 radio_callback (w
, WIDGET_FOCUS
, ' ');
420 widget_move (&r
->widget
, r
->pos
, 1);
426 for (i
= 0; i
< r
->count
; i
++) {
427 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
428 widget_selectcolor (w
, focused
, FALSE
);
429 widget_move (&r
->widget
, i
, 0);
430 tty_print_string ((r
->sel
== i
) ? "(*) " : "( ) ");
431 draw_hotkey (w
, r
->texts
[i
], focused
);
436 for (i
= 0; i
< r
->count
; i
++) {
437 release_hotkey (r
->texts
[i
]);
443 return default_proc (msg
, parm
);
448 radio_event (Gpm_Event
*event
, void *data
)
453 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
454 Dlg_head
*h
= r
->widget
.parent
;
456 r
->pos
= event
->y
- 1;
457 dlg_select_widget (r
);
458 if (event
->type
& GPM_UP
){
459 radio_callback (w
, WIDGET_KEY
, ' ');
460 radio_callback (w
, WIDGET_FOCUS
, 0);
461 h
->callback (h
, w
, DLG_POST_KEY
, ' ', NULL
);
469 radio_new (int y
, int x
, int count
, const char **texts
)
471 WRadio
*result
= g_new (WRadio
, 1);
474 /* Compute the longest string */
475 result
->texts
= g_new (struct hotkey_t
, count
);
478 for (i
= 0; i
< count
; i
++){
479 result
->texts
[i
] = parse_hotkey (texts
[i
]);
480 m
= hotkey_width (result
->texts
[i
]);
485 init_widget (&result
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
489 result
->count
= count
;
490 widget_want_hotkey (result
->widget
, 1);
496 /* Checkbutton widget */
498 static int check_event (Gpm_Event
*event
, void *);
501 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
503 WCheck
*c
= (WCheck
*) w
;
504 Dlg_head
*h
= c
->widget
.parent
;
508 if (c
->text
.hotkey
!= NULL
) {
509 if (g_ascii_tolower ((gchar
)c
->text
.hotkey
[0]) ==
510 g_ascii_tolower ((gchar
)parm
)) {
512 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
516 return MSG_NOT_HANDLED
;
520 return MSG_NOT_HANDLED
;
522 c
->state
^= C_CHANGE
;
523 h
->callback (h
, w
, DLG_ACTION
, 0, NULL
);
524 check_callback (w
, WIDGET_FOCUS
, ' ');
528 widget_move (&c
->widget
, 0, 1);
534 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
535 widget_move (&c
->widget
, 0, 0);
536 tty_print_string ((c
->state
& C_BOOL
) ? "[x] " : "[ ] ");
537 draw_hotkey (w
, c
->text
, msg
== WIDGET_FOCUS
);
541 release_hotkey (c
->text
);
545 return default_proc (msg
, parm
);
550 check_event (Gpm_Event
*event
, void *data
)
555 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
556 Dlg_head
*h
= c
->widget
.parent
;
558 dlg_select_widget (c
);
559 if (event
->type
& GPM_UP
){
560 check_callback (w
, WIDGET_KEY
, ' ');
561 check_callback (w
, WIDGET_FOCUS
, 0);
562 h
->callback (h
, w
, DLG_POST_KEY
, ' ', NULL
);
570 check_new (int y
, int x
, int state
, const char *text
)
572 WCheck
*c
= g_new (WCheck
, 1);
574 c
->text
= parse_hotkey (text
);
576 init_widget (&c
->widget
, y
, x
, 1, hotkey_width (c
->text
),
577 check_callback
, check_event
);
578 c
->state
= state
? C_BOOL
: 0;
579 widget_want_hotkey (c
->widget
, 1);
585 save_text_to_clip_file (const char *text
)
590 fname
= g_build_filename (home_dir
, EDIT_CLIP_FILE
, NULL
);
591 file
= mc_open (fname
, O_CREAT
| O_WRONLY
| O_TRUNC
,
592 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
);
598 mc_write (file
, (char *) text
, strlen (text
));
604 load_text_from_clip_file (char **text
)
609 gboolean first
= TRUE
;
611 fname
= g_build_filename (home_dir
, EDIT_CLIP_FILE
, NULL
);
612 f
= fopen (fname
, "r");
620 while (fgets (buf
, sizeof (buf
), f
)) {
625 if (buf
[len
- 1] == '\n')
630 *text
= g_strdup (buf
);
632 /* remove \n on EOL */
635 tmp
= g_strconcat (*text
, " ", buf
, (char *) NULL
);
644 return (*text
!= NULL
);
648 panel_save_curent_file_to_clip_file (void)
652 if (current_panel
->marked
== 0)
653 res
= save_text_to_clip_file (selection (current_panel
)->fname
);
656 gboolean first
= TRUE
;
659 for (i
= 0; i
< current_panel
->count
; i
++)
660 if (current_panel
->dir
.list
[i
].f
.marked
!= 0) { /* Skip the unmarked ones */
662 flist
= g_strdup (current_panel
->dir
.list
[i
].fname
);
665 /* Add empty lines after the file */
668 tmp
= g_strconcat (flist
, "\n", current_panel
->dir
.list
[i
].fname
, (char *) NULL
);
675 res
= save_text_to_clip_file (flist
);
686 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
688 WLabel
*l
= (WLabel
*) w
;
689 Dlg_head
*h
= l
->widget
.parent
;
695 /* We don't want to get the focus */
697 return MSG_NOT_HANDLED
;
701 char *p
= l
->text
, *q
, c
= 0;
708 tty_setcolor (DEFAULT_COLOR
);
710 tty_setcolor (DLG_NORMALC (h
));
713 q
= strchr (p
, '\n');
719 widget_move (&l
->widget
, y
, 0);
720 tty_print_string (str_fit_to_term (p
, l
->widget
.cols
, J_LEFT
));
736 return default_proc (msg
, parm
);
741 label_set_text (WLabel
*label
, const char *text
)
743 int newcols
= label
->widget
.cols
;
746 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
747 return; /* Flickering is not nice */
749 g_free (label
->text
);
752 label
->text
= g_strdup (text
);
753 if (label
->auto_adjust_cols
) {
754 str_msg_term_size (text
, &newlines
, &newcols
);
755 if (newcols
> label
->widget
.cols
)
756 label
->widget
.cols
= newcols
;
757 if (newlines
> label
->widget
.lines
)
758 label
->widget
.lines
= newlines
;
760 } else label
->text
= NULL
;
762 if (label
->widget
.parent
)
763 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
765 if (newcols
< label
->widget
.cols
)
766 label
->widget
.cols
= newcols
;
770 label_new (int y
, int x
, const char *text
)
777 str_msg_term_size (text
, &lines
, &cols
);
779 l
= g_new (WLabel
, 1);
780 init_widget (&l
->widget
, y
, x
, lines
, cols
, label_callback
, NULL
);
781 l
->text
= (text
!= NULL
) ? g_strdup (text
) : NULL
;
782 l
->auto_adjust_cols
= 1;
784 widget_want_cursor (l
->widget
, 0);
789 /* Gauge widget (progress indicator) */
790 /* Currently width is hardcoded here for text mode */
794 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
796 WGauge
*g
= (WGauge
*) w
;
797 Dlg_head
*h
= g
->widget
.parent
;
799 if (msg
== WIDGET_INIT
)
802 /* We don't want to get the focus */
803 if (msg
== WIDGET_FOCUS
)
804 return MSG_NOT_HANDLED
;
806 if (msg
== WIDGET_DRAW
){
807 widget_move (&g
->widget
, 0, 0);
808 tty_setcolor (DLG_NORMALC (h
));
810 tty_printf ("%*s", gauge_len
, "");
812 int percentage
, columns
;
813 long total
= g
->max
, done
= g
->current
;
815 if (total
<= 0 || done
< 0) {
821 while (total
> 65535) {
825 percentage
= (200 * done
/ total
+ 1) / 2;
826 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
827 tty_print_char ('[');
828 tty_setcolor (GAUGE_COLOR
);
829 tty_printf ("%*s", (int) columns
, "");
830 tty_setcolor (DLG_NORMALC (h
));
831 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
836 return default_proc (msg
, parm
);
840 gauge_set_value (WGauge
*g
, int max
, int current
)
842 if (g
->current
== current
&& g
->max
== max
)
843 return; /* Do not flicker */
845 max
= 1; /* I do not like division by zero :) */
847 g
->current
= current
;
849 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
853 gauge_show (WGauge
*g
, int shown
)
855 if (g
->shown
== shown
)
858 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
862 gauge_new (int y
, int x
, int shown
, int max
, int current
)
864 WGauge
*g
= g_new (WGauge
, 1);
866 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
869 max
= 1; /* I do not like division by zero :) */
871 g
->current
= current
;
872 widget_want_cursor (g
->widget
, 0);
879 /* {{{ history button */
881 #define LARGE_HISTORY_BUTTON 1
883 #ifdef LARGE_HISTORY_BUTTON
884 # define HISTORY_BUTTON_WIDTH 3
886 # define HISTORY_BUTTON_WIDTH 1
889 #define should_show_history_button(in) \
890 (in->history && in->field_width > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
892 static void draw_history_button (WInput
* in
)
895 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
896 widget_move (&in
->widget
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
);
897 #ifdef LARGE_HISTORY_BUTTON
900 h
= in
->widget
.parent
;
901 tty_setcolor (NORMAL_COLOR
);
902 tty_print_string ("[ ]");
903 /* Too distracting: tty_setcolor (MARKED_COLOR); */
904 widget_move (&in
->widget
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1);
908 tty_setcolor (MARKED_COLOR
);
913 /* }}} history button */
916 /* Input widgets now have a global kill ring */
917 /* Pointer to killed data */
918 static char *kill_buffer
= 0;
921 update_input (WInput
*in
, int clear_first
)
925 int buf_len
= str_length (in
->buffer
);
929 if (should_show_history_button (in
))
930 has_history
= HISTORY_BUTTON_WIDTH
;
932 if (in
->disable_update
)
935 pw
= str_term_width2 (in
->buffer
, in
->point
);
937 /* Make the point visible */
938 if ((pw
< in
->term_first_shown
) ||
939 (pw
>= in
->term_first_shown
+ in
->field_width
- has_history
)) {
941 in
->term_first_shown
= pw
- (in
->field_width
/ 3);
942 if (in
->term_first_shown
< 0)
943 in
->term_first_shown
= 0;
946 /* Adjust the mark */
947 if (in
->mark
> buf_len
)
951 draw_history_button (in
);
953 tty_setcolor (in
->color
);
955 widget_move (&in
->widget
, 0, 0);
957 if (!in
->is_password
) {
958 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
959 in
->field_width
- has_history
));
962 for (i
= -in
->term_first_shown
; i
< in
->field_width
- has_history
; i
++){
964 tty_print_char ((cp
[0] != '\0') ? '*' : ' ');
966 if (cp
[0] != '\0') str_cnext_char (&cp
);
975 winput_set_origin (WInput
*in
, int x
, int field_width
)
978 in
->field_width
= in
->widget
.cols
= field_width
;
979 update_input (in
, 0);
982 /* {{{ history saving and loading */
984 int num_history_items_recorded
= 60;
987 This loads and saves the history of an input line to and from the
988 widget. It is called with the widgets history name on creation of the
989 widget, and returns the GList list. It stores histories in the file
990 ~/.mc/history in using the profile code.
992 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
993 function) then input_new assigns the default text to be the last text
994 entered, or "" if not found.
998 history_get (const char *input_name
)
1005 size_t keys_num
= 0;
1008 if (!num_history_items_recorded
) /* this is how to disable */
1010 if (!input_name
|| !*input_name
)
1013 profile
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_HISTORY_FILE
, NULL
);
1014 cfg
= mc_config_init (profile
);
1016 /* get number of keys */
1017 keys
= mc_config_get_keys (cfg
, input_name
, &keys_num
);
1020 for (i
= 0; i
< keys_num
; i
++) {
1021 char key_name
[BUF_TINY
];
1022 g_snprintf (key_name
, sizeof (key_name
), "%lu", (unsigned long)i
);
1023 this_entry
= mc_config_get_string (cfg
, input_name
, key_name
, "");
1025 if (this_entry
!= NULL
)
1026 hist
= list_append_unique (hist
, this_entry
);
1029 mc_config_deinit (cfg
);
1032 /* return pointer to the last entry in the list */
1033 return g_list_last (hist
);
1037 history_put (const char *input_name
, GList
*h
)
1052 if (!num_history_items_recorded
) /* this is how to disable */
1055 profile
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_HISTORY_FILE
, NULL
);
1057 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
1060 /* Make sure the history is only readable by the user */
1061 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
1066 /* go to end of list */
1067 h
= g_list_last (h
);
1069 /* go back 60 places */
1070 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
1071 h
= g_list_previous (h
);
1073 cfg
= mc_config_init(profile
);
1076 mc_config_del_group(cfg
,input_name
);
1078 /* dump histories into profile */
1079 for (i
= 0; h
; h
= g_list_next (h
)) {
1080 char *text
= (char *) h
->data
;
1082 /* We shouldn't have null entries, but let's be sure */
1084 char key_name
[BUF_TINY
];
1085 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
1086 mc_config_set_string(cfg
,input_name
, key_name
, text
);
1090 mc_config_save_file (cfg
, NULL
);
1091 mc_config_deinit(cfg
);
1095 /* }}} history saving and loading */
1098 /* {{{ history display */
1103 return _(" History ");
1107 listbox_fwd (WListbox
*l
)
1109 if (l
->current
!= l
->list
->prev
)
1110 listbox_select_entry (l
, l
->current
->next
);
1112 listbox_select_first (l
);
1122 dlg_hist_reposition (Dlg_head
*dlg_head
)
1124 dlg_hist_data
*data
;
1125 int x
= 0, y
, he
, wi
;
1128 if ((dlg_head
== NULL
)
1129 || (dlg_head
->data
== NULL
))
1130 return MSG_NOT_HANDLED
;
1132 data
= (dlg_hist_data
*) dlg_head
->data
;
1134 y
= data
->widget
->y
;
1135 he
= data
->count
+ 2;
1137 if (he
<= y
|| y
> (LINES
- 6)) {
1138 he
= min (he
, y
- 1);
1142 he
= min (he
, LINES
- y
);
1145 if (data
->widget
->x
> 2)
1146 x
= data
->widget
->x
- 2;
1148 wi
= data
->maxlen
+ 4;
1150 if ((wi
+ x
) > COLS
) {
1151 wi
= min (wi
, COLS
);
1155 dlg_set_position (dlg_head
, y
, x
, y
+ he
, x
+ wi
);
1161 dlg_hist_callback (Dlg_head
*h
, Widget
*sender
,
1162 dlg_msg_t msg
, int parm
, void *data
)
1166 return dlg_hist_reposition (h
);
1169 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1174 show_hist (GList
*history
, Widget
*widget
)
1177 size_t maxlen
, i
, count
= 0;
1179 Dlg_head
*query_dlg
;
1180 WListbox
*query_list
;
1181 dlg_hist_data hist_data
;
1183 if (history
== NULL
)
1186 maxlen
= str_term_width1 (i18n_htitle ());
1188 z
= g_list_first (history
);
1191 i
= str_term_width1 ((char *) hi
->data
);
1192 maxlen
= max (maxlen
, i
);
1194 hi
= g_list_next (hi
);
1197 hist_data
.maxlen
= maxlen
;
1198 hist_data
.widget
= widget
;
1199 hist_data
.count
= count
;
1202 create_dlg (0, 0, 4, 4, dialog_colors
, dlg_hist_callback
,
1203 "[History-query]", i18n_htitle (), DLG_COMPACT
);
1204 query_dlg
->data
= &hist_data
;
1206 query_list
= listbox_new (1, 1, 2, 2, NULL
);
1208 /* this call makes list stick to all sides of dialog, effectively make
1209 it be resized with dialog */
1210 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
);
1212 /* to avoid diplicating of (calculating sizes in two places)
1213 code, call dlg_hist_callback function here, to set dialog and
1215 The main idea - create 4x4 dialog and add 2x2 list in
1216 center of it, and let dialog function resize it to needed
1218 dlg_hist_callback (query_dlg
, NULL
, DLG_RESIZE
, 0, NULL
);
1220 if (query_dlg
->y
< widget
->y
) {
1224 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1225 0, (char *) hi
->data
, NULL
);
1226 hi
= g_list_next (hi
);
1228 listbox_select_last (query_list
);
1230 /* traverse backwards */
1231 hi
= g_list_last (history
);
1233 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1234 0, (char *) hi
->data
, NULL
);
1235 hi
= g_list_previous (hi
);
1239 if (run_dlg (query_dlg
) != B_CANCEL
) {
1240 listbox_get_current (query_list
, &q
, NULL
);
1244 destroy_dlg (query_dlg
);
1249 do_show_hist (WInput
*in
)
1252 r
= show_hist (in
->history
, &in
->widget
);
1254 assign_text (in
, r
);
1259 /* }}} history display */
1262 input_destroy (WInput
*in
)
1265 fprintf (stderr
, "Internal error: null Input *\n");
1272 if (!in
->is_password
) /* don't save passwords ;-) */
1273 history_put (in
->history_name
, in
->history
);
1275 in
->history
= g_list_first (in
->history
);
1276 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1277 g_list_free (in
->history
);
1280 g_free (in
->buffer
);
1281 free_completions (in
);
1282 g_free (in
->history_name
);
1286 input_disable_update (WInput
*in
)
1288 in
->disable_update
++;
1292 input_enable_update (WInput
*in
)
1294 in
->disable_update
--;
1295 update_input (in
, 0);
1300 push_history (WInput
*in
, const char *text
)
1302 /* input widget where urls with passwords are entered without any
1304 const char *password_input_fields
[] = {
1305 N_(" Link to a remote machine "),
1306 N_(" FTP to machine "),
1307 N_(" SMB link to machine ")
1309 const size_t ELEMENTS
= (sizeof (password_input_fields
) /
1310 sizeof (password_input_fields
[0]));
1320 for (i
= 0; i
< ELEMENTS
; i
++)
1321 password_input_fields
[i
] = _(password_input_fields
[i
]);
1324 t
= g_strstrip (g_strdup (text
));
1327 t
= g_strdup (empty
? "" : text
);
1329 if (in
->history_name
!= NULL
) {
1330 const char *p
= in
->history_name
+ 3;
1332 for (i
= 0; i
< ELEMENTS
; i
++)
1333 if (strcmp (p
, password_input_fields
[i
]) == 0)
1336 strip_password (t
, i
>= ELEMENTS
);
1339 in
->history
= list_append_unique (in
->history
, t
);
1343 /* Cleans the input line and adds the current text to the history */
1345 new_input (WInput
*in
)
1347 push_history (in
, in
->buffer
);
1349 in
->buffer
[0] = '\0';
1353 free_completions (in
);
1354 update_input (in
, 0);
1358 move_buffer_backward (WInput
*in
, int start
, int end
)
1361 int str_len
= str_length (in
->buffer
);
1362 if (start
>= str_len
|| end
> str_len
+ 1) return;
1364 pos
= str_offset_to_pos (in
->buffer
, start
);
1365 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
1367 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
1368 in
->buffer
[i
] = in
->buffer
[i
+ len
];
1372 insert_char (WInput
*in
, int c_code
)
1378 return MSG_NOT_HANDLED
;
1380 if (in
->charpoint
>= MB_LEN_MAX
)
1383 in
->charbuf
[in
->charpoint
] = c_code
;
1386 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
1389 in
->charpoint
= 0; /* broken multibyte char, skip */
1394 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
){
1395 /* Expand the buffer */
1396 size_t new_length
= in
->current_max_size
+
1397 in
->field_width
+ in
->charpoint
;
1398 char *narea
= g_try_renew (char, in
->buffer
, new_length
);
1401 in
->current_max_size
= new_length
;
1405 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
) {
1406 /* bytes from begin */
1407 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
1409 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
1411 for (i
= rest_bytes
+ 1; i
> 0; i
--)
1412 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] =
1413 in
->buffer
[ins_point
+ i
- 1];
1415 memcpy(in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
1424 beginning_of_line (WInput
*in
)
1431 end_of_line (WInput
*in
)
1433 in
->point
= str_length (in
->buffer
);
1438 backward_char (WInput
*in
)
1440 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1442 if (in
->point
> 0) {
1443 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
1449 forward_char (WInput
*in
)
1451 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1452 if (act
[0] != '\0') {
1453 in
->point
+= str_cnext_noncomb_char (&act
);
1459 forward_word (WInput
* in
)
1461 const char *p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1463 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
))) {
1464 str_cnext_char (&p
);
1467 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
)) {
1468 str_cnext_char (&p
);
1474 backward_word (WInput
*in
)
1480 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1481 (p
!= in
->buffer
) && (p
[0] == '\0');
1482 str_cprev_char (&p
), in
->point
--
1485 while (p
!= in
->buffer
) {
1487 str_cprev_char (&p
);
1488 if (!str_isspace (p
) && !str_ispunct (p
)) {
1494 while (p
!= in
->buffer
) {
1495 str_cprev_char (&p
);
1496 if (str_isspace (p
) || str_ispunct (p
))
1504 key_left (WInput
*in
)
1510 key_ctrl_left (WInput
*in
)
1516 key_right (WInput
*in
)
1522 key_ctrl_right (WInput
*in
)
1527 backward_delete (WInput
*in
)
1529 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1535 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
1536 move_buffer_backward(in
, start
, in
->point
);
1543 delete_char (WInput
*in
)
1545 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1546 int end
= in
->point
;
1548 end
+= str_cnext_noncomb_char (&act
);
1550 move_buffer_backward(in
, in
->point
, end
);
1556 copy_region (WInput
*in
, int x_first
, int x_last
)
1558 int first
= min (x_first
, x_last
);
1559 int last
= max (x_first
, x_last
);
1561 if (last
== first
) {
1562 /* Copy selected files to clipboard */
1563 panel_save_curent_file_to_clip_file ();
1567 g_free (kill_buffer
);
1569 first
= str_offset_to_pos (in
->buffer
, first
);
1570 last
= str_offset_to_pos (in
->buffer
, last
);
1572 kill_buffer
= g_strndup(in
->buffer
+ first
, last
- first
);
1573 save_text_to_clip_file (kill_buffer
);
1577 delete_region (WInput
*in
, int x_first
, int x_last
)
1579 int first
= min (x_first
, x_last
);
1580 int last
= max (x_first
, x_last
);
1584 if (in
->mark
> first
)
1586 last
= str_offset_to_pos (in
->buffer
, last
);
1587 first
= str_offset_to_pos (in
->buffer
, first
);
1588 len
= strlen (&in
->buffer
[last
]) + 1;
1589 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1595 kill_word (WInput
*in
)
1597 int old_point
= in
->point
;
1601 new_point
= in
->point
;
1602 in
->point
= old_point
;
1604 copy_region (in
, old_point
, new_point
);
1605 delete_region (in
, old_point
, new_point
);
1612 back_kill_word (WInput
*in
)
1614 int old_point
= in
->point
;
1618 new_point
= in
->point
;
1619 in
->point
= old_point
;
1621 copy_region (in
, old_point
, new_point
);
1622 delete_region (in
, old_point
, new_point
);
1627 set_mark (WInput
*in
)
1629 in
->mark
= in
->point
;
1633 kill_save (WInput
*in
)
1635 copy_region (in
, in
->mark
, in
->point
);
1639 kill_region (WInput
*in
)
1642 delete_region (in
, in
->point
, in
->mark
);
1646 clear_region (WInput
*in
)
1648 delete_region (in
, in
->point
, in
->mark
);
1659 for (p
= kill_buffer
; *p
; p
++)
1660 insert_char (in
, *p
);
1665 kill_line (WInput
*in
)
1667 int chp
= str_offset_to_pos (in
->buffer
, in
->point
);
1668 g_free (kill_buffer
);
1669 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
1670 in
->buffer
[chp
] = '\0';
1675 ins_from_clip (WInput
*in
)
1679 if (load_text_from_clip_file (&p
)) {
1682 for (pp
= p
; *pp
!= '\0'; pp
++)
1683 insert_char (in
, *pp
);
1690 assign_text (WInput
*in
, const char *text
)
1692 free_completions (in
);
1693 g_free (in
->buffer
);
1694 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1695 in
->current_max_size
= strlen (in
->buffer
) + 1;
1696 in
->point
= str_length (in
->buffer
);
1703 hist_prev (WInput
*in
)
1711 push_history (in
, in
->buffer
);
1713 prev
= g_list_previous (in
->history
);
1716 assign_text (in
, (char *) prev
->data
);
1722 hist_next (WInput
*in
)
1724 if (in
->need_push
) {
1725 push_history (in
, in
->buffer
);
1726 assign_text (in
, "");
1733 if (!in
->history
->next
) {
1734 assign_text (in
, "");
1738 in
->history
= g_list_next (in
->history
);
1739 assign_text (in
, (char *) in
->history
->data
);
1744 port_region_marked_for_delete (WInput
*in
)
1746 in
->buffer
[0] = '\0';
1753 input_execute_cmd (WInput
*in
, unsigned long command
)
1755 cb_ret_t res
= MSG_HANDLED
;
1759 beginning_of_line (in
);
1764 case CK_InputMoveLeft
:
1767 case CK_InputWordLeft
:
1770 case CK_InputMoveRight
:
1773 case CK_InputWordRight
:
1774 key_ctrl_right (in
);
1776 case CK_InputBackwardChar
:
1779 case CK_InputBackwardWord
:
1782 case CK_InputForwardChar
:
1785 case CK_InputForwardWord
:
1788 case CK_InputBackwardDelete
:
1789 backward_delete (in
);
1791 case CK_InputDeleteChar
:
1794 case CK_InputKillWord
:
1797 case CK_InputBackwardKillWord
:
1798 back_kill_word (in
);
1800 case CK_InputSetMark
:
1803 case CK_InputKillRegion
:
1806 case CK_InputClearLine
:
1809 case CK_InputKillSave
:
1818 case CK_InputKillLine
:
1821 case CK_InputHistoryPrev
:
1824 case CK_InputHistoryNext
:
1827 case CK_InputHistoryShow
:
1830 case CK_InputComplete
:
1834 res
= MSG_NOT_HANDLED
;
1840 /* This function is a test for a special input key used in complete.c */
1841 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1842 and 2 if it is a complete key */
1844 is_in_input_map (WInput
*in
, int key
)
1847 for (i
= 0; input_map
[i
].key
!= 0; i
++)
1848 if (key
== input_map
[i
].key
) {
1849 input_execute_cmd (in
, input_map
[i
].command
);
1850 return (input_map
[i
].command
== CK_InputComplete
) ? 2 : 1;
1856 handle_char (WInput
*in
, int key
)
1861 v
= MSG_NOT_HANDLED
;
1864 free_completions (in
);
1865 v
= insert_char (in
, key
);
1866 update_input (in
, 1);
1870 for (i
= 0; input_map
[i
].key
; i
++) {
1871 if (key
== input_map
[i
].key
) {
1872 if (input_map
[i
].command
!= CK_InputComplete
)
1873 free_completions (in
);
1874 input_execute_cmd (in
, input_map
[i
].command
);
1875 update_input (in
, 1);
1880 if (input_map
[i
].command
== 0) {
1882 return MSG_NOT_HANDLED
;
1884 port_region_marked_for_delete (in
);
1885 free_completions (in
);
1886 v
= insert_char (in
, key
);
1888 update_input (in
, 1);
1892 /* Inserts text in input line */
1894 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1896 input_disable_update (in
);
1897 while (*text
!= '\0')
1898 handle_char (in
, (unsigned char) *text
++); /* unsigned extension char->int */
1899 if (insert_extra_space
)
1900 handle_char (in
, ' ');
1901 input_enable_update (in
);
1902 update_input (in
, 1);
1906 input_set_point (WInput
*in
, int pos
)
1908 int max_pos
= str_length (in
->buffer
);
1912 if (pos
!= in
->point
)
1913 free_completions (in
);
1916 update_input (in
, 1);
1920 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1922 WInput
*in
= (WInput
*) w
;
1927 if (parm
== XCTRL ('q')) {
1929 v
= handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1934 /* Keys we want others to handle */
1935 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1936 || parm
== KEY_F (10) || parm
== '\n')
1937 return MSG_NOT_HANDLED
;
1939 /* When pasting multiline text, insert literal Enter */
1940 if ((parm
& ~KEY_M_MASK
) == '\n') {
1942 v
= handle_char (in
, '\n');
1947 return handle_char (in
, parm
);
1949 case WIDGET_COMMAND
:
1950 return input_execute_cmd (in
, parm
);
1953 case WIDGET_UNFOCUS
:
1955 update_input (in
, 0);
1959 widget_move (&in
->widget
, 0, str_term_width2 (in
->buffer
, in
->point
)
1960 - in
->term_first_shown
);
1963 case WIDGET_DESTROY
:
1968 return default_proc (msg
, parm
);
1973 input_event (Gpm_Event
* event
, void *data
)
1977 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1978 dlg_select_widget (in
);
1980 if (event
->x
>= in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1
1981 && should_show_history_button (in
)) {
1984 in
->point
= str_length (in
->buffer
);
1985 if (event
->x
+ in
->term_first_shown
- 1 <
1986 str_term_width1 (in
->buffer
))
1988 in
->point
= str_column_to_pos (in
->buffer
, event
->x
1989 + in
->term_first_shown
- 1);
1992 update_input (in
, 1);
1998 input_new (int y
, int x
, int color
, int width
, const char *def_text
,
1999 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
2001 WInput
*in
= g_new (WInput
, 1);
2002 int initial_buffer_len
;
2004 init_widget (&in
->widget
, y
, x
, 1, width
, input_callback
, input_event
);
2008 in
->history_name
= 0;
2011 in
->history_name
= g_strdup (histname
);
2012 in
->history
= history_get (histname
);
2016 if (def_text
== NULL
)
2019 if (def_text
== INPUT_LAST_TEXT
) {
2022 if (in
->history
->data
)
2023 def_text
= (char *) in
->history
->data
;
2025 initial_buffer_len
= 1 + max ((size_t) width
, strlen (def_text
));
2026 in
->widget
.options
|= W_IS_INPUT
;
2027 in
->completions
= NULL
;
2028 in
->completion_flags
= completion_flags
;
2029 in
->current_max_size
= initial_buffer_len
;
2030 in
->buffer
= g_new (char, initial_buffer_len
);
2032 in
->field_width
= width
;
2034 in
->term_first_shown
= 0;
2035 in
->disable_update
= 0;
2038 in
->is_password
= 0;
2040 strcpy (in
->buffer
, def_text
);
2041 in
->point
= str_length (in
->buffer
);
2046 /* Listbox widget */
2048 /* Should draw the scrollbar, but currently draws only
2049 * indications that there is more information
2051 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
2054 listbox_drawscroll (WListbox
*l
)
2058 int max_line
= l
->widget
.lines
- 1;
2060 /* Are we at the top? */
2061 widget_move (&l
->widget
, 0, l
->widget
.cols
);
2062 if (l
->list
== l
->top
)
2063 tty_print_one_vline ();
2065 tty_print_char ('^');
2067 /* Are we at the bottom? */
2068 widget_move (&l
->widget
, max_line
, l
->widget
.cols
);
2069 top
= listbox_cdiff (l
->list
, l
->top
);
2070 if ((top
+ l
->widget
.lines
== l
->count
) || l
->widget
.lines
>= l
->count
)
2071 tty_print_one_vline ();
2073 tty_print_char ('v');
2075 /* Now draw the nice relative pointer */
2077 line
= 1+ ((l
->pos
* (l
->widget
.lines
- 2)) / l
->count
);
2079 for (i
= 1; i
< max_line
; i
++){
2080 widget_move (&l
->widget
, i
, l
->widget
.cols
);
2082 tty_print_one_vline ();
2084 tty_print_char ('*');
2089 listbox_draw (WListbox
*l
, gboolean focused
)
2091 const Dlg_head
*h
= l
->widget
.parent
;
2092 const int normalc
= DLG_NORMALC (h
);
2093 int selc
= focused
? DLG_HOT_FOCUSC (h
) : DLG_FOCUSC (h
);
2100 for (e
= l
->top
, i
= 0; i
< l
->widget
.lines
; i
++) {
2101 /* Display the entry */
2102 if (e
== l
->current
&& sel_line
== -1) {
2104 tty_setcolor (selc
);
2106 tty_setcolor (normalc
);
2108 widget_move (&l
->widget
, i
, 1);
2110 if ((i
> 0 && e
== l
->list
) || !l
->list
)
2116 tty_print_string (str_fit_to_term (text
, l
->widget
.cols
- 2, J_LEFT_FIT
));
2118 l
->cursor_y
= sel_line
;
2120 if (l
->scrollbar
&& l
->count
> l
->widget
.lines
) {
2121 tty_setcolor (normalc
);
2122 listbox_drawscroll (l
);
2126 /* Returns the number of items between s and e,
2127 must be on the same linked list */
2129 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
2133 for (count
= 0; s
!= e
; count
++)
2139 listbox_check_hotkey (WListbox
*l
, int key
)
2151 /* If we didn't find anything, return */
2152 if (i
&& e
== l
->list
)
2155 if (e
->hotkey
== key
)
2163 /* Selects the last entry and scrolls the list to the bottom */
2165 listbox_select_last (WListbox
*l
)
2168 l
->current
= l
->top
= l
->list
->prev
;
2169 for (i
= min (l
->widget
.lines
, l
->count
) - 1; i
; i
--)
2170 l
->top
= l
->top
->prev
;
2171 l
->pos
= l
->count
- 1;
2174 /* Selects the first entry and scrolls the list to the top */
2176 listbox_select_first (WListbox
*l
)
2178 l
->current
= l
->top
= l
->list
;
2183 listbox_remove_list (WListbox
*l
)
2192 while (l
->count
--) {
2198 l
->pos
= l
->count
= 0;
2199 l
->list
= l
->top
= l
->current
= 0;
2203 * bor 30.10.96: added force flag to remove *last* entry as well
2204 * bor 30.10.96: corrected selection bug if last entry was removed
2208 listbox_remove_current (WListbox
*l
, int force
)
2212 /* Ok, note: this won't allow for emtpy lists */
2213 if (!force
&& (!l
->count
|| l
->count
== 1))
2220 l
->current
->next
->prev
= l
->current
->prev
;
2221 l
->current
->prev
->next
= l
->current
->next
;
2222 if (p
->next
== l
->list
) {
2223 l
->current
= p
->prev
;
2227 l
->current
= p
->next
;
2230 l
->list
= l
->top
= p
->next
;
2233 l
->list
= l
->top
= l
->current
= 0;
2240 /* Makes *e the selected entry (sets current and pos) */
2242 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
2251 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
2259 while (listbox_cdiff (l
->top
, l
->current
) >= l
->widget
.lines
)
2260 l
->top
= l
->top
->next
;
2262 l
->top
= l
->current
;
2268 /* If we are unable to find it, set decent values */
2269 l
->current
= l
->top
= l
->list
;
2273 /* Selects from base the pos element */
2275 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
2277 WLEntry
*last
= l
->list
->prev
;
2290 listbox_back (WListbox
*l
)
2293 listbox_select_entry (l
, l
->current
->prev
);
2295 listbox_select_last (l
);
2298 /* Return MSG_HANDLED if we want a redraw */
2300 listbox_key (WListbox
*l
, int key
)
2304 cb_ret_t j
= MSG_NOT_HANDLED
;
2306 /* focus on listbox item N by '0'..'9' keys */
2307 if (key
>= '0' && key
<= '9') {
2308 int oldpos
= l
->pos
;
2309 listbox_select_by_number(l
, key
- '0');
2311 /* need scroll to item? */
2312 if (abs(oldpos
- l
->pos
) > l
->widget
.lines
)
2313 l
->top
= l
->current
;
2319 return MSG_NOT_HANDLED
;
2325 listbox_select_first (l
);
2331 listbox_select_last (l
);
2346 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2347 && (l
->current
!= l
->list
->prev
)); i
++) {
2355 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2356 && (l
->current
!= l
->list
)); i
++) {
2362 return MSG_NOT_HANDLED
;
2366 listbox_destroy (WListbox
*l
)
2368 WLEntry
*n
, *p
= l
->list
;
2371 for (i
= 0; i
< l
->count
; i
++){
2380 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2382 WListbox
*l
= (WListbox
*) w
;
2383 Dlg_head
*h
= l
->widget
.parent
;
2392 e
= listbox_check_hotkey (l
, parm
);
2396 listbox_select_entry (l
, e
);
2397 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2400 action
= (*l
->cback
) (l
);
2402 action
= LISTBOX_DONE
;
2404 if (action
== LISTBOX_DONE
) {
2405 h
->ret_value
= B_ENTER
;
2410 return MSG_NOT_HANDLED
;
2413 ret_code
= listbox_key (l
, parm
);
2414 if (ret_code
!= MSG_NOT_HANDLED
) {
2415 listbox_draw (l
, TRUE
);
2416 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2421 widget_move (&l
->widget
, l
->cursor_y
, 0);
2422 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2426 case WIDGET_UNFOCUS
:
2428 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2431 case WIDGET_DESTROY
:
2432 listbox_destroy (l
);
2435 case WIDGET_RESIZED
:
2439 return default_proc (msg
, parm
);
2444 listbox_event (Gpm_Event
*event
, void *data
)
2449 Dlg_head
*h
= l
->widget
.parent
;
2452 if (event
->type
& GPM_DOWN
)
2453 dlg_select_widget (l
);
2455 if (l
->list
== NULL
)
2458 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2459 int ret
= MOU_REPEAT
;
2461 if (event
->x
< 0 || event
->x
> l
->widget
.cols
)
2465 for (i
= -event
->y
; i
>= 0; i
--)
2467 else if (event
->y
> l
->widget
.lines
)
2468 for (i
= event
->y
- l
->widget
.lines
; i
> 0; i
--)
2470 else if (event
->buttons
& GPM_B_UP
) {
2473 } else if (event
->buttons
& GPM_B_DOWN
) {
2477 listbox_select_entry (l
,
2478 listbox_select_pos (l
, l
->top
,
2481 /* We need to refresh ourselves since the dialog manager doesn't */
2482 /* know about this event */
2483 listbox_draw (l
, TRUE
);
2488 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2491 if (event
->x
< 0 || event
->x
>= l
->widget
.cols
2492 || event
->y
< 1 || event
->y
> l
->widget
.lines
)
2495 dlg_select_widget (l
);
2496 listbox_select_entry (l
,
2497 listbox_select_pos (l
, l
->top
,
2501 action
= (*l
->cback
) (l
);
2503 action
= LISTBOX_DONE
;
2505 if (action
== LISTBOX_DONE
) {
2506 h
->ret_value
= B_ENTER
;
2515 listbox_new (int y
, int x
, int height
, int width
, lcback callback
)
2517 WListbox
*l
= g_new (WListbox
, 1);
2522 init_widget (&l
->widget
, y
, x
, height
, width
,
2523 listbox_callback
, listbox_event
);
2525 l
->list
= l
->top
= l
->current
= 0;
2528 l
->cback
= callback
;
2529 l
->allow_duplicates
= 1;
2530 l
->scrollbar
= !tty_is_slow ();
2531 widget_want_hotkey (l
->widget
, 1);
2536 /* Listbox item adding function. They still lack a lot of functionality */
2538 /* 1.11.96 bor: added pos argument to control placement of new entry */
2540 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2548 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2550 e
->prev
= l
->list
->prev
;
2551 l
->list
->prev
->next
= e
;
2553 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2554 e
->next
= l
->current
;
2555 e
->prev
= l
->current
->prev
;
2556 l
->current
->prev
->next
= e
;
2557 l
->current
->prev
= e
;
2558 if (l
->list
== l
->current
) { /* move list one position down */
2562 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2563 e
->prev
= l
->current
;
2564 e
->next
= l
->current
->next
;
2565 l
->current
->next
->prev
= e
;
2566 l
->current
->next
= e
;
2567 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2568 WLEntry
*w
= l
->list
;
2570 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2572 if (w
->next
== l
->list
) {
2588 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2589 const char *text
, void *data
)
2596 if (!l
->allow_duplicates
)
2597 if (listbox_search_text (l
, text
))
2600 entry
= g_new (WLEntry
, 1);
2601 entry
->text
= g_strdup (text
);
2603 entry
->hotkey
= hotkey
;
2605 listbox_append_item (l
, entry
, pos
);
2610 /* Selects the nth entry in the listbox */
2612 listbox_select_by_number (WListbox
*l
, int n
)
2614 if (l
->list
!= NULL
)
2615 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2619 listbox_search_text (WListbox
*l
, const char *text
)
2628 if(!strcmp (e
->text
, text
))
2631 } while (e
!=l
->list
);
2636 /* Returns the current string text as well as the associated extra data */
2638 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2644 if (string
&& l
->current
)
2645 *string
= l
->current
->text
;
2646 if (extra
&& l
->current
)
2647 *extra
= l
->current
->data
;
2650 /* returns TRUE if a function has been called, FALSE otherwise. */
2652 buttonbar_call (WButtonBar
*bb
, int i
)
2654 cb_ret_t ret
= MSG_NOT_HANDLED
;
2657 ret
= bb
->widget
.parent
->callback (bb
->widget
.parent
,
2658 (Widget
*) bb
, DLG_ACTION
,
2659 bb
->labels
[i
].command
,
2660 bb
->labels
[i
].receiver
);
2664 /* calculate width of one button, width is never lesser than 7 */
2666 buttonbat_get_button_width (void)
2668 int result
= COLS
/ BUTTONBAR_LABELS_NUM
;
2669 return (result
>= 7) ? result
: 7;
2673 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2675 WButtonBar
*bb
= (WButtonBar
*) w
;
2681 return MSG_NOT_HANDLED
;
2684 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2685 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2687 return MSG_NOT_HANDLED
;
2692 int count_free_positions
;
2694 widget_move (&bb
->widget
, 0, 0);
2695 tty_setcolor (DEFAULT_COLOR
);
2696 bb
->btn_width
= buttonbat_get_button_width ();
2697 tty_printf ("%-*s", bb
->widget
.cols
, "");
2698 count_free_positions
= COLS
- bb
->btn_width
* BUTTONBAR_LABELS_NUM
;
2700 for (i
= 0; i
< COLS
/ bb
->btn_width
&& i
< BUTTONBAR_LABELS_NUM
; i
++) {
2701 widget_move (&bb
->widget
, 0, (i
* bb
->btn_width
) + offset
);
2702 tty_setcolor (BUTTONBAR_HOTKEY_COLOR
);
2703 tty_printf ("%2d", i
+ 1);
2704 tty_setcolor (BUTTONBAR_BUTTON_COLOR
);
2705 text
= (bb
->labels
[i
].text
!= NULL
) ? bb
->labels
[i
].text
: "";
2706 tty_print_string (str_fit_to_term (
2708 bb
->btn_width
- 2 + (int)(offset
< count_free_positions
),
2711 if (count_free_positions
!= 0 && offset
< count_free_positions
)
2717 case WIDGET_DESTROY
:
2718 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2719 g_free (bb
->labels
[i
].text
);
2723 return default_proc (msg
, parm
);
2728 buttonbar_event (Gpm_Event
*event
, void *data
)
2730 WButtonBar
*bb
= data
;
2733 if (!(event
->type
& GPM_UP
))
2737 button
= (event
->x
- 1) * BUTTONBAR_LABELS_NUM
/ COLS
;
2738 if (button
< BUTTONBAR_LABELS_NUM
)
2739 buttonbar_call (bb
, button
);
2744 buttonbar_new (gboolean visible
)
2748 bb
= g_new0 (WButtonBar
, 1);
2750 init_widget (&bb
->widget
, LINES
- 1, 0, 1, COLS
,
2751 buttonbar_callback
, buttonbar_event
);
2752 bb
->widget
.pos_flags
= WPOS_KEEP_HORZ
| WPOS_KEEP_BOTTOM
;
2753 bb
->visible
= visible
;
2754 widget_want_hotkey (bb
->widget
, 1);
2755 widget_want_cursor (bb
->widget
, 0);
2756 bb
->btn_width
= buttonbat_get_button_width ();
2762 set_label_text (WButtonBar
*bb
, int lc_index
, const char *text
)
2764 g_free (bb
->labels
[lc_index
- 1].text
);
2765 bb
->labels
[lc_index
- 1].text
= g_strdup (text
);
2768 /* Find ButtonBar widget in the dialog */
2770 find_buttonbar (const Dlg_head
*h
)
2772 return (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2776 buttonbar_set_label (WButtonBar
*bb
, int idx
, const char *text
,
2777 const struct global_keymap_t
*keymap
, const Widget
*receiver
)
2779 if ((bb
!= NULL
) && (idx
>= 1) && (idx
<= BUTTONBAR_LABELS_NUM
)) {
2780 unsigned long command
= CK_Ignore_Key
;
2783 command
= lookup_keymap_command (keymap
, KEY_F (idx
));
2785 if ((text
== NULL
) || (text
[0] == '\0'))
2786 set_label_text (bb
, idx
, "");
2788 set_label_text (bb
, idx
, text
);
2790 bb
->labels
[idx
- 1].command
= command
;
2791 bb
->labels
[idx
- 1].receiver
= (Widget
*) receiver
;
2796 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2798 bb
->visible
= visible
;
2802 buttonbar_redraw (WButtonBar
*bb
)
2805 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2809 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2811 WGroupbox
*g
= (WGroupbox
*) w
;
2818 return MSG_NOT_HANDLED
;
2821 tty_setcolor (COLOR_NORMAL
);
2822 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2823 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2826 tty_setcolor (COLOR_HOT_NORMAL
);
2827 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2828 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2829 tty_print_string (g
->title
);
2832 case WIDGET_DESTROY
:
2837 return default_proc (msg
, parm
);
2842 groupbox_new (int y
, int x
, int height
, int width
, const char *title
)
2844 WGroupbox
*g
= g_new (WGroupbox
, 1);
2846 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2848 g
->widget
.options
&= ~W_WANT_CURSOR
;
2849 widget_want_hotkey (g
->widget
, 0);
2851 /* Strip existing spaces, add one space before and after the title */
2854 t
= g_strstrip (g_strdup (title
));
2855 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);