remove trailing whitespace at end of lines
[reactos.git] / rosapps / mc / src / wtools.c
1 /* {{{ */
2
3 /* {{{ Copyright Notice */
4
5 /* Widget based utility functions.
6 Copyright (C) 1994, 1995 the Free Software Foundation
7
8 Authors: 1994, 1995, 1996 Miguel de Icaza
9 1994, 1995 Radek Doulik
10 1995 Jakub Jelinek
11 1995 Andrej Borsenkow
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 */
28
29 /* }}} */
30
31 /* [] = "$Id$" */
32
33 #include <config.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <malloc.h>
37 #include "tty.h"
38 #include <stdarg.h>
39 #include "mad.h"
40 #include "global.h"
41 #include "util.h"
42 #include "win.h"
43 #include "color.h"
44 #include "mouse.h"
45 #include "dlg.h"
46 #include "widget.h"
47 #include "menu.h"
48 #include "wtools.h"
49 #include "key.h" /* For mi_getch() */
50 #include "dialog.h" /* For do_refresh() and my_wputs() */
51 #include "complete.h" /* INPUT_COMPLETE_CD */
52 #include "x.h"
53
54 /* }}} */
55
56 /* {{{ Common dialog callback */
57 #ifdef HAVE_X
58 void dialog_repaint (struct Dlg_head *h, int back, int title_fore)
59 {
60 }
61 #else
62 void
63 dialog_repaint (struct Dlg_head *h, int back, int title_fore)
64 {
65 attrset (back);
66 dlg_erase (h);
67 draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
68 attrset (title_fore);
69 if (h->title){
70 dlg_move (h, 1, (h->cols-strlen (h->title))/2);
71 addstr (h->title);
72 }
73 }
74 #endif
75 void
76 common_dialog_repaint (struct Dlg_head *h)
77 {
78 dialog_repaint (h, COLOR_NORMAL, COLOR_HOT_NORMAL);
79 }
80
81 int
82 common_dialog_callback (struct Dlg_head *h, int id, int msg)
83 {
84 if (msg == DLG_DRAW)
85 common_dialog_repaint (h);
86 return 0;
87 }
88
89 /* }}} */
90 /* {{{ Listbox utility functions */
91
92 void
93 listbox_refresh (Dlg_head *h)
94 {
95 dialog_repaint (h, COLOR_NORMAL, COLOR_HOT_NORMAL);
96 }
97
98 static int listbox_callback (Dlg_head *h, int id, int msg)
99 {
100 switch (msg) {
101 case DLG_DRAW:
102 #ifndef HAVE_X
103 listbox_refresh(h);
104 #endif
105 return 1;
106 }
107 return 0;
108 }
109
110 Listbox *create_listbox_window (int cols, int lines, char *title, char *help)
111 {
112 int xpos, ypos, len;
113 Listbox *listbox = xmalloc (sizeof (Listbox), "create_listbox_window");
114 char* cancel_string = _("&Cancel");
115
116 /* Adjust sizes */
117 lines = (lines > LINES-6) ? LINES - 6 : lines;
118
119 if (title && (cols < (len = strlen(title) + 2)))
120 cols = len;
121
122 /* no &, but 4 spaces around button for brackets and such */
123 if (cols < (len = strlen(cancel_string) + 3))
124 cols = len;
125
126 cols = cols > COLS-6 ? COLS-6 : cols;
127
128 /* I'm not sure if this -2 is safe, should test it */
129 xpos = (COLS-cols)/2;
130 ypos = (LINES-lines)/2 - 2;
131
132 /* Create components */
133 listbox->dlg = create_dlg (ypos, xpos, lines+6, cols+4, dialog_colors,
134 listbox_callback, help, "listbox", DLG_CENTER|DLG_GRID);
135 x_set_dialog_title (listbox->dlg, title);
136
137 listbox->list = listbox_new (2, 2, cols, lines, listbox_finish, 0, "li");
138
139 add_widget (listbox->dlg,
140 button_new (lines+3, (cols/2 + 2) - len/2,
141 B_CANCEL, NORMAL_BUTTON, cancel_string, 0, 0, "c"));
142 add_widget (listbox->dlg, listbox->list);
143 #ifndef HAVE_X
144 listbox_refresh(listbox->dlg);
145 #endif /* !HAVE_X */
146 return listbox;
147 }
148
149 /* Returns the number of the item selected */
150 int run_listbox (Listbox *l)
151 {
152 int val;
153
154 run_dlg (l->dlg);
155 if (l->dlg->ret_value == B_CANCEL)
156 val = -1;
157 else
158 val = l->list->pos;
159 destroy_dlg (l->dlg);
160 free (l);
161 return val;
162 }
163
164 /* }}} */
165
166
167 /* {{{ Query Dialog functions */
168 #ifndef HAVE_GNOME
169 struct text_struct {
170 char *text;
171 char *header;
172 };
173
174 static int query_callback (struct Dlg_head *h, int Id, int Msg)
175 {
176 struct text_struct *info;
177
178 info = (struct text_struct *) h->data;
179
180 switch (Msg){
181 #ifndef HAVE_X
182 case DLG_DRAW:
183 /* designate window */
184 attrset (NORMALC);
185 dlg_erase (h);
186 draw_box (h, 1, 1, h->lines-2, h->cols-2);
187 attrset (HOT_NORMALC);
188 dlg_move (h, 1, (h->cols-strlen (info->header))/2);
189 addstr (info->header);
190 break;
191 #endif
192 }
193 return 0;
194 }
195
196
197 Dlg_head *last_query_dlg;
198
199 static int sel_pos = 0;
200
201 /* Used to ask questions to the user */
202 int query_dialog (char *header, char *text, int flags, int count, ...)
203 {
204 va_list ap;
205 Dlg_head *query_dlg;
206 int win_len = 0;
207 int i;
208 int result = -1;
209 int xpos, ypos;
210 int cols, lines;
211 char *cur_name;
212 static int query_colors [4];
213 static struct text_struct pass;
214 #ifdef HAVE_X
215 static char *buttonnames [10];
216 #endif
217
218 /* set dialog colors */
219 query_colors [0] = (flags & D_ERROR) ? ERROR_COLOR : Q_UNSELECTED_COLOR;
220 query_colors [1] = (flags & D_ERROR) ? REVERSE_COLOR : Q_SELECTED_COLOR;
221 query_colors [2] = (flags & D_ERROR) ? ERROR_COLOR : COLOR_HOT_NORMAL;
222 query_colors [3] = (flags & D_ERROR) ? COLOR_HOT_NORMAL : COLOR_HOT_FOCUS;
223
224 if (header == MSG_ERROR)
225 header = _(" Error ");
226
227 if (count > 0){
228 va_start (ap, count);
229 for (i = 0; i < count; i++)
230 {
231 char* cp = va_arg (ap, char *);
232 win_len += strlen (cp) + 6;
233 if (strchr (cp, '&') != NULL)
234 win_len--;
235 }
236 va_end (ap);
237 }
238
239 /* count coordinates */
240 cols = 6 + max (win_len, max (strlen (header), msglen (text, &lines)));
241 lines += 4 + (count > 0 ? 2 : 0);
242 xpos = COLS/2 - cols/2;
243 ypos = LINES/3 - (lines-3)/2;
244 pass.header = header;
245 pass.text = text;
246
247 /* prepare dialog */
248 query_dlg = create_dlg (ypos, xpos, lines, cols, query_colors,
249 query_callback, "[QueryBox]", "query", DLG_NONE);
250 x_set_dialog_title (query_dlg, header);
251
252 /* The data we need to pass to the callback */
253 query_dlg->cols = cols;
254 query_dlg->lines = lines;
255 query_dlg->data = &pass;
256
257 query_dlg->direction = DIR_BACKWARD;
258
259 if (count > 0){
260
261 cols = (cols-win_len-2)/2+2;
262 va_start (ap, count);
263 for (i = 0; i < count; i++){
264 cur_name = va_arg (ap, char *);
265 xpos = strlen (cur_name)+6;
266 if (strchr(cur_name, '&') != NULL)
267 xpos--;
268 #ifndef HAVE_XVIEW
269 add_widget (query_dlg, button_new
270 (lines-3, cols, B_USER+i, NORMAL_BUTTON, cur_name,
271 0, 0, NULL));
272 #else
273 buttonnames [i] = cur_name;
274 #endif
275 cols += xpos;
276 if (i == sel_pos)
277 query_dlg->initfocus = query_dlg->current;
278 }
279 va_end (ap);
280
281 #ifdef HAVE_XVIEW
282 for (i = count - 1; i >= 0; i--)
283 add_widgetl (query_dlg, button_new
284 (0, 0, B_USER+i, NORMAL_BUTTON, buttonnames [i], 0, 0, NULL),
285 i ? XV_WLAY_RIGHTOF : XV_WLAY_CENTERROW);
286 #endif
287 add_widget (query_dlg, label_new (2, 3, text, NULL));
288
289 /* run dialog and make result */
290 run_dlg (query_dlg);
291 switch (query_dlg->ret_value){
292 case B_CANCEL:
293 break;
294 default:
295 result = query_dlg->ret_value-B_USER;
296 }
297
298 /* free used memory */
299 destroy_dlg (query_dlg);
300 } else {
301 #ifdef HAVE_X
302 add_widgetl (query_dlg, button_new(0, 0, B_EXIT, NORMAL_BUTTON, _("&Ok"), 0, 0, NULL),
303 XV_WLAY_CENTERROW);
304
305 add_widget (query_dlg, label_new (2, 3, text, NULL));
306 #ifdef HAVE_TK
307 if (flags & D_INSERT){
308 } else
309 #endif
310 {
311 run_dlg (query_dlg);
312 destroy_dlg (query_dlg);
313 }
314 #else
315 add_widget (query_dlg, label_new (2, 3, text, NULL));
316 add_widget (query_dlg, button_new(0, 0, 0, HIDDEN_BUTTON, "-", 0, 0, NULL));
317 #endif /* HAVE_X */
318 last_query_dlg = query_dlg;
319 }
320 sel_pos = 0;
321 return result;
322 }
323
324 void query_set_sel (int new_sel)
325 {
326 sel_pos = new_sel;
327 }
328
329 /* }}} */
330
331 /* {{{ The message function */
332
333 /* To show nice messages to the users */
334 Dlg_head *message (int error, char *header, char *text, ...)
335 {
336 va_list args;
337 char buffer [4096];
338 Dlg_head *d;
339
340 /* Setup the display information */
341 strcpy (buffer, "\n");
342 va_start (args, text);
343 vsprintf (&buffer [1], text, args);
344 strcat (buffer, "\n");
345 va_end (args);
346
347 query_dialog (header, buffer, error, 0);
348 #ifndef HAVE_XVIEW
349 d = last_query_dlg;
350 #ifdef HAVE_TK
351 if (error & D_INSERT){
352 init_dlg (d);
353 tk_dispatch_all ();
354 return d;
355 }
356 #else
357 init_dlg (d);
358 if (!(error & D_INSERT)){
359 mi_getch ();
360 dlg_run_done (d);
361 destroy_dlg (d);
362 } else
363 return d;
364 #endif
365 #endif
366 return 0;
367 }
368 #endif
369 /* }}} */
370
371 /* {{{ The chooser routines */
372
373 static int remove_callback (int i, void *data)
374 {
375 Chooser *c = (Chooser *) data;
376
377 listbox_remove_current (c->listbox, 0);
378
379 dlg_select_widget (c->dialog, c->listbox);
380 dlg_select_nth_widget (c->dialog, 0);
381
382 /* Return: do not abort dialog */
383 return 0;
384 }
385
386 Chooser *new_chooser (int lines, int cols, char *help, int flags)
387 {
388 Chooser *c;
389 int button_lines;
390
391 c = (Chooser *) xmalloc (sizeof (Chooser), "new_chooser");
392 c->dialog = create_dlg (0, 0, lines, cols, dialog_colors, common_dialog_callback,
393 help, "chooser", DLG_CENTER | DLG_GRID);
394
395 c->dialog->lines = lines;
396 c->dialog->cols = cols;
397
398 button_lines = flags & CHOOSE_EDITABLE ? 3 : 0;
399
400 c->listbox = listbox_new (1, 1, cols-2, lines-button_lines,
401 listbox_finish, 0, "listbox");
402
403 if (button_lines){
404 add_widget (c->dialog, button_new (lines-button_lines+1,
405 20, B_ENTER, DEFPUSH_BUTTON, _("&Remove"),
406 remove_callback, c, "button-remove"));
407 add_widget (c->dialog, button_new (lines-button_lines+1,
408 4, B_CANCEL, NORMAL_BUTTON, _("&Cancel"),
409 0, 0, "button-cancel"));
410 }
411 add_widget (c->dialog, c->listbox);
412 return c;
413 }
414
415 int run_chooser (Chooser *c)
416 {
417 run_dlg (c->dialog);
418 return c->dialog->ret_value;
419 }
420
421 void destroy_chooser (Chooser *c)
422 {
423 destroy_dlg (c->dialog);
424 }
425
426 /* }}} */
427
428 /* {{{ Quick dialog routines */
429
430 static int quick_callback (struct Dlg_head *h, int id, int Msg)
431 {
432 switch (Msg){
433 #ifndef HAVE_X
434 case DLG_DRAW:
435 attrset (COLOR_NORMAL);
436 dlg_erase (h);
437 draw_box (h, 1, 1, h->lines-2, h->cols-2);
438
439 attrset (COLOR_HOT_NORMAL);
440 dlg_move (h, 1,((h->cols-strlen (h->data))/2));
441 addstr (h->data);
442 break;
443 #endif
444 case DLG_KEY:
445 if (id == '\n'){
446 h->ret_value = B_ENTER;
447 dlg_stop (h);
448 break;
449 }
450 }
451 return 0;
452 }
453
454 #define I18N(x) (do_int && *x ? (x = _(x)): x)
455
456 int quick_dialog_skip (QuickDialog *qd, int nskip)
457 {
458 Dlg_head *dd;
459 void *widget;
460 WRadio *r;
461 int xpos;
462 int ypos;
463 int return_val;
464 WInput *input;
465 QuickWidget *qw;
466 int do_int;
467
468 if (!qd->i18n){
469 qd->i18n = 1;
470 do_int = 1;
471 if (*qd->title)
472 qd->title = _(qd->title);
473 } else
474 do_int = 0;
475
476 if (qd->xpos == -1)
477 dd = create_dlg (0, 0, qd->ylen, qd->xlen, dialog_colors, quick_callback,
478 qd->help, qd->class, DLG_CENTER | DLG_TRYUP | DLG_GRID);
479 else
480 dd = create_dlg (qd->ypos, qd->xpos, qd->ylen, qd->xlen, dialog_colors,
481 quick_callback,
482 qd->help, qd->class, DLG_GRID);
483
484 x_set_dialog_title (dd, qd->title);
485
486 /* We pass this to the callback */
487 dd->cols = qd->xlen;
488 dd->lines = qd->ylen;
489 dd->data = qd->title;
490
491 for (qw = qd->widgets; qw->widget_type; qw++){
492 #ifdef HAVE_X
493 xpos = ypos = 0;
494 #else
495 xpos = (qd->xlen * qw->relative_x)/qw->x_divisions;
496 ypos = (qd->ylen * qw->relative_y)/qw->y_divisions;
497 #endif
498
499 switch (qw->widget_type){
500 case quick_checkbox:
501 widget = check_new (ypos, xpos, *qw->result, I18N (qw->text), qw->tkname);
502 break;
503
504 case quick_radio:
505 r = radio_new (ypos, xpos, qw->hotkey_pos, qw->str_result, 1, qw->tkname);
506 r->pos = r->sel = qw->value;
507 widget = r;
508 break;
509
510 case quick_button:
511 widget = button_new (ypos, xpos, qw->value, (qw->value==B_ENTER) ? DEFPUSH_BUTTON : NORMAL_BUTTON,
512 I18N (qw->text), 0, 0, qw->tkname);
513 break;
514
515 /* We use the hotkey pos as the field length */
516 case quick_input:
517 input = input_new (ypos, xpos, INPUT_COLOR,
518 qw->hotkey_pos, qw->text, qw->tkname);
519 input->is_password = qw->value == 1;
520 input->point = 0;
521 if (qw->value & 2)
522 input->completion_flags |= INPUT_COMPLETE_CD;
523 widget = input;
524 break;
525
526 case quick_label:
527 widget = label_new (ypos, xpos, I18N(qw->text), qw->tkname);
528 break;
529
530 default:
531 widget = 0;
532 fprintf (stderr, "QuickWidget: unknown widget type\n");
533 break;
534 }
535 qw->the_widget = widget;
536 add_widgetl (dd, widget, qw->layout);
537 }
538
539 while (nskip--)
540 dd->current = dd->current->next;
541
542 run_dlg (dd);
543
544 /* Get the data if we found something interesting */
545 if (dd->ret_value != B_CANCEL){
546 for (qw = qd->widgets; qw->widget_type; qw++){
547 switch (qw->widget_type){
548 case quick_checkbox:
549 *qw->result = ((WCheck *) qw->the_widget)->state & C_BOOL;
550 break;
551
552 case quick_radio:
553 *qw->result = ((WRadio *) qw->the_widget)->sel;
554 break;
555
556 case quick_input:
557 *qw->str_result = strdup (((WInput *) qw->the_widget)->buffer);
558 break;
559 }
560 }
561 }
562 return_val = dd->ret_value;
563 destroy_dlg (dd);
564
565 return return_val;
566 }
567
568 int quick_dialog (QuickDialog *qd)
569 {
570 return quick_dialog_skip (qd, 0);
571 }
572
573 /* }}} */
574
575 /* {{{ Input routines */
576 #define INPUT_INDEX 2
577 char *real_input_dialog_help (char *header, char *text, char *help, char *def_text)
578 {
579 QuickDialog Quick_input;
580 QuickWidget quick_widgets [] = {
581 { quick_button, 6, 10, 1, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
582 XV_WLAY_RIGHTOF, "button-cancel" },
583 { quick_button, 3, 10, 1, 0, N_("&Ok"), 0, B_ENTER, 0, 0,
584 XV_WLAY_CENTERROW, "button-ok" },
585 { quick_input, 4, 80, 0, 0, "", 58, 0, 0, 0, XV_WLAY_NEXTROW, 0 },
586 { quick_label, 3, 80, 2, 0, "", 0, 0, 0, 0, XV_WLAY_NEXTROW, "label" },
587 { 0 } };
588
589 int len;
590 int i;
591 int lines;
592 char *my_str;
593 char tk_name[64] = "inp|";
594
595 /* we need a unique name for tkname because widget.c:history_tool()
596 needs a unique name for each dialog - using the header is ideal */
597
598 #ifdef HAVE_GNOME
599 strncpy (tk_name + 4, header, 59);
600 #else
601 strncpy (tk_name + 3, header, 60);
602 #endif
603 tk_name[63] = '\0';
604 quick_widgets[2].tkname = tk_name;
605
606 len = max (strlen (header), msglen (text, &lines)) + 4;
607 len = max (len, 64);
608
609 if (strncmp (text, _("Password:"), strlen (_("Password"))) == 0){
610 quick_widgets [INPUT_INDEX].value = 1;
611 tk_name[3]=0;
612 } else {
613 quick_widgets [INPUT_INDEX].value = 0;
614 }
615
616 #ifdef ENABLE_NLS
617 /*
618 * An attempt to place buttons symmetrically, based on actual i18n
619 * length of the string. It looks nicer with i18n (IMO) - alex
620 */
621 quick_widgets [0].relative_x = len/2 + 4;
622 quick_widgets [1].relative_x =
623 len/2 - (strlen (_(quick_widgets [1].text)) + 9);
624 quick_widgets [0].x_divisions = quick_widgets [1].x_divisions = len;
625 #endif /* ENABLE_NLS */
626
627 Quick_input.xlen = len;
628 Quick_input.xpos = -1;
629 Quick_input.title = header;
630 Quick_input.help = help;
631 Quick_input.class = "quick_input";
632 Quick_input.i18n = 0;
633 quick_widgets [INPUT_INDEX+1].text = text;
634 quick_widgets [INPUT_INDEX].text = def_text;
635
636 for (i = 0; i < 4; i++)
637 quick_widgets [i].y_divisions = lines+6;
638 Quick_input.ylen = lines + 6;
639
640 for (i = 0; i < 3; i++)
641 quick_widgets [i].relative_y += 2 + lines;
642
643 quick_widgets [INPUT_INDEX].str_result = &my_str;
644
645 Quick_input.widgets = quick_widgets;
646 if (quick_dialog (&Quick_input) != B_CANCEL){
647 return *(quick_widgets [INPUT_INDEX].str_result);
648 } else
649 return 0;
650 }
651
652 char *input_dialog (char *header, char *text, char *def_text)
653 {
654 return input_dialog_help (header, text, "[Input Line Keys]", def_text);
655 }
656
657 int input_dialog_help_2 (char *header, char *text1, char *text2, char *help, char **r1, char **r2)
658 {
659 QuickDialog Quick_input;
660 QuickWidget quick_widgets [] = {
661 { quick_button, 6, 10, 4, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
662 XV_WLAY_DONTCARE, "button-cancel" },
663 { quick_button, 3, 10, 4, 0, N_("Ok")
664 , 0, B_ENTER, 0, 0,
665 XV_WLAY_DONTCARE, "button-ok" },
666 { quick_input, 4, 80, 4, 0, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-pth" },
667 { quick_label, 3, 80, 3, 0, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-pth" },
668 { quick_input, 4, 80, 3, 0, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-lbl" },
669 { quick_label, 3, 80, 2, 0, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-lbl" },
670 { 0 } };
671
672 int len;
673 int i;
674 int lines1, lines2;
675 char *my_str1, *my_str2;
676
677 len = max (strlen (header), msglen (text1, &lines1));
678 len = max (len, msglen (text2, &lines2)) + 4;
679 len = max (len, 64);
680
681 Quick_input.xlen = len;
682 Quick_input.xpos = -1;
683 Quick_input.title = header;
684 Quick_input.help = help;
685 Quick_input.class = "quick_input_2";
686 Quick_input.i18n = 0;
687 quick_widgets [5].text = text1;
688 quick_widgets [3].text = text2;
689
690 for (i = 0; i < 6; i++)
691 quick_widgets [i].y_divisions = lines1+lines2+7;
692 Quick_input.ylen = lines1 + lines2 + 7;
693
694 quick_widgets [0].relative_y += (lines1 + lines2);
695 quick_widgets [1].relative_y += (lines1 + lines2);
696 quick_widgets [2].relative_y += (lines1);
697 quick_widgets [3].relative_y += (lines1);
698
699 quick_widgets [4].str_result = &my_str1;
700 quick_widgets [2].str_result = &my_str2;
701
702 Quick_input.widgets = quick_widgets;
703 if (quick_dialog (&Quick_input) != B_CANCEL){
704 *r1 = *(quick_widgets [4].str_result);
705 *r2 = *(quick_widgets [2].str_result);
706 return 1;
707 } else
708 return 0;
709 }
710
711 int input_dialog_2 (char *header, char *text1, char *text2, char **r1, char **r2)
712 {
713 return input_dialog_help_2 (header, text1, text2, "[Input Line Keys]", r1, r2);
714 }
715
716 char *input_expand_dialog (char *header, char *text, char *def_text)
717 {
718 char *result;
719 char *expanded;
720
721 result = input_dialog (header, text, def_text);
722 if (result){
723 expanded = tilde_expand (result);
724 if (expanded){
725 free (result);
726 return expanded;
727 } else
728 return result;
729 }
730 return result;
731 }
732
733 /* }}} */
734
735 /* }}} */
736 /*
737 Cause emacs to enter folding mode for this file:
738 Local variables:
739 end:
740 */