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 */
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;
799 Hist
*history_get (char *input_name
)
807 if (!num_history_items_recorded
) /* this is how to disable */
813 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
815 char key_name
[BUF_TINY
];
816 char this_entry
[BUF_LARGE
];
817 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
818 GetPrivateProfileString (input_name
, key_name
, "", this_entry
, sizeof (this_entry
), profile
);
821 new = g_new0 (Hist
, 1);
822 new->text
= g_strdup (this_entry
);
823 new->prev
= old
; /* set up list pointers */
829 return new; /* return pointer to last entry in list */
832 void history_put (char *input_name
, Hist
*h
)
846 if (!num_history_items_recorded
) /* this is how to disable */
849 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
851 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
853 /* Just in case I forgot to strip passwords somewhere -- Norbert */
854 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
){
859 while (h
->next
) /* go to end of list */
862 /* go back 60 places */
863 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
867 profile_clean_section (input_name
, profile
);
869 /* dump histories into profile */
870 for (i
= 0; h
; h
= h
->next
){
873 /* probably aren't any null entries, but lets be sure */
875 char key_name
[BUF_TINY
];
876 g_snprintf (key_name
, sizeof(key_name
), "%d", i
++);
877 WritePrivateProfileString (input_name
, key_name
, h
->text
, profile
);
884 /* }}} history saving and loading */
887 /* {{{ history display */
892 static char *history_title
= NULL
;
894 if (history_title
== NULL
)
895 history_title
= _(" History ");
896 return history_title
;
900 history_callback (Dlg_head
* h
, int Par
, int Msg
)
904 attrset (COLOR_NORMAL
);
906 draw_box (h
, 0, 0, h
->lines
, h
->cols
);
907 attrset (COLOR_HOT_NORMAL
);
908 dlg_move (h
, 0, (h
->cols
- strlen (i18n_htitle())) / 2);
909 printw (i18n_htitle());
915 static inline int listbox_fwd (WListbox
*l
);
917 char *show_hist (Hist
*history
, int widget_x
, int widget_y
)
920 size_t maxlen
= strlen (i18n_htitle()), i
, count
= 0;
924 WListbox
*query_list
;
930 while (z
->prev
) /* goto first */
934 if ((i
= strlen (hi
->text
)) > maxlen
)
942 if (h
<= y
|| y
> LINES
- 6)
950 h
= min(h
, LINES
- y
);
957 if ((w
= maxlen
+ 4) + x
> COLS
)
963 query_dlg
= create_dlg (y
, x
, h
, w
, dialog_colors
, history_callback
,
964 "[History-query]", "history", DLG_NONE
);
965 query_list
= listbox_new (1, 1, w
- 2, h
- 2, listbox_finish
, 0, NULL
);
966 add_widget (query_dlg
, query_list
);
969 while (hi
) { /* traverse */
970 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
973 while (listbox_fwd (query_list
));
977 while (hi
) { /* traverse backwards */
978 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
984 if (query_dlg
->ret_value
!= B_CANCEL
) {
985 listbox_get_current (query_list
, &q
, NULL
);
989 destroy_dlg (query_dlg
);
993 static void do_show_hist (WInput
* in
)
996 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1003 /* }}} history display */
1006 input_destroy (WInput
*in
)
1009 fprintf (stderr
, "Internal error: null Input *\n");
1015 Hist
*current
, *old
;
1017 if (!in
->is_password
) /* don't save passwords ;-) */
1018 history_put (in
->history_name
, in
->history
);
1020 current
= in
->history
;
1021 while (current
->next
)
1022 current
= current
->next
;
1025 current
= current
->prev
;
1030 g_free (in
->buffer
);
1031 free_completions (in
);
1032 if (in
->history_name
)
1033 g_free (in
->history_name
);
1036 static char disable_update
= 0;
1039 input_disable_update (WInput
*in
)
1041 in
->disable_update
++;
1045 input_enable_update (WInput
*in
)
1047 in
->disable_update
--;
1048 update_input (in
, 0);
1051 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1054 push_history (WInput
*in
, char *text
)
1057 /* input widget where urls with passwords are entered without any
1059 static const char *password_input_fields
[] = {
1060 N_(" Link to a remote machine "),
1061 N_(" FTP to machine "),
1062 N_(" SMB link to machine ")
1070 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1071 password_input_fields
[i
] = _(password_input_fields
[i
]);
1074 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1078 while (in
->history
->next
)
1079 in
->history
= in
->history
->next
;
1080 if (!strcmp (in
->history
->text
, text
))
1082 new = g_new (Hist
, 1);
1083 in
->history
->next
= new;
1085 new = g_new (Hist
, 1);
1088 new->prev
= in
->history
;
1089 new->text
= g_strdup (text
);
1090 if (in
->history_name
) {
1091 p
= in
->history_name
+ 3;
1092 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1093 if (strcmp (p
, password_input_fields
[i
]) == 0)
1095 if (i
< ELEMENTS(password_input_fields
))
1096 strip_password (new->text
, 0);
1098 strip_password (new->text
, 1);
1107 /* Cleans the input line and adds the current text to the history */
1109 new_input (WInput
*in
)
1112 push_history (in
, in
->buffer
);
1117 free_completions (in
);
1118 update_input (in
, 0);
1122 insert_char (WInput
*in
, int c_code
)
1130 if (strlen (in
->buffer
)+1 == in
->current_max_len
){
1131 /* Expand the buffer */
1132 char *narea
= g_malloc (in
->current_max_len
+ in
->field_len
);
1134 char *p
= in
->buffer
;
1136 strcpy (narea
, in
->buffer
);
1138 in
->current_max_len
+= in
->field_len
;
1142 if (strlen (in
->buffer
)+1 < in
->current_max_len
){
1143 int l
= strlen (&in
->buffer
[in
->point
]);
1144 for (i
= l
+1; i
> 0; i
--)
1145 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1146 in
->buffer
[in
->point
] = c_code
;
1153 beginning_of_line (WInput
*in
)
1159 end_of_line (WInput
*in
)
1161 in
->point
= strlen (in
->buffer
);
1165 backward_char (WInput
*in
)
1172 forward_char (WInput
*in
)
1174 if (in
->buffer
[in
->point
])
1179 forward_word (WInput
*in
)
1181 unsigned char *p
= in
->buffer
+in
->point
;
1183 while (*p
&& (isspace (*p
) || ispunct (*p
)))
1185 while (*p
&& isalnum (*p
))
1187 in
->point
= p
- in
->buffer
;
1191 backward_word (WInput
*in
)
1193 unsigned char *p
= in
->buffer
+in
->point
;
1195 while (p
-1 > in
->buffer
-1 && (isspace (*(p
-1)) || ispunct (*(p
-1))))
1197 while (p
-1 > in
->buffer
-1 && isalnum (*(p
-1)))
1199 in
->point
= p
- in
->buffer
;
1203 key_left (WInput
*in
)
1205 if (ctrl_pressed ())
1212 key_right (WInput
*in
)
1214 if (ctrl_pressed ())
1221 backward_delete (WInput
*in
)
1227 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1228 in
->buffer
[i
-1] = in
->buffer
[i
];
1234 delete_char (WInput
*in
)
1238 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1239 in
->buffer
[i
] = in
->buffer
[i
+1];
1244 copy_region (WInput
*in
, int x_first
, int x_last
)
1246 int first
= min (x_first
, x_last
);
1247 int last
= max (x_first
, x_last
);
1253 g_free (kill_buffer
);
1255 kill_buffer
= g_malloc (last
-first
+ 1);
1256 strncpy (kill_buffer
, in
->buffer
+first
, last
-first
);
1257 kill_buffer
[last
-first
] = 0;
1261 delete_region (WInput
*in
, int x_first
, int x_last
)
1263 int first
= min (x_first
, x_last
);
1264 int last
= max (x_first
, x_last
);
1268 strcpy (&in
->buffer
[first
], &in
->buffer
[last
]);
1273 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 back_kill_word (WInput
*in
)
1290 int old_point
= in
->point
;
1294 new_point
= in
->point
;
1295 in
->point
= old_point
;
1297 copy_region (in
, old_point
, new_point
);
1298 delete_region (in
, old_point
, new_point
);
1303 set_mark (WInput
*in
)
1305 in
->mark
= in
->point
;
1309 kill_save (WInput
*in
)
1311 copy_region (in
, in
->mark
, in
->point
);
1315 kill_region (WInput
*in
)
1318 delete_region (in
, in
->point
, in
->mark
);
1328 for (p
= kill_buffer
; *p
; p
++)
1329 insert_char (in
, *p
);
1333 kill_line (WInput
*in
)
1336 g_free (kill_buffer
);
1337 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1338 in
->buffer
[in
->point
] = 0;
1342 assign_text (WInput
*in
, char *text
)
1344 free_completions (in
);
1345 g_free (in
->buffer
);
1346 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1347 in
->current_max_len
= strlen (in
->buffer
) + 1;
1348 in
->point
= strlen (in
->buffer
);
1354 hist_prev (WInput
*in
)
1359 if (in
->need_push
) {
1360 switch (push_history (in
, in
->buffer
)) {
1361 case 2: in
->history
= in
->history
->prev
; break;
1362 case 1: if (in
->history
->prev
) in
->history
= in
->history
->prev
; break;
1365 } else if (in
->history
->prev
)
1366 in
->history
= in
->history
->prev
;
1369 assign_text (in
, in
->history
->text
);
1374 hist_next (WInput
*in
)
1376 if (in
->need_push
) {
1377 switch (push_history (in
, in
->buffer
)) {
1379 assign_text (in
, "");
1389 if (!in
->history
->next
) {
1390 assign_text (in
, "");
1394 in
->history
= in
->history
->next
;
1395 assign_text (in
, in
->history
->text
);
1399 static const struct {
1401 void (*fn
)(WInput
*in
);
1404 { XCTRL('a'), beginning_of_line
},
1405 { KEY_HOME
, beginning_of_line
},
1406 { KEY_A1
, beginning_of_line
},
1407 { XCTRL('e'), end_of_line
},
1408 { KEY_END
, end_of_line
},
1409 { KEY_C1
, end_of_line
},
1410 { KEY_LEFT
, key_left
},
1411 { XCTRL('b'), backward_char
},
1412 { ALT('b'), backward_word
},
1413 { KEY_RIGHT
, key_right
},
1414 { XCTRL('f'), forward_char
},
1415 { ALT('f'), forward_word
},
1418 { 0177, backward_delete
},
1419 { KEY_BACKSPACE
, backward_delete
},
1420 { XCTRL('h'), backward_delete
},
1421 { KEY_DC
, delete_char
},
1422 { XCTRL('d'), delete_char
},
1423 { ALT('d'), kill_word
},
1424 { ALT(KEY_BACKSPACE
), back_kill_word
},
1425 { ALT(XCTRL('h')), back_kill_word
},
1426 { ALT(127), back_kill_word
},
1428 /* Region manipulation */
1430 { XCTRL('w'), kill_region
},
1431 { ALT('w'), kill_save
},
1432 { XCTRL('y'), yank
},
1433 { XCTRL('k'), kill_line
},
1436 { ALT('p'), hist_prev
},
1437 { ALT('n'), hist_next
},
1438 { ALT('h'), do_show_hist
},
1441 { ALT('\t'), complete
},
1446 /* This function is a test for a special input key used in complete.c */
1447 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1448 and 2 if it is a complete key */
1450 is_in_input_map (WInput
*in
, int c_code
)
1454 for (i
= 0; input_map
[i
].fn
; i
++)
1455 if (c_code
== input_map
[i
].key_code
) {
1456 if (input_map
[i
].fn
== complete
)
1465 port_region_marked_for_delete (WInput
*in
)
1473 handle_char (WInput
*in
, int c_code
)
1481 free_completions (in
);
1482 v
= insert_char (in
, c_code
);
1483 update_input (in
, 1);
1488 for (i
= 0; input_map
[i
].fn
; i
++){
1489 if (c_code
== input_map
[i
].key_code
){
1490 if (input_map
[i
].fn
!= complete
)
1491 free_completions (in
);
1492 (*input_map
[i
].fn
)(in
);
1497 if (!input_map
[i
].fn
){
1498 if (c_code
> 255 || !is_printable (c_code
))
1501 port_region_marked_for_delete (in
);
1503 free_completions (in
);
1504 v
= insert_char (in
, c_code
);
1505 in
->inserted_one
= c_code
;
1507 if (!disable_update
)
1508 update_input (in
, 1);
1512 /* Inserts text in input line */
1514 stuff (WInput
*in
, char *text
, int insert_extra_space
)
1516 input_disable_update (in
);
1518 handle_char (in
, *text
++);
1519 if (insert_extra_space
)
1520 handle_char (in
, ' ');
1521 input_enable_update (in
);
1522 update_input (in
, 1);
1526 input_set_point (WInput
*in
, int pos
)
1528 if (pos
> in
->current_max_len
)
1529 pos
= in
->current_max_len
;
1530 if (pos
!= in
->point
)
1531 free_completions (in
);
1533 update_input (in
, 1);
1536 int input_event (Gpm_Event
*event
, WInput
*b
);
1539 input_callback (Dlg_head
*h
, WInput
*in
, int Msg
, int Par
)
1546 if (Par
== XCTRL('q')){
1550 v
= handle_char (in
, mi_getch ());
1554 if (Par
== KEY_UP
|| Par
== KEY_DOWN
||
1555 Par
== ESC_CHAR
|| Par
== KEY_F(10) ||
1557 return 0; /* We don't handle up/down */
1563 return handle_char (in
, Par
);
1566 case WIDGET_UNFOCUS
:
1568 update_input (in
, 0);
1571 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1575 return default_proc (h
, Msg
, Par
);
1578 /* Not declared static, since we check against this value in dlg.c */
1579 /* FIXME: Declare static again and provide an identification mechanism */
1581 input_event (Gpm_Event
*event
, WInput
*in
)
1583 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
1584 dlg_select_widget (in
->widget
.parent
, in
);
1586 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1 && should_show_history_button (in
)) {
1589 in
->point
= strlen (in
->buffer
);
1590 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1591 in
->point
= event
->x
- in
->first_shown
- 1;
1595 update_input (in
, 1);
1601 input_new (int y
, int x
, int color
, int len
, const char *def_text
, char *tkname
)
1603 WInput
*in
= g_new (WInput
, 1);
1604 int initial_buffer_len
;
1606 init_widget (&in
->widget
, y
, x
, 1, len
,
1607 (callback_fn
) input_callback
,
1608 (destroy_fn
) input_destroy
, (mouse_h
) input_event
, tkname
);
1612 in
->history_name
= 0;
1615 in
->history_name
= g_strdup (tkname
);
1616 in
->history
= history_get (tkname
);
1623 if (def_text
== INPUT_LAST_TEXT
) {
1626 if (in
->history
->text
)
1627 def_text
= in
->history
->text
;
1629 initial_buffer_len
= 1 + max (len
, strlen (def_text
));
1630 in
->widget
.options
|= W_IS_INPUT
;
1631 in
->completions
= NULL
;
1632 in
->completion_flags
=
1633 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
|
1634 INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
;
1635 in
->current_max_len
= initial_buffer_len
;
1636 in
->buffer
= g_malloc (initial_buffer_len
);
1638 in
->field_len
= len
;
1640 in
->first_shown
= 0;
1641 in
->disable_update
= 0;
1644 in
->is_password
= 0;
1646 strcpy (in
->buffer
, def_text
);
1647 in
->point
= strlen (in
->buffer
);
1652 /* Listbox widget */
1654 /* Should draw the scrollbar, but currently draws only
1655 * indications that there is more information
1657 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1660 listbox_drawscroll (WListbox
*l
)
1662 extern int slow_terminal
;
1665 int max_line
= l
->height
-1;
1667 /* Are we at the top? */
1668 widget_move (&l
->widget
, 0, l
->width
);
1669 if (l
->list
== l
->top
)
1674 /* Are we at the bottom? */
1675 widget_move (&l
->widget
, max_line
, l
->width
);
1676 top
= listbox_cdiff (l
->list
, l
->top
);
1677 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1682 /* Now draw the nice relative pointer */
1684 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1688 for (i
= 1; i
< max_line
; i
++){
1689 widget_move (&l
->widget
, i
, l
->width
);
1698 listbox_draw (WListbox
*l
, Dlg_head
*h
, int focused
)
1703 int normalc
= NORMALC
;
1714 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1716 /* Display the entry */
1717 if (e
== l
->current
&& sel_line
== -1){
1723 widget_move (&l
->widget
, i
, 0);
1725 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1731 printw (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1733 l
->cursor_y
= sel_line
;
1737 listbox_drawscroll (l
);
1740 /* Returns the number of items between s and e,
1741 must be on the same linked list */
1743 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1747 for (count
= 0; s
!= e
; count
++)
1753 listbox_check_hotkey (WListbox
*l
, int key
)
1765 /* If we didn't find anything, return */
1766 if (i
&& e
== l
->list
)
1769 if (e
->hotkey
== key
)
1777 /* Used only for display updating, for avoiding line at a time scroll */
1779 listbox_select_last (WListbox
*l
, int set_top
)
1782 l
->current
= l
->list
->prev
;
1783 l
->pos
= l
->count
- 1;
1785 l
->top
= l
->list
->prev
;
1790 listbox_remove_list (WListbox
*l
)
1799 while (l
->count
--) {
1805 l
->pos
= l
->count
= 0;
1806 l
->list
= l
->top
= l
->current
= 0;
1810 * bor 30.10.96: added force flag to remove *last* entry as well
1811 * bor 30.10.96: corrected selection bug if last entry was removed
1815 listbox_remove_current (WListbox
*l
, int force
)
1819 /* Ok, note: this won't allow for emtpy lists */
1820 if (!force
&& (!l
->count
|| l
->count
== 1))
1827 l
->current
->next
->prev
= l
->current
->prev
;
1828 l
->current
->prev
->next
= l
->current
->next
;
1829 if (p
->next
== l
->list
) {
1830 l
->current
= p
->prev
;
1834 l
->current
= p
->next
;
1837 l
->list
= l
->top
= p
->next
;
1840 l
->list
= l
->top
= l
->current
= 0;
1847 /* Makes *e the selected entry (sets current and pos) */
1849 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1858 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1866 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1867 l
->top
= l
->top
->next
;
1869 l
->top
= l
->current
;
1875 /* If we are unable to find it, set decent values */
1876 l
->current
= l
->top
= l
->list
;
1880 /* Selects from base the pos element */
1882 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1884 WLEntry
*last
= l
->list
->prev
;
1897 listbox_back (WListbox
*l
)
1900 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1907 listbox_fwd (WListbox
*l
)
1909 if (l
->current
!= l
->list
->prev
){
1910 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
1916 /* Returns 1 if we want a redraw */
1918 listbox_key (WListbox
*l
, int key
)
1929 l
->current
= l
->top
= l
->list
;
1935 l
->current
= l
->top
= l
->list
->prev
;
1936 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1937 l
->top
= l
->top
->prev
;
1938 l
->pos
= l
->count
- 1;
1953 for (i
= 0; i
< l
->height
-1; i
++)
1954 j
|= listbox_fwd (l
);
1959 for (i
= 0; i
< l
->height
-1; i
++)
1960 j
|= listbox_back (l
);
1966 static int listbox_event (Gpm_Event
*event
, WListbox
*l
);
1968 listbox_callback (Dlg_head
*h
, WListbox
*l
, int msg
, int par
)
1971 /* int selected_color; Never used */
1979 if ((e
= listbox_check_hotkey (l
, par
)) != NULL
){
1980 listbox_select_entry (l
, e
);
1982 /* Take the appropriate action */
1983 if (l
->action
== listbox_finish
){
1984 l
->widget
.parent
->running
= 0;
1985 l
->widget
.parent
->ret_value
= B_ENTER
;
1986 } else if (l
->action
== listbox_cback
){
1987 if ((*l
->cback
)(l
) == listbox_finish
){
1988 l
->widget
.parent
->running
= 0;
1989 l
->widget
.parent
->ret_value
= B_ENTER
;
1997 if ((ret_code
= listbox_key (l
, par
)))
1998 listbox_draw (l
, h
, 1);
2002 widget_move (&l
->widget
, l
->cursor_y
, 0);
2006 case WIDGET_UNFOCUS
:
2008 listbox_draw (l
, h
, msg
!= WIDGET_UNFOCUS
);
2011 return default_proc (h
, msg
, par
);
2015 listbox_event (Gpm_Event
*event
, WListbox
*l
)
2019 Dlg_head
*h
= l
->widget
.parent
;
2022 if (event
->type
& GPM_DOWN
)
2023 dlg_select_widget (l
->widget
.parent
, l
);
2026 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2027 if (event
->x
< 0 || event
->x
>= l
->width
)
2030 for (i
= -event
->y
; i
>= 0; i
--)
2032 else if (event
->y
> l
->height
)
2033 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2036 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
,
2039 /* We need to refresh ourselves since the dialog manager doesn't */
2040 /* know about this event */
2041 listbox_callback (h
, l
, WIDGET_DRAW
, 0);
2047 if ((event
->type
& (GPM_DOUBLE
|GPM_UP
)) == (GPM_UP
|GPM_DOUBLE
)){
2048 if (event
->x
< 0 || event
->x
>= l
->width
)
2050 if (event
->y
< 1 || event
->y
> l
->height
)
2053 dlg_select_widget (l
->widget
.parent
, l
);
2054 listbox_select_entry (l
, listbox_select_pos (l
, l
->top
, event
->y
- 1));
2057 case listbox_nothing
:
2060 case listbox_finish
:
2061 h
->ret_value
= B_ENTER
;
2066 if ((*l
->cback
)(l
) == listbox_finish
)
2074 listbox_destroy (WListbox
*l
)
2076 WLEntry
*n
, *p
= l
->list
;
2079 for (i
= 0; i
< l
->count
; i
++){
2088 listbox_new (int y
, int x
, int width
, int height
,
2089 int action
, lcback callback
, char *tkname
)
2091 WListbox
*l
= g_new (WListbox
, 1);
2092 extern int slow_terminal
;
2094 init_widget (&l
->widget
, y
, x
, height
, width
,
2095 (callback_fn
)listbox_callback
,
2096 (destroy_fn
) listbox_destroy
, (mouse_h
)listbox_event
, tkname
);
2098 l
->list
= l
->top
= l
->current
= 0;
2108 l
->cback
= callback
;
2110 l
->allow_duplicates
= 1;
2111 l
->scrollbar
= slow_terminal
? 0 : 1;
2112 widget_want_hotkey (l
->widget
, 1);
2117 /* Listbox item adding function. They still lack a lot of functionality */
2119 /* 1.11.96 bor: added pos argument to control placement of new entry */
2121 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2129 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2131 e
->prev
= l
->list
->prev
;
2132 l
->list
->prev
->next
= e
;
2134 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2135 e
->next
= l
->current
;
2136 e
->prev
= l
->current
->prev
;
2137 l
->current
->prev
->next
= e
;
2138 l
->current
->prev
= e
;
2139 if (l
->list
== l
->current
) { /* move list one position down */
2143 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2144 e
->prev
= l
->current
;
2145 e
->next
= l
->current
->next
;
2146 l
->current
->next
->prev
= e
;
2147 l
->current
->next
= e
;
2153 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
, char *text
,
2161 if (!l
->allow_duplicates
)
2162 if (listbox_search_text (l
, text
))
2165 entry
= g_new (WLEntry
, 1);
2166 entry
->text
= g_strdup (text
);
2168 entry
->hotkey
= hotkey
;
2170 listbox_append_item (l
, entry
, pos
);
2175 /* Selects the nth entry in the listbox */
2177 listbox_select_by_number (WListbox
*l
, int n
)
2179 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2183 listbox_search_text (WListbox
*l
, char *text
)
2192 if(!strcmp (e
->text
, text
))
2195 } while (e
!=l
->list
);
2200 /* Returns the current string text as well as the associated extra data */
2202 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2208 if (string
&& l
->current
)
2209 *string
= l
->current
->text
;
2210 if (extra
&& l
->current
)
2211 *extra
= l
->current
->data
;
2215 buttonbar_callback (Dlg_head
*h
, WButtonBar
*bb
, int msg
, int par
)
2227 for (i
= 0; i
< 10; i
++){
2228 if (par
== KEY_F(i
+1) && bb
->labels
[i
].function
){
2229 (*bb
->labels
[i
].function
)(bb
->labels
[i
].data
);
2238 widget_move (&bb
->widget
, 0, 0);
2239 attrset (DEFAULT_COLOR
);
2240 printw ("%-*s", bb
->widget
.cols
- 1, "");
2241 for (i
= 0; i
< COLS
/8 && i
< 10; i
++){
2242 widget_move (&bb
->widget
, 0, i
*8);
2243 attrset (DEFAULT_COLOR
);
2245 attrset (SELECTED_COLOR
);
2246 printw ("%-*s", ((i
+1) * 8 == COLS
? 5 : 6),
2247 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2248 attrset (DEFAULT_COLOR
);
2250 attrset (SELECTED_COLOR
);
2253 return default_proc (h
, msg
, par
);
2257 buttonbar_destroy (WButtonBar
*bb
)
2261 for (i
= 0; i
< 10; i
++){
2262 if (bb
->labels
[i
].text
)
2263 g_free (bb
->labels
[i
].text
);
2268 buttonbar_event (Gpm_Event
*event
, WButtonBar
*bb
)
2272 if (!(event
->type
& GPM_UP
))
2276 button
= event
->x
/ 8;
2277 if (button
< 10 && bb
->labels
[button
].function
)
2278 (*bb
->labels
[button
].function
)(bb
->labels
[button
].data
);
2283 buttonbar_new (int visible
)
2286 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2288 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2289 (callback_fn
) buttonbar_callback
,
2290 (destroy_fn
) buttonbar_destroy
, (mouse_h
) buttonbar_event
, NULL
);
2292 bb
->visible
= visible
;
2293 for (i
= 0; i
< 10; i
++){
2294 bb
->labels
[i
].text
= 0;
2295 bb
->labels
[i
].function
= 0;
2297 widget_want_hotkey (bb
->widget
, 1);
2298 widget_want_cursor (bb
->widget
, 0);
2304 set_label_text (WButtonBar
*bb
, int index
, char *text
)
2306 if (bb
->labels
[index
-1].text
)
2307 g_free (bb
->labels
[index
-1].text
);
2309 bb
->labels
[index
-1].text
= g_strdup (text
);
2312 /* paneletc is either the panel widget, or info or view or tree widget */
2314 find_buttonbar (Dlg_head
*h
, Widget
*paneletc
)
2321 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
){
2322 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
){
2323 bb
= (WButtonBar
*) item
->widget
;
2331 define_label_data (Dlg_head
*h
, Widget
*paneletc
, int idx
, char *text
,
2332 buttonbarfn cback
, void *data
)
2334 WButtonBar
*bb
= find_buttonbar (h
, paneletc
);
2338 set_label_text (bb
, idx
, text
);
2339 bb
->labels
[idx
-1].function
= cback
;
2340 bb
->labels
[idx
-1].data
= data
;
2344 define_label (Dlg_head
*h
, Widget
*paneletc
, int idx
, char *text
, void (*cback
)(void))
2346 define_label_data (h
, paneletc
, idx
, text
, (buttonbarfn
) cback
, 0);
2350 redraw_labels (Dlg_head
*h
, Widget
*paneletc
)
2355 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
){
2356 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
){
2357 widget_redraw (h
, item
);