1 /* Widgets for the Midnight Commander
3 Copyright (C) 1994, 1995, 1996 the Free Software Foundation
5 Authors: 1994, 1995 Radek Doulik
6 1994, 1995 Miguel de Icaza
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <sys/types.h>
42 #include "key.h" /* XCTRL and ALT macros */
43 #include "profile.h" /* for history loading and saving */
44 #include "wtools.h" /* For common_dialog_repaint() */
46 static int button_event (Gpm_Event
*event
, WButton
*b
);
51 button_callback (WButton
*b
, int Msg
, int Par
)
56 Dlg_head
*h
= b
->widget
.parent
;
63 if (b
->hotkey
== Par
|| toupper(b
->hotkey
) == Par
){
64 button_callback (b
, WIDGET_KEY
, ' '); /* to make action */
70 if (Par
!= ' ' && Par
!= '\n')
74 stop
= (*b
->callback
)(b
->action
, b
->callback_data
);
75 if (!b
->callback
|| stop
){
76 h
->ret_value
= b
->action
;
97 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
103 if (Msg
==WIDGET_UNFOCUS
)
105 else if (Msg
==WIDGET_FOCUS
)
110 g_snprintf (buf
, sizeof(buf
), "[< %s >]", b
->text
);
114 g_snprintf (buf
, sizeof(buf
), "[ %s ]", b
->text
);
118 g_snprintf (buf
, sizeof(buf
), "[%s]", b
->text
);
128 attrset ((b
->selected
) ? FOCUSC
: NORMALC
);
129 widget_move (&b
->widget
, 0, 0);
134 attrset ((b
->selected
) ? HOT_FOCUSC
: HOT_NORMALC
);
135 widget_move (&b
->widget
, 0, b
->hotpos
+off
);
136 addch ((unsigned char)b
->text
[b
->hotpos
]);
138 if (Msg
== WIDGET_FOCUS
)
144 return default_proc (Msg
, Par
);
148 button_event (Gpm_Event
*event
, WButton
*b
)
150 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
151 Dlg_head
*h
=b
->widget
.parent
;
152 dlg_select_widget (h
, b
);
153 if (event
->type
& GPM_UP
){
154 button_callback (b
, WIDGET_KEY
, ' ');
155 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
163 button_destroy (WButton
*b
)
169 button_len (const char *text
, unsigned int flags
)
171 int ret
= strlen (text
);
190 * Locate the hotkey and remove it from the button text. Assuming that
191 * the button text is g_malloc()ed, we can safely change and shorten it.
194 button_scan_hotkey(WButton
* b
)
196 char* cp
= strchr (b
->text
, '&');
198 if (cp
!= NULL
&& cp
[1] != '\0'){
200 b
->hotkey
= tolower (*cp
);
201 b
->hotpos
= cp
- b
->text
;
206 button_new (int y
, int x
, int action
, int flags
, char *text
,
207 int (*callback
)(int, void *), void *callback_data
, char *tkname
)
209 WButton
*b
= g_new (WButton
, 1);
211 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
212 (callback_fn
) button_callback
,
213 (destroy_fn
) button_destroy
, (mouse_h
)button_event
, tkname
);
218 b
->text
= g_strdup (text
);
219 b
->callback
= callback
;
220 b
->callback_data
= callback_data
;
221 widget_want_hotkey (b
->widget
, 1);
225 button_scan_hotkey(b
);
230 button_set_text (WButton
*b
, char *text
)
233 b
->text
= g_strdup (text
);
234 b
->widget
.cols
= button_len (text
, b
->flags
);
235 button_scan_hotkey(b
);
236 dlg_redraw (b
->widget
.parent
);
240 /* Radio button widget */
241 static int radio_event (Gpm_Event
*event
, WRadio
*r
);
244 radio_callback (WRadio
*r
, int Msg
, int Par
)
247 Dlg_head
*h
= r
->widget
.parent
;
255 int i
, lp
= tolower(Par
);
258 for (i
= 0; i
< r
->count
; i
++){
259 cp
= strchr (r
->texts
[i
], '&');
260 if (cp
!= NULL
&& cp
[1] != '\0'){
261 int c
= tolower (cp
[1]);
266 radio_callback (r
, WIDGET_KEY
, ' '); /* Take action */
277 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
278 radio_callback (r
, WIDGET_FOCUS
, ' ');
291 if (r
->count
- 1 > r
->pos
) {
299 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
300 radio_callback (r
, WIDGET_FOCUS
, ' ');
301 widget_move (&r
->widget
, r
->pos
, 1);
307 for (i
= 0; i
< r
->count
; i
++){
308 register unsigned char* cp
;
309 attrset ((i
==r
->pos
&& Msg
==WIDGET_FOCUS
) ? FOCUSC
:NORMALC
);
310 widget_move (&r
->widget
, i
, 0);
312 printw("(%c) ", (r
->sel
== i
) ? '*' : ' ');
313 for (cp
= r
->texts
[i
]; *cp
; cp
++)
317 attrset ((i
==r
->pos
&& Msg
==WIDGET_FOCUS
)
318 ? HOT_FOCUSC
: HOT_NORMALC
);
320 attrset ((i
==r
->pos
&& Msg
==WIDGET_FOCUS
) ? FOCUSC
: NORMALC
);
329 return default_proc (Msg
, Par
);
333 radio_event (Gpm_Event
*event
, WRadio
*r
)
335 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
336 Dlg_head
*h
= r
->widget
.parent
;
338 r
->pos
= event
->y
- 1;
339 dlg_select_widget (h
, r
);
340 if (event
->type
& GPM_UP
){
341 radio_callback (r
, WIDGET_KEY
, ' ');
342 radio_callback (r
, WIDGET_FOCUS
, 0);
343 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
351 radio_new (int y
, int x
, int count
, char **texts
, int use_hotkey
, char *tkname
)
353 WRadio
*r
= g_new (WRadio
, 1);
356 /* Compute the longest string */
358 for (i
= 0; i
< count
; i
++){
359 m
= strlen (texts
[i
]);
364 init_widget (&r
->widget
, y
, x
, count
, max
, (callback_fn
) radio_callback
,
365 0, (mouse_h
) radio_event
, tkname
);
371 r
->upper_letter_is_hotkey
= use_hotkey
;
372 widget_want_hotkey (r
->widget
, 1);
378 /* Checkbutton widget */
380 static int check_event (Gpm_Event
*event
, WCheck
*b
);
383 check_callback (WCheck
*c
, int Msg
, int Par
)
385 Dlg_head
*h
= c
->widget
.parent
;
392 if (c
->hotkey
==Par
||
393 (c
->hotkey
>='a' && c
->hotkey
<='z' && c
->hotkey
-32==Par
)){
394 check_callback (c
, WIDGET_KEY
, ' '); /* make action */
403 c
->state
^= C_CHANGE
;
404 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
405 check_callback (c
, WIDGET_FOCUS
, ' ');
409 widget_move (&c
->widget
, 0, 1);
415 attrset ((Msg
== WIDGET_FOCUS
) ? FOCUSC
: NORMALC
);
416 widget_move (&c
->widget
, 0, 0);
417 printw ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
420 attrset ((Msg
== WIDGET_FOCUS
) ? HOT_FOCUSC
: HOT_NORMALC
);
421 widget_move (&c
->widget
, 0, + c
->hotpos
+4);
422 addch ((unsigned char)c
->text
[c
->hotpos
]);
426 return default_proc (Msg
, Par
);
430 check_event (Gpm_Event
*event
, WCheck
*c
)
432 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
433 Dlg_head
*h
= c
->widget
.parent
;
435 dlg_select_widget (h
, c
);
436 if (event
->type
& GPM_UP
){
437 check_callback (c
, WIDGET_KEY
, ' ');
438 check_callback (c
, WIDGET_FOCUS
, 0);
439 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
447 check_destroy (WCheck
*c
)
453 check_new (int y
, int x
, int state
, char *text
, char *tkname
)
455 WCheck
*c
= g_new (WCheck
, 1);
458 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
459 (callback_fn
)check_callback
,
460 (destroy_fn
)check_destroy
, (mouse_h
) check_event
, tkname
);
461 c
->state
= state
? C_BOOL
: 0;
462 c
->text
= g_strdup (text
);
465 widget_want_hotkey (c
->widget
, 1);
467 /* Scan for the hotkey */
468 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
475 c
->hotkey
= tolower (*s
);
476 c
->hotpos
= t
- c
->text
;
488 label_callback (WLabel
*l
, int Msg
, int Par
)
490 Dlg_head
*h
= l
->widget
.parent
;
492 if (Msg
== WIDGET_INIT
)
495 /* We don't want to get the focus */
496 if (Msg
== WIDGET_FOCUS
)
498 if (Msg
== WIDGET_DRAW
&& l
->text
){
499 char *p
= l
->text
, *q
, c
= 0;
502 attrset (DEFAULT_COLOR
);
508 q
= strchr (p
, '\n');
513 widget_move (&l
->widget
, y
, 0);
515 xlen
= l
->widget
.cols
- strlen (p
);
517 printw ("%*s", xlen
, " ");
526 return default_proc (Msg
, Par
);
530 label_set_text (WLabel
*label
, char *text
)
532 int newcols
= label
->widget
.cols
;
534 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
535 return; /* Flickering is not nice */
538 g_free (label
->text
);
541 label
->text
= g_strdup (text
);
542 if (label
->auto_adjust_cols
) {
543 newcols
= strlen (text
);
544 if (newcols
> label
->widget
.cols
)
545 label
->widget
.cols
= newcols
;
550 if (label
->widget
.parent
)
551 label_callback (label
, WIDGET_DRAW
, 0);
553 if (newcols
< label
->widget
.cols
)
554 label
->widget
.cols
= newcols
;
558 label_destroy (WLabel
*l
)
565 label_new (int y
, int x
, const char *text
, char *tkname
)
570 /* Multiline labels are immutable - no need to compute their sizes */
571 if (!text
|| strchr(text
, '\n'))
574 width
= strlen (text
);
576 l
= g_new (WLabel
, 1);
577 init_widget (&l
->widget
, y
, x
, 1, width
,
578 (callback_fn
) label_callback
,
579 (destroy_fn
) label_destroy
, NULL
, tkname
);
580 l
->text
= text
? g_strdup (text
) : 0;
581 l
->auto_adjust_cols
= 1;
583 widget_want_cursor (l
->widget
, 0);
588 /* Gauge widget (progress indicator) */
589 /* Currently width is hardcoded here for text mode */
593 gauge_callback (WGauge
*g
, int Msg
, int Par
)
595 Dlg_head
*h
= g
->widget
.parent
;
597 if (Msg
== WIDGET_INIT
)
600 /* We don't want to get the focus */
601 if (Msg
== WIDGET_FOCUS
)
604 if (Msg
== WIDGET_DRAW
){
605 widget_move (&g
->widget
, 0, 0);
608 printw ("%*s", gauge_len
, "");
610 long percentage
, columns
;
611 long total
= g
->max
, done
= g
->current
;
613 if (total
<= 0 || done
< 0) {
619 while (total
> 65535) {
623 percentage
= (200 * done
/ total
+ 1) / 2;
624 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
626 attrset (GAUGE_COLOR
);
627 printw ("%*s", columns
, "");
629 printw ("%*s] %3d%%", gauge_len
- 7 - columns
, "", percentage
);
633 return default_proc (Msg
, Par
);
637 gauge_set_value (WGauge
*g
, int max
, int current
)
639 if (g
->current
== current
&& g
->max
== max
)
640 return; /* Do not flicker */
642 max
= 1; /* I do not like division by zero :) */
644 g
->current
= current
;
646 gauge_callback (g
, WIDGET_DRAW
, 0);
650 gauge_show (WGauge
*g
, int shown
)
652 if (g
->shown
== shown
)
655 gauge_callback (g
, WIDGET_DRAW
, 0);
659 gauge_destroy (WGauge
*g
)
665 gauge_new (int y
, int x
, int shown
, int max
, int current
, char *tkname
)
667 WGauge
*g
= g_new (WGauge
, 1);
669 init_widget (&g
->widget
, y
, x
, 1, gauge_len
,
670 (callback_fn
) gauge_callback
,
671 (destroy_fn
) gauge_destroy
, NULL
, tkname
);
674 max
= 1; /* I do not like division by zero :) */
676 g
->current
= current
;
677 widget_want_cursor (g
->widget
, 0);
684 /* {{{ history button */
686 #define LARGE_HISTORY_BUTTON 1
688 #ifdef LARGE_HISTORY_BUTTON
689 # define HISTORY_BUTTON_WIDTH 3
691 # define HISTORY_BUTTON_WIDTH 1
694 #define should_show_history_button(in) \
695 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
697 static void draw_history_button (WInput
* in
)
700 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
701 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
702 #ifdef LARGE_HISTORY_BUTTON
705 h
= in
->widget
.parent
;
707 attrset (NORMALC
); /* button has the same colour as other buttons */
709 attrset (HOT_NORMALC
);
711 attrset (NORMAL_COLOR
);
713 /* Too distracting: attrset (MARKED_COLOR); */
715 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
719 attrset (MARKED_COLOR
);
724 /* }}} history button */
727 /* Input widgets now have a global kill ring */
728 /* Pointer to killed data */
729 static char *kill_buffer
= 0;
732 update_input (WInput
*in
, int clear_first
)
737 int buf_len
= strlen (in
->buffer
);
739 if (should_show_history_button (in
))
740 has_history
= HISTORY_BUTTON_WIDTH
;
742 if (in
->disable_update
)
745 /* Make the point visible */
746 if ((in
->point
< in
->first_shown
) ||
747 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
748 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
749 if (in
->first_shown
< 0)
753 /* Adjust the mark */
754 if (in
->mark
> buf_len
)
758 draw_history_button (in
);
762 widget_move (&in
->widget
, 0, 0);
763 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
765 widget_move (&in
->widget
, 0, 0);
767 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
768 c
= in
->buffer
[j
++];
769 c
= is_printable (c
) ? c
: '.';
774 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
781 winput_set_origin (WInput
*in
, int x
, int field_len
)
784 in
->field_len
= in
->widget
.cols
= field_len
;
785 update_input (in
, 0);
788 /* {{{ history saving and loading */
790 int num_history_items_recorded
= 60;
793 This loads and saves the history of an input line to and from the
794 widget. It is called with the widgets tk name on creation of the
795 widget, and returns the GList list. It stores histories in the file
796 ~/.mc/history in using the profile code.
798 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
799 function) then input_new assigns the default text to be the last text
800 entered, or "" if not found.
804 history_get (char *input_name
)
812 if (!num_history_items_recorded
) /* this is how to disable */
818 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
820 char key_name
[BUF_TINY
];
821 char this_entry
[BUF_LARGE
];
822 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
823 GetPrivateProfileString (input_name
, key_name
, "", this_entry
,
824 sizeof (this_entry
), profile
);
828 hist
= list_append_unique (hist
, g_strdup (this_entry
));
832 /* return pointer to the last entry in the list */
833 hist
= g_list_last (hist
);
839 history_put (char *input_name
, GList
*h
)
853 if (!num_history_items_recorded
) /* this is how to disable */
856 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
858 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
861 /* Make sure the history is only readable by the user */
862 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
867 /* go to end of list */
870 /* go back 60 places */
871 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
872 h
= g_list_previous (h
);
875 profile_clean_section (input_name
, profile
);
877 /* dump histories into profile */
878 for (i
= 0; h
; h
= g_list_next (h
)) {
881 text
= (char *) h
->data
;
883 /* We shouldn't have null entries, but let's be sure */
885 char key_name
[BUF_TINY
];
886 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
887 WritePrivateProfileString (input_name
, key_name
, text
,
895 /* }}} history saving and loading */
898 /* {{{ history display */
903 static char *history_title
= NULL
;
905 if (history_title
== NULL
)
906 history_title
= _(" History ");
907 return history_title
;
910 static inline int listbox_fwd (WListbox
*l
);
913 show_hist (GList
*history
, int widget_x
, int widget_y
)
916 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
920 WListbox
*query_list
;
926 z
= g_list_first (history
);
929 if ((i
= strlen ((char *) hi
->data
)) > maxlen
)
932 hi
= g_list_next (hi
);
937 if (h
<= y
|| y
> LINES
- 6) {
942 h
= min (h
, LINES
- y
);
949 if ((w
= maxlen
+ 4) + x
> COLS
) {
955 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
956 i18n_htitle (), DLG_COMPACT
);
957 query_list
= listbox_new (1, 1, w
- 2, h
- 2, listbox_finish
, 0, NULL
);
958 add_widget (query_dlg
, query_list
);
963 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
964 hi
= g_list_next (hi
);
966 while (listbox_fwd (query_list
));
968 /* traverse backwards */
969 hi
= g_list_last (history
);
971 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
972 hi
= g_list_previous (hi
);
977 if (query_dlg
->ret_value
!= B_CANCEL
) {
978 listbox_get_current (query_list
, &q
, NULL
);
982 destroy_dlg (query_dlg
);
986 static void do_show_hist (WInput
* in
)
989 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
996 /* }}} history display */
999 input_destroy (WInput
*in
)
1002 fprintf (stderr
, "Internal error: null Input *\n");
1009 if (!in
->is_password
) /* don't save passwords ;-) */
1010 history_put (in
->history_name
, in
->history
);
1012 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1013 g_list_free (in
->history
);
1016 g_free (in
->buffer
);
1017 free_completions (in
);
1018 if (in
->history_name
)
1019 g_free (in
->history_name
);
1022 static char disable_update
= 0;
1025 input_disable_update (WInput
*in
)
1027 in
->disable_update
++;
1031 input_enable_update (WInput
*in
)
1033 in
->disable_update
--;
1034 update_input (in
, 0);
1037 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1040 push_history (WInput
*in
, char *text
)
1043 /* input widget where urls with passwords are entered without any
1045 static const char *password_input_fields
[] = {
1046 N_(" Link to a remote machine "),
1047 N_(" FTP to machine "),
1048 N_(" SMB link to machine ")
1056 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1057 password_input_fields
[i
] = _(password_input_fields
[i
]);
1060 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1065 /* Avoid duplicated entries */
1066 in
->history
= g_list_last (in
->history
);
1067 if (!strcmp ((char *) in
->history
->data
, text
))
1071 t
= g_strdup (text
);
1073 if (in
->history_name
) {
1074 p
= in
->history_name
+ 3;
1075 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1076 if (strcmp (p
, password_input_fields
[i
]) == 0)
1078 if (i
< ELEMENTS (password_input_fields
))
1079 strip_password (t
, 0);
1081 strip_password (t
, 1);
1084 in
->history
= list_append_unique (in
->history
, t
);
1092 /* Cleans the input line and adds the current text to the history */
1094 new_input (WInput
*in
)
1097 push_history (in
, in
->buffer
);
1102 free_completions (in
);
1103 update_input (in
, 0);
1107 insert_char (WInput
*in
, int c_code
)
1115 if (strlen (in
->buffer
)+1 == in
->current_max_len
){
1116 /* Expand the buffer */
1117 char *narea
= g_malloc (in
->current_max_len
+ in
->field_len
);
1119 char *p
= in
->buffer
;
1121 strcpy (narea
, in
->buffer
);
1123 in
->current_max_len
+= in
->field_len
;
1127 if (strlen (in
->buffer
)+1 < in
->current_max_len
){
1128 int l
= strlen (&in
->buffer
[in
->point
]);
1129 for (i
= l
+1; i
> 0; i
--)
1130 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1131 in
->buffer
[in
->point
] = c_code
;
1138 beginning_of_line (WInput
*in
)
1144 end_of_line (WInput
*in
)
1146 in
->point
= strlen (in
->buffer
);
1150 backward_char (WInput
*in
)
1157 forward_char (WInput
*in
)
1159 if (in
->buffer
[in
->point
])
1164 forward_word (WInput
*in
)
1166 unsigned char *p
= in
->buffer
+in
->point
;
1168 while (*p
&& (isspace (*p
) || ispunct (*p
)))
1170 while (*p
&& isalnum (*p
))
1172 in
->point
= p
- in
->buffer
;
1176 backward_word (WInput
*in
)
1178 unsigned char *p
= in
->buffer
+in
->point
;
1180 while (p
-1 > in
->buffer
-1 && (isspace (*(p
-1)) || ispunct (*(p
-1))))
1182 while (p
-1 > in
->buffer
-1 && isalnum (*(p
-1)))
1184 in
->point
= p
- in
->buffer
;
1188 key_left (WInput
*in
)
1194 key_ctrl_left (WInput
*in
)
1200 key_right (WInput
*in
)
1206 key_ctrl_right (WInput
*in
)
1211 backward_delete (WInput
*in
)
1217 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1218 in
->buffer
[i
-1] = in
->buffer
[i
];
1224 delete_char (WInput
*in
)
1228 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1229 in
->buffer
[i
] = in
->buffer
[i
+1];
1234 copy_region (WInput
*in
, int x_first
, int x_last
)
1236 int first
= min (x_first
, x_last
);
1237 int last
= max (x_first
, x_last
);
1243 g_free (kill_buffer
);
1245 kill_buffer
= g_malloc (last
-first
+ 1);
1246 strncpy (kill_buffer
, in
->buffer
+first
, last
-first
);
1247 kill_buffer
[last
-first
] = 0;
1251 delete_region (WInput
*in
, int x_first
, int x_last
)
1253 int first
= min (x_first
, x_last
);
1254 int last
= max (x_first
, x_last
);
1258 strcpy (&in
->buffer
[first
], &in
->buffer
[last
]);
1263 kill_word (WInput
*in
)
1265 int old_point
= in
->point
;
1269 new_point
= in
->point
;
1270 in
->point
= old_point
;
1272 copy_region (in
, old_point
, new_point
);
1273 delete_region (in
, old_point
, new_point
);
1278 back_kill_word (WInput
*in
)
1280 int old_point
= in
->point
;
1284 new_point
= in
->point
;
1285 in
->point
= old_point
;
1287 copy_region (in
, old_point
, new_point
);
1288 delete_region (in
, old_point
, new_point
);
1293 set_mark (WInput
*in
)
1295 in
->mark
= in
->point
;
1299 kill_save (WInput
*in
)
1301 copy_region (in
, in
->mark
, in
->point
);
1305 kill_region (WInput
*in
)
1308 delete_region (in
, in
->point
, in
->mark
);
1318 for (p
= kill_buffer
; *p
; p
++)
1319 insert_char (in
, *p
);
1323 kill_line (WInput
*in
)
1326 g_free (kill_buffer
);
1327 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1328 in
->buffer
[in
->point
] = 0;
1332 assign_text (WInput
*in
, char *text
)
1334 free_completions (in
);
1335 g_free (in
->buffer
);
1336 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1337 in
->current_max_len
= strlen (in
->buffer
) + 1;
1338 in
->point
= strlen (in
->buffer
);
1344 hist_prev (WInput
*in
)
1349 if (in
->need_push
) {
1350 switch (push_history (in
, in
->buffer
)) {
1352 in
->history
= g_list_previous (in
->history
);
1355 if (in
->history
->prev
)
1356 in
->history
= g_list_previous (in
->history
);
1361 } else if (in
->history
->prev
)
1362 in
->history
= g_list_previous (in
->history
);
1365 assign_text (in
, (char *) in
->history
->data
);
1370 hist_next (WInput
*in
)
1372 if (in
->need_push
) {
1373 switch (push_history (in
, in
->buffer
)) {
1375 assign_text (in
, "");
1385 if (!in
->history
->next
) {
1386 assign_text (in
, "");
1390 in
->history
= g_list_next (in
->history
);
1391 assign_text (in
, (char *) in
->history
->data
);
1395 static const struct {
1397 void (*fn
)(WInput
*in
);
1400 { XCTRL('a'), beginning_of_line
},
1401 { KEY_HOME
, beginning_of_line
},
1402 { KEY_A1
, beginning_of_line
},
1403 { XCTRL('e'), end_of_line
},
1404 { KEY_END
, end_of_line
},
1405 { KEY_C1
, end_of_line
},
1406 { KEY_LEFT
, key_left
},
1407 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1408 { XCTRL('b'), backward_char
},
1409 { ALT('b'), backward_word
},
1410 { KEY_RIGHT
, key_right
},
1411 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1412 { XCTRL('f'), forward_char
},
1413 { ALT('f'), forward_word
},
1416 { KEY_BACKSPACE
, backward_delete
},
1417 { KEY_DC
, delete_char
},
1418 { ALT('d'), kill_word
},
1419 { ALT(KEY_BACKSPACE
), back_kill_word
},
1421 /* Region manipulation */
1423 { XCTRL('w'), kill_region
},
1424 { ALT('w'), kill_save
},
1425 { XCTRL('y'), yank
},
1426 { XCTRL('k'), kill_line
},
1429 { ALT('p'), hist_prev
},
1430 { ALT('n'), hist_next
},
1431 { ALT('h'), do_show_hist
},
1434 { ALT('\t'), complete
},
1439 /* This function is a test for a special input key used in complete.c */
1440 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1441 and 2 if it is a complete key */
1443 is_in_input_map (WInput
*in
, int c_code
)
1447 for (i
= 0; input_map
[i
].fn
; i
++)
1448 if (c_code
== input_map
[i
].key_code
) {
1449 if (input_map
[i
].fn
== complete
)
1458 port_region_marked_for_delete (WInput
*in
)
1466 handle_char (WInput
*in
, int c_code
)
1474 free_completions (in
);
1475 v
= insert_char (in
, c_code
);
1476 update_input (in
, 1);
1481 for (i
= 0; input_map
[i
].fn
; i
++){
1482 if (c_code
== input_map
[i
].key_code
){
1483 if (input_map
[i
].fn
!= complete
)
1484 free_completions (in
);
1485 (*input_map
[i
].fn
)(in
);
1490 if (!input_map
[i
].fn
){
1491 if (c_code
> 255 || !is_printable (c_code
))
1494 port_region_marked_for_delete (in
);
1496 free_completions (in
);
1497 v
= insert_char (in
, c_code
);
1499 if (!disable_update
)
1500 update_input (in
, 1);
1504 /* Inserts text in input line */
1506 stuff (WInput
*in
, char *text
, int insert_extra_space
)
1508 input_disable_update (in
);
1510 handle_char (in
, *text
++);
1511 if (insert_extra_space
)
1512 handle_char (in
, ' ');
1513 input_enable_update (in
);
1514 update_input (in
, 1);
1518 input_set_point (WInput
*in
, int pos
)
1520 if (pos
> in
->current_max_len
)
1521 pos
= in
->current_max_len
;
1522 if (pos
!= in
->point
)
1523 free_completions (in
);
1525 update_input (in
, 1);
1529 input_callback (WInput
*in
, int Msg
, int Par
)
1532 Dlg_head
*h
= in
->widget
.parent
;
1539 if (Par
== XCTRL ('q')) {
1541 v
= handle_char (in
, mi_getch ());
1545 if (Par
== KEY_UP
|| Par
== KEY_DOWN
|| Par
== ESC_CHAR
1546 || Par
== KEY_F (10) || Par
== XCTRL ('g'))
1547 return 0; /* We don't handle up/down */
1554 /* When pasting multiline text, insert literal Enter */
1555 if ((Par
& ~KEY_M_MASK
) == '\n') {
1557 v
= handle_char (in
, '\n');
1562 return handle_char (in
, Par
);
1565 case WIDGET_UNFOCUS
:
1567 update_input (in
, 0);
1570 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1574 return default_proc (Msg
, Par
);
1578 input_event (Gpm_Event
* event
, WInput
* in
)
1580 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1581 dlg_select_widget (in
->widget
.parent
, in
);
1583 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1584 && should_show_history_button (in
)) {
1587 in
->point
= strlen (in
->buffer
);
1588 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1589 in
->point
= event
->x
- in
->first_shown
- 1;
1593 update_input (in
, 1);
1599 input_new (int y
, int x
, int color
, int len
, const char *def_text
, char *tkname
)
1601 WInput
*in
= g_new (WInput
, 1);
1602 int initial_buffer_len
;
1604 init_widget (&in
->widget
, y
, x
, 1, len
,
1605 (callback_fn
) input_callback
,
1606 (destroy_fn
) input_destroy
, (mouse_h
) input_event
, tkname
);
1610 in
->history_name
= 0;
1613 in
->history_name
= g_strdup (tkname
);
1614 in
->history
= history_get (tkname
);
1621 if (def_text
== INPUT_LAST_TEXT
) {
1624 if (in
->history
->data
)
1625 def_text
= (char *) in
->history
->data
;
1627 initial_buffer_len
= 1 + max (len
, strlen (def_text
));
1628 in
->widget
.options
|= W_IS_INPUT
;
1629 in
->completions
= NULL
;
1630 in
->completion_flags
=
1631 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
|
1632 INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
;
1633 in
->current_max_len
= initial_buffer_len
;
1634 in
->buffer
= g_malloc (initial_buffer_len
);
1636 in
->field_len
= len
;
1638 in
->first_shown
= 0;
1639 in
->disable_update
= 0;
1642 in
->is_password
= 0;
1644 strcpy (in
->buffer
, def_text
);
1645 in
->point
= strlen (in
->buffer
);
1650 /* Listbox widget */
1652 /* Should draw the scrollbar, but currently draws only
1653 * indications that there is more information
1655 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1658 listbox_drawscroll (WListbox
*l
)
1660 extern int slow_terminal
;
1663 int max_line
= l
->height
-1;
1665 /* Are we at the top? */
1666 widget_move (&l
->widget
, 0, l
->width
);
1667 if (l
->list
== l
->top
)
1672 /* Are we at the bottom? */
1673 widget_move (&l
->widget
, max_line
, l
->width
);
1674 top
= listbox_cdiff (l
->list
, l
->top
);
1675 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1680 /* Now draw the nice relative pointer */
1682 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1686 for (i
= 1; i
< max_line
; i
++){
1687 widget_move (&l
->widget
, i
, l
->width
);
1696 listbox_draw (WListbox
*l
, int focused
)
1701 Dlg_head
*h
= l
->widget
.parent
;
1702 int normalc
= NORMALC
;
1713 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1715 /* Display the entry */
1716 if (e
== l
->current
&& sel_line
== -1){
1722 widget_move (&l
->widget
, i
, 0);
1724 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1730 printw (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1732 l
->cursor_y
= sel_line
;
1736 listbox_drawscroll (l
);
1739 /* Returns the number of items between s and e,
1740 must be on the same linked list */
1742 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1746 for (count
= 0; s
!= e
; count
++)
1752 listbox_check_hotkey (WListbox
*l
, int key
)
1764 /* If we didn't find anything, return */
1765 if (i
&& e
== l
->list
)
1768 if (e
->hotkey
== key
)
1776 /* Used only for display updating, for avoiding line at a time scroll */
1778 listbox_select_last (WListbox
*l
, int set_top
)
1781 l
->current
= l
->list
->prev
;
1782 l
->pos
= l
->count
- 1;
1784 l
->top
= l
->list
->prev
;
1789 listbox_remove_list (WListbox
*l
)
1798 while (l
->count
--) {
1804 l
->pos
= l
->count
= 0;
1805 l
->list
= l
->top
= l
->current
= 0;
1809 * bor 30.10.96: added force flag to remove *last* entry as well
1810 * bor 30.10.96: corrected selection bug if last entry was removed
1814 listbox_remove_current (WListbox
*l
, int force
)
1818 /* Ok, note: this won't allow for emtpy lists */
1819 if (!force
&& (!l
->count
|| l
->count
== 1))
1826 l
->current
->next
->prev
= l
->current
->prev
;
1827 l
->current
->prev
->next
= l
->current
->next
;
1828 if (p
->next
== l
->list
) {
1829 l
->current
= p
->prev
;
1833 l
->current
= p
->next
;
1836 l
->list
= l
->top
= p
->next
;
1839 l
->list
= l
->top
= l
->current
= 0;
1846 /* Makes *e the selected entry (sets current and pos) */
1848 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1857 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1865 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1866 l
->top
= l
->top
->next
;
1868 l
->top
= l
->current
;
1874 /* If we are unable to find it, set decent values */
1875 l
->current
= l
->top
= l
->list
;
1879 /* Selects from base the pos element */
1881 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1883 WLEntry
*last
= l
->list
->prev
;
1896 listbox_back (WListbox
*l
)
1899 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1906 listbox_fwd (WListbox
*l
)
1908 if (l
->current
!= l
->list
->prev
){
1909 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
1915 /* Returns 1 if we want a redraw */
1917 listbox_key (WListbox
*l
, int key
)
1928 l
->current
= l
->top
= l
->list
;
1934 l
->current
= l
->top
= l
->list
->prev
;
1935 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1936 l
->top
= l
->top
->prev
;
1937 l
->pos
= l
->count
- 1;
1952 for (i
= 0; i
< l
->height
-1; i
++)
1953 j
|= listbox_fwd (l
);
1958 for (i
= 0; i
< l
->height
-1; i
++)
1959 j
|= listbox_back (l
);
1965 static int listbox_event (Gpm_Event
*event
, WListbox
*l
);
1967 listbox_callback (WListbox
*l
, int msg
, int par
)
1970 /* int selected_color; Never used */
1978 if ((e
= listbox_check_hotkey (l
, par
)) != NULL
){
1979 listbox_select_entry (l
, e
);
1981 /* Take the appropriate action */
1982 if (l
->action
== listbox_finish
){
1983 l
->widget
.parent
->running
= 0;
1984 l
->widget
.parent
->ret_value
= B_ENTER
;
1985 } else if (l
->action
== listbox_cback
){
1986 if ((*l
->cback
)(l
) == listbox_finish
){
1987 l
->widget
.parent
->running
= 0;
1988 l
->widget
.parent
->ret_value
= B_ENTER
;
1996 if ((ret_code
= listbox_key (l
, par
)))
1997 listbox_draw (l
, 1);
2001 widget_move (&l
->widget
, l
->cursor_y
, 0);
2005 case WIDGET_UNFOCUS
:
2007 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2010 return default_proc (msg
, par
);
2014 listbox_event (Gpm_Event
*event
, WListbox
*l
)
2018 Dlg_head
*h
= l
->widget
.parent
;
2021 if (event
->type
& GPM_DOWN
)
2022 dlg_select_widget (l
->widget
.parent
, l
);
2025 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2026 if (event
->x
< 0 || event
->x
>= l
->width
)
2029 for (i
= -event
->y
; i
>= 0; i
--)
2031 else if (event
->y
> l
->height
)
2032 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2035 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
,
2038 /* We need to refresh ourselves since the dialog manager doesn't */
2039 /* know about this event */
2040 listbox_callback (l
, WIDGET_DRAW
, 0);
2046 if ((event
->type
& (GPM_DOUBLE
|GPM_UP
)) == (GPM_UP
|GPM_DOUBLE
)){
2047 if (event
->x
< 0 || event
->x
>= l
->width
)
2049 if (event
->y
< 1 || event
->y
> l
->height
)
2052 dlg_select_widget (l
->widget
.parent
, l
);
2053 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
, event
->y
- 1));
2056 case listbox_nothing
:
2059 case listbox_finish
:
2060 h
->ret_value
= B_ENTER
;
2065 if ((*l
->cback
)(l
) == listbox_finish
)
2073 listbox_destroy (WListbox
*l
)
2075 WLEntry
*n
, *p
= l
->list
;
2078 for (i
= 0; i
< l
->count
; i
++){
2087 listbox_new (int y
, int x
, int width
, int height
,
2088 int action
, lcback callback
, char *tkname
)
2090 WListbox
*l
= g_new (WListbox
, 1);
2091 extern int slow_terminal
;
2093 init_widget (&l
->widget
, y
, x
, height
, width
,
2094 (callback_fn
)listbox_callback
,
2095 (destroy_fn
) listbox_destroy
, (mouse_h
)listbox_event
, tkname
);
2097 l
->list
= l
->top
= l
->current
= 0;
2107 l
->cback
= callback
;
2109 l
->allow_duplicates
= 1;
2110 l
->scrollbar
= slow_terminal
? 0 : 1;
2111 widget_want_hotkey (l
->widget
, 1);
2116 /* Listbox item adding function. They still lack a lot of functionality */
2118 /* 1.11.96 bor: added pos argument to control placement of new entry */
2120 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2128 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2130 e
->prev
= l
->list
->prev
;
2131 l
->list
->prev
->next
= e
;
2133 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2134 e
->next
= l
->current
;
2135 e
->prev
= l
->current
->prev
;
2136 l
->current
->prev
->next
= e
;
2137 l
->current
->prev
= e
;
2138 if (l
->list
== l
->current
) { /* move list one position down */
2142 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2143 e
->prev
= l
->current
;
2144 e
->next
= l
->current
->next
;
2145 l
->current
->next
->prev
= e
;
2146 l
->current
->next
= e
;
2152 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
, char *text
,
2160 if (!l
->allow_duplicates
)
2161 if (listbox_search_text (l
, text
))
2164 entry
= g_new (WLEntry
, 1);
2165 entry
->text
= g_strdup (text
);
2167 entry
->hotkey
= hotkey
;
2169 listbox_append_item (l
, entry
, pos
);
2174 /* Selects the nth entry in the listbox */
2176 listbox_select_by_number (WListbox
*l
, int n
)
2178 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2182 listbox_search_text (WListbox
*l
, char *text
)
2191 if(!strcmp (e
->text
, text
))
2194 } while (e
!=l
->list
);
2199 /* Returns the current string text as well as the associated extra data */
2201 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2207 if (string
&& l
->current
)
2208 *string
= l
->current
->text
;
2209 if (extra
&& l
->current
)
2210 *extra
= l
->current
->data
;
2214 buttonbar_callback (WButtonBar
*bb
, int msg
, int par
)
2226 for (i
= 0; i
< 10; i
++){
2227 if (par
== KEY_F(i
+1) && bb
->labels
[i
].function
){
2228 (*bb
->labels
[i
].function
)(bb
->labels
[i
].data
);
2237 widget_move (&bb
->widget
, 0, 0);
2238 attrset (DEFAULT_COLOR
);
2239 printw ("%-*s", bb
->widget
.cols
, "");
2240 for (i
= 0; i
< COLS
/8 && i
< 10; i
++){
2241 widget_move (&bb
->widget
, 0, i
*8);
2242 attrset (DEFAULT_COLOR
);
2244 attrset (SELECTED_COLOR
);
2245 printw ("%-*s", ((i
+1) * 8 == COLS
? 5 : 6),
2246 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2247 attrset (DEFAULT_COLOR
);
2249 attrset (SELECTED_COLOR
);
2252 return default_proc (msg
, par
);
2256 buttonbar_destroy (WButtonBar
*bb
)
2260 for (i
= 0; i
< 10; i
++){
2261 if (bb
->labels
[i
].text
)
2262 g_free (bb
->labels
[i
].text
);
2267 buttonbar_event (Gpm_Event
*event
, WButtonBar
*bb
)
2271 if (!(event
->type
& GPM_UP
))
2275 button
= event
->x
/ 8;
2276 if (button
< 10 && bb
->labels
[button
].function
)
2277 (*bb
->labels
[button
].function
)(bb
->labels
[button
].data
);
2282 buttonbar_new (int visible
)
2285 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2287 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2288 (callback_fn
) buttonbar_callback
,
2289 (destroy_fn
) buttonbar_destroy
, (mouse_h
) buttonbar_event
, NULL
);
2291 bb
->visible
= visible
;
2292 for (i
= 0; i
< 10; i
++){
2293 bb
->labels
[i
].text
= 0;
2294 bb
->labels
[i
].function
= 0;
2296 widget_want_hotkey (bb
->widget
, 1);
2297 widget_want_cursor (bb
->widget
, 0);
2303 set_label_text (WButtonBar
* bb
, int index
, char *text
)
2305 if (bb
->labels
[index
- 1].text
)
2306 g_free (bb
->labels
[index
- 1].text
);
2308 bb
->labels
[index
- 1].text
= g_strdup (text
);
2311 /* Find ButtonBar widget in the dialog */
2313 find_buttonbar (Dlg_head
*h
)
2317 bb
= (WButtonBar
*) find_widget_type (h
, (callback_fn
)
2318 buttonbar_callback
);
2323 define_label_data (Dlg_head
*h
, int idx
, char *text
, buttonbarfn cback
,
2326 WButtonBar
*bb
= find_buttonbar (h
);
2331 set_label_text (bb
, idx
, text
);
2332 bb
->labels
[idx
- 1].function
= cback
;
2333 bb
->labels
[idx
- 1].data
= data
;
2337 define_label (Dlg_head
*h
, int idx
, char *text
, void (*cback
) (void))
2339 define_label_data (h
, idx
, text
, (buttonbarfn
) cback
, 0);
2342 /* Redraw labels of the buttonbar */
2344 redraw_labels (Dlg_head
*h
)
2346 WButtonBar
*bb
= find_buttonbar (h
);
2351 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);