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 */
791 This loads and saves the history of an input line to and from the
792 widget. It is called with the widgets tk name on creation of the
793 widget, and returns the Hist list. It stores histories in the file
794 ~/.mc/history in using the profile code.
796 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
797 function) then input_new assigns the default text to be the last text
798 entered, or "" if not found.
801 int num_history_items_recorded
= 60;
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
, sizeof (this_entry
), profile
);
826 new = g_new0 (Hist
, 1);
827 new->text
= g_strdup (this_entry
);
828 new->prev
= old
; /* set up list pointers */
834 return new; /* return pointer to last entry in list */
838 history_put (char *input_name
, Hist
*h
)
852 if (!num_history_items_recorded
) /* this is how to disable */
855 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
857 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
859 /* Just in case I forgot to strip passwords somewhere -- Norbert */
860 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
){
865 while (h
->next
) /* go to end of list */
868 /* go back 60 places */
869 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
873 profile_clean_section (input_name
, profile
);
875 /* dump histories into profile */
876 for (i
= 0; h
; h
= h
->next
){
879 /* probably aren't any null entries, but lets be sure */
881 char key_name
[BUF_TINY
];
882 g_snprintf (key_name
, sizeof(key_name
), "%d", i
++);
883 WritePrivateProfileString (input_name
, key_name
, h
->text
, profile
);
890 /* }}} history saving and loading */
893 /* {{{ history display */
898 static char *history_title
= NULL
;
900 if (history_title
== NULL
)
901 history_title
= _(" History ");
902 return history_title
;
905 static inline int listbox_fwd (WListbox
*l
);
908 show_hist (Hist
* history
, int widget_x
, int widget_y
)
911 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
915 WListbox
*query_list
;
921 while (z
->prev
) /* goto first */
925 if ((i
= strlen (hi
->text
)) > maxlen
)
933 if (h
<= y
|| y
> LINES
- 6) {
938 h
= min (h
, LINES
- y
);
945 if ((w
= maxlen
+ 4) + x
> COLS
) {
951 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
952 i18n_htitle (), DLG_COMPACT
);
953 query_list
= listbox_new (1, 1, w
- 2, h
- 2, listbox_finish
, 0, NULL
);
954 add_widget (query_dlg
, query_list
);
957 while (hi
) { /* traverse */
958 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
961 while (listbox_fwd (query_list
));
965 while (hi
) { /* traverse backwards */
966 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
972 if (query_dlg
->ret_value
!= B_CANCEL
) {
973 listbox_get_current (query_list
, &q
, NULL
);
977 destroy_dlg (query_dlg
);
981 static void do_show_hist (WInput
* in
)
984 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
991 /* }}} history display */
994 input_destroy (WInput
*in
)
997 fprintf (stderr
, "Internal error: null Input *\n");
1003 Hist
*current
, *old
;
1005 if (!in
->is_password
) /* don't save passwords ;-) */
1006 history_put (in
->history_name
, in
->history
);
1008 current
= in
->history
;
1009 while (current
->next
)
1010 current
= current
->next
;
1013 current
= current
->prev
;
1018 g_free (in
->buffer
);
1019 free_completions (in
);
1020 if (in
->history_name
)
1021 g_free (in
->history_name
);
1024 static char disable_update
= 0;
1027 input_disable_update (WInput
*in
)
1029 in
->disable_update
++;
1033 input_enable_update (WInput
*in
)
1035 in
->disable_update
--;
1036 update_input (in
, 0);
1039 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1042 push_history (WInput
*in
, char *text
)
1045 /* input widget where urls with passwords are entered without any
1047 static const char *password_input_fields
[] = {
1048 N_(" Link to a remote machine "),
1049 N_(" FTP to machine "),
1050 N_(" SMB link to machine ")
1058 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1059 password_input_fields
[i
] = _(password_input_fields
[i
]);
1062 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1066 while (in
->history
->next
)
1067 in
->history
= in
->history
->next
;
1068 if (!strcmp (in
->history
->text
, text
))
1070 new = g_new (Hist
, 1);
1071 in
->history
->next
= new;
1073 new = g_new (Hist
, 1);
1076 new->prev
= in
->history
;
1077 new->text
= g_strdup (text
);
1078 if (in
->history_name
) {
1079 p
= in
->history_name
+ 3;
1080 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1081 if (strcmp (p
, password_input_fields
[i
]) == 0)
1083 if (i
< ELEMENTS(password_input_fields
))
1084 strip_password (new->text
, 0);
1086 strip_password (new->text
, 1);
1095 /* Cleans the input line and adds the current text to the history */
1097 new_input (WInput
*in
)
1100 push_history (in
, in
->buffer
);
1105 free_completions (in
);
1106 update_input (in
, 0);
1110 insert_char (WInput
*in
, int c_code
)
1118 if (strlen (in
->buffer
)+1 == in
->current_max_len
){
1119 /* Expand the buffer */
1120 char *narea
= g_malloc (in
->current_max_len
+ in
->field_len
);
1122 char *p
= in
->buffer
;
1124 strcpy (narea
, in
->buffer
);
1126 in
->current_max_len
+= in
->field_len
;
1130 if (strlen (in
->buffer
)+1 < in
->current_max_len
){
1131 int l
= strlen (&in
->buffer
[in
->point
]);
1132 for (i
= l
+1; i
> 0; i
--)
1133 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1134 in
->buffer
[in
->point
] = c_code
;
1141 beginning_of_line (WInput
*in
)
1147 end_of_line (WInput
*in
)
1149 in
->point
= strlen (in
->buffer
);
1153 backward_char (WInput
*in
)
1160 forward_char (WInput
*in
)
1162 if (in
->buffer
[in
->point
])
1167 forward_word (WInput
*in
)
1169 unsigned char *p
= in
->buffer
+in
->point
;
1171 while (*p
&& (isspace (*p
) || ispunct (*p
)))
1173 while (*p
&& isalnum (*p
))
1175 in
->point
= p
- in
->buffer
;
1179 backward_word (WInput
*in
)
1181 unsigned char *p
= in
->buffer
+in
->point
;
1183 while (p
-1 > in
->buffer
-1 && (isspace (*(p
-1)) || ispunct (*(p
-1))))
1185 while (p
-1 > in
->buffer
-1 && isalnum (*(p
-1)))
1187 in
->point
= p
- in
->buffer
;
1191 key_left (WInput
*in
)
1193 if (ctrl_pressed ())
1200 key_right (WInput
*in
)
1202 if (ctrl_pressed ())
1209 backward_delete (WInput
*in
)
1215 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1216 in
->buffer
[i
-1] = in
->buffer
[i
];
1222 delete_char (WInput
*in
)
1226 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1227 in
->buffer
[i
] = in
->buffer
[i
+1];
1232 copy_region (WInput
*in
, int x_first
, int x_last
)
1234 int first
= min (x_first
, x_last
);
1235 int last
= max (x_first
, x_last
);
1241 g_free (kill_buffer
);
1243 kill_buffer
= g_malloc (last
-first
+ 1);
1244 strncpy (kill_buffer
, in
->buffer
+first
, last
-first
);
1245 kill_buffer
[last
-first
] = 0;
1249 delete_region (WInput
*in
, int x_first
, int x_last
)
1251 int first
= min (x_first
, x_last
);
1252 int last
= max (x_first
, x_last
);
1256 strcpy (&in
->buffer
[first
], &in
->buffer
[last
]);
1261 kill_word (WInput
*in
)
1263 int old_point
= in
->point
;
1267 new_point
= in
->point
;
1268 in
->point
= old_point
;
1270 copy_region (in
, old_point
, new_point
);
1271 delete_region (in
, old_point
, new_point
);
1276 back_kill_word (WInput
*in
)
1278 int old_point
= in
->point
;
1282 new_point
= in
->point
;
1283 in
->point
= old_point
;
1285 copy_region (in
, old_point
, new_point
);
1286 delete_region (in
, old_point
, new_point
);
1291 set_mark (WInput
*in
)
1293 in
->mark
= in
->point
;
1297 kill_save (WInput
*in
)
1299 copy_region (in
, in
->mark
, in
->point
);
1303 kill_region (WInput
*in
)
1306 delete_region (in
, in
->point
, in
->mark
);
1316 for (p
= kill_buffer
; *p
; p
++)
1317 insert_char (in
, *p
);
1321 kill_line (WInput
*in
)
1324 g_free (kill_buffer
);
1325 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1326 in
->buffer
[in
->point
] = 0;
1330 assign_text (WInput
*in
, char *text
)
1332 free_completions (in
);
1333 g_free (in
->buffer
);
1334 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1335 in
->current_max_len
= strlen (in
->buffer
) + 1;
1336 in
->point
= strlen (in
->buffer
);
1342 hist_prev (WInput
*in
)
1347 if (in
->need_push
) {
1348 switch (push_history (in
, in
->buffer
)) {
1349 case 2: in
->history
= in
->history
->prev
; break;
1350 case 1: if (in
->history
->prev
) in
->history
= in
->history
->prev
; break;
1353 } else if (in
->history
->prev
)
1354 in
->history
= in
->history
->prev
;
1357 assign_text (in
, in
->history
->text
);
1362 hist_next (WInput
*in
)
1364 if (in
->need_push
) {
1365 switch (push_history (in
, in
->buffer
)) {
1367 assign_text (in
, "");
1377 if (!in
->history
->next
) {
1378 assign_text (in
, "");
1382 in
->history
= in
->history
->next
;
1383 assign_text (in
, in
->history
->text
);
1387 static const struct {
1389 void (*fn
)(WInput
*in
);
1392 { XCTRL('a'), beginning_of_line
},
1393 { KEY_HOME
, beginning_of_line
},
1394 { KEY_A1
, beginning_of_line
},
1395 { XCTRL('e'), end_of_line
},
1396 { KEY_END
, end_of_line
},
1397 { KEY_C1
, end_of_line
},
1398 { KEY_LEFT
, key_left
},
1399 { XCTRL('b'), backward_char
},
1400 { ALT('b'), backward_word
},
1401 { KEY_RIGHT
, key_right
},
1402 { XCTRL('f'), forward_char
},
1403 { ALT('f'), forward_word
},
1406 { 0177, backward_delete
},
1407 { KEY_BACKSPACE
, backward_delete
},
1408 { XCTRL('h'), backward_delete
},
1409 { KEY_DC
, delete_char
},
1410 { XCTRL('d'), delete_char
},
1411 { ALT('d'), kill_word
},
1412 { ALT(KEY_BACKSPACE
), back_kill_word
},
1413 { ALT(XCTRL('h')), back_kill_word
},
1414 { ALT(127), back_kill_word
},
1416 /* Region manipulation */
1418 { XCTRL('w'), kill_region
},
1419 { ALT('w'), kill_save
},
1420 { XCTRL('y'), yank
},
1421 { XCTRL('k'), kill_line
},
1424 { ALT('p'), hist_prev
},
1425 { ALT('n'), hist_next
},
1426 { ALT('h'), do_show_hist
},
1429 { ALT('\t'), complete
},
1434 /* This function is a test for a special input key used in complete.c */
1435 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1436 and 2 if it is a complete key */
1438 is_in_input_map (WInput
*in
, int c_code
)
1442 for (i
= 0; input_map
[i
].fn
; i
++)
1443 if (c_code
== input_map
[i
].key_code
) {
1444 if (input_map
[i
].fn
== complete
)
1453 port_region_marked_for_delete (WInput
*in
)
1461 handle_char (WInput
*in
, int c_code
)
1469 free_completions (in
);
1470 v
= insert_char (in
, c_code
);
1471 update_input (in
, 1);
1476 for (i
= 0; input_map
[i
].fn
; i
++){
1477 if (c_code
== input_map
[i
].key_code
){
1478 if (input_map
[i
].fn
!= complete
)
1479 free_completions (in
);
1480 (*input_map
[i
].fn
)(in
);
1485 if (!input_map
[i
].fn
){
1486 if (c_code
> 255 || !is_printable (c_code
))
1489 port_region_marked_for_delete (in
);
1491 free_completions (in
);
1492 v
= insert_char (in
, c_code
);
1494 if (!disable_update
)
1495 update_input (in
, 1);
1499 /* Inserts text in input line */
1501 stuff (WInput
*in
, char *text
, int insert_extra_space
)
1503 input_disable_update (in
);
1505 handle_char (in
, *text
++);
1506 if (insert_extra_space
)
1507 handle_char (in
, ' ');
1508 input_enable_update (in
);
1509 update_input (in
, 1);
1513 input_set_point (WInput
*in
, int pos
)
1515 if (pos
> in
->current_max_len
)
1516 pos
= in
->current_max_len
;
1517 if (pos
!= in
->point
)
1518 free_completions (in
);
1520 update_input (in
, 1);
1524 input_callback (WInput
*in
, int Msg
, int Par
)
1526 Dlg_head
*h
= in
->widget
.parent
;
1533 if (Par
== XCTRL('q')){
1537 v
= handle_char (in
, mi_getch ());
1541 if (Par
== KEY_UP
|| Par
== KEY_DOWN
||
1542 Par
== ESC_CHAR
|| Par
== KEY_F(10) ||
1544 return 0; /* We don't handle up/down */
1550 return handle_char (in
, Par
);
1553 case WIDGET_UNFOCUS
:
1555 update_input (in
, 0);
1558 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1562 return default_proc (Msg
, Par
);
1566 input_event (Gpm_Event
* event
, WInput
* in
)
1568 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1569 dlg_select_widget (in
->widget
.parent
, in
);
1571 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1572 && should_show_history_button (in
)) {
1575 in
->point
= strlen (in
->buffer
);
1576 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1577 in
->point
= event
->x
- in
->first_shown
- 1;
1581 update_input (in
, 1);
1587 input_new (int y
, int x
, int color
, int len
, const char *def_text
, char *tkname
)
1589 WInput
*in
= g_new (WInput
, 1);
1590 int initial_buffer_len
;
1592 init_widget (&in
->widget
, y
, x
, 1, len
,
1593 (callback_fn
) input_callback
,
1594 (destroy_fn
) input_destroy
, (mouse_h
) input_event
, tkname
);
1598 in
->history_name
= 0;
1601 in
->history_name
= g_strdup (tkname
);
1602 in
->history
= history_get (tkname
);
1609 if (def_text
== INPUT_LAST_TEXT
) {
1612 if (in
->history
->text
)
1613 def_text
= in
->history
->text
;
1615 initial_buffer_len
= 1 + max (len
, strlen (def_text
));
1616 in
->widget
.options
|= W_IS_INPUT
;
1617 in
->completions
= NULL
;
1618 in
->completion_flags
=
1619 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
|
1620 INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
;
1621 in
->current_max_len
= initial_buffer_len
;
1622 in
->buffer
= g_malloc (initial_buffer_len
);
1624 in
->field_len
= len
;
1626 in
->first_shown
= 0;
1627 in
->disable_update
= 0;
1630 in
->is_password
= 0;
1632 strcpy (in
->buffer
, def_text
);
1633 in
->point
= strlen (in
->buffer
);
1638 /* Listbox widget */
1640 /* Should draw the scrollbar, but currently draws only
1641 * indications that there is more information
1643 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1646 listbox_drawscroll (WListbox
*l
)
1648 extern int slow_terminal
;
1651 int max_line
= l
->height
-1;
1653 /* Are we at the top? */
1654 widget_move (&l
->widget
, 0, l
->width
);
1655 if (l
->list
== l
->top
)
1660 /* Are we at the bottom? */
1661 widget_move (&l
->widget
, max_line
, l
->width
);
1662 top
= listbox_cdiff (l
->list
, l
->top
);
1663 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1668 /* Now draw the nice relative pointer */
1670 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1674 for (i
= 1; i
< max_line
; i
++){
1675 widget_move (&l
->widget
, i
, l
->width
);
1684 listbox_draw (WListbox
*l
, int focused
)
1689 Dlg_head
*h
= l
->widget
.parent
;
1690 int normalc
= NORMALC
;
1701 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1703 /* Display the entry */
1704 if (e
== l
->current
&& sel_line
== -1){
1710 widget_move (&l
->widget
, i
, 0);
1712 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1718 printw (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1720 l
->cursor_y
= sel_line
;
1724 listbox_drawscroll (l
);
1727 /* Returns the number of items between s and e,
1728 must be on the same linked list */
1730 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1734 for (count
= 0; s
!= e
; count
++)
1740 listbox_check_hotkey (WListbox
*l
, int key
)
1752 /* If we didn't find anything, return */
1753 if (i
&& e
== l
->list
)
1756 if (e
->hotkey
== key
)
1764 /* Used only for display updating, for avoiding line at a time scroll */
1766 listbox_select_last (WListbox
*l
, int set_top
)
1769 l
->current
= l
->list
->prev
;
1770 l
->pos
= l
->count
- 1;
1772 l
->top
= l
->list
->prev
;
1777 listbox_remove_list (WListbox
*l
)
1786 while (l
->count
--) {
1792 l
->pos
= l
->count
= 0;
1793 l
->list
= l
->top
= l
->current
= 0;
1797 * bor 30.10.96: added force flag to remove *last* entry as well
1798 * bor 30.10.96: corrected selection bug if last entry was removed
1802 listbox_remove_current (WListbox
*l
, int force
)
1806 /* Ok, note: this won't allow for emtpy lists */
1807 if (!force
&& (!l
->count
|| l
->count
== 1))
1814 l
->current
->next
->prev
= l
->current
->prev
;
1815 l
->current
->prev
->next
= l
->current
->next
;
1816 if (p
->next
== l
->list
) {
1817 l
->current
= p
->prev
;
1821 l
->current
= p
->next
;
1824 l
->list
= l
->top
= p
->next
;
1827 l
->list
= l
->top
= l
->current
= 0;
1834 /* Makes *e the selected entry (sets current and pos) */
1836 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1845 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1853 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1854 l
->top
= l
->top
->next
;
1856 l
->top
= l
->current
;
1862 /* If we are unable to find it, set decent values */
1863 l
->current
= l
->top
= l
->list
;
1867 /* Selects from base the pos element */
1869 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1871 WLEntry
*last
= l
->list
->prev
;
1884 listbox_back (WListbox
*l
)
1887 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1894 listbox_fwd (WListbox
*l
)
1896 if (l
->current
!= l
->list
->prev
){
1897 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
1903 /* Returns 1 if we want a redraw */
1905 listbox_key (WListbox
*l
, int key
)
1916 l
->current
= l
->top
= l
->list
;
1922 l
->current
= l
->top
= l
->list
->prev
;
1923 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1924 l
->top
= l
->top
->prev
;
1925 l
->pos
= l
->count
- 1;
1940 for (i
= 0; i
< l
->height
-1; i
++)
1941 j
|= listbox_fwd (l
);
1946 for (i
= 0; i
< l
->height
-1; i
++)
1947 j
|= listbox_back (l
);
1953 static int listbox_event (Gpm_Event
*event
, WListbox
*l
);
1955 listbox_callback (WListbox
*l
, int msg
, int par
)
1958 /* int selected_color; Never used */
1966 if ((e
= listbox_check_hotkey (l
, par
)) != NULL
){
1967 listbox_select_entry (l
, e
);
1969 /* Take the appropriate action */
1970 if (l
->action
== listbox_finish
){
1971 l
->widget
.parent
->running
= 0;
1972 l
->widget
.parent
->ret_value
= B_ENTER
;
1973 } else if (l
->action
== listbox_cback
){
1974 if ((*l
->cback
)(l
) == listbox_finish
){
1975 l
->widget
.parent
->running
= 0;
1976 l
->widget
.parent
->ret_value
= B_ENTER
;
1984 if ((ret_code
= listbox_key (l
, par
)))
1985 listbox_draw (l
, 1);
1989 widget_move (&l
->widget
, l
->cursor_y
, 0);
1993 case WIDGET_UNFOCUS
:
1995 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
1998 return default_proc (msg
, par
);
2002 listbox_event (Gpm_Event
*event
, WListbox
*l
)
2006 Dlg_head
*h
= l
->widget
.parent
;
2009 if (event
->type
& GPM_DOWN
)
2010 dlg_select_widget (l
->widget
.parent
, l
);
2013 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2014 if (event
->x
< 0 || event
->x
>= l
->width
)
2017 for (i
= -event
->y
; i
>= 0; i
--)
2019 else if (event
->y
> l
->height
)
2020 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2023 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
,
2026 /* We need to refresh ourselves since the dialog manager doesn't */
2027 /* know about this event */
2028 listbox_callback (l
, WIDGET_DRAW
, 0);
2034 if ((event
->type
& (GPM_DOUBLE
|GPM_UP
)) == (GPM_UP
|GPM_DOUBLE
)){
2035 if (event
->x
< 0 || event
->x
>= l
->width
)
2037 if (event
->y
< 1 || event
->y
> l
->height
)
2040 dlg_select_widget (l
->widget
.parent
, l
);
2041 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
, event
->y
- 1));
2044 case listbox_nothing
:
2047 case listbox_finish
:
2048 h
->ret_value
= B_ENTER
;
2053 if ((*l
->cback
)(l
) == listbox_finish
)
2061 listbox_destroy (WListbox
*l
)
2063 WLEntry
*n
, *p
= l
->list
;
2066 for (i
= 0; i
< l
->count
; i
++){
2075 listbox_new (int y
, int x
, int width
, int height
,
2076 int action
, lcback callback
, char *tkname
)
2078 WListbox
*l
= g_new (WListbox
, 1);
2079 extern int slow_terminal
;
2081 init_widget (&l
->widget
, y
, x
, height
, width
,
2082 (callback_fn
)listbox_callback
,
2083 (destroy_fn
) listbox_destroy
, (mouse_h
)listbox_event
, tkname
);
2085 l
->list
= l
->top
= l
->current
= 0;
2095 l
->cback
= callback
;
2097 l
->allow_duplicates
= 1;
2098 l
->scrollbar
= slow_terminal
? 0 : 1;
2099 widget_want_hotkey (l
->widget
, 1);
2104 /* Listbox item adding function. They still lack a lot of functionality */
2106 /* 1.11.96 bor: added pos argument to control placement of new entry */
2108 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2116 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2118 e
->prev
= l
->list
->prev
;
2119 l
->list
->prev
->next
= e
;
2121 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2122 e
->next
= l
->current
;
2123 e
->prev
= l
->current
->prev
;
2124 l
->current
->prev
->next
= e
;
2125 l
->current
->prev
= e
;
2126 if (l
->list
== l
->current
) { /* move list one position down */
2130 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2131 e
->prev
= l
->current
;
2132 e
->next
= l
->current
->next
;
2133 l
->current
->next
->prev
= e
;
2134 l
->current
->next
= e
;
2140 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
, char *text
,
2148 if (!l
->allow_duplicates
)
2149 if (listbox_search_text (l
, text
))
2152 entry
= g_new (WLEntry
, 1);
2153 entry
->text
= g_strdup (text
);
2155 entry
->hotkey
= hotkey
;
2157 listbox_append_item (l
, entry
, pos
);
2162 /* Selects the nth entry in the listbox */
2164 listbox_select_by_number (WListbox
*l
, int n
)
2166 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2170 listbox_search_text (WListbox
*l
, char *text
)
2179 if(!strcmp (e
->text
, text
))
2182 } while (e
!=l
->list
);
2187 /* Returns the current string text as well as the associated extra data */
2189 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2195 if (string
&& l
->current
)
2196 *string
= l
->current
->text
;
2197 if (extra
&& l
->current
)
2198 *extra
= l
->current
->data
;
2202 buttonbar_callback (WButtonBar
*bb
, int msg
, int par
)
2214 for (i
= 0; i
< 10; i
++){
2215 if (par
== KEY_F(i
+1) && bb
->labels
[i
].function
){
2216 (*bb
->labels
[i
].function
)(bb
->labels
[i
].data
);
2225 widget_move (&bb
->widget
, 0, 0);
2226 attrset (DEFAULT_COLOR
);
2227 printw ("%-*s", bb
->widget
.cols
, "");
2228 for (i
= 0; i
< COLS
/8 && i
< 10; i
++){
2229 widget_move (&bb
->widget
, 0, i
*8);
2230 attrset (DEFAULT_COLOR
);
2232 attrset (SELECTED_COLOR
);
2233 printw ("%-*s", ((i
+1) * 8 == COLS
? 5 : 6),
2234 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2235 attrset (DEFAULT_COLOR
);
2237 attrset (SELECTED_COLOR
);
2240 return default_proc (msg
, par
);
2244 buttonbar_destroy (WButtonBar
*bb
)
2248 for (i
= 0; i
< 10; i
++){
2249 if (bb
->labels
[i
].text
)
2250 g_free (bb
->labels
[i
].text
);
2255 buttonbar_event (Gpm_Event
*event
, WButtonBar
*bb
)
2259 if (!(event
->type
& GPM_UP
))
2263 button
= event
->x
/ 8;
2264 if (button
< 10 && bb
->labels
[button
].function
)
2265 (*bb
->labels
[button
].function
)(bb
->labels
[button
].data
);
2270 buttonbar_new (int visible
)
2273 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2275 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2276 (callback_fn
) buttonbar_callback
,
2277 (destroy_fn
) buttonbar_destroy
, (mouse_h
) buttonbar_event
, NULL
);
2279 bb
->visible
= visible
;
2280 for (i
= 0; i
< 10; i
++){
2281 bb
->labels
[i
].text
= 0;
2282 bb
->labels
[i
].function
= 0;
2284 widget_want_hotkey (bb
->widget
, 1);
2285 widget_want_cursor (bb
->widget
, 0);
2291 set_label_text (WButtonBar
* bb
, int index
, char *text
)
2293 if (bb
->labels
[index
- 1].text
)
2294 g_free (bb
->labels
[index
- 1].text
);
2296 bb
->labels
[index
- 1].text
= g_strdup (text
);
2299 /* Find ButtonBar widget in the dialog */
2301 find_buttonbar (Dlg_head
*h
)
2305 bb
= (WButtonBar
*) find_widget_type (h
, (callback_fn
)
2306 buttonbar_callback
);
2311 define_label_data (Dlg_head
*h
, int idx
, char *text
, buttonbarfn cback
,
2314 WButtonBar
*bb
= find_buttonbar (h
);
2319 set_label_text (bb
, idx
, text
);
2320 bb
->labels
[idx
- 1].function
= cback
;
2321 bb
->labels
[idx
- 1].data
= data
;
2325 define_label (Dlg_head
*h
, int idx
, char *text
, void (*cback
) (void))
2327 define_label_data (h
, idx
, text
, (buttonbarfn
) cback
, 0);
2330 /* Redraw labels of the buttonbar */
2332 redraw_labels (Dlg_head
*h
)
2334 WButtonBar
*bb
= find_buttonbar (h
);
2339 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);