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>
46 #include "key.h" /* XCTRL and ALT macros */
47 #include "profile.h" /* for history loading and saving */
48 #include "wtools.h" /* For common_dialog_repaint() */
49 #include "main.h" /* for `slow_terminal' */
51 #define HISTORY_FILE_NAME ".mc/history"
55 int visible
; /* Is it visible? */
58 enum { BBFUNC_NONE
, BBFUNC_VOID
, BBFUNC_PTR
} tag
;
67 static int button_event (Gpm_Event
*event
, void *);
72 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
74 Dlg_head
*h
= w
->parent
;
79 : DLG_HOT_NORMALC (h
))
86 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
88 WButton
*b
= (WButton
*) w
;
92 Dlg_head
*h
= b
->widget
.parent
;
97 * Don't let the default button steal Enter from the current
98 * button. This is a workaround for the flawed event model
99 * when hotkeys are sent to all widgets before the key is
100 * handled by the current widget.
102 if (parm
== '\n' && h
->current
== &b
->widget
) {
103 button_callback (w
, WIDGET_KEY
, ' ');
107 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
108 button_callback (w
, WIDGET_KEY
, ' ');
112 if (b
->hotkey
== tolower (parm
)) {
113 button_callback (w
, WIDGET_KEY
, ' ');
117 return MSG_NOT_HANDLED
;
120 if (parm
!= ' ' && parm
!= '\n')
121 return MSG_NOT_HANDLED
;
124 stop
= (*b
->callback
) (b
->action
);
125 if (!b
->callback
|| stop
) {
126 h
->ret_value
= b
->action
;
147 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
153 if (msg
== WIDGET_UNFOCUS
)
155 else if (msg
== WIDGET_FOCUS
)
160 g_snprintf (buf
, sizeof (buf
), "[< %s >]", b
->text
);
164 g_snprintf (buf
, sizeof (buf
), "[ %s ]", b
->text
);
168 g_snprintf (buf
, sizeof (buf
), "[%s]", b
->text
);
178 widget_selectcolor (w
, b
->selected
, FALSE
);
179 widget_move (w
, 0, 0);
183 if (b
->hotpos
>= 0) {
184 widget_selectcolor (w
, b
->selected
, TRUE
);
185 widget_move (w
, 0, b
->hotpos
+ off
);
186 addch ((unsigned char) b
->text
[b
->hotpos
]);
195 return default_proc (msg
, parm
);
200 button_event (Gpm_Event
*event
, void *data
)
204 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
205 Dlg_head
*h
=b
->widget
.parent
;
206 dlg_select_widget (b
);
207 if (event
->type
& GPM_UP
){
208 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
209 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
217 button_len (const char *text
, unsigned int flags
)
219 int ret
= strlen (text
);
238 * Locate the hotkey and remove it from the button text. Assuming that
239 * the button text is g_malloc()ed, we can safely change and shorten it.
242 button_scan_hotkey (WButton
*b
)
244 char *cp
= strchr (b
->text
, '&');
246 if (cp
!= NULL
&& cp
[1] != '\0') {
247 g_strlcpy (cp
, cp
+ 1, strlen (cp
));
248 b
->hotkey
= tolower ((unsigned char) *cp
);
249 b
->hotpos
= cp
- b
->text
;
254 button_new (int y
, int x
, int action
, int flags
, const char *text
,
257 WButton
*b
= g_new (WButton
, 1);
259 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
260 button_callback
, button_event
);
265 b
->text
= g_strdup (text
);
266 b
->callback
= callback
;
267 widget_want_hotkey (b
->widget
, 1);
271 button_scan_hotkey(b
);
276 button_get_text (WButton
*b
)
282 button_set_text (WButton
*b
, const char *text
)
285 b
->text
= g_strdup (text
);
286 b
->widget
.cols
= button_len (text
, b
->flags
);
287 button_scan_hotkey(b
);
288 dlg_redraw (b
->widget
.parent
);
292 /* Radio button widget */
293 static int radio_event (Gpm_Event
*event
, void *);
296 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
298 WRadio
*r
= (WRadio
*) w
;
300 Dlg_head
*h
= r
->widget
.parent
;
305 int i
, lp
= tolower (parm
);
308 for (i
= 0; i
< r
->count
; i
++) {
309 cp
= strchr (r
->texts
[i
], '&');
310 if (cp
!= NULL
&& cp
[1] != '\0') {
311 int c
= tolower ((unsigned char) cp
[1]);
318 radio_callback (w
, WIDGET_KEY
, ' ');
323 return MSG_NOT_HANDLED
;
329 (*h
->callback
) (h
, DLG_ACTION
, 0);
330 radio_callback (w
, WIDGET_FOCUS
, ' ');
339 return MSG_NOT_HANDLED
;
343 if (r
->count
- 1 > r
->pos
) {
348 return MSG_NOT_HANDLED
;
351 (*h
->callback
) (h
, DLG_ACTION
, 0);
352 radio_callback (w
, WIDGET_FOCUS
, ' ');
353 widget_move (&r
->widget
, r
->pos
, 1);
359 for (i
= 0; i
< r
->count
; i
++) {
360 register const char *cp
;
361 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
362 widget_selectcolor (w
, focused
, FALSE
);
363 widget_move (&r
->widget
, i
, 0);
365 tty_printf ("(%c) ", (r
->sel
== i
) ? '*' : ' ');
366 for (cp
= r
->texts
[i
]; *cp
; cp
++) {
368 widget_selectcolor (w
, focused
, TRUE
);
370 widget_selectcolor (w
, focused
, FALSE
);
378 return default_proc (msg
, parm
);
383 radio_event (Gpm_Event
*event
, void *data
)
388 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
389 Dlg_head
*h
= r
->widget
.parent
;
391 r
->pos
= event
->y
- 1;
392 dlg_select_widget (r
);
393 if (event
->type
& GPM_UP
){
394 radio_callback (w
, WIDGET_KEY
, ' ');
395 radio_callback (w
, WIDGET_FOCUS
, 0);
396 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
404 radio_new (int y
, int x
, int count
, const char **texts
)
406 WRadio
*r
= g_new (WRadio
, 1);
409 /* Compute the longest string */
411 for (i
= 0; i
< count
; i
++){
412 m
= strlen (texts
[i
]);
417 init_widget (&r
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
423 widget_want_hotkey (r
->widget
, 1);
429 /* Checkbutton widget */
431 static int check_event (Gpm_Event
*event
, void *);
434 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
436 WCheck
*c
= (WCheck
*) w
;
437 Dlg_head
*h
= c
->widget
.parent
;
441 if (c
->hotkey
== parm
442 || (c
->hotkey
>= 'a' && c
->hotkey
<= 'z'
443 && c
->hotkey
- 32 == parm
)) {
444 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
447 return MSG_NOT_HANDLED
;
451 return MSG_NOT_HANDLED
;
453 c
->state
^= C_CHANGE
;
454 (*h
->callback
) (h
, DLG_ACTION
, 0);
455 check_callback (w
, WIDGET_FOCUS
, ' ');
459 widget_move (&c
->widget
, 0, 1);
465 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
466 widget_move (&c
->widget
, 0, 0);
467 tty_printf ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
469 if (c
->hotpos
>= 0) {
470 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, TRUE
);
471 widget_move (&c
->widget
, 0, +c
->hotpos
+ 4);
472 addch ((unsigned char) c
->text
[c
->hotpos
]);
481 return default_proc (msg
, parm
);
486 check_event (Gpm_Event
*event
, void *data
)
491 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
492 Dlg_head
*h
= c
->widget
.parent
;
494 dlg_select_widget (c
);
495 if (event
->type
& GPM_UP
){
496 check_callback (w
, WIDGET_KEY
, ' ');
497 check_callback (w
, WIDGET_FOCUS
, 0);
498 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
506 check_new (int y
, int x
, int state
, const char *text
)
508 WCheck
*c
= g_new (WCheck
, 1);
512 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
513 check_callback
, check_event
);
514 c
->state
= state
? C_BOOL
: 0;
515 c
->text
= g_strdup (text
);
518 widget_want_hotkey (c
->widget
, 1);
520 /* Scan for the hotkey */
521 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
528 c
->hotkey
= tolower ((unsigned char) *s
);
529 c
->hotpos
= t
- c
->text
;
541 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
543 WLabel
*l
= (WLabel
*) w
;
544 Dlg_head
*h
= l
->widget
.parent
;
550 /* We don't want to get the focus */
552 return MSG_NOT_HANDLED
;
556 char *p
= l
->text
, *q
, c
= 0;
563 attrset (DEFAULT_COLOR
);
565 attrset (DLG_NORMALC (h
));
569 q
= strchr (p
, '\n');
574 widget_move (&l
->widget
, y
, 0);
575 tty_printf ("%s", p
);
576 xlen
= l
->widget
.cols
- strlen (p
);
578 tty_printf ("%*s", xlen
, " ");
593 return default_proc (msg
, parm
);
598 label_set_text (WLabel
*label
, const char *text
)
600 int newcols
= label
->widget
.cols
;
602 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
603 return; /* Flickering is not nice */
605 g_free (label
->text
);
608 label
->text
= g_strdup (text
);
609 if (label
->auto_adjust_cols
) {
610 newcols
= strlen (text
);
611 if (newcols
> label
->widget
.cols
)
612 label
->widget
.cols
= newcols
;
617 if (label
->widget
.parent
)
618 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
620 if (newcols
< label
->widget
.cols
)
621 label
->widget
.cols
= newcols
;
625 label_new (int y
, int x
, const char *text
)
630 /* Multiline labels are immutable - no need to compute their sizes */
631 if (!text
|| strchr(text
, '\n'))
634 width
= strlen (text
);
636 l
= g_new (WLabel
, 1);
637 init_widget (&l
->widget
, y
, x
, 1, width
, label_callback
, NULL
);
638 l
->text
= text
? g_strdup (text
) : 0;
639 l
->auto_adjust_cols
= 1;
641 widget_want_cursor (l
->widget
, 0);
646 /* Gauge widget (progress indicator) */
647 /* Currently width is hardcoded here for text mode */
651 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
653 WGauge
*g
= (WGauge
*) w
;
654 Dlg_head
*h
= g
->widget
.parent
;
656 if (msg
== WIDGET_INIT
)
659 /* We don't want to get the focus */
660 if (msg
== WIDGET_FOCUS
)
661 return MSG_NOT_HANDLED
;
663 if (msg
== WIDGET_DRAW
){
664 widget_move (&g
->widget
, 0, 0);
665 attrset (DLG_NORMALC (h
));
667 tty_printf ("%*s", gauge_len
, "");
669 int percentage
, columns
;
670 long total
= g
->max
, done
= g
->current
;
672 if (total
<= 0 || done
< 0) {
678 while (total
> 65535) {
682 percentage
= (200 * done
/ total
+ 1) / 2;
683 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
685 attrset (GAUGE_COLOR
);
686 tty_printf ("%*s", (int) columns
, "");
687 attrset (DLG_NORMALC (h
));
688 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
692 return default_proc (msg
, parm
);
696 gauge_set_value (WGauge
*g
, int max
, int current
)
698 if (g
->current
== current
&& g
->max
== max
)
699 return; /* Do not flicker */
701 max
= 1; /* I do not like division by zero :) */
703 g
->current
= current
;
705 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
709 gauge_show (WGauge
*g
, int shown
)
711 if (g
->shown
== shown
)
714 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
718 gauge_new (int y
, int x
, int shown
, int max
, int current
)
720 WGauge
*g
= g_new (WGauge
, 1);
722 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
725 max
= 1; /* I do not like division by zero :) */
727 g
->current
= current
;
728 widget_want_cursor (g
->widget
, 0);
735 /* {{{ history button */
737 #define LARGE_HISTORY_BUTTON 1
739 #ifdef LARGE_HISTORY_BUTTON
740 # define HISTORY_BUTTON_WIDTH 3
742 # define HISTORY_BUTTON_WIDTH 1
745 #define should_show_history_button(in) \
746 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
748 static void draw_history_button (WInput
* in
)
751 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
752 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
753 #ifdef LARGE_HISTORY_BUTTON
756 h
= in
->widget
.parent
;
758 attrset (NORMALC
); /* button has the same color as other buttons */
760 attrset (HOT_NORMALC
);
762 attrset (NORMAL_COLOR
);
764 /* Too distracting: attrset (MARKED_COLOR); */
766 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
770 attrset (MARKED_COLOR
);
775 /* }}} history button */
778 /* Input widgets now have a global kill ring */
779 /* Pointer to killed data */
780 static char *kill_buffer
= 0;
783 update_input (WInput
*in
, int clear_first
)
788 int buf_len
= strlen (in
->buffer
);
790 if (should_show_history_button (in
))
791 has_history
= HISTORY_BUTTON_WIDTH
;
793 if (in
->disable_update
)
796 /* Make the point visible */
797 if ((in
->point
< in
->first_shown
) ||
798 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
799 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
800 if (in
->first_shown
< 0)
804 /* Adjust the mark */
805 if (in
->mark
> buf_len
)
809 draw_history_button (in
);
813 widget_move (&in
->widget
, 0, 0);
814 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
816 widget_move (&in
->widget
, 0, 0);
818 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
819 c
= in
->buffer
[j
++];
820 c
= is_printable (c
) ? c
: '.';
825 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
832 winput_set_origin (WInput
*in
, int x
, int field_len
)
835 in
->field_len
= in
->widget
.cols
= field_len
;
836 update_input (in
, 0);
839 /* {{{ history saving and loading */
841 int num_history_items_recorded
= 60;
844 This loads and saves the history of an input line to and from the
845 widget. It is called with the widgets history name on creation of the
846 widget, and returns the GList list. It stores histories in the file
847 ~/.mc/history in using the profile code.
849 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
850 function) then input_new assigns the default text to be the last text
851 entered, or "" if not found.
855 history_get (const char *input_name
)
863 if (!num_history_items_recorded
) /* this is how to disable */
869 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
871 char key_name
[BUF_TINY
];
872 char this_entry
[BUF_LARGE
];
873 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
874 GetPrivateProfileString (input_name
, key_name
, "", this_entry
,
875 sizeof (this_entry
), profile
);
879 hist
= list_append_unique (hist
, g_strdup (this_entry
));
883 /* return pointer to the last entry in the list */
884 hist
= g_list_last (hist
);
890 history_put (const char *input_name
, GList
*h
)
904 if (!num_history_items_recorded
) /* this is how to disable */
907 profile
= concat_dir_and_file (home_dir
, HISTORY_FILE_NAME
);
909 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
912 /* Make sure the history is only readable by the user */
913 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
918 /* go to end of list */
921 /* go back 60 places */
922 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
923 h
= g_list_previous (h
);
926 profile_clean_section (input_name
, profile
);
928 /* dump histories into profile */
929 for (i
= 0; h
; h
= g_list_next (h
)) {
932 text
= (char *) h
->data
;
934 /* We shouldn't have null entries, but let's be sure */
936 char key_name
[BUF_TINY
];
937 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
938 WritePrivateProfileString (input_name
, key_name
, text
,
946 /* }}} history saving and loading */
949 /* {{{ history display */
954 static const char *history_title
= NULL
;
956 if (history_title
== NULL
)
957 history_title
= _(" History ");
958 return history_title
;
961 static WLEntry
*listbox_select_pos (WListbox
*l
, WLEntry
*base
, int
964 static inline cb_ret_t
965 listbox_fwd (WListbox
*l
)
967 if (l
->current
!= l
->list
->prev
){
968 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
971 return MSG_NOT_HANDLED
;
975 show_hist (GList
*history
, int widget_x
, int widget_y
)
978 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
982 WListbox
*query_list
;
988 z
= g_list_first (history
);
991 if ((i
= strlen ((char *) hi
->data
)) > maxlen
)
994 hi
= g_list_next (hi
);
999 if (h
<= y
|| y
> LINES
- 6) {
1004 h
= min (h
, LINES
- y
);
1011 if ((w
= maxlen
+ 4) + x
> COLS
) {
1017 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
1018 i18n_htitle (), DLG_COMPACT
);
1019 query_list
= listbox_new (1, 1, w
- 2, h
- 2, 0);
1020 add_widget (query_dlg
, query_list
);
1025 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1026 hi
= g_list_next (hi
);
1028 while (listbox_fwd (query_list
));
1030 /* traverse backwards */
1031 hi
= g_list_last (history
);
1033 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1034 hi
= g_list_previous (hi
);
1037 run_dlg (query_dlg
);
1039 if (query_dlg
->ret_value
!= B_CANCEL
) {
1040 listbox_get_current (query_list
, &q
, NULL
);
1044 destroy_dlg (query_dlg
);
1048 static void do_show_hist (WInput
* in
)
1051 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1053 assign_text (in
, r
);
1058 /* }}} history display */
1061 input_destroy (WInput
*in
)
1064 fprintf (stderr
, "Internal error: null Input *\n");
1071 if (!in
->is_password
) /* don't save passwords ;-) */
1072 history_put (in
->history_name
, in
->history
);
1074 in
->history
= g_list_first (in
->history
);
1075 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1076 g_list_free (in
->history
);
1079 g_free (in
->buffer
);
1080 free_completions (in
);
1081 g_free (in
->history_name
);
1085 input_disable_update (WInput
*in
)
1087 in
->disable_update
++;
1091 input_enable_update (WInput
*in
)
1093 in
->disable_update
--;
1094 update_input (in
, 0);
1097 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1100 push_history (WInput
*in
, const char *text
)
1103 /* input widget where urls with passwords are entered without any
1105 static const char *password_input_fields
[] = {
1106 N_(" Link to a remote machine "),
1107 N_(" FTP to machine "),
1108 N_(" SMB link to machine ")
1116 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1117 password_input_fields
[i
] = _(password_input_fields
[i
]);
1120 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1125 /* Avoid duplicated entries */
1126 in
->history
= g_list_last (in
->history
);
1127 if (!strcmp ((char *) in
->history
->data
, text
))
1131 t
= g_strdup (text
);
1133 if (in
->history_name
) {
1134 p
= in
->history_name
+ 3;
1135 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1136 if (strcmp (p
, password_input_fields
[i
]) == 0)
1138 if (i
< ELEMENTS (password_input_fields
))
1139 strip_password (t
, 0);
1141 strip_password (t
, 1);
1144 in
->history
= list_append_unique (in
->history
, t
);
1152 /* Cleans the input line and adds the current text to the history */
1154 new_input (WInput
*in
)
1157 push_history (in
, in
->buffer
);
1162 free_completions (in
);
1163 update_input (in
, 0);
1167 insert_char (WInput
*in
, int c_code
)
1172 return MSG_NOT_HANDLED
;
1175 if (strlen (in
->buffer
)+1 == (size_t) in
->current_max_len
){
1176 /* Expand the buffer */
1177 char *narea
= g_realloc (in
->buffer
, in
->current_max_len
+ in
->field_len
);
1180 in
->current_max_len
+= in
->field_len
;
1183 if (strlen (in
->buffer
)+1 < (size_t) in
->current_max_len
){
1184 size_t l
= strlen (&in
->buffer
[in
->point
]);
1185 for (i
= l
+1; i
> 0; i
--)
1186 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1187 in
->buffer
[in
->point
] = c_code
;
1194 beginning_of_line (WInput
*in
)
1200 end_of_line (WInput
*in
)
1202 in
->point
= strlen (in
->buffer
);
1206 backward_char (WInput
*in
)
1213 forward_char (WInput
*in
)
1215 if (in
->buffer
[in
->point
])
1220 forward_word (WInput
* in
)
1222 char *p
= in
->buffer
+ in
->point
;
1225 && (isspace ((unsigned char) *p
)
1226 || ispunct ((unsigned char) *p
)))
1228 while (*p
&& isalnum ((unsigned char) *p
))
1230 in
->point
= p
- in
->buffer
;
1234 backward_word (WInput
*in
)
1236 char *p
= in
->buffer
+ in
->point
;
1238 while (p
- 1 > in
->buffer
- 1 && (isspace ((unsigned char) *(p
- 1))
1239 || ispunct ((unsigned char)
1242 while (p
- 1 > in
->buffer
- 1 && isalnum ((unsigned char) *(p
- 1)))
1244 in
->point
= p
- in
->buffer
;
1248 key_left (WInput
*in
)
1254 key_ctrl_left (WInput
*in
)
1260 key_right (WInput
*in
)
1266 key_ctrl_right (WInput
*in
)
1271 backward_delete (WInput
*in
)
1277 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1278 in
->buffer
[i
-1] = in
->buffer
[i
];
1284 delete_char (WInput
*in
)
1288 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1289 in
->buffer
[i
] = in
->buffer
[i
+1];
1294 copy_region (WInput
*in
, int x_first
, int x_last
)
1296 int first
= min (x_first
, x_last
);
1297 int last
= max (x_first
, x_last
);
1302 g_free (kill_buffer
);
1304 kill_buffer
= g_strndup(in
->buffer
+first
,last
-first
);
1308 delete_region (WInput
*in
, int x_first
, int x_last
)
1310 int first
= min (x_first
, x_last
);
1311 int last
= max (x_first
, x_last
);
1312 size_t len
= strlen (&in
->buffer
[last
]) + 1;
1316 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1321 kill_word (WInput
*in
)
1323 int old_point
= in
->point
;
1327 new_point
= in
->point
;
1328 in
->point
= old_point
;
1330 copy_region (in
, old_point
, new_point
);
1331 delete_region (in
, old_point
, new_point
);
1336 back_kill_word (WInput
*in
)
1338 int old_point
= in
->point
;
1342 new_point
= in
->point
;
1343 in
->point
= old_point
;
1345 copy_region (in
, old_point
, new_point
);
1346 delete_region (in
, old_point
, new_point
);
1351 set_mark (WInput
*in
)
1353 in
->mark
= in
->point
;
1357 kill_save (WInput
*in
)
1359 copy_region (in
, in
->mark
, in
->point
);
1363 kill_region (WInput
*in
)
1366 delete_region (in
, in
->point
, in
->mark
);
1376 for (p
= kill_buffer
; *p
; p
++)
1377 insert_char (in
, *p
);
1381 kill_line (WInput
*in
)
1383 g_free (kill_buffer
);
1384 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1385 in
->buffer
[in
->point
] = 0;
1389 assign_text (WInput
*in
, const char *text
)
1391 free_completions (in
);
1392 g_free (in
->buffer
);
1393 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1394 in
->current_max_len
= strlen (in
->buffer
) + 1;
1395 in
->point
= strlen (in
->buffer
);
1401 hist_prev (WInput
*in
)
1406 if (in
->need_push
) {
1407 switch (push_history (in
, in
->buffer
)) {
1409 in
->history
= g_list_previous (in
->history
);
1412 if (in
->history
->prev
)
1413 in
->history
= g_list_previous (in
->history
);
1418 } else if (in
->history
->prev
)
1419 in
->history
= g_list_previous (in
->history
);
1422 assign_text (in
, (char *) in
->history
->data
);
1427 hist_next (WInput
*in
)
1429 if (in
->need_push
) {
1430 switch (push_history (in
, in
->buffer
)) {
1432 assign_text (in
, "");
1442 if (!in
->history
->next
) {
1443 assign_text (in
, "");
1447 in
->history
= g_list_next (in
->history
);
1448 assign_text (in
, (char *) in
->history
->data
);
1452 static const struct {
1454 void (*fn
)(WInput
*in
);
1457 { XCTRL('a'), beginning_of_line
},
1458 { KEY_HOME
, beginning_of_line
},
1459 { KEY_A1
, beginning_of_line
},
1460 { ALT ('<'), beginning_of_line
},
1461 { XCTRL('e'), end_of_line
},
1462 { KEY_END
, end_of_line
},
1463 { KEY_C1
, end_of_line
},
1464 { ALT ('>'), end_of_line
},
1465 { KEY_LEFT
, key_left
},
1466 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1467 { XCTRL('b'), backward_char
},
1468 { ALT('b'), backward_word
},
1469 { KEY_RIGHT
, key_right
},
1470 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1471 { XCTRL('f'), forward_char
},
1472 { ALT('f'), forward_word
},
1475 { KEY_BACKSPACE
, backward_delete
},
1476 { KEY_DC
, delete_char
},
1477 { ALT('d'), kill_word
},
1478 { ALT(KEY_BACKSPACE
), back_kill_word
},
1480 /* Region manipulation */
1482 { XCTRL('w'), kill_region
},
1483 { ALT('w'), kill_save
},
1484 { XCTRL('y'), yank
},
1485 { XCTRL('k'), kill_line
},
1488 { ALT('p'), hist_prev
},
1489 { ALT('n'), hist_next
},
1490 { ALT('h'), do_show_hist
},
1493 { ALT('\t'), complete
},
1498 /* This function is a test for a special input key used in complete.c */
1499 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1500 and 2 if it is a complete key */
1502 is_in_input_map (WInput
*in
, int c_code
)
1508 for (i
= 0; input_map
[i
].fn
; i
++)
1509 if (c_code
== input_map
[i
].key_code
) {
1510 if (input_map
[i
].fn
== complete
)
1519 port_region_marked_for_delete (WInput
*in
)
1527 handle_char (WInput
*in
, int c_code
)
1532 v
= MSG_NOT_HANDLED
;
1535 free_completions (in
);
1536 v
= insert_char (in
, c_code
);
1537 update_input (in
, 1);
1542 for (i
= 0; input_map
[i
].fn
; i
++){
1543 if (c_code
== input_map
[i
].key_code
){
1544 if (input_map
[i
].fn
!= complete
)
1545 free_completions (in
);
1546 (*input_map
[i
].fn
)(in
);
1551 if (!input_map
[i
].fn
){
1552 if (c_code
> 255 || !is_printable (c_code
))
1553 return MSG_NOT_HANDLED
;
1555 port_region_marked_for_delete (in
);
1557 free_completions (in
);
1558 v
= insert_char (in
, c_code
);
1560 update_input (in
, 1);
1564 /* Inserts text in input line */
1566 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1568 input_disable_update (in
);
1570 handle_char (in
, *text
++);
1571 if (insert_extra_space
)
1572 handle_char (in
, ' ');
1573 input_enable_update (in
);
1574 update_input (in
, 1);
1578 input_set_point (WInput
*in
, int pos
)
1580 if (pos
> in
->current_max_len
)
1581 pos
= in
->current_max_len
;
1582 if (pos
!= in
->point
)
1583 free_completions (in
);
1585 update_input (in
, 1);
1589 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1591 WInput
*in
= (WInput
*) w
;
1596 if (parm
== XCTRL ('q')) {
1598 v
= handle_char (in
, ascii_alpha_to_cntrl (mi_getch ()));
1603 /* Keys we want others to handle */
1604 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1605 || parm
== KEY_F (10) || parm
== XCTRL ('g') || parm
== '\n')
1606 return MSG_NOT_HANDLED
;
1608 /* When pasting multiline text, insert literal Enter */
1609 if ((parm
& ~KEY_M_MASK
) == '\n') {
1611 v
= handle_char (in
, '\n');
1616 return handle_char (in
, parm
);
1619 case WIDGET_UNFOCUS
:
1621 update_input (in
, 0);
1625 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1628 case WIDGET_DESTROY
:
1633 return default_proc (msg
, parm
);
1638 input_event (Gpm_Event
* event
, void *data
)
1642 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1643 dlg_select_widget (in
);
1645 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1646 && should_show_history_button (in
)) {
1649 in
->point
= strlen (in
->buffer
);
1650 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1651 in
->point
= event
->x
- in
->first_shown
- 1;
1655 update_input (in
, 1);
1661 input_new (int y
, int x
, int color
, int len
, const char *def_text
,
1662 const char *histname
)
1664 WInput
*in
= g_new (WInput
, 1);
1665 int initial_buffer_len
;
1667 init_widget (&in
->widget
, y
, x
, 1, len
, input_callback
, input_event
);
1671 in
->history_name
= 0;
1674 in
->history_name
= g_strdup (histname
);
1675 in
->history
= history_get (histname
);
1682 if (def_text
== INPUT_LAST_TEXT
) {
1685 if (in
->history
->data
)
1686 def_text
= (char *) in
->history
->data
;
1688 initial_buffer_len
= 1 + max ((size_t) len
, strlen (def_text
));
1689 in
->widget
.options
|= W_IS_INPUT
;
1690 in
->completions
= NULL
;
1691 in
->completion_flags
=
1692 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
|
1693 INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
;
1694 in
->current_max_len
= initial_buffer_len
;
1695 in
->buffer
= g_malloc (initial_buffer_len
);
1697 in
->field_len
= len
;
1699 in
->first_shown
= 0;
1700 in
->disable_update
= 0;
1703 in
->is_password
= 0;
1705 strcpy (in
->buffer
, def_text
);
1706 in
->point
= strlen (in
->buffer
);
1711 /* Listbox widget */
1713 /* Should draw the scrollbar, but currently draws only
1714 * indications that there is more information
1716 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1719 listbox_drawscroll (WListbox
*l
)
1723 int max_line
= l
->height
-1;
1725 /* Are we at the top? */
1726 widget_move (&l
->widget
, 0, l
->width
);
1727 if (l
->list
== l
->top
)
1732 /* Are we at the bottom? */
1733 widget_move (&l
->widget
, max_line
, l
->width
);
1734 top
= listbox_cdiff (l
->list
, l
->top
);
1735 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1740 /* Now draw the nice relative pointer */
1742 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1746 for (i
= 1; i
< max_line
; i
++){
1747 widget_move (&l
->widget
, i
, l
->width
);
1756 listbox_draw (WListbox
*l
, int focused
)
1761 Dlg_head
*h
= l
->widget
.parent
;
1762 int normalc
= DLG_NORMALC (h
);
1767 selc
= DLG_FOCUSC (h
);
1769 selc
= DLG_HOT_FOCUSC (h
);
1773 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1775 /* Display the entry */
1776 if (e
== l
->current
&& sel_line
== -1){
1782 widget_move (&l
->widget
, i
, 0);
1784 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1790 tty_printf (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1792 l
->cursor_y
= sel_line
;
1796 listbox_drawscroll (l
);
1799 /* Returns the number of items between s and e,
1800 must be on the same linked list */
1802 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1806 for (count
= 0; s
!= e
; count
++)
1812 listbox_check_hotkey (WListbox
*l
, int key
)
1824 /* If we didn't find anything, return */
1825 if (i
&& e
== l
->list
)
1828 if (e
->hotkey
== key
)
1836 /* Used only for display updating, for avoiding line at a time scroll */
1838 listbox_select_last (WListbox
*l
, int set_top
)
1841 l
->current
= l
->list
->prev
;
1842 l
->pos
= l
->count
- 1;
1844 l
->top
= l
->list
->prev
;
1849 listbox_remove_list (WListbox
*l
)
1858 while (l
->count
--) {
1864 l
->pos
= l
->count
= 0;
1865 l
->list
= l
->top
= l
->current
= 0;
1869 * bor 30.10.96: added force flag to remove *last* entry as well
1870 * bor 30.10.96: corrected selection bug if last entry was removed
1874 listbox_remove_current (WListbox
*l
, int force
)
1878 /* Ok, note: this won't allow for emtpy lists */
1879 if (!force
&& (!l
->count
|| l
->count
== 1))
1886 l
->current
->next
->prev
= l
->current
->prev
;
1887 l
->current
->prev
->next
= l
->current
->next
;
1888 if (p
->next
== l
->list
) {
1889 l
->current
= p
->prev
;
1893 l
->current
= p
->next
;
1896 l
->list
= l
->top
= p
->next
;
1899 l
->list
= l
->top
= l
->current
= 0;
1906 /* Makes *e the selected entry (sets current and pos) */
1908 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1917 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1925 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1926 l
->top
= l
->top
->next
;
1928 l
->top
= l
->current
;
1934 /* If we are unable to find it, set decent values */
1935 l
->current
= l
->top
= l
->list
;
1939 /* Selects from base the pos element */
1941 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1943 WLEntry
*last
= l
->list
->prev
;
1955 static inline cb_ret_t
1956 listbox_back (WListbox
*l
)
1959 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1962 return MSG_NOT_HANDLED
;
1965 /* Return MSG_HANDLED if we want a redraw */
1967 listbox_key (WListbox
*l
, int key
)
1973 return MSG_NOT_HANDLED
;
1979 l
->current
= l
->top
= l
->list
;
1986 l
->current
= l
->top
= l
->list
->prev
;
1987 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1988 l
->top
= l
->top
->prev
;
1989 l
->pos
= l
->count
- 1;
2004 for (i
= 0; i
< l
->height
-1; i
++)
2005 j
|= listbox_fwd (l
);
2006 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2010 for (i
= 0; i
< l
->height
-1; i
++)
2011 j
|= listbox_back (l
);
2012 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2014 return MSG_NOT_HANDLED
;
2018 listbox_destroy (WListbox
*l
)
2020 WLEntry
*n
, *p
= l
->list
;
2023 for (i
= 0; i
< l
->count
; i
++){
2032 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2034 WListbox
*l
= (WListbox
*) w
;
2037 Dlg_head
*h
= l
->widget
.parent
;
2044 if ((e
= listbox_check_hotkey (l
, parm
)) != NULL
) {
2047 listbox_select_entry (l
, e
);
2050 action
= (*l
->cback
) (l
);
2052 action
= LISTBOX_DONE
;
2054 if (action
== LISTBOX_DONE
) {
2055 h
->ret_value
= B_ENTER
;
2060 return MSG_NOT_HANDLED
;
2063 if ((ret_code
= listbox_key (l
, parm
)))
2064 listbox_draw (l
, 1);
2068 widget_move (&l
->widget
, l
->cursor_y
, 0);
2072 case WIDGET_UNFOCUS
:
2074 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2077 case WIDGET_DESTROY
:
2078 listbox_destroy (l
);
2082 return default_proc (msg
, parm
);
2087 listbox_event (Gpm_Event
*event
, void *data
)
2093 Dlg_head
*h
= l
->widget
.parent
;
2096 if (event
->type
& GPM_DOWN
)
2097 dlg_select_widget (l
);
2100 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2101 if (event
->x
< 0 || event
->x
>= l
->width
)
2104 for (i
= -event
->y
; i
>= 0; i
--)
2106 else if (event
->y
> l
->height
)
2107 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2110 listbox_select_entry (l
,
2111 listbox_select_pos (l
, l
->top
,
2114 /* We need to refresh ourselves since the dialog manager doesn't */
2115 /* know about this event */
2116 listbox_callback (w
, WIDGET_DRAW
, 0);
2122 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2125 if (event
->x
< 0 || event
->x
>= l
->width
)
2127 if (event
->y
< 1 || event
->y
> l
->height
)
2130 dlg_select_widget (l
);
2131 listbox_select_entry (l
,
2132 listbox_select_pos (l
, l
->top
,
2136 action
= (*l
->cback
) (l
);
2138 action
= LISTBOX_DONE
;
2140 if (action
== LISTBOX_DONE
) {
2141 h
->ret_value
= B_ENTER
;
2150 listbox_new (int y
, int x
, int width
, int height
, lcback callback
)
2152 WListbox
*l
= g_new (WListbox
, 1);
2154 init_widget (&l
->widget
, y
, x
, height
, width
,
2155 listbox_callback
, listbox_event
);
2157 l
->list
= l
->top
= l
->current
= 0;
2165 l
->cback
= callback
;
2166 l
->allow_duplicates
= 1;
2167 l
->scrollbar
= slow_terminal
? 0 : 1;
2168 widget_want_hotkey (l
->widget
, 1);
2173 /* Listbox item adding function. They still lack a lot of functionality */
2175 /* 1.11.96 bor: added pos argument to control placement of new entry */
2177 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2185 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2187 e
->prev
= l
->list
->prev
;
2188 l
->list
->prev
->next
= e
;
2190 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2191 e
->next
= l
->current
;
2192 e
->prev
= l
->current
->prev
;
2193 l
->current
->prev
->next
= e
;
2194 l
->current
->prev
= e
;
2195 if (l
->list
== l
->current
) { /* move list one position down */
2199 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2200 e
->prev
= l
->current
;
2201 e
->next
= l
->current
->next
;
2202 l
->current
->next
->prev
= e
;
2203 l
->current
->next
= e
;
2204 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2205 WLEntry
*w
= l
->list
;
2207 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2209 if (w
->next
== l
->list
) {
2225 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2226 const char *text
, void *data
)
2233 if (!l
->allow_duplicates
)
2234 if (listbox_search_text (l
, text
))
2237 entry
= g_new (WLEntry
, 1);
2238 entry
->text
= g_strdup (text
);
2240 entry
->hotkey
= hotkey
;
2242 listbox_append_item (l
, entry
, pos
);
2247 /* Selects the nth entry in the listbox */
2249 listbox_select_by_number (WListbox
*l
, int n
)
2251 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2255 listbox_search_text (WListbox
*l
, const char *text
)
2264 if(!strcmp (e
->text
, text
))
2267 } while (e
!=l
->list
);
2272 /* Returns the current string text as well as the associated extra data */
2274 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2280 if (string
&& l
->current
)
2281 *string
= l
->current
->text
;
2282 if (extra
&& l
->current
)
2283 *extra
= l
->current
->data
;
2286 /* returns TRUE if a function has been called, FALSE otherwise. */
2288 buttonbar_call (WButtonBar
*bb
, int i
)
2290 switch (bb
->labels
[i
].tag
) {
2294 bb
->labels
[i
].u
.fn_void ();
2297 bb
->labels
[i
].u
.fn_ptr (bb
->labels
[i
].data
);
2305 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2307 WButtonBar
*bb
= (WButtonBar
*) w
;
2312 return MSG_NOT_HANDLED
;
2315 for (i
= 0; i
< 10; i
++) {
2316 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2319 return MSG_NOT_HANDLED
;
2324 widget_move (&bb
->widget
, 0, 0);
2325 attrset (DEFAULT_COLOR
);
2326 tty_printf ("%-*s", bb
->widget
.cols
, "");
2327 for (i
= 0; i
< COLS
/ 8 && i
< 10; i
++) {
2328 widget_move (&bb
->widget
, 0, i
* 8);
2329 attrset (DEFAULT_COLOR
);
2330 tty_printf ("%d", i
+ 1);
2331 attrset (SELECTED_COLOR
);
2332 tty_printf ("%-*s", ((i
+ 1) * 8 == COLS
? 5 : 6),
2333 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2334 attrset (DEFAULT_COLOR
);
2336 attrset (SELECTED_COLOR
);
2339 case WIDGET_DESTROY
:
2340 for (i
= 0; i
< 10; i
++)
2341 g_free (bb
->labels
[i
].text
);
2345 return default_proc (msg
, parm
);
2350 buttonbar_event (Gpm_Event
*event
, void *data
)
2352 WButtonBar
*bb
= data
;
2355 if (!(event
->type
& GPM_UP
))
2359 button
= event
->x
/ 8;
2361 buttonbar_call (bb
, button
);
2366 buttonbar_new (int visible
)
2369 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2371 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2372 buttonbar_callback
, buttonbar_event
);
2374 bb
->visible
= visible
;
2375 for (i
= 0; i
< 10; i
++){
2376 bb
->labels
[i
].text
= NULL
;
2377 bb
->labels
[i
].tag
= BBFUNC_NONE
;
2379 widget_want_hotkey (bb
->widget
, 1);
2380 widget_want_cursor (bb
->widget
, 0);
2386 set_label_text (WButtonBar
* bb
, int index
, const char *text
)
2388 g_free (bb
->labels
[index
- 1].text
);
2390 bb
->labels
[index
- 1].text
= g_strdup (text
);
2393 /* Find ButtonBar widget in the dialog */
2395 find_buttonbar (Dlg_head
*h
)
2399 bb
= (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2404 buttonbar_clear_label (Dlg_head
*h
, int idx
)
2406 WButtonBar
*bb
= find_buttonbar (h
);
2411 set_label_text (bb
, idx
, "");
2412 bb
->labels
[idx
- 1].tag
= BBFUNC_NONE
;
2416 buttonbar_set_label_data (Dlg_head
*h
, int idx
, const char *text
, buttonbarfn cback
,
2419 WButtonBar
*bb
= find_buttonbar (h
);
2424 assert (cback
!= (buttonbarfn
) 0);
2425 set_label_text (bb
, idx
, text
);
2426 bb
->labels
[idx
- 1].tag
= BBFUNC_PTR
;
2427 bb
->labels
[idx
- 1].u
.fn_ptr
= cback
;
2428 bb
->labels
[idx
- 1].data
= data
;
2432 buttonbar_set_label (Dlg_head
*h
, int idx
, const char *text
, voidfn cback
)
2434 WButtonBar
*bb
= find_buttonbar (h
);
2439 assert (cback
!= (voidfn
) 0);
2440 set_label_text (bb
, idx
, text
);
2441 bb
->labels
[idx
- 1].tag
= BBFUNC_VOID
;
2442 bb
->labels
[idx
- 1].u
.fn_void
= cback
;
2446 buttonbar_set_visible (WButtonBar
*bb
, gboolean visible
)
2448 bb
->visible
= visible
;
2452 buttonbar_redraw (Dlg_head
*h
)
2454 WButtonBar
*bb
= find_buttonbar (h
);
2459 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2463 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2465 WGroupbox
*g
= (WGroupbox
*) w
;
2472 return MSG_NOT_HANDLED
;
2475 attrset (COLOR_NORMAL
);
2476 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2477 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2480 attrset (COLOR_HOT_NORMAL
);
2481 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2482 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2486 case WIDGET_DESTROY
:
2491 return default_proc (msg
, parm
);
2496 groupbox_new (int x
, int y
, int width
, int height
, const char *title
)
2498 WGroupbox
*g
= g_new (WGroupbox
, 1);
2500 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2502 g
->widget
.options
&= ~W_WANT_CURSOR
;
2503 widget_want_hotkey (g
->widget
, 0);
2505 /* Strip existing spaces, add one space before and after the title */
2508 t
= g_strstrip (g_strdup (title
));
2509 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);