1 /* Widgets for the Midnight Commander
3 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
6 Authors: 1994, 1995 Radek Doulik
7 1994, 1995 Miguel de Icaza
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
35 #include <sys/types.h>
44 #include "key.h" /* XCTRL and ALT macros */
45 #include "profile.h" /* for history loading and saving */
46 #include "wtools.h" /* For common_dialog_repaint() */
47 #include "main.h" /* for `slow_terminal' */
49 #define HISTORY_FILE_NAME ".mc/history"
53 int visible
; /* Is it visible? */
56 enum { BBFUNC_NONE
, BBFUNC_VOID
, BBFUNC_PTR
} tag
;
65 static int button_event (Gpm_Event
*event
, void *);
70 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
72 Dlg_head
*h
= w
->parent
;
77 : DLG_HOT_NORMALC (h
))
84 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
86 WButton
*b
= (WButton
*) w
;
90 Dlg_head
*h
= b
->widget
.parent
;
95 * Don't let the default button steal Enter from the current
96 * button. This is a workaround for the flawed event model
97 * when hotkeys are sent to all widgets before the key is
98 * handled by the current widget.
100 if (parm
== '\n' && h
->current
== &b
->widget
) {
101 button_callback (w
, WIDGET_KEY
, ' ');
105 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
106 button_callback (w
, WIDGET_KEY
, ' ');
110 if (b
->hotkey
== tolower (parm
)) {
111 button_callback (w
, WIDGET_KEY
, ' ');
115 return MSG_NOT_HANDLED
;
118 if (parm
!= ' ' && parm
!= '\n')
119 return MSG_NOT_HANDLED
;
122 stop
= (*b
->callback
) (b
->action
);
123 if (!b
->callback
|| stop
) {
124 h
->ret_value
= b
->action
;
145 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
151 if (msg
== WIDGET_UNFOCUS
)
153 else if (msg
== WIDGET_FOCUS
)
158 g_snprintf (buf
, sizeof (buf
), "[< %s >]", b
->text
);
162 g_snprintf (buf
, sizeof (buf
), "[ %s ]", b
->text
);
166 g_snprintf (buf
, sizeof (buf
), "[%s]", b
->text
);
176 widget_selectcolor (w
, b
->selected
, FALSE
);
177 widget_move (w
, 0, 0);
181 if (b
->hotpos
>= 0) {
182 widget_selectcolor (w
, b
->selected
, TRUE
);
183 widget_move (w
, 0, b
->hotpos
+ off
);
184 addch ((unsigned char) b
->text
[b
->hotpos
]);
193 return default_proc (msg
, parm
);
198 button_event (Gpm_Event
*event
, void *data
)
202 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
203 Dlg_head
*h
=b
->widget
.parent
;
204 dlg_select_widget (b
);
205 if (event
->type
& GPM_UP
){
206 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
207 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
215 button_len (const char *text
, unsigned int flags
)
217 int ret
= strlen (text
);
236 * Locate the hotkey and remove it from the button text. Assuming that
237 * the button text is g_malloc()ed, we can safely change and shorten it.
240 button_scan_hotkey (WButton
*b
)
242 char *cp
= strchr (b
->text
, '&');
244 if (cp
!= NULL
&& cp
[1] != '\0') {
245 g_strlcpy (cp
, cp
+ 1, strlen (cp
));
246 b
->hotkey
= tolower ((unsigned char) *cp
);
247 b
->hotpos
= cp
- b
->text
;
252 button_new (int y
, int x
, int action
, int flags
, const char *text
,
255 WButton
*b
= g_new (WButton
, 1);
257 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
258 button_callback
, button_event
);
263 b
->text
= g_strdup (text
);
264 b
->callback
= callback
;
265 widget_want_hotkey (b
->widget
, 1);
269 button_scan_hotkey(b
);
274 button_get_text (WButton
*b
)
280 button_set_text (WButton
*b
, const char *text
)
283 b
->text
= g_strdup (text
);
284 b
->widget
.cols
= button_len (text
, b
->flags
);
285 button_scan_hotkey(b
);
286 dlg_redraw (b
->widget
.parent
);
290 /* Radio button widget */
291 static int radio_event (Gpm_Event
*event
, void *);
294 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
296 WRadio
*r
= (WRadio
*) w
;
298 Dlg_head
*h
= r
->widget
.parent
;
303 int i
, lp
= tolower (parm
);
306 for (i
= 0; i
< r
->count
; i
++) {
307 cp
= strchr (r
->texts
[i
], '&');
308 if (cp
!= NULL
&& cp
[1] != '\0') {
309 int c
= tolower ((unsigned char) cp
[1]);
316 radio_callback (w
, WIDGET_KEY
, ' ');
321 return MSG_NOT_HANDLED
;
327 (*h
->callback
) (h
, DLG_ACTION
, 0);
328 radio_callback (w
, WIDGET_FOCUS
, ' ');
337 return MSG_NOT_HANDLED
;
341 if (r
->count
- 1 > r
->pos
) {
346 return MSG_NOT_HANDLED
;
349 (*h
->callback
) (h
, DLG_ACTION
, 0);
350 radio_callback (w
, WIDGET_FOCUS
, ' ');
351 widget_move (&r
->widget
, r
->pos
, 1);
357 for (i
= 0; i
< r
->count
; i
++) {
358 register const char *cp
;
359 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
360 widget_selectcolor (w
, focused
, FALSE
);
361 widget_move (&r
->widget
, i
, 0);
363 tty_printf ("(%c) ", (r
->sel
== i
) ? '*' : ' ');
364 for (cp
= r
->texts
[i
]; *cp
; cp
++) {
366 widget_selectcolor (w
, focused
, TRUE
);
368 widget_selectcolor (w
, focused
, FALSE
);
376 return default_proc (msg
, parm
);
381 radio_event (Gpm_Event
*event
, void *data
)
386 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
387 Dlg_head
*h
= r
->widget
.parent
;
389 r
->pos
= event
->y
- 1;
390 dlg_select_widget (r
);
391 if (event
->type
& GPM_UP
){
392 radio_callback (w
, WIDGET_KEY
, ' ');
393 radio_callback (w
, WIDGET_FOCUS
, 0);
394 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
402 radio_new (int y
, int x
, int count
, const char **texts
)
404 WRadio
*r
= g_new (WRadio
, 1);
407 /* Compute the longest string */
409 for (i
= 0; i
< count
; i
++){
410 m
= strlen (texts
[i
]);
415 init_widget (&r
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
421 widget_want_hotkey (r
->widget
, 1);
427 /* Checkbutton widget */
429 static int check_event (Gpm_Event
*event
, void *);
432 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
434 WCheck
*c
= (WCheck
*) w
;
435 Dlg_head
*h
= c
->widget
.parent
;
439 if (c
->hotkey
== parm
440 || (c
->hotkey
>= 'a' && c
->hotkey
<= 'z'
441 && c
->hotkey
- 32 == parm
)) {
442 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
445 return MSG_NOT_HANDLED
;
449 return MSG_NOT_HANDLED
;
451 c
->state
^= C_CHANGE
;
452 (*h
->callback
) (h
, DLG_ACTION
, 0);
453 check_callback (w
, WIDGET_FOCUS
, ' ');
457 widget_move (&c
->widget
, 0, 1);
463 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
464 widget_move (&c
->widget
, 0, 0);
465 tty_printf ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
467 if (c
->hotpos
>= 0) {
468 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, TRUE
);
469 widget_move (&c
->widget
, 0, +c
->hotpos
+ 4);
470 addch ((unsigned char) c
->text
[c
->hotpos
]);
479 return default_proc (msg
, parm
);
484 check_event (Gpm_Event
*event
, void *data
)
489 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
490 Dlg_head
*h
= c
->widget
.parent
;
492 dlg_select_widget (c
);
493 if (event
->type
& GPM_UP
){
494 check_callback (w
, WIDGET_KEY
, ' ');
495 check_callback (w
, WIDGET_FOCUS
, 0);
496 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
504 check_new (int y
, int x
, int state
, const char *text
)
506 WCheck
*c
= g_new (WCheck
, 1);
510 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
511 check_callback
, check_event
);
512 c
->state
= state
? C_BOOL
: 0;
513 c
->text
= g_strdup (text
);
516 widget_want_hotkey (c
->widget
, 1);
518 /* Scan for the hotkey */
519 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
526 c
->hotkey
= tolower ((unsigned char) *s
);
527 c
->hotpos
= t
- c
->text
;
539 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
541 WLabel
*l
= (WLabel
*) w
;
542 Dlg_head
*h
= l
->widget
.parent
;
548 /* We don't want to get the focus */
550 return MSG_NOT_HANDLED
;
554 char *p
= l
->text
, *q
, c
= 0;
561 attrset (DEFAULT_COLOR
);
563 attrset (DLG_NORMALC (h
));
567 q
= strchr (p
, '\n');
572 widget_move (&l
->widget
, y
, 0);
573 tty_printf ("%s", p
);
574 xlen
= l
->widget
.cols
- strlen (p
);
576 tty_printf ("%*s", xlen
, " ");
591 return default_proc (msg
, parm
);
596 label_set_text (WLabel
*label
, const char *text
)
598 int newcols
= label
->widget
.cols
;
600 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
601 return; /* Flickering is not nice */
603 g_free (label
->text
);
606 label
->text
= g_strdup (text
);
607 if (label
->auto_adjust_cols
) {
608 newcols
= strlen (text
);
609 if (newcols
> label
->widget
.cols
)
610 label
->widget
.cols
= newcols
;
615 if (label
->widget
.parent
)
616 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
618 if (newcols
< label
->widget
.cols
)
619 label
->widget
.cols
= newcols
;
623 label_new (int y
, int x
, const char *text
)
628 /* Multiline labels are immutable - no need to compute their sizes */
629 if (!text
|| strchr(text
, '\n'))
632 width
= strlen (text
);
634 l
= g_new (WLabel
, 1);
635 init_widget (&l
->widget
, y
, x
, 1, width
, label_callback
, NULL
);
636 l
->text
= text
? g_strdup (text
) : 0;
637 l
->auto_adjust_cols
= 1;
639 widget_want_cursor (l
->widget
, 0);
644 /* Gauge widget (progress indicator) */
645 /* Currently width is hardcoded here for text mode */
649 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
651 WGauge
*g
= (WGauge
*) w
;
652 Dlg_head
*h
= g
->widget
.parent
;
654 if (msg
== WIDGET_INIT
)
657 /* We don't want to get the focus */
658 if (msg
== WIDGET_FOCUS
)
659 return MSG_NOT_HANDLED
;
661 if (msg
== WIDGET_DRAW
){
662 widget_move (&g
->widget
, 0, 0);
663 attrset (DLG_NORMALC (h
));
665 tty_printf ("%*s", gauge_len
, "");
667 int percentage
, columns
;
668 long total
= g
->max
, done
= g
->current
;
670 if (total
<= 0 || done
< 0) {
676 while (total
> 65535) {
680 percentage
= (200 * done
/ total
+ 1) / 2;
681 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
683 attrset (GAUGE_COLOR
);
684 tty_printf ("%*s", (int) columns
, "");
685 attrset (DLG_NORMALC (h
));
686 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
690 return default_proc (msg
, parm
);
694 gauge_set_value (WGauge
*g
, int max
, int current
)
696 if (g
->current
== current
&& g
->max
== max
)
697 return; /* Do not flicker */
699 max
= 1; /* I do not like division by zero :) */
701 g
->current
= current
;
703 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
707 gauge_show (WGauge
*g
, int shown
)
709 if (g
->shown
== shown
)
712 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
716 gauge_new (int y
, int x
, int shown
, int max
, int current
)
718 WGauge
*g
= g_new (WGauge
, 1);
720 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
723 max
= 1; /* I do not like division by zero :) */
725 g
->current
= current
;
726 widget_want_cursor (g
->widget
, 0);
733 /* {{{ history button */
735 #define LARGE_HISTORY_BUTTON 1
737 #ifdef LARGE_HISTORY_BUTTON
738 # define HISTORY_BUTTON_WIDTH 3
740 # define HISTORY_BUTTON_WIDTH 1
743 #define should_show_history_button(in) \
744 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
746 static void draw_history_button (WInput
* in
)
749 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
750 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
751 #ifdef LARGE_HISTORY_BUTTON
754 h
= in
->widget
.parent
;
756 attrset (NORMALC
); /* button has the same color as other buttons */
758 attrset (HOT_NORMALC
);
760 attrset (NORMAL_COLOR
);
762 /* Too distracting: attrset (MARKED_COLOR); */
764 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
768 attrset (MARKED_COLOR
);
773 /* }}} history button */
776 /* Input widgets now have a global kill ring */
777 /* Pointer to killed data */
778 static char *kill_buffer
= 0;
781 update_input (WInput
*in
, int clear_first
)
786 int buf_len
= strlen (in
->buffer
);
788 if (should_show_history_button (in
))
789 has_history
= HISTORY_BUTTON_WIDTH
;
791 if (in
->disable_update
)
794 /* Make the point visible */
795 if ((in
->point
< in
->first_shown
) ||
796 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
797 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
798 if (in
->first_shown
< 0)
802 /* Adjust the mark */
803 if (in
->mark
> buf_len
)
807 draw_history_button (in
);
811 widget_move (&in
->widget
, 0, 0);
812 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
814 widget_move (&in
->widget
, 0, 0);
816 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
817 c
= in
->buffer
[j
++];
818 c
= is_printable (c
) ? c
: '.';
823 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
830 winput_set_origin (WInput
*in
, int x
, int field_len
)
833 in
->field_len
= in
->widget
.cols
= field_len
;
834 update_input (in
, 0);
837 /* {{{ history saving and loading */
839 int num_history_items_recorded
= 60;
842 This loads and saves the history of an input line to and from the
843 widget. It is called with the widgets history name on creation of the
844 widget, and returns the GList list. It stores histories in the file
845 ~/.mc/history in using the profile code.
847 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
848 function) then input_new assigns the default text to be the last text
849 entered, or "" if not found.
853 history_get (const char *input_name
)
861 if (!num_history_items_recorded
) /* this is how to disable */
867 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
869 char key_name
[BUF_TINY
];
870 char this_entry
[BUF_LARGE
];
871 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
872 GetPrivateProfileString (input_name
, key_name
, "", this_entry
,
873 sizeof (this_entry
), profile
);
877 hist
= list_append_unique (hist
, g_strdup (this_entry
));
881 /* return pointer to the last entry in the list */
882 hist
= g_list_last (hist
);
888 history_put (const char *input_name
, GList
*h
)
902 if (!num_history_items_recorded
) /* this is how to disable */
905 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
907 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
910 /* Make sure the history is only readable by the user */
911 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
916 /* go to end of list */
919 /* go back 60 places */
920 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
921 h
= g_list_previous (h
);
924 profile_clean_section (input_name
, profile
);
926 /* dump histories into profile */
927 for (i
= 0; h
; h
= g_list_next (h
)) {
930 text
= (char *) h
->data
;
932 /* We shouldn't have null entries, but let's be sure */
934 char key_name
[BUF_TINY
];
935 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
936 WritePrivateProfileString (input_name
, key_name
, text
,
944 /* }}} history saving and loading */
947 /* {{{ history display */
952 static const char *history_title
= NULL
;
954 if (history_title
== NULL
)
955 history_title
= _(" History ");
956 return history_title
;
959 static WLEntry
*listbox_select_pos (WListbox
*l
, WLEntry
*base
, int
962 static inline cb_ret_t
963 listbox_fwd (WListbox
*l
)
965 if (l
->current
!= l
->list
->prev
){
966 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
969 return MSG_NOT_HANDLED
;
973 show_hist (GList
*history
, int widget_x
, int widget_y
)
976 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
980 WListbox
*query_list
;
986 z
= g_list_first (history
);
989 if ((i
= strlen ((char *) hi
->data
)) > maxlen
)
992 hi
= g_list_next (hi
);
997 if (h
<= y
|| y
> LINES
- 6) {
1002 h
= min (h
, LINES
- y
);
1009 if ((w
= maxlen
+ 4) + x
> COLS
) {
1015 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
1016 i18n_htitle (), DLG_COMPACT
);
1017 query_list
= listbox_new (1, 1, w
- 2, h
- 2, 0);
1018 add_widget (query_dlg
, query_list
);
1023 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1024 hi
= g_list_next (hi
);
1026 while (listbox_fwd (query_list
));
1028 /* traverse backwards */
1029 hi
= g_list_last (history
);
1031 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1032 hi
= g_list_previous (hi
);
1035 run_dlg (query_dlg
);
1037 if (query_dlg
->ret_value
!= B_CANCEL
) {
1038 listbox_get_current (query_list
, &q
, NULL
);
1042 destroy_dlg (query_dlg
);
1046 static void do_show_hist (WInput
* in
)
1049 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1051 assign_text (in
, r
);
1056 /* }}} history display */
1059 input_destroy (WInput
*in
)
1062 fprintf (stderr
, "Internal error: null Input *\n");
1069 if (!in
->is_password
) /* don't save passwords ;-) */
1070 history_put (in
->history_name
, in
->history
);
1072 in
->history
= g_list_first (in
->history
);
1073 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1074 g_list_free (in
->history
);
1077 g_free (in
->buffer
);
1078 free_completions (in
);
1079 g_free (in
->history_name
);
1083 input_disable_update (WInput
*in
)
1085 in
->disable_update
++;
1089 input_enable_update (WInput
*in
)
1091 in
->disable_update
--;
1092 update_input (in
, 0);
1095 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1098 push_history (WInput
*in
, const char *text
)
1101 /* input widget where urls with passwords are entered without any
1103 static const char *password_input_fields
[] = {
1104 N_(" Link to a remote machine "),
1105 N_(" FTP to machine "),
1106 N_(" SMB link to machine ")
1114 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1115 password_input_fields
[i
] = _(password_input_fields
[i
]);
1118 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1123 /* Avoid duplicated entries */
1124 in
->history
= g_list_last (in
->history
);
1125 if (!strcmp ((char *) in
->history
->data
, text
))
1129 t
= g_strdup (text
);
1131 if (in
->history_name
) {
1132 p
= in
->history_name
+ 3;
1133 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1134 if (strcmp (p
, password_input_fields
[i
]) == 0)
1136 if (i
< ELEMENTS (password_input_fields
))
1137 strip_password (t
, 0);
1139 strip_password (t
, 1);
1142 in
->history
= list_append_unique (in
->history
, t
);
1150 /* Cleans the input line and adds the current text to the history */
1152 new_input (WInput
*in
)
1155 push_history (in
, in
->buffer
);
1160 free_completions (in
);
1161 update_input (in
, 0);
1165 insert_char (WInput
*in
, int c_code
)
1170 return MSG_NOT_HANDLED
;
1173 if (strlen (in
->buffer
)+1 == (size_t) in
->current_max_len
){
1174 /* Expand the buffer */
1175 char *narea
= g_realloc (in
->buffer
, in
->current_max_len
+ in
->field_len
);
1178 in
->current_max_len
+= in
->field_len
;
1181 if (strlen (in
->buffer
)+1 < (size_t) in
->current_max_len
){
1182 size_t l
= strlen (&in
->buffer
[in
->point
]);
1183 for (i
= l
+1; i
> 0; i
--)
1184 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1185 in
->buffer
[in
->point
] = c_code
;
1192 beginning_of_line (WInput
*in
)
1198 end_of_line (WInput
*in
)
1200 in
->point
= strlen (in
->buffer
);
1204 backward_char (WInput
*in
)
1211 forward_char (WInput
*in
)
1213 if (in
->buffer
[in
->point
])
1218 forward_word (WInput
* in
)
1220 char *p
= in
->buffer
+ in
->point
;
1223 && (isspace ((unsigned char) *p
)
1224 || ispunct ((unsigned char) *p
)))
1226 while (*p
&& isalnum ((unsigned char) *p
))
1228 in
->point
= p
- in
->buffer
;
1232 backward_word (WInput
*in
)
1234 char *p
= in
->buffer
+ in
->point
;
1236 while (p
- 1 > in
->buffer
- 1 && (isspace ((unsigned char) *(p
- 1))
1237 || ispunct ((unsigned char)
1240 while (p
- 1 > in
->buffer
- 1 && isalnum ((unsigned char) *(p
- 1)))
1242 in
->point
= p
- in
->buffer
;
1246 key_left (WInput
*in
)
1252 key_ctrl_left (WInput
*in
)
1258 key_right (WInput
*in
)
1264 key_ctrl_right (WInput
*in
)
1269 backward_delete (WInput
*in
)
1275 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1276 in
->buffer
[i
-1] = in
->buffer
[i
];
1282 delete_char (WInput
*in
)
1286 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1287 in
->buffer
[i
] = in
->buffer
[i
+1];
1292 copy_region (WInput
*in
, int x_first
, int x_last
)
1294 int first
= min (x_first
, x_last
);
1295 int last
= max (x_first
, x_last
);
1300 g_free (kill_buffer
);
1302 kill_buffer
= g_strndup(in
->buffer
+first
,last
-first
);
1306 delete_region (WInput
*in
, int x_first
, int x_last
)
1308 int first
= min (x_first
, x_last
);
1309 int last
= max (x_first
, x_last
);
1310 size_t len
= strlen (&in
->buffer
[last
]) + 1;
1314 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1319 kill_word (WInput
*in
)
1321 int old_point
= in
->point
;
1325 new_point
= in
->point
;
1326 in
->point
= old_point
;
1328 copy_region (in
, old_point
, new_point
);
1329 delete_region (in
, old_point
, new_point
);
1334 back_kill_word (WInput
*in
)
1336 int old_point
= in
->point
;
1340 new_point
= in
->point
;
1341 in
->point
= old_point
;
1343 copy_region (in
, old_point
, new_point
);
1344 delete_region (in
, old_point
, new_point
);
1349 set_mark (WInput
*in
)
1351 in
->mark
= in
->point
;
1355 kill_save (WInput
*in
)
1357 copy_region (in
, in
->mark
, in
->point
);
1361 kill_region (WInput
*in
)
1364 delete_region (in
, in
->point
, in
->mark
);
1374 for (p
= kill_buffer
; *p
; p
++)
1375 insert_char (in
, *p
);
1379 kill_line (WInput
*in
)
1381 g_free (kill_buffer
);
1382 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1383 in
->buffer
[in
->point
] = 0;
1387 assign_text (WInput
*in
, const char *text
)
1389 free_completions (in
);
1390 g_free (in
->buffer
);
1391 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1392 in
->current_max_len
= strlen (in
->buffer
) + 1;
1393 in
->point
= strlen (in
->buffer
);
1399 hist_prev (WInput
*in
)
1404 if (in
->need_push
) {
1405 switch (push_history (in
, in
->buffer
)) {
1407 in
->history
= g_list_previous (in
->history
);
1410 if (in
->history
->prev
)
1411 in
->history
= g_list_previous (in
->history
);
1416 } else if (in
->history
->prev
)
1417 in
->history
= g_list_previous (in
->history
);
1420 assign_text (in
, (char *) in
->history
->data
);
1425 hist_next (WInput
*in
)
1427 if (in
->need_push
) {
1428 switch (push_history (in
, in
->buffer
)) {
1430 assign_text (in
, "");
1440 if (!in
->history
->next
) {
1441 assign_text (in
, "");
1445 in
->history
= g_list_next (in
->history
);
1446 assign_text (in
, (char *) in
->history
->data
);
1450 static const struct {
1452 void (*fn
)(WInput
*in
);
1455 { XCTRL('a'), beginning_of_line
},
1456 { KEY_HOME
, beginning_of_line
},
1457 { KEY_A1
, beginning_of_line
},
1458 { ALT ('<'), beginning_of_line
},
1459 { XCTRL('e'), end_of_line
},
1460 { KEY_END
, end_of_line
},
1461 { KEY_C1
, end_of_line
},
1462 { ALT ('>'), end_of_line
},
1463 { KEY_LEFT
, key_left
},
1464 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1465 { XCTRL('b'), backward_char
},
1466 { ALT('b'), backward_word
},
1467 { KEY_RIGHT
, key_right
},
1468 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1469 { XCTRL('f'), forward_char
},
1470 { ALT('f'), forward_word
},
1473 { KEY_BACKSPACE
, backward_delete
},
1474 { KEY_DC
, delete_char
},
1475 { ALT('d'), kill_word
},
1476 { ALT(KEY_BACKSPACE
), back_kill_word
},
1478 /* Region manipulation */
1480 { XCTRL('w'), kill_region
},
1481 { ALT('w'), kill_save
},
1482 { XCTRL('y'), yank
},
1483 { XCTRL('k'), kill_line
},
1486 { ALT('p'), hist_prev
},
1487 { ALT('n'), hist_next
},
1488 { ALT('h'), do_show_hist
},
1491 { ALT('\t'), complete
},
1496 /* This function is a test for a special input key used in complete.c */
1497 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1498 and 2 if it is a complete key */
1500 is_in_input_map (WInput
*in
, int c_code
)
1506 for (i
= 0; input_map
[i
].fn
; i
++)
1507 if (c_code
== input_map
[i
].key_code
) {
1508 if (input_map
[i
].fn
== complete
)
1517 port_region_marked_for_delete (WInput
*in
)
1525 handle_char (WInput
*in
, int c_code
)
1530 v
= MSG_NOT_HANDLED
;
1533 free_completions (in
);
1534 v
= insert_char (in
, c_code
);
1535 update_input (in
, 1);
1540 for (i
= 0; input_map
[i
].fn
; i
++){
1541 if (c_code
== input_map
[i
].key_code
){
1542 if (input_map
[i
].fn
!= complete
)
1543 free_completions (in
);
1544 (*input_map
[i
].fn
)(in
);
1549 if (!input_map
[i
].fn
){
1550 if (c_code
> 255 || !is_printable (c_code
))
1551 return MSG_NOT_HANDLED
;
1553 port_region_marked_for_delete (in
);
1555 free_completions (in
);
1556 v
= insert_char (in
, c_code
);
1558 update_input (in
, 1);
1562 /* Inserts text in input line */
1564 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1566 input_disable_update (in
);
1568 handle_char (in
, *text
++);
1569 if (insert_extra_space
)
1570 handle_char (in
, ' ');
1571 input_enable_update (in
);
1572 update_input (in
, 1);
1576 input_set_point (WInput
*in
, int pos
)
1578 if (pos
> in
->current_max_len
)
1579 pos
= in
->current_max_len
;
1580 if (pos
!= in
->point
)
1581 free_completions (in
);
1583 update_input (in
, 1);
1587 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1589 WInput
*in
= (WInput
*) w
;
1594 if (parm
== XCTRL ('q')) {
1596 v
= handle_char (in
, ascii_alpha_to_cntrl (mi_getch ()));
1601 /* Keys we want others to handle */
1602 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1603 || parm
== KEY_F (10) || parm
== XCTRL ('g') || parm
== '\n')
1604 return MSG_NOT_HANDLED
;
1606 /* When pasting multiline text, insert literal Enter */
1607 if ((parm
& ~KEY_M_MASK
) == '\n') {
1609 v
= handle_char (in
, '\n');
1614 return handle_char (in
, parm
);
1617 case WIDGET_UNFOCUS
:
1619 update_input (in
, 0);
1623 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1626 case WIDGET_DESTROY
:
1631 return default_proc (msg
, parm
);
1636 input_event (Gpm_Event
* event
, void *data
)
1640 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1641 dlg_select_widget (in
);
1643 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1644 && should_show_history_button (in
)) {
1647 in
->point
= strlen (in
->buffer
);
1648 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1649 in
->point
= event
->x
- in
->first_shown
- 1;
1653 update_input (in
, 1);
1659 input_new (int y
, int x
, int color
, int len
, const char *def_text
,
1660 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
1662 WInput
*in
= g_new (WInput
, 1);
1663 int initial_buffer_len
;
1665 init_widget (&in
->widget
, y
, x
, 1, len
, input_callback
, input_event
);
1669 in
->history_name
= 0;
1672 in
->history_name
= g_strdup (histname
);
1673 in
->history
= history_get (histname
);
1680 if (def_text
== INPUT_LAST_TEXT
) {
1683 if (in
->history
->data
)
1684 def_text
= (char *) in
->history
->data
;
1686 initial_buffer_len
= 1 + max ((size_t) len
, strlen (def_text
));
1687 in
->widget
.options
|= W_IS_INPUT
;
1688 in
->completions
= NULL
;
1689 in
->completion_flags
= completion_flags
;
1690 in
->current_max_len
= initial_buffer_len
;
1691 in
->buffer
= g_malloc (initial_buffer_len
);
1693 in
->field_len
= len
;
1695 in
->first_shown
= 0;
1696 in
->disable_update
= 0;
1699 in
->is_password
= 0;
1701 strcpy (in
->buffer
, def_text
);
1702 in
->point
= strlen (in
->buffer
);
1707 /* Listbox widget */
1709 /* Should draw the scrollbar, but currently draws only
1710 * indications that there is more information
1712 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1715 listbox_drawscroll (WListbox
*l
)
1719 int max_line
= l
->height
-1;
1721 /* Are we at the top? */
1722 widget_move (&l
->widget
, 0, l
->width
);
1723 if (l
->list
== l
->top
)
1728 /* Are we at the bottom? */
1729 widget_move (&l
->widget
, max_line
, l
->width
);
1730 top
= listbox_cdiff (l
->list
, l
->top
);
1731 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1736 /* Now draw the nice relative pointer */
1738 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1742 for (i
= 1; i
< max_line
; i
++){
1743 widget_move (&l
->widget
, i
, l
->width
);
1752 listbox_draw (WListbox
*l
, int focused
)
1757 Dlg_head
*h
= l
->widget
.parent
;
1758 int normalc
= DLG_NORMALC (h
);
1763 selc
= DLG_FOCUSC (h
);
1765 selc
= DLG_HOT_FOCUSC (h
);
1769 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1771 /* Display the entry */
1772 if (e
== l
->current
&& sel_line
== -1){
1778 widget_move (&l
->widget
, i
, 0);
1780 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1786 tty_printf (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1788 l
->cursor_y
= sel_line
;
1792 listbox_drawscroll (l
);
1795 /* Returns the number of items between s and e,
1796 must be on the same linked list */
1798 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1802 for (count
= 0; s
!= e
; count
++)
1808 listbox_check_hotkey (WListbox
*l
, int key
)
1820 /* If we didn't find anything, return */
1821 if (i
&& e
== l
->list
)
1824 if (e
->hotkey
== key
)
1832 /* Used only for display updating, for avoiding line at a time scroll */
1834 listbox_select_last (WListbox
*l
, int set_top
)
1837 l
->current
= l
->list
->prev
;
1838 l
->pos
= l
->count
- 1;
1840 l
->top
= l
->list
->prev
;
1845 listbox_remove_list (WListbox
*l
)
1854 while (l
->count
--) {
1860 l
->pos
= l
->count
= 0;
1861 l
->list
= l
->top
= l
->current
= 0;
1865 * bor 30.10.96: added force flag to remove *last* entry as well
1866 * bor 30.10.96: corrected selection bug if last entry was removed
1870 listbox_remove_current (WListbox
*l
, int force
)
1874 /* Ok, note: this won't allow for emtpy lists */
1875 if (!force
&& (!l
->count
|| l
->count
== 1))
1882 l
->current
->next
->prev
= l
->current
->prev
;
1883 l
->current
->prev
->next
= l
->current
->next
;
1884 if (p
->next
== l
->list
) {
1885 l
->current
= p
->prev
;
1889 l
->current
= p
->next
;
1892 l
->list
= l
->top
= p
->next
;
1895 l
->list
= l
->top
= l
->current
= 0;
1902 /* Makes *e the selected entry (sets current and pos) */
1904 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1913 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1921 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1922 l
->top
= l
->top
->next
;
1924 l
->top
= l
->current
;
1930 /* If we are unable to find it, set decent values */
1931 l
->current
= l
->top
= l
->list
;
1935 /* Selects from base the pos element */
1937 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1939 WLEntry
*last
= l
->list
->prev
;
1951 static inline cb_ret_t
1952 listbox_back (WListbox
*l
)
1955 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1958 return MSG_NOT_HANDLED
;
1961 /* Return MSG_HANDLED if we want a redraw */
1963 listbox_key (WListbox
*l
, int key
)
1969 return MSG_NOT_HANDLED
;
1975 l
->current
= l
->top
= l
->list
;
1982 l
->current
= l
->top
= l
->list
->prev
;
1983 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1984 l
->top
= l
->top
->prev
;
1985 l
->pos
= l
->count
- 1;
2000 for (i
= 0; i
< l
->height
-1; i
++)
2001 j
|= listbox_fwd (l
);
2002 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2006 for (i
= 0; i
< l
->height
-1; i
++)
2007 j
|= listbox_back (l
);
2008 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2010 return MSG_NOT_HANDLED
;
2014 listbox_destroy (WListbox
*l
)
2016 WLEntry
*n
, *p
= l
->list
;
2019 for (i
= 0; i
< l
->count
; i
++){
2028 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2030 WListbox
*l
= (WListbox
*) w
;
2033 Dlg_head
*h
= l
->widget
.parent
;
2040 if ((e
= listbox_check_hotkey (l
, parm
)) != NULL
) {
2043 listbox_select_entry (l
, e
);
2046 action
= (*l
->cback
) (l
);
2048 action
= LISTBOX_DONE
;
2050 if (action
== LISTBOX_DONE
) {
2051 h
->ret_value
= B_ENTER
;
2056 return MSG_NOT_HANDLED
;
2059 if ((ret_code
= listbox_key (l
, parm
)))
2060 listbox_draw (l
, 1);
2064 widget_move (&l
->widget
, l
->cursor_y
, 0);
2068 case WIDGET_UNFOCUS
:
2070 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2073 case WIDGET_DESTROY
:
2074 listbox_destroy (l
);
2078 return default_proc (msg
, parm
);
2083 listbox_event (Gpm_Event
*event
, void *data
)
2089 Dlg_head
*h
= l
->widget
.parent
;
2092 if (event
->type
& GPM_DOWN
)
2093 dlg_select_widget (l
);
2096 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2097 if (event
->x
< 0 || event
->x
>= l
->width
)
2100 for (i
= -event
->y
; i
>= 0; i
--)
2102 else if (event
->y
> l
->height
)
2103 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2106 listbox_select_entry (l
,
2107 listbox_select_pos (l
, l
->top
,
2110 /* We need to refresh ourselves since the dialog manager doesn't */
2111 /* know about this event */
2112 listbox_callback (w
, WIDGET_DRAW
, 0);
2118 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2121 if (event
->x
< 0 || event
->x
>= l
->width
)
2123 if (event
->y
< 1 || event
->y
> l
->height
)
2126 dlg_select_widget (l
);
2127 listbox_select_entry (l
,
2128 listbox_select_pos (l
, l
->top
,
2132 action
= (*l
->cback
) (l
);
2134 action
= LISTBOX_DONE
;
2136 if (action
== LISTBOX_DONE
) {
2137 h
->ret_value
= B_ENTER
;
2146 listbox_new (int y
, int x
, int width
, int height
, lcback callback
)
2148 WListbox
*l
= g_new (WListbox
, 1);
2150 init_widget (&l
->widget
, y
, x
, height
, width
,
2151 listbox_callback
, listbox_event
);
2153 l
->list
= l
->top
= l
->current
= 0;
2161 l
->cback
= callback
;
2162 l
->allow_duplicates
= 1;
2163 l
->scrollbar
= slow_terminal
? 0 : 1;
2164 widget_want_hotkey (l
->widget
, 1);
2169 /* Listbox item adding function. They still lack a lot of functionality */
2171 /* 1.11.96 bor: added pos argument to control placement of new entry */
2173 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2181 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2183 e
->prev
= l
->list
->prev
;
2184 l
->list
->prev
->next
= e
;
2186 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2187 e
->next
= l
->current
;
2188 e
->prev
= l
->current
->prev
;
2189 l
->current
->prev
->next
= e
;
2190 l
->current
->prev
= e
;
2191 if (l
->list
== l
->current
) { /* move list one position down */
2195 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2196 e
->prev
= l
->current
;
2197 e
->next
= l
->current
->next
;
2198 l
->current
->next
->prev
= e
;
2199 l
->current
->next
= e
;
2200 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2201 WLEntry
*w
= l
->list
;
2203 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2205 if (w
->next
== l
->list
) {
2221 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2222 const char *text
, void *data
)
2229 if (!l
->allow_duplicates
)
2230 if (listbox_search_text (l
, text
))
2233 entry
= g_new (WLEntry
, 1);
2234 entry
->text
= g_strdup (text
);
2236 entry
->hotkey
= hotkey
;
2238 listbox_append_item (l
, entry
, pos
);
2243 /* Selects the nth entry in the listbox */
2245 listbox_select_by_number (WListbox
*l
, int n
)
2247 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2251 listbox_search_text (WListbox
*l
, const char *text
)
2260 if(!strcmp (e
->text
, text
))
2263 } while (e
!=l
->list
);
2268 /* Returns the current string text as well as the associated extra data */
2270 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2276 if (string
&& l
->current
)
2277 *string
= l
->current
->text
;
2278 if (extra
&& l
->current
)
2279 *extra
= l
->current
->data
;
2282 /* returns TRUE if a function has been called, FALSE otherwise. */
2284 buttonbar_call (WButtonBar
*bb
, int i
)
2286 switch (bb
->labels
[i
].tag
) {
2290 bb
->labels
[i
].u
.fn_void ();
2293 bb
->labels
[i
].u
.fn_ptr (bb
->labels
[i
].data
);
2301 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2303 WButtonBar
*bb
= (WButtonBar
*) w
;
2308 return MSG_NOT_HANDLED
;
2311 for (i
= 0; i
< 10; i
++) {
2312 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2315 return MSG_NOT_HANDLED
;
2320 widget_move (&bb
->widget
, 0, 0);
2321 attrset (DEFAULT_COLOR
);
2322 tty_printf ("%-*s", bb
->widget
.cols
, "");
2323 for (i
= 0; i
< COLS
/ 8 && i
< 10; i
++) {
2324 widget_move (&bb
->widget
, 0, i
* 8);
2325 attrset (DEFAULT_COLOR
);
2326 tty_printf ("%d", i
+ 1);
2327 attrset (SELECTED_COLOR
);
2328 tty_printf ("%-*s", ((i
+ 1) * 8 == COLS
? 5 : 6),
2329 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2330 attrset (DEFAULT_COLOR
);
2332 attrset (SELECTED_COLOR
);
2335 case WIDGET_DESTROY
:
2336 for (i
= 0; i
< 10; i
++)
2337 g_free (bb
->labels
[i
].text
);
2341 return default_proc (msg
, parm
);
2346 buttonbar_event (Gpm_Event
*event
, void *data
)
2348 WButtonBar
*bb
= data
;
2351 if (!(event
->type
& GPM_UP
))
2355 button
= event
->x
/ 8;
2357 buttonbar_call (bb
, button
);
2362 buttonbar_new (int visible
)
2365 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2367 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2368 buttonbar_callback
, buttonbar_event
);
2370 bb
->visible
= visible
;
2371 for (i
= 0; i
< 10; i
++){
2372 bb
->labels
[i
].text
= NULL
;
2373 bb
->labels
[i
].tag
= BBFUNC_NONE
;
2375 widget_want_hotkey (bb
->widget
, 1);
2376 widget_want_cursor (bb
->widget
, 0);
2382 set_label_text (WButtonBar
* bb
, int index
, const char *text
)
2384 g_free (bb
->labels
[index
- 1].text
);
2386 bb
->labels
[index
- 1].text
= g_strdup (text
);
2389 /* Find ButtonBar widget in the dialog */
2391 find_buttonbar (Dlg_head
*h
)
2395 bb
= (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2400 buttonbar_clear_label (Dlg_head
*h
, int idx
)
2402 WButtonBar
*bb
= find_buttonbar (h
);
2407 set_label_text (bb
, idx
, "");
2408 bb
->labels
[idx
- 1].tag
= BBFUNC_NONE
;
2412 buttonbar_set_label_data (Dlg_head
*h
, int idx
, const char *text
, buttonbarfn cback
,
2415 WButtonBar
*bb
= find_buttonbar (h
);
2420 assert (cback
!= (buttonbarfn
) 0);
2421 set_label_text (bb
, idx
, text
);
2422 bb
->labels
[idx
- 1].tag
= BBFUNC_PTR
;
2423 bb
->labels
[idx
- 1].u
.fn_ptr
= cback
;
2424 bb
->labels
[idx
- 1].data
= data
;
2428 buttonbar_set_label (Dlg_head
*h
, int idx
, const char *text
, voidfn cback
)
2430 WButtonBar
*bb
= find_buttonbar (h
);
2435 assert (cback
!= (voidfn
) 0);
2436 set_label_text (bb
, idx
, text
);
2437 bb
->labels
[idx
- 1].tag
= BBFUNC_VOID
;
2438 bb
->labels
[idx
- 1].u
.fn_void
= cback
;
2442 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2444 bb
->visible
= visible
;
2448 buttonbar_redraw (Dlg_head
*h
)
2450 WButtonBar
*bb
= find_buttonbar (h
);
2455 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2459 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2461 WGroupbox
*g
= (WGroupbox
*) w
;
2468 return MSG_NOT_HANDLED
;
2471 attrset (COLOR_NORMAL
);
2472 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2473 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2476 attrset (COLOR_HOT_NORMAL
);
2477 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2478 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2482 case WIDGET_DESTROY
:
2487 return default_proc (msg
, parm
);
2492 groupbox_new (int x
, int y
, int width
, int height
, const char *title
)
2494 WGroupbox
*g
= g_new (WGroupbox
, 1);
2496 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2498 g
->widget
.options
&= ~W_WANT_CURSOR
;
2499 widget_want_hotkey (g
->widget
, 0);
2501 /* Strip existing spaces, add one space before and after the title */
2504 t
= g_strstrip (g_strdup (title
));
2505 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);