Extend QUICK_INPUT and QUICK_LABELED_INPUT macros for getting completion flags via...
[midnight-commander.git] / lib / widget / quick.c
blob790915b33ff9fed064ae74e9e166a2a32b6b69c9
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 qw->u.input.completion_flags);
77 in->is_password = qw->u.input.is_passwd;
78 in->strip_password = qw->u.input.strip_passwd;
80 return in;
83 /* --------------------------------------------------------------------------------------------- */
85 static void
86 quick_create_labeled_input (GArray * widgets, int *y, int x, quick_widget_t * quick_widget,
87 int *width)
89 quick_widget_item_t in, label;
91 label.quick_widget = g_new0 (quick_widget_t, 1);
92 label.quick_widget->widget_type = quick_label;
93 label.quick_widget->options = quick_widget->options;
94 /* FIXME: this should be turned in depend of label_location */
95 label.quick_widget->pos_flags = quick_widget->pos_flags;
97 switch (quick_widget->u.input.label_location)
99 case input_label_above:
100 label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text)));
101 *y += label.widget->lines - 1;
102 g_array_append_val (widgets, label);
104 in.widget = WIDGET (quick_create_input (++(*y), x, quick_widget));
105 in.quick_widget = quick_widget;
106 g_array_append_val (widgets, in);
108 *width = max (label.widget->cols, in.widget->cols);
109 break;
111 case input_label_left:
112 label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text)));
113 g_array_append_val (widgets, label);
115 in.widget = WIDGET (quick_create_input (*y, x + label.widget->cols + 1, quick_widget));
116 in.quick_widget = quick_widget;
117 g_array_append_val (widgets, in);
119 *width = label.widget->cols + in.widget->cols + 1;
120 break;
122 case input_label_right:
123 in.widget = WIDGET (quick_create_input (*y, x, quick_widget));
124 in.quick_widget = quick_widget;
125 g_array_append_val (widgets, in);
127 label.widget =
128 WIDGET (label_new
129 (*y, x + in.widget->cols + 1, I18N (quick_widget->u.input.label_text)));
130 g_array_append_val (widgets, label);
132 *width = label.widget->cols + in.widget->cols + 1;
133 break;
135 case input_label_below:
136 in.widget = WIDGET (quick_create_input (*y, x, quick_widget));
137 in.quick_widget = quick_widget;
138 g_array_append_val (widgets, in);
140 label.widget = WIDGET (label_new (++(*y), x, I18N (quick_widget->u.input.label_text)));
141 *y += label.widget->lines - 1;
142 g_array_append_val (widgets, label);
144 *width = max (label.widget->cols, in.widget->cols);
145 break;
147 default:
148 return;
151 INPUT (in.widget)->label = LABEL (label.widget);
152 /* cross references */
153 label.quick_widget->u.label.input = in.quick_widget;
154 in.quick_widget->u.input.label = label.quick_widget;
157 /* --------------------------------------------------------------------------------------------- */
158 /*** public functions ****************************************************************************/
159 /* --------------------------------------------------------------------------------------------- */
162 quick_dialog_skip (quick_dialog_t * quick_dlg, int nskip)
164 int len;
165 int blen = 0;
166 int x, y; /* current positions */
167 int y1 = 0; /* bottom of 1st column in case of two columns */
168 int y2 = -1; /* start of two columns */
169 int width1 = 0; /* width of single column */
170 int width2 = 0; /* width of each of two columns */
171 gboolean have_groupbox = FALSE;
172 gboolean two_columns = FALSE;
173 gboolean put_buttons = FALSE;
175 /* x position of 1st column is 3 */
176 const int x1 = 3;
177 /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */
178 int x2 = 4;
180 GArray *widgets;
181 size_t i;
182 quick_widget_t *quick_widget;
183 WGroupbox *g = NULL;
184 WDialog *dd;
185 int return_val;
187 len = str_term_width1 (I18N (quick_dlg->title)) + 6;
188 quick_dlg->cols = max (quick_dlg->cols, len);
190 y = 1;
191 x = x1;
193 /* create widgets */
194 widgets = g_array_sized_new (FALSE, FALSE, sizeof (quick_widget_item_t), 8);
196 for (quick_widget = quick_dlg->widgets; quick_widget->widget_type != quick_end; quick_widget++)
198 quick_widget_item_t item = { NULL, quick_widget };
199 int width = 0;
201 switch (quick_widget->widget_type)
203 case quick_checkbox:
204 item.widget =
205 WIDGET (check_new
206 (++y, x, *quick_widget->u.checkbox.state,
207 I18N (quick_widget->u.checkbox.text)));
208 g_array_append_val (widgets, item);
209 width = item.widget->cols;
210 if (g != NULL)
211 width += 2;
212 if (two_columns)
213 width2 = max (width2, width);
214 else
215 width1 = max (width1, width);
216 break;
218 case quick_button:
219 /* single button */
220 item.widget = WIDGET (button_new (++y, x, quick_widget->u.button.action,
221 quick_widget->u.button.action == B_ENTER ?
222 DEFPUSH_BUTTON : NORMAL_BUTTON,
223 I18N (quick_widget->u.button.text),
224 quick_widget->u.button.callback));
225 g_array_append_val (widgets, item);
226 width = item.widget->cols;
227 if (g != NULL)
228 width += 2;
229 if (two_columns)
230 width2 = max (width2, width);
231 else
232 width1 = max (width1, width);
233 break;
235 case quick_input:
236 *quick_widget->u.input.result = NULL;
237 y++;
238 if (quick_widget->u.input.label_location != input_label_none)
239 quick_create_labeled_input (widgets, &y, x, quick_widget, &width);
240 else
242 item.widget = WIDGET (quick_create_input (y, x, quick_widget));
243 g_array_append_val (widgets, item);
244 width = item.widget->cols;
246 if (g != NULL)
247 width += 2;
248 if (two_columns)
249 width2 = max (width2, width);
250 else
251 width1 = max (width1, width);
252 break;
254 case quick_label:
255 item.widget = WIDGET (label_new (++y, x, I18N (quick_widget->u.label.text)));
256 g_array_append_val (widgets, item);
257 y += item.widget->lines - 1;
258 width = item.widget->cols;
259 if (g != NULL)
260 width += 2;
261 if (two_columns)
262 width2 = max (width2, width);
263 else
264 width1 = max (width1, width);
265 break;
267 case quick_radio:
269 WRadio *r;
270 char **items = NULL;
272 /* create the copy of radio_items to avoid mwmory leak */
273 items = g_new (char *, quick_widget->u.radio.count + 1);
274 for (i = 0; i < (size_t) quick_widget->u.radio.count; i++)
275 items[i] = g_strdup (_(quick_widget->u.radio.items[i]));
276 items[i] = NULL;
278 r = radio_new (++y, x, quick_widget->u.radio.count, (const char **) items);
279 r->pos = r->sel = *quick_widget->u.radio.value;
280 g_strfreev (items);
281 item.widget = WIDGET (r);
282 g_array_append_val (widgets, item);
283 y += item.widget->lines - 1;
284 width = item.widget->cols;
285 if (g != NULL)
286 width += 2;
287 if (two_columns)
288 width2 = max (width2, width);
289 else
290 width1 = max (width1, width);
292 break;
294 case quick_start_groupbox:
295 I18N (quick_widget->u.groupbox.title);
296 len = str_term_width1 (quick_widget->u.groupbox.title);
297 g = groupbox_new (++y, x, 1, len + 4, quick_widget->u.groupbox.title);
298 item.widget = WIDGET (g);
299 g_array_append_val (widgets, item);
300 have_groupbox = TRUE;
301 break;
303 case quick_stop_groupbox:
304 if (g != NULL)
306 Widget *w = WIDGET (g);
308 y++;
309 w->lines = y + 1 - w->y;
310 g = NULL;
312 g_array_append_val (widgets, item);
314 break;
316 case quick_separator:
317 y++;
318 if (quick_widget->u.separator.line)
320 item.widget = WIDGET (hline_new (y, x, 1));
321 g_array_append_val (widgets, item);
323 break;
325 case quick_start_columns:
326 y2 = y;
327 g_array_append_val (widgets, item);
328 two_columns = TRUE;
329 break;
331 case quick_next_column:
332 x = x2;
333 y1 = y;
334 y = y2;
335 break;
337 case quick_stop_columns:
338 x = x1;
339 y = max (y1, y);
340 g_array_append_val (widgets, item);
341 two_columns = FALSE;
342 break;
344 case quick_buttons:
345 /* start put several buttons in bottom line */
346 if (quick_widget->u.separator.space)
348 y++;
350 if (quick_widget->u.separator.line)
351 item.widget = WIDGET (hline_new (y, 1, -1));
354 g_array_append_val (widgets, item);
356 /* several buttons in bottom line */
357 y++;
358 quick_widget++;
359 for (; quick_widget->widget_type == quick_button; quick_widget++)
361 item.widget = WIDGET (button_new (y, x++, quick_widget->u.button.action,
362 quick_widget->u.button.action == B_ENTER ?
363 DEFPUSH_BUTTON : NORMAL_BUTTON,
364 I18N (quick_widget->u.button.text),
365 quick_widget->u.button.callback));
366 item.quick_widget = quick_widget;
367 g_array_append_val (widgets, item);
368 blen += item.widget->cols + 1;
371 /* stop dialog build here */
372 blen--;
373 quick_widget->widget_type = quick_end;
374 quick_widget--;
375 break;
377 default:
378 break;
382 /* adjust dialog width */
383 quick_dlg->cols = max (quick_dlg->cols, blen + 6);
384 if (have_groupbox)
386 if (width1 != 0)
387 width1 += 2;
388 if (width2 != 0)
389 width2 += 2;
391 if (width2 == 0)
392 len = width1 + 6;
393 else
395 len = width2 * 2 + 7;
396 if (width1 != 0)
397 len = max (len, width1 + 6);
400 quick_dlg->cols = max (quick_dlg->cols, len);
401 width1 = quick_dlg->cols - 6;
402 width2 = (quick_dlg->cols - 7) / 2;
404 if (quick_dlg->x == -1 || quick_dlg->y == -1)
405 dd = create_dlg (TRUE, 0, 0, y + 3, quick_dlg->cols,
406 dialog_colors, quick_dlg->callback, quick_dlg->mouse, quick_dlg->help,
407 quick_dlg->title, DLG_CENTER | DLG_TRYUP);
408 else
409 dd = create_dlg (TRUE, quick_dlg->y, quick_dlg->x, y + 3, quick_dlg->cols,
410 dialog_colors, quick_dlg->callback, quick_dlg->mouse, quick_dlg->help,
411 quick_dlg->title, DLG_NONE);
413 /* add widgets into the dialog */
414 x2 = x1 + width2 + 1;
415 g = NULL;
416 two_columns = FALSE;
417 x = (WIDGET (dd)->cols - blen) / 2;
419 for (i = 0; i < widgets->len; i++)
421 quick_widget_item_t *item;
422 int column_width;
424 item = &g_array_index (widgets, quick_widget_item_t, i);
425 column_width = two_columns ? width2 : width1;
427 /* adjust widget width and x position */
428 switch (item->quick_widget->widget_type)
430 case quick_label:
432 quick_widget_t *input = item->quick_widget->u.label.input;
434 if (input != NULL && input->u.input.label_location == input_label_right)
436 /* location of this label will be adjusted later */
437 break;
440 /* fall through */
441 case quick_checkbox:
442 case quick_radio:
443 if (item->widget->x != x1)
444 item->widget->x = x2;
445 if (g != NULL)
446 item->widget->x += 2;
447 break;
449 case quick_button:
450 if (!put_buttons)
452 if (item->widget->x != x1)
453 item->widget->x = x2;
454 if (g != NULL)
455 item->widget->x += 2;
457 else
459 item->widget->x = x;
460 x += item->widget->cols + 1;
462 break;
464 case quick_input:
466 Widget *label = WIDGET (INPUT (item->widget)->label);
467 int width = column_width;
469 if (g != NULL)
470 width -= 4;
472 switch (item->quick_widget->u.input.label_location)
474 case input_label_left:
475 /* label was adjusted before; adjust input line */
476 item->widget->x = label->x + label->cols + 1 - WIDGET (label->owner)->x;
477 item->widget->cols = width - label->cols - 1;
478 break;
480 case input_label_right:
481 label->x =
482 item->widget->x + item->widget->cols + 1 - WIDGET (item->widget->owner)->x;
483 item->widget->cols = width - label->cols - 1;
484 break;
486 default:
487 if (item->widget->x != x1)
488 item->widget->x = x2;
489 if (g != NULL)
490 item->widget->x += 2;
491 item->widget->cols = width;
492 break;
495 /* forced update internal variables of inpuit line */
496 input_set_origin (INPUT (item->widget), item->widget->x, item->widget->cols);
498 break;
500 case quick_start_groupbox:
501 g = GROUPBOX (item->widget);
502 if (item->widget->x != x1)
503 item->widget->x = x2;
504 item->widget->cols = column_width;
505 break;
507 case quick_stop_groupbox:
508 g = NULL;
509 break;
511 case quick_separator:
512 if (item->widget != NULL)
514 if (g != NULL)
516 Widget *wg = WIDGET (g);
518 HLINE (item->widget)->auto_adjust_cols = FALSE;
519 item->widget->x = wg->x + 1 - WIDGET (wg->owner)->x;
520 item->widget->cols = wg->cols;
522 else if (two_columns)
524 HLINE (item->widget)->auto_adjust_cols = FALSE;
525 if (item->widget->x != x1)
526 item->widget->x = x2;
527 item->widget->x--;
528 item->widget->cols = column_width + 2;
530 else
531 HLINE (item->widget)->auto_adjust_cols = TRUE;
533 break;
535 case quick_start_columns:
536 two_columns = TRUE;
537 break;
539 case quick_stop_columns:
540 two_columns = FALSE;
541 break;
543 case quick_buttons:
544 /* several buttons in bottom line */
545 put_buttons = TRUE;
546 break;
548 default:
549 break;
552 if (item->widget != NULL)
554 unsigned long id;
556 /* add widget into dialog */
557 item->widget->options |= item->quick_widget->options; /* FIXME: cannot reset flags, setup only */
558 id = add_widget_autopos (dd, item->widget, item->quick_widget->pos_flags, NULL);
559 if (item->quick_widget->id != NULL)
560 *item->quick_widget->id = id;
564 while (nskip-- != 0)
566 dd->current = g_list_next (dd->current);
567 if (dd->current == NULL)
568 dd->current = dd->widgets;
571 return_val = run_dlg (dd);
573 /* Get the data if we found something interesting */
574 if (return_val != B_CANCEL)
575 for (i = 0; i < widgets->len; i++)
577 quick_widget_item_t *item;
579 item = &g_array_index (widgets, quick_widget_item_t, i);
581 switch (item->quick_widget->widget_type)
583 case quick_checkbox:
584 *item->quick_widget->u.checkbox.state = CHECK (item->widget)->state & C_BOOL;
585 break;
587 case quick_input:
588 if ((quick_widget->u.input.completion_flags & INPUT_COMPLETE_CD) != 0)
589 *item->quick_widget->u.input.result =
590 tilde_expand (INPUT (item->widget)->buffer);
591 else
592 *item->quick_widget->u.input.result = g_strdup (INPUT (item->widget)->buffer);
593 break;
595 case quick_radio:
596 *item->quick_widget->u.radio.value = RADIO (item->widget)->sel;
597 break;
599 default:
600 break;
604 destroy_dlg (dd);
606 /* destroy input labels created before */
607 for (i = 0; i < widgets->len; i++)
609 quick_widget_item_t *item;
611 item = &g_array_index (widgets, quick_widget_item_t, i);
612 if (item->quick_widget->widget_type == quick_input)
613 g_free (item->quick_widget->u.input.label);
616 g_array_free (widgets, TRUE);
618 return return_val;
621 /* --------------------------------------------------------------------------------------------- */