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>
43 #include "lib/global.h"
45 #include "lib/tty/tty.h"
47 #include "lib/tty/mouse.h"
48 #include "lib/tty/key.h" /* XCTRL and ALT macros */
49 #include "lib/mcconfig.h" /* for history loading and saving */
50 #include "lib/vfs/mc-vfs/vfs.h"
51 #include "lib/fileloc.h"
52 #include "lib/strutil.h"
58 #include "cmddef.h" /* CK_ cmd name const */
59 #include "keybind.h" /* global_keymap_t */
60 #include "panel.h" /* current_panel */
62 const global_keymap_t
*input_map
;
65 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
67 Dlg_head
*h
= w
->parent
;
72 : DLG_HOT_NORMALC (h
))
79 parse_hotkey (const char *text
)
81 struct hotkey_t result
;
84 /* search for '&', that is not on the of text */
85 cp
= strchr (text
, '&');
86 if (cp
!= NULL
&& cp
[1] != '\0') {
87 result
.start
= g_strndup (text
, cp
- text
);
91 p
= str_cget_next_char (cp
);
92 result
.hotkey
= g_strndup (cp
, p
- cp
);
95 result
.end
= g_strdup (cp
);
97 result
.start
= g_strdup (text
);
105 release_hotkey (const struct hotkey_t hotkey
)
107 g_free (hotkey
.start
);
108 g_free (hotkey
.hotkey
);
113 hotkey_width (const struct hotkey_t hotkey
)
117 result
= str_term_width1 (hotkey
.start
);
118 result
+= (hotkey
.hotkey
!= NULL
) ? str_term_width1 (hotkey
.hotkey
) : 0;
119 result
+= (hotkey
.end
!= NULL
) ? str_term_width1 (hotkey
.end
) : 0;
124 draw_hotkey (Widget
*w
, const struct hotkey_t hotkey
, gboolean focused
)
126 widget_selectcolor (w
, focused
, FALSE
);
127 tty_print_string (hotkey
.start
);
129 if (hotkey
.hotkey
!= NULL
) {
130 widget_selectcolor (w
, focused
, TRUE
);
131 tty_print_string (hotkey
.hotkey
);
132 widget_selectcolor (w
, focused
, FALSE
);
135 if (hotkey
.end
!= NULL
)
136 tty_print_string (hotkey
.end
);
140 /* Default callback for widgets */
142 default_proc (widget_msg_t msg
, int parm
)
157 return MSG_NOT_HANDLED
;
161 static int button_event (Gpm_Event
*event
, void *);
166 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
168 WButton
*b
= (WButton
*) w
;
171 Dlg_head
*h
= b
->widget
.parent
;
176 * Don't let the default button steal Enter from the current
177 * button. This is a workaround for the flawed event model
178 * when hotkeys are sent to all widgets before the key is
179 * handled by the current widget.
181 if (parm
== '\n' && h
->current
== &b
->widget
) {
182 button_callback (w
, WIDGET_KEY
, ' ');
186 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
187 button_callback (w
, WIDGET_KEY
, ' ');
191 if (b
->text
.hotkey
!= NULL
) {
192 if (g_ascii_tolower ((gchar
)b
->text
.hotkey
[0]) ==
193 g_ascii_tolower ((gchar
)parm
)) {
194 button_callback (w
, WIDGET_KEY
, ' ');
198 return MSG_NOT_HANDLED
;
201 if (parm
!= ' ' && parm
!= '\n')
202 return MSG_NOT_HANDLED
;
205 stop
= (*b
->callback
) (b
->action
);
206 if (!b
->callback
|| stop
) {
207 h
->ret_value
= b
->action
;
228 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
234 if (msg
== WIDGET_UNFOCUS
)
236 else if (msg
== WIDGET_FOCUS
)
239 widget_selectcolor (w
, b
->selected
, FALSE
);
240 widget_move (w
, 0, 0);
244 tty_print_string ("[< ");
247 tty_print_string ("[ ");
250 tty_print_string ("[");
257 draw_hotkey (w
, b
->text
, b
->selected
);
261 tty_print_string (" >]");
264 tty_print_string (" ]");
267 tty_print_string ("]");
273 release_hotkey (b
->text
);
277 return default_proc (msg
, parm
);
282 button_event (Gpm_Event
*event
, void *data
)
286 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
287 Dlg_head
*h
= b
->widget
.parent
;
288 dlg_select_widget (b
);
289 if (event
->type
& GPM_UP
){
290 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
291 h
->callback (h
, &b
->widget
, DLG_POST_KEY
, ' ', NULL
);
299 button_get_len (const WButton
*b
)
301 int ret
= hotkey_width (b
->text
);
320 button_new (int y
, int x
, int action
, int flags
, const char *text
,
323 WButton
*b
= g_new (WButton
, 1);
327 b
->text
= parse_hotkey (text
);
329 init_widget (&b
->widget
, y
, x
, 1, button_get_len (b
),
330 button_callback
, button_event
);
333 b
->callback
= callback
;
334 widget_want_hotkey (b
->widget
, 1);
335 b
->hotpos
= (b
->text
.hotkey
!= NULL
) ? str_term_width1 (b
->text
.start
) : -1;
341 button_get_text (const WButton
*b
)
343 if (b
->text
.hotkey
!= NULL
)
344 return g_strconcat (b
->text
.start
, "&", b
->text
.hotkey
,
345 b
->text
.end
, (char *) NULL
);
347 return g_strdup (b
->text
.start
);
351 button_set_text (WButton
*b
, const char *text
)
353 release_hotkey (b
->text
);
354 b
->text
= parse_hotkey (text
);
355 b
->widget
.cols
= button_get_len (b
);
356 dlg_redraw (b
->widget
.parent
);
360 /* Radio button widget */
361 static int radio_event (Gpm_Event
*event
, void *);
364 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
366 WRadio
*r
= (WRadio
*) w
;
368 Dlg_head
*h
= r
->widget
.parent
;
373 int lp
= g_ascii_tolower ((gchar
)parm
);
375 for (i
= 0; i
< r
->count
; i
++) {
376 if (r
->texts
[i
].hotkey
!= NULL
) {
377 int c
= g_ascii_tolower ((gchar
)r
->texts
[i
].hotkey
[0]);
384 radio_callback (w
, WIDGET_KEY
, ' ');
389 return MSG_NOT_HANDLED
;
395 h
->callback (h
, w
, DLG_ACTION
, 0, NULL
);
396 radio_callback (w
, WIDGET_FOCUS
, ' ');
405 return MSG_NOT_HANDLED
;
409 if (r
->count
- 1 > r
->pos
) {
414 return MSG_NOT_HANDLED
;
417 h
->callback (h
, w
, DLG_ACTION
, 0, NULL
);
418 radio_callback (w
, WIDGET_FOCUS
, ' ');
419 widget_move (&r
->widget
, r
->pos
, 1);
425 for (i
= 0; i
< r
->count
; i
++) {
426 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
427 widget_selectcolor (w
, focused
, FALSE
);
428 widget_move (&r
->widget
, i
, 0);
429 tty_print_string ((r
->sel
== i
) ? "(*) " : "( ) ");
430 draw_hotkey (w
, r
->texts
[i
], focused
);
435 for (i
= 0; i
< r
->count
; i
++) {
436 release_hotkey (r
->texts
[i
]);
442 return default_proc (msg
, parm
);
447 radio_event (Gpm_Event
*event
, void *data
)
452 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
453 Dlg_head
*h
= r
->widget
.parent
;
455 r
->pos
= event
->y
- 1;
456 dlg_select_widget (r
);
457 if (event
->type
& GPM_UP
){
458 radio_callback (w
, WIDGET_KEY
, ' ');
459 radio_callback (w
, WIDGET_FOCUS
, 0);
460 h
->callback (h
, w
, DLG_POST_KEY
, ' ', NULL
);
468 radio_new (int y
, int x
, int count
, const char **texts
)
470 WRadio
*result
= g_new (WRadio
, 1);
473 /* Compute the longest string */
474 result
->texts
= g_new (struct hotkey_t
, count
);
477 for (i
= 0; i
< count
; i
++){
478 result
->texts
[i
] = parse_hotkey (texts
[i
]);
479 m
= hotkey_width (result
->texts
[i
]);
484 init_widget (&result
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
488 result
->count
= count
;
489 widget_want_hotkey (result
->widget
, 1);
495 /* Checkbutton widget */
497 static int check_event (Gpm_Event
*event
, void *);
500 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
502 WCheck
*c
= (WCheck
*) w
;
503 Dlg_head
*h
= c
->widget
.parent
;
507 if (c
->text
.hotkey
!= NULL
) {
508 if (g_ascii_tolower ((gchar
)c
->text
.hotkey
[0]) ==
509 g_ascii_tolower ((gchar
)parm
)) {
511 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
515 return MSG_NOT_HANDLED
;
519 return MSG_NOT_HANDLED
;
521 c
->state
^= C_CHANGE
;
522 h
->callback (h
, w
, DLG_ACTION
, 0, NULL
);
523 check_callback (w
, WIDGET_FOCUS
, ' ');
527 widget_move (&c
->widget
, 0, 1);
533 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
534 widget_move (&c
->widget
, 0, 0);
535 tty_print_string ((c
->state
& C_BOOL
) ? "[x] " : "[ ] ");
536 draw_hotkey (w
, c
->text
, msg
== WIDGET_FOCUS
);
540 release_hotkey (c
->text
);
544 return default_proc (msg
, parm
);
549 check_event (Gpm_Event
*event
, void *data
)
554 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
555 Dlg_head
*h
= c
->widget
.parent
;
557 dlg_select_widget (c
);
558 if (event
->type
& GPM_UP
){
559 check_callback (w
, WIDGET_KEY
, ' ');
560 check_callback (w
, WIDGET_FOCUS
, 0);
561 h
->callback (h
, w
, DLG_POST_KEY
, ' ', NULL
);
569 check_new (int y
, int x
, int state
, const char *text
)
571 WCheck
*c
= g_new (WCheck
, 1);
573 c
->text
= parse_hotkey (text
);
575 init_widget (&c
->widget
, y
, x
, 1, hotkey_width (c
->text
),
576 check_callback
, check_event
);
577 c
->state
= state
? C_BOOL
: 0;
578 widget_want_hotkey (c
->widget
, 1);
584 save_text_to_clip_file (const char *text
)
589 fname
= g_build_filename (home_dir
, EDIT_CLIP_FILE
, NULL
);
590 file
= mc_open (fname
, O_CREAT
| O_WRONLY
| O_TRUNC
,
591 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
);
597 mc_write (file
, (char *) text
, strlen (text
));
603 load_text_from_clip_file (char **text
)
608 gboolean first
= TRUE
;
610 fname
= g_build_filename (home_dir
, EDIT_CLIP_FILE
, NULL
);
611 f
= fopen (fname
, "r");
619 while (fgets (buf
, sizeof (buf
), f
)) {
624 if (buf
[len
- 1] == '\n')
629 *text
= g_strdup (buf
);
631 /* remove \n on EOL */
634 tmp
= g_strconcat (*text
, " ", buf
, (char *) NULL
);
643 return (*text
!= NULL
);
647 panel_save_curent_file_to_clip_file (void)
651 if (current_panel
->marked
== 0)
652 res
= save_text_to_clip_file (selection (current_panel
)->fname
);
655 gboolean first
= TRUE
;
658 for (i
= 0; i
< current_panel
->count
; i
++)
659 if (current_panel
->dir
.list
[i
].f
.marked
!= 0) { /* Skip the unmarked ones */
661 flist
= g_strdup (current_panel
->dir
.list
[i
].fname
);
664 /* Add empty lines after the file */
667 tmp
= g_strconcat (flist
, "\n", current_panel
->dir
.list
[i
].fname
, (char *) NULL
);
674 res
= save_text_to_clip_file (flist
);
685 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
687 WLabel
*l
= (WLabel
*) w
;
688 Dlg_head
*h
= l
->widget
.parent
;
694 /* We don't want to get the focus */
696 return MSG_NOT_HANDLED
;
700 char *p
= l
->text
, *q
, c
= 0;
707 tty_setcolor (DEFAULT_COLOR
);
709 tty_setcolor (DLG_NORMALC (h
));
712 q
= strchr (p
, '\n');
718 widget_move (&l
->widget
, y
, 0);
719 tty_print_string (str_fit_to_term (p
, l
->widget
.cols
, J_LEFT
));
735 return default_proc (msg
, parm
);
740 label_set_text (WLabel
*label
, const char *text
)
742 int newcols
= label
->widget
.cols
;
745 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
746 return; /* Flickering is not nice */
748 g_free (label
->text
);
751 label
->text
= g_strdup (text
);
752 if (label
->auto_adjust_cols
) {
753 str_msg_term_size (text
, &newlines
, &newcols
);
754 if (newcols
> label
->widget
.cols
)
755 label
->widget
.cols
= newcols
;
756 if (newlines
> label
->widget
.lines
)
757 label
->widget
.lines
= newlines
;
759 } else label
->text
= NULL
;
761 if (label
->widget
.parent
)
762 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
764 if (newcols
< label
->widget
.cols
)
765 label
->widget
.cols
= newcols
;
769 label_new (int y
, int x
, const char *text
)
776 str_msg_term_size (text
, &lines
, &cols
);
778 l
= g_new (WLabel
, 1);
779 init_widget (&l
->widget
, y
, x
, lines
, cols
, label_callback
, NULL
);
780 l
->text
= (text
!= NULL
) ? g_strdup (text
) : NULL
;
781 l
->auto_adjust_cols
= 1;
783 widget_want_cursor (l
->widget
, 0);
788 /* Gauge widget (progress indicator) */
789 /* Currently width is hardcoded here for text mode */
793 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
795 WGauge
*g
= (WGauge
*) w
;
796 Dlg_head
*h
= g
->widget
.parent
;
798 if (msg
== WIDGET_INIT
)
801 /* We don't want to get the focus */
802 if (msg
== WIDGET_FOCUS
)
803 return MSG_NOT_HANDLED
;
805 if (msg
== WIDGET_DRAW
){
806 widget_move (&g
->widget
, 0, 0);
807 tty_setcolor (DLG_NORMALC (h
));
809 tty_printf ("%*s", gauge_len
, "");
811 int percentage
, columns
;
812 long total
= g
->max
, done
= g
->current
;
814 if (total
<= 0 || done
< 0) {
820 while (total
> 65535) {
824 percentage
= (200 * done
/ total
+ 1) / 2;
825 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
826 tty_print_char ('[');
827 tty_setcolor (GAUGE_COLOR
);
828 tty_printf ("%*s", (int) columns
, "");
829 tty_setcolor (DLG_NORMALC (h
));
830 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
835 return default_proc (msg
, parm
);
839 gauge_set_value (WGauge
*g
, int max
, int current
)
841 if (g
->current
== current
&& g
->max
== max
)
842 return; /* Do not flicker */
844 max
= 1; /* I do not like division by zero :) */
846 g
->current
= current
;
848 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
852 gauge_show (WGauge
*g
, int shown
)
854 if (g
->shown
== shown
)
857 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
861 gauge_new (int y
, int x
, int shown
, int max
, int current
)
863 WGauge
*g
= g_new (WGauge
, 1);
865 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
868 max
= 1; /* I do not like division by zero :) */
870 g
->current
= current
;
871 widget_want_cursor (g
->widget
, 0);
878 /* {{{ history button */
880 #define LARGE_HISTORY_BUTTON 1
882 #ifdef LARGE_HISTORY_BUTTON
883 # define HISTORY_BUTTON_WIDTH 3
885 # define HISTORY_BUTTON_WIDTH 1
888 #define should_show_history_button(in) \
889 (in->history && in->field_width > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
891 static void draw_history_button (WInput
* in
)
894 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
895 widget_move (&in
->widget
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
);
896 #ifdef LARGE_HISTORY_BUTTON
899 h
= in
->widget
.parent
;
900 tty_setcolor (NORMAL_COLOR
);
901 tty_print_string ("[ ]");
902 /* Too distracting: tty_setcolor (MARKED_COLOR); */
903 widget_move (&in
->widget
, 0, in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1);
907 tty_setcolor (MARKED_COLOR
);
912 /* }}} history button */
915 /* Input widgets now have a global kill ring */
916 /* Pointer to killed data */
917 static char *kill_buffer
= 0;
920 update_input (WInput
*in
, int clear_first
)
924 int buf_len
= str_length (in
->buffer
);
928 if (should_show_history_button (in
))
929 has_history
= HISTORY_BUTTON_WIDTH
;
931 if (in
->disable_update
)
934 pw
= str_term_width2 (in
->buffer
, in
->point
);
936 /* Make the point visible */
937 if ((pw
< in
->term_first_shown
) ||
938 (pw
>= in
->term_first_shown
+ in
->field_width
- has_history
)) {
940 in
->term_first_shown
= pw
- (in
->field_width
/ 3);
941 if (in
->term_first_shown
< 0)
942 in
->term_first_shown
= 0;
945 /* Adjust the mark */
946 if (in
->mark
> buf_len
)
950 draw_history_button (in
);
952 tty_setcolor (in
->color
);
954 widget_move (&in
->widget
, 0, 0);
956 if (!in
->is_password
) {
957 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
958 in
->field_width
- has_history
));
961 for (i
= -in
->term_first_shown
; i
< in
->field_width
- has_history
; i
++){
963 tty_print_char ((cp
[0] != '\0') ? '*' : ' ');
965 if (cp
[0] != '\0') str_cnext_char (&cp
);
974 winput_set_origin (WInput
*in
, int x
, int field_width
)
977 in
->field_width
= in
->widget
.cols
= field_width
;
978 update_input (in
, 0);
981 /* {{{ history saving and loading */
983 int num_history_items_recorded
= 60;
986 This loads and saves the history of an input line to and from the
987 widget. It is called with the widgets history name on creation of the
988 widget, and returns the GList list. It stores histories in the file
989 ~/.mc/history in using the profile code.
991 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
992 function) then input_new assigns the default text to be the last text
993 entered, or "" if not found.
997 history_get (const char *input_name
)
1004 size_t keys_num
= 0;
1007 if (!num_history_items_recorded
) /* this is how to disable */
1009 if (!input_name
|| !*input_name
)
1012 profile
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_HISTORY_FILE
, NULL
);
1013 cfg
= mc_config_init (profile
);
1015 /* get number of keys */
1016 keys
= mc_config_get_keys (cfg
, input_name
, &keys_num
);
1019 for (i
= 0; i
< keys_num
; i
++) {
1020 char key_name
[BUF_TINY
];
1021 g_snprintf (key_name
, sizeof (key_name
), "%lu", (unsigned long)i
);
1022 this_entry
= mc_config_get_string (cfg
, input_name
, key_name
, "");
1024 if (this_entry
!= NULL
)
1025 hist
= list_append_unique (hist
, this_entry
);
1028 mc_config_deinit (cfg
);
1031 /* return pointer to the last entry in the list */
1032 return g_list_last (hist
);
1036 history_put (const char *input_name
, GList
*h
)
1051 if (!num_history_items_recorded
) /* this is how to disable */
1054 profile
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_HISTORY_FILE
, NULL
);
1056 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
1059 /* Make sure the history is only readable by the user */
1060 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
1065 /* go to end of list */
1066 h
= g_list_last (h
);
1068 /* go back 60 places */
1069 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
1070 h
= g_list_previous (h
);
1072 cfg
= mc_config_init(profile
);
1075 mc_config_del_group(cfg
,input_name
);
1077 /* dump histories into profile */
1078 for (i
= 0; h
; h
= g_list_next (h
)) {
1079 char *text
= (char *) h
->data
;
1081 /* We shouldn't have null entries, but let's be sure */
1083 char key_name
[BUF_TINY
];
1084 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
1085 mc_config_set_string(cfg
,input_name
, key_name
, text
);
1089 mc_config_save_file (cfg
, NULL
);
1090 mc_config_deinit(cfg
);
1094 /* }}} history saving and loading */
1097 /* {{{ history display */
1102 return _(" History ");
1106 listbox_fwd (WListbox
*l
)
1108 if (l
->current
!= l
->list
->prev
)
1109 listbox_select_entry (l
, l
->current
->next
);
1111 listbox_select_first (l
);
1121 dlg_hist_reposition (Dlg_head
*dlg_head
)
1123 dlg_hist_data
*data
;
1124 int x
= 0, y
, he
, wi
;
1127 if ((dlg_head
== NULL
)
1128 || (dlg_head
->data
== NULL
))
1129 return MSG_NOT_HANDLED
;
1131 data
= (dlg_hist_data
*) dlg_head
->data
;
1133 y
= data
->widget
->y
;
1134 he
= data
->count
+ 2;
1136 if (he
<= y
|| y
> (LINES
- 6)) {
1137 he
= min (he
, y
- 1);
1141 he
= min (he
, LINES
- y
);
1144 if (data
->widget
->x
> 2)
1145 x
= data
->widget
->x
- 2;
1147 wi
= data
->maxlen
+ 4;
1149 if ((wi
+ x
) > COLS
) {
1150 wi
= min (wi
, COLS
);
1154 dlg_set_position (dlg_head
, y
, x
, y
+ he
, x
+ wi
);
1160 dlg_hist_callback (Dlg_head
*h
, Widget
*sender
,
1161 dlg_msg_t msg
, int parm
, void *data
)
1165 return dlg_hist_reposition (h
);
1168 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1173 show_hist (GList
*history
, Widget
*widget
)
1176 size_t maxlen
, i
, count
= 0;
1178 Dlg_head
*query_dlg
;
1179 WListbox
*query_list
;
1180 dlg_hist_data hist_data
;
1182 if (history
== NULL
)
1185 maxlen
= str_term_width1 (i18n_htitle ());
1187 z
= g_list_first (history
);
1190 i
= str_term_width1 ((char *) hi
->data
);
1191 maxlen
= max (maxlen
, i
);
1193 hi
= g_list_next (hi
);
1196 hist_data
.maxlen
= maxlen
;
1197 hist_data
.widget
= widget
;
1198 hist_data
.count
= count
;
1201 create_dlg (0, 0, 4, 4, dialog_colors
, dlg_hist_callback
,
1202 "[History-query]", i18n_htitle (), DLG_COMPACT
);
1203 query_dlg
->data
= &hist_data
;
1205 query_list
= listbox_new (1, 1, 2, 2, NULL
);
1207 /* this call makes list stick to all sides of dialog, effectively make
1208 it be resized with dialog */
1209 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
);
1211 /* to avoid diplicating of (calculating sizes in two places)
1212 code, call dlg_hist_callback function here, to set dialog and
1214 The main idea - create 4x4 dialog and add 2x2 list in
1215 center of it, and let dialog function resize it to needed
1217 dlg_hist_callback (query_dlg
, NULL
, DLG_RESIZE
, 0, NULL
);
1219 if (query_dlg
->y
< widget
->y
) {
1223 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1224 0, (char *) hi
->data
, NULL
);
1225 hi
= g_list_next (hi
);
1227 listbox_select_last (query_list
);
1229 /* traverse backwards */
1230 hi
= g_list_last (history
);
1232 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1233 0, (char *) hi
->data
, NULL
);
1234 hi
= g_list_previous (hi
);
1238 if (run_dlg (query_dlg
) != B_CANCEL
) {
1239 listbox_get_current (query_list
, &q
, NULL
);
1243 destroy_dlg (query_dlg
);
1248 do_show_hist (WInput
*in
)
1251 r
= show_hist (in
->history
, &in
->widget
);
1253 assign_text (in
, r
);
1258 /* }}} history display */
1261 input_destroy (WInput
*in
)
1264 fprintf (stderr
, "Internal error: null Input *\n");
1271 if (!in
->is_password
) /* don't save passwords ;-) */
1272 history_put (in
->history_name
, in
->history
);
1274 in
->history
= g_list_first (in
->history
);
1275 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1276 g_list_free (in
->history
);
1279 g_free (in
->buffer
);
1280 free_completions (in
);
1281 g_free (in
->history_name
);
1285 input_disable_update (WInput
*in
)
1287 in
->disable_update
++;
1291 input_enable_update (WInput
*in
)
1293 in
->disable_update
--;
1294 update_input (in
, 0);
1299 push_history (WInput
*in
, const char *text
)
1301 /* input widget where urls with passwords are entered without any
1303 const char *password_input_fields
[] = {
1304 N_(" Link to a remote machine "),
1305 N_(" FTP to machine "),
1306 N_(" SMB link to machine ")
1308 const size_t ELEMENTS
= (sizeof (password_input_fields
) /
1309 sizeof (password_input_fields
[0]));
1319 for (i
= 0; i
< ELEMENTS
; i
++)
1320 password_input_fields
[i
] = _(password_input_fields
[i
]);
1323 t
= g_strstrip (g_strdup (text
));
1326 t
= g_strdup (empty
? "" : text
);
1328 if (in
->history_name
!= NULL
) {
1329 const char *p
= in
->history_name
+ 3;
1331 for (i
= 0; i
< ELEMENTS
; i
++)
1332 if (strcmp (p
, password_input_fields
[i
]) == 0)
1335 strip_password (t
, i
>= ELEMENTS
);
1338 in
->history
= list_append_unique (in
->history
, t
);
1342 /* Cleans the input line and adds the current text to the history */
1344 new_input (WInput
*in
)
1346 push_history (in
, in
->buffer
);
1348 in
->buffer
[0] = '\0';
1352 free_completions (in
);
1353 update_input (in
, 0);
1357 move_buffer_backward (WInput
*in
, int start
, int end
)
1360 int str_len
= str_length (in
->buffer
);
1361 if (start
>= str_len
|| end
> str_len
+ 1) return;
1363 pos
= str_offset_to_pos (in
->buffer
, start
);
1364 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
1366 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
1367 in
->buffer
[i
] = in
->buffer
[i
+ len
];
1371 insert_char (WInput
*in
, int c_code
)
1377 return MSG_NOT_HANDLED
;
1379 if (in
->charpoint
>= MB_LEN_MAX
)
1382 in
->charbuf
[in
->charpoint
] = c_code
;
1385 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
1388 in
->charpoint
= 0; /* broken multibyte char, skip */
1393 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
){
1394 /* Expand the buffer */
1395 size_t new_length
= in
->current_max_size
+
1396 in
->field_width
+ in
->charpoint
;
1397 char *narea
= g_try_renew (char, in
->buffer
, new_length
);
1400 in
->current_max_size
= new_length
;
1404 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
) {
1405 /* bytes from begin */
1406 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
1408 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
1410 for (i
= rest_bytes
+ 1; i
> 0; i
--)
1411 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] =
1412 in
->buffer
[ins_point
+ i
- 1];
1414 memcpy(in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
1423 beginning_of_line (WInput
*in
)
1430 end_of_line (WInput
*in
)
1432 in
->point
= str_length (in
->buffer
);
1437 backward_char (WInput
*in
)
1439 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1441 if (in
->point
> 0) {
1442 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
1448 forward_char (WInput
*in
)
1450 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1451 if (act
[0] != '\0') {
1452 in
->point
+= str_cnext_noncomb_char (&act
);
1458 forward_word (WInput
* in
)
1460 const char *p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1462 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
))) {
1463 str_cnext_char (&p
);
1466 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
)) {
1467 str_cnext_char (&p
);
1473 backward_word (WInput
*in
)
1479 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1480 (p
!= in
->buffer
) && (p
[0] == '\0');
1481 str_cprev_char (&p
), in
->point
--
1484 while (p
!= in
->buffer
) {
1486 str_cprev_char (&p
);
1487 if (!str_isspace (p
) && !str_ispunct (p
)) {
1493 while (p
!= in
->buffer
) {
1494 str_cprev_char (&p
);
1495 if (str_isspace (p
) || str_ispunct (p
))
1503 key_left (WInput
*in
)
1509 key_ctrl_left (WInput
*in
)
1515 key_right (WInput
*in
)
1521 key_ctrl_right (WInput
*in
)
1526 backward_delete (WInput
*in
)
1528 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1534 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
1535 move_buffer_backward(in
, start
, in
->point
);
1542 delete_char (WInput
*in
)
1544 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1545 int end
= in
->point
;
1547 end
+= str_cnext_noncomb_char (&act
);
1549 move_buffer_backward(in
, in
->point
, end
);
1555 copy_region (WInput
*in
, int x_first
, int x_last
)
1557 int first
= min (x_first
, x_last
);
1558 int last
= max (x_first
, x_last
);
1560 if (last
== first
) {
1561 /* Copy selected files to clipboard */
1562 panel_save_curent_file_to_clip_file ();
1566 g_free (kill_buffer
);
1568 first
= str_offset_to_pos (in
->buffer
, first
);
1569 last
= str_offset_to_pos (in
->buffer
, last
);
1571 kill_buffer
= g_strndup(in
->buffer
+ first
, last
- first
);
1572 save_text_to_clip_file (kill_buffer
);
1576 delete_region (WInput
*in
, int x_first
, int x_last
)
1578 int first
= min (x_first
, x_last
);
1579 int last
= max (x_first
, x_last
);
1583 if (in
->mark
> first
)
1585 last
= str_offset_to_pos (in
->buffer
, last
);
1586 first
= str_offset_to_pos (in
->buffer
, first
);
1587 len
= strlen (&in
->buffer
[last
]) + 1;
1588 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1594 kill_word (WInput
*in
)
1596 int old_point
= in
->point
;
1600 new_point
= in
->point
;
1601 in
->point
= old_point
;
1603 copy_region (in
, old_point
, new_point
);
1604 delete_region (in
, old_point
, new_point
);
1611 back_kill_word (WInput
*in
)
1613 int old_point
= in
->point
;
1617 new_point
= in
->point
;
1618 in
->point
= old_point
;
1620 copy_region (in
, old_point
, new_point
);
1621 delete_region (in
, old_point
, new_point
);
1626 set_mark (WInput
*in
)
1628 in
->mark
= in
->point
;
1632 kill_save (WInput
*in
)
1634 copy_region (in
, in
->mark
, in
->point
);
1638 kill_region (WInput
*in
)
1641 delete_region (in
, in
->point
, in
->mark
);
1645 clear_region (WInput
*in
)
1647 delete_region (in
, in
->point
, in
->mark
);
1658 for (p
= kill_buffer
; *p
; p
++)
1659 insert_char (in
, *p
);
1664 kill_line (WInput
*in
)
1666 int chp
= str_offset_to_pos (in
->buffer
, in
->point
);
1667 g_free (kill_buffer
);
1668 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
1669 in
->buffer
[chp
] = '\0';
1674 ins_from_clip (WInput
*in
)
1678 if (load_text_from_clip_file (&p
)) {
1681 for (pp
= p
; *pp
!= '\0'; pp
++)
1682 insert_char (in
, *pp
);
1689 assign_text (WInput
*in
, const char *text
)
1691 free_completions (in
);
1692 g_free (in
->buffer
);
1693 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1694 in
->current_max_size
= strlen (in
->buffer
) + 1;
1695 in
->point
= str_length (in
->buffer
);
1702 hist_prev (WInput
*in
)
1710 push_history (in
, in
->buffer
);
1712 prev
= g_list_previous (in
->history
);
1715 assign_text (in
, (char *) prev
->data
);
1721 hist_next (WInput
*in
)
1723 if (in
->need_push
) {
1724 push_history (in
, in
->buffer
);
1725 assign_text (in
, "");
1732 if (!in
->history
->next
) {
1733 assign_text (in
, "");
1737 in
->history
= g_list_next (in
->history
);
1738 assign_text (in
, (char *) in
->history
->data
);
1743 port_region_marked_for_delete (WInput
*in
)
1745 in
->buffer
[0] = '\0';
1752 input_execute_cmd (WInput
*in
, unsigned long command
)
1754 cb_ret_t res
= MSG_HANDLED
;
1758 beginning_of_line (in
);
1763 case CK_InputMoveLeft
:
1766 case CK_InputWordLeft
:
1769 case CK_InputMoveRight
:
1772 case CK_InputWordRight
:
1773 key_ctrl_right (in
);
1775 case CK_InputBackwardChar
:
1778 case CK_InputBackwardWord
:
1781 case CK_InputForwardChar
:
1784 case CK_InputForwardWord
:
1787 case CK_InputBackwardDelete
:
1788 backward_delete (in
);
1790 case CK_InputDeleteChar
:
1793 case CK_InputKillWord
:
1796 case CK_InputBackwardKillWord
:
1797 back_kill_word (in
);
1799 case CK_InputSetMark
:
1802 case CK_InputKillRegion
:
1805 case CK_InputClearLine
:
1808 case CK_InputKillSave
:
1817 case CK_InputKillLine
:
1820 case CK_InputHistoryPrev
:
1823 case CK_InputHistoryNext
:
1826 case CK_InputHistoryShow
:
1829 case CK_InputComplete
:
1833 res
= MSG_NOT_HANDLED
;
1839 /* This function is a test for a special input key used in complete.c */
1840 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1841 and 2 if it is a complete key */
1843 is_in_input_map (WInput
*in
, int key
)
1846 for (i
= 0; input_map
[i
].key
!= 0; i
++)
1847 if (key
== input_map
[i
].key
) {
1848 input_execute_cmd (in
, input_map
[i
].command
);
1849 return (input_map
[i
].command
== CK_InputComplete
) ? 2 : 1;
1855 handle_char (WInput
*in
, int key
)
1860 v
= MSG_NOT_HANDLED
;
1863 free_completions (in
);
1864 v
= insert_char (in
, key
);
1865 update_input (in
, 1);
1869 for (i
= 0; input_map
[i
].key
; i
++) {
1870 if (key
== input_map
[i
].key
) {
1871 if (input_map
[i
].command
!= CK_InputComplete
)
1872 free_completions (in
);
1873 input_execute_cmd (in
, input_map
[i
].command
);
1874 update_input (in
, 1);
1879 if (input_map
[i
].command
== 0) {
1881 return MSG_NOT_HANDLED
;
1883 port_region_marked_for_delete (in
);
1884 free_completions (in
);
1885 v
= insert_char (in
, key
);
1887 update_input (in
, 1);
1891 /* Inserts text in input line */
1893 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1895 input_disable_update (in
);
1896 while (*text
!= '\0')
1897 handle_char (in
, (unsigned char) *text
++); /* unsigned extension char->int */
1898 if (insert_extra_space
)
1899 handle_char (in
, ' ');
1900 input_enable_update (in
);
1901 update_input (in
, 1);
1905 input_set_point (WInput
*in
, int pos
)
1907 int max_pos
= str_length (in
->buffer
);
1911 if (pos
!= in
->point
)
1912 free_completions (in
);
1915 update_input (in
, 1);
1919 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1921 WInput
*in
= (WInput
*) w
;
1926 if (parm
== XCTRL ('q')) {
1928 v
= handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1933 /* Keys we want others to handle */
1934 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1935 || parm
== KEY_F (10) || parm
== '\n')
1936 return MSG_NOT_HANDLED
;
1938 /* When pasting multiline text, insert literal Enter */
1939 if ((parm
& ~KEY_M_MASK
) == '\n') {
1941 v
= handle_char (in
, '\n');
1946 return handle_char (in
, parm
);
1948 case WIDGET_COMMAND
:
1949 return input_execute_cmd (in
, parm
);
1952 case WIDGET_UNFOCUS
:
1954 update_input (in
, 0);
1958 widget_move (&in
->widget
, 0, str_term_width2 (in
->buffer
, in
->point
)
1959 - in
->term_first_shown
);
1962 case WIDGET_DESTROY
:
1967 return default_proc (msg
, parm
);
1972 input_event (Gpm_Event
* event
, void *data
)
1976 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1977 dlg_select_widget (in
);
1979 if (event
->x
>= in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1
1980 && should_show_history_button (in
)) {
1983 in
->point
= str_length (in
->buffer
);
1984 if (event
->x
+ in
->term_first_shown
- 1 <
1985 str_term_width1 (in
->buffer
))
1987 in
->point
= str_column_to_pos (in
->buffer
, event
->x
1988 + in
->term_first_shown
- 1);
1991 update_input (in
, 1);
1997 input_new (int y
, int x
, int color
, int width
, const char *def_text
,
1998 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
2000 WInput
*in
= g_new (WInput
, 1);
2001 int initial_buffer_len
;
2003 init_widget (&in
->widget
, y
, x
, 1, width
, input_callback
, input_event
);
2007 in
->history_name
= 0;
2010 in
->history_name
= g_strdup (histname
);
2011 in
->history
= history_get (histname
);
2015 if (def_text
== NULL
)
2018 if (def_text
== INPUT_LAST_TEXT
) {
2021 if (in
->history
->data
)
2022 def_text
= (char *) in
->history
->data
;
2024 initial_buffer_len
= 1 + max ((size_t) width
, strlen (def_text
));
2025 in
->widget
.options
|= W_IS_INPUT
;
2026 in
->completions
= NULL
;
2027 in
->completion_flags
= completion_flags
;
2028 in
->current_max_size
= initial_buffer_len
;
2029 in
->buffer
= g_new (char, initial_buffer_len
);
2031 in
->field_width
= width
;
2033 in
->term_first_shown
= 0;
2034 in
->disable_update
= 0;
2037 in
->is_password
= 0;
2039 strcpy (in
->buffer
, def_text
);
2040 in
->point
= str_length (in
->buffer
);
2045 /* Listbox widget */
2047 /* Should draw the scrollbar, but currently draws only
2048 * indications that there is more information
2050 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
2053 listbox_drawscroll (WListbox
*l
)
2057 int max_line
= l
->widget
.lines
- 1;
2059 /* Are we at the top? */
2060 widget_move (&l
->widget
, 0, l
->widget
.cols
);
2061 if (l
->list
== l
->top
)
2062 tty_print_one_vline ();
2064 tty_print_char ('^');
2066 /* Are we at the bottom? */
2067 widget_move (&l
->widget
, max_line
, l
->widget
.cols
);
2068 top
= listbox_cdiff (l
->list
, l
->top
);
2069 if ((top
+ l
->widget
.lines
== l
->count
) || l
->widget
.lines
>= l
->count
)
2070 tty_print_one_vline ();
2072 tty_print_char ('v');
2074 /* Now draw the nice relative pointer */
2076 line
= 1+ ((l
->pos
* (l
->widget
.lines
- 2)) / l
->count
);
2078 for (i
= 1; i
< max_line
; i
++){
2079 widget_move (&l
->widget
, i
, l
->widget
.cols
);
2081 tty_print_one_vline ();
2083 tty_print_char ('*');
2088 listbox_draw (WListbox
*l
, gboolean focused
)
2090 const Dlg_head
*h
= l
->widget
.parent
;
2091 const int normalc
= DLG_NORMALC (h
);
2092 int selc
= focused
? DLG_HOT_FOCUSC (h
) : DLG_FOCUSC (h
);
2099 for (e
= l
->top
, i
= 0; i
< l
->widget
.lines
; i
++) {
2100 /* Display the entry */
2101 if (e
== l
->current
&& sel_line
== -1) {
2103 tty_setcolor (selc
);
2105 tty_setcolor (normalc
);
2107 widget_move (&l
->widget
, i
, 1);
2109 if ((i
> 0 && e
== l
->list
) || !l
->list
)
2115 tty_print_string (str_fit_to_term (text
, l
->widget
.cols
- 2, J_LEFT_FIT
));
2117 l
->cursor_y
= sel_line
;
2119 if (l
->scrollbar
&& l
->count
> l
->widget
.lines
) {
2120 tty_setcolor (normalc
);
2121 listbox_drawscroll (l
);
2125 /* Returns the number of items between s and e,
2126 must be on the same linked list */
2128 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
2132 for (count
= 0; s
!= e
; count
++)
2138 listbox_check_hotkey (WListbox
*l
, int key
)
2150 /* If we didn't find anything, return */
2151 if (i
&& e
== l
->list
)
2154 if (e
->hotkey
== key
)
2162 /* Selects the last entry and scrolls the list to the bottom */
2164 listbox_select_last (WListbox
*l
)
2167 l
->current
= l
->top
= l
->list
->prev
;
2168 for (i
= min (l
->widget
.lines
, l
->count
) - 1; i
; i
--)
2169 l
->top
= l
->top
->prev
;
2170 l
->pos
= l
->count
- 1;
2173 /* Selects the first entry and scrolls the list to the top */
2175 listbox_select_first (WListbox
*l
)
2177 l
->current
= l
->top
= l
->list
;
2182 listbox_remove_list (WListbox
*l
)
2191 while (l
->count
--) {
2197 l
->pos
= l
->count
= 0;
2198 l
->list
= l
->top
= l
->current
= 0;
2202 * bor 30.10.96: added force flag to remove *last* entry as well
2203 * bor 30.10.96: corrected selection bug if last entry was removed
2207 listbox_remove_current (WListbox
*l
, int force
)
2211 /* Ok, note: this won't allow for emtpy lists */
2212 if (!force
&& (!l
->count
|| l
->count
== 1))
2219 l
->current
->next
->prev
= l
->current
->prev
;
2220 l
->current
->prev
->next
= l
->current
->next
;
2221 if (p
->next
== l
->list
) {
2222 l
->current
= p
->prev
;
2226 l
->current
= p
->next
;
2229 l
->list
= l
->top
= p
->next
;
2232 l
->list
= l
->top
= l
->current
= 0;
2239 /* Makes *e the selected entry (sets current and pos) */
2241 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
2250 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
2258 while (listbox_cdiff (l
->top
, l
->current
) >= l
->widget
.lines
)
2259 l
->top
= l
->top
->next
;
2261 l
->top
= l
->current
;
2267 /* If we are unable to find it, set decent values */
2268 l
->current
= l
->top
= l
->list
;
2272 /* Selects from base the pos element */
2274 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
2276 WLEntry
*last
= l
->list
->prev
;
2289 listbox_back (WListbox
*l
)
2292 listbox_select_entry (l
, l
->current
->prev
);
2294 listbox_select_last (l
);
2297 /* Return MSG_HANDLED if we want a redraw */
2299 listbox_key (WListbox
*l
, int key
)
2303 cb_ret_t j
= MSG_NOT_HANDLED
;
2305 /* focus on listbox item N by '0'..'9' keys */
2306 if (key
>= '0' && key
<= '9') {
2307 int oldpos
= l
->pos
;
2308 listbox_select_by_number(l
, key
- '0');
2310 /* need scroll to item? */
2311 if (abs(oldpos
- l
->pos
) > l
->widget
.lines
)
2312 l
->top
= l
->current
;
2318 return MSG_NOT_HANDLED
;
2324 listbox_select_first (l
);
2330 listbox_select_last (l
);
2345 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2346 && (l
->current
!= l
->list
->prev
)); i
++) {
2354 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2355 && (l
->current
!= l
->list
)); i
++) {
2361 return MSG_NOT_HANDLED
;
2365 listbox_destroy (WListbox
*l
)
2367 WLEntry
*n
, *p
= l
->list
;
2370 for (i
= 0; i
< l
->count
; i
++){
2379 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2381 WListbox
*l
= (WListbox
*) w
;
2382 Dlg_head
*h
= l
->widget
.parent
;
2391 e
= listbox_check_hotkey (l
, parm
);
2395 listbox_select_entry (l
, e
);
2396 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2399 action
= (*l
->cback
) (l
);
2401 action
= LISTBOX_DONE
;
2403 if (action
== LISTBOX_DONE
) {
2404 h
->ret_value
= B_ENTER
;
2409 return MSG_NOT_HANDLED
;
2412 ret_code
= listbox_key (l
, parm
);
2413 if (ret_code
!= MSG_NOT_HANDLED
) {
2414 listbox_draw (l
, TRUE
);
2415 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2420 widget_move (&l
->widget
, l
->cursor_y
, 0);
2421 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2425 case WIDGET_UNFOCUS
:
2427 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2430 case WIDGET_DESTROY
:
2431 listbox_destroy (l
);
2434 case WIDGET_RESIZED
:
2438 return default_proc (msg
, parm
);
2443 listbox_event (Gpm_Event
*event
, void *data
)
2448 Dlg_head
*h
= l
->widget
.parent
;
2451 if (event
->type
& GPM_DOWN
)
2452 dlg_select_widget (l
);
2454 if (l
->list
== NULL
)
2457 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2458 int ret
= MOU_REPEAT
;
2460 if (event
->x
< 0 || event
->x
> l
->widget
.cols
)
2464 for (i
= -event
->y
; i
>= 0; i
--)
2466 else if (event
->y
> l
->widget
.lines
)
2467 for (i
= event
->y
- l
->widget
.lines
; i
> 0; i
--)
2469 else if (event
->buttons
& GPM_B_UP
) {
2472 } else if (event
->buttons
& GPM_B_DOWN
) {
2476 listbox_select_entry (l
,
2477 listbox_select_pos (l
, l
->top
,
2480 /* We need to refresh ourselves since the dialog manager doesn't */
2481 /* know about this event */
2482 listbox_draw (l
, TRUE
);
2487 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2490 if (event
->x
< 0 || event
->x
>= l
->widget
.cols
2491 || event
->y
< 1 || event
->y
> l
->widget
.lines
)
2494 dlg_select_widget (l
);
2495 listbox_select_entry (l
,
2496 listbox_select_pos (l
, l
->top
,
2500 action
= (*l
->cback
) (l
);
2502 action
= LISTBOX_DONE
;
2504 if (action
== LISTBOX_DONE
) {
2505 h
->ret_value
= B_ENTER
;
2514 listbox_new (int y
, int x
, int height
, int width
, lcback callback
)
2516 WListbox
*l
= g_new (WListbox
, 1);
2521 init_widget (&l
->widget
, y
, x
, height
, width
,
2522 listbox_callback
, listbox_event
);
2524 l
->list
= l
->top
= l
->current
= 0;
2527 l
->cback
= callback
;
2528 l
->allow_duplicates
= 1;
2529 l
->scrollbar
= !tty_is_slow ();
2530 widget_want_hotkey (l
->widget
, 1);
2535 /* Listbox item adding function. They still lack a lot of functionality */
2537 /* 1.11.96 bor: added pos argument to control placement of new entry */
2539 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2547 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2549 e
->prev
= l
->list
->prev
;
2550 l
->list
->prev
->next
= e
;
2552 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2553 e
->next
= l
->current
;
2554 e
->prev
= l
->current
->prev
;
2555 l
->current
->prev
->next
= e
;
2556 l
->current
->prev
= e
;
2557 if (l
->list
== l
->current
) { /* move list one position down */
2561 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2562 e
->prev
= l
->current
;
2563 e
->next
= l
->current
->next
;
2564 l
->current
->next
->prev
= e
;
2565 l
->current
->next
= e
;
2566 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2567 WLEntry
*w
= l
->list
;
2569 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2571 if (w
->next
== l
->list
) {
2587 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2588 const char *text
, void *data
)
2595 if (!l
->allow_duplicates
)
2596 if (listbox_search_text (l
, text
))
2599 entry
= g_new (WLEntry
, 1);
2600 entry
->text
= g_strdup (text
);
2602 entry
->hotkey
= hotkey
;
2604 listbox_append_item (l
, entry
, pos
);
2609 /* Selects the nth entry in the listbox */
2611 listbox_select_by_number (WListbox
*l
, int n
)
2613 if (l
->list
!= NULL
)
2614 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2618 listbox_search_text (WListbox
*l
, const char *text
)
2627 if(!strcmp (e
->text
, text
))
2630 } while (e
!=l
->list
);
2635 /* Returns the current string text as well as the associated extra data */
2637 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2643 if (string
&& l
->current
)
2644 *string
= l
->current
->text
;
2645 if (extra
&& l
->current
)
2646 *extra
= l
->current
->data
;
2649 /* returns TRUE if a function has been called, FALSE otherwise. */
2651 buttonbar_call (WButtonBar
*bb
, int i
)
2653 cb_ret_t ret
= MSG_NOT_HANDLED
;
2656 ret
= bb
->widget
.parent
->callback (bb
->widget
.parent
,
2657 (Widget
*) bb
, DLG_ACTION
,
2658 bb
->labels
[i
].command
,
2659 bb
->labels
[i
].receiver
);
2663 /* calculate width of one button, width is never lesser than 7 */
2665 buttonbat_get_button_width (void)
2667 int result
= COLS
/ BUTTONBAR_LABELS_NUM
;
2668 return (result
>= 7) ? result
: 7;
2672 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2674 WButtonBar
*bb
= (WButtonBar
*) w
;
2680 return MSG_NOT_HANDLED
;
2683 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2684 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2686 return MSG_NOT_HANDLED
;
2691 int count_free_positions
;
2693 widget_move (&bb
->widget
, 0, 0);
2694 tty_setcolor (DEFAULT_COLOR
);
2695 bb
->btn_width
= buttonbat_get_button_width ();
2696 tty_printf ("%-*s", bb
->widget
.cols
, "");
2697 count_free_positions
= COLS
- bb
->btn_width
* BUTTONBAR_LABELS_NUM
;
2699 for (i
= 0; i
< COLS
/ bb
->btn_width
&& i
< BUTTONBAR_LABELS_NUM
; i
++) {
2700 widget_move (&bb
->widget
, 0, (i
* bb
->btn_width
) + offset
);
2701 tty_setcolor (BUTTONBAR_HOTKEY_COLOR
);
2702 tty_printf ("%2d", i
+ 1);
2703 tty_setcolor (BUTTONBAR_BUTTON_COLOR
);
2704 text
= (bb
->labels
[i
].text
!= NULL
) ? bb
->labels
[i
].text
: "";
2705 tty_print_string (str_fit_to_term (
2707 bb
->btn_width
- 2 + (int)(offset
< count_free_positions
),
2710 if (count_free_positions
!= 0 && offset
< count_free_positions
)
2716 case WIDGET_DESTROY
:
2717 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2718 g_free (bb
->labels
[i
].text
);
2722 return default_proc (msg
, parm
);
2727 buttonbar_event (Gpm_Event
*event
, void *data
)
2729 WButtonBar
*bb
= data
;
2732 if (!(event
->type
& GPM_UP
))
2736 button
= (event
->x
- 1) * BUTTONBAR_LABELS_NUM
/ COLS
;
2737 if (button
< BUTTONBAR_LABELS_NUM
)
2738 buttonbar_call (bb
, button
);
2743 buttonbar_new (gboolean visible
)
2747 bb
= g_new0 (WButtonBar
, 1);
2749 init_widget (&bb
->widget
, LINES
- 1, 0, 1, COLS
,
2750 buttonbar_callback
, buttonbar_event
);
2751 bb
->widget
.pos_flags
= WPOS_KEEP_HORZ
| WPOS_KEEP_BOTTOM
;
2752 bb
->visible
= visible
;
2753 widget_want_hotkey (bb
->widget
, 1);
2754 widget_want_cursor (bb
->widget
, 0);
2755 bb
->btn_width
= buttonbat_get_button_width ();
2761 set_label_text (WButtonBar
*bb
, int lc_index
, const char *text
)
2763 g_free (bb
->labels
[lc_index
- 1].text
);
2764 bb
->labels
[lc_index
- 1].text
= g_strdup (text
);
2767 /* Find ButtonBar widget in the dialog */
2769 find_buttonbar (const Dlg_head
*h
)
2771 return (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2775 buttonbar_set_label (WButtonBar
*bb
, int idx
, const char *text
,
2776 const struct global_keymap_t
*keymap
, const Widget
*receiver
)
2778 if ((bb
!= NULL
) && (idx
>= 1) && (idx
<= BUTTONBAR_LABELS_NUM
)) {
2779 unsigned long command
= CK_Ignore_Key
;
2782 command
= lookup_keymap_command (keymap
, KEY_F (idx
));
2784 if ((text
== NULL
) || (text
[0] == '\0'))
2785 set_label_text (bb
, idx
, "");
2787 set_label_text (bb
, idx
, text
);
2789 bb
->labels
[idx
- 1].command
= command
;
2790 bb
->labels
[idx
- 1].receiver
= (Widget
*) receiver
;
2795 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2797 bb
->visible
= visible
;
2801 buttonbar_redraw (WButtonBar
*bb
)
2804 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2808 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2810 WGroupbox
*g
= (WGroupbox
*) w
;
2817 return MSG_NOT_HANDLED
;
2820 tty_setcolor (COLOR_NORMAL
);
2821 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2822 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2825 tty_setcolor (COLOR_HOT_NORMAL
);
2826 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2827 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2828 tty_print_string (g
->title
);
2831 case WIDGET_DESTROY
:
2836 return default_proc (msg
, parm
);
2841 groupbox_new (int y
, int x
, int height
, int width
, const char *title
)
2843 WGroupbox
*g
= g_new (WGroupbox
, 1);
2845 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2847 g
->widget
.options
&= ~W_WANT_CURSOR
;
2848 widget_want_hotkey (g
->widget
, 0);
2850 /* Strip existing spaces, add one space before and after the title */
2853 t
= g_strstrip (g_strdup (title
));
2854 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);