ooops reverting mischanged option menu order...
[midnight-commander.git] / src / dlg.c
blob506fd3fee9e00dd04a05d51778374960f97cfca7
1 /* Dlg box features module for the Midnight Commander
2 Copyright (C) 1994, 1995 Radek Doulik, Miguel de Icaza
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <config.h>
20 /* "$Id$" */
21 #include <string.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <stdarg.h>
25 #include "global.h"
26 #include "tty.h"
27 #include "menu.h"
28 #include "win.h"
29 #include "color.h"
30 #include "mouse.h"
31 #include "help.h"
32 #include "key.h" /* For mi_getch() */
33 #include "dlg.h"
34 #include "dialog.h" /* For push_refresh() and pop_refresh() */
35 #include "layout.h"
36 #include "main.h"
38 #define waddc(w,y1,x1,c) move (w->y+y1, w->x+x1); addch (c)
40 /* Primitive way to check if the the current dialog is our dialog */
41 /* This is needed by async routines like load_prompt */
42 Dlg_head *current_dlg = 0;
44 /* A hook list for idle events */
45 Hook *idle_hook = 0;
47 static void dlg_broadcast_msg_to (Dlg_head *h, int message, int reverse, int flags);
49 static void slow_box (Dlg_head *h, int y, int x, int ys, int xs)
51 move (h->y+y, h->x+x);
52 hline (' ', xs);
53 vline (' ', ys);
54 move (h->y+y, h->x+x+xs-1);
55 vline (' ', ys);
56 move (h->y+y+ys-1, h->x+x);
57 hline (' ', xs);
60 /* draw box in window */
61 void draw_box (Dlg_head *h, int y, int x, int ys, int xs)
63 extern int slow_terminal;
65 if (slow_terminal){
66 slow_box (h, y, x, ys, xs);
67 return;
70 #ifndef HAVE_SLANG
71 waddc (h, y, x, ACS_ULCORNER);
72 hline (ACS_HLINE, xs - 2);
73 waddc (h, y + ys - 1, x, ACS_LLCORNER);
74 hline (ACS_HLINE, xs - 2);
76 waddc (h, y, x + xs - 1, ACS_URCORNER);
77 waddc (h, y + ys - 1, x + xs - 1, ACS_LRCORNER);
79 move (h->y+y+1, h->x+x);
80 vline (ACS_VLINE, ys - 2);
81 move (h->y+y+1, h->x+x+xs-1);
82 vline (ACS_VLINE, ys - 2);
83 #else
84 SLsmg_draw_box (h->y+y, h->x+x, ys, xs);
85 #endif /* HAVE_SLANG */
88 /* draw box in window */
89 void draw_double_box (Dlg_head *h, int y, int x, int ys, int xs)
91 #ifndef HAVE_SLANG
92 draw_box (h, y, x, ys, xs);
93 #else
94 SLsmg_draw_double_box (h->y+y, h->x+x, ys, xs);
95 #endif /* HAVE_SLANG */
98 void widget_erase (Widget *w)
100 int x, y;
102 for (y = 0; y < w->lines; y++){
103 widget_move (w, y, 0);
104 for (x = 0; x < w->cols; x++)
105 addch (' ');
109 void dlg_erase (Dlg_head *h)
111 int x, y;
113 for (y = 0; y < h->lines; y++){
114 move (y+h->y, h->x); /* FIXME: should test if ERR */
115 for (x = 0; x < h->cols; x++){
116 addch (' ');
121 void init_widget (Widget *w, int y, int x, int lines, int cols,
122 int (*callback)(Dlg_head *, void *, int, int),
123 destroy_fn destroy, mouse_h mouse_handler, char *tkname)
125 w->x = x;
126 w->y = y;
127 w->cols = cols;
128 w->lines = lines;
129 w->callback = callback;
130 w->destroy = destroy;
131 w->mouse = mouse_handler;
132 w->parent = 0;
133 w->tkname = tkname;
135 if (tkname && *tkname == 0){
136 fprintf (stderr, "Got a null string for the tkname\n");
137 abort ();
139 /* Almost all widgets want to put the cursor in a suitable place */
140 w->options = W_WANT_CURSOR;
143 /* Default callback for widgets */
144 int default_proc (Dlg_head *h, int Msg, int Par)
146 switch (Msg){
148 case WIDGET_HOTKEY: /* Didn't use the key */
149 return 0;
151 case WIDGET_INIT: /* We could tell if something went wrong */
152 return 1;
154 case WIDGET_KEY:
155 return 0; /* Didn't use the key */
157 case WIDGET_FOCUS: /* We accept FOCUSes */
158 return 1;
160 case WIDGET_UNFOCUS: /* We accept loose FOCUSes */
161 return 1;
163 case WIDGET_DRAW:
164 return 1;
166 case WIDGET_DESTROY:
167 return 1;
169 case WIDGET_CURSOR:
170 /* Move the cursor to the default widget position */
171 return 1;
173 case WIDGET_IDLE:
174 return 1;
176 printf ("Internal error: unhandled message: %d\n", Msg);
177 return 1;
180 /* Clean the dialog area, draw the frame and the title */
181 void
182 common_dialog_repaint (struct Dlg_head *h)
184 int space;
186 space = (h->flags & DLG_COMPACT) ? 0 : 1;
188 attrset (NORMALC);
189 dlg_erase (h);
190 draw_box (h, space, space, h->lines - 2 * space, h->cols - 2 * space);
192 if (h->title) {
193 attrset (HOT_NORMALC);
194 dlg_move (h, space, (h->cols - strlen (h->title)) / 2);
195 addstr (h->title);
199 /* Default dialog callback */
200 int default_dlg_callback (Dlg_head *h, int id, int msg)
202 if (msg == DLG_DRAW && h->color) {
203 common_dialog_repaint (h);
204 return MSG_HANDLED;
206 if (msg == DLG_IDLE){
207 dlg_broadcast_msg_to (h, WIDGET_IDLE, 0, W_WANT_IDLE);
208 return MSG_HANDLED;
210 return MSG_NOT_HANDLED;
213 Dlg_head *create_dlg (int y1, int x1, int lines, int cols,
214 const int *color_set,
215 int (*callback) (struct Dlg_head *, int, int),
216 char *help_ctx, const char *title, int flags)
218 Dlg_head *new_d;
220 if (flags & DLG_CENTER){
221 y1 = (LINES-lines)/2;
222 x1 = (COLS-cols)/2;
225 if ((flags & DLG_TRYUP) && (y1 > 3))
226 y1 -= 2;
228 new_d = g_new0 (Dlg_head, 1);
229 new_d->color = color_set;
230 new_d->help_ctx = help_ctx;
231 new_d->callback = callback ? callback : default_dlg_callback;
232 new_d->x = x1;
233 new_d->y = y1;
234 new_d->cols = cols;
235 new_d->lines = lines;
236 new_d->flags = flags;
238 /* Strip existing spaces, add one space before and after the title */
239 if (title) {
240 char *t;
241 t = g_strstrip (g_strdup (title));
242 new_d->title = g_strconcat (" ", t, " ", NULL);
243 g_free (t);
246 return (new_d);
249 void set_idle_proc (Dlg_head *d, int state)
251 d->send_idle_msg = state;
254 /* add component to dialog buffer */
255 int add_widget (Dlg_head *where, void *what)
257 Widget_Item *back;
258 Widget *widget = (Widget *) what;
260 /* Don't accept 0 widgets, this could be from widgets that could not */
261 /* initialize properly */
262 if (!what)
263 return 0;
265 widget->x += where->x;
266 widget->y += where->y;
268 if (where->running){
269 Widget_Item *point = where->current;
271 where->current = g_new (Widget_Item, 1);
273 if (point){
274 where->current->next = point->next;
275 where->current->prev = point;
276 point->next->prev = where->current;
277 point->next = where->current;
278 } else {
279 where->current->next = where->current;
280 where->first = where->current;
281 where->current->prev = where->first;
282 where->last = where->current;
283 where->first->next = where->last;
285 } else {
286 back = where->current;
287 where->current = g_new (Widget_Item, 1);
288 if (back){
289 back->prev = where->current;
290 where->current->next = back;
291 } else {
292 where->current->next = where->current;
293 where->first = where->current;
296 where->current->prev = where->first;
297 where->last = where->current;
298 where->first->next = where->last;
301 where->current->dlg_id = where->count;
302 where->current->widget = what;
303 where->current->widget->parent = where;
305 where->count++;
307 /* If the widget is inserted in a running dialog */
308 if (where->running){
309 send_message (where, widget, WIDGET_INIT, 0);
310 send_message (where, widget, WIDGET_DRAW, 0);
312 return (where->count - 1);
315 int send_message (Dlg_head *h, Widget *w, int msg, int par)
317 return (*(w->callback))(h, w, msg, par);
320 /* broadcast a message to all the widgets in a dialog that have
321 * the options set to flags.
323 static void
324 dlg_broadcast_msg_to (Dlg_head *h, int message, int reverse, int flags)
326 Widget_Item *p, *first, *wi;
328 if (!h->current)
329 return;
331 if (reverse)
332 first = p = h->current->prev;
333 else
334 first = p = h->current->next;
336 do {
337 wi = p;
338 if (reverse)
339 p = p->prev;
340 else
341 p = p->next;
342 send_message (h, wi->widget, message, 0);
343 } while (first != p);
346 /* broadcast a message to all the widgets in a dialog */
347 void dlg_broadcast_msg (Dlg_head *h, int message, int reverse)
349 dlg_broadcast_msg_to (h, message, reverse, ~0);
352 int dlg_focus (Dlg_head *h)
354 if (!h->current)
355 return 0;
357 if (send_message (h, h->current->widget, WIDGET_FOCUS, 0)){
358 (*h->callback) (h, h->current->dlg_id, DLG_FOCUS);
359 return 1;
361 return 0;
364 static int
365 dlg_unfocus (Dlg_head *h)
367 if (!h->current)
368 return 0;
370 if (send_message (h, h->current->widget, WIDGET_UNFOCUS, 0)){
371 (*h->callback) (h, h->current->dlg_id, DLG_UNFOCUS);
372 return 1;
374 return 0;
377 static void select_a_widget (Dlg_head *h, int down)
379 int dir_forward = !(h->flags & DLG_BACKWARD);
381 if (!h->current)
382 return;
384 if (!down)
385 dir_forward = !dir_forward;
387 do {
388 if (dir_forward)
389 h->current = h->current->next;
390 else
391 h->current = h->current->prev;
393 (*h->callback) (h, h->current->dlg_id, DLG_ONE_DOWN);
394 } while (!dlg_focus (h));
397 /* Return true if the windows overlap */
398 int dlg_overlap (Widget *a, Widget *b)
400 if ((b->x >= a->x + a->cols)
401 || (a->x >= b->x + b->cols)
402 || (b->y >= a->y + a->lines)
403 || (a->y >= b->y + b->lines))
404 return 0;
405 return 1;
409 /* Searches a widget, uses the callback as a signature in the dialog h */
410 Widget *find_widget_type (Dlg_head *h, callback_fn signature)
412 Widget *w;
413 Widget_Item *item;
414 int i;
416 if (!h)
417 return 0;
418 if (!h->current)
419 return 0;
421 w = 0;
422 for (i = 0, item = h->current; i < h->count; i++, item = item->next){
423 if (item->widget->callback == signature){
424 w = item->widget;
425 break;
428 return w;
431 void dlg_one_up (Dlg_head *h)
433 Widget_Item *old;
435 old = h->current;
437 if (!old)
438 return;
440 /* If it accepts unFOCUSion */
441 if (!dlg_unfocus(h))
442 return;
444 select_a_widget (h, 0);
445 if (dlg_overlap (old->widget, h->current->widget)){
446 send_message (h, h->current->widget, WIDGET_DRAW, 0);
447 send_message (h, h->current->widget, WIDGET_FOCUS, 0);
451 void dlg_one_down (Dlg_head *h)
453 Widget_Item *old;
455 old = h->current;
456 if (!old)
457 return;
459 if (!dlg_unfocus (h))
460 return;
462 select_a_widget (h, 1);
463 if (dlg_overlap (old->widget, h->current->widget)){
464 send_message (h, h->current->widget, WIDGET_DRAW, 0);
465 send_message (h, h->current->widget, WIDGET_FOCUS, 0);
469 int dlg_select_widget (Dlg_head *h, void *w)
471 if (!h->current)
472 return 0;
474 if (dlg_unfocus (h)){
475 while (h->current->widget != w)
476 h->current = h->current->next;
477 while (!dlg_focus (h))
478 h->current = h->current->next;
480 return 1;
482 return 0;
485 int send_message_to (Dlg_head *h, Widget *w, int msg, int par)
487 Widget_Item *p = h->current;
488 int v, i;
490 if (!h->current)
491 return 0;
493 v = 0;
494 for (i = 0; i < h->count; i++){
495 if (w == (void *) p->widget){
496 v = send_message (h, p->widget, msg, par);
497 break;
499 p = p->next;
501 return v;
504 #define callback(h) (h->current->widget->callback)
506 void update_cursor (Dlg_head *h)
508 if (!h->current)
509 return;
510 if (h->current->widget->options & W_WANT_CURSOR)
511 send_message (h, h->current->widget, WIDGET_CURSOR, 0);
512 else {
513 Widget_Item *p = h->current;
515 do {
516 if (p->widget->options & W_WANT_CURSOR)
517 if ((*p->widget->callback)(h, p->widget, WIDGET_CURSOR, 0)){
518 break;
520 p = p->next;
521 } while (h->current != p);
525 /* Redraw the widgets in reverse order, leaving the current widget
526 * as the last one
528 void dlg_redraw (Dlg_head *h)
530 (h->callback)(h, 0, DLG_DRAW);
532 dlg_broadcast_msg (h, WIDGET_DRAW, 1);
534 update_cursor (h);
537 static void
538 dlg_refresh (void *parameter)
540 dlg_redraw ((Dlg_head *) parameter);
543 void dlg_stop (Dlg_head *h)
545 h->running = 0;
548 static inline void dialog_handle_key (Dlg_head *h, int d_key)
550 switch (d_key){
551 case KEY_LEFT:
552 case KEY_UP:
553 dlg_one_up (h);
554 break;
556 case KEY_RIGHT:
557 case KEY_DOWN:
558 dlg_one_down (h);
559 break;
561 case KEY_F(1):
562 interactive_display (NULL, h->help_ctx);
563 do_refresh ();
564 break;
566 case XCTRL('z'):
567 suspend_cmd ();
568 /* Fall through */
570 case XCTRL('l'):
571 #ifndef HAVE_SLANG
572 /* Use this if the refreshes fail */
573 clr_scr ();
574 do_refresh ();
575 #else
576 touchwin (stdscr);
577 #endif /* HAVE_SLANG */
578 mc_refresh ();
579 doupdate ();
580 break;
582 case '\n':
583 case KEY_ENTER:
584 h->ret_value = B_ENTER;
585 h->running = 0;
586 break;
588 case ESC_CHAR:
589 case KEY_F (10):
590 case XCTRL ('c'):
591 case XCTRL ('g'):
592 h->ret_value = B_CANCEL;
593 dlg_stop (h);
594 break;
598 static int dlg_try_hotkey (Dlg_head *h, int d_key)
600 Widget_Item *hot_cur;
601 Widget_Item *previous;
602 int handled, c;
604 if (!h->current)
605 return 0;
608 * Explanation: we don't send letter hotkeys to other widgets if
609 * the currently selected widget is an input line
612 if (h->current->widget->options & W_IS_INPUT){
613 if(d_key < 255 && isalpha(d_key))
614 return 0;
617 /* If it's an alt key, send the message */
618 c = d_key & ~ALT(0);
619 if (d_key & ALT(0) && c < 255 && isalpha(c))
620 d_key = tolower(c);
622 #ifdef NATIVE_WIN32
623 /* .ado: fix problem with file_permission under Win95 */
624 if (d_key == 0) return 0;
625 #endif
627 handled = 0;
628 if (h->current->widget->options & W_WANT_HOTKEY)
629 handled = callback (h) (h, h->current->widget, WIDGET_HOTKEY, d_key);
631 /* If not used, send hotkey to other widgets */
632 if (handled)
633 return handled;
635 hot_cur = h->current;
637 /* send it to all widgets */
638 do {
639 if (hot_cur->widget->options & W_WANT_HOTKEY)
640 handled |= (*hot_cur->widget->callback)
641 (h, hot_cur->widget, WIDGET_HOTKEY, d_key);
643 if (!handled)
644 hot_cur = hot_cur->next;
645 } while (h->current != hot_cur && !handled);
647 if (!handled)
648 return 0;
650 (*h->callback) (h, 0, DLG_HOTKEY_HANDLED);
651 previous = h->current;
652 if (!dlg_unfocus (h))
653 return handled;
655 h->current = hot_cur;
656 if (!dlg_focus (h)){
657 h->current = previous;
658 dlg_focus (h);
660 return handled;
663 static int
664 dlg_key_event (Dlg_head * h, int d_key)
666 int handled;
668 if (!h->current)
669 return 0;
671 /* TAB used to cycle */
672 if (!(h->flags & DLG_WANT_TAB)
673 && (d_key == '\t' || d_key == KEY_BTAB)) {
674 if (d_key == '\t')
675 dlg_one_down (h);
676 else
677 dlg_one_up (h);
678 } else {
680 /* first can dlg_callback handle the key */
681 handled = (*h->callback) (h, d_key, DLG_KEY);
683 /* next try the hotkey */
684 if (!handled)
685 handled = dlg_try_hotkey (h, d_key);
687 /* not used - then try widget_callback */
688 if (!handled)
689 handled |=
690 callback (h) (h, h->current->widget, WIDGET_KEY, d_key);
692 /* not used- try to use the unhandled case */
693 if (!handled)
694 handled |= (*h->callback) (h, d_key, DLG_UNHANDLED_KEY);
696 if (!handled)
697 dialog_handle_key (h, d_key);
698 (*h->callback) (h, d_key, DLG_POST_KEY);
700 return handled;
702 return 1;
705 static inline int
706 dlg_mouse_event (Dlg_head * h, Gpm_Event * event)
708 Widget_Item *item;
709 Widget_Item *starting_widget = h->current;
710 Gpm_Event new_event;
711 int x = event->x;
712 int y = event->y;
713 int ret_value;
715 /* kludge for the menubar: start at h->first, not current */
716 /* Must be careful in the insertion order to the dlg list */
717 if (y == 1 && (h->flags & DLG_HAS_MENUBAR))
718 starting_widget = h->first;
720 item = starting_widget;
721 do {
722 Widget *widget = item->widget;
724 item = item->next;
726 if (!((x > widget->x) && (x <= widget->x + widget->cols)
727 && (y > widget->y) && (y <= widget->y + widget->lines)))
728 continue;
730 new_event = *event;
731 new_event.x -= widget->x;
732 new_event.y -= widget->y;
734 ret_value = widget->mouse ? (*widget->mouse) (&new_event, widget) :
735 MOU_NORMAL;
737 return ret_value;
738 } while (item != starting_widget);
739 return 0;
742 /* Run dialog routines */
744 /* Init the process */
745 void init_dlg (Dlg_head *h)
747 int refresh_mode;
749 /* Initialize dialog manager and widgets */
750 (*h->callback) (h, 0, DLG_INIT);
751 dlg_broadcast_msg (h, WIDGET_INIT, 0);
753 if (h->x == 0 && h->y == 0 && h->cols == COLS && h->lines == LINES)
754 refresh_mode = REFRESH_COVERS_ALL;
755 else
756 refresh_mode = REFRESH_COVERS_PART;
758 push_refresh (dlg_refresh, h, refresh_mode);
759 h->refresh_pushed = 1;
761 /* Initialize direction */
762 if (h->flags & DLG_BACKWARD)
763 h->current = h->first;
765 if (h->initfocus != NULL)
766 h->current = h->initfocus;
768 h->previous_dialog = current_dlg;
769 current_dlg = h;
771 /* Initialize the mouse status */
772 h->mouse_status = 0;
774 /* Redraw the screen */
775 dlg_redraw (h);
777 while (!dlg_focus (h) && h->current)
778 h->current = h->current->next;
780 h->ret_value = 0;
781 h->running = 1;
784 /* Shutdown the run_dlg */
785 void dlg_run_done (Dlg_head *h)
787 if (h->current)
788 (*h->callback) (h, h->current->dlg_id, DLG_END);
790 current_dlg = (Dlg_head *) h->previous_dialog;
793 void dlg_process_event (Dlg_head *h, int key, Gpm_Event *event)
795 if (key == EV_NONE){
796 if (got_interrupt ())
797 key = XCTRL('g');
798 else
799 return;
802 if (key == EV_MOUSE)
803 h->mouse_status = dlg_mouse_event (h, event);
804 else
805 dlg_key_event (h, key);
808 static inline void
809 frontend_run_dlg (Dlg_head *h)
811 int d_key;
812 Gpm_Event event;
814 event.x = -1;
815 while (h->running) {
816 #if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
817 /* It does not work with ncurses before 1.9.9g, it will break */
818 if (winch_flag)
819 change_screen_size ();
820 #endif
821 if (is_idle ()){
822 if (idle_hook)
823 execute_hooks (idle_hook);
825 while (h->send_idle_msg && is_idle ()){
826 (*h->callback) (h, 0, DLG_IDLE);
830 update_cursor (h);
831 (*h->callback)(h, 0, DLG_PRE_EVENT);
833 /* Clear interrupt flag */
834 got_interrupt ();
835 d_key = get_event (&event, h->mouse_status == MOU_REPEAT, 1);
837 dlg_process_event (h, d_key, &event);
841 /* Standard run dialog routine
842 * We have to keep this routine small so that we can duplicate it's
843 * behavior on complex routines like the file routines, this way,
844 * they can call the dlg_process_event without rewriting all the code
846 int run_dlg (Dlg_head *h)
848 init_dlg (h);
849 frontend_run_dlg (h);
850 dlg_run_done (h);
851 return h->ret_value;
854 void
855 destroy_dlg (Dlg_head *h)
857 int i;
858 Widget_Item *c;
860 if (h->refresh_pushed)
861 pop_refresh ();
863 dlg_broadcast_msg (h, WIDGET_DESTROY, 0);
864 c = h->current;
865 for (i = 0; i < h->count; i++){
866 if (c->widget->destroy)
867 c->widget->destroy (c->widget);
868 c = c->next;
869 if (h->current){
870 g_free (h->current->widget);
871 g_free (h->current);
873 h->current = c;
875 g_free (h->title);
876 g_free (h);
878 if (refresh_list)
879 do_refresh ();
882 void widget_set_size (Widget *widget, int y, int x, int lines, int cols)
884 widget->x = x;
885 widget->y = y;
886 widget->cols = cols;
887 widget->lines = lines;
890 /* Replace widget old for widget new in the h dialog */
891 void dlg_replace_widget (Dlg_head *h, Widget *old, Widget *new)
893 Widget_Item *p = h->current;
894 int should_focus = 0;
896 if (!h->current)
897 return;
899 do {
900 if (p->widget == old){
902 if (old == h->current->widget)
903 should_focus = 1;
905 /* We found the widget */
906 /* First kill the widget */
907 new->parent = h;
908 send_message_to (h, old, WIDGET_DESTROY, 0);
909 (*old->destroy) (old);
911 /* We insert the new widget */
912 p->widget = new;
913 send_message_to (h, new, WIDGET_INIT, 0);
914 if (should_focus){
915 if (dlg_focus (h) == 0)
916 select_a_widget (h, 1);
918 send_message_to (h, new, WIDGET_DRAW, 0);
919 break;
921 p = p->next;
922 } while (p != h->current);
925 void widget_redraw (Dlg_head *h, Widget_Item *w)
927 Widget_Item *save = h->current;
929 if (!h->current)
930 return;
932 h->current = w;
933 (*w->widget->callback)(h, h->current->widget, WIDGET_DRAW, 0);
934 h->current = save;
937 /* Returns the index of h->current from h->first */
938 int dlg_item_number (Dlg_head *h)
940 Widget_Item *p;
941 int i = 0;
943 p = h->first;
945 do {
946 if (p == h->current)
947 return i;
948 i++;
949 p = p->next;
950 } while (p != h->first);
951 fprintf (stderr, "Internal error: current not in dialog list\n\r");
952 exit (1);
955 int dlg_select_nth_widget (Dlg_head *h, int n)
957 Widget_Item *w;
958 int i;
960 w = h->first;
961 for (i = 0; i < n; i++)
962 w = w->next;
964 return dlg_select_widget (h, w->widget);