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 (Dlg_head
*h
, WButton
*b
, int Msg
, int Par
)
62 if (b
->hotkey
== Par
|| toupper(b
->hotkey
) == Par
){
63 button_callback (h
, b
, WIDGET_KEY
, ' '); /* to make action */
69 if (Par
!= ' ' && Par
!= '\n')
73 stop
= (*b
->callback
)(b
->action
, b
->callback_data
);
74 if (!b
->callback
|| stop
){
75 h
->ret_value
= b
->action
;
96 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
102 if (Msg
==WIDGET_UNFOCUS
)
104 else if (Msg
==WIDGET_FOCUS
)
109 g_snprintf (buf
, sizeof(buf
), "[< %s >]", b
->text
);
113 g_snprintf (buf
, sizeof(buf
), "[ %s ]", b
->text
);
117 g_snprintf (buf
, sizeof(buf
), "[%s]", b
->text
);
127 attrset ((b
->selected
) ? FOCUSC
: NORMALC
);
128 widget_move (&b
->widget
, 0, 0);
133 attrset ((b
->selected
) ? HOT_FOCUSC
: HOT_NORMALC
);
134 widget_move (&b
->widget
, 0, b
->hotpos
+off
);
135 addch ((unsigned char)b
->text
[b
->hotpos
]);
137 if (Msg
== WIDGET_FOCUS
)
143 return default_proc (h
, Msg
, Par
);
147 button_event (Gpm_Event
*event
, WButton
*b
)
149 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
150 Dlg_head
*h
=b
->widget
.parent
;
151 dlg_select_widget (h
, b
);
152 if (event
->type
& GPM_UP
){
153 button_callback (h
, b
, WIDGET_KEY
, ' ');
154 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
162 button_destroy (WButton
*b
)
168 button_len (const char *text
, unsigned int flags
)
170 int ret
= strlen (text
);
189 * Assuming that button text is malloc'ed, we may safely change it
190 * (as opposed to statically allocated); from other hand, excluding &
191 * and shifting data past it to the left results to one unused byte.
192 * This does not harm though :)
195 button_scan_hotkey(WButton
* b
)
197 char* cp
= strchr (b
->text
, '&');
199 if (cp
!= NULL
&& cp
[1] != '\0'){
201 b
->hotkey
= tolower (*cp
);
202 b
->hotpos
= cp
- b
->text
;
207 button_new (int y
, int x
, int action
, int flags
, char *text
,
208 int (*callback
)(int, void *), void *callback_data
, char *tkname
)
210 WButton
*b
= g_new (WButton
, 1);
212 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
213 (callback_fn
) button_callback
,
214 (destroy_fn
) button_destroy
, (mouse_h
)button_event
, tkname
);
219 b
->text
= g_strdup (text
);
220 b
->callback
= callback
;
221 b
->callback_data
= callback_data
;
222 widget_want_hotkey (b
->widget
, 1);
226 button_scan_hotkey(b
);
231 button_set_text (WButton
*b
, char *text
)
234 b
->text
= g_strdup (text
);
235 b
->widget
.cols
= button_len (text
, b
->flags
);
236 button_scan_hotkey(b
);
237 dlg_redraw (b
->widget
.parent
);
241 /* Radio button widget */
242 static int radio_event (Gpm_Event
*event
, WRadio
*r
);
245 radio_callback (Dlg_head
*h
, WRadio
*r
, int Msg
, int Par
)
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 (h
, r
, WIDGET_KEY
, ' '); /* Take action */
277 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
278 radio_callback (h
, r
, WIDGET_FOCUS
, ' ');
291 if (r
->count
- 1 > r
->pos
) {
299 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
300 radio_callback (h
, 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 (h
, 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 (h
, r
, WIDGET_KEY
, ' ');
342 radio_callback (h
, 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 (Dlg_head
*h
, WCheck
*c
, int Msg
, int Par
)
390 if (c
->hotkey
==Par
||
391 (c
->hotkey
>='a' && c
->hotkey
<='z' && c
->hotkey
-32==Par
)){
392 check_callback (h
, c
, WIDGET_KEY
, ' '); /* make action */
401 c
->state
^= C_CHANGE
;
402 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
403 check_callback (h
, c
, WIDGET_FOCUS
, ' ');
407 widget_move (&c
->widget
, 0, 1);
413 attrset ((Msg
== WIDGET_FOCUS
) ? FOCUSC
: NORMALC
);
414 widget_move (&c
->widget
, 0, 0);
415 printw ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
418 attrset ((Msg
== WIDGET_FOCUS
) ? HOT_FOCUSC
: HOT_NORMALC
);
419 widget_move (&c
->widget
, 0, + c
->hotpos
+4);
420 addch ((unsigned char)c
->text
[c
->hotpos
]);
424 return default_proc (h
, Msg
, Par
);
428 check_event (Gpm_Event
*event
, WCheck
*c
)
430 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
431 Dlg_head
*h
= c
->widget
.parent
;
433 dlg_select_widget (h
, c
);
434 if (event
->type
& GPM_UP
){
435 check_callback (h
, c
, WIDGET_KEY
, ' ');
436 check_callback (h
, c
, WIDGET_FOCUS
, 0);
437 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
445 check_destroy (WCheck
*c
)
451 check_new (int y
, int x
, int state
, char *text
, char *tkname
)
453 WCheck
*c
= g_new (WCheck
, 1);
456 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
457 (callback_fn
)check_callback
,
458 (destroy_fn
)check_destroy
, (mouse_h
) check_event
, tkname
);
459 c
->state
= state
? C_BOOL
: 0;
460 c
->text
= g_strdup (text
);
463 widget_want_hotkey (c
->widget
, 1);
465 /* Scan for the hotkey */
466 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
473 c
->hotkey
= tolower (*s
);
474 c
->hotpos
= t
- c
->text
;
486 label_callback (Dlg_head
*h
, WLabel
*l
, int Msg
, int Par
)
488 if (Msg
== WIDGET_INIT
)
491 /* We don't want to get the focus */
492 if (Msg
== WIDGET_FOCUS
)
494 if (Msg
== WIDGET_DRAW
&& l
->text
){
495 char *p
= l
->text
, *q
, c
= 0;
498 attrset (DEFAULT_COLOR
);
504 q
= strchr (p
, '\n');
509 widget_move (&l
->widget
, y
, 0);
511 xlen
= l
->widget
.cols
- strlen (p
);
513 printw ("%*s", xlen
, " ");
522 return default_proc (h
, Msg
, Par
);
526 label_set_text (WLabel
*label
, char *text
)
528 int newcols
= label
->widget
.cols
;
530 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
531 return; /* Flickering is not nice */
534 g_free (label
->text
);
537 label
->text
= g_strdup (text
);
538 if (label
->auto_adjust_cols
) {
539 newcols
= strlen (text
);
540 if (newcols
> label
->widget
.cols
)
541 label
->widget
.cols
= newcols
;
546 if (label
->widget
.parent
)
547 label_callback (label
->widget
.parent
, label
, WIDGET_DRAW
, 0);
549 if (newcols
< label
->widget
.cols
)
550 label
->widget
.cols
= newcols
;
554 label_destroy (WLabel
*l
)
561 label_new (int y
, int x
, const char *text
, char *tkname
)
566 /* Multiline labels are immutable - no need to compute their sizes */
567 if (!text
|| strchr(text
, '\n'))
570 width
= strlen (text
);
572 l
= g_new (WLabel
, 1);
573 init_widget (&l
->widget
, y
, x
, 1, width
,
574 (callback_fn
) label_callback
,
575 (destroy_fn
) label_destroy
, NULL
, tkname
);
576 l
->text
= text
? g_strdup (text
) : 0;
577 l
->auto_adjust_cols
= 1;
579 widget_want_cursor (l
->widget
, 0);
584 /* Gauge widget (progress indicator) */
585 /* Currently width is hardcoded here for text mode */
589 gauge_callback (Dlg_head
*h
, WGauge
*g
, int Msg
, int Par
)
592 if (Msg
== WIDGET_INIT
)
595 /* We don't want to get the focus */
596 if (Msg
== WIDGET_FOCUS
)
599 if (Msg
== WIDGET_DRAW
){
600 widget_move (&g
->widget
, 0, 0);
603 printw ("%*s", gauge_len
, "");
605 long percentage
, columns
;
606 long total
= g
->max
, done
= g
->current
;
608 if (total
<= 0 || done
< 0) {
614 while (total
> 65535) {
618 percentage
= (200 * done
/ total
+ 1) / 2;
619 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
621 attrset (GAUGE_COLOR
);
622 printw ("%*s", columns
, "");
624 printw ("%*s] %3d%%", gauge_len
- 7 - columns
, "", percentage
);
628 return default_proc (h
, Msg
, Par
);
632 gauge_set_value (WGauge
*g
, int max
, int current
)
634 if (g
->current
== current
&& g
->max
== max
)
635 return; /* Do not flicker */
637 max
= 1; /* I do not like division by zero :) */
639 g
->current
= current
;
641 gauge_callback (g
->widget
.parent
, g
, WIDGET_DRAW
, 0);
645 gauge_show (WGauge
*g
, int shown
)
647 if (g
->shown
== shown
)
650 gauge_callback (g
->widget
.parent
, g
, WIDGET_DRAW
, 0);
654 gauge_destroy (WGauge
*g
)
660 gauge_new (int y
, int x
, int shown
, int max
, int current
, char *tkname
)
662 WGauge
*g
= g_new (WGauge
, 1);
664 init_widget (&g
->widget
, y
, x
, 1, gauge_len
,
665 (callback_fn
) gauge_callback
,
666 (destroy_fn
) gauge_destroy
, NULL
, tkname
);
669 max
= 1; /* I do not like division by zero :) */
671 g
->current
= current
;
673 widget_want_cursor (g
->widget
, 0);
680 /* {{{ history button */
682 #define LARGE_HISTORY_BUTTON 1
684 #ifdef LARGE_HISTORY_BUTTON
685 # define HISTORY_BUTTON_WIDTH 3
687 # define HISTORY_BUTTON_WIDTH 1
690 #define should_show_history_button(in) \
691 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
693 static void draw_history_button (WInput
* in
)
696 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
697 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
698 #ifdef LARGE_HISTORY_BUTTON
701 h
= in
->widget
.parent
;
703 attrset (NORMALC
); /* button has the same colour as other buttons */
705 attrset (HOT_NORMALC
);
707 attrset (NORMAL_COLOR
);
709 /* Too distracting: attrset (MARKED_COLOR); */
711 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
715 attrset (MARKED_COLOR
);
720 /* }}} history button */
723 /* Input widgets now have a global kill ring */
724 /* Pointer to killed data */
725 static char *kill_buffer
= 0;
728 update_input (WInput
*in
, int clear_first
)
733 int buf_len
= strlen (in
->buffer
);
735 if (should_show_history_button (in
))
736 has_history
= HISTORY_BUTTON_WIDTH
;
738 if (in
->disable_update
)
741 /* Make the point visible */
742 if ((in
->point
< in
->first_shown
) ||
743 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
744 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
745 if (in
->first_shown
< 0)
749 /* Adjust the mark */
750 if (in
->mark
> buf_len
)
754 draw_history_button (in
);
758 widget_move (&in
->widget
, 0, 0);
759 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
761 widget_move (&in
->widget
, 0, 0);
763 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
764 c
= in
->buffer
[j
++];
765 c
= is_printable (c
) ? c
: '.';
770 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
777 winput_set_origin (WInput
*in
, int x
, int field_len
)
780 in
->field_len
= in
->widget
.cols
= field_len
;
781 update_input (in
, 0);
784 /* {{{ history saving and loading */
787 This loads and saves the history of an input line to and from the
788 widget. It is called with the widgets tk name on creation of the
789 widget, and returns the Hist list. It stores histories in the file
790 ~/.mc/history in using the profile code.
792 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
793 function) then input_new assigns the default text to be the last text
794 entered, or "" if not found.
797 int num_history_items_recorded
= 60;
800 history_get (char *input_name
)
808 if (!num_history_items_recorded
) /* this is how to disable */
814 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
816 char key_name
[BUF_TINY
];
817 char this_entry
[BUF_LARGE
];
818 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
819 GetPrivateProfileString (input_name
, key_name
, "", this_entry
, sizeof (this_entry
), profile
);
822 new = g_new0 (Hist
, 1);
823 new->text
= g_strdup (this_entry
);
824 new->prev
= old
; /* set up list pointers */
830 return new; /* return pointer to last entry in list */
834 history_put (char *input_name
, Hist
*h
)
848 if (!num_history_items_recorded
) /* this is how to disable */
851 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
853 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
855 /* Just in case I forgot to strip passwords somewhere -- Norbert */
856 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
){
861 while (h
->next
) /* go to end of list */
864 /* go back 60 places */
865 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
869 profile_clean_section (input_name
, profile
);
871 /* dump histories into profile */
872 for (i
= 0; h
; h
= h
->next
){
875 /* probably aren't any null entries, but lets be sure */
877 char key_name
[BUF_TINY
];
878 g_snprintf (key_name
, sizeof(key_name
), "%d", i
++);
879 WritePrivateProfileString (input_name
, key_name
, h
->text
, profile
);
886 /* }}} history saving and loading */
889 /* {{{ history display */
894 static char *history_title
= NULL
;
896 if (history_title
== NULL
)
897 history_title
= _(" History ");
898 return history_title
;
901 static inline int listbox_fwd (WListbox
*l
);
904 show_hist (Hist
* history
, int widget_x
, int widget_y
)
907 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
911 WListbox
*query_list
;
917 while (z
->prev
) /* goto first */
921 if ((i
= strlen (hi
->text
)) > maxlen
)
929 if (h
<= y
|| y
> LINES
- 6) {
934 h
= min (h
, LINES
- y
);
941 if ((w
= maxlen
+ 4) + x
> COLS
) {
947 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
948 i18n_htitle (), DLG_COMPACT
);
949 query_list
= listbox_new (1, 1, w
- 2, h
- 2, listbox_finish
, 0, NULL
);
950 add_widget (query_dlg
, query_list
);
953 while (hi
) { /* traverse */
954 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
957 while (listbox_fwd (query_list
));
961 while (hi
) { /* traverse backwards */
962 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
968 if (query_dlg
->ret_value
!= B_CANCEL
) {
969 listbox_get_current (query_list
, &q
, NULL
);
973 destroy_dlg (query_dlg
);
977 static void do_show_hist (WInput
* in
)
980 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
987 /* }}} history display */
990 input_destroy (WInput
*in
)
993 fprintf (stderr
, "Internal error: null Input *\n");
1001 if (!in
->is_password
) /* don't save passwords ;-) */
1002 history_put (in
->history_name
, in
->history
);
1004 current
= in
->history
;
1005 while (current
->next
)
1006 current
= current
->next
;
1009 current
= current
->prev
;
1014 g_free (in
->buffer
);
1015 free_completions (in
);
1016 if (in
->history_name
)
1017 g_free (in
->history_name
);
1020 static char disable_update
= 0;
1023 input_disable_update (WInput
*in
)
1025 in
->disable_update
++;
1029 input_enable_update (WInput
*in
)
1031 in
->disable_update
--;
1032 update_input (in
, 0);
1035 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1038 push_history (WInput
*in
, char *text
)
1041 /* input widget where urls with passwords are entered without any
1043 static const char *password_input_fields
[] = {
1044 N_(" Link to a remote machine "),
1045 N_(" FTP to machine "),
1046 N_(" SMB link to machine ")
1054 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1055 password_input_fields
[i
] = _(password_input_fields
[i
]);
1058 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1062 while (in
->history
->next
)
1063 in
->history
= in
->history
->next
;
1064 if (!strcmp (in
->history
->text
, text
))
1066 new = g_new (Hist
, 1);
1067 in
->history
->next
= new;
1069 new = g_new (Hist
, 1);
1072 new->prev
= in
->history
;
1073 new->text
= g_strdup (text
);
1074 if (in
->history_name
) {
1075 p
= in
->history_name
+ 3;
1076 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1077 if (strcmp (p
, password_input_fields
[i
]) == 0)
1079 if (i
< ELEMENTS(password_input_fields
))
1080 strip_password (new->text
, 0);
1082 strip_password (new->text
, 1);
1091 /* Cleans the input line and adds the current text to the history */
1093 new_input (WInput
*in
)
1096 push_history (in
, in
->buffer
);
1101 free_completions (in
);
1102 update_input (in
, 0);
1106 insert_char (WInput
*in
, int c_code
)
1114 if (strlen (in
->buffer
)+1 == in
->current_max_len
){
1115 /* Expand the buffer */
1116 char *narea
= g_malloc (in
->current_max_len
+ in
->field_len
);
1118 char *p
= in
->buffer
;
1120 strcpy (narea
, in
->buffer
);
1122 in
->current_max_len
+= in
->field_len
;
1126 if (strlen (in
->buffer
)+1 < in
->current_max_len
){
1127 int l
= strlen (&in
->buffer
[in
->point
]);
1128 for (i
= l
+1; i
> 0; i
--)
1129 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1130 in
->buffer
[in
->point
] = c_code
;
1137 beginning_of_line (WInput
*in
)
1143 end_of_line (WInput
*in
)
1145 in
->point
= strlen (in
->buffer
);
1149 backward_char (WInput
*in
)
1156 forward_char (WInput
*in
)
1158 if (in
->buffer
[in
->point
])
1163 forward_word (WInput
*in
)
1165 unsigned char *p
= in
->buffer
+in
->point
;
1167 while (*p
&& (isspace (*p
) || ispunct (*p
)))
1169 while (*p
&& isalnum (*p
))
1171 in
->point
= p
- in
->buffer
;
1175 backward_word (WInput
*in
)
1177 unsigned char *p
= in
->buffer
+in
->point
;
1179 while (p
-1 > in
->buffer
-1 && (isspace (*(p
-1)) || ispunct (*(p
-1))))
1181 while (p
-1 > in
->buffer
-1 && isalnum (*(p
-1)))
1183 in
->point
= p
- in
->buffer
;
1187 key_left (WInput
*in
)
1189 if (ctrl_pressed ())
1196 key_right (WInput
*in
)
1198 if (ctrl_pressed ())
1205 backward_delete (WInput
*in
)
1211 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1212 in
->buffer
[i
-1] = in
->buffer
[i
];
1218 delete_char (WInput
*in
)
1222 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1223 in
->buffer
[i
] = in
->buffer
[i
+1];
1228 copy_region (WInput
*in
, int x_first
, int x_last
)
1230 int first
= min (x_first
, x_last
);
1231 int last
= max (x_first
, x_last
);
1237 g_free (kill_buffer
);
1239 kill_buffer
= g_malloc (last
-first
+ 1);
1240 strncpy (kill_buffer
, in
->buffer
+first
, last
-first
);
1241 kill_buffer
[last
-first
] = 0;
1245 delete_region (WInput
*in
, int x_first
, int x_last
)
1247 int first
= min (x_first
, x_last
);
1248 int last
= max (x_first
, x_last
);
1252 strcpy (&in
->buffer
[first
], &in
->buffer
[last
]);
1257 kill_word (WInput
*in
)
1259 int old_point
= in
->point
;
1263 new_point
= in
->point
;
1264 in
->point
= old_point
;
1266 copy_region (in
, old_point
, new_point
);
1267 delete_region (in
, old_point
, new_point
);
1272 back_kill_word (WInput
*in
)
1274 int old_point
= in
->point
;
1278 new_point
= in
->point
;
1279 in
->point
= old_point
;
1281 copy_region (in
, old_point
, new_point
);
1282 delete_region (in
, old_point
, new_point
);
1287 set_mark (WInput
*in
)
1289 in
->mark
= in
->point
;
1293 kill_save (WInput
*in
)
1295 copy_region (in
, in
->mark
, in
->point
);
1299 kill_region (WInput
*in
)
1302 delete_region (in
, in
->point
, in
->mark
);
1312 for (p
= kill_buffer
; *p
; p
++)
1313 insert_char (in
, *p
);
1317 kill_line (WInput
*in
)
1320 g_free (kill_buffer
);
1321 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1322 in
->buffer
[in
->point
] = 0;
1326 assign_text (WInput
*in
, char *text
)
1328 free_completions (in
);
1329 g_free (in
->buffer
);
1330 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1331 in
->current_max_len
= strlen (in
->buffer
) + 1;
1332 in
->point
= strlen (in
->buffer
);
1338 hist_prev (WInput
*in
)
1343 if (in
->need_push
) {
1344 switch (push_history (in
, in
->buffer
)) {
1345 case 2: in
->history
= in
->history
->prev
; break;
1346 case 1: if (in
->history
->prev
) in
->history
= in
->history
->prev
; break;
1349 } else if (in
->history
->prev
)
1350 in
->history
= in
->history
->prev
;
1353 assign_text (in
, in
->history
->text
);
1358 hist_next (WInput
*in
)
1360 if (in
->need_push
) {
1361 switch (push_history (in
, in
->buffer
)) {
1363 assign_text (in
, "");
1373 if (!in
->history
->next
) {
1374 assign_text (in
, "");
1378 in
->history
= in
->history
->next
;
1379 assign_text (in
, in
->history
->text
);
1383 static const struct {
1385 void (*fn
)(WInput
*in
);
1388 { XCTRL('a'), beginning_of_line
},
1389 { KEY_HOME
, beginning_of_line
},
1390 { KEY_A1
, beginning_of_line
},
1391 { XCTRL('e'), end_of_line
},
1392 { KEY_END
, end_of_line
},
1393 { KEY_C1
, end_of_line
},
1394 { KEY_LEFT
, key_left
},
1395 { XCTRL('b'), backward_char
},
1396 { ALT('b'), backward_word
},
1397 { KEY_RIGHT
, key_right
},
1398 { XCTRL('f'), forward_char
},
1399 { ALT('f'), forward_word
},
1402 { 0177, backward_delete
},
1403 { KEY_BACKSPACE
, backward_delete
},
1404 { XCTRL('h'), backward_delete
},
1405 { KEY_DC
, delete_char
},
1406 { XCTRL('d'), delete_char
},
1407 { ALT('d'), kill_word
},
1408 { ALT(KEY_BACKSPACE
), back_kill_word
},
1409 { ALT(XCTRL('h')), back_kill_word
},
1410 { ALT(127), back_kill_word
},
1412 /* Region manipulation */
1414 { XCTRL('w'), kill_region
},
1415 { ALT('w'), kill_save
},
1416 { XCTRL('y'), yank
},
1417 { XCTRL('k'), kill_line
},
1420 { ALT('p'), hist_prev
},
1421 { ALT('n'), hist_next
},
1422 { ALT('h'), do_show_hist
},
1425 { ALT('\t'), complete
},
1430 /* This function is a test for a special input key used in complete.c */
1431 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1432 and 2 if it is a complete key */
1434 is_in_input_map (WInput
*in
, int c_code
)
1438 for (i
= 0; input_map
[i
].fn
; i
++)
1439 if (c_code
== input_map
[i
].key_code
) {
1440 if (input_map
[i
].fn
== complete
)
1449 port_region_marked_for_delete (WInput
*in
)
1457 handle_char (WInput
*in
, int c_code
)
1465 free_completions (in
);
1466 v
= insert_char (in
, c_code
);
1467 update_input (in
, 1);
1472 for (i
= 0; input_map
[i
].fn
; i
++){
1473 if (c_code
== input_map
[i
].key_code
){
1474 if (input_map
[i
].fn
!= complete
)
1475 free_completions (in
);
1476 (*input_map
[i
].fn
)(in
);
1481 if (!input_map
[i
].fn
){
1482 if (c_code
> 255 || !is_printable (c_code
))
1485 port_region_marked_for_delete (in
);
1487 free_completions (in
);
1488 v
= insert_char (in
, c_code
);
1489 in
->inserted_one
= c_code
;
1491 if (!disable_update
)
1492 update_input (in
, 1);
1496 /* Inserts text in input line */
1498 stuff (WInput
*in
, char *text
, int insert_extra_space
)
1500 input_disable_update (in
);
1502 handle_char (in
, *text
++);
1503 if (insert_extra_space
)
1504 handle_char (in
, ' ');
1505 input_enable_update (in
);
1506 update_input (in
, 1);
1510 input_set_point (WInput
*in
, int pos
)
1512 if (pos
> in
->current_max_len
)
1513 pos
= in
->current_max_len
;
1514 if (pos
!= in
->point
)
1515 free_completions (in
);
1517 update_input (in
, 1);
1521 input_callback (Dlg_head
*h
, WInput
*in
, int Msg
, int Par
)
1528 if (Par
== XCTRL('q')){
1532 v
= handle_char (in
, mi_getch ());
1536 if (Par
== KEY_UP
|| Par
== KEY_DOWN
||
1537 Par
== ESC_CHAR
|| Par
== KEY_F(10) ||
1539 return 0; /* We don't handle up/down */
1545 return handle_char (in
, Par
);
1548 case WIDGET_UNFOCUS
:
1550 update_input (in
, 0);
1553 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1557 return default_proc (h
, Msg
, Par
);
1561 input_event (Gpm_Event
* event
, WInput
* in
)
1563 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1564 dlg_select_widget (in
->widget
.parent
, in
);
1566 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1567 && should_show_history_button (in
)) {
1570 in
->point
= strlen (in
->buffer
);
1571 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1572 in
->point
= event
->x
- in
->first_shown
- 1;
1576 update_input (in
, 1);
1582 input_new (int y
, int x
, int color
, int len
, const char *def_text
, char *tkname
)
1584 WInput
*in
= g_new (WInput
, 1);
1585 int initial_buffer_len
;
1587 init_widget (&in
->widget
, y
, x
, 1, len
,
1588 (callback_fn
) input_callback
,
1589 (destroy_fn
) input_destroy
, (mouse_h
) input_event
, tkname
);
1593 in
->history_name
= 0;
1596 in
->history_name
= g_strdup (tkname
);
1597 in
->history
= history_get (tkname
);
1604 if (def_text
== INPUT_LAST_TEXT
) {
1607 if (in
->history
->text
)
1608 def_text
= in
->history
->text
;
1610 initial_buffer_len
= 1 + max (len
, strlen (def_text
));
1611 in
->widget
.options
|= W_IS_INPUT
;
1612 in
->completions
= NULL
;
1613 in
->completion_flags
=
1614 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
|
1615 INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
;
1616 in
->current_max_len
= initial_buffer_len
;
1617 in
->buffer
= g_malloc (initial_buffer_len
);
1619 in
->field_len
= len
;
1621 in
->first_shown
= 0;
1622 in
->disable_update
= 0;
1625 in
->is_password
= 0;
1627 strcpy (in
->buffer
, def_text
);
1628 in
->point
= strlen (in
->buffer
);
1633 /* Listbox widget */
1635 /* Should draw the scrollbar, but currently draws only
1636 * indications that there is more information
1638 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1641 listbox_drawscroll (WListbox
*l
)
1643 extern int slow_terminal
;
1646 int max_line
= l
->height
-1;
1648 /* Are we at the top? */
1649 widget_move (&l
->widget
, 0, l
->width
);
1650 if (l
->list
== l
->top
)
1655 /* Are we at the bottom? */
1656 widget_move (&l
->widget
, max_line
, l
->width
);
1657 top
= listbox_cdiff (l
->list
, l
->top
);
1658 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1663 /* Now draw the nice relative pointer */
1665 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1669 for (i
= 1; i
< max_line
; i
++){
1670 widget_move (&l
->widget
, i
, l
->width
);
1679 listbox_draw (WListbox
*l
, Dlg_head
*h
, int focused
)
1684 int normalc
= NORMALC
;
1695 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1697 /* Display the entry */
1698 if (e
== l
->current
&& sel_line
== -1){
1704 widget_move (&l
->widget
, i
, 0);
1706 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1712 printw (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1714 l
->cursor_y
= sel_line
;
1718 listbox_drawscroll (l
);
1721 /* Returns the number of items between s and e,
1722 must be on the same linked list */
1724 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1728 for (count
= 0; s
!= e
; count
++)
1734 listbox_check_hotkey (WListbox
*l
, int key
)
1746 /* If we didn't find anything, return */
1747 if (i
&& e
== l
->list
)
1750 if (e
->hotkey
== key
)
1758 /* Used only for display updating, for avoiding line at a time scroll */
1760 listbox_select_last (WListbox
*l
, int set_top
)
1763 l
->current
= l
->list
->prev
;
1764 l
->pos
= l
->count
- 1;
1766 l
->top
= l
->list
->prev
;
1771 listbox_remove_list (WListbox
*l
)
1780 while (l
->count
--) {
1786 l
->pos
= l
->count
= 0;
1787 l
->list
= l
->top
= l
->current
= 0;
1791 * bor 30.10.96: added force flag to remove *last* entry as well
1792 * bor 30.10.96: corrected selection bug if last entry was removed
1796 listbox_remove_current (WListbox
*l
, int force
)
1800 /* Ok, note: this won't allow for emtpy lists */
1801 if (!force
&& (!l
->count
|| l
->count
== 1))
1808 l
->current
->next
->prev
= l
->current
->prev
;
1809 l
->current
->prev
->next
= l
->current
->next
;
1810 if (p
->next
== l
->list
) {
1811 l
->current
= p
->prev
;
1815 l
->current
= p
->next
;
1818 l
->list
= l
->top
= p
->next
;
1821 l
->list
= l
->top
= l
->current
= 0;
1828 /* Makes *e the selected entry (sets current and pos) */
1830 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1839 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1847 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1848 l
->top
= l
->top
->next
;
1850 l
->top
= l
->current
;
1856 /* If we are unable to find it, set decent values */
1857 l
->current
= l
->top
= l
->list
;
1861 /* Selects from base the pos element */
1863 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1865 WLEntry
*last
= l
->list
->prev
;
1878 listbox_back (WListbox
*l
)
1881 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1888 listbox_fwd (WListbox
*l
)
1890 if (l
->current
!= l
->list
->prev
){
1891 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
1897 /* Returns 1 if we want a redraw */
1899 listbox_key (WListbox
*l
, int key
)
1910 l
->current
= l
->top
= l
->list
;
1916 l
->current
= l
->top
= l
->list
->prev
;
1917 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1918 l
->top
= l
->top
->prev
;
1919 l
->pos
= l
->count
- 1;
1934 for (i
= 0; i
< l
->height
-1; i
++)
1935 j
|= listbox_fwd (l
);
1940 for (i
= 0; i
< l
->height
-1; i
++)
1941 j
|= listbox_back (l
);
1947 static int listbox_event (Gpm_Event
*event
, WListbox
*l
);
1949 listbox_callback (Dlg_head
*h
, WListbox
*l
, int msg
, int par
)
1952 /* int selected_color; Never used */
1960 if ((e
= listbox_check_hotkey (l
, par
)) != NULL
){
1961 listbox_select_entry (l
, e
);
1963 /* Take the appropriate action */
1964 if (l
->action
== listbox_finish
){
1965 l
->widget
.parent
->running
= 0;
1966 l
->widget
.parent
->ret_value
= B_ENTER
;
1967 } else if (l
->action
== listbox_cback
){
1968 if ((*l
->cback
)(l
) == listbox_finish
){
1969 l
->widget
.parent
->running
= 0;
1970 l
->widget
.parent
->ret_value
= B_ENTER
;
1978 if ((ret_code
= listbox_key (l
, par
)))
1979 listbox_draw (l
, h
, 1);
1983 widget_move (&l
->widget
, l
->cursor_y
, 0);
1987 case WIDGET_UNFOCUS
:
1989 listbox_draw (l
, h
, msg
!= WIDGET_UNFOCUS
);
1992 return default_proc (h
, msg
, par
);
1996 listbox_event (Gpm_Event
*event
, WListbox
*l
)
2000 Dlg_head
*h
= l
->widget
.parent
;
2003 if (event
->type
& GPM_DOWN
)
2004 dlg_select_widget (l
->widget
.parent
, l
);
2007 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2008 if (event
->x
< 0 || event
->x
>= l
->width
)
2011 for (i
= -event
->y
; i
>= 0; i
--)
2013 else if (event
->y
> l
->height
)
2014 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2017 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
,
2020 /* We need to refresh ourselves since the dialog manager doesn't */
2021 /* know about this event */
2022 listbox_callback (h
, l
, WIDGET_DRAW
, 0);
2028 if ((event
->type
& (GPM_DOUBLE
|GPM_UP
)) == (GPM_UP
|GPM_DOUBLE
)){
2029 if (event
->x
< 0 || event
->x
>= l
->width
)
2031 if (event
->y
< 1 || event
->y
> l
->height
)
2034 dlg_select_widget (l
->widget
.parent
, l
);
2035 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
, event
->y
- 1));
2038 case listbox_nothing
:
2041 case listbox_finish
:
2042 h
->ret_value
= B_ENTER
;
2047 if ((*l
->cback
)(l
) == listbox_finish
)
2055 listbox_destroy (WListbox
*l
)
2057 WLEntry
*n
, *p
= l
->list
;
2060 for (i
= 0; i
< l
->count
; i
++){
2069 listbox_new (int y
, int x
, int width
, int height
,
2070 int action
, lcback callback
, char *tkname
)
2072 WListbox
*l
= g_new (WListbox
, 1);
2073 extern int slow_terminal
;
2075 init_widget (&l
->widget
, y
, x
, height
, width
,
2076 (callback_fn
)listbox_callback
,
2077 (destroy_fn
) listbox_destroy
, (mouse_h
)listbox_event
, tkname
);
2079 l
->list
= l
->top
= l
->current
= 0;
2089 l
->cback
= callback
;
2091 l
->allow_duplicates
= 1;
2092 l
->scrollbar
= slow_terminal
? 0 : 1;
2093 widget_want_hotkey (l
->widget
, 1);
2098 /* Listbox item adding function. They still lack a lot of functionality */
2100 /* 1.11.96 bor: added pos argument to control placement of new entry */
2102 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2110 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2112 e
->prev
= l
->list
->prev
;
2113 l
->list
->prev
->next
= e
;
2115 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2116 e
->next
= l
->current
;
2117 e
->prev
= l
->current
->prev
;
2118 l
->current
->prev
->next
= e
;
2119 l
->current
->prev
= e
;
2120 if (l
->list
== l
->current
) { /* move list one position down */
2124 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2125 e
->prev
= l
->current
;
2126 e
->next
= l
->current
->next
;
2127 l
->current
->next
->prev
= e
;
2128 l
->current
->next
= e
;
2134 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
, char *text
,
2142 if (!l
->allow_duplicates
)
2143 if (listbox_search_text (l
, text
))
2146 entry
= g_new (WLEntry
, 1);
2147 entry
->text
= g_strdup (text
);
2149 entry
->hotkey
= hotkey
;
2151 listbox_append_item (l
, entry
, pos
);
2156 /* Selects the nth entry in the listbox */
2158 listbox_select_by_number (WListbox
*l
, int n
)
2160 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2164 listbox_search_text (WListbox
*l
, char *text
)
2173 if(!strcmp (e
->text
, text
))
2176 } while (e
!=l
->list
);
2181 /* Returns the current string text as well as the associated extra data */
2183 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2189 if (string
&& l
->current
)
2190 *string
= l
->current
->text
;
2191 if (extra
&& l
->current
)
2192 *extra
= l
->current
->data
;
2196 buttonbar_callback (Dlg_head
*h
, WButtonBar
*bb
, int msg
, int par
)
2208 for (i
= 0; i
< 10; i
++){
2209 if (par
== KEY_F(i
+1) && bb
->labels
[i
].function
){
2210 (*bb
->labels
[i
].function
)(bb
->labels
[i
].data
);
2219 widget_move (&bb
->widget
, 0, 0);
2220 attrset (DEFAULT_COLOR
);
2221 printw ("%-*s", bb
->widget
.cols
, "");
2222 for (i
= 0; i
< COLS
/8 && i
< 10; i
++){
2223 widget_move (&bb
->widget
, 0, i
*8);
2224 attrset (DEFAULT_COLOR
);
2226 attrset (SELECTED_COLOR
);
2227 printw ("%-*s", ((i
+1) * 8 == COLS
? 5 : 6),
2228 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2229 attrset (DEFAULT_COLOR
);
2231 attrset (SELECTED_COLOR
);
2234 return default_proc (h
, msg
, par
);
2238 buttonbar_destroy (WButtonBar
*bb
)
2242 for (i
= 0; i
< 10; i
++){
2243 if (bb
->labels
[i
].text
)
2244 g_free (bb
->labels
[i
].text
);
2249 buttonbar_event (Gpm_Event
*event
, WButtonBar
*bb
)
2253 if (!(event
->type
& GPM_UP
))
2257 button
= event
->x
/ 8;
2258 if (button
< 10 && bb
->labels
[button
].function
)
2259 (*bb
->labels
[button
].function
)(bb
->labels
[button
].data
);
2264 buttonbar_new (int visible
)
2267 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2269 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2270 (callback_fn
) buttonbar_callback
,
2271 (destroy_fn
) buttonbar_destroy
, (mouse_h
) buttonbar_event
, NULL
);
2273 bb
->visible
= visible
;
2274 for (i
= 0; i
< 10; i
++){
2275 bb
->labels
[i
].text
= 0;
2276 bb
->labels
[i
].function
= 0;
2278 widget_want_hotkey (bb
->widget
, 1);
2279 widget_want_cursor (bb
->widget
, 0);
2285 set_label_text (WButtonBar
* bb
, int index
, char *text
)
2287 if (bb
->labels
[index
- 1].text
)
2288 g_free (bb
->labels
[index
- 1].text
);
2290 bb
->labels
[index
- 1].text
= g_strdup (text
);
2293 /* paneletc is either the panel widget, or info or view or tree widget */
2295 find_buttonbar (Dlg_head
* h
, Widget
* paneletc
)
2302 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
) {
2303 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
) {
2304 bb
= (WButtonBar
*) item
->widget
;
2312 define_label_data (Dlg_head
* h
, Widget
* paneletc
, int idx
, char *text
,
2313 buttonbarfn cback
, void *data
)
2315 WButtonBar
*bb
= find_buttonbar (h
, paneletc
);
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
, Widget
* paneletc
, int idx
, char *text
,
2326 void (*cback
) (void))
2328 define_label_data (h
, paneletc
, idx
, text
, (buttonbarfn
) cback
, 0);
2332 redraw_labels (Dlg_head
*h
, Widget
*paneletc
)
2337 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
){
2338 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
){
2339 widget_redraw (h
, item
);