e3c42fb5b89eeb36f912dd42b239f9f095bc1a3e
[midnight-commander.git] / lib / widget / quick.c
blobe3c42fb5b89eeb36f912dd42b239f9f095bc1a3e
1 /*
2 Widget based utility functions.
4 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
6 The Free Software Foundation, Inc.
8 Authors:
9 Miguel de Icaza, 1994, 1995, 1996
10 Radek Doulik, 1994, 1995
11 Jakub Jelinek, 1995
12 Andrej Borsenkow, 1995
13 Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012
15 This file is part of the Midnight Commander.
17 The Midnight Commander is free software: you can redistribute it
18 and/or modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation, either version 3 of the License,
20 or (at your option) any later version.
22 The Midnight Commander is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 /** \file quick.c
32 * \brief Source: quick dialog engine
35 #include <config.h>
37 #include <stdlib.h>
38 #include <stdio.h> /* fprintf() */
40 #include "lib/global.h"
41 #include "lib/strutil.h" /* str_term_width1() */
42 #include "lib/util.h" /* tilde_expand() */
43 #include "lib/widget.h"
45 /*** global variables ****************************************************************************/
47 /*** file scope macro definitions ****************************************************************/
49 #ifdef ENABLE_NLS
50 #define I18N(x) (x = x != NULL && *x != '\0' ? _(x) : x)
51 #else
52 #define I18N(x) (x = x)
53 #endif
55 /*** file scope type declarations ****************************************************************/
57 typedef struct
59 Widget *widget;
60 quick_widget_t *quick_widget;
61 } quick_widget_item_t;
63 /*** file scope variables ************************************************************************/
65 /* --------------------------------------------------------------------------------------------- */
66 /*** file scope functions ************************************************************************/
67 /* --------------------------------------------------------------------------------------------- */
69 static WInput *
70 quick_create_input (int y, int x, const quick_widget_t * qw)
72 WInput *in;
74 in = input_new (y, x, input_get_default_colors (), 8, qw->u.input.text, qw->u.input.histname,
75 INPUT_COMPLETE_DEFAULT);
76 in->is_password = (qw->u.input.flags == 1);
77 if ((qw->u.input.flags & 2) != 0)
78 in->completion_flags |= INPUT_COMPLETE_CD;
79 if ((qw->u.input.flags & 4) != 0)
80 in->strip_password = TRUE;
82 return in;
85 /* --------------------------------------------------------------------------------------------- */
87 static void
88 quick_create_labeled_input (GArray * widgets, int *y, int x, quick_widget_t * quick_widget,
89 int *width)
91 quick_widget_item_t in, label;
93 label.quick_widget = g_new0 (quick_widget_t, 1);
94 label.quick_widget->widget_type = quick_label;
95 label.quick_widget->options = quick_widget->options;
96 /* FIXME: this should be turned in depend of label_location */
97 label.quick_widget->pos_flags = quick_widget->pos_flags;
99 switch (quick_widget->u.input.label_location)
101 case input_label_above:
102 label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text)));
103 *y += label.widget->lines - 1;
104 g_array_append_val (widgets, label);
106 in.widget = WIDGET (quick_create_input (++(*y), x, quick_widget));
107 in.quick_widget = quick_widget;
108 g_array_append_val (widgets, in);
110 *width = max (label.widget->cols, in.widget->cols);
111 break;
113 case input_label_left:
114 label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text)));
115 g_array_append_val (widgets, label);
117 in.widget = WIDGET (quick_create_input (*y, x + label.widget->cols + 1, quick_widget));
118 in.quick_widget = quick_widget;
119 g_array_append_val (widgets, in);
121 *width = label.widget->cols + in.widget->cols + 1;
122 break;
124 case input_label_right:
125 in.widget = WIDGET (quick_create_input (*y, x, quick_widget));
126 in.quick_widget = quick_widget;
127 g_array_append_val (widgets, in);
129 label.widget =
130 WIDGET (label_new
131 (*y, x + in.widget->cols + 1, I18N (quick_widget->u.input.label_text)));
132 g_array_append_val (widgets, label);
134 *width = label.widget->cols + in.widget->cols + 1;
135 break;
137 case input_label_below:
138 in.widget = WIDGET (quick_create_input (*y, x, quick_widget));
139 in.quick_widget = quick_widget;
140 g_array_append_val (widgets, in);
142 label.widget = WIDGET (label_new (++(*y), x, I18N (quick_widget->u.input.label_text)));
143 *y += label.widget->lines - 1;
144 g_array_append_val (widgets, label);
146 *width = max (label.widget->cols, in.widget->cols);
147 break;
149 default:
150 return;
153 INPUT (in.widget)->label = LABEL (label.widget);
154 /* cross references */
155 label.quick_widget->u.label.input = in.quick_widget;
156 in.quick_widget->u.input.label = label.quick_widget;
159 /* --------------------------------------------------------------------------------------------- */
160 /*** public functions ****************************************************************************/
161 /* --------------------------------------------------------------------------------------------- */
164 quick_dialog_skip (quick_dialog_t * quick_dlg, int nskip)
166 int len;
167 int blen = 0;
168 int x, y; /* current positions */
169 int y1 = 0; /* bottom of 1st column in case of two columns */
170 int y2 = -1; /* start of two columns */
171 int width1 = 0; /* width of single column */
172 int width2 = 0; /* width of each of two columns */
173 gboolean have_groupbox = FALSE;
174 gboolean two_columns = FALSE;
175 gboolean put_buttons = FALSE;
177 /* x position of 1st column is 3 */
178 const int x1 = 3;
179 /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */
180 int x2 = 4;
182 GArray *widgets;
183 size_t i;
184 quick_widget_t *quick_widget;
185 WGroupbox *g = NULL;
186 WDialog *dd;
187 int return_val;
189 len = str_term_width1 (I18N (quick_dlg->title)) + 6;
190 quick_dlg->cols = max (quick_dlg->cols, len);
192 y = 1;
193 x = x1;
195 /* create widgets */
196 widgets = g_array_sized_new (FALSE, FALSE, sizeof (quick_widget_item_t), 8);
198 for (quick_widget = quick_dlg->widgets; quick_widget->widget_type != quick_end; quick_widget++)
200 quick_widget_item_t item = { NULL, quick_widget };
201 int width = 0;
203 switch (quick_widget->widget_type)
205 case quick_checkbox:
206 item.widget =
207 WIDGET (check_new
208 (++y, x, *quick_widget->u.checkbox.state,
209 I18N (quick_widget->u.checkbox.text)));
210 g_array_append_val (widgets, item);
211 width = item.widget->cols;
212 if (g != NULL)
213 width += 2;
214 if (two_columns)
215 width2 = max (width2, width);
216 else
217 width1 = max (width1, width);
218 break;
220 case quick_button:
221 /* single button */
222 item.widget = WIDGET (button_new (++y, x, quick_widget->u.button.action,
223 quick_widget->u.button.action == B_ENTER ?
224 DEFPUSH_BUTTON : NORMAL_BUTTON,
225 I18N (quick_widget->u.button.text),
226 quick_widget->u.button.callback));
227 g_array_append_val (widgets, item);
228 width = item.widget->cols;
229 if (g != NULL)
230 width += 2;
231 if (two_columns)
232 width2 = max (width2, width);
233 else
234 width1 = max (width1, width);
235 break;
237 case quick_input:
238 *quick_widget->u.input.result = NULL;
239 y++;
240 if (quick_widget->u.input.label_location != input_label_none)
241 quick_create_labeled_input (widgets, &y, x, quick_widget, &width);
242 else
244 item.widget = WIDGET (quick_create_input (y, x, quick_widget));
245 g_array_append_val (widgets, item);
246 width = item.widget->cols;
248 if (g != NULL)
249 width += 2;
250 if (two_columns)
251 width2 = max (width2, width);
252 else
253 width1 = max (width1, width);
254 break;
256 case quick_label:
257 item.widget = WIDGET (label_new (++y, x, I18N (quick_widget->u.label.text)));
258 g_array_append_val (widgets, item);
259 y += item.widget->lines - 1;
260 width = item.widget->cols;
261 if (g != NULL)
262 width += 2;
263 if (two_columns)
264 width2 = max (width2, width);
265 else
266 width1 = max (width1, width);
267 break;
269 case quick_radio:
271 WRadio *r;
272 char **items = NULL;
274 /* create the copy of radio_items to avoid mwmory leak */
275 items = g_new (char *, quick_widget->u.radio.count + 1);
276 for (i = 0; i < (size_t) quick_widget->u.radio.count; i++)
277 items[i] = g_strdup (_(quick_widget->u.radio.items[i]));
278 items[i] = NULL;
280 r = radio_new (++y, x, quick_widget->u.radio.count, (const char **) items);
281 r->pos = r->sel = *quick_widget->u.radio.value;
282 g_strfreev (items);
283 item.widget = WIDGET (r);
284 g_array_append_val (widgets, item);
285 y += item.widget->lines - 1;
286 width = item.widget->cols;
287 if (g != NULL)
288 width += 2;
289 if (two_columns)
290 width2 = max (width2, width);
291 else
292 width1 = max (width1, width);
294 break;
296 case quick_start_groupbox:
297 I18N (quick_widget->u.groupbox.title);
298 len = str_term_width1 (quick_widget->u.groupbox.title);
299 g = groupbox_new (++y, x, 1, len + 4, quick_widget->u.groupbox.title);
300 item.widget = WIDGET (g);
301 g_array_append_val (widgets, item);
302 have_groupbox = TRUE;
303 break;
305 case quick_stop_groupbox:
306 if (g != NULL)
308 Widget *w = WIDGET (g);
310 y++;
311 w->lines = y + 1 - w->y;
312 g = NULL;
314 g_array_append_val (widgets, item);
316 break;
318 case quick_separator:
319 y++;
320 if (quick_widget->u.separator.line)
322 item.widget = WIDGET (hline_new (y, x, 1));
323 g_array_append_val (widgets, item);
325 break;
327 case quick_start_columns:
328 y2 = y;
329 g_array_append_val (widgets, item);
330 two_columns = TRUE;
331 break;
333 case quick_next_column:
334 x = x2;
335 y1 = y;
336 y = y2;
337 break;
339 case quick_stop_columns:
340 x = x1;
341 y = max (y1, y);
342 g_array_append_val (widgets, item);
343 two_columns = FALSE;
344 break;
346 case quick_buttons:
347 /* start put several buttons in bottom line */
348 if (quick_widget->u.separator.space)
350 y++;
352 if (quick_widget->u.separator.line)
353 item.widget = WIDGET (hline_new (y, 1, -1));
356 g_array_append_val (widgets, item);
358 /* several buttons in bottom line */
359 y++;
360 quick_widget++;
361 for (; quick_widget->widget_type == quick_button; quick_widget++)
363 item.widget = WIDGET (button_new (y, x++, quick_widget->u.button.action,
364 quick_widget->u.button.action == B_ENTER ?
365 DEFPUSH_BUTTON : NORMAL_BUTTON,
366 I18N (quick_widget->u.button.text),
367 quick_widget->u.button.callback));
368 item.quick_widget = quick_widget;
369 g_array_append_val (widgets, item);
370 blen += item.widget->cols + 1;
373 /* stop dialog build here */
374 blen--;
375 quick_widget->widget_type = quick_end;
376 quick_widget--;
377 break;
379 default:
380 break;
384 /* adjust dialog width */
385 quick_dlg->cols = max (quick_dlg->cols, blen + 6);
386 if (have_groupbox)
388 if (width1 != 0)
389 width1 += 2;
390 if (width2 != 0)
391 width2 += 2;
393 if (width2 == 0)
394 len = width1 + 6;
395 else
397 len = width2 * 2 + 7;
398 if (width1 != 0)
399 len = max (len, width1 + 6);
402 quick_dlg->cols = max (quick_dlg->cols, len);
403 width1 = quick_dlg->cols - 6;
404 width2 = (quick_dlg->cols - 7) / 2;
406 if (quick_dlg->x == -1 || quick_dlg->y == -1)
407 dd = create_dlg (TRUE, 0, 0, y + 3, quick_dlg->cols,
408 dialog_colors, quick_dlg->callback, quick_dlg->mouse, quick_dlg->help,
409 quick_dlg->title, DLG_CENTER | DLG_TRYUP);
410 else
411 dd = create_dlg (TRUE, quick_dlg->y, quick_dlg->x, y + 3, quick_dlg->cols,
412 dialog_colors, quick_dlg->callback, quick_dlg->mouse, quick_dlg->help,
413 quick_dlg->title, DLG_NONE);
415 /* add widgets into the dialog */
416 x2 = x1 + width2 + 1;
417 g = NULL;
418 two_columns = FALSE;
419 x = (WIDGET (dd)->cols - blen) / 2;
421 for (i = 0; i < widgets->len; i++)
423 quick_widget_item_t *item;
424 int column_width;
426 item = &g_array_index (widgets, quick_widget_item_t, i);
427 column_width = two_columns ? width2 : width1;
429 /* adjust widget width and x position */
430 switch (item->quick_widget->widget_type)
432 case quick_label:
434 quick_widget_t *input = item->quick_widget->u.label.input;
436 if (input != NULL && input->u.input.label_location == input_label_right)
438 /* location of this label will be adjusted later */
439 break;
442 /* fall through */
443 case quick_checkbox:
444 case quick_radio:
445 if (item->widget->x != x1)
446 item->widget->x = x2;
447 if (g != NULL)
448 item->widget->x += 2;
449 break;
451 case quick_button:
452 if (!put_buttons)
454 if (item->widget->x != x1)
455 item->widget->x = x2;
456 if (g != NULL)
457 item->widget->x += 2;
459 else
461 item->widget->x = x;
462 x += item->widget->cols + 1;
464 break;
466 case quick_input:
468 Widget *label = WIDGET (INPUT (item->widget)->label);
469 int width = column_width;
471 if (g != NULL)
472 width -= 4;
474 switch (item->quick_widget->u.input.label_location)
476 case input_label_left:
477 /* label was adjusted before; adjust input line */
478 item->widget->x = label->x + label->cols + 1 - WIDGET (label->owner)->x;
479 item->widget->cols = width - label->cols - 1;
480 break;
482 case input_label_right:
483 label->x =
484 item->widget->x + item->widget->cols + 1 - WIDGET (item->widget->owner)->x;
485 item->widget->cols = width - label->cols - 1;
486 break;
488 default:
489 if (item->widget->x != x1)
490 item->widget->x = x2;
491 if (g != NULL)
492 item->widget->x += 2;
493 item->widget->cols = width;
494 break;
497 /* forced update internal variables of inpuit line */
498 input_set_origin (INPUT (item->widget), item->widget->x, item->widget->cols);
500 break;
502 case quick_start_groupbox:
503 g = GROUPBOX (item->widget);
504 if (item->widget->x != x1)
505 item->widget->x = x2;
506 item->widget->cols = column_width;
507 break;
509 case quick_stop_groupbox:
510 g = NULL;
511 break;
513 case quick_separator:
514 if (item->widget != NULL)
516 if (g != NULL)
518 Widget *wg = WIDGET (g);
520 HLINE (item->widget)->auto_adjust_cols = FALSE;
521 item->widget->x = wg->x + 1 - WIDGET (wg->owner)->x;
522 item->widget->cols = wg->cols;
524 else if (two_columns)
526 HLINE (item->widget)->auto_adjust_cols = FALSE;
527 if (item->widget->x != x1)
528 item->widget->x = x2;
529 item->widget->x--;
530 item->widget->cols = column_width + 2;
532 else
533 HLINE (item->widget)->auto_adjust_cols = TRUE;
535 break;
537 case quick_start_columns:
538 two_columns = TRUE;
539 break;
541 case quick_stop_columns:
542 two_columns = FALSE;
543 break;
545 case quick_buttons:
546 /* several buttons in bottom line */
547 put_buttons = TRUE;
548 break;
550 default:
551 break;
554 if (item->widget != NULL)
556 unsigned long id;
558 /* add widget into dialog */
559 item->widget->options |= item->quick_widget->options; /* FIXME: cannot reset flags, setup only */
560 id = add_widget_autopos (dd, item->widget, item->quick_widget->pos_flags, NULL);
561 if (item->quick_widget->id != NULL)
562 *item->quick_widget->id = id;
566 while (nskip-- != 0)
568 dd->current = g_list_next (dd->current);
569 if (dd->current == NULL)
570 dd->current = dd->widgets;
573 return_val = run_dlg (dd);
575 /* Get the data if we found something interesting */
576 if (return_val != B_CANCEL)
577 for (i = 0; i < widgets->len; i++)
579 quick_widget_item_t *item;
581 item = &g_array_index (widgets, quick_widget_item_t, i);
583 switch (item->quick_widget->widget_type)
585 case quick_checkbox:
586 *item->quick_widget->u.checkbox.state = CHECK (item->widget)->state & C_BOOL;
587 break;
589 case quick_input:
590 if ((quick_widget->u.input.flags & 2) != 0)
591 *item->quick_widget->u.input.result =
592 tilde_expand (INPUT (item->widget)->buffer);
593 else
594 *item->quick_widget->u.input.result = g_strdup (INPUT (item->widget)->buffer);
595 break;
597 case quick_radio:
598 *item->quick_widget->u.radio.value = RADIO (item->widget)->sel;
599 break;
601 default:
602 break;
606 destroy_dlg (dd);
608 /* destroy input labels created before */
609 for (i = 0; i < widgets->len; i++)
611 quick_widget_item_t *item;
613 item = &g_array_index (widgets, quick_widget_item_t, i);
614 if (item->quick_widget->widget_type == quick_input)
615 g_free (item->quick_widget->u.input.label);
618 g_array_free (widgets, TRUE);
620 return return_val;
623 /* --------------------------------------------------------------------------------------------- */