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
, DLG_POST_KEY
, ' ');
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
, DLG_ACTION
, 0);
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
, DLG_ACTION
, 0);
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
, DLG_POST_KEY
, ' ');
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
, DLG_ACTION
, 0);
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
, DLG_POST_KEY
, ' ');
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
, dlg_msg_t msg
, int parm
)
1166 return dlg_hist_reposition (h
);
1169 return default_dlg_callback (h
, msg
, parm
);
1174 show_hist (GList
*history
, Widget
*widget
)
1177 size_t maxlen
, i
, count
= 0;
1179 Dlg_head
*query_dlg
;
1180 WListbox
*query_list
;
1181 dlg_hist_data hist_data
;
1183 if (history
== NULL
)
1186 maxlen
= str_term_width1 (i18n_htitle ());
1188 z
= g_list_first (history
);
1191 i
= str_term_width1 ((char *) hi
->data
);
1192 maxlen
= max (maxlen
, i
);
1194 hi
= g_list_next (hi
);
1197 hist_data
.maxlen
= maxlen
;
1198 hist_data
.widget
= widget
;
1199 hist_data
.count
= count
;
1202 create_dlg (0, 0, 4, 4, dialog_colors
, dlg_hist_callback
,
1203 "[History-query]", i18n_htitle (), DLG_COMPACT
);
1204 query_dlg
->data
= &hist_data
;
1206 query_list
= listbox_new (1, 1, 2, 2, NULL
);
1208 /* this call makes list stick to all sides of dialog, effectively make
1209 it be resized with dialog */
1210 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
);
1212 /* to avoid diplicating of (calculating sizes in two places)
1213 code, call dlg_hist_callback function here, to set dialog and
1215 The main idea - create 4x4 dialog and add 2x2 list in
1216 center of it, and let dialog function resize it to needed
1218 dlg_hist_callback (query_dlg
, DLG_RESIZE
, 0);
1220 if (query_dlg
->y
< widget
->y
) {
1224 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1225 0, (char *) hi
->data
, NULL
);
1226 hi
= g_list_next (hi
);
1228 listbox_select_last (query_list
);
1230 /* traverse backwards */
1231 hi
= g_list_last (history
);
1233 listbox_add_item (query_list
, LISTBOX_APPEND_AT_END
,
1234 0, (char *) hi
->data
, NULL
);
1235 hi
= g_list_previous (hi
);
1239 if (run_dlg (query_dlg
) != B_CANCEL
) {
1240 listbox_get_current (query_list
, &q
, NULL
);
1244 destroy_dlg (query_dlg
);
1249 do_show_hist (WInput
*in
)
1252 r
= show_hist (in
->history
, &in
->widget
);
1254 assign_text (in
, r
);
1259 /* }}} history display */
1262 input_destroy (WInput
*in
)
1265 fprintf (stderr
, "Internal error: null Input *\n");
1272 if (!in
->is_password
) /* don't save passwords ;-) */
1273 history_put (in
->history_name
, in
->history
);
1275 in
->history
= g_list_first (in
->history
);
1276 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1277 g_list_free (in
->history
);
1280 g_free (in
->buffer
);
1281 free_completions (in
);
1282 g_free (in
->history_name
);
1286 input_disable_update (WInput
*in
)
1288 in
->disable_update
++;
1292 input_enable_update (WInput
*in
)
1294 in
->disable_update
--;
1295 update_input (in
, 0);
1298 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1301 push_history (WInput
*in
, const char *text
)
1304 /* input widget where urls with passwords are entered without any
1306 static const char *password_input_fields
[] = {
1307 N_(" Link to a remote machine "),
1308 N_(" FTP to machine "),
1309 N_(" SMB link to machine ")
1317 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1318 password_input_fields
[i
] = _(password_input_fields
[i
]);
1321 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1326 /* Avoid duplicated entries */
1327 in
->history
= g_list_last (in
->history
);
1328 if (!strcmp ((char *) in
->history
->data
, text
))
1332 t
= g_strdup (text
);
1334 if (in
->history_name
) {
1335 p
= in
->history_name
+ 3;
1336 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1337 if (strcmp (p
, password_input_fields
[i
]) == 0)
1339 if (i
< ELEMENTS (password_input_fields
))
1340 strip_password (t
, 0);
1342 strip_password (t
, 1);
1345 in
->history
= list_append_unique (in
->history
, t
);
1353 /* Cleans the input line and adds the current text to the history */
1355 new_input (WInput
*in
)
1358 push_history (in
, in
->buffer
);
1360 in
->buffer
[0] = '\0';
1364 free_completions (in
);
1365 update_input (in
, 0);
1369 move_buffer_backward (WInput
*in
, int start
, int end
)
1372 int str_len
= str_length (in
->buffer
);
1373 if (start
>= str_len
|| end
> str_len
+ 1) return;
1375 pos
= str_offset_to_pos (in
->buffer
, start
);
1376 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
1378 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
1379 in
->buffer
[i
] = in
->buffer
[i
+ len
];
1383 insert_char (WInput
*in
, int c_code
)
1389 return MSG_NOT_HANDLED
;
1391 if (in
->charpoint
>= MB_LEN_MAX
)
1394 in
->charbuf
[in
->charpoint
] = c_code
;
1397 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
1400 in
->charpoint
= 0; /* broken multibyte char, skip */
1405 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
){
1406 /* Expand the buffer */
1407 size_t new_length
= in
->current_max_size
+
1408 in
->field_width
+ in
->charpoint
;
1409 char *narea
= g_try_renew (char, in
->buffer
, new_length
);
1412 in
->current_max_size
= new_length
;
1416 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
) {
1417 /* bytes from begin */
1418 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
1420 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
1422 for (i
= rest_bytes
+ 1; i
> 0; i
--)
1423 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] =
1424 in
->buffer
[ins_point
+ i
- 1];
1426 memcpy(in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
1435 beginning_of_line (WInput
*in
)
1442 end_of_line (WInput
*in
)
1444 in
->point
= str_length (in
->buffer
);
1449 backward_char (WInput
*in
)
1451 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1453 if (in
->point
> 0) {
1454 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
1460 forward_char (WInput
*in
)
1462 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1463 if (act
[0] != '\0') {
1464 in
->point
+= str_cnext_noncomb_char (&act
);
1470 forward_word (WInput
* in
)
1472 const char *p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1474 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
))) {
1475 str_cnext_char (&p
);
1478 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
)) {
1479 str_cnext_char (&p
);
1485 backward_word (WInput
*in
)
1491 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1492 (p
!= in
->buffer
) && (p
[0] == '\0');
1496 while (p
!= in
->buffer
) {
1498 str_cprev_char (&p
);
1499 if (!str_isspace (p
) && !str_ispunct (p
)) {
1505 while (p
!= in
->buffer
) {
1506 str_cprev_char (&p
);
1507 if (str_isspace (p
) || str_ispunct (p
))
1515 key_left (WInput
*in
)
1521 key_ctrl_left (WInput
*in
)
1527 key_right (WInput
*in
)
1533 key_ctrl_right (WInput
*in
)
1538 backward_delete (WInput
*in
)
1540 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1546 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
1547 move_buffer_backward(in
, start
, in
->point
);
1554 delete_char (WInput
*in
)
1556 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
1557 int end
= in
->point
;
1559 end
+= str_cnext_noncomb_char (&act
);
1561 move_buffer_backward(in
, in
->point
, end
);
1567 copy_region (WInput
*in
, int x_first
, int x_last
)
1569 int first
= min (x_first
, x_last
);
1570 int last
= max (x_first
, x_last
);
1572 if (last
== first
) {
1573 /* Copy selected files to clipboard */
1574 panel_save_curent_file_to_clip_file ();
1578 g_free (kill_buffer
);
1580 first
= str_offset_to_pos (in
->buffer
, first
);
1581 last
= str_offset_to_pos (in
->buffer
, last
);
1583 kill_buffer
= g_strndup(in
->buffer
+ first
, last
- first
);
1584 save_text_to_clip_file (kill_buffer
);
1588 delete_region (WInput
*in
, int x_first
, int x_last
)
1590 int first
= min (x_first
, x_last
);
1591 int last
= max (x_first
, x_last
);
1596 last
= str_offset_to_pos (in
->buffer
, last
);
1597 first
= str_offset_to_pos (in
->buffer
, first
);
1598 len
= strlen (&in
->buffer
[last
]) + 1;
1599 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1605 kill_word (WInput
*in
)
1607 int old_point
= in
->point
;
1611 new_point
= in
->point
;
1612 in
->point
= old_point
;
1614 copy_region (in
, old_point
, new_point
);
1615 delete_region (in
, old_point
, new_point
);
1622 back_kill_word (WInput
*in
)
1624 int old_point
= in
->point
;
1628 new_point
= in
->point
;
1629 in
->point
= old_point
;
1631 copy_region (in
, old_point
, new_point
);
1632 delete_region (in
, old_point
, new_point
);
1637 set_mark (WInput
*in
)
1639 in
->mark
= in
->point
;
1643 kill_save (WInput
*in
)
1645 copy_region (in
, in
->mark
, in
->point
);
1649 kill_region (WInput
*in
)
1652 delete_region (in
, in
->point
, in
->mark
);
1656 clear_region (WInput
*in
)
1658 delete_region (in
, in
->point
, in
->mark
);
1669 for (p
= kill_buffer
; *p
; p
++)
1670 insert_char (in
, *p
);
1675 kill_line (WInput
*in
)
1677 int chp
= str_offset_to_pos (in
->buffer
, in
->point
);
1678 g_free (kill_buffer
);
1679 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
1680 in
->buffer
[chp
] = '\0';
1685 ins_from_clip (WInput
*in
)
1689 if (load_text_from_clip_file (&p
)) {
1692 for (pp
= p
; *pp
!= '\0'; pp
++)
1693 insert_char (in
, *pp
);
1700 assign_text (WInput
*in
, const char *text
)
1702 free_completions (in
);
1703 g_free (in
->buffer
);
1704 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1705 in
->current_max_size
= strlen (in
->buffer
) + 1;
1706 in
->point
= str_length (in
->buffer
);
1713 hist_prev (WInput
*in
)
1718 if (in
->need_push
) {
1719 switch (push_history (in
, in
->buffer
)) {
1721 in
->history
= g_list_previous (in
->history
);
1724 if (in
->history
->prev
)
1725 in
->history
= g_list_previous (in
->history
);
1730 } else if (in
->history
->prev
)
1731 in
->history
= g_list_previous (in
->history
);
1734 assign_text (in
, (char *) in
->history
->data
);
1739 hist_next (WInput
*in
)
1741 if (in
->need_push
) {
1742 switch (push_history (in
, in
->buffer
)) {
1744 assign_text (in
, "");
1754 if (!in
->history
->next
) {
1755 assign_text (in
, "");
1759 in
->history
= g_list_next (in
->history
);
1760 assign_text (in
, (char *) in
->history
->data
);
1765 port_region_marked_for_delete (WInput
*in
)
1767 in
->buffer
[0] = '\0';
1774 input_execute_cmd (WInput
*in
, int command
)
1776 cb_ret_t res
= MSG_HANDLED
;
1780 beginning_of_line (in
);
1785 case CK_InputMoveLeft
:
1788 case CK_InputWordLeft
:
1791 case CK_InputMoveRight
:
1794 case CK_InputWordRight
:
1795 key_ctrl_right (in
);
1797 case CK_InputBackwardChar
:
1800 case CK_InputBackwardWord
:
1803 case CK_InputForwardChar
:
1806 case CK_InputForwardWord
:
1809 case CK_InputBackwardDelete
:
1810 backward_delete (in
);
1812 case CK_InputDeleteChar
:
1815 case CK_InputKillWord
:
1818 case CK_InputBackwardKillWord
:
1819 back_kill_word (in
);
1821 case CK_InputSetMark
:
1824 case CK_InputKillRegion
:
1827 case CK_InputClearLine
:
1830 case CK_InputKillSave
:
1839 case CK_InputKillLine
:
1842 case CK_InputHistoryPrev
:
1845 case CK_InputHistoryNext
:
1848 case CK_InputHistoryShow
:
1851 case CK_InputComplete
:
1855 res
= MSG_NOT_HANDLED
;
1861 /* This function is a test for a special input key used in complete.c */
1862 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1863 and 2 if it is a complete key */
1865 is_in_input_map (WInput
*in
, int key
)
1868 for (i
= 0; input_map
[i
].key
; i
++) {
1869 if (key
== input_map
[i
].key
) {
1870 input_execute_cmd (in
, input_map
[i
].command
);
1871 if (input_map
[i
].command
== CK_InputComplete
)
1881 handle_char (WInput
*in
, int key
)
1886 v
= MSG_NOT_HANDLED
;
1889 free_completions (in
);
1890 v
= insert_char (in
, key
);
1891 update_input (in
, 1);
1895 for (i
= 0; input_map
[i
].key
; i
++) {
1896 if (key
== input_map
[i
].key
) {
1897 if (input_map
[i
].command
!= CK_InputComplete
)
1898 free_completions (in
);
1899 input_execute_cmd (in
, input_map
[i
].command
);
1900 update_input (in
, 1);
1905 if (input_map
[i
].command
== 0) {
1907 return MSG_NOT_HANDLED
;
1909 port_region_marked_for_delete (in
);
1910 free_completions (in
);
1911 v
= insert_char (in
, key
);
1913 update_input (in
, 1);
1917 /* Inserts text in input line */
1919 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1921 input_disable_update (in
);
1923 handle_char (in
, *text
++);
1924 if (insert_extra_space
)
1925 handle_char (in
, ' ');
1926 input_enable_update (in
);
1927 update_input (in
, 1);
1931 input_set_point (WInput
*in
, int pos
)
1933 int max_pos
= str_length (in
->buffer
);
1937 if (pos
!= in
->point
)
1938 free_completions (in
);
1941 update_input (in
, 1);
1945 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1947 WInput
*in
= (WInput
*) w
;
1952 if (parm
== XCTRL ('q')) {
1954 v
= handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1959 /* Keys we want others to handle */
1960 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1961 || parm
== KEY_F (10) || parm
== '\n')
1962 return MSG_NOT_HANDLED
;
1964 /* When pasting multiline text, insert literal Enter */
1965 if ((parm
& ~KEY_M_MASK
) == '\n') {
1967 v
= handle_char (in
, '\n');
1972 return handle_char (in
, parm
);
1974 case WIDGET_COMMAND
:
1975 return input_execute_cmd (in
, parm
);
1978 case WIDGET_UNFOCUS
:
1980 update_input (in
, 0);
1984 widget_move (&in
->widget
, 0, str_term_width2 (in
->buffer
, in
->point
)
1985 - in
->term_first_shown
);
1988 case WIDGET_DESTROY
:
1993 return default_proc (msg
, parm
);
1998 input_event (Gpm_Event
* event
, void *data
)
2002 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2003 dlg_select_widget (in
);
2005 if (event
->x
>= in
->field_width
- HISTORY_BUTTON_WIDTH
+ 1
2006 && should_show_history_button (in
)) {
2009 in
->point
= str_length (in
->buffer
);
2010 if (event
->x
+ in
->term_first_shown
- 1 <
2011 str_term_width1 (in
->buffer
))
2013 in
->point
= str_column_to_pos (in
->buffer
, event
->x
2014 + in
->term_first_shown
- 1);
2017 update_input (in
, 1);
2023 input_new (int y
, int x
, int color
, int width
, const char *def_text
,
2024 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
2026 WInput
*in
= g_new (WInput
, 1);
2027 int initial_buffer_len
;
2029 init_widget (&in
->widget
, y
, x
, 1, width
, input_callback
, input_event
);
2033 in
->history_name
= 0;
2036 in
->history_name
= g_strdup (histname
);
2037 in
->history
= history_get (histname
);
2041 if (def_text
== NULL
)
2044 if (def_text
== INPUT_LAST_TEXT
) {
2047 if (in
->history
->data
)
2048 def_text
= (char *) in
->history
->data
;
2050 initial_buffer_len
= 1 + max ((size_t) width
, strlen (def_text
));
2051 in
->widget
.options
|= W_IS_INPUT
;
2052 in
->completions
= NULL
;
2053 in
->completion_flags
= completion_flags
;
2054 in
->current_max_size
= initial_buffer_len
;
2055 in
->buffer
= g_new (char, initial_buffer_len
);
2057 in
->field_width
= width
;
2059 in
->term_first_shown
= 0;
2060 in
->disable_update
= 0;
2063 in
->is_password
= 0;
2065 strcpy (in
->buffer
, def_text
);
2066 in
->point
= str_length (in
->buffer
);
2071 /* Listbox widget */
2073 /* Should draw the scrollbar, but currently draws only
2074 * indications that there is more information
2076 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
2079 listbox_drawscroll (WListbox
*l
)
2083 int max_line
= l
->widget
.lines
- 1;
2085 /* Are we at the top? */
2086 widget_move (&l
->widget
, 0, l
->widget
.cols
);
2087 if (l
->list
== l
->top
)
2088 tty_print_one_vline ();
2090 tty_print_char ('^');
2092 /* Are we at the bottom? */
2093 widget_move (&l
->widget
, max_line
, l
->widget
.cols
);
2094 top
= listbox_cdiff (l
->list
, l
->top
);
2095 if ((top
+ l
->widget
.lines
== l
->count
) || l
->widget
.lines
>= l
->count
)
2096 tty_print_one_vline ();
2098 tty_print_char ('v');
2100 /* Now draw the nice relative pointer */
2102 line
= 1+ ((l
->pos
* (l
->widget
.lines
- 2)) / l
->count
);
2104 for (i
= 1; i
< max_line
; i
++){
2105 widget_move (&l
->widget
, i
, l
->widget
.cols
);
2107 tty_print_one_vline ();
2109 tty_print_char ('*');
2114 listbox_draw (WListbox
*l
, gboolean focused
)
2116 const Dlg_head
*h
= l
->widget
.parent
;
2117 const int normalc
= DLG_NORMALC (h
);
2118 int selc
= focused
? DLG_HOT_FOCUSC (h
) : DLG_FOCUSC (h
);
2125 for (e
= l
->top
, i
= 0; i
< l
->widget
.lines
; i
++) {
2126 /* Display the entry */
2127 if (e
== l
->current
&& sel_line
== -1) {
2129 tty_setcolor (selc
);
2131 tty_setcolor (normalc
);
2133 widget_move (&l
->widget
, i
, 1);
2135 if ((i
> 0 && e
== l
->list
) || !l
->list
)
2141 tty_print_string (str_fit_to_term (text
, l
->widget
.cols
- 2, J_LEFT_FIT
));
2143 l
->cursor_y
= sel_line
;
2145 if (l
->scrollbar
&& l
->count
> l
->widget
.lines
) {
2146 tty_setcolor (normalc
);
2147 listbox_drawscroll (l
);
2151 /* Returns the number of items between s and e,
2152 must be on the same linked list */
2154 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
2158 for (count
= 0; s
!= e
; count
++)
2164 listbox_check_hotkey (WListbox
*l
, int key
)
2176 /* If we didn't find anything, return */
2177 if (i
&& e
== l
->list
)
2180 if (e
->hotkey
== key
)
2188 /* Selects the last entry and scrolls the list to the bottom */
2190 listbox_select_last (WListbox
*l
)
2193 l
->current
= l
->top
= l
->list
->prev
;
2194 for (i
= min (l
->widget
.lines
, l
->count
) - 1; i
; i
--)
2195 l
->top
= l
->top
->prev
;
2196 l
->pos
= l
->count
- 1;
2199 /* Selects the first entry and scrolls the list to the top */
2201 listbox_select_first (WListbox
*l
)
2203 l
->current
= l
->top
= l
->list
;
2208 listbox_remove_list (WListbox
*l
)
2217 while (l
->count
--) {
2223 l
->pos
= l
->count
= 0;
2224 l
->list
= l
->top
= l
->current
= 0;
2228 * bor 30.10.96: added force flag to remove *last* entry as well
2229 * bor 30.10.96: corrected selection bug if last entry was removed
2233 listbox_remove_current (WListbox
*l
, int force
)
2237 /* Ok, note: this won't allow for emtpy lists */
2238 if (!force
&& (!l
->count
|| l
->count
== 1))
2245 l
->current
->next
->prev
= l
->current
->prev
;
2246 l
->current
->prev
->next
= l
->current
->next
;
2247 if (p
->next
== l
->list
) {
2248 l
->current
= p
->prev
;
2252 l
->current
= p
->next
;
2255 l
->list
= l
->top
= p
->next
;
2258 l
->list
= l
->top
= l
->current
= 0;
2265 /* Makes *e the selected entry (sets current and pos) */
2267 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
2276 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
2284 while (listbox_cdiff (l
->top
, l
->current
) >= l
->widget
.lines
)
2285 l
->top
= l
->top
->next
;
2287 l
->top
= l
->current
;
2293 /* If we are unable to find it, set decent values */
2294 l
->current
= l
->top
= l
->list
;
2298 /* Selects from base the pos element */
2300 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
2302 WLEntry
*last
= l
->list
->prev
;
2315 listbox_back (WListbox
*l
)
2318 listbox_select_entry (l
, l
->current
->prev
);
2320 listbox_select_last (l
);
2323 /* Return MSG_HANDLED if we want a redraw */
2325 listbox_key (WListbox
*l
, int key
)
2329 cb_ret_t j
= MSG_NOT_HANDLED
;
2331 /* focus on listbox item N by '0'..'9' keys */
2332 if (key
>= '0' && key
<= '9') {
2333 int oldpos
= l
->pos
;
2334 listbox_select_by_number(l
, key
- '0');
2336 /* need scroll to item? */
2337 if (abs(oldpos
- l
->pos
) > l
->widget
.lines
)
2338 l
->top
= l
->current
;
2344 return MSG_NOT_HANDLED
;
2350 listbox_select_first (l
);
2356 listbox_select_last (l
);
2371 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2372 && (l
->current
!= l
->list
->prev
)); i
++) {
2380 for (i
= 0; ((i
< l
->widget
.lines
- 1)
2381 && (l
->current
!= l
->list
)); i
++) {
2387 return MSG_NOT_HANDLED
;
2391 listbox_destroy (WListbox
*l
)
2393 WLEntry
*n
, *p
= l
->list
;
2396 for (i
= 0; i
< l
->count
; i
++){
2405 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2407 WListbox
*l
= (WListbox
*) w
;
2408 Dlg_head
*h
= l
->widget
.parent
;
2417 e
= listbox_check_hotkey (l
, parm
);
2421 listbox_select_entry (l
, e
);
2423 (*h
->callback
) (h
, DLG_ACTION
, l
->pos
);
2426 action
= (*l
->cback
) (l
);
2428 action
= LISTBOX_DONE
;
2430 if (action
== LISTBOX_DONE
) {
2431 h
->ret_value
= B_ENTER
;
2436 return MSG_NOT_HANDLED
;
2439 ret_code
= listbox_key (l
, parm
);
2440 if (ret_code
!= MSG_NOT_HANDLED
) {
2441 listbox_draw (l
, TRUE
);
2442 (*h
->callback
) (h
, DLG_ACTION
, l
->pos
);
2447 widget_move (&l
->widget
, l
->cursor_y
, 0);
2448 (*h
->callback
) (h
, DLG_ACTION
, l
->pos
);
2452 case WIDGET_UNFOCUS
:
2454 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2457 case WIDGET_DESTROY
:
2458 listbox_destroy (l
);
2461 case WIDGET_RESIZED
:
2465 return default_proc (msg
, parm
);
2470 listbox_event (Gpm_Event
*event
, void *data
)
2475 Dlg_head
*h
= l
->widget
.parent
;
2478 if (event
->type
& GPM_DOWN
)
2479 dlg_select_widget (l
);
2481 if (l
->list
== NULL
)
2484 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2485 int ret
= MOU_REPEAT
;
2487 if (event
->x
< 0 || event
->x
> l
->widget
.cols
)
2491 for (i
= -event
->y
; i
>= 0; i
--)
2493 else if (event
->y
> l
->widget
.lines
)
2494 for (i
= event
->y
- l
->widget
.lines
; i
> 0; i
--)
2496 else if (event
->buttons
& GPM_B_UP
) {
2499 } else if (event
->buttons
& GPM_B_DOWN
) {
2503 listbox_select_entry (l
,
2504 listbox_select_pos (l
, l
->top
,
2507 /* We need to refresh ourselves since the dialog manager doesn't */
2508 /* know about this event */
2509 listbox_draw (l
, TRUE
);
2514 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2517 if (event
->x
< 0 || event
->x
>= l
->widget
.cols
2518 || event
->y
< 1 || event
->y
> l
->widget
.lines
)
2521 dlg_select_widget (l
);
2522 listbox_select_entry (l
,
2523 listbox_select_pos (l
, l
->top
,
2527 action
= (*l
->cback
) (l
);
2529 action
= LISTBOX_DONE
;
2531 if (action
== LISTBOX_DONE
) {
2532 h
->ret_value
= B_ENTER
;
2541 listbox_new (int y
, int x
, int height
, int width
, lcback callback
)
2543 WListbox
*l
= g_new (WListbox
, 1);
2548 init_widget (&l
->widget
, y
, x
, height
, width
,
2549 listbox_callback
, listbox_event
);
2551 l
->list
= l
->top
= l
->current
= 0;
2554 l
->cback
= callback
;
2555 l
->allow_duplicates
= 1;
2556 l
->scrollbar
= !tty_is_slow ();
2557 widget_want_hotkey (l
->widget
, 1);
2562 /* Listbox item adding function. They still lack a lot of functionality */
2564 /* 1.11.96 bor: added pos argument to control placement of new entry */
2566 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2574 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2576 e
->prev
= l
->list
->prev
;
2577 l
->list
->prev
->next
= e
;
2579 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2580 e
->next
= l
->current
;
2581 e
->prev
= l
->current
->prev
;
2582 l
->current
->prev
->next
= e
;
2583 l
->current
->prev
= e
;
2584 if (l
->list
== l
->current
) { /* move list one position down */
2588 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2589 e
->prev
= l
->current
;
2590 e
->next
= l
->current
->next
;
2591 l
->current
->next
->prev
= e
;
2592 l
->current
->next
= e
;
2593 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2594 WLEntry
*w
= l
->list
;
2596 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2598 if (w
->next
== l
->list
) {
2614 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2615 const char *text
, void *data
)
2622 if (!l
->allow_duplicates
)
2623 if (listbox_search_text (l
, text
))
2626 entry
= g_new (WLEntry
, 1);
2627 entry
->text
= g_strdup (text
);
2629 entry
->hotkey
= hotkey
;
2631 listbox_append_item (l
, entry
, pos
);
2636 /* Selects the nth entry in the listbox */
2638 listbox_select_by_number (WListbox
*l
, int n
)
2640 if (l
->list
!= NULL
)
2641 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2645 listbox_search_text (WListbox
*l
, const char *text
)
2654 if(!strcmp (e
->text
, text
))
2657 } while (e
!=l
->list
);
2662 /* Returns the current string text as well as the associated extra data */
2664 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2670 if (string
&& l
->current
)
2671 *string
= l
->current
->text
;
2672 if (extra
&& l
->current
)
2673 *extra
= l
->current
->data
;
2676 /* returns TRUE if a function has been called, FALSE otherwise. */
2678 buttonbar_call (WButtonBar
*bb
, int i
)
2680 switch (bb
->labels
[i
].tag
) {
2684 bb
->labels
[i
].u
.fn_void ();
2687 bb
->labels
[i
].u
.fn_ptr (bb
->labels
[i
].data
);
2693 /* calculate width of one button, width is never lesser than 7 */
2695 buttonbat_get_button_width ()
2697 int result
= COLS
/ BUTTONBAR_LABELS_NUM
;
2698 return (result
>= 7) ? result
: 7;
2703 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2705 WButtonBar
*bb
= (WButtonBar
*) w
;
2711 return MSG_NOT_HANDLED
;
2714 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2715 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2717 return MSG_NOT_HANDLED
;
2722 int count_free_positions
;
2724 widget_move (&bb
->widget
, 0, 0);
2725 tty_setcolor (DEFAULT_COLOR
);
2726 bb
->btn_width
= buttonbat_get_button_width ();
2727 tty_printf ("%-*s", bb
->widget
.cols
, "");
2728 count_free_positions
= COLS
- bb
->btn_width
*BUTTONBAR_LABELS_NUM
;
2730 for (i
= 0; i
< COLS
/ bb
->btn_width
&& i
< BUTTONBAR_LABELS_NUM
; i
++) {
2731 widget_move (&bb
->widget
, 0, (i
* bb
->btn_width
) + offset
);
2732 tty_setcolor (BUTTONBAR_HOTKEY_COLOR
);
2733 tty_printf ("%2d", i
+ 1);
2734 tty_setcolor (BUTTONBAR_BUTTON_COLOR
);
2735 text
= (bb
->labels
[i
].text
!= NULL
) ? bb
->labels
[i
].text
: "";
2736 tty_print_string (str_fit_to_term (
2738 bb
->btn_width
- 2 + (int)(offset
< count_free_positions
),
2741 if (count_free_positions
!= 0 && offset
< count_free_positions
)
2747 case WIDGET_DESTROY
:
2748 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++)
2749 g_free (bb
->labels
[i
].text
);
2753 return default_proc (msg
, parm
);
2758 buttonbar_event (Gpm_Event
*event
, void *data
)
2760 WButtonBar
*bb
= data
;
2763 if (!(event
->type
& GPM_UP
))
2767 button
= (event
->x
- 1) * BUTTONBAR_LABELS_NUM
/ (COLS
);
2768 if (button
< BUTTONBAR_LABELS_NUM
)
2769 buttonbar_call (bb
, button
);
2774 buttonbar_new (int visible
)
2779 bb
= g_new0 (WButtonBar
, 1);
2781 init_widget (&bb
->widget
, LINES
- 1, 0, 1, COLS
,
2782 buttonbar_callback
, buttonbar_event
);
2783 bb
->widget
.pos_flags
= WPOS_KEEP_HORZ
| WPOS_KEEP_BOTTOM
;
2784 bb
->visible
= visible
;
2785 for (i
= 0; i
< BUTTONBAR_LABELS_NUM
; i
++){
2786 bb
->labels
[i
].text
= NULL
;
2787 bb
->labels
[i
].tag
= BBFUNC_NONE
;
2789 widget_want_hotkey (bb
->widget
, 1);
2790 widget_want_cursor (bb
->widget
, 0);
2791 bb
->btn_width
= buttonbat_get_button_width ();
2797 set_label_text (WButtonBar
* bb
, int lc_index
, const char *text
)
2799 g_free (bb
->labels
[lc_index
- 1].text
);
2801 bb
->labels
[lc_index
- 1].text
= g_strdup (text
);
2804 /* Find ButtonBar widget in the dialog */
2806 find_buttonbar (Dlg_head
*h
)
2810 bb
= (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2815 buttonbar_clear_label (Dlg_head
*h
, int idx
)
2817 WButtonBar
*bb
= find_buttonbar (h
);
2822 set_label_text (bb
, idx
, "");
2823 bb
->labels
[idx
- 1].tag
= BBFUNC_NONE
;
2827 buttonbar_set_label_data (Dlg_head
*h
, int idx
, const char *text
,
2828 buttonbarfn cback
, void *data
)
2830 WButtonBar
*bb
= find_buttonbar (h
);
2835 assert (cback
!= (buttonbarfn
) 0);
2836 set_label_text (bb
, idx
, text
);
2837 bb
->labels
[idx
- 1].tag
= BBFUNC_PTR
;
2838 bb
->labels
[idx
- 1].u
.fn_ptr
= cback
;
2839 bb
->labels
[idx
- 1].data
= data
;
2843 buttonbar_set_label (Dlg_head
*h
, int idx
, const char *text
, voidfn cback
)
2845 WButtonBar
*bb
= find_buttonbar (h
);
2850 assert (cback
!= (voidfn
) 0);
2851 set_label_text (bb
, idx
, text
);
2852 bb
->labels
[idx
- 1].tag
= BBFUNC_VOID
;
2853 bb
->labels
[idx
- 1].u
.fn_void
= cback
;
2857 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2859 bb
->visible
= visible
;
2863 buttonbar_redraw (Dlg_head
*h
)
2865 WButtonBar
*bb
= find_buttonbar (h
);
2870 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2874 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2876 WGroupbox
*g
= (WGroupbox
*) w
;
2883 return MSG_NOT_HANDLED
;
2886 tty_setcolor (COLOR_NORMAL
);
2887 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2888 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2891 tty_setcolor (COLOR_HOT_NORMAL
);
2892 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2893 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2894 tty_print_string (g
->title
);
2897 case WIDGET_DESTROY
:
2902 return default_proc (msg
, parm
);
2907 groupbox_new (int y
, int x
, int height
, int width
, const char *title
)
2909 WGroupbox
*g
= g_new (WGroupbox
, 1);
2911 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2913 g
->widget
.options
&= ~W_WANT_CURSOR
;
2914 widget_want_hotkey (g
->widget
, 0);
2916 /* Strip existing spaces, add one space before and after the title */
2919 t
= g_strstrip (g_strdup (title
));
2920 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);