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>
37 #include <mhl/types.h>
38 #include <mhl/memory.h>
39 #include <mhl/string.h>
48 #include "key.h" /* XCTRL and ALT macros */
49 #include "profile.h" /* for history loading and saving */
50 #include "wtools.h" /* For common_dialog_repaint() */
51 #include "main.h" /* for `slow_terminal' */
53 #define HISTORY_FILE_NAME ".mc/history"
57 int visible
; /* Is it visible? */
60 enum { BBFUNC_NONE
, BBFUNC_VOID
, BBFUNC_PTR
} tag
;
69 static int button_event (Gpm_Event
*event
, void *);
74 widget_selectcolor (Widget
*w
, gboolean focused
, gboolean hotkey
)
76 Dlg_head
*h
= w
->parent
;
81 : DLG_HOT_NORMALC (h
))
88 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
90 WButton
*b
= (WButton
*) w
;
94 Dlg_head
*h
= b
->widget
.parent
;
99 * Don't let the default button steal Enter from the current
100 * button. This is a workaround for the flawed event model
101 * when hotkeys are sent to all widgets before the key is
102 * handled by the current widget.
104 if (parm
== '\n' && h
->current
== &b
->widget
) {
105 button_callback (w
, WIDGET_KEY
, ' ');
109 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
110 button_callback (w
, WIDGET_KEY
, ' ');
114 if (b
->hotkey
== tolower (parm
)) {
115 button_callback (w
, WIDGET_KEY
, ' ');
119 return MSG_NOT_HANDLED
;
122 if (parm
!= ' ' && parm
!= '\n')
123 return MSG_NOT_HANDLED
;
126 stop
= (*b
->callback
) (b
->action
);
127 if (!b
->callback
|| stop
) {
128 h
->ret_value
= b
->action
;
149 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
155 if (msg
== WIDGET_UNFOCUS
)
157 else if (msg
== WIDGET_FOCUS
)
162 g_snprintf (buf
, sizeof (buf
), "[< %s >]", b
->text
);
166 g_snprintf (buf
, sizeof (buf
), "[ %s ]", b
->text
);
170 g_snprintf (buf
, sizeof (buf
), "[%s]", b
->text
);
180 widget_selectcolor (w
, b
->selected
, FALSE
);
181 widget_move (w
, 0, 0);
185 if (b
->hotpos
>= 0) {
186 widget_selectcolor (w
, b
->selected
, TRUE
);
187 widget_move (w
, 0, b
->hotpos
+ off
);
188 addch ((unsigned char) b
->text
[b
->hotpos
]);
197 return default_proc (msg
, parm
);
202 button_event (Gpm_Event
*event
, void *data
)
206 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
207 Dlg_head
*h
=b
->widget
.parent
;
208 dlg_select_widget (b
);
209 if (event
->type
& GPM_UP
){
210 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
211 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
219 button_len (const char *text
, unsigned int flags
)
221 int ret
= strlen (text
);
240 * Locate the hotkey and remove it from the button text. Assuming that
241 * the button text is g_malloc()ed, we can safely change and shorten it.
244 button_scan_hotkey (WButton
*b
)
246 char *cp
= strchr (b
->text
, '&');
248 if (cp
!= NULL
&& cp
[1] != '\0') {
249 g_strlcpy (cp
, cp
+ 1, strlen (cp
));
250 b
->hotkey
= tolower ((unsigned char) *cp
);
251 b
->hotpos
= cp
- b
->text
;
256 button_new (int y
, int x
, int action
, int flags
, const char *text
,
259 WButton
*b
= g_new (WButton
, 1);
261 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
262 button_callback
, button_event
);
267 b
->text
= g_strdup (text
);
268 b
->callback
= callback
;
269 widget_want_hotkey (b
->widget
, 1);
273 button_scan_hotkey(b
);
278 button_get_text (WButton
*b
)
284 button_set_text (WButton
*b
, const char *text
)
287 b
->text
= g_strdup (text
);
288 b
->widget
.cols
= button_len (text
, b
->flags
);
289 button_scan_hotkey(b
);
290 dlg_redraw (b
->widget
.parent
);
294 /* Radio button widget */
295 static int radio_event (Gpm_Event
*event
, void *);
298 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
300 WRadio
*r
= (WRadio
*) w
;
302 Dlg_head
*h
= r
->widget
.parent
;
307 int i
, lp
= tolower (parm
);
310 for (i
= 0; i
< r
->count
; i
++) {
311 cp
= strchr (r
->texts
[i
], '&');
312 if (cp
!= NULL
&& cp
[1] != '\0') {
313 int c
= tolower ((unsigned char) cp
[1]);
320 radio_callback (w
, WIDGET_KEY
, ' ');
325 return MSG_NOT_HANDLED
;
331 (*h
->callback
) (h
, DLG_ACTION
, 0);
332 radio_callback (w
, WIDGET_FOCUS
, ' ');
341 return MSG_NOT_HANDLED
;
345 if (r
->count
- 1 > r
->pos
) {
350 return MSG_NOT_HANDLED
;
353 (*h
->callback
) (h
, DLG_ACTION
, 0);
354 radio_callback (w
, WIDGET_FOCUS
, ' ');
355 widget_move (&r
->widget
, r
->pos
, 1);
361 for (i
= 0; i
< r
->count
; i
++) {
362 register const char *cp
;
363 const gboolean focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
364 widget_selectcolor (w
, focused
, FALSE
);
365 widget_move (&r
->widget
, i
, 0);
367 tty_printf ("(%c) ", (r
->sel
== i
) ? '*' : ' ');
368 for (cp
= r
->texts
[i
]; *cp
; cp
++) {
370 widget_selectcolor (w
, focused
, TRUE
);
372 widget_selectcolor (w
, focused
, FALSE
);
380 return default_proc (msg
, parm
);
385 radio_event (Gpm_Event
*event
, void *data
)
390 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
391 Dlg_head
*h
= r
->widget
.parent
;
393 r
->pos
= event
->y
- 1;
394 dlg_select_widget (r
);
395 if (event
->type
& GPM_UP
){
396 radio_callback (w
, WIDGET_KEY
, ' ');
397 radio_callback (w
, WIDGET_FOCUS
, 0);
398 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
406 radio_new (int y
, int x
, int count
, const char **texts
)
408 WRadio
*r
= g_new (WRadio
, 1);
411 /* Compute the longest string */
413 for (i
= 0; i
< count
; i
++){
414 m
= strlen (texts
[i
]);
419 init_widget (&r
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
425 widget_want_hotkey (r
->widget
, 1);
431 /* Checkbutton widget */
433 static int check_event (Gpm_Event
*event
, void *);
436 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
438 WCheck
*c
= (WCheck
*) w
;
439 Dlg_head
*h
= c
->widget
.parent
;
443 if (c
->hotkey
== parm
444 || (c
->hotkey
>= 'a' && c
->hotkey
<= 'z'
445 && c
->hotkey
- 32 == parm
)) {
446 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
449 return MSG_NOT_HANDLED
;
453 return MSG_NOT_HANDLED
;
455 c
->state
^= C_CHANGE
;
456 (*h
->callback
) (h
, DLG_ACTION
, 0);
457 check_callback (w
, WIDGET_FOCUS
, ' ');
461 widget_move (&c
->widget
, 0, 1);
467 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
468 widget_move (&c
->widget
, 0, 0);
469 tty_printf ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
471 if (c
->hotpos
>= 0) {
472 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, TRUE
);
473 widget_move (&c
->widget
, 0, +c
->hotpos
+ 4);
474 addch ((unsigned char) c
->text
[c
->hotpos
]);
483 return default_proc (msg
, parm
);
488 check_event (Gpm_Event
*event
, void *data
)
493 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
494 Dlg_head
*h
= c
->widget
.parent
;
496 dlg_select_widget (c
);
497 if (event
->type
& GPM_UP
){
498 check_callback (w
, WIDGET_KEY
, ' ');
499 check_callback (w
, WIDGET_FOCUS
, 0);
500 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
508 check_new (int y
, int x
, int state
, const char *text
)
510 WCheck
*c
= g_new (WCheck
, 1);
514 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
515 check_callback
, check_event
);
516 c
->state
= state
? C_BOOL
: 0;
517 c
->text
= g_strdup (text
);
520 widget_want_hotkey (c
->widget
, 1);
522 /* Scan for the hotkey */
523 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
530 c
->hotkey
= tolower ((unsigned char) *s
);
531 c
->hotpos
= t
- c
->text
;
543 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
545 WLabel
*l
= (WLabel
*) w
;
546 Dlg_head
*h
= l
->widget
.parent
;
552 /* We don't want to get the focus */
554 return MSG_NOT_HANDLED
;
558 char *p
= l
->text
, *q
, c
= 0;
565 attrset (DEFAULT_COLOR
);
567 attrset (DLG_NORMALC (h
));
571 q
= strchr (p
, '\n');
576 widget_move (&l
->widget
, y
, 0);
577 tty_printf ("%s", p
);
578 xlen
= l
->widget
.cols
- strlen (p
);
580 tty_printf ("%*s", xlen
, " ");
595 return default_proc (msg
, parm
);
600 label_set_text (WLabel
*label
, const char *text
)
602 int newcols
= label
->widget
.cols
;
604 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
605 return; /* Flickering is not nice */
607 g_free (label
->text
);
610 label
->text
= g_strdup (text
);
611 if (label
->auto_adjust_cols
) {
612 newcols
= strlen (text
);
613 if (newcols
> label
->widget
.cols
)
614 label
->widget
.cols
= newcols
;
619 if (label
->widget
.parent
)
620 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
622 if (newcols
< label
->widget
.cols
)
623 label
->widget
.cols
= newcols
;
627 label_new (int y
, int x
, const char *text
)
632 /* Multiline labels are immutable - no need to compute their sizes */
633 if (!text
|| strchr(text
, '\n'))
636 width
= strlen (text
);
638 l
= g_new (WLabel
, 1);
639 init_widget (&l
->widget
, y
, x
, 1, width
, label_callback
, NULL
);
640 l
->text
= text
? g_strdup (text
) : 0;
641 l
->auto_adjust_cols
= 1;
643 widget_want_cursor (l
->widget
, 0);
648 /* Gauge widget (progress indicator) */
649 /* Currently width is hardcoded here for text mode */
653 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
655 WGauge
*g
= (WGauge
*) w
;
656 Dlg_head
*h
= g
->widget
.parent
;
658 if (msg
== WIDGET_INIT
)
661 /* We don't want to get the focus */
662 if (msg
== WIDGET_FOCUS
)
663 return MSG_NOT_HANDLED
;
665 if (msg
== WIDGET_DRAW
){
666 widget_move (&g
->widget
, 0, 0);
667 attrset (DLG_NORMALC (h
));
669 tty_printf ("%*s", gauge_len
, "");
671 int percentage
, columns
;
672 long total
= g
->max
, done
= g
->current
;
674 if (total
<= 0 || done
< 0) {
680 while (total
> 65535) {
684 percentage
= (200 * done
/ total
+ 1) / 2;
685 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
687 attrset (GAUGE_COLOR
);
688 tty_printf ("%*s", (int) columns
, "");
689 attrset (DLG_NORMALC (h
));
690 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
694 return default_proc (msg
, parm
);
698 gauge_set_value (WGauge
*g
, int max
, int current
)
700 if (g
->current
== current
&& g
->max
== max
)
701 return; /* Do not flicker */
703 max
= 1; /* I do not like division by zero :) */
705 g
->current
= current
;
707 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
711 gauge_show (WGauge
*g
, int shown
)
713 if (g
->shown
== shown
)
716 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
720 gauge_new (int y
, int x
, int shown
, int max
, int current
)
722 WGauge
*g
= g_new (WGauge
, 1);
724 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
727 max
= 1; /* I do not like division by zero :) */
729 g
->current
= current
;
730 widget_want_cursor (g
->widget
, 0);
737 /* {{{ history button */
739 #define LARGE_HISTORY_BUTTON 1
741 #ifdef LARGE_HISTORY_BUTTON
742 # define HISTORY_BUTTON_WIDTH 3
744 # define HISTORY_BUTTON_WIDTH 1
747 #define should_show_history_button(in) \
748 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
750 static void draw_history_button (WInput
* in
)
753 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
754 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
755 #ifdef LARGE_HISTORY_BUTTON
758 h
= in
->widget
.parent
;
760 attrset (NORMALC
); /* button has the same color as other buttons */
762 attrset (HOT_NORMALC
);
764 attrset (NORMAL_COLOR
);
766 /* Too distracting: attrset (MARKED_COLOR); */
768 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
772 attrset (MARKED_COLOR
);
777 /* }}} history button */
780 /* Input widgets now have a global kill ring */
781 /* Pointer to killed data */
782 static char *kill_buffer
= 0;
785 update_input (WInput
*in
, int clear_first
)
790 int buf_len
= strlen (in
->buffer
);
792 if (should_show_history_button (in
))
793 has_history
= HISTORY_BUTTON_WIDTH
;
795 if (in
->disable_update
)
798 /* Make the point visible */
799 if ((in
->point
< in
->first_shown
) ||
800 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
801 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
802 if (in
->first_shown
< 0)
806 /* Adjust the mark */
807 if (in
->mark
> buf_len
)
811 draw_history_button (in
);
815 widget_move (&in
->widget
, 0, 0);
816 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
818 widget_move (&in
->widget
, 0, 0);
820 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
821 c
= in
->buffer
[j
++];
822 c
= is_printable (c
) ? c
: '.';
827 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
834 winput_set_origin (WInput
*in
, int x
, int field_len
)
837 in
->field_len
= in
->widget
.cols
= field_len
;
838 update_input (in
, 0);
841 /* {{{ history saving and loading */
843 int num_history_items_recorded
= 60;
846 This loads and saves the history of an input line to and from the
847 widget. It is called with the widgets history name on creation of the
848 widget, and returns the GList list. It stores histories in the file
849 ~/.mc/history in using the profile code.
851 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
852 function) then input_new assigns the default text to be the last text
853 entered, or "" if not found.
857 history_get (const char *input_name
)
865 if (!num_history_items_recorded
) /* this is how to disable */
871 profile
= mhl_str_dir_plus_file (home_dir
, HISTORY_FILE_NAME
);
873 char key_name
[BUF_TINY
];
874 char this_entry
[BUF_LARGE
];
875 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
876 GetPrivateProfileString (input_name
, key_name
, "", this_entry
,
877 sizeof (this_entry
), profile
);
881 hist
= list_append_unique (hist
, g_strdup (this_entry
));
885 /* return pointer to the last entry in the list */
886 hist
= g_list_last (hist
);
892 history_put (const char *input_name
, GList
*h
)
906 if (!num_history_items_recorded
) /* this is how to disable */
909 profile
= mhl_str_dir_plus_file (home_dir
, HISTORY_FILE_NAME
);
911 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
914 /* Make sure the history is only readable by the user */
915 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
920 /* go to end of list */
923 /* go back 60 places */
924 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
925 h
= g_list_previous (h
);
928 profile_clean_section (input_name
, profile
);
930 /* dump histories into profile */
931 for (i
= 0; h
; h
= g_list_next (h
)) {
934 text
= (char *) h
->data
;
936 /* We shouldn't have null entries, but let's be sure */
938 char key_name
[BUF_TINY
];
939 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
940 WritePrivateProfileString (input_name
, key_name
, text
,
948 /* }}} history saving and loading */
951 /* {{{ history display */
956 static const char *history_title
= NULL
;
958 if (history_title
== NULL
)
959 history_title
= _(" History ");
960 return history_title
;
963 static WLEntry
*listbox_select_pos (WListbox
*l
, WLEntry
*base
, int
966 static inline cb_ret_t
967 listbox_fwd (WListbox
*l
)
969 if (l
->current
!= l
->list
->prev
){
970 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
973 return MSG_NOT_HANDLED
;
977 show_hist (GList
*history
, int widget_x
, int widget_y
)
980 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
984 WListbox
*query_list
;
990 z
= g_list_first (history
);
993 if ((i
= strlen ((char *) hi
->data
)) > maxlen
)
996 hi
= g_list_next (hi
);
1001 if (h
<= y
|| y
> LINES
- 6) {
1006 h
= min (h
, LINES
- y
);
1013 if ((w
= maxlen
+ 4) + x
> COLS
) {
1019 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
1020 i18n_htitle (), DLG_COMPACT
);
1021 query_list
= listbox_new (1, 1, w
- 2, h
- 2, 0);
1022 add_widget (query_dlg
, query_list
);
1027 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1028 hi
= g_list_next (hi
);
1030 while (listbox_fwd (query_list
));
1032 /* traverse backwards */
1033 hi
= g_list_last (history
);
1035 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1036 hi
= g_list_previous (hi
);
1039 run_dlg (query_dlg
);
1041 if (query_dlg
->ret_value
!= B_CANCEL
) {
1042 listbox_get_current (query_list
, &q
, NULL
);
1046 destroy_dlg (query_dlg
);
1050 static void do_show_hist (WInput
* in
)
1053 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1055 assign_text (in
, r
);
1060 /* }}} history display */
1063 input_destroy (WInput
*in
)
1066 fprintf (stderr
, "Internal error: null Input *\n");
1073 if (!in
->is_password
) /* don't save passwords ;-) */
1074 history_put (in
->history_name
, in
->history
);
1076 in
->history
= g_list_first (in
->history
);
1077 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1078 g_list_free (in
->history
);
1081 g_free (in
->buffer
);
1082 free_completions (in
);
1083 g_free (in
->history_name
);
1087 input_disable_update (WInput
*in
)
1089 in
->disable_update
++;
1093 input_enable_update (WInput
*in
)
1095 in
->disable_update
--;
1096 update_input (in
, 0);
1099 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1102 push_history (WInput
*in
, const char *text
)
1105 /* input widget where urls with passwords are entered without any
1107 static const char *password_input_fields
[] = {
1108 N_(" Link to a remote machine "),
1109 N_(" FTP to machine "),
1110 N_(" SMB link to machine ")
1118 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1119 password_input_fields
[i
] = _(password_input_fields
[i
]);
1122 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1127 /* Avoid duplicated entries */
1128 in
->history
= g_list_last (in
->history
);
1129 if (!strcmp ((char *) in
->history
->data
, text
))
1133 t
= g_strdup (text
);
1135 if (in
->history_name
) {
1136 p
= in
->history_name
+ 3;
1137 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1138 if (strcmp (p
, password_input_fields
[i
]) == 0)
1140 if (i
< ELEMENTS (password_input_fields
))
1141 strip_password (t
, 0);
1143 strip_password (t
, 1);
1146 in
->history
= list_append_unique (in
->history
, t
);
1154 /* Cleans the input line and adds the current text to the history */
1156 new_input (WInput
*in
)
1159 push_history (in
, in
->buffer
);
1164 free_completions (in
);
1165 update_input (in
, 0);
1169 insert_char (WInput
*in
, int c_code
)
1174 return MSG_NOT_HANDLED
;
1177 if (strlen (in
->buffer
)+1 == (size_t) in
->current_max_len
){
1178 /* Expand the buffer */
1179 char *narea
= g_realloc (in
->buffer
, in
->current_max_len
+ in
->field_len
);
1182 in
->current_max_len
+= in
->field_len
;
1185 if (strlen (in
->buffer
)+1 < (size_t) in
->current_max_len
){
1186 size_t l
= strlen (&in
->buffer
[in
->point
]);
1187 for (i
= l
+1; i
> 0; i
--)
1188 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1189 in
->buffer
[in
->point
] = c_code
;
1196 beginning_of_line (WInput
*in
)
1202 end_of_line (WInput
*in
)
1204 in
->point
= strlen (in
->buffer
);
1208 backward_char (WInput
*in
)
1215 forward_char (WInput
*in
)
1217 if (in
->buffer
[in
->point
])
1222 forward_word (WInput
* in
)
1224 char *p
= in
->buffer
+ in
->point
;
1227 && (isspace ((unsigned char) *p
)
1228 || ispunct ((unsigned char) *p
)))
1230 while (*p
&& isalnum ((unsigned char) *p
))
1232 in
->point
= p
- in
->buffer
;
1236 backward_word (WInput
*in
)
1238 char *p
= in
->buffer
+ in
->point
;
1240 while (p
- 1 > in
->buffer
- 1 && (isspace ((unsigned char) *(p
- 1))
1241 || ispunct ((unsigned char)
1244 while (p
- 1 > in
->buffer
- 1 && isalnum ((unsigned char) *(p
- 1)))
1246 in
->point
= p
- in
->buffer
;
1250 key_left (WInput
*in
)
1256 key_ctrl_left (WInput
*in
)
1262 key_right (WInput
*in
)
1268 key_ctrl_right (WInput
*in
)
1273 backward_delete (WInput
*in
)
1279 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1280 in
->buffer
[i
-1] = in
->buffer
[i
];
1286 delete_char (WInput
*in
)
1290 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1291 in
->buffer
[i
] = in
->buffer
[i
+1];
1296 copy_region (WInput
*in
, int x_first
, int x_last
)
1298 int first
= min (x_first
, x_last
);
1299 int last
= max (x_first
, x_last
);
1304 g_free (kill_buffer
);
1306 kill_buffer
= g_strndup(in
->buffer
+first
,last
-first
);
1310 delete_region (WInput
*in
, int x_first
, int x_last
)
1312 int first
= min (x_first
, x_last
);
1313 int last
= max (x_first
, x_last
);
1314 size_t len
= strlen (&in
->buffer
[last
]) + 1;
1318 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1323 kill_word (WInput
*in
)
1325 int old_point
= in
->point
;
1329 new_point
= in
->point
;
1330 in
->point
= old_point
;
1332 copy_region (in
, old_point
, new_point
);
1333 delete_region (in
, old_point
, new_point
);
1338 back_kill_word (WInput
*in
)
1340 int old_point
= in
->point
;
1344 new_point
= in
->point
;
1345 in
->point
= old_point
;
1347 copy_region (in
, old_point
, new_point
);
1348 delete_region (in
, old_point
, new_point
);
1353 set_mark (WInput
*in
)
1355 in
->mark
= in
->point
;
1359 kill_save (WInput
*in
)
1361 copy_region (in
, in
->mark
, in
->point
);
1365 kill_region (WInput
*in
)
1368 delete_region (in
, in
->point
, in
->mark
);
1378 for (p
= kill_buffer
; *p
; p
++)
1379 insert_char (in
, *p
);
1383 kill_line (WInput
*in
)
1385 g_free (kill_buffer
);
1386 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1387 in
->buffer
[in
->point
] = 0;
1391 assign_text (WInput
*in
, const char *text
)
1393 free_completions (in
);
1394 g_free (in
->buffer
);
1395 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1396 in
->current_max_len
= strlen (in
->buffer
) + 1;
1397 in
->point
= strlen (in
->buffer
);
1403 hist_prev (WInput
*in
)
1408 if (in
->need_push
) {
1409 switch (push_history (in
, in
->buffer
)) {
1411 in
->history
= g_list_previous (in
->history
);
1414 if (in
->history
->prev
)
1415 in
->history
= g_list_previous (in
->history
);
1420 } else if (in
->history
->prev
)
1421 in
->history
= g_list_previous (in
->history
);
1424 assign_text (in
, (char *) in
->history
->data
);
1429 hist_next (WInput
*in
)
1431 if (in
->need_push
) {
1432 switch (push_history (in
, in
->buffer
)) {
1434 assign_text (in
, "");
1444 if (!in
->history
->next
) {
1445 assign_text (in
, "");
1449 in
->history
= g_list_next (in
->history
);
1450 assign_text (in
, (char *) in
->history
->data
);
1454 static const struct {
1456 void (*fn
)(WInput
*in
);
1459 { XCTRL('a'), beginning_of_line
},
1460 { KEY_HOME
, beginning_of_line
},
1461 { KEY_A1
, beginning_of_line
},
1462 { ALT ('<'), beginning_of_line
},
1463 { XCTRL('e'), end_of_line
},
1464 { KEY_END
, end_of_line
},
1465 { KEY_C1
, end_of_line
},
1466 { ALT ('>'), end_of_line
},
1467 { KEY_LEFT
, key_left
},
1468 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1469 { XCTRL('b'), backward_char
},
1470 { ALT('b'), backward_word
},
1471 { KEY_RIGHT
, key_right
},
1472 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1473 { XCTRL('f'), forward_char
},
1474 { ALT('f'), forward_word
},
1477 { KEY_BACKSPACE
, backward_delete
},
1478 { KEY_DC
, delete_char
},
1479 { ALT('d'), kill_word
},
1480 { ALT(KEY_BACKSPACE
), back_kill_word
},
1482 /* Region manipulation */
1484 { XCTRL('w'), kill_region
},
1485 { ALT('w'), kill_save
},
1486 { XCTRL('y'), yank
},
1487 { XCTRL('k'), kill_line
},
1490 { ALT('p'), hist_prev
},
1491 { ALT('n'), hist_next
},
1492 { ALT('h'), do_show_hist
},
1495 { ALT('\t'), complete
},
1500 /* This function is a test for a special input key used in complete.c */
1501 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1502 and 2 if it is a complete key */
1504 is_in_input_map (WInput
*in
, int c_code
)
1510 for (i
= 0; input_map
[i
].fn
; i
++)
1511 if (c_code
== input_map
[i
].key_code
) {
1512 if (input_map
[i
].fn
== complete
)
1521 port_region_marked_for_delete (WInput
*in
)
1529 handle_char (WInput
*in
, int c_code
)
1534 v
= MSG_NOT_HANDLED
;
1537 free_completions (in
);
1538 v
= insert_char (in
, c_code
);
1539 update_input (in
, 1);
1544 for (i
= 0; input_map
[i
].fn
; i
++){
1545 if (c_code
== input_map
[i
].key_code
){
1546 if (input_map
[i
].fn
!= complete
)
1547 free_completions (in
);
1548 (*input_map
[i
].fn
)(in
);
1553 if (!input_map
[i
].fn
){
1554 if (c_code
> 255 || !is_printable (c_code
))
1555 return MSG_NOT_HANDLED
;
1557 port_region_marked_for_delete (in
);
1559 free_completions (in
);
1560 v
= insert_char (in
, c_code
);
1562 update_input (in
, 1);
1566 /* Inserts text in input line */
1568 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1570 input_disable_update (in
);
1572 handle_char (in
, *text
++);
1573 if (insert_extra_space
)
1574 handle_char (in
, ' ');
1575 input_enable_update (in
);
1576 update_input (in
, 1);
1580 input_set_point (WInput
*in
, int pos
)
1582 if (pos
> in
->current_max_len
)
1583 pos
= in
->current_max_len
;
1584 if (pos
!= in
->point
)
1585 free_completions (in
);
1587 update_input (in
, 1);
1591 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1593 WInput
*in
= (WInput
*) w
;
1598 if (parm
== XCTRL ('q')) {
1600 v
= handle_char (in
, ascii_alpha_to_cntrl (mi_getch ()));
1605 /* Keys we want others to handle */
1606 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1607 || parm
== KEY_F (10) || parm
== XCTRL ('g') || parm
== '\n')
1608 return MSG_NOT_HANDLED
;
1610 /* When pasting multiline text, insert literal Enter */
1611 if ((parm
& ~KEY_M_MASK
) == '\n') {
1613 v
= handle_char (in
, '\n');
1618 return handle_char (in
, parm
);
1621 case WIDGET_UNFOCUS
:
1623 update_input (in
, 0);
1627 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1630 case WIDGET_DESTROY
:
1635 return default_proc (msg
, parm
);
1640 input_event (Gpm_Event
* event
, void *data
)
1644 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1645 dlg_select_widget (in
);
1647 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1648 && should_show_history_button (in
)) {
1651 in
->point
= strlen (in
->buffer
);
1652 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1653 in
->point
= event
->x
- in
->first_shown
- 1;
1657 update_input (in
, 1);
1663 input_new (int y
, int x
, int color
, int len
, const char *def_text
,
1664 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
1666 WInput
*in
= g_new (WInput
, 1);
1667 int initial_buffer_len
;
1669 init_widget (&in
->widget
, y
, x
, 1, len
, input_callback
, input_event
);
1673 in
->history_name
= 0;
1676 in
->history_name
= g_strdup (histname
);
1677 in
->history
= history_get (histname
);
1684 if (def_text
== INPUT_LAST_TEXT
) {
1687 if (in
->history
->data
)
1688 def_text
= (char *) in
->history
->data
;
1690 initial_buffer_len
= 1 + max ((size_t) len
, strlen (def_text
));
1691 in
->widget
.options
|= W_IS_INPUT
;
1692 in
->completions
= NULL
;
1693 in
->completion_flags
= completion_flags
;
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
);