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 */
50 #include "../src/mcconfig/mcconfig.h" /* for history loading and saving */
57 #include "cmddef.h" /* CK_ cmd name const */
58 #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
,
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
&& *this_entry
)
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
)) {
1081 text
= (char *) h
->data
;
1083 /* We shouldn't have null entries, but let's be sure */
1084 if (text
&& *text
) {
1085 char key_name
[BUF_TINY
];
1086 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
1087 mc_config_set_string(cfg
,input_name
, key_name
, text
);
1091 mc_config_save_file (cfg
, NULL
);
1092 mc_config_deinit(cfg
);
1096 /* }}} history saving and loading */
1099 /* {{{ history display */
1104 return _(" History ");
1108 listbox_fwd (WListbox
*l
)
1110 if (l
->current
!= l
->list
->prev
)
1111 listbox_select_entry (l
, l
->current
->next
);
1113 listbox_select_first (l
);
1123 dlg_hist_reposition (Dlg_head
*dlg_head
)
1125 dlg_hist_data
*data
;
1126 int x
= 0, y
, he
, wi
;
1129 if ((dlg_head
== NULL
)
1130 || (dlg_head
->data
== NULL
))
1131 return MSG_NOT_HANDLED
;
1133 data
= (dlg_hist_data
*) dlg_head
->data
;
1135 y
= data
->widget
->y
;
1136 he
= data
->count
+ 2;
1138 if (he
<= y
|| y
> (LINES
- 6)) {
1139 he
= min (he
, y
- 1);
1143 he
= min (he
, LINES
- y
);
1146 if (data
->widget
->x
> 2)
1147 x
= data
->widget
->x
- 2;
1149 wi
= data
->maxlen
+ 4;
1151 if ((wi
+ x
) > COLS
) {
1152 wi
= min (wi
, COLS
);
1156 dlg_set_position (dlg_head
, y
, x
, y
+ he
, x
+ wi
);
1162 dlg_hist_callback (Dlg_head
*h
, Widget
*sender
,
1163 dlg_msg_t msg
, int parm
, void *data
)
1167 return dlg_hist_reposition (h
);
1170 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1175 show_hist (GList
*history
, Widget
*widget
)
1178 size_t maxlen
, i
, count
= 0;
1180 Dlg_head
*query_dlg
;
1181 WListbox
*query_list
;
1182 dlg_hist_data hist_data
;
1184 if (history
== NULL
)
1187 maxlen
= str_term_width1 (i18n_htitle ());
1189 z
= g_list_first (history
);
1192 i
= str_term_width1 ((char *) hi
->data
);
1193 maxlen
= max (maxlen
, i
);
1195 hi
= g_list_next (hi
);
1198 hist_data
.maxlen
= maxlen
;
1199 hist_data
.widget
= widget
;
1200 hist_data
.count
= count
;
1203 create_dlg (0, 0, 4, 4, dialog_colors
, dlg_hist_callback
,
1204 "[History-query]", i18n_htitle (), DLG_COMPACT
);
1205 query_dlg
->data
= &hist_data
;
1207 query_list
= listbox_new (1, 1, 2, 2, NULL
);
1209 /* this call makes list stick to all sides of dialog, effectively make
1210 it be resized with dialog */
1211 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
);
1213 /* to avoid diplicating of (calculating sizes in two places)
1214 code, call dlg_hist_callback function here, to set dialog and
1216 The main idea - create 4x4 dialog and add 2x2 list in
1217 center of it, and let dialog function resize it to needed
1219 dlg_hist_callback (query_dlg
, NULL
, DLG_RESIZE
, 0, NULL
);
1221 if (query_dlg
->y
< widget
->y
) {
1225 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1226 0, (char *) hi
->data
, NULL
);
1227 hi
= g_list_next (hi
);
1229 listbox_select_last (query_list
);
1231 /* traverse backwards */
1232 hi
= g_list_last (history
);
1234 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1235 0, (char *) hi
->data
, NULL
);
1236 hi
= g_list_previous (hi
);
1240 if (run_dlg (query_dlg
) != B_CANCEL
) {
1241 listbox_get_current (query_list
, &q
, NULL
);
1245 destroy_dlg (query_dlg
);
1250 do_show_hist (WInput
*in
)
1253 r
= show_hist (in
->history
, &in
->widget
);
1255 assign_text (in
, r
);
1260 /* }}} history display */
1263 input_destroy (WInput
*in
)
1266 fprintf (stderr
, "Internal error: null Input *\n");
1273 if (!in
->is_password
) /* don't save passwords ;-) */
1274 history_put (in
->history_name
, in
->history
);
1276 in
->history
= g_list_first (in
->history
);
1277 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1278 g_list_free (in
->history
);
1281 g_free (in
->buffer
);
1282 free_completions (in
);
1283 g_free (in
->history_name
);
1287 input_disable_update (WInput
*in
)
1289 in
->disable_update
++;
1293 input_enable_update (WInput
*in
)
1295 in
->disable_update
--;
1296 update_input (in
, 0);
1299 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1302 push_history (WInput
*in
, const char *text
)
1305 /* input widget where urls with passwords are entered without any
1307 static const char *password_input_fields
[] = {
1308 N_(" Link to a remote machine "),
1309 N_(" FTP to machine "),
1310 N_(" SMB link to machine ")
1318 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1319 password_input_fields
[i
] = _(password_input_fields
[i
]);
1322 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1327 /* Avoid duplicated entries */
1328 in
->history
= g_list_last (in
->history
);
1329 if (!strcmp ((char *) in
->history
->data
, text
))
1333 t
= g_strdup (text
);
1335 if (in
->history_name
) {
1336 p
= in
->history_name
+ 3;
1337 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1338 if (strcmp (p
, password_input_fields
[i
]) == 0)
1340 if (i
< ELEMENTS (password_input_fields
))
1341 strip_password (t
, 0);
1343 strip_password (t
, 1);
1346 in
->history
= list_append_unique (in
->history
, t
);
1354 /* Cleans the input line and adds the current text to the history */
1356 new_input (WInput
*in
)
1359 push_history (in
, in
->buffer
);
1361 in
->buffer
[0] = '\0';
1365 free_completions (in
);
1366 update_input (in
, 0);
1370 move_buffer_backward (WInput
*in
, int start
, int end
)
1373 int str_len
= str_length (in
->buffer
);
1374 if (start
>= str_len
|| end
> str_len
+ 1) return;
1376 pos
= str_offset_to_pos (in
->buffer
, start
);
1377 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
1379 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
1380 in
->buffer
[i
] = in
->buffer
[i
+ len
];
1384 insert_char (WInput
*in
, int c_code
)
1390 return MSG_NOT_HANDLED
;
1392 if (in
->charpoint
>= MB_LEN_MAX
)
1395 in
->charbuf
[in
->charpoint
] = c_code
;
1398 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
1401 in
->charpoint
= 0; /* broken multibyte char, skip */
1406 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
){
1407 /* Expand the buffer */
1408 size_t new_length
= in
->current_max_size
+
1409 in
->field_width
+ in
->charpoint
;
1410 char *narea
= g_try_renew (char, in
->buffer
, new_length
);
1413 in
->current_max_size
= new_length
;
1417 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
) {
1418 /* bytes from begin */
1419 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
1421 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
1423 for (i
= rest_bytes
+ 1; i
> 0; i
--)
1424 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] =
1425 in
->buffer
[ins_point
+ i
- 1];
1427 memcpy(in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
1436 beginning_of_line (WInput
*in
)
1443 end_of_line (WInput
*in
)
1445 in
->point
= str_length (in
->buffer
);
1450 backward_char (WInput
*in
)
1452 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1454 if (in
->point
> 0) {
1455 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
1461 forward_char (WInput
*in
)
1463 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1464 if (act
[0] != '\0') {
1465 in
->point
+= str_cnext_noncomb_char (&act
);
1471 forward_word (WInput
* in
)
1473 const char *p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1475 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
))) {
1476 str_cnext_char (&p
);
1479 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
)) {
1480 str_cnext_char (&p
);
1486 backward_word (WInput
*in
)
1492 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1493 (p
!= in
->buffer
) && (p
[0] == '\0');
1494 str_cprev_char (&p
), in
->point
--
1497 while (p
!= in
->buffer
) {
1499 str_cprev_char (&p
);
1500 if (!str_isspace (p
) && !str_ispunct (p
)) {
1506 while (p
!= in
->buffer
) {
1507 str_cprev_char (&p
);
1508 if (str_isspace (p
) || str_ispunct (p
))
1516 key_left (WInput
*in
)
1522 key_ctrl_left (WInput
*in
)
1528 key_right (WInput
*in
)
1534 key_ctrl_right (WInput
*in
)
1539 backward_delete (WInput
*in
)
1541 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1547 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
1548 move_buffer_backward(in
, start
, in
->point
);
1555 delete_char (WInput
*in
)
1557 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1558 int end
= in
->point
;
1560 end
+= str_cnext_noncomb_char (&act
);
1562 move_buffer_backward(in
, in
->point
, end
);
1568 copy_region (WInput
*in
, int x_first
, int x_last
)
1570 int first
= min (x_first
, x_last
);
1571 int last
= max (x_first
, x_last
);
1573 if (last
== first
) {
1574 /* Copy selected files to clipboard */
1575 panel_save_curent_file_to_clip_file ();
1579 g_free (kill_buffer
);
1581 first
= str_offset_to_pos (in
->buffer
, first
);
1582 last
= str_offset_to_pos (in
->buffer
, last
);
1584 kill_buffer
= g_strndup(in
->buffer
+ first
, last
- first
);
1585 save_text_to_clip_file (kill_buffer
);
1589 delete_region (WInput
*in
, int x_first
, int x_last
)
1591 int first
= min (x_first
, x_last
);
1592 int last
= max (x_first
, x_last
);
1597 last
= str_offset_to_pos (in
->buffer
, last
);
1598 first
= str_offset_to_pos (in
->buffer
, first
);
1599 len
= strlen (&in
->buffer
[last
]) + 1;
1600 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1606 kill_word (WInput
*in
)
1608 int old_point
= in
->point
;
1612 new_point
= in
->point
;
1613 in
->point
= old_point
;
1615 copy_region (in
, old_point
, new_point
);
1616 delete_region (in
, old_point
, new_point
);
1623 back_kill_word (WInput
*in
)
1625 int old_point
= in
->point
;
1629 new_point
= in
->point
;
1630 in
->point
= old_point
;
1632 copy_region (in
, old_point
, new_point
);
1633 delete_region (in
, old_point
, new_point
);
1638 set_mark (WInput
*in
)
1640 in
->mark
= in
->point
;
1644 kill_save (WInput
*in
)
1646 copy_region (in
, in
->mark
, in
->point
);
1650 kill_region (WInput
*in
)
1653 delete_region (in
, in
->point
, in
->mark
);
1657 clear_region (WInput
*in
)
1659 delete_region (in
, in
->point
, in
->mark
);
1670 for (p
= kill_buffer
; *p
; p
++)
1671 insert_char (in
, *p
);
1676 kill_line (WInput
*in
)
1678 int chp
= str_offset_to_pos (in
->buffer
, in
->point
);
1679 g_free (kill_buffer
);
1680 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
1681 in
->buffer
[chp
] = '\0';
1686 ins_from_clip (WInput
*in
)
1690 if (load_text_from_clip_file (&p
)) {
1693 for (pp
= p
; *pp
!= '\0'; pp
++)
1694 insert_char (in
, *pp
);
1701 assign_text (WInput
*in
, const char *text
)
1703 free_completions (in
);
1704 g_free (in
->buffer
);
1705 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1706 in
->current_max_size
= strlen (in
->buffer
) + 1;
1707 in
->point
= str_length (in
->buffer
);
1714 hist_prev (WInput
*in
)
1719 if (in
->need_push
) {
1720 switch (push_history (in
, in
->buffer
)) {
1722 in
->history
= g_list_previous (in
->history
);
1725 if (in
->history
->prev
)
1726 in
->history
= g_list_previous (in
->history
);
1731 } else if (in
->history
->prev
)
1732 in
->history
= g_list_previous (in
->history
);
1735 assign_text (in
, (char *) in
->history
->data
);
1740 hist_next (WInput
*in
)
1742 if (in
->need_push
) {
1743 switch (push_history (in
, in
->buffer
)) {
1745 assign_text (in
, "");
1755 if (!in
->history
->next
) {
1756 assign_text (in
, "");
1760 in
->history
= g_list_next (in
->history
);
1761 assign_text (in
, (char *) in
->history
->data
);
1766 port_region_marked_for_delete (WInput
*in
)
1768 in
->buffer
[0] = '\0';
1775 input_execute_cmd (WInput
*in
, unsigned long command
)
1777 cb_ret_t res
= MSG_HANDLED
;
1781 beginning_of_line (in
);
1786 case CK_InputMoveLeft
:
1789 case CK_InputWordLeft
:
1792 case CK_InputMoveRight
:
1795 case CK_InputWordRight
:
1796 key_ctrl_right (in
);
1798 case CK_InputBackwardChar
:
1801 case CK_InputBackwardWord
:
1804 case CK_InputForwardChar
:
1807 case CK_InputForwardWord
:
1810 case CK_InputBackwardDelete
:
1811 backward_delete (in
);
1813 case CK_InputDeleteChar
:
1816 case CK_InputKillWord
:
1819 case CK_InputBackwardKillWord
:
1820 back_kill_word (in
);
1822 case CK_InputSetMark
:
1825 case CK_InputKillRegion
:
1828 case CK_InputClearLine
:
1831 case CK_InputKillSave
:
1840 case CK_InputKillLine
:
1843 case CK_InputHistoryPrev
:
1846 case CK_InputHistoryNext
:
1849 case CK_InputHistoryShow
:
1852 case CK_InputComplete
:
1856 res
= MSG_NOT_HANDLED
;
1862 /* This function is a test for a special input key used in complete.c */
1863 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1864 and 2 if it is a complete key */
1866 is_in_input_map (WInput
*in
, int key
)
1869 for (i
= 0; input_map
[i
].key
!= 0; i
++)
1870 if (key
== input_map
[i
].key
) {
1871 input_execute_cmd (in
, input_map
[i
].command
);
1872 return (input_map
[i
].command
== CK_InputComplete
) ? 2 : 1;
1878 handle_char (WInput
*in
, int key
)
1883 v
= MSG_NOT_HANDLED
;
1886 free_completions (in
);
1887 v
= insert_char (in
, key
);
1888 update_input (in
, 1);
1892 for (i
= 0; input_map
[i
].key
; i
++) {
1893 if (key
== input_map
[i
].key
) {
1894 if (input_map
[i
].command
!= CK_InputComplete
)
1895 free_completions (in
);
1896 input_execute_cmd (in
, input_map
[i
].command
);
1897 update_input (in
, 1);
1902 if (input_map
[i
].command
== 0) {
1904 return MSG_NOT_HANDLED
;
1906 port_region_marked_for_delete (in
);
1907 free_completions (in
);
1908 v
= insert_char (in
, key
);
1910 update_input (in
, 1);
1914 /* Inserts text in input line */
1916 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1918 input_disable_update (in
);
1920 handle_char (in
, *text
++);
1921 if (insert_extra_space
)
1922 handle_char (in
, ' ');
1923 input_enable_update (in
);
1924 update_input (in
, 1);
1928 input_set_point (WInput
*in
, int pos
)
1930 int max_pos
= str_length (in
->buffer
);
1934 if (pos
!= in
->point
)
1935 free_completions (in
);
1938 update_input (in
, 1);
1942 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1944 WInput
*in
= (WInput
*) w
;
1949 if (parm
== XCTRL ('q')) {
1951 v
= handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1956 /* Keys we want others to handle */
1957 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1958 || parm
== KEY_F (10) || parm
== '\n')
1959 return MSG_NOT_HANDLED
;
1961 /* When pasting multiline text, insert literal Enter */
1962 if ((parm
& ~KEY_M_MASK
) == '\n') {
1964 v
= handle_char (in
, '\n');
1969 return handle_char (in
, parm
);
1971 case WIDGET_COMMAND
:
1972 return input_execute_cmd (in
, parm
);
1975 case WIDGET_UNFOCUS
:
1977 update_input (in
, 0);
1981 widget_move (&in
->widget
, 0, str_term_width2 (in
->buffer
, in
->point
)
1982 - in
->term_first_shown
);
1985 case WIDGET_DESTROY
:
1990 return default_proc (msg
, parm
);
1995 input_event (Gpm_Event
* event
, void *data
)
1999 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2000 dlg_select_widget (in
);
2002 if (event
->x
>= in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1
2003 && should_show_history_button (in
)) {
2006 in
->point
= str_length (in
->buffer
);
2007 if (event
->x
+ in
->term_first_shown
- 1 <
2008 str_term_width1 (in
->buffer
))
2010 in
->point
= str_column_to_pos (in
->buffer
, event
->x
2011 + in
->term_first_shown
- 1);
2014 update_input (in
, 1);
2020 input_new (int y
, int x
, int color
, int width
, const char *def_text
,
2021 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
2023 WInput
*in
= g_new (WInput
, 1);
2024 int initial_buffer_len
;
2026 init_widget (&in
->widget
, y
, x
, 1, width
, input_callback
, input_event
);
2030 in
->history_name
= 0;
2033 in
->history_name
= g_strdup (histname
);
2034 in
->history
= history_get (histname
);
2038 if (def_text
== NULL
)
2041 if (def_text
== INPUT_LAST_TEXT
) {
2044 if (in
->history
->data
)
2045 def_text
= (char *) in
->history
->data
;
2047 initial_buffer_len
= 1 + max ((size_t) width
, strlen (def_text
));
2048 in
->widget
.options
|= W_IS_INPUT
;
2049 in
->completions
= NULL
;
2050 in
->completion_flags
= completion_flags
;
2051 in
->current_max_size
= initial_buffer_len
;
2052 in
->buffer
= g_new (char, initial_buffer_len
);
2054 in
->field_width
= width
;
2056 in
->term_first_shown
= 0;
2057 in
->disable_update
= 0;
2060 in
->is_password
= 0;
2062 strcpy (in
->buffer
, def_text
);
2063 in
->point
= str_length (in
->buffer
);
2068 /* Listbox widget */
2070 /* Should draw the scrollbar, but currently draws only
2071 * indications that there is more information
2073 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
2076 listbox_drawscroll (WListbox
*l
)
2080 int max_line
= l
->widget
.lines
- 1;
2082 /* Are we at the top? */
2083 widget_move (&l
->widget
, 0, l
->widget
.cols
);
2084 if (l
->list
== l
->top
)
2085 tty_print_one_vline ();
2087 tty_print_char ('^');
2089 /* Are we at the bottom? */
2090 widget_move (&l
->widget
, max_line
, l
->widget
.cols
);
2091 top
= listbox_cdiff (l
->list
, l
->top
);
2092 if ((top
+ l
->widget
.lines
== l
->count
) || l
->widget
.lines
>= l
->count
)
2093 tty_print_one_vline ();
2095 tty_print_char ('v');
2097 /* Now draw the nice relative pointer */
2099 line
= 1+ ((l
->pos
* (l
->widget
.lines
- 2)) / l
->count
);
2101 for (i
= 1; i
< max_line
; i
++){
2102 widget_move (&l
->widget
, i
, l
->widget
.cols
);
2104 tty_print_one_vline ();
2106 tty_print_char ('*');
2111 listbox_draw (WListbox
*l
, gboolean focused
)
2113 const Dlg_head
*h
= l
->widget
.parent
;
2114 const int normalc
= DLG_NORMALC (h
);
2115 int selc
= focused
? DLG_HOT_FOCUSC (h
) : DLG_FOCUSC (h
);
2122 for (e
= l
->top
, i
= 0; i
< l
->widget
.lines
; i
++) {
2123 /* Display the entry */
2124 if (e
== l
->current
&& sel_line
== -1) {
2126 tty_setcolor (selc
);
2128 tty_setcolor (normalc
);
2130 widget_move (&l
->widget
, i
, 1);
2132 if ((i
> 0 && e
== l
->list
) || !l
->list
)
2138 tty_print_string (str_fit_to_term (text
, l
->widget
.cols
- 2, J_LEFT_FIT
));
2140 l
->cursor_y
= sel_line
;
2142 if (l
->scrollbar
&& l
->count
> l
->widget
.lines
) {
2143 tty_setcolor (normalc
);
2144 listbox_drawscroll (l
);
2148 /* Returns the number of items between s and e,
2149 must be on the same linked list */
2151 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
2155 for (count
= 0; s
!= e
; count
++)
2161 listbox_check_hotkey (WListbox
*l
, int key
)
2173 /* If we didn't find anything, return */
2174 if (i
&& e
== l
->list
)
2177 if (e
->hotkey
== key
)
2185 /* Selects the last entry and scrolls the list to the bottom */
2187 listbox_select_last (WListbox
*l
)
2190 l
->current
= l
->top
= l
->list
->prev
;
2191 for (i
= min (l
->widget
.lines
, l
->count
) - 1; i
; i
--)
2192 l
->top
= l
->top
->prev
;
2193 l
->pos
= l
->count
- 1;
2196 /* Selects the first entry and scrolls the list to the top */
2198 listbox_select_first (WListbox
*l
)
2200 l
->current
= l
->top
= l
->list
;
2205 listbox_remove_list (WListbox
*l
)
2214 while (l
->count
--) {
2220 l
->pos
= l
->count
= 0;
2221 l
->list
= l
->top
= l
->current
= 0;
2225 * bor 30.10.96: added force flag to remove *last* entry as well
2226 * bor 30.10.96: corrected selection bug if last entry was removed
2230 listbox_remove_current (WListbox
*l
, int force
)
2234 /* Ok, note: this won't allow for emtpy lists */
2235 if (!force
&& (!l
->count
|| l
->count
== 1))
2242 l
->current
->next
->prev
= l
->current
->prev
;
2243 l
->current
->prev
->next
= l
->current
->next
;
2244 if (p
->next
== l
->list
) {
2245 l
->current
= p
->prev
;
2249 l
->current
= p
->next
;
2252 l
->list
= l
->top
= p
->next
;
2255 l
->list
= l
->top
= l
->current
= 0;
2262 /* Makes *e the selected entry (sets current and pos) */
2264 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
2273 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
2281 while (listbox_cdiff (l
->top
, l
->current
) >= l
->widget
.lines
)
2282 l
->top
= l
->top
->next
;
2284 l
->top
= l
->current
;
2290 /* If we are unable to find it, set decent values */
2291 l
->current
= l
->top
= l
->list
;
2295 /* Selects from base the pos element */
2297 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
2299 WLEntry
*last
= l
->list
->prev
;
2312 listbox_back (WListbox
*l
)
2315 listbox_select_entry (l
, l
->current
->prev
);
2317 listbox_select_last (l
);
2320 /* Return MSG_HANDLED if we want a redraw */
2322 listbox_key (WListbox
*l
, int key
)
2326 cb_ret_t j
= MSG_NOT_HANDLED
;
2328 /* focus on listbox item N by '0'..'9' keys */
2329 if (key
>= '0' && key
<= '9') {
2330 int oldpos
= l
->pos
;
2331 listbox_select_by_number(l
, key
- '0');
2333 /* need scroll to item? */
2334 if (abs(oldpos
- l
->pos
) > l
->widget
.lines
)
2335 l
->top
= l
->current
;
2341 return MSG_NOT_HANDLED
;
2347 listbox_select_first (l
);
2353 listbox_select_last (l
);
2368 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2369 && (l
->current
!= l
->list
->prev
)); i
++) {
2377 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2378 && (l
->current
!= l
->list
)); i
++) {
2384 return MSG_NOT_HANDLED
;
2388 listbox_destroy (WListbox
*l
)
2390 WLEntry
*n
, *p
= l
->list
;
2393 for (i
= 0; i
< l
->count
; i
++){
2402 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2404 WListbox
*l
= (WListbox
*) w
;
2405 Dlg_head
*h
= l
->widget
.parent
;
2414 e
= listbox_check_hotkey (l
, parm
);
2418 listbox_select_entry (l
, e
);
2419 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2422 action
= (*l
->cback
) (l
);
2424 action
= LISTBOX_DONE
;
2426 if (action
== LISTBOX_DONE
) {
2427 h
->ret_value
= B_ENTER
;
2432 return MSG_NOT_HANDLED
;
2435 ret_code
= listbox_key (l
, parm
);
2436 if (ret_code
!= MSG_NOT_HANDLED
) {
2437 listbox_draw (l
, TRUE
);
2438 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2443 widget_move (&l
->widget
, l
->cursor_y
, 0);
2444 h
->callback (h
, w
, DLG_ACTION
, l
->pos
, NULL
);
2448 case WIDGET_UNFOCUS
:
2450 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2453 case WIDGET_DESTROY
:
2454 listbox_destroy (l
);
2457 case WIDGET_RESIZED
:
2461 return default_proc (msg
, parm
);
2466 listbox_event (Gpm_Event
*event
, void *data
)
2471 Dlg_head
*h
= l
->widget
.parent
;
2474 if (event
->type
& GPM_DOWN
)
2475 dlg_select_widget (l
);
2477 if (l
->list
== NULL
)
2480 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2481 int ret
= MOU_REPEAT
;
2483 if (event
->x
< 0 || event
->x
> l
->widget
.cols
)
2487 for (i
= -event
->y
; i
>= 0; i
--)
2489 else if (event
->y
> l
->widget
.lines
)
2490 for (i
= event
->y
- l
->widget
.lines
; i
> 0; i
--)
2492 else if (event
->buttons
& GPM_B_UP
) {
2495 } else if (event
->buttons
& GPM_B_DOWN
) {
2499 listbox_select_entry (l
,
2500 listbox_select_pos (l
, l
->top
,
2503 /* We need to refresh ourselves since the dialog manager doesn't */
2504 /* know about this event */
2505 listbox_draw (l
, TRUE
);
2510 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2513 if (event
->x
< 0 || event
->x
>= l
->widget
.cols
2514 || event
->y
< 1 || event
->y
> l
->widget
.lines
)
2517 dlg_select_widget (l
);
2518 listbox_select_entry (l
,
2519 listbox_select_pos (l
, l
->top
,
2523 action
= (*l
->cback
) (l
);
2525 action
= LISTBOX_DONE
;
2527 if (action
== LISTBOX_DONE
) {
2528 h
->ret_value
= B_ENTER
;
2537 listbox_new (int y
, int x
, int height
, int width
, lcback callback
)
2539 WListbox
*l
= g_new (WListbox
, 1);
2544 init_widget (&l
->widget
, y
, x
, height
, width
,
2545 listbox_callback
, listbox_event
);
2547 l
->list
= l
->top
= l
->current
= 0;
2550 l
->cback
= callback
;
2551 l
->allow_duplicates
= 1;
2552 l
->scrollbar
= !tty_is_slow ();
2553 widget_want_hotkey (l
->widget
, 1);
2558 /* Listbox item adding function. They still lack a lot of functionality */
2560 /* 1.11.96 bor: added pos argument to control placement of new entry */
2562 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2570 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2572 e
->prev
= l
->list
->prev
;
2573 l
->list
->prev
->next
= e
;
2575 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2576 e
->next
= l
->current
;
2577 e
->prev
= l
->current
->prev
;
2578 l
->current
->prev
->next
= e
;
2579 l
->current
->prev
= e
;
2580 if (l
->list
== l
->current
) { /* move list one position down */
2584 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2585 e
->prev
= l
->current
;
2586 e
->next
= l
->current
->next
;
2587 l
->current
->next
->prev
= e
;
2588 l
->current
->next
= e
;
2589 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2590 WLEntry
*w
= l
->list
;
2592 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2594 if (w
->next
== l
->list
) {
2610 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2611 const char *text
, void *data
)
2618 if (!l
->allow_duplicates
)
2619 if (listbox_search_text (l
, text
))
2622 entry
= g_new (WLEntry
, 1);
2623 entry
->text
= g_strdup (text
);
2625 entry
->hotkey
= hotkey
;
2627 listbox_append_item (l
, entry
, pos
);
2632 /* Selects the nth entry in the listbox */
2634 listbox_select_by_number (WListbox
*l
, int n
)
2636 if (l
->list
!= NULL
)
2637 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2641 listbox_search_text (WListbox
*l
, const char *text
)
2650 if(!strcmp (e
->text
, text
))
2653 } while (e
!=l
->list
);
2658 /* Returns the current string text as well as the associated extra data */
2660 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2666 if (string
&& l
->current
)
2667 *string
= l
->current
->text
;
2668 if (extra
&& l
->current
)
2669 *extra
= l
->current
->data
;
2672 /* returns TRUE if a function has been called, FALSE otherwise. */
2674 buttonbar_call (WButtonBar
*bb
, int i
)
2676 cb_ret_t ret
= MSG_NOT_HANDLED
;
2679 ret
= bb
->widget
.parent
->callback (bb
->widget
.parent
,
2680 (Widget
*) bb
, DLG_ACTION
,
2681 bb
->labels
[i
].command
,
2682 bb
->labels
[i
].receiver
);
2686 /* calculate width of one button, width is never lesser than 7 */
2688 buttonbat_get_button_width (void)
2690 int result
= COLS
/ BUTTONBAR_LABELS_NUM
;
2691 return (result
>= 7) ? result
: 7;
2695 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2697 WButtonBar
*bb
= (WButtonBar
*) w
;
2703 return MSG_NOT_HANDLED
;
2706 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2707 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2709 return MSG_NOT_HANDLED
;
2714 int count_free_positions
;
2716 widget_move (&bb
->widget
, 0, 0);
2717 tty_setcolor (DEFAULT_COLOR
);
2718 bb
->btn_width
= buttonbat_get_button_width ();
2719 tty_printf ("%-*s", bb
->widget
.cols
, "");
2720 count_free_positions
= COLS
- bb
->btn_width
* BUTTONBAR_LABELS_NUM
;
2722 for (i
= 0; i
< COLS
/ bb
->btn_width
&& i
< BUTTONBAR_LABELS_NUM
; i
++) {
2723 widget_move (&bb
->widget
, 0, (i
* bb
->btn_width
) + offset
);
2724 tty_setcolor (BUTTONBAR_HOTKEY_COLOR
);
2725 tty_printf ("%2d", i
+ 1);
2726 tty_setcolor (BUTTONBAR_BUTTON_COLOR
);
2727 text
= (bb
->labels
[i
].text
!= NULL
) ? bb
->labels
[i
].text
: "";
2728 tty_print_string (str_fit_to_term (
2730 bb
->btn_width
- 2 + (int)(offset
< count_free_positions
),
2733 if (count_free_positions
!= 0 && offset
< count_free_positions
)
2739 case WIDGET_DESTROY
:
2740 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2741 g_free (bb
->labels
[i
].text
);
2745 return default_proc (msg
, parm
);
2750 buttonbar_event (Gpm_Event
*event
, void *data
)
2752 WButtonBar
*bb
= data
;
2755 if (!(event
->type
& GPM_UP
))
2759 button
= (event
->x
- 1) * BUTTONBAR_LABELS_NUM
/ COLS
;
2760 if (button
< BUTTONBAR_LABELS_NUM
)
2761 buttonbar_call (bb
, button
);
2766 buttonbar_new (gboolean visible
)
2770 bb
= g_new0 (WButtonBar
, 1);
2772 init_widget (&bb
->widget
, LINES
- 1, 0, 1, COLS
,
2773 buttonbar_callback
, buttonbar_event
);
2774 bb
->widget
.pos_flags
= WPOS_KEEP_HORZ
| WPOS_KEEP_BOTTOM
;
2775 bb
->visible
= visible
;
2776 widget_want_hotkey (bb
->widget
, 1);
2777 widget_want_cursor (bb
->widget
, 0);
2778 bb
->btn_width
= buttonbat_get_button_width ();
2784 set_label_text (WButtonBar
*bb
, int lc_index
, const char *text
)
2786 g_free (bb
->labels
[lc_index
- 1].text
);
2787 bb
->labels
[lc_index
- 1].text
= g_strdup (text
);
2790 /* Find ButtonBar widget in the dialog */
2792 find_buttonbar (const Dlg_head
*h
)
2794 return (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2798 buttonbar_set_label (WButtonBar
*bb
, int idx
, const char *text
,
2799 const struct global_keymap_t
*keymap
, const Widget
*receiver
)
2801 if ((bb
!= NULL
) && (idx
>= 1) && (idx
<= BUTTONBAR_LABELS_NUM
)) {
2802 unsigned long command
= CK_Ignore_Key
;
2805 command
= lookup_keymap_command (keymap
, KEY_F (idx
));
2807 if ((text
== NULL
) || (text
[0] == '\0'))
2808 set_label_text (bb
, idx
, "");
2810 set_label_text (bb
, idx
, text
);
2812 bb
->labels
[idx
- 1].command
= command
;
2813 bb
->labels
[idx
- 1].receiver
= (Widget
*) receiver
;
2818 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2820 bb
->visible
= visible
;
2824 buttonbar_redraw (WButtonBar
*bb
)
2827 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2831 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2833 WGroupbox
*g
= (WGroupbox
*) w
;
2840 return MSG_NOT_HANDLED
;
2843 tty_setcolor (COLOR_NORMAL
);
2844 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2845 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2848 tty_setcolor (COLOR_HOT_NORMAL
);
2849 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2850 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2851 tty_print_string (g
->title
);
2854 case WIDGET_DESTROY
:
2859 return default_proc (msg
, parm
);
2864 groupbox_new (int y
, int x
, int height
, int width
, const char *title
)
2866 WGroupbox
*g
= g_new (WGroupbox
, 1);
2868 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2870 g
->widget
.options
&= ~W_WANT_CURSOR
;
2871 widget_want_hotkey (g
->widget
, 0);
2873 /* Strip existing spaces, add one space before and after the title */
2876 t
= g_strstrip (g_strdup (title
));
2877 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);