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/string.h>
47 #include "key.h" /* XCTRL and ALT macros */
48 #include "profile.h" /* for history loading and saving */
49 #include "wtools.h" /* For common_dialog_repaint() */
50 #include "main.h" /* for `slow_terminal' */
52 #define HISTORY_FILE_NAME ".mc/history"
56 int visible
; /* Is it visible? */
59 enum { BBFUNC_NONE
, BBFUNC_VOID
, BBFUNC_PTR
} tag
;
68 static int button_event (Gpm_Event
*event
, void *);
73 widget_selectcolor (Widget
*w
, bool focused
, bool hotkey
)
75 Dlg_head
*h
= w
->parent
;
80 : DLG_HOT_NORMALC (h
))
87 button_callback (Widget
*w
, widget_msg_t msg
, int parm
)
89 WButton
*b
= (WButton
*) w
;
93 Dlg_head
*h
= b
->widget
.parent
;
98 * Don't let the default button steal Enter from the current
99 * button. This is a workaround for the flawed event model
100 * when hotkeys are sent to all widgets before the key is
101 * handled by the current widget.
103 if (parm
== '\n' && h
->current
== &b
->widget
) {
104 button_callback (w
, WIDGET_KEY
, ' ');
108 if (parm
== '\n' && b
->flags
== DEFPUSH_BUTTON
) {
109 button_callback (w
, WIDGET_KEY
, ' ');
113 if (b
->hotkey
== tolower (parm
)) {
114 button_callback (w
, WIDGET_KEY
, ' ');
118 return MSG_NOT_HANDLED
;
121 if (parm
!= ' ' && parm
!= '\n')
122 return MSG_NOT_HANDLED
;
125 stop
= (*b
->callback
) (b
->action
);
126 if (!b
->callback
|| stop
) {
127 h
->ret_value
= b
->action
;
148 widget_move (&b
->widget
, 0, b
->hotpos
+ off
);
154 if (msg
== WIDGET_UNFOCUS
)
156 else if (msg
== WIDGET_FOCUS
)
161 g_snprintf (buf
, sizeof (buf
), "[< %s >]", b
->text
);
165 g_snprintf (buf
, sizeof (buf
), "[ %s ]", b
->text
);
169 g_snprintf (buf
, sizeof (buf
), "[%s]", b
->text
);
179 widget_selectcolor (w
, b
->selected
, FALSE
);
180 widget_move (w
, 0, 0);
184 if (b
->hotpos
>= 0) {
185 widget_selectcolor (w
, b
->selected
, TRUE
);
186 widget_move (w
, 0, b
->hotpos
+ off
);
187 addch ((unsigned char) b
->text
[b
->hotpos
]);
196 return default_proc (msg
, parm
);
201 button_event (Gpm_Event
*event
, void *data
)
205 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
206 Dlg_head
*h
=b
->widget
.parent
;
207 dlg_select_widget (b
);
208 if (event
->type
& GPM_UP
){
209 button_callback ((Widget
*) data
, WIDGET_KEY
, ' ');
210 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
218 button_len (const char *text
, unsigned int flags
)
220 int ret
= strlen (text
);
239 * Locate the hotkey and remove it from the button text. Assuming that
240 * the button text is g_malloc()ed, we can safely change and shorten it.
243 button_scan_hotkey (WButton
*b
)
245 char *cp
= strchr (b
->text
, '&');
247 if (cp
!= NULL
&& cp
[1] != '\0') {
248 g_strlcpy (cp
, cp
+ 1, strlen (cp
));
249 b
->hotkey
= tolower ((unsigned char) *cp
);
250 b
->hotpos
= cp
- b
->text
;
255 button_new (int y
, int x
, int action
, int flags
, const char *text
,
258 WButton
*b
= g_new (WButton
, 1);
260 init_widget (&b
->widget
, y
, x
, 1, button_len (text
, flags
),
261 button_callback
, button_event
);
266 b
->text
= g_strdup (text
);
267 b
->callback
= callback
;
268 widget_want_hotkey (b
->widget
, 1);
272 button_scan_hotkey(b
);
277 button_get_text (WButton
*b
)
283 button_set_text (WButton
*b
, const char *text
)
286 b
->text
= g_strdup (text
);
287 b
->widget
.cols
= button_len (text
, b
->flags
);
288 button_scan_hotkey(b
);
289 dlg_redraw (b
->widget
.parent
);
293 /* Radio button widget */
294 static int radio_event (Gpm_Event
*event
, void *);
297 radio_callback (Widget
*w
, widget_msg_t msg
, int parm
)
299 WRadio
*r
= (WRadio
*) w
;
301 Dlg_head
*h
= r
->widget
.parent
;
306 int i
, lp
= tolower (parm
);
309 for (i
= 0; i
< r
->count
; i
++) {
310 cp
= strchr (r
->texts
[i
], '&');
311 if (cp
!= NULL
&& cp
[1] != '\0') {
312 int c
= tolower ((unsigned char) cp
[1]);
319 radio_callback (w
, WIDGET_KEY
, ' ');
324 return MSG_NOT_HANDLED
;
330 (*h
->callback
) (h
, DLG_ACTION
, 0);
331 radio_callback (w
, WIDGET_FOCUS
, ' ');
340 return MSG_NOT_HANDLED
;
344 if (r
->count
- 1 > r
->pos
) {
349 return MSG_NOT_HANDLED
;
352 (*h
->callback
) (h
, DLG_ACTION
, 0);
353 radio_callback (w
, WIDGET_FOCUS
, ' ');
354 widget_move (&r
->widget
, r
->pos
, 1);
360 for (i
= 0; i
< r
->count
; i
++) {
361 register const char *cp
;
362 const bool focused
= (i
== r
->pos
&& msg
== WIDGET_FOCUS
);
363 widget_selectcolor (w
, focused
, FALSE
);
364 widget_move (&r
->widget
, i
, 0);
366 tty_printf ("(%c) ", (r
->sel
== i
) ? '*' : ' ');
367 for (cp
= r
->texts
[i
]; *cp
; cp
++) {
369 widget_selectcolor (w
, focused
, TRUE
);
371 widget_selectcolor (w
, focused
, FALSE
);
379 return default_proc (msg
, parm
);
384 radio_event (Gpm_Event
*event
, void *data
)
389 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
390 Dlg_head
*h
= r
->widget
.parent
;
392 r
->pos
= event
->y
- 1;
393 dlg_select_widget (r
);
394 if (event
->type
& GPM_UP
){
395 radio_callback (w
, WIDGET_KEY
, ' ');
396 radio_callback (w
, WIDGET_FOCUS
, 0);
397 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
405 radio_new (int y
, int x
, int count
, const char **texts
)
407 WRadio
*r
= g_new (WRadio
, 1);
410 /* Compute the longest string */
412 for (i
= 0; i
< count
; i
++){
413 m
= strlen (texts
[i
]);
418 init_widget (&r
->widget
, y
, x
, count
, max
, radio_callback
, radio_event
);
424 widget_want_hotkey (r
->widget
, 1);
430 /* Checkbutton widget */
432 static int check_event (Gpm_Event
*event
, void *);
435 check_callback (Widget
*w
, widget_msg_t msg
, int parm
)
437 WCheck
*c
= (WCheck
*) w
;
438 Dlg_head
*h
= c
->widget
.parent
;
442 if (c
->hotkey
== parm
443 || (c
->hotkey
>= 'a' && c
->hotkey
<= 'z'
444 && c
->hotkey
- 32 == parm
)) {
445 check_callback (w
, WIDGET_KEY
, ' '); /* make action */
448 return MSG_NOT_HANDLED
;
452 return MSG_NOT_HANDLED
;
454 c
->state
^= C_CHANGE
;
455 (*h
->callback
) (h
, DLG_ACTION
, 0);
456 check_callback (w
, WIDGET_FOCUS
, ' ');
460 widget_move (&c
->widget
, 0, 1);
466 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, FALSE
);
467 widget_move (&c
->widget
, 0, 0);
468 tty_printf ("[%c] %s", (c
->state
& C_BOOL
) ? 'x' : ' ', c
->text
);
470 if (c
->hotpos
>= 0) {
471 widget_selectcolor (w
, msg
== WIDGET_FOCUS
, TRUE
);
472 widget_move (&c
->widget
, 0, +c
->hotpos
+ 4);
473 addch ((unsigned char) c
->text
[c
->hotpos
]);
482 return default_proc (msg
, parm
);
487 check_event (Gpm_Event
*event
, void *data
)
492 if (event
->type
& (GPM_DOWN
|GPM_UP
)){
493 Dlg_head
*h
= c
->widget
.parent
;
495 dlg_select_widget (c
);
496 if (event
->type
& GPM_UP
){
497 check_callback (w
, WIDGET_KEY
, ' ');
498 check_callback (w
, WIDGET_FOCUS
, 0);
499 (*h
->callback
) (h
, DLG_POST_KEY
, ' ');
507 check_new (int y
, int x
, int state
, const char *text
)
509 WCheck
*c
= g_new (WCheck
, 1);
513 init_widget (&c
->widget
, y
, x
, 1, strlen (text
),
514 check_callback
, check_event
);
515 c
->state
= state
? C_BOOL
: 0;
516 c
->text
= g_strdup (text
);
519 widget_want_hotkey (c
->widget
, 1);
521 /* Scan for the hotkey */
522 for (s
= text
, t
= c
->text
; *s
; s
++, t
++){
529 c
->hotkey
= tolower ((unsigned char) *s
);
530 c
->hotpos
= t
- c
->text
;
542 label_callback (Widget
*w
, widget_msg_t msg
, int parm
)
544 WLabel
*l
= (WLabel
*) w
;
545 Dlg_head
*h
= l
->widget
.parent
;
551 /* We don't want to get the focus */
553 return MSG_NOT_HANDLED
;
557 char *p
= l
->text
, *q
, c
= 0;
564 attrset (DEFAULT_COLOR
);
566 attrset (DLG_NORMALC (h
));
570 q
= strchr (p
, '\n');
575 widget_move (&l
->widget
, y
, 0);
576 tty_printf ("%s", p
);
577 xlen
= l
->widget
.cols
- strlen (p
);
579 tty_printf ("%*s", xlen
, " ");
594 return default_proc (msg
, parm
);
599 label_set_text (WLabel
*label
, const char *text
)
601 int newcols
= label
->widget
.cols
;
603 if (label
->text
&& text
&& !strcmp (label
->text
, text
))
604 return; /* Flickering is not nice */
606 g_free (label
->text
);
609 label
->text
= g_strdup (text
);
610 if (label
->auto_adjust_cols
) {
611 newcols
= strlen (text
);
612 if (newcols
> label
->widget
.cols
)
613 label
->widget
.cols
= newcols
;
618 if (label
->widget
.parent
)
619 label_callback ((Widget
*) label
, WIDGET_DRAW
, 0);
621 if (newcols
< label
->widget
.cols
)
622 label
->widget
.cols
= newcols
;
626 label_new (int y
, int x
, const char *text
)
631 /* Multiline labels are immutable - no need to compute their sizes */
632 if (!text
|| strchr(text
, '\n'))
635 width
= strlen (text
);
637 l
= g_new (WLabel
, 1);
638 init_widget (&l
->widget
, y
, x
, 1, width
, label_callback
, NULL
);
639 l
->text
= text
? g_strdup (text
) : 0;
640 l
->auto_adjust_cols
= 1;
642 widget_want_cursor (l
->widget
, 0);
647 /* Gauge widget (progress indicator) */
648 /* Currently width is hardcoded here for text mode */
652 gauge_callback (Widget
*w
, widget_msg_t msg
, int parm
)
654 WGauge
*g
= (WGauge
*) w
;
655 Dlg_head
*h
= g
->widget
.parent
;
657 if (msg
== WIDGET_INIT
)
660 /* We don't want to get the focus */
661 if (msg
== WIDGET_FOCUS
)
662 return MSG_NOT_HANDLED
;
664 if (msg
== WIDGET_DRAW
){
665 widget_move (&g
->widget
, 0, 0);
666 attrset (DLG_NORMALC (h
));
668 tty_printf ("%*s", gauge_len
, "");
670 int percentage
, columns
;
671 long total
= g
->max
, done
= g
->current
;
673 if (total
<= 0 || done
< 0) {
679 while (total
> 65535) {
683 percentage
= (200 * done
/ total
+ 1) / 2;
684 columns
= (2 * (gauge_len
- 7) * done
/ total
+ 1) / 2;
686 attrset (GAUGE_COLOR
);
687 tty_printf ("%*s", (int) columns
, "");
688 attrset (DLG_NORMALC (h
));
689 tty_printf ("%*s] %3d%%", (int)(gauge_len
- 7 - columns
), "", (int) percentage
);
693 return default_proc (msg
, parm
);
697 gauge_set_value (WGauge
*g
, int max
, int current
)
699 if (g
->current
== current
&& g
->max
== max
)
700 return; /* Do not flicker */
702 max
= 1; /* I do not like division by zero :) */
704 g
->current
= current
;
706 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
710 gauge_show (WGauge
*g
, int shown
)
712 if (g
->shown
== shown
)
715 gauge_callback ((Widget
*) g
, WIDGET_DRAW
, 0);
719 gauge_new (int y
, int x
, int shown
, int max
, int current
)
721 WGauge
*g
= g_new (WGauge
, 1);
723 init_widget (&g
->widget
, y
, x
, 1, gauge_len
, gauge_callback
, NULL
);
726 max
= 1; /* I do not like division by zero :) */
728 g
->current
= current
;
729 widget_want_cursor (g
->widget
, 0);
736 /* {{{ history button */
738 #define LARGE_HISTORY_BUTTON 1
740 #ifdef LARGE_HISTORY_BUTTON
741 # define HISTORY_BUTTON_WIDTH 3
743 # define HISTORY_BUTTON_WIDTH 1
746 #define should_show_history_button(in) \
747 (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
749 static void draw_history_button (WInput
* in
)
752 c
= in
->history
->next
? (in
->history
->prev
? '|' : 'v') : '^';
753 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
);
754 #ifdef LARGE_HISTORY_BUTTON
757 h
= in
->widget
.parent
;
759 attrset (NORMALC
); /* button has the same color as other buttons */
761 attrset (HOT_NORMALC
);
763 attrset (NORMAL_COLOR
);
765 /* Too distracting: attrset (MARKED_COLOR); */
767 widget_move (&in
->widget
, 0, in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1);
771 attrset (MARKED_COLOR
);
776 /* }}} history button */
779 /* Input widgets now have a global kill ring */
780 /* Pointer to killed data */
781 static char *kill_buffer
= 0;
784 update_input (WInput
*in
, int clear_first
)
789 int buf_len
= strlen (in
->buffer
);
791 if (should_show_history_button (in
))
792 has_history
= HISTORY_BUTTON_WIDTH
;
794 if (in
->disable_update
)
797 /* Make the point visible */
798 if ((in
->point
< in
->first_shown
) ||
799 (in
->point
>= in
->first_shown
+in
->field_len
- has_history
)){
800 in
->first_shown
= in
->point
- (in
->field_len
/ 3);
801 if (in
->first_shown
< 0)
805 /* Adjust the mark */
806 if (in
->mark
> buf_len
)
810 draw_history_button (in
);
814 widget_move (&in
->widget
, 0, 0);
815 for (i
= 0; i
< in
->field_len
- has_history
; i
++)
817 widget_move (&in
->widget
, 0, 0);
819 for (i
= 0, j
= in
->first_shown
; i
< in
->field_len
- has_history
&& in
->buffer
[j
]; i
++){
820 c
= in
->buffer
[j
++];
821 c
= is_printable (c
) ? c
: '.';
826 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
833 winput_set_origin (WInput
*in
, int x
, int field_len
)
836 in
->field_len
= in
->widget
.cols
= field_len
;
837 update_input (in
, 0);
840 /* {{{ history saving and loading */
842 int num_history_items_recorded
= 60;
845 This loads and saves the history of an input line to and from the
846 widget. It is called with the widgets history name on creation of the
847 widget, and returns the GList list. It stores histories in the file
848 ~/.mc/history in using the profile code.
850 If def_text is passed as INPUT_LAST_TEXT (to the input_new()
851 function) then input_new assigns the default text to be the last text
852 entered, or "" if not found.
856 history_get (const char *input_name
)
864 if (!num_history_items_recorded
) /* this is how to disable */
870 profile
= mhl_str_dir_plus_file (home_dir
, HISTORY_FILE_NAME
);
872 char key_name
[BUF_TINY
];
873 char this_entry
[BUF_LARGE
];
874 g_snprintf (key_name
, sizeof (key_name
), "%d", i
);
875 GetPrivateProfileString (input_name
, key_name
, "", this_entry
,
876 sizeof (this_entry
), profile
);
880 hist
= list_append_unique (hist
, g_strdup (this_entry
));
884 /* return pointer to the last entry in the list */
885 hist
= g_list_last (hist
);
891 history_put (const char *input_name
, GList
*h
)
905 if (!num_history_items_recorded
) /* this is how to disable */
908 profile
= mhl_str_dir_plus_file (home_dir
, HISTORY_FILE_NAME
);
910 if ((i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
)) != -1)
913 /* Make sure the history is only readable by the user */
914 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
) {
919 /* go to end of list */
922 /* go back 60 places */
923 for (i
= 0; i
< num_history_items_recorded
- 1 && h
->prev
; i
++)
924 h
= g_list_previous (h
);
927 profile_clean_section (input_name
, profile
);
929 /* dump histories into profile */
930 for (i
= 0; h
; h
= g_list_next (h
)) {
933 text
= (char *) h
->data
;
935 /* We shouldn't have null entries, but let's be sure */
937 char key_name
[BUF_TINY
];
938 g_snprintf (key_name
, sizeof (key_name
), "%d", i
++);
939 WritePrivateProfileString (input_name
, key_name
, text
,
947 /* }}} history saving and loading */
950 /* {{{ history display */
955 static const char *history_title
= NULL
;
957 if (history_title
== NULL
)
958 history_title
= _(" History ");
959 return history_title
;
962 static WLEntry
*listbox_select_pos (WListbox
*l
, WLEntry
*base
, int
965 static inline cb_ret_t
966 listbox_fwd (WListbox
*l
)
968 if (l
->current
!= l
->list
->prev
){
969 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
+1));
972 return MSG_NOT_HANDLED
;
976 show_hist (GList
*history
, int widget_x
, int widget_y
)
979 size_t maxlen
= strlen (i18n_htitle ()), i
, count
= 0;
983 WListbox
*query_list
;
989 z
= g_list_first (history
);
992 if ((i
= strlen ((char *) hi
->data
)) > maxlen
)
995 hi
= g_list_next (hi
);
1000 if (h
<= y
|| y
> LINES
- 6) {
1005 h
= min (h
, LINES
- y
);
1012 if ((w
= maxlen
+ 4) + x
> COLS
) {
1018 create_dlg (y
, x
, h
, w
, dialog_colors
, NULL
, "[History-query]",
1019 i18n_htitle (), DLG_COMPACT
);
1020 query_list
= listbox_new (1, 1, w
- 2, h
- 2, 0);
1021 add_widget (query_dlg
, query_list
);
1026 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1027 hi
= g_list_next (hi
);
1029 while (listbox_fwd (query_list
));
1031 /* traverse backwards */
1032 hi
= g_list_last (history
);
1034 listbox_add_item (query_list
, 0, 0, (char *) hi
->data
, NULL
);
1035 hi
= g_list_previous (hi
);
1038 run_dlg (query_dlg
);
1040 if (query_dlg
->ret_value
!= B_CANCEL
) {
1041 listbox_get_current (query_list
, &q
, NULL
);
1045 destroy_dlg (query_dlg
);
1049 static void do_show_hist (WInput
* in
)
1052 r
= show_hist (in
->history
, in
->widget
.x
, in
->widget
.y
);
1054 assign_text (in
, r
);
1059 /* }}} history display */
1062 input_destroy (WInput
*in
)
1065 fprintf (stderr
, "Internal error: null Input *\n");
1072 if (!in
->is_password
) /* don't save passwords ;-) */
1073 history_put (in
->history_name
, in
->history
);
1075 in
->history
= g_list_first (in
->history
);
1076 g_list_foreach (in
->history
, (GFunc
) g_free
, NULL
);
1077 g_list_free (in
->history
);
1080 g_free (in
->buffer
);
1081 free_completions (in
);
1082 g_free (in
->history_name
);
1086 input_disable_update (WInput
*in
)
1088 in
->disable_update
++;
1092 input_enable_update (WInput
*in
)
1094 in
->disable_update
--;
1095 update_input (in
, 0);
1098 #define ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
1101 push_history (WInput
*in
, const char *text
)
1104 /* input widget where urls with passwords are entered without any
1106 static const char *password_input_fields
[] = {
1107 N_(" Link to a remote machine "),
1108 N_(" FTP to machine "),
1109 N_(" SMB link to machine ")
1117 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1118 password_input_fields
[i
] = _(password_input_fields
[i
]);
1121 for (p
= text
; *p
== ' ' || *p
== '\t'; p
++);
1126 /* Avoid duplicated entries */
1127 in
->history
= g_list_last (in
->history
);
1128 if (!strcmp ((char *) in
->history
->data
, text
))
1132 t
= g_strdup (text
);
1134 if (in
->history_name
) {
1135 p
= in
->history_name
+ 3;
1136 for (i
= 0; i
< ELEMENTS (password_input_fields
); i
++)
1137 if (strcmp (p
, password_input_fields
[i
]) == 0)
1139 if (i
< ELEMENTS (password_input_fields
))
1140 strip_password (t
, 0);
1142 strip_password (t
, 1);
1145 in
->history
= list_append_unique (in
->history
, t
);
1153 /* Cleans the input line and adds the current text to the history */
1155 new_input (WInput
*in
)
1158 push_history (in
, in
->buffer
);
1163 free_completions (in
);
1164 update_input (in
, 0);
1168 insert_char (WInput
*in
, int c_code
)
1173 return MSG_NOT_HANDLED
;
1176 if (strlen (in
->buffer
)+1 == (size_t) in
->current_max_len
){
1177 /* Expand the buffer */
1178 char *narea
= g_realloc (in
->buffer
, in
->current_max_len
+ in
->field_len
);
1181 in
->current_max_len
+= in
->field_len
;
1184 if (strlen (in
->buffer
)+1 < (size_t) in
->current_max_len
){
1185 size_t l
= strlen (&in
->buffer
[in
->point
]);
1186 for (i
= l
+1; i
> 0; i
--)
1187 in
->buffer
[in
->point
+i
] = in
->buffer
[in
->point
+i
-1];
1188 in
->buffer
[in
->point
] = c_code
;
1195 beginning_of_line (WInput
*in
)
1201 end_of_line (WInput
*in
)
1203 in
->point
= strlen (in
->buffer
);
1207 backward_char (WInput
*in
)
1214 forward_char (WInput
*in
)
1216 if (in
->buffer
[in
->point
])
1221 forward_word (WInput
* in
)
1223 char *p
= in
->buffer
+ in
->point
;
1226 && (isspace ((unsigned char) *p
)
1227 || ispunct ((unsigned char) *p
)))
1229 while (*p
&& isalnum ((unsigned char) *p
))
1231 in
->point
= p
- in
->buffer
;
1235 backward_word (WInput
*in
)
1237 char *p
= in
->buffer
+ in
->point
;
1239 while (p
- 1 > in
->buffer
- 1 && (isspace ((unsigned char) *(p
- 1))
1240 || ispunct ((unsigned char)
1243 while (p
- 1 > in
->buffer
- 1 && isalnum ((unsigned char) *(p
- 1)))
1245 in
->point
= p
- in
->buffer
;
1249 key_left (WInput
*in
)
1255 key_ctrl_left (WInput
*in
)
1261 key_right (WInput
*in
)
1267 key_ctrl_right (WInput
*in
)
1272 backward_delete (WInput
*in
)
1278 for (i
= in
->point
; in
->buffer
[i
-1]; i
++)
1279 in
->buffer
[i
-1] = in
->buffer
[i
];
1285 delete_char (WInput
*in
)
1289 for (i
= in
->point
; in
->buffer
[i
]; i
++)
1290 in
->buffer
[i
] = in
->buffer
[i
+1];
1295 copy_region (WInput
*in
, int x_first
, int x_last
)
1297 int first
= min (x_first
, x_last
);
1298 int last
= max (x_first
, x_last
);
1303 g_free (kill_buffer
);
1305 kill_buffer
= g_strndup(in
->buffer
+first
,last
-first
);
1309 delete_region (WInput
*in
, int x_first
, int x_last
)
1311 int first
= min (x_first
, x_last
);
1312 int last
= max (x_first
, x_last
);
1313 size_t len
= strlen (&in
->buffer
[last
]) + 1;
1317 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
1322 kill_word (WInput
*in
)
1324 int old_point
= in
->point
;
1328 new_point
= in
->point
;
1329 in
->point
= old_point
;
1331 copy_region (in
, old_point
, new_point
);
1332 delete_region (in
, old_point
, new_point
);
1337 back_kill_word (WInput
*in
)
1339 int old_point
= in
->point
;
1343 new_point
= in
->point
;
1344 in
->point
= old_point
;
1346 copy_region (in
, old_point
, new_point
);
1347 delete_region (in
, old_point
, new_point
);
1352 set_mark (WInput
*in
)
1354 in
->mark
= in
->point
;
1358 kill_save (WInput
*in
)
1360 copy_region (in
, in
->mark
, in
->point
);
1364 kill_region (WInput
*in
)
1367 delete_region (in
, in
->point
, in
->mark
);
1377 for (p
= kill_buffer
; *p
; p
++)
1378 insert_char (in
, *p
);
1382 kill_line (WInput
*in
)
1384 g_free (kill_buffer
);
1385 kill_buffer
= g_strdup (&in
->buffer
[in
->point
]);
1386 in
->buffer
[in
->point
] = 0;
1390 assign_text (WInput
*in
, const char *text
)
1392 free_completions (in
);
1393 g_free (in
->buffer
);
1394 in
->buffer
= g_strdup (text
); /* was in->buffer->text */
1395 in
->current_max_len
= strlen (in
->buffer
) + 1;
1396 in
->point
= strlen (in
->buffer
);
1402 hist_prev (WInput
*in
)
1407 if (in
->need_push
) {
1408 switch (push_history (in
, in
->buffer
)) {
1410 in
->history
= g_list_previous (in
->history
);
1413 if (in
->history
->prev
)
1414 in
->history
= g_list_previous (in
->history
);
1419 } else if (in
->history
->prev
)
1420 in
->history
= g_list_previous (in
->history
);
1423 assign_text (in
, (char *) in
->history
->data
);
1428 hist_next (WInput
*in
)
1430 if (in
->need_push
) {
1431 switch (push_history (in
, in
->buffer
)) {
1433 assign_text (in
, "");
1443 if (!in
->history
->next
) {
1444 assign_text (in
, "");
1448 in
->history
= g_list_next (in
->history
);
1449 assign_text (in
, (char *) in
->history
->data
);
1453 static const struct {
1455 void (*fn
)(WInput
*in
);
1458 { XCTRL('a'), beginning_of_line
},
1459 { KEY_HOME
, beginning_of_line
},
1460 { KEY_A1
, beginning_of_line
},
1461 { ALT ('<'), beginning_of_line
},
1462 { XCTRL('e'), end_of_line
},
1463 { KEY_END
, end_of_line
},
1464 { KEY_C1
, end_of_line
},
1465 { ALT ('>'), end_of_line
},
1466 { KEY_LEFT
, key_left
},
1467 { KEY_LEFT
| KEY_M_CTRL
, key_ctrl_left
},
1468 { XCTRL('b'), backward_char
},
1469 { ALT('b'), backward_word
},
1470 { KEY_RIGHT
, key_right
},
1471 { KEY_RIGHT
| KEY_M_CTRL
, key_ctrl_right
},
1472 { XCTRL('f'), forward_char
},
1473 { ALT('f'), forward_word
},
1476 { KEY_BACKSPACE
, backward_delete
},
1477 { KEY_DC
, delete_char
},
1478 { ALT('d'), kill_word
},
1479 { ALT(KEY_BACKSPACE
), back_kill_word
},
1481 /* Region manipulation */
1483 { XCTRL('w'), kill_region
},
1484 { ALT('w'), kill_save
},
1485 { XCTRL('y'), yank
},
1486 { XCTRL('k'), kill_line
},
1489 { ALT('p'), hist_prev
},
1490 { ALT('n'), hist_next
},
1491 { ALT('h'), do_show_hist
},
1494 { ALT('\t'), complete
},
1499 /* This function is a test for a special input key used in complete.c */
1500 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1501 and 2 if it is a complete key */
1503 is_in_input_map (WInput
*in
, int c_code
)
1509 for (i
= 0; input_map
[i
].fn
; i
++)
1510 if (c_code
== input_map
[i
].key_code
) {
1511 if (input_map
[i
].fn
== complete
)
1520 port_region_marked_for_delete (WInput
*in
)
1528 handle_char (WInput
*in
, int c_code
)
1533 v
= MSG_NOT_HANDLED
;
1536 free_completions (in
);
1537 v
= insert_char (in
, c_code
);
1538 update_input (in
, 1);
1543 for (i
= 0; input_map
[i
].fn
; i
++){
1544 if (c_code
== input_map
[i
].key_code
){
1545 if (input_map
[i
].fn
!= complete
)
1546 free_completions (in
);
1547 (*input_map
[i
].fn
)(in
);
1552 if (!input_map
[i
].fn
){
1553 if (c_code
> 255 || !is_printable (c_code
))
1554 return MSG_NOT_HANDLED
;
1556 port_region_marked_for_delete (in
);
1558 free_completions (in
);
1559 v
= insert_char (in
, c_code
);
1561 update_input (in
, 1);
1565 /* Inserts text in input line */
1567 stuff (WInput
*in
, const char *text
, int insert_extra_space
)
1569 input_disable_update (in
);
1571 handle_char (in
, *text
++);
1572 if (insert_extra_space
)
1573 handle_char (in
, ' ');
1574 input_enable_update (in
);
1575 update_input (in
, 1);
1579 input_set_point (WInput
*in
, int pos
)
1581 if (pos
> in
->current_max_len
)
1582 pos
= in
->current_max_len
;
1583 if (pos
!= in
->point
)
1584 free_completions (in
);
1586 update_input (in
, 1);
1590 input_callback (Widget
*w
, widget_msg_t msg
, int parm
)
1592 WInput
*in
= (WInput
*) w
;
1597 if (parm
== XCTRL ('q')) {
1599 v
= handle_char (in
, ascii_alpha_to_cntrl (mi_getch ()));
1604 /* Keys we want others to handle */
1605 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1606 || parm
== KEY_F (10) || parm
== XCTRL ('g') || parm
== '\n')
1607 return MSG_NOT_HANDLED
;
1609 /* When pasting multiline text, insert literal Enter */
1610 if ((parm
& ~KEY_M_MASK
) == '\n') {
1612 v
= handle_char (in
, '\n');
1617 return handle_char (in
, parm
);
1620 case WIDGET_UNFOCUS
:
1622 update_input (in
, 0);
1626 widget_move (&in
->widget
, 0, in
->point
- in
->first_shown
);
1629 case WIDGET_DESTROY
:
1634 return default_proc (msg
, parm
);
1639 input_event (Gpm_Event
* event
, void *data
)
1643 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
1644 dlg_select_widget (in
);
1646 if (event
->x
>= in
->field_len
- HISTORY_BUTTON_WIDTH
+ 1
1647 && should_show_history_button (in
)) {
1650 in
->point
= strlen (in
->buffer
);
1651 if (event
->x
- in
->first_shown
- 1 < in
->point
)
1652 in
->point
= event
->x
- in
->first_shown
- 1;
1656 update_input (in
, 1);
1662 input_new (int y
, int x
, int color
, int len
, const char *def_text
,
1663 const char *histname
, INPUT_COMPLETE_FLAGS completion_flags
)
1665 WInput
*in
= g_new (WInput
, 1);
1666 int initial_buffer_len
;
1668 init_widget (&in
->widget
, y
, x
, 1, len
, input_callback
, input_event
);
1672 in
->history_name
= 0;
1675 in
->history_name
= g_strdup (histname
);
1676 in
->history
= history_get (histname
);
1683 if (def_text
== INPUT_LAST_TEXT
) {
1686 if (in
->history
->data
)
1687 def_text
= (char *) in
->history
->data
;
1689 initial_buffer_len
= 1 + max ((size_t) len
, strlen (def_text
));
1690 in
->widget
.options
|= W_IS_INPUT
;
1691 in
->completions
= NULL
;
1692 in
->completion_flags
= completion_flags
;
1693 in
->current_max_len
= initial_buffer_len
;
1694 in
->buffer
= g_malloc (initial_buffer_len
);
1696 in
->field_len
= len
;
1698 in
->first_shown
= 0;
1699 in
->disable_update
= 0;
1702 in
->is_password
= 0;
1704 strcpy (in
->buffer
, def_text
);
1705 in
->point
= strlen (in
->buffer
);
1710 /* Listbox widget */
1712 /* Should draw the scrollbar, but currently draws only
1713 * indications that there is more information
1715 static int listbox_cdiff (WLEntry
*s
, WLEntry
*e
);
1718 listbox_drawscroll (WListbox
*l
)
1722 int max_line
= l
->height
-1;
1724 /* Are we at the top? */
1725 widget_move (&l
->widget
, 0, l
->width
);
1726 if (l
->list
== l
->top
)
1731 /* Are we at the bottom? */
1732 widget_move (&l
->widget
, max_line
, l
->width
);
1733 top
= listbox_cdiff (l
->list
, l
->top
);
1734 if ((top
+ l
->height
== l
->count
) || l
->height
>= l
->count
)
1739 /* Now draw the nice relative pointer */
1741 line
= 1+ ((l
->pos
* (l
->height
-2)) / l
->count
);
1745 for (i
= 1; i
< max_line
; i
++){
1746 widget_move (&l
->widget
, i
, l
->width
);
1755 listbox_draw (WListbox
*l
, int focused
)
1760 Dlg_head
*h
= l
->widget
.parent
;
1761 int normalc
= DLG_NORMALC (h
);
1766 selc
= DLG_FOCUSC (h
);
1768 selc
= DLG_HOT_FOCUSC (h
);
1772 for (e
= l
->top
, i
= 0; (i
< l
->height
); i
++){
1774 /* Display the entry */
1775 if (e
== l
->current
&& sel_line
== -1){
1781 widget_move (&l
->widget
, i
, 0);
1783 if ((i
> 0 && e
== l
->list
) || !l
->list
)
1789 tty_printf (" %-*s ", l
->width
-2, name_trunc (text
, l
->width
-2));
1791 l
->cursor_y
= sel_line
;
1795 listbox_drawscroll (l
);
1798 /* Returns the number of items between s and e,
1799 must be on the same linked list */
1801 listbox_cdiff (WLEntry
*s
, WLEntry
*e
)
1805 for (count
= 0; s
!= e
; count
++)
1811 listbox_check_hotkey (WListbox
*l
, int key
)
1823 /* If we didn't find anything, return */
1824 if (i
&& e
== l
->list
)
1827 if (e
->hotkey
== key
)
1835 /* Used only for display updating, for avoiding line at a time scroll */
1837 listbox_select_last (WListbox
*l
, int set_top
)
1840 l
->current
= l
->list
->prev
;
1841 l
->pos
= l
->count
- 1;
1843 l
->top
= l
->list
->prev
;
1848 listbox_remove_list (WListbox
*l
)
1857 while (l
->count
--) {
1863 l
->pos
= l
->count
= 0;
1864 l
->list
= l
->top
= l
->current
= 0;
1868 * bor 30.10.96: added force flag to remove *last* entry as well
1869 * bor 30.10.96: corrected selection bug if last entry was removed
1873 listbox_remove_current (WListbox
*l
, int force
)
1877 /* Ok, note: this won't allow for emtpy lists */
1878 if (!force
&& (!l
->count
|| l
->count
== 1))
1885 l
->current
->next
->prev
= l
->current
->prev
;
1886 l
->current
->prev
->next
= l
->current
->next
;
1887 if (p
->next
== l
->list
) {
1888 l
->current
= p
->prev
;
1892 l
->current
= p
->next
;
1895 l
->list
= l
->top
= p
->next
;
1898 l
->list
= l
->top
= l
->current
= 0;
1905 /* Makes *e the selected entry (sets current and pos) */
1907 listbox_select_entry (WListbox
*l
, WLEntry
*dest
)
1916 for (pos
= 0, e
= l
->list
; pos
< l
->count
; e
= e
->next
, pos
++){
1924 while (listbox_cdiff (l
->top
, l
->current
) >= l
->height
)
1925 l
->top
= l
->top
->next
;
1927 l
->top
= l
->current
;
1933 /* If we are unable to find it, set decent values */
1934 l
->current
= l
->top
= l
->list
;
1938 /* Selects from base the pos element */
1940 listbox_select_pos (WListbox
*l
, WLEntry
*base
, int pos
)
1942 WLEntry
*last
= l
->list
->prev
;
1954 static inline cb_ret_t
1955 listbox_back (WListbox
*l
)
1958 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, l
->pos
-1));
1961 return MSG_NOT_HANDLED
;
1964 /* Return MSG_HANDLED if we want a redraw */
1966 listbox_key (WListbox
*l
, int key
)
1972 return MSG_NOT_HANDLED
;
1978 l
->current
= l
->top
= l
->list
;
1985 l
->current
= l
->top
= l
->list
->prev
;
1986 for (i
= min (l
->height
- 1, l
->count
- 1); i
; i
--)
1987 l
->top
= l
->top
->prev
;
1988 l
->pos
= l
->count
- 1;
2003 for (i
= 0; i
< l
->height
-1; i
++)
2004 j
|= listbox_fwd (l
);
2005 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2009 for (i
= 0; i
< l
->height
-1; i
++)
2010 j
|= listbox_back (l
);
2011 return (j
> 0) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
2013 return MSG_NOT_HANDLED
;
2017 listbox_destroy (WListbox
*l
)
2019 WLEntry
*n
, *p
= l
->list
;
2022 for (i
= 0; i
< l
->count
; i
++){
2031 listbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2033 WListbox
*l
= (WListbox
*) w
;
2036 Dlg_head
*h
= l
->widget
.parent
;
2043 if ((e
= listbox_check_hotkey (l
, parm
)) != NULL
) {
2046 listbox_select_entry (l
, e
);
2049 action
= (*l
->cback
) (l
);
2051 action
= LISTBOX_DONE
;
2053 if (action
== LISTBOX_DONE
) {
2054 h
->ret_value
= B_ENTER
;
2059 return MSG_NOT_HANDLED
;
2062 if ((ret_code
= listbox_key (l
, parm
)))
2063 listbox_draw (l
, 1);
2067 widget_move (&l
->widget
, l
->cursor_y
, 0);
2071 case WIDGET_UNFOCUS
:
2073 listbox_draw (l
, msg
!= WIDGET_UNFOCUS
);
2076 case WIDGET_DESTROY
:
2077 listbox_destroy (l
);
2081 return default_proc (msg
, parm
);
2086 listbox_event (Gpm_Event
*event
, void *data
)
2092 Dlg_head
*h
= l
->widget
.parent
;
2095 if (event
->type
& GPM_DOWN
)
2096 dlg_select_widget (l
);
2099 if (event
->type
& (GPM_DOWN
| GPM_DRAG
)) {
2100 if (event
->x
< 0 || event
->x
>= l
->width
)
2103 for (i
= -event
->y
; i
>= 0; i
--)
2105 else if (event
->y
> l
->height
)
2106 for (i
= event
->y
- l
->height
; i
> 0; i
--)
2109 listbox_select_entry (l
,
2110 listbox_select_pos (l
, l
->top
,
2113 /* We need to refresh ourselves since the dialog manager doesn't */
2114 /* know about this event */
2115 listbox_callback (w
, WIDGET_DRAW
, 0);
2121 if ((event
->type
& (GPM_DOUBLE
| GPM_UP
)) == (GPM_UP
| GPM_DOUBLE
)) {
2124 if (event
->x
< 0 || event
->x
>= l
->width
)
2126 if (event
->y
< 1 || event
->y
> l
->height
)
2129 dlg_select_widget (l
);
2130 listbox_select_entry (l
,
2131 listbox_select_pos (l
, l
->top
,
2135 action
= (*l
->cback
) (l
);
2137 action
= LISTBOX_DONE
;
2139 if (action
== LISTBOX_DONE
) {
2140 h
->ret_value
= B_ENTER
;
2149 listbox_new (int y
, int x
, int width
, int height
, lcback callback
)
2151 WListbox
*l
= g_new (WListbox
, 1);
2153 init_widget (&l
->widget
, y
, x
, height
, width
,
2154 listbox_callback
, listbox_event
);
2156 l
->list
= l
->top
= l
->current
= 0;
2164 l
->cback
= callback
;
2165 l
->allow_duplicates
= 1;
2166 l
->scrollbar
= slow_terminal
? 0 : 1;
2167 widget_want_hotkey (l
->widget
, 1);
2172 /* Listbox item adding function. They still lack a lot of functionality */
2174 /* 1.11.96 bor: added pos argument to control placement of new entry */
2176 listbox_append_item (WListbox
*l
, WLEntry
*e
, enum append_pos pos
)
2184 } else if (pos
== LISTBOX_APPEND_AT_END
) {
2186 e
->prev
= l
->list
->prev
;
2187 l
->list
->prev
->next
= e
;
2189 } else if (pos
== LISTBOX_APPEND_BEFORE
){
2190 e
->next
= l
->current
;
2191 e
->prev
= l
->current
->prev
;
2192 l
->current
->prev
->next
= e
;
2193 l
->current
->prev
= e
;
2194 if (l
->list
== l
->current
) { /* move list one position down */
2198 } else if (pos
== LISTBOX_APPEND_AFTER
) {
2199 e
->prev
= l
->current
;
2200 e
->next
= l
->current
->next
;
2201 l
->current
->next
->prev
= e
;
2202 l
->current
->next
= e
;
2203 } else if (pos
== LISTBOX_APPEND_SORTED
) {
2204 WLEntry
*w
= l
->list
;
2206 while (w
->next
!= l
->list
&& strcmp (e
->text
, w
->text
) > 0)
2208 if (w
->next
== l
->list
) {
2224 listbox_add_item (WListbox
*l
, enum append_pos pos
, int hotkey
,
2225 const char *text
, void *data
)
2232 if (!l
->allow_duplicates
)
2233 if (listbox_search_text (l
, text
))
2236 entry
= g_new (WLEntry
, 1);
2237 entry
->text
= g_strdup (text
);
2239 entry
->hotkey
= hotkey
;
2241 listbox_append_item (l
, entry
, pos
);
2246 /* Selects the nth entry in the listbox */
2248 listbox_select_by_number (WListbox
*l
, int n
)
2250 listbox_select_entry (l
, listbox_select_pos (l
, l
->list
, n
));
2254 listbox_search_text (WListbox
*l
, const char *text
)
2263 if(!strcmp (e
->text
, text
))
2266 } while (e
!=l
->list
);
2271 /* Returns the current string text as well as the associated extra data */
2273 listbox_get_current (WListbox
*l
, char **string
, char **extra
)
2279 if (string
&& l
->current
)
2280 *string
= l
->current
->text
;
2281 if (extra
&& l
->current
)
2282 *extra
= l
->current
->data
;
2285 /* returns TRUE if a function has been called, FALSE otherwise. */
2287 buttonbar_call (WButtonBar
*bb
, int i
)
2289 switch (bb
->labels
[i
].tag
) {
2293 bb
->labels
[i
].u
.fn_void ();
2296 bb
->labels
[i
].u
.fn_ptr (bb
->labels
[i
].data
);
2304 buttonbar_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2306 WButtonBar
*bb
= (WButtonBar
*) w
;
2311 return MSG_NOT_HANDLED
;
2314 for (i
= 0; i
< 10; i
++) {
2315 if (parm
== KEY_F (i
+ 1) && buttonbar_call (bb
, i
))
2318 return MSG_NOT_HANDLED
;
2323 widget_move (&bb
->widget
, 0, 0);
2324 attrset (DEFAULT_COLOR
);
2325 tty_printf ("%-*s", bb
->widget
.cols
, "");
2326 for (i
= 0; i
< COLS
/ 8 && i
< 10; i
++) {
2327 widget_move (&bb
->widget
, 0, i
* 8);
2328 attrset (DEFAULT_COLOR
);
2329 tty_printf ("%d", i
+ 1);
2330 attrset (SELECTED_COLOR
);
2331 tty_printf ("%-*s", ((i
+ 1) * 8 == COLS
? 5 : 6),
2332 bb
->labels
[i
].text
? bb
->labels
[i
].text
: "");
2333 attrset (DEFAULT_COLOR
);
2335 attrset (SELECTED_COLOR
);
2338 case WIDGET_DESTROY
:
2339 for (i
= 0; i
< 10; i
++)
2340 g_free (bb
->labels
[i
].text
);
2344 return default_proc (msg
, parm
);
2349 buttonbar_event (Gpm_Event
*event
, void *data
)
2351 WButtonBar
*bb
= data
;
2354 if (!(event
->type
& GPM_UP
))
2358 button
= event
->x
/ 8;
2360 buttonbar_call (bb
, button
);
2365 buttonbar_new (int visible
)
2368 WButtonBar
*bb
= g_new (WButtonBar
, 1);
2370 init_widget (&bb
->widget
, LINES
-1, 0, 1, COLS
,
2371 buttonbar_callback
, buttonbar_event
);
2373 bb
->visible
= visible
;
2374 for (i
= 0; i
< 10; i
++){
2375 bb
->labels
[i
].text
= NULL
;
2376 bb
->labels
[i
].tag
= BBFUNC_NONE
;
2378 widget_want_hotkey (bb
->widget
, 1);
2379 widget_want_cursor (bb
->widget
, 0);
2385 set_label_text (WButtonBar
* bb
, int index
, const char *text
)
2387 g_free (bb
->labels
[index
- 1].text
);
2389 bb
->labels
[index
- 1].text
= g_strdup (text
);
2392 /* Find ButtonBar widget in the dialog */
2394 find_buttonbar (Dlg_head
*h
)
2398 bb
= (WButtonBar
*) find_widget_type (h
, buttonbar_callback
);
2403 buttonbar_clear_label (Dlg_head
*h
, int idx
)
2405 WButtonBar
*bb
= find_buttonbar (h
);
2410 set_label_text (bb
, idx
, "");
2411 bb
->labels
[idx
- 1].tag
= BBFUNC_NONE
;
2415 buttonbar_set_label_data (Dlg_head
*h
, int idx
, const char *text
, buttonbarfn cback
,
2418 WButtonBar
*bb
= find_buttonbar (h
);
2423 assert (cback
!= (buttonbarfn
) 0);
2424 set_label_text (bb
, idx
, text
);
2425 bb
->labels
[idx
- 1].tag
= BBFUNC_PTR
;
2426 bb
->labels
[idx
- 1].u
.fn_ptr
= cback
;
2427 bb
->labels
[idx
- 1].data
= data
;
2431 buttonbar_set_label (Dlg_head
*h
, int idx
, const char *text
, voidfn cback
)
2433 WButtonBar
*bb
= find_buttonbar (h
);
2438 assert (cback
!= (voidfn
) 0);
2439 set_label_text (bb
, idx
, text
);
2440 bb
->labels
[idx
- 1].tag
= BBFUNC_VOID
;
2441 bb
->labels
[idx
- 1].u
.fn_void
= cback
;
2445 buttonbar_set_visible (WButtonBar
*bb
, bool visible
)
2447 bb
->visible
= visible
;
2451 buttonbar_redraw (Dlg_head
*h
)
2453 WButtonBar
*bb
= find_buttonbar (h
);
2458 send_message ((Widget
*) bb
, WIDGET_DRAW
, 0);
2462 groupbox_callback (Widget
*w
, widget_msg_t msg
, int parm
)
2464 WGroupbox
*g
= (WGroupbox
*) w
;
2471 return MSG_NOT_HANDLED
;
2474 attrset (COLOR_NORMAL
);
2475 draw_box (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2476 g
->widget
.x
- g
->widget
.parent
->x
, g
->widget
.lines
,
2479 attrset (COLOR_HOT_NORMAL
);
2480 dlg_move (g
->widget
.parent
, g
->widget
.y
- g
->widget
.parent
->y
,
2481 g
->widget
.x
- g
->widget
.parent
->x
+ 1);
2485 case WIDGET_DESTROY
:
2490 return default_proc (msg
, parm
);
2495 groupbox_new (int x
, int y
, int width
, int height
, const char *title
)
2497 WGroupbox
*g
= g_new (WGroupbox
, 1);
2499 init_widget (&g
->widget
, y
, x
, height
, width
, groupbox_callback
, NULL
);
2501 g
->widget
.options
&= ~W_WANT_CURSOR
;
2502 widget_want_hotkey (g
->widget
, 0);
2504 /* Strip existing spaces, add one space before and after the title */
2507 t
= g_strstrip (g_strdup (title
));
2508 g
->title
= g_strconcat (" ", t
, " ", (char *) NULL
);