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>
43 #include "key.h" /* XCTRL and ALT macros */
44 #include "profile.h" /* for history loading and saving */
45 #include "wtools.h" /* For common_dialog_repaint() */
47 static int button_event (Gpm_Event
*event
, WButton
*b
);
52 button_callback (Dlg_head
*h
, WButton
*b
, int Msg
, int Par
)
63 if (b
->hotkey
== Par
|| toupper(b
->hotkey
) == Par
){
64 button_callback (h
, 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 (h
, 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 (h
, 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 * Assuming that button text is malloc'ed, we may safely change it
191 * (as opposed to statically allocated); from other hand, excluding &
192 * and shifting data past it to the left results to one unused byte.
193 * This does not harm though :)
196 button_scan_hotkey(WButton
* b
)
198 char* cp
= strchr (b
->text
, '&');
200 if (cp
!= NULL
&& cp
[1] != '\0'){
202 b
->hotkey
= tolower (*cp
);
203 b
->hotpos
= cp
- b
->text
;
208 button_new (int y
, int x
, int action
, int flags
, char *text
,
209 int (*callback
)(int, void *), void *callback_data
, char *tkname
)
211 WButton
*b
= g_new (WButton
, 1);
213 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
214 (callback_fn
) button_callback
,
215 (destroy_fn
) button_destroy
, (mouse_h
)button_event
, tkname
);
220 b
->text
= g_strdup (text
);
221 b
->callback
= callback
;
222 b
->callback_data
= callback_data
;
223 widget_want_hotkey (b
->widget
, 1);
227 button_scan_hotkey(b
);
232 button_set_text (WButton
*b
, char *text
)
235 b
->text
= g_strdup (text
);
236 b
->widget
.cols
= button_len (text
, b
->flags
);
237 button_scan_hotkey(b
);
238 dlg_redraw (b
->widget
.parent
);
242 /* Radio button widget */
243 static int radio_event (Gpm_Event
*event
, WRadio
*r
);
246 radio_callback (Dlg_head
*h
, WRadio
*r
, int Msg
, int Par
)
256 int i
, lp
= tolower(Par
);
259 for (i
= 0; i
< r
->count
; i
++){
260 cp
= strchr (r
->texts
[i
], '&');
261 if (cp
!= NULL
&& cp
[1] != '\0'){
262 int c
= tolower (cp
[1]);
267 radio_callback (h
, r
, WIDGET_KEY
, ' '); /* Take action */
278 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
279 radio_callback (h
, r
, WIDGET_FOCUS
, ' ');
292 if (r
->count
- 1 > r
->pos
) {
300 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
301 radio_callback (h
, r
, WIDGET_FOCUS
, ' ');
302 widget_move (&r
->widget
, r
->pos
, 1);
308 for (i
= 0; i
< r
->count
; i
++){
309 register unsigned char* cp
;
310 attrset ((i
==r
->pos
&& Msg
==WIDGET_FOCUS
) ? FOCUSC
:NORMALC
);
311 widget_move (&r
->widget
, i
, 0);
313 printw("(%c) ", (r
->sel
== i
) ? '*' : ' ');
314 for (cp
= r
->texts
[i
]; *cp
; cp
++)
318 attrset ((i
==r
->pos
&& Msg
==WIDGET_FOCUS
)
319 ? HOT_FOCUSC
: HOT_NORMALC
);
321 attrset ((i
==r
->pos
&& Msg
==WIDGET_FOCUS
) ? FOCUSC
: NORMALC
);
330 return default_proc (h
, Msg
, Par
);
334 radio_event (Gpm_Event
*event
, WRadio
*r
)
336 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
337 Dlg_head
*h
= r
->widget
.parent
;
339 r
->pos
= event
->y
- 1;
340 dlg_select_widget (h
, r
);
341 if (event
->type
& GPM_UP
){
342 radio_callback (h
, r
, WIDGET_KEY
, ' ');
343 radio_callback (h
, r
, WIDGET_FOCUS
, 0);
344 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
352 radio_new (int y
, int x
, int count
, char **texts
, int use_hotkey
, char *tkname
)
354 WRadio
*r
= g_new (WRadio
, 1);
357 /* Compute the longest string */
359 for (i
= 0; i
< count
; i
++){
360 m
= strlen (texts
[i
]);
365 init_widget (&r
->widget
, y
, x
, count
, max
, (callback_fn
) radio_callback
,
366 0, (mouse_h
) radio_event
, tkname
);
372 r
->upper_letter_is_hotkey
= use_hotkey
;
373 widget_want_hotkey (r
->widget
, 1);
379 /* Checkbutton widget */
381 static int check_event (Gpm_Event
*event
, WCheck
*b
);
384 check_callback (Dlg_head
*h
, WCheck
*c
, int Msg
, int Par
)
391 if (c
->hotkey
==Par
||
392 (c
->hotkey
>='a' && c
->hotkey
<='z' && c
->hotkey
-32==Par
)){
393 check_callback (h
, c
, WIDGET_KEY
, ' '); /* make action */
402 c
->state
^= C_CHANGE
;
403 (*h
->callback
) (h
, h
->current
->dlg_id
, DLG_ACTION
);
404 check_callback (h
, c
, WIDGET_FOCUS
, ' ');
408 widget_move (&c
->widget
, 0, 1);
414 attrset ((Msg
== WIDGET_FOCUS
) ? FOCUSC
: NORMALC
);
415 widget_move (&c
->widget
, 0, 0);
416 printw ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
419 attrset ((Msg
== WIDGET_FOCUS
) ? HOT_FOCUSC
: HOT_NORMALC
);
420 widget_move (&c
->widget
, 0, + c
->hotpos
+4);
421 addch ((unsigned char)c
->text
[c
->hotpos
]);
425 return default_proc (h
, Msg
, Par
);
429 check_event (Gpm_Event
*event
, WCheck
*c
)
431 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
432 Dlg_head
*h
= c
->widget
.parent
;
434 dlg_select_widget (h
, c
);
435 if (event
->type
& GPM_UP
){
436 check_callback (h
, c
, WIDGET_KEY
, ' ');
437 check_callback (h
, c
, WIDGET_FOCUS
, 0);
438 (*h
->callback
) (h
, ' ', DLG_POST_KEY
);
446 check_destroy (WCheck
*c
)
452 check_new (int y
, int x
, int state
, char *text
, char *tkname
)
454 WCheck
*c
= g_new (WCheck
, 1);
457 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
458 (callback_fn
)check_callback
,
459 (destroy_fn
)check_destroy
, (mouse_h
) check_event
, tkname
);
460 c
->state
= state
? C_BOOL
: 0;
461 c
->text
= g_strdup (text
);
464 widget_want_hotkey (c
->widget
, 1);
466 /* Scan for the hotkey */
467 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
474 c
->hotkey
= tolower (*s
);
475 c
->hotpos
= t
- c
->text
;
487 label_callback (Dlg_head
*h
, WLabel
*l
, int Msg
, int Par
)
489 if (Msg
== WIDGET_INIT
)
492 /* We don't want to get the focus */
493 if (Msg
== WIDGET_FOCUS
)
495 if (Msg
== WIDGET_DRAW
&& l
->text
){
496 char *p
= l
->text
, *q
, c
= 0;
499 attrset (DEFAULT_COLOR
);
505 q
= strchr (p
, '\n');
510 widget_move (&l
->widget
, y
, 0);
512 xlen
= l
->widget
.cols
- strlen (p
);
514 printw ("%*s", xlen
, " ");
523 return default_proc (h
, Msg
, Par
);
527 label_set_text (WLabel
*label
, char *text
)
529 int newcols
= label
->widget
.cols
;
531 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
532 return; /* Flickering is not nice */
535 g_free (label
->text
);
538 label
->text
= g_strdup (text
);
539 if (label
->auto_adjust_cols
) {
540 newcols
= strlen (text
);
541 if (newcols
> label
->widget
.cols
)
542 label
->widget
.cols
= newcols
;
547 if (label
->widget
.parent
)
548 label_callback (label
->widget
.parent
, label
, WIDGET_DRAW
, 0);
550 if (newcols
< label
->widget
.cols
)
551 label
->widget
.cols
= newcols
;
555 label_destroy (WLabel
*l
)
562 label_new (int y
, int x
, const char *text
, char *tkname
)
567 /* Multiline labels are immutable - no need to compute their sizes */
568 if (!text
|| strchr(text
, '\n'))
571 width
= strlen (text
);
573 l
= g_new (WLabel
, 1);
574 init_widget (&l
->widget
, y
, x
, 1, width
,
575 (callback_fn
) label_callback
,
576 (destroy_fn
) label_destroy
, NULL
, tkname
);
577 l
->text
= text
? g_strdup (text
) : 0;
578 l
->auto_adjust_cols
= 1;
580 widget_want_cursor (l
->widget
, 0);
585 /* Gauge widget (progress indicator) */
586 /* Currently width is hardcoded here for text mode */
590 gauge_callback (Dlg_head
*h
, WGauge
*g
, int Msg
, int Par
)
593 if (Msg
== WIDGET_INIT
)
596 /* We don't want to get the focus */
597 if (Msg
== WIDGET_FOCUS
)
600 if (Msg
== WIDGET_DRAW
){
601 widget_move (&g
->widget
, 0, 0);
604 printw ("%*s", gauge_len
, "");
606 long percentage
, columns
;
607 long total
= g
->max
, done
= g
->current
;
609 if (total
<= 0 || done
< 0) {
615 while (total
> 65535) {
619 percentage
= (200 * done
/ total
+ 1) / 2;
620 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
622 attrset (GAUGE_COLOR
);
623 printw ("%*s", columns
, "");
625 printw ("%*s] %3d%%", gauge_len
- 7 - columns
, "", percentage
);
629 return default_proc (h
, Msg
, Par
);
633 gauge_set_value (WGauge
*g
, int max
, int current
)
635 if (g
->current
== current
&& g
->max
== max
)
636 return; /* Do not flicker */
638 max
= 1; /* I do not like division by zero :) */
640 g
->current
= current
;
642 gauge_callback (g
->widget
.parent
, g
, WIDGET_DRAW
, 0);
646 gauge_show (WGauge
*g
, int shown
)
648 if (g
->shown
== shown
)
651 gauge_callback (g
->widget
.parent
, g
, WIDGET_DRAW
, 0);
655 gauge_destroy (WGauge
*g
)
661 gauge_new (int y
, int x
, int shown
, int max
, int current
, char *tkname
)
663 WGauge
*g
= g_new (WGauge
, 1);
665 init_widget (&g
->widget
, y
, x
, 1, gauge_len
,
666 (callback_fn
) gauge_callback
,
667 (destroy_fn
) gauge_destroy
, NULL
, tkname
);
670 max
= 1; /* I do not like division by zero :) */
672 g
->current
= current
;
674 widget_want_cursor (g
->widget
, 0);
681 /* {{{ history button */
683 #define LARGE_HISTORY_BUTTON 1
685 #ifdef LARGE_HISTORY_BUTTON
686 # define HISTORY_BUTTON_WIDTH 3
688 # define HISTORY_BUTTON_WIDTH 1
691 #define should_show_history_button(in) \
692 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
694 static void draw_history_button (WInput
* in
)
697 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
698 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
699 #ifdef LARGE_HISTORY_BUTTON
702 h
= in
->widget
.parent
;
704 attrset (NORMALC
); /* button has the same colour as other buttons */
706 attrset (HOT_NORMALC
);
708 attrset (NORMAL_COLOR
);
710 /* Too distracting: attrset (MARKED_COLOR); */
712 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
716 attrset (MARKED_COLOR
);
721 /* }}} history button */
724 /* Input widgets now have a global kill ring */
725 /* Pointer to killed data */
726 static char *kill_buffer
= 0;
729 update_input (WInput
*in
, int clear_first
)
734 int buf_len
= strlen (in
->buffer
);
736 if (should_show_history_button (in
))
737 has_history
= HISTORY_BUTTON_WIDTH
;
739 if (in
->disable_update
)
742 /* Make the point visible */
743 if ((in
->point
< in
->first_shown
) ||
744 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
745 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
746 if (in
->first_shown
< 0)
750 /* Adjust the mark */
751 if (in
->mark
> buf_len
)
755 draw_history_button (in
);
759 widget_move (&in
->widget
, 0, 0);
760 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
762 widget_move (&in
->widget
, 0, 0);
764 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
765 c
= in
->buffer
[j
++];
766 c
= is_printable (c
) ? c
: '.';
771 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
778 winput_set_origin (WInput
*in
, int x
, int field_len
)
781 in
->field_len
= in
->widget
.cols
= field_len
;
782 update_input (in
, 0);
785 /* {{{ history saving and loading */
788 This loads and saves the history of an input line to and from the
789 widget. It is called with the widgets tk name on creation of the
790 widget, and returns the Hist list. It stores histories in the file
791 ~/.mc/history in using the profile code.
793 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
794 function) then input_new assigns the default text to be the last text
795 entered, or "" if not found.
798 int num_history_items_recorded
= 60;
801 history_get (char *input_name
)
809 if (!num_history_items_recorded
) /* this is how to disable */
815 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
817 char key_name
[BUF_TINY
];
818 char this_entry
[BUF_LARGE
];
819 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
820 GetPrivateProfileString (input_name
, key_name
, "", this_entry
, sizeof (this_entry
), profile
);
823 new = g_new0 (Hist
, 1);
824 new->text
= g_strdup (this_entry
);
825 new->prev
= old
; /* set up list pointers */
831 return new; /* return pointer to last entry in list */
835 history_put (char *input_name
, Hist
*h
)
849 if (!num_history_items_recorded
) /* this is how to disable */
852 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
854 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
856 /* Just in case I forgot to strip passwords somewhere -- Norbert */
857 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
){
862 while (h
->next
) /* go to end of list */
865 /* go back 60 places */
866 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
870 profile_clean_section (input_name
, profile
);
872 /* dump histories into profile */
873 for (i
= 0; h
; h
= h
->next
){
876 /* probably aren't any null entries, but lets be sure */
878 char key_name
[BUF_TINY
];
879 g_snprintf (key_name
, sizeof(key_name
), "%d", i
++);
880 WritePrivateProfileString (input_name
, key_name
, h
->text
, profile
);
887 /* }}} history saving and loading */
890 /* {{{ history display */
895 static char *history_title
= NULL
;
897 if (history_title
== NULL
)
898 history_title
= _(" History ");
899 return history_title
;
902 static inline int listbox_fwd (WListbox
*l
);
905 show_hist (Hist
* history
, int widget_x
, int widget_y
)
908 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
912 WListbox
*query_list
;
918 while (z
->prev
) /* goto first */
922 if ((i
= strlen (hi
->text
)) > maxlen
)
930 if (h
<= y
|| y
> LINES
- 6) {
935 h
= min (h
, LINES
- y
);
942 if ((w
= maxlen
+ 4) + x
> COLS
) {
948 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
949 i18n_htitle (), DLG_COMPACT
);
950 query_list
= listbox_new (1, 1, w
- 2, h
- 2, listbox_finish
, 0, NULL
);
951 add_widget (query_dlg
, query_list
);
954 while (hi
) { /* traverse */
955 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
958 while (listbox_fwd (query_list
));
962 while (hi
) { /* traverse backwards */
963 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
969 if (query_dlg
->ret_value
!= B_CANCEL
) {
970 listbox_get_current (query_list
, &q
, NULL
);
974 destroy_dlg (query_dlg
);
978 static void do_show_hist (WInput
* in
)
981 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
988 /* }}} history display */
991 input_destroy (WInput
*in
)
994 fprintf (stderr
, "Internal error: null Input *\n");
1000 Hist
*current
, *old
;
1002 if (!in
->is_password
) /* don't save passwords ;-) */
1003 history_put (in
->history_name
, in
->history
);
1005 current
= in
->history
;
1006 while (current
->next
)
1007 current
= current
->next
;
1010 current
= current
->prev
;
1015 g_free (in
->buffer
);
1016 free_completions (in
);
1017 if (in
->history_name
)
1018 g_free (in
->history_name
);
1021 static char disable_update
= 0;
1024 input_disable_update (WInput
*in
)
1026 in
->disable_update
++;
1030 input_enable_update (WInput
*in
)
1032 in
->disable_update
--;
1033 update_input (in
, 0);
1036 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1039 push_history (WInput
*in
, char *text
)
1042 /* input widget where urls with passwords are entered without any
1044 static const char *password_input_fields
[] = {
1045 N_(" Link to a remote machine "),
1046 N_(" FTP to machine "),
1047 N_(" SMB link to machine ")
1055 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1056 password_input_fields
[i
] = _(password_input_fields
[i
]);
1059 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1063 while (in
->history
->next
)
1064 in
->history
= in
->history
->next
;
1065 if (!strcmp (in
->history
->text
, text
))
1067 new = g_new (Hist
, 1);
1068 in
->history
->next
= new;
1070 new = g_new (Hist
, 1);
1073 new->prev
= in
->history
;
1074 new->text
= g_strdup (text
);
1075 if (in
->history_name
) {
1076 p
= in
->history_name
+ 3;
1077 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1078 if (strcmp (p
, password_input_fields
[i
]) == 0)
1080 if (i
< ELEMENTS(password_input_fields
))
1081 strip_password (new->text
, 0);
1083 strip_password (new->text
, 1);
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
)
1190 if (ctrl_pressed ())
1197 key_right (WInput
*in
)
1199 if (ctrl_pressed ())
1206 backward_delete (WInput
*in
)
1212 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1213 in
->buffer
[i
-1] = in
->buffer
[i
];
1219 delete_char (WInput
*in
)
1223 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1224 in
->buffer
[i
] = in
->buffer
[i
+1];
1229 copy_region (WInput
*in
, int x_first
, int x_last
)
1231 int first
= min (x_first
, x_last
);
1232 int last
= max (x_first
, x_last
);
1238 g_free (kill_buffer
);
1240 kill_buffer
= g_malloc (last
-first
+ 1);
1241 strncpy (kill_buffer
, in
->buffer
+first
, last
-first
);
1242 kill_buffer
[last
-first
] = 0;
1246 delete_region (WInput
*in
, int x_first
, int x_last
)
1248 int first
= min (x_first
, x_last
);
1249 int last
= max (x_first
, x_last
);
1253 strcpy (&in
->buffer
[first
], &in
->buffer
[last
]);
1258 kill_word (WInput
*in
)
1260 int old_point
= in
->point
;
1264 new_point
= in
->point
;
1265 in
->point
= old_point
;
1267 copy_region (in
, old_point
, new_point
);
1268 delete_region (in
, old_point
, new_point
);
1273 back_kill_word (WInput
*in
)
1275 int old_point
= in
->point
;
1279 new_point
= in
->point
;
1280 in
->point
= old_point
;
1282 copy_region (in
, old_point
, new_point
);
1283 delete_region (in
, old_point
, new_point
);
1288 set_mark (WInput
*in
)
1290 in
->mark
= in
->point
;
1294 kill_save (WInput
*in
)
1296 copy_region (in
, in
->mark
, in
->point
);
1300 kill_region (WInput
*in
)
1303 delete_region (in
, in
->point
, in
->mark
);
1313 for (p
= kill_buffer
; *p
; p
++)
1314 insert_char (in
, *p
);
1318 kill_line (WInput
*in
)
1321 g_free (kill_buffer
);
1322 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1323 in
->buffer
[in
->point
] = 0;
1327 assign_text (WInput
*in
, char *text
)
1329 free_completions (in
);
1330 g_free (in
->buffer
);
1331 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1332 in
->current_max_len
= strlen (in
->buffer
) + 1;
1333 in
->point
= strlen (in
->buffer
);
1339 hist_prev (WInput
*in
)
1344 if (in
->need_push
) {
1345 switch (push_history (in
, in
->buffer
)) {
1346 case 2: in
->history
= in
->history
->prev
; break;
1347 case 1: if (in
->history
->prev
) in
->history
= in
->history
->prev
; break;
1350 } else if (in
->history
->prev
)
1351 in
->history
= in
->history
->prev
;
1354 assign_text (in
, in
->history
->text
);
1359 hist_next (WInput
*in
)
1361 if (in
->need_push
) {
1362 switch (push_history (in
, in
->buffer
)) {
1364 assign_text (in
, "");
1374 if (!in
->history
->next
) {
1375 assign_text (in
, "");
1379 in
->history
= in
->history
->next
;
1380 assign_text (in
, in
->history
->text
);
1384 static const struct {
1386 void (*fn
)(WInput
*in
);
1389 { XCTRL('a'), beginning_of_line
},
1390 { KEY_HOME
, beginning_of_line
},
1391 { KEY_A1
, beginning_of_line
},
1392 { XCTRL('e'), end_of_line
},
1393 { KEY_END
, end_of_line
},
1394 { KEY_C1
, end_of_line
},
1395 { KEY_LEFT
, key_left
},
1396 { XCTRL('b'), backward_char
},
1397 { ALT('b'), backward_word
},
1398 { KEY_RIGHT
, key_right
},
1399 { XCTRL('f'), forward_char
},
1400 { ALT('f'), forward_word
},
1403 { 0177, backward_delete
},
1404 { KEY_BACKSPACE
, backward_delete
},
1405 { XCTRL('h'), backward_delete
},
1406 { KEY_DC
, delete_char
},
1407 { XCTRL('d'), delete_char
},
1408 { ALT('d'), kill_word
},
1409 { ALT(KEY_BACKSPACE
), back_kill_word
},
1410 { ALT(XCTRL('h')), back_kill_word
},
1411 { ALT(127), back_kill_word
},
1413 /* Region manipulation */
1415 { XCTRL('w'), kill_region
},
1416 { ALT('w'), kill_save
},
1417 { XCTRL('y'), yank
},
1418 { XCTRL('k'), kill_line
},
1421 { ALT('p'), hist_prev
},
1422 { ALT('n'), hist_next
},
1423 { ALT('h'), do_show_hist
},
1426 { ALT('\t'), complete
},
1431 /* This function is a test for a special input key used in complete.c */
1432 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1433 and 2 if it is a complete key */
1435 is_in_input_map (WInput
*in
, int c_code
)
1439 for (i
= 0; input_map
[i
].fn
; i
++)
1440 if (c_code
== input_map
[i
].key_code
) {
1441 if (input_map
[i
].fn
== complete
)
1450 port_region_marked_for_delete (WInput
*in
)
1458 handle_char (WInput
*in
, int c_code
)
1466 free_completions (in
);
1467 v
= insert_char (in
, c_code
);
1468 update_input (in
, 1);
1473 for (i
= 0; input_map
[i
].fn
; i
++){
1474 if (c_code
== input_map
[i
].key_code
){
1475 if (input_map
[i
].fn
!= complete
)
1476 free_completions (in
);
1477 (*input_map
[i
].fn
)(in
);
1482 if (!input_map
[i
].fn
){
1483 if (c_code
> 255 || !is_printable (c_code
))
1486 port_region_marked_for_delete (in
);
1488 free_completions (in
);
1489 v
= insert_char (in
, c_code
);
1490 in
->inserted_one
= c_code
;
1492 if (!disable_update
)
1493 update_input (in
, 1);
1497 /* Inserts text in input line */
1499 stuff (WInput
*in
, char *text
, int insert_extra_space
)
1501 input_disable_update (in
);
1503 handle_char (in
, *text
++);
1504 if (insert_extra_space
)
1505 handle_char (in
, ' ');
1506 input_enable_update (in
);
1507 update_input (in
, 1);
1511 input_set_point (WInput
*in
, int pos
)
1513 if (pos
> in
->current_max_len
)
1514 pos
= in
->current_max_len
;
1515 if (pos
!= in
->point
)
1516 free_completions (in
);
1518 update_input (in
, 1);
1522 input_callback (Dlg_head
*h
, WInput
*in
, int Msg
, int Par
)
1529 if (Par
== XCTRL('q')){
1533 v
= handle_char (in
, mi_getch ());
1537 if (Par
== KEY_UP
|| Par
== KEY_DOWN
||
1538 Par
== ESC_CHAR
|| Par
== KEY_F(10) ||
1540 return 0; /* We don't handle up/down */
1546 return handle_char (in
, Par
);
1549 case WIDGET_UNFOCUS
:
1551 update_input (in
, 0);
1554 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1558 return default_proc (h
, Msg
, Par
);
1562 input_event (Gpm_Event
* event
, WInput
* in
)
1564 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1565 dlg_select_widget (in
->widget
.parent
, in
);
1567 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1568 && should_show_history_button (in
)) {
1571 in
->point
= strlen (in
->buffer
);
1572 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1573 in
->point
= event
->x
- in
->first_shown
- 1;
1577 update_input (in
, 1);
1583 input_new (int y
, int x
, int color
, int len
, const char *def_text
, char *tkname
)
1585 WInput
*in
= g_new (WInput
, 1);
1586 int initial_buffer_len
;
1588 init_widget (&in
->widget
, y
, x
, 1, len
,
1589 (callback_fn
) input_callback
,
1590 (destroy_fn
) input_destroy
, (mouse_h
) input_event
, tkname
);
1594 in
->history_name
= 0;
1597 in
->history_name
= g_strdup (tkname
);
1598 in
->history
= history_get (tkname
);
1605 if (def_text
== INPUT_LAST_TEXT
) {
1608 if (in
->history
->text
)
1609 def_text
= in
->history
->text
;
1611 initial_buffer_len
= 1 + max (len
, strlen (def_text
));
1612 in
->widget
.options
|= W_IS_INPUT
;
1613 in
->completions
= NULL
;
1614 in
->completion_flags
=
1615 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
|
1616 INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
;
1617 in
->current_max_len
= initial_buffer_len
;
1618 in
->buffer
= g_malloc (initial_buffer_len
);
1620 in
->field_len
= len
;
1622 in
->first_shown
= 0;
1623 in
->disable_update
= 0;
1626 in
->is_password
= 0;
1628 strcpy (in
->buffer
, def_text
);
1629 in
->point
= strlen (in
->buffer
);
1634 /* Listbox widget */
1636 /* Should draw the scrollbar, but currently draws only
1637 * indications that there is more information
1639 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1642 listbox_drawscroll (WListbox
*l
)
1644 extern int slow_terminal
;
1647 int max_line
= l
->height
-1;
1649 /* Are we at the top? */
1650 widget_move (&l
->widget
, 0, l
->width
);
1651 if (l
->list
== l
->top
)
1656 /* Are we at the bottom? */
1657 widget_move (&l
->widget
, max_line
, l
->width
);
1658 top
= listbox_cdiff (l
->list
, l
->top
);
1659 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1664 /* Now draw the nice relative pointer */
1666 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1670 for (i
= 1; i
< max_line
; i
++){
1671 widget_move (&l
->widget
, i
, l
->width
);
1680 listbox_draw (WListbox
*l
, Dlg_head
*h
, int focused
)
1685 int normalc
= NORMALC
;
1696 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1698 /* Display the entry */
1699 if (e
== l
->current
&& sel_line
== -1){
1705 widget_move (&l
->widget
, i
, 0);
1707 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1713 printw (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1715 l
->cursor_y
= sel_line
;
1719 listbox_drawscroll (l
);
1722 /* Returns the number of items between s and e,
1723 must be on the same linked list */
1725 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1729 for (count
= 0; s
!= e
; count
++)
1735 listbox_check_hotkey (WListbox
*l
, int key
)
1747 /* If we didn't find anything, return */
1748 if (i
&& e
== l
->list
)
1751 if (e
->hotkey
== key
)
1759 /* Used only for display updating, for avoiding line at a time scroll */
1761 listbox_select_last (WListbox
*l
, int set_top
)
1764 l
->current
= l
->list
->prev
;
1765 l
->pos
= l
->count
- 1;
1767 l
->top
= l
->list
->prev
;
1772 listbox_remove_list (WListbox
*l
)
1781 while (l
->count
--) {
1787 l
->pos
= l
->count
= 0;
1788 l
->list
= l
->top
= l
->current
= 0;
1792 * bor 30.10.96: added force flag to remove *last* entry as well
1793 * bor 30.10.96: corrected selection bug if last entry was removed
1797 listbox_remove_current (WListbox
*l
, int force
)
1801 /* Ok, note: this won't allow for emtpy lists */
1802 if (!force
&& (!l
->count
|| l
->count
== 1))
1809 l
->current
->next
->prev
= l
->current
->prev
;
1810 l
->current
->prev
->next
= l
->current
->next
;
1811 if (p
->next
== l
->list
) {
1812 l
->current
= p
->prev
;
1816 l
->current
= p
->next
;
1819 l
->list
= l
->top
= p
->next
;
1822 l
->list
= l
->top
= l
->current
= 0;
1829 /* Makes *e the selected entry (sets current and pos) */
1831 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1840 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1848 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1849 l
->top
= l
->top
->next
;
1851 l
->top
= l
->current
;
1857 /* If we are unable to find it, set decent values */
1858 l
->current
= l
->top
= l
->list
;
1862 /* Selects from base the pos element */
1864 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1866 WLEntry
*last
= l
->list
->prev
;
1879 listbox_back (WListbox
*l
)
1882 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1889 listbox_fwd (WListbox
*l
)
1891 if (l
->current
!= l
->list
->prev
){
1892 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
1898 /* Returns 1 if we want a redraw */
1900 listbox_key (WListbox
*l
, int key
)
1911 l
->current
= l
->top
= l
->list
;
1917 l
->current
= l
->top
= l
->list
->prev
;
1918 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1919 l
->top
= l
->top
->prev
;
1920 l
->pos
= l
->count
- 1;
1935 for (i
= 0; i
< l
->height
-1; i
++)
1936 j
|= listbox_fwd (l
);
1941 for (i
= 0; i
< l
->height
-1; i
++)
1942 j
|= listbox_back (l
);
1948 static int listbox_event (Gpm_Event
*event
, WListbox
*l
);
1950 listbox_callback (Dlg_head
*h
, WListbox
*l
, int msg
, int par
)
1953 /* int selected_color; Never used */
1961 if ((e
= listbox_check_hotkey (l
, par
)) != NULL
){
1962 listbox_select_entry (l
, e
);
1964 /* Take the appropriate action */
1965 if (l
->action
== listbox_finish
){
1966 l
->widget
.parent
->running
= 0;
1967 l
->widget
.parent
->ret_value
= B_ENTER
;
1968 } else if (l
->action
== listbox_cback
){
1969 if ((*l
->cback
)(l
) == listbox_finish
){
1970 l
->widget
.parent
->running
= 0;
1971 l
->widget
.parent
->ret_value
= B_ENTER
;
1979 if ((ret_code
= listbox_key (l
, par
)))
1980 listbox_draw (l
, h
, 1);
1984 widget_move (&l
->widget
, l
->cursor_y
, 0);
1988 case WIDGET_UNFOCUS
:
1990 listbox_draw (l
, h
, msg
!= WIDGET_UNFOCUS
);
1993 return default_proc (h
, msg
, par
);
1997 listbox_event (Gpm_Event
*event
, WListbox
*l
)
2001 Dlg_head
*h
= l
->widget
.parent
;
2004 if (event
->type
& GPM_DOWN
)
2005 dlg_select_widget (l
->widget
.parent
, l
);
2008 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2009 if (event
->x
< 0 || event
->x
>= l
->width
)
2012 for (i
= -event
->y
; i
>= 0; i
--)
2014 else if (event
->y
> l
->height
)
2015 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2018 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
,
2021 /* We need to refresh ourselves since the dialog manager doesn't */
2022 /* know about this event */
2023 listbox_callback (h
, l
, WIDGET_DRAW
, 0);
2029 if ((event
->type
& (GPM_DOUBLE
|GPM_UP
)) == (GPM_UP
|GPM_DOUBLE
)){
2030 if (event
->x
< 0 || event
->x
>= l
->width
)
2032 if (event
->y
< 1 || event
->y
> l
->height
)
2035 dlg_select_widget (l
->widget
.parent
, l
);
2036 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
, event
->y
- 1));
2039 case listbox_nothing
:
2042 case listbox_finish
:
2043 h
->ret_value
= B_ENTER
;
2048 if ((*l
->cback
)(l
) == listbox_finish
)
2056 listbox_destroy (WListbox
*l
)
2058 WLEntry
*n
, *p
= l
->list
;
2061 for (i
= 0; i
< l
->count
; i
++){
2070 listbox_new (int y
, int x
, int width
, int height
,
2071 int action
, lcback callback
, char *tkname
)
2073 WListbox
*l
= g_new (WListbox
, 1);
2074 extern int slow_terminal
;
2076 init_widget (&l
->widget
, y
, x
, height
, width
,
2077 (callback_fn
)listbox_callback
,
2078 (destroy_fn
) listbox_destroy
, (mouse_h
)listbox_event
, tkname
);
2080 l
->list
= l
->top
= l
->current
= 0;
2090 l
->cback
= callback
;
2092 l
->allow_duplicates
= 1;
2093 l
->scrollbar
= slow_terminal
? 0 : 1;
2094 widget_want_hotkey (l
->widget
, 1);
2099 /* Listbox item adding function. They still lack a lot of functionality */
2101 /* 1.11.96 bor: added pos argument to control placement of new entry */
2103 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2111 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2113 e
->prev
= l
->list
->prev
;
2114 l
->list
->prev
->next
= e
;
2116 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2117 e
->next
= l
->current
;
2118 e
->prev
= l
->current
->prev
;
2119 l
->current
->prev
->next
= e
;
2120 l
->current
->prev
= e
;
2121 if (l
->list
== l
->current
) { /* move list one position down */
2125 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2126 e
->prev
= l
->current
;
2127 e
->next
= l
->current
->next
;
2128 l
->current
->next
->prev
= e
;
2129 l
->current
->next
= e
;
2135 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
, char *text
,
2143 if (!l
->allow_duplicates
)
2144 if (listbox_search_text (l
, text
))
2147 entry
= g_new (WLEntry
, 1);
2148 entry
->text
= g_strdup (text
);
2150 entry
->hotkey
= hotkey
;
2152 listbox_append_item (l
, entry
, pos
);
2157 /* Selects the nth entry in the listbox */
2159 listbox_select_by_number (WListbox
*l
, int n
)
2161 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2165 listbox_search_text (WListbox
*l
, char *text
)
2174 if(!strcmp (e
->text
, text
))
2177 } while (e
!=l
->list
);
2182 /* Returns the current string text as well as the associated extra data */
2184 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2190 if (string
&& l
->current
)
2191 *string
= l
->current
->text
;
2192 if (extra
&& l
->current
)
2193 *extra
= l
->current
->data
;
2197 buttonbar_callback (Dlg_head
*h
, WButtonBar
*bb
, int msg
, int par
)
2209 for (i
= 0; i
< 10; i
++){
2210 if (par
== KEY_F(i
+1) && bb
->labels
[i
].function
){
2211 (*bb
->labels
[i
].function
)(bb
->labels
[i
].data
);
2220 widget_move (&bb
->widget
, 0, 0);
2221 attrset (DEFAULT_COLOR
);
2222 printw ("%-*s", bb
->widget
.cols
, "");
2223 for (i
= 0; i
< COLS
/8 && i
< 10; i
++){
2224 widget_move (&bb
->widget
, 0, i
*8);
2225 attrset (DEFAULT_COLOR
);
2227 attrset (SELECTED_COLOR
);
2228 printw ("%-*s", ((i
+1) * 8 == COLS
? 5 : 6),
2229 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2230 attrset (DEFAULT_COLOR
);
2232 attrset (SELECTED_COLOR
);
2235 return default_proc (h
, msg
, par
);
2239 buttonbar_destroy (WButtonBar
*bb
)
2243 for (i
= 0; i
< 10; i
++){
2244 if (bb
->labels
[i
].text
)
2245 g_free (bb
->labels
[i
].text
);
2250 buttonbar_event (Gpm_Event
*event
, WButtonBar
*bb
)
2254 if (!(event
->type
& GPM_UP
))
2258 button
= event
->x
/ 8;
2259 if (button
< 10 && bb
->labels
[button
].function
)
2260 (*bb
->labels
[button
].function
)(bb
->labels
[button
].data
);
2265 buttonbar_new (int visible
)
2268 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2270 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2271 (callback_fn
) buttonbar_callback
,
2272 (destroy_fn
) buttonbar_destroy
, (mouse_h
) buttonbar_event
, NULL
);
2274 bb
->visible
= visible
;
2275 for (i
= 0; i
< 10; i
++){
2276 bb
->labels
[i
].text
= 0;
2277 bb
->labels
[i
].function
= 0;
2279 widget_want_hotkey (bb
->widget
, 1);
2280 widget_want_cursor (bb
->widget
, 0);
2286 set_label_text (WButtonBar
* bb
, int index
, char *text
)
2288 if (bb
->labels
[index
- 1].text
)
2289 g_free (bb
->labels
[index
- 1].text
);
2291 bb
->labels
[index
- 1].text
= g_strdup (text
);
2294 /* paneletc is either the panel widget, or info or view or tree widget */
2296 find_buttonbar (Dlg_head
* h
, Widget
* paneletc
)
2303 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
) {
2304 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
) {
2305 bb
= (WButtonBar
*) item
->widget
;
2313 define_label_data (Dlg_head
* h
, Widget
* paneletc
, int idx
, char *text
,
2314 buttonbarfn cback
, void *data
)
2316 WButtonBar
*bb
= find_buttonbar (h
, paneletc
);
2320 set_label_text (bb
, idx
, text
);
2321 bb
->labels
[idx
- 1].function
= cback
;
2322 bb
->labels
[idx
- 1].data
= data
;
2326 define_label (Dlg_head
* h
, Widget
* paneletc
, int idx
, char *text
,
2327 void (*cback
) (void))
2329 define_label_data (h
, paneletc
, idx
, text
, (buttonbarfn
) cback
, 0);
2333 redraw_labels (Dlg_head
*h
, Widget
*paneletc
)
2338 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
){
2339 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
){
2340 widget_redraw (h
, item
);