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.
36 #include <sys/types.h>
45 #include "key.h" /* XCTRL and ALT macros */
46 #include "profile.h" /* for history loading and saving */
47 #include "wtools.h" /* For common_dialog_repaint() */
48 #include "main.h" /* for `slow_terminal' */
50 #define HISTORY_FILE_NAME ".mc/history"
54 int visible
; /* Is it visible? */
57 enum { BBFUNC_NONE
, BBFUNC_VOID
, BBFUNC_PTR
} tag
;
66 static int button_event (Gpm_Event
*event
, void *);
71 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
73 Dlg_head
*h
= w
->parent
;
78 : DLG_HOT_NORMALC (h
))
85 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
87 WButton
*b
= (WButton
*) w
;
91 Dlg_head
*h
= b
->widget
.parent
;
96 * Don't let the default button steal Enter from the current
97 * button. This is a workaround for the flawed event model
98 * when hotkeys are sent to all widgets before the key is
99 * handled by the current widget.
101 if (parm
== '\n' && h
->current
== &b
->widget
) {
102 button_callback (w
, WIDGET_KEY
, ' ');
106 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
107 button_callback (w
, WIDGET_KEY
, ' ');
111 if (b
->hotkey
== tolower (parm
)) {
112 button_callback (w
, WIDGET_KEY
, ' ');
116 return MSG_NOT_HANDLED
;
119 if (parm
!= ' ' && parm
!= '\n')
120 return MSG_NOT_HANDLED
;
123 stop
= (*b
->callback
) (b
->action
);
124 if (!b
->callback
|| stop
) {
125 h
->ret_value
= b
->action
;
146 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
152 if (msg
== WIDGET_UNFOCUS
)
154 else if (msg
== WIDGET_FOCUS
)
159 g_snprintf (buf
, sizeof (buf
), "[< %s >]", b
->text
);
163 g_snprintf (buf
, sizeof (buf
), "[ %s ]", b
->text
);
167 g_snprintf (buf
, sizeof (buf
), "[%s]", b
->text
);
177 widget_selectcolor (w
, b
->selected
, FALSE
);
178 widget_move (w
, 0, 0);
182 if (b
->hotpos
>= 0) {
183 widget_selectcolor (w
, b
->selected
, TRUE
);
184 widget_move (w
, 0, b
->hotpos
+ off
);
185 addch ((unsigned char) b
->text
[b
->hotpos
]);
194 return default_proc (msg
, parm
);
199 button_event (Gpm_Event
*event
, void *data
)
203 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
204 Dlg_head
*h
=b
->widget
.parent
;
205 dlg_select_widget (b
);
206 if (event
->type
& GPM_UP
){
207 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
208 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
216 button_len (const char *text
, unsigned int flags
)
218 int ret
= strlen (text
);
237 * Locate the hotkey and remove it from the button text. Assuming that
238 * the button text is g_malloc()ed, we can safely change and shorten it.
241 button_scan_hotkey (WButton
*b
)
243 char *cp
= strchr (b
->text
, '&');
245 if (cp
!= NULL
&& cp
[1] != '\0') {
246 g_strlcpy (cp
, cp
+ 1, strlen (cp
));
247 b
->hotkey
= tolower ((unsigned char) *cp
);
248 b
->hotpos
= cp
- b
->text
;
253 button_new (int y
, int x
, int action
, int flags
, const char *text
,
256 WButton
*b
= g_new (WButton
, 1);
258 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
259 button_callback
, button_event
);
264 b
->text
= g_strdup (text
);
265 b
->callback
= callback
;
266 widget_want_hotkey (b
->widget
, 1);
270 button_scan_hotkey(b
);
275 button_get_text (WButton
*b
)
281 button_set_text (WButton
*b
, const char *text
)
284 b
->text
= g_strdup (text
);
285 b
->widget
.cols
= button_len (text
, b
->flags
);
286 button_scan_hotkey(b
);
287 dlg_redraw (b
->widget
.parent
);
291 /* Radio button widget */
292 static int radio_event (Gpm_Event
*event
, void *);
295 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
297 WRadio
*r
= (WRadio
*) w
;
299 Dlg_head
*h
= r
->widget
.parent
;
304 int i
, lp
= tolower (parm
);
307 for (i
= 0; i
< r
->count
; i
++) {
308 cp
= strchr (r
->texts
[i
], '&');
309 if (cp
!= NULL
&& cp
[1] != '\0') {
310 int c
= tolower ((unsigned char) cp
[1]);
317 radio_callback (w
, WIDGET_KEY
, ' ');
322 return MSG_NOT_HANDLED
;
328 (*h
->callback
) (h
, DLG_ACTION
, 0);
329 radio_callback (w
, WIDGET_FOCUS
, ' ');
338 return MSG_NOT_HANDLED
;
342 if (r
->count
- 1 > r
->pos
) {
347 return MSG_NOT_HANDLED
;
350 (*h
->callback
) (h
, DLG_ACTION
, 0);
351 radio_callback (w
, WIDGET_FOCUS
, ' ');
352 widget_move (&r
->widget
, r
->pos
, 1);
358 for (i
= 0; i
< r
->count
; i
++) {
359 register const char *cp
;
360 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
361 widget_selectcolor (w
, focused
, FALSE
);
362 widget_move (&r
->widget
, i
, 0);
364 tty_printf ("(%c) ", (r
->sel
== i
) ? '*' : ' ');
365 for (cp
= r
->texts
[i
]; *cp
; cp
++) {
367 widget_selectcolor (w
, focused
, TRUE
);
369 widget_selectcolor (w
, focused
, FALSE
);
377 return default_proc (msg
, parm
);
382 radio_event (Gpm_Event
*event
, void *data
)
387 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
388 Dlg_head
*h
= r
->widget
.parent
;
390 r
->pos
= event
->y
- 1;
391 dlg_select_widget (r
);
392 if (event
->type
& GPM_UP
){
393 radio_callback (w
, WIDGET_KEY
, ' ');
394 radio_callback (w
, WIDGET_FOCUS
, 0);
395 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
403 radio_new (int y
, int x
, int count
, const char **texts
)
405 WRadio
*r
= g_new (WRadio
, 1);
408 /* Compute the longest string */
410 for (i
= 0; i
< count
; i
++){
411 m
= strlen (texts
[i
]);
416 init_widget (&r
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
422 widget_want_hotkey (r
->widget
, 1);
428 /* Checkbutton widget */
430 static int check_event (Gpm_Event
*event
, void *);
433 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
435 WCheck
*c
= (WCheck
*) w
;
436 Dlg_head
*h
= c
->widget
.parent
;
440 if (c
->hotkey
== parm
441 || (c
->hotkey
>= 'a' && c
->hotkey
<= 'z'
442 && c
->hotkey
- 32 == parm
)) {
443 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
446 return MSG_NOT_HANDLED
;
450 return MSG_NOT_HANDLED
;
452 c
->state
^= C_CHANGE
;
453 (*h
->callback
) (h
, DLG_ACTION
, 0);
454 check_callback (w
, WIDGET_FOCUS
, ' ');
458 widget_move (&c
->widget
, 0, 1);
464 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
465 widget_move (&c
->widget
, 0, 0);
466 tty_printf ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
468 if (c
->hotpos
>= 0) {
469 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, TRUE
);
470 widget_move (&c
->widget
, 0, +c
->hotpos
+ 4);
471 addch ((unsigned char) c
->text
[c
->hotpos
]);
480 return default_proc (msg
, parm
);
485 check_event (Gpm_Event
*event
, void *data
)
490 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
491 Dlg_head
*h
= c
->widget
.parent
;
493 dlg_select_widget (c
);
494 if (event
->type
& GPM_UP
){
495 check_callback (w
, WIDGET_KEY
, ' ');
496 check_callback (w
, WIDGET_FOCUS
, 0);
497 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
505 check_new (int y
, int x
, int state
, const char *text
)
507 WCheck
*c
= g_new (WCheck
, 1);
511 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
512 check_callback
, check_event
);
513 c
->state
= state
? C_BOOL
: 0;
514 c
->text
= g_strdup (text
);
517 widget_want_hotkey (c
->widget
, 1);
519 /* Scan for the hotkey */
520 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
527 c
->hotkey
= tolower ((unsigned char) *s
);
528 c
->hotpos
= t
- c
->text
;
540 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
542 WLabel
*l
= (WLabel
*) w
;
543 Dlg_head
*h
= l
->widget
.parent
;
549 /* We don't want to get the focus */
551 return MSG_NOT_HANDLED
;
555 char *p
= l
->text
, *q
, c
= 0;
562 attrset (DEFAULT_COLOR
);
564 attrset (DLG_NORMALC (h
));
568 q
= strchr (p
, '\n');
573 widget_move (&l
->widget
, y
, 0);
574 tty_printf ("%s", p
);
575 xlen
= l
->widget
.cols
- strlen (p
);
577 tty_printf ("%*s", xlen
, " ");
592 return default_proc (msg
, parm
);
597 label_set_text (WLabel
*label
, const char *text
)
599 int newcols
= label
->widget
.cols
;
601 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
602 return; /* Flickering is not nice */
604 g_free (label
->text
);
607 label
->text
= g_strdup (text
);
608 if (label
->auto_adjust_cols
) {
609 newcols
= strlen (text
);
610 if (newcols
> label
->widget
.cols
)
611 label
->widget
.cols
= newcols
;
616 if (label
->widget
.parent
)
617 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
619 if (newcols
< label
->widget
.cols
)
620 label
->widget
.cols
= newcols
;
624 label_new (int y
, int x
, const char *text
)
629 /* Multiline labels are immutable - no need to compute their sizes */
630 if (!text
|| strchr(text
, '\n'))
633 width
= strlen (text
);
635 l
= g_new (WLabel
, 1);
636 init_widget (&l
->widget
, y
, x
, 1, width
, label_callback
, NULL
);
637 l
->text
= text
? g_strdup (text
) : 0;
638 l
->auto_adjust_cols
= 1;
640 widget_want_cursor (l
->widget
, 0);
645 /* Gauge widget (progress indicator) */
646 /* Currently width is hardcoded here for text mode */
650 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
652 WGauge
*g
= (WGauge
*) w
;
653 Dlg_head
*h
= g
->widget
.parent
;
655 if (msg
== WIDGET_INIT
)
658 /* We don't want to get the focus */
659 if (msg
== WIDGET_FOCUS
)
660 return MSG_NOT_HANDLED
;
662 if (msg
== WIDGET_DRAW
){
663 widget_move (&g
->widget
, 0, 0);
664 attrset (DLG_NORMALC (h
));
666 tty_printf ("%*s", gauge_len
, "");
668 int percentage
, columns
;
669 long total
= g
->max
, done
= g
->current
;
671 if (total
<= 0 || done
< 0) {
677 while (total
> 65535) {
681 percentage
= (200 * done
/ total
+ 1) / 2;
682 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
684 attrset (GAUGE_COLOR
);
685 tty_printf ("%*s", (int) columns
, "");
686 attrset (DLG_NORMALC (h
));
687 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
691 return default_proc (msg
, parm
);
695 gauge_set_value (WGauge
*g
, int max
, int current
)
697 if (g
->current
== current
&& g
->max
== max
)
698 return; /* Do not flicker */
700 max
= 1; /* I do not like division by zero :) */
702 g
->current
= current
;
704 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
708 gauge_show (WGauge
*g
, int shown
)
710 if (g
->shown
== shown
)
713 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
717 gauge_new (int y
, int x
, int shown
, int max
, int current
)
719 WGauge
*g
= g_new (WGauge
, 1);
721 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
724 max
= 1; /* I do not like division by zero :) */
726 g
->current
= current
;
727 widget_want_cursor (g
->widget
, 0);
734 /* {{{ history button */
736 #define LARGE_HISTORY_BUTTON 1
738 #ifdef LARGE_HISTORY_BUTTON
739 # define HISTORY_BUTTON_WIDTH 3
741 # define HISTORY_BUTTON_WIDTH 1
744 #define should_show_history_button(in) \
745 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
747 static void draw_history_button (WInput
* in
)
750 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
751 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
752 #ifdef LARGE_HISTORY_BUTTON
755 h
= in
->widget
.parent
;
757 attrset (NORMALC
); /* button has the same color as other buttons */
759 attrset (HOT_NORMALC
);
761 attrset (NORMAL_COLOR
);
763 /* Too distracting: attrset (MARKED_COLOR); */
765 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
769 attrset (MARKED_COLOR
);
774 /* }}} history button */
777 /* Input widgets now have a global kill ring */
778 /* Pointer to killed data */
779 static char *kill_buffer
= 0;
782 update_input (WInput
*in
, int clear_first
)
787 int buf_len
= strlen (in
->buffer
);
789 if (should_show_history_button (in
))
790 has_history
= HISTORY_BUTTON_WIDTH
;
792 if (in
->disable_update
)
795 /* Make the point visible */
796 if ((in
->point
< in
->first_shown
) ||
797 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
798 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
799 if (in
->first_shown
< 0)
803 /* Adjust the mark */
804 if (in
->mark
> buf_len
)
808 draw_history_button (in
);
812 widget_move (&in
->widget
, 0, 0);
813 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
815 widget_move (&in
->widget
, 0, 0);
817 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
818 c
= in
->buffer
[j
++];
819 c
= is_printable (c
) ? c
: '.';
824 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
831 winput_set_origin (WInput
*in
, int x
, int field_len
)
834 in
->field_len
= in
->widget
.cols
= field_len
;
835 update_input (in
, 0);
838 /* {{{ history saving and loading */
840 int num_history_items_recorded
= 60;
843 This loads and saves the history of an input line to and from the
844 widget. It is called with the widgets history name on creation of the
845 widget, and returns the GList list. It stores histories in the file
846 ~/.mc/history in using the profile code.
848 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
849 function) then input_new assigns the default text to be the last text
850 entered, or "" if not found.
854 history_get (const char *input_name
)
862 if (!num_history_items_recorded
) /* this is how to disable */
868 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
870 char key_name
[BUF_TINY
];
871 char this_entry
[BUF_LARGE
];
872 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
873 GetPrivateProfileString (input_name
, key_name
, "", this_entry
,
874 sizeof (this_entry
), profile
);
878 hist
= list_append_unique (hist
, g_strdup (this_entry
));
882 /* return pointer to the last entry in the list */
883 hist
= g_list_last (hist
);
889 history_put (const char *input_name
, GList
*h
)
903 if (!num_history_items_recorded
) /* this is how to disable */
906 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
908 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
911 /* Make sure the history is only readable by the user */
912 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
917 /* go to end of list */
920 /* go back 60 places */
921 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
922 h
= g_list_previous (h
);
925 profile_clean_section (input_name
, profile
);
927 /* dump histories into profile */
928 for (i
= 0; h
; h
= g_list_next (h
)) {
931 text
= (char *) h
->data
;
933 /* We shouldn't have null entries, but let's be sure */
935 char key_name
[BUF_TINY
];
936 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
937 WritePrivateProfileString (input_name
, key_name
, text
,
945 /* }}} history saving and loading */
948 /* {{{ history display */
953 static const char *history_title
= NULL
;
955 if (history_title
== NULL
)
956 history_title
= _(" History ");
957 return history_title
;
960 static WLEntry
*listbox_select_pos (WListbox
*l
, WLEntry
*base
, int
963 static inline cb_ret_t
964 listbox_fwd (WListbox
*l
)
966 if (l
->current
!= l
->list
->prev
){
967 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
970 return MSG_NOT_HANDLED
;
974 show_hist (GList
*history
, int widget_x
, int widget_y
)
977 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
981 WListbox
*query_list
;
987 z
= g_list_first (history
);
990 if ((i
= strlen ((char *) hi
->data
)) > maxlen
)
993 hi
= g_list_next (hi
);
998 if (h
<= y
|| y
> LINES
- 6) {
1003 h
= min (h
, LINES
- y
);
1010 if ((w
= maxlen
+ 4) + x
> COLS
) {
1016 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
1017 i18n_htitle (), DLG_COMPACT
);
1018 query_list
= listbox_new (1, 1, w
- 2, h
- 2, 0);
1019 add_widget (query_dlg
, query_list
);
1024 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1025 hi
= g_list_next (hi
);
1027 while (listbox_fwd (query_list
));
1029 /* traverse backwards */
1030 hi
= g_list_last (history
);
1032 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1033 hi
= g_list_previous (hi
);
1036 run_dlg (query_dlg
);
1038 if (query_dlg
->ret_value
!= B_CANCEL
) {
1039 listbox_get_current (query_list
, &q
, NULL
);
1043 destroy_dlg (query_dlg
);
1047 static void do_show_hist (WInput
* in
)
1050 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1052 assign_text (in
, r
);
1057 /* }}} history display */
1060 input_destroy (WInput
*in
)
1063 fprintf (stderr
, "Internal error: null Input *\n");
1070 if (!in
->is_password
) /* don't save passwords ;-) */
1071 history_put (in
->history_name
, in
->history
);
1073 in
->history
= g_list_first (in
->history
);
1074 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1075 g_list_free (in
->history
);
1078 g_free (in
->buffer
);
1079 free_completions (in
);
1080 g_free (in
->history_name
);
1084 input_disable_update (WInput
*in
)
1086 in
->disable_update
++;
1090 input_enable_update (WInput
*in
)
1092 in
->disable_update
--;
1093 update_input (in
, 0);
1096 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1099 push_history (WInput
*in
, const char *text
)
1102 /* input widget where urls with passwords are entered without any
1104 static const char *password_input_fields
[] = {
1105 N_(" Link to a remote machine "),
1106 N_(" FTP to machine "),
1107 N_(" SMB link to machine ")
1115 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1116 password_input_fields
[i
] = _(password_input_fields
[i
]);
1119 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1124 /* Avoid duplicated entries */
1125 in
->history
= g_list_last (in
->history
);
1126 if (!strcmp ((char *) in
->history
->data
, text
))
1130 t
= g_strdup (text
);
1132 if (in
->history_name
) {
1133 p
= in
->history_name
+ 3;
1134 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1135 if (strcmp (p
, password_input_fields
[i
]) == 0)
1137 if (i
< ELEMENTS (password_input_fields
))
1138 strip_password (t
, 0);
1140 strip_password (t
, 1);
1143 in
->history
= list_append_unique (in
->history
, t
);
1151 /* Cleans the input line and adds the current text to the history */
1153 new_input (WInput
*in
)
1156 push_history (in
, in
->buffer
);
1161 free_completions (in
);
1162 update_input (in
, 0);
1166 insert_char (WInput
*in
, int c_code
)
1171 return MSG_NOT_HANDLED
;
1174 if (strlen (in
->buffer
)+1 == (size_t) in
->current_max_len
){
1175 /* Expand the buffer */
1176 char *narea
= g_realloc (in
->buffer
, in
->current_max_len
+ in
->field_len
);
1179 in
->current_max_len
+= in
->field_len
;
1182 if (strlen (in
->buffer
)+1 < (size_t) in
->current_max_len
){
1183 size_t l
= strlen (&in
->buffer
[in
->point
]);
1184 for (i
= l
+1; i
> 0; i
--)
1185 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1186 in
->buffer
[in
->point
] = c_code
;
1193 beginning_of_line (WInput
*in
)
1199 end_of_line (WInput
*in
)
1201 in
->point
= strlen (in
->buffer
);
1205 backward_char (WInput
*in
)
1212 forward_char (WInput
*in
)
1214 if (in
->buffer
[in
->point
])
1219 forward_word (WInput
* in
)
1221 char *p
= in
->buffer
+ in
->point
;
1224 && (isspace ((unsigned char) *p
)
1225 || ispunct ((unsigned char) *p
)))
1227 while (*p
&& isalnum ((unsigned char) *p
))
1229 in
->point
= p
- in
->buffer
;
1233 backward_word (WInput
*in
)
1235 char *p
= in
->buffer
+ in
->point
;
1237 while (p
- 1 > in
->buffer
- 1 && (isspace ((unsigned char) *(p
- 1))
1238 || ispunct ((unsigned char)
1241 while (p
- 1 > in
->buffer
- 1 && isalnum ((unsigned char) *(p
- 1)))
1243 in
->point
= p
- in
->buffer
;
1247 key_left (WInput
*in
)
1253 key_ctrl_left (WInput
*in
)
1259 key_right (WInput
*in
)
1265 key_ctrl_right (WInput
*in
)
1270 backward_delete (WInput
*in
)
1276 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1277 in
->buffer
[i
-1] = in
->buffer
[i
];
1283 delete_char (WInput
*in
)
1287 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1288 in
->buffer
[i
] = in
->buffer
[i
+1];
1293 copy_region (WInput
*in
, int x_first
, int x_last
)
1295 int first
= min (x_first
, x_last
);
1296 int last
= max (x_first
, x_last
);
1301 g_free (kill_buffer
);
1303 kill_buffer
= g_strndup(in
->buffer
+first
,last
-first
);
1307 delete_region (WInput
*in
, int x_first
, int x_last
)
1309 int first
= min (x_first
, x_last
);
1310 int last
= max (x_first
, x_last
);
1311 size_t len
= strlen (&in
->buffer
[last
]) + 1;
1315 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1320 kill_word (WInput
*in
)
1322 int old_point
= in
->point
;
1326 new_point
= in
->point
;
1327 in
->point
= old_point
;
1329 copy_region (in
, old_point
, new_point
);
1330 delete_region (in
, old_point
, new_point
);
1335 back_kill_word (WInput
*in
)
1337 int old_point
= in
->point
;
1341 new_point
= in
->point
;
1342 in
->point
= old_point
;
1344 copy_region (in
, old_point
, new_point
);
1345 delete_region (in
, old_point
, new_point
);
1350 set_mark (WInput
*in
)
1352 in
->mark
= in
->point
;
1356 kill_save (WInput
*in
)
1358 copy_region (in
, in
->mark
, in
->point
);
1362 kill_region (WInput
*in
)
1365 delete_region (in
, in
->point
, in
->mark
);
1375 for (p
= kill_buffer
; *p
; p
++)
1376 insert_char (in
, *p
);
1380 kill_line (WInput
*in
)
1382 g_free (kill_buffer
);
1383 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1384 in
->buffer
[in
->point
] = 0;
1388 assign_text (WInput
*in
, const char *text
)
1390 free_completions (in
);
1391 g_free (in
->buffer
);
1392 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1393 in
->current_max_len
= strlen (in
->buffer
) + 1;
1394 in
->point
= strlen (in
->buffer
);
1400 hist_prev (WInput
*in
)
1405 if (in
->need_push
) {
1406 switch (push_history (in
, in
->buffer
)) {
1408 in
->history
= g_list_previous (in
->history
);
1411 if (in
->history
->prev
)
1412 in
->history
= g_list_previous (in
->history
);
1417 } else if (in
->history
->prev
)
1418 in
->history
= g_list_previous (in
->history
);
1421 assign_text (in
, (char *) in
->history
->data
);
1426 hist_next (WInput
*in
)
1428 if (in
->need_push
) {
1429 switch (push_history (in
, in
->buffer
)) {
1431 assign_text (in
, "");
1441 if (!in
->history
->next
) {
1442 assign_text (in
, "");
1446 in
->history
= g_list_next (in
->history
);
1447 assign_text (in
, (char *) in
->history
->data
);
1451 static const struct {
1453 void (*fn
)(WInput
*in
);
1456 { XCTRL('a'), beginning_of_line
},
1457 { KEY_HOME
, beginning_of_line
},
1458 { KEY_A1
, beginning_of_line
},
1459 { ALT ('<'), beginning_of_line
},
1460 { XCTRL('e'), end_of_line
},
1461 { KEY_END
, end_of_line
},
1462 { KEY_C1
, end_of_line
},
1463 { ALT ('>'), end_of_line
},
1464 { KEY_LEFT
, key_left
},
1465 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1466 { XCTRL('b'), backward_char
},
1467 { ALT('b'), backward_word
},
1468 { KEY_RIGHT
, key_right
},
1469 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1470 { XCTRL('f'), forward_char
},
1471 { ALT('f'), forward_word
},
1474 { KEY_BACKSPACE
, backward_delete
},
1475 { KEY_DC
, delete_char
},
1476 { ALT('d'), kill_word
},
1477 { ALT(KEY_BACKSPACE
), back_kill_word
},
1479 /* Region manipulation */
1481 { XCTRL('w'), kill_region
},
1482 { ALT('w'), kill_save
},
1483 { XCTRL('y'), yank
},
1484 { XCTRL('k'), kill_line
},
1487 { ALT('p'), hist_prev
},
1488 { ALT('n'), hist_next
},
1489 { ALT('h'), do_show_hist
},
1492 { ALT('\t'), complete
},
1497 /* This function is a test for a special input key used in complete.c */
1498 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1499 and 2 if it is a complete key */
1501 is_in_input_map (WInput
*in
, int c_code
)
1507 for (i
= 0; input_map
[i
].fn
; i
++)
1508 if (c_code
== input_map
[i
].key_code
) {
1509 if (input_map
[i
].fn
== complete
)
1518 port_region_marked_for_delete (WInput
*in
)
1526 handle_char (WInput
*in
, int c_code
)
1531 v
= MSG_NOT_HANDLED
;
1534 free_completions (in
);
1535 v
= insert_char (in
, c_code
);
1536 update_input (in
, 1);
1541 for (i
= 0; input_map
[i
].fn
; i
++){
1542 if (c_code
== input_map
[i
].key_code
){
1543 if (input_map
[i
].fn
!= complete
)
1544 free_completions (in
);
1545 (*input_map
[i
].fn
)(in
);
1550 if (!input_map
[i
].fn
){
1551 if (c_code
> 255 || !is_printable (c_code
))
1552 return MSG_NOT_HANDLED
;
1554 port_region_marked_for_delete (in
);
1556 free_completions (in
);
1557 v
= insert_char (in
, c_code
);
1559 update_input (in
, 1);
1563 /* Inserts text in input line */
1565 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1567 input_disable_update (in
);
1569 handle_char (in
, *text
++);
1570 if (insert_extra_space
)
1571 handle_char (in
, ' ');
1572 input_enable_update (in
);
1573 update_input (in
, 1);
1577 input_set_point (WInput
*in
, int pos
)
1579 if (pos
> in
->current_max_len
)
1580 pos
= in
->current_max_len
;
1581 if (pos
!= in
->point
)
1582 free_completions (in
);
1584 update_input (in
, 1);
1588 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1590 WInput
*in
= (WInput
*) w
;
1595 if (parm
== XCTRL ('q')) {
1597 v
= handle_char (in
, ascii_alpha_to_cntrl (mi_getch ()));
1602 /* Keys we want others to handle */
1603 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1604 || parm
== KEY_F (10) || parm
== XCTRL ('g') || parm
== '\n')
1605 return MSG_NOT_HANDLED
;
1607 /* When pasting multiline text, insert literal Enter */
1608 if ((parm
& ~KEY_M_MASK
) == '\n') {
1610 v
= handle_char (in
, '\n');
1615 return handle_char (in
, parm
);
1618 case WIDGET_UNFOCUS
:
1620 update_input (in
, 0);
1624 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1627 case WIDGET_DESTROY
:
1632 return default_proc (msg
, parm
);
1637 input_event (Gpm_Event
* event
, void *data
)
1641 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1642 dlg_select_widget (in
);
1644 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1645 && should_show_history_button (in
)) {
1648 in
->point
= strlen (in
->buffer
);
1649 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1650 in
->point
= event
->x
- in
->first_shown
- 1;
1654 update_input (in
, 1);
1660 input_new (int y
, int x
, int color
, int len
, const char *def_text
,
1661 const char *histname
, int completion_flags
)
1663 WInput
*in
= g_new (WInput
, 1);
1664 int initial_buffer_len
;
1666 init_widget (&in
->widget
, y
, x
, 1, len
, input_callback
, input_event
);
1670 in
->history_name
= 0;
1673 in
->history_name
= g_strdup (histname
);
1674 in
->history
= history_get (histname
);
1681 if (def_text
== INPUT_LAST_TEXT
) {
1684 if (in
->history
->data
)
1685 def_text
= (char *) in
->history
->data
;
1687 initial_buffer_len
= 1 + max ((size_t) len
, strlen (def_text
));
1688 in
->widget
.options
|= W_IS_INPUT
;
1689 in
->completions
= NULL
;
1690 in
->completion_flags
= completion_flags
;
1691 in
->current_max_len
= initial_buffer_len
;
1692 in
->buffer
= g_malloc (initial_buffer_len
);
1694 in
->field_len
= len
;
1696 in
->first_shown
= 0;
1697 in
->disable_update
= 0;
1700 in
->is_password
= 0;
1702 strcpy (in
->buffer
, def_text
);
1703 in
->point
= strlen (in
->buffer
);
1708 /* Listbox widget */
1710 /* Should draw the scrollbar, but currently draws only
1711 * indications that there is more information
1713 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1716 listbox_drawscroll (WListbox
*l
)
1720 int max_line
= l
->height
-1;
1722 /* Are we at the top? */
1723 widget_move (&l
->widget
, 0, l
->width
);
1724 if (l
->list
== l
->top
)
1729 /* Are we at the bottom? */
1730 widget_move (&l
->widget
, max_line
, l
->width
);
1731 top
= listbox_cdiff (l
->list
, l
->top
);
1732 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1737 /* Now draw the nice relative pointer */
1739 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1743 for (i
= 1; i
< max_line
; i
++){
1744 widget_move (&l
->widget
, i
, l
->width
);
1753 listbox_draw (WListbox
*l
, int focused
)
1758 Dlg_head
*h
= l
->widget
.parent
;
1759 int normalc
= DLG_NORMALC (h
);
1764 selc
= DLG_FOCUSC (h
);
1766 selc
= DLG_HOT_FOCUSC (h
);
1770 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1772 /* Display the entry */
1773 if (e
== l
->current
&& sel_line
== -1){
1779 widget_move (&l
->widget
, i
, 0);
1781 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1787 tty_printf (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1789 l
->cursor_y
= sel_line
;
1793 listbox_drawscroll (l
);
1796 /* Returns the number of items between s and e,
1797 must be on the same linked list */
1799 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1803 for (count
= 0; s
!= e
; count
++)
1809 listbox_check_hotkey (WListbox
*l
, int key
)
1821 /* If we didn't find anything, return */
1822 if (i
&& e
== l
->list
)
1825 if (e
->hotkey
== key
)
1833 /* Used only for display updating, for avoiding line at a time scroll */
1835 listbox_select_last (WListbox
*l
, int set_top
)
1838 l
->current
= l
->list
->prev
;
1839 l
->pos
= l
->count
- 1;
1841 l
->top
= l
->list
->prev
;
1846 listbox_remove_list (WListbox
*l
)
1855 while (l
->count
--) {
1861 l
->pos
= l
->count
= 0;
1862 l
->list
= l
->top
= l
->current
= 0;
1866 * bor 30.10.96: added force flag to remove *last* entry as well
1867 * bor 30.10.96: corrected selection bug if last entry was removed
1871 listbox_remove_current (WListbox
*l
, int force
)
1875 /* Ok, note: this won't allow for emtpy lists */
1876 if (!force
&& (!l
->count
|| l
->count
== 1))
1883 l
->current
->next
->prev
= l
->current
->prev
;
1884 l
->current
->prev
->next
= l
->current
->next
;
1885 if (p
->next
== l
->list
) {
1886 l
->current
= p
->prev
;
1890 l
->current
= p
->next
;
1893 l
->list
= l
->top
= p
->next
;
1896 l
->list
= l
->top
= l
->current
= 0;
1903 /* Makes *e the selected entry (sets current and pos) */
1905 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1914 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1922 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1923 l
->top
= l
->top
->next
;
1925 l
->top
= l
->current
;
1931 /* If we are unable to find it, set decent values */
1932 l
->current
= l
->top
= l
->list
;
1936 /* Selects from base the pos element */
1938 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1940 WLEntry
*last
= l
->list
->prev
;
1952 static inline cb_ret_t
1953 listbox_back (WListbox
*l
)
1956 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1959 return MSG_NOT_HANDLED
;
1962 /* Return MSG_HANDLED if we want a redraw */
1964 listbox_key (WListbox
*l
, int key
)
1970 return MSG_NOT_HANDLED
;
1976 l
->current
= l
->top
= l
->list
;
1983 l
->current
= l
->top
= l
->list
->prev
;
1984 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1985 l
->top
= l
->top
->prev
;
1986 l
->pos
= l
->count
- 1;
2001 for (i
= 0; i
< l
->height
-1; i
++)
2002 j
|= listbox_fwd (l
);
2003 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2007 for (i
= 0; i
< l
->height
-1; i
++)
2008 j
|= listbox_back (l
);
2009 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2011 return MSG_NOT_HANDLED
;
2015 listbox_destroy (WListbox
*l
)
2017 WLEntry
*n
, *p
= l
->list
;
2020 for (i
= 0; i
< l
->count
; i
++){
2029 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2031 WListbox
*l
= (WListbox
*) w
;
2034 Dlg_head
*h
= l
->widget
.parent
;
2041 if ((e
= listbox_check_hotkey (l
, parm
)) != NULL
) {
2044 listbox_select_entry (l
, e
);
2047 action
= (*l
->cback
) (l
);
2049 action
= LISTBOX_DONE
;
2051 if (action
== LISTBOX_DONE
) {
2052 h
->ret_value
= B_ENTER
;
2057 return MSG_NOT_HANDLED
;
2060 if ((ret_code
= listbox_key (l
, parm
)))
2061 listbox_draw (l
, 1);
2065 widget_move (&l
->widget
, l
->cursor_y
, 0);
2069 case WIDGET_UNFOCUS
:
2071 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2074 case WIDGET_DESTROY
:
2075 listbox_destroy (l
);
2079 return default_proc (msg
, parm
);
2084 listbox_event (Gpm_Event
*event
, void *data
)
2090 Dlg_head
*h
= l
->widget
.parent
;
2093 if (event
->type
& GPM_DOWN
)
2094 dlg_select_widget (l
);
2097 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2098 if (event
->x
< 0 || event
->x
>= l
->width
)
2101 for (i
= -event
->y
; i
>= 0; i
--)
2103 else if (event
->y
> l
->height
)
2104 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2107 listbox_select_entry (l
,
2108 listbox_select_pos (l
, l
->top
,
2111 /* We need to refresh ourselves since the dialog manager doesn't */
2112 /* know about this event */
2113 listbox_callback (w
, WIDGET_DRAW
, 0);
2119 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2122 if (event
->x
< 0 || event
->x
>= l
->width
)
2124 if (event
->y
< 1 || event
->y
> l
->height
)
2127 dlg_select_widget (l
);
2128 listbox_select_entry (l
,
2129 listbox_select_pos (l
, l
->top
,
2133 action
= (*l
->cback
) (l
);
2135 action
= LISTBOX_DONE
;
2137 if (action
== LISTBOX_DONE
) {
2138 h
->ret_value
= B_ENTER
;
2147 listbox_new (int y
, int x
, int width
, int height
, lcback callback
)
2149 WListbox
*l
= g_new (WListbox
, 1);
2151 init_widget (&l
->widget
, y
, x
, height
, width
,
2152 listbox_callback
, listbox_event
);
2154 l
->list
= l
->top
= l
->current
= 0;
2162 l
->cback
= callback
;
2163 l
->allow_duplicates
= 1;
2164 l
->scrollbar
= slow_terminal
? 0 : 1;
2165 widget_want_hotkey (l
->widget
, 1);
2170 /* Listbox item adding function. They still lack a lot of functionality */
2172 /* 1.11.96 bor: added pos argument to control placement of new entry */
2174 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2182 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2184 e
->prev
= l
->list
->prev
;
2185 l
->list
->prev
->next
= e
;
2187 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2188 e
->next
= l
->current
;
2189 e
->prev
= l
->current
->prev
;
2190 l
->current
->prev
->next
= e
;
2191 l
->current
->prev
= e
;
2192 if (l
->list
== l
->current
) { /* move list one position down */
2196 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2197 e
->prev
= l
->current
;
2198 e
->next
= l
->current
->next
;
2199 l
->current
->next
->prev
= e
;
2200 l
->current
->next
= e
;
2201 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2202 WLEntry
*w
= l
->list
;
2204 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2206 if (w
->next
== l
->list
) {
2222 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2223 const char *text
, void *data
)
2230 if (!l
->allow_duplicates
)
2231 if (listbox_search_text (l
, text
))
2234 entry
= g_new (WLEntry
, 1);
2235 entry
->text
= g_strdup (text
);
2237 entry
->hotkey
= hotkey
;
2239 listbox_append_item (l
, entry
, pos
);
2244 /* Selects the nth entry in the listbox */
2246 listbox_select_by_number (WListbox
*l
, int n
)
2248 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2252 listbox_search_text (WListbox
*l
, const char *text
)
2261 if(!strcmp (e
->text
, text
))
2264 } while (e
!=l
->list
);
2269 /* Returns the current string text as well as the associated extra data */
2271 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2277 if (string
&& l
->current
)
2278 *string
= l
->current
->text
;
2279 if (extra
&& l
->current
)
2280 *extra
= l
->current
->data
;
2283 /* returns TRUE if a function has been called, FALSE otherwise. */
2285 buttonbar_call (WButtonBar
*bb
, int i
)
2287 switch (bb
->labels
[i
].tag
) {
2291 bb
->labels
[i
].u
.fn_void ();
2294 bb
->labels
[i
].u
.fn_ptr (bb
->labels
[i
].data
);
2302 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2304 WButtonBar
*bb
= (WButtonBar
*) w
;
2309 return MSG_NOT_HANDLED
;
2312 for (i
= 0; i
< 10; i
++) {
2313 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2316 return MSG_NOT_HANDLED
;
2321 widget_move (&bb
->widget
, 0, 0);
2322 attrset (DEFAULT_COLOR
);
2323 tty_printf ("%-*s", bb
->widget
.cols
, "");
2324 for (i
= 0; i
< COLS
/ 8 && i
< 10; i
++) {
2325 widget_move (&bb
->widget
, 0, i
* 8);
2326 attrset (DEFAULT_COLOR
);
2327 tty_printf ("%d", i
+ 1);
2328 attrset (SELECTED_COLOR
);
2329 tty_printf ("%-*s", ((i
+ 1) * 8 == COLS
? 5 : 6),
2330 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2331 attrset (DEFAULT_COLOR
);
2333 attrset (SELECTED_COLOR
);
2336 case WIDGET_DESTROY
:
2337 for (i
= 0; i
< 10; i
++)
2338 g_free (bb
->labels
[i
].text
);
2342 return default_proc (msg
, parm
);
2347 buttonbar_event (Gpm_Event
*event
, void *data
)
2349 WButtonBar
*bb
= data
;
2352 if (!(event
->type
& GPM_UP
))
2356 button
= event
->x
/ 8;
2358 buttonbar_call (bb
, button
);
2363 buttonbar_new (int visible
)
2366 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2368 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2369 buttonbar_callback
, buttonbar_event
);
2371 bb
->visible
= visible
;
2372 for (i
= 0; i
< 10; i
++){
2373 bb
->labels
[i
].text
= NULL
;
2374 bb
->labels
[i
].tag
= BBFUNC_NONE
;
2376 widget_want_hotkey (bb
->widget
, 1);
2377 widget_want_cursor (bb
->widget
, 0);
2383 set_label_text (WButtonBar
* bb
, int index
, const char *text
)
2385 g_free (bb
->labels
[index
- 1].text
);
2387 bb
->labels
[index
- 1].text
= g_strdup (text
);
2390 /* Find ButtonBar widget in the dialog */
2392 find_buttonbar (Dlg_head
*h
)
2396 bb
= (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2401 buttonbar_clear_label (Dlg_head
*h
, int idx
)
2403 WButtonBar
*bb
= find_buttonbar (h
);
2408 set_label_text (bb
, idx
, "");
2409 bb
->labels
[idx
- 1].tag
= BBFUNC_NONE
;
2413 buttonbar_set_label_data (Dlg_head
*h
, int idx
, const char *text
, buttonbarfn cback
,
2416 WButtonBar
*bb
= find_buttonbar (h
);
2421 assert (cback
!= (buttonbarfn
) 0);
2422 set_label_text (bb
, idx
, text
);
2423 bb
->labels
[idx
- 1].tag
= BBFUNC_PTR
;
2424 bb
->labels
[idx
- 1].u
.fn_ptr
= cback
;
2425 bb
->labels
[idx
- 1].data
= data
;
2429 buttonbar_set_label (Dlg_head
*h
, int idx
, const char *text
, voidfn cback
)
2431 WButtonBar
*bb
= find_buttonbar (h
);
2436 assert (cback
!= (voidfn
) 0);
2437 set_label_text (bb
, idx
, text
);
2438 bb
->labels
[idx
- 1].tag
= BBFUNC_VOID
;
2439 bb
->labels
[idx
- 1].u
.fn_void
= cback
;
2443 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2445 bb
->visible
= visible
;
2449 buttonbar_redraw (Dlg_head
*h
)
2451 WButtonBar
*bb
= find_buttonbar (h
);
2456 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2460 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2462 WGroupbox
*g
= (WGroupbox
*) w
;
2469 return MSG_NOT_HANDLED
;
2472 attrset (COLOR_NORMAL
);
2473 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2474 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2477 attrset (COLOR_HOT_NORMAL
);
2478 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2479 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2483 case WIDGET_DESTROY
:
2488 return default_proc (msg
, parm
);
2493 groupbox_new (int x
, int y
, int width
, int height
, const char *title
)
2495 WGroupbox
*g
= g_new (WGroupbox
, 1);
2497 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2499 g
->widget
.options
&= ~W_WANT_CURSOR
;
2500 widget_want_hotkey (g
->widget
, 0);
2502 /* Strip existing spaces, add one space before and after the title */
2505 t
= g_strstrip (g_strdup (title
));
2506 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);