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;
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
;
902 history_callback (Dlg_head
* h
, int Par
, int Msg
)
906 attrset (COLOR_NORMAL
);
908 draw_box (h
, 0, 0, h
->lines
, h
->cols
);
909 attrset (COLOR_HOT_NORMAL
);
910 dlg_move (h
, 0, (h
->cols
- strlen (i18n_htitle())) / 2);
911 printw (i18n_htitle());
917 static inline int listbox_fwd (WListbox
*l
);
920 show_hist (Hist
*history
, int widget_x
, int widget_y
)
923 size_t maxlen
= strlen (i18n_htitle()), i
, count
= 0;
927 WListbox
*query_list
;
933 while (z
->prev
) /* goto first */
937 if ((i
= strlen (hi
->text
)) > maxlen
)
945 if (h
<= y
|| y
> LINES
- 6)
953 h
= min(h
, LINES
- y
);
960 if ((w
= maxlen
+ 4) + x
> COLS
)
966 query_dlg
= create_dlg (y
, x
, h
, w
, dialog_colors
, history_callback
,
967 "[History-query]", "history", DLG_NONE
);
968 query_list
= listbox_new (1, 1, w
- 2, h
- 2, listbox_finish
, 0, NULL
);
969 add_widget (query_dlg
, query_list
);
972 while (hi
) { /* traverse */
973 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
976 while (listbox_fwd (query_list
));
980 while (hi
) { /* traverse backwards */
981 listbox_add_item (query_list
, 0, 0, hi
->text
, NULL
);
987 if (query_dlg
->ret_value
!= B_CANCEL
) {
988 listbox_get_current (query_list
, &q
, NULL
);
992 destroy_dlg (query_dlg
);
996 static void do_show_hist (WInput
* in
)
999 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1001 assign_text (in
, r
);
1006 /* }}} history display */
1009 input_destroy (WInput
*in
)
1012 fprintf (stderr
, "Internal error: null Input *\n");
1018 Hist
*current
, *old
;
1020 if (!in
->is_password
) /* don't save passwords ;-) */
1021 history_put (in
->history_name
, in
->history
);
1023 current
= in
->history
;
1024 while (current
->next
)
1025 current
= current
->next
;
1028 current
= current
->prev
;
1033 g_free (in
->buffer
);
1034 free_completions (in
);
1035 if (in
->history_name
)
1036 g_free (in
->history_name
);
1039 static char disable_update
= 0;
1042 input_disable_update (WInput
*in
)
1044 in
->disable_update
++;
1048 input_enable_update (WInput
*in
)
1050 in
->disable_update
--;
1051 update_input (in
, 0);
1054 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1057 push_history (WInput
*in
, char *text
)
1060 /* input widget where urls with passwords are entered without any
1062 static const char *password_input_fields
[] = {
1063 N_(" Link to a remote machine "),
1064 N_(" FTP to machine "),
1065 N_(" SMB link to machine ")
1073 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1074 password_input_fields
[i
] = _(password_input_fields
[i
]);
1077 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1081 while (in
->history
->next
)
1082 in
->history
= in
->history
->next
;
1083 if (!strcmp (in
->history
->text
, text
))
1085 new = g_new (Hist
, 1);
1086 in
->history
->next
= new;
1088 new = g_new (Hist
, 1);
1091 new->prev
= in
->history
;
1092 new->text
= g_strdup (text
);
1093 if (in
->history_name
) {
1094 p
= in
->history_name
+ 3;
1095 for (i
= 0; i
< ELEMENTS(password_input_fields
); i
++)
1096 if (strcmp (p
, password_input_fields
[i
]) == 0)
1098 if (i
< ELEMENTS(password_input_fields
))
1099 strip_password (new->text
, 0);
1101 strip_password (new->text
, 1);
1110 /* Cleans the input line and adds the current text to the history */
1112 new_input (WInput
*in
)
1115 push_history (in
, in
->buffer
);
1120 free_completions (in
);
1121 update_input (in
, 0);
1125 insert_char (WInput
*in
, int c_code
)
1133 if (strlen (in
->buffer
)+1 == in
->current_max_len
){
1134 /* Expand the buffer */
1135 char *narea
= g_malloc (in
->current_max_len
+ in
->field_len
);
1137 char *p
= in
->buffer
;
1139 strcpy (narea
, in
->buffer
);
1141 in
->current_max_len
+= in
->field_len
;
1145 if (strlen (in
->buffer
)+1 < in
->current_max_len
){
1146 int l
= strlen (&in
->buffer
[in
->point
]);
1147 for (i
= l
+1; i
> 0; i
--)
1148 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1149 in
->buffer
[in
->point
] = c_code
;
1156 beginning_of_line (WInput
*in
)
1162 end_of_line (WInput
*in
)
1164 in
->point
= strlen (in
->buffer
);
1168 backward_char (WInput
*in
)
1175 forward_char (WInput
*in
)
1177 if (in
->buffer
[in
->point
])
1182 forward_word (WInput
*in
)
1184 unsigned char *p
= in
->buffer
+in
->point
;
1186 while (*p
&& (isspace (*p
) || ispunct (*p
)))
1188 while (*p
&& isalnum (*p
))
1190 in
->point
= p
- in
->buffer
;
1194 backward_word (WInput
*in
)
1196 unsigned char *p
= in
->buffer
+in
->point
;
1198 while (p
-1 > in
->buffer
-1 && (isspace (*(p
-1)) || ispunct (*(p
-1))))
1200 while (p
-1 > in
->buffer
-1 && isalnum (*(p
-1)))
1202 in
->point
= p
- in
->buffer
;
1206 key_left (WInput
*in
)
1208 if (ctrl_pressed ())
1215 key_right (WInput
*in
)
1217 if (ctrl_pressed ())
1224 backward_delete (WInput
*in
)
1230 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1231 in
->buffer
[i
-1] = in
->buffer
[i
];
1237 delete_char (WInput
*in
)
1241 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1242 in
->buffer
[i
] = in
->buffer
[i
+1];
1247 copy_region (WInput
*in
, int x_first
, int x_last
)
1249 int first
= min (x_first
, x_last
);
1250 int last
= max (x_first
, x_last
);
1256 g_free (kill_buffer
);
1258 kill_buffer
= g_malloc (last
-first
+ 1);
1259 strncpy (kill_buffer
, in
->buffer
+first
, last
-first
);
1260 kill_buffer
[last
-first
] = 0;
1264 delete_region (WInput
*in
, int x_first
, int x_last
)
1266 int first
= min (x_first
, x_last
);
1267 int last
= max (x_first
, x_last
);
1271 strcpy (&in
->buffer
[first
], &in
->buffer
[last
]);
1276 kill_word (WInput
*in
)
1278 int old_point
= in
->point
;
1282 new_point
= in
->point
;
1283 in
->point
= old_point
;
1285 copy_region (in
, old_point
, new_point
);
1286 delete_region (in
, old_point
, new_point
);
1291 back_kill_word (WInput
*in
)
1293 int old_point
= in
->point
;
1297 new_point
= in
->point
;
1298 in
->point
= old_point
;
1300 copy_region (in
, old_point
, new_point
);
1301 delete_region (in
, old_point
, new_point
);
1306 set_mark (WInput
*in
)
1308 in
->mark
= in
->point
;
1312 kill_save (WInput
*in
)
1314 copy_region (in
, in
->mark
, in
->point
);
1318 kill_region (WInput
*in
)
1321 delete_region (in
, in
->point
, in
->mark
);
1331 for (p
= kill_buffer
; *p
; p
++)
1332 insert_char (in
, *p
);
1336 kill_line (WInput
*in
)
1339 g_free (kill_buffer
);
1340 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1341 in
->buffer
[in
->point
] = 0;
1345 assign_text (WInput
*in
, char *text
)
1347 free_completions (in
);
1348 g_free (in
->buffer
);
1349 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1350 in
->current_max_len
= strlen (in
->buffer
) + 1;
1351 in
->point
= strlen (in
->buffer
);
1357 hist_prev (WInput
*in
)
1362 if (in
->need_push
) {
1363 switch (push_history (in
, in
->buffer
)) {
1364 case 2: in
->history
= in
->history
->prev
; break;
1365 case 1: if (in
->history
->prev
) in
->history
= in
->history
->prev
; break;
1368 } else if (in
->history
->prev
)
1369 in
->history
= in
->history
->prev
;
1372 assign_text (in
, in
->history
->text
);
1377 hist_next (WInput
*in
)
1379 if (in
->need_push
) {
1380 switch (push_history (in
, in
->buffer
)) {
1382 assign_text (in
, "");
1392 if (!in
->history
->next
) {
1393 assign_text (in
, "");
1397 in
->history
= in
->history
->next
;
1398 assign_text (in
, in
->history
->text
);
1402 static const struct {
1404 void (*fn
)(WInput
*in
);
1407 { XCTRL('a'), beginning_of_line
},
1408 { KEY_HOME
, beginning_of_line
},
1409 { KEY_A1
, beginning_of_line
},
1410 { XCTRL('e'), end_of_line
},
1411 { KEY_END
, end_of_line
},
1412 { KEY_C1
, end_of_line
},
1413 { KEY_LEFT
, key_left
},
1414 { XCTRL('b'), backward_char
},
1415 { ALT('b'), backward_word
},
1416 { KEY_RIGHT
, key_right
},
1417 { XCTRL('f'), forward_char
},
1418 { ALT('f'), forward_word
},
1421 { 0177, backward_delete
},
1422 { KEY_BACKSPACE
, backward_delete
},
1423 { XCTRL('h'), backward_delete
},
1424 { KEY_DC
, delete_char
},
1425 { XCTRL('d'), delete_char
},
1426 { ALT('d'), kill_word
},
1427 { ALT(KEY_BACKSPACE
), back_kill_word
},
1428 { ALT(XCTRL('h')), back_kill_word
},
1429 { ALT(127), back_kill_word
},
1431 /* Region manipulation */
1433 { XCTRL('w'), kill_region
},
1434 { ALT('w'), kill_save
},
1435 { XCTRL('y'), yank
},
1436 { XCTRL('k'), kill_line
},
1439 { ALT('p'), hist_prev
},
1440 { ALT('n'), hist_next
},
1441 { ALT('h'), do_show_hist
},
1444 { ALT('\t'), complete
},
1449 /* This function is a test for a special input key used in complete.c */
1450 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1451 and 2 if it is a complete key */
1453 is_in_input_map (WInput
*in
, int c_code
)
1457 for (i
= 0; input_map
[i
].fn
; i
++)
1458 if (c_code
== input_map
[i
].key_code
) {
1459 if (input_map
[i
].fn
== complete
)
1468 port_region_marked_for_delete (WInput
*in
)
1476 handle_char (WInput
*in
, int c_code
)
1484 free_completions (in
);
1485 v
= insert_char (in
, c_code
);
1486 update_input (in
, 1);
1491 for (i
= 0; input_map
[i
].fn
; i
++){
1492 if (c_code
== input_map
[i
].key_code
){
1493 if (input_map
[i
].fn
!= complete
)
1494 free_completions (in
);
1495 (*input_map
[i
].fn
)(in
);
1500 if (!input_map
[i
].fn
){
1501 if (c_code
> 255 || !is_printable (c_code
))
1504 port_region_marked_for_delete (in
);
1506 free_completions (in
);
1507 v
= insert_char (in
, c_code
);
1508 in
->inserted_one
= c_code
;
1510 if (!disable_update
)
1511 update_input (in
, 1);
1515 /* Inserts text in input line */
1517 stuff (WInput
*in
, char *text
, int insert_extra_space
)
1519 input_disable_update (in
);
1521 handle_char (in
, *text
++);
1522 if (insert_extra_space
)
1523 handle_char (in
, ' ');
1524 input_enable_update (in
);
1525 update_input (in
, 1);
1529 input_set_point (WInput
*in
, int pos
)
1531 if (pos
> in
->current_max_len
)
1532 pos
= in
->current_max_len
;
1533 if (pos
!= in
->point
)
1534 free_completions (in
);
1536 update_input (in
, 1);
1540 input_callback (Dlg_head
*h
, WInput
*in
, int Msg
, int Par
)
1547 if (Par
== XCTRL('q')){
1551 v
= handle_char (in
, mi_getch ());
1555 if (Par
== KEY_UP
|| Par
== KEY_DOWN
||
1556 Par
== ESC_CHAR
|| Par
== KEY_F(10) ||
1558 return 0; /* We don't handle up/down */
1564 return handle_char (in
, Par
);
1567 case WIDGET_UNFOCUS
:
1569 update_input (in
, 0);
1572 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1576 return default_proc (h
, Msg
, Par
);
1580 input_event (Gpm_Event
* event
, WInput
* in
)
1582 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1583 dlg_select_widget (in
->widget
.parent
, in
);
1585 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1586 && 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
, "");
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
,
2345 void (*cback
) (void))
2347 define_label_data (h
, paneletc
, idx
, text
, (buttonbarfn
) cback
, 0);
2351 redraw_labels (Dlg_head
*h
, Widget
*paneletc
)
2356 for (i
= 0, item
= h
->current
; i
< h
->count
; i
++, item
= item
->next
){
2357 if (item
->widget
->callback
== (callback_fn
) buttonbar_callback
){
2358 widget_redraw (h
, item
);