Drop old mouse API and use the new one.
[midnight-commander.git] / lib / widget / quick.c
blob780aed87e0bf13db6b36f6b82bd11741bc246d75
1 /*
2 Widget based utility functions.
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
7 Authors:
8 Miguel de Icaza, 1994, 1995, 1996
9 Radek Doulik, 1994, 1995
10 Jakub Jelinek, 1995
11 Andrej Borsenkow, 1995
12 Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012, 2013
14 This file is part of the Midnight Commander.
16 The Midnight Commander is free software: you can redistribute it
17 and/or modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation, either version 3 of the License,
19 or (at your option) any later version.
21 The Midnight Commander is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
30 /** \file quick.c
31 * \brief Source: quick dialog engine
34 #include <config.h>
36 #include <stdlib.h>
37 #include <stdio.h> /* fprintf() */
39 #include "lib/global.h"
40 #include "lib/strutil.h" /* str_term_width1() */
41 #include "lib/util.h" /* tilde_expand() */
42 #include "lib/widget.h"
44 /*** global variables ****************************************************************************/
46 /*** file scope macro definitions ****************************************************************/
48 #ifdef ENABLE_NLS
49 #define I18N(x) (x = x != NULL && *x != '\0' ? _(x) : x)
50 #else
51 #define I18N(x) (x = x)
52 #endif
54 /*** file scope type declarations ****************************************************************/
56 typedef struct
58 Widget *widget;
59 quick_widget_t *quick_widget;
60 } quick_widget_item_t;
62 /*** file scope variables ************************************************************************/
64 /* --------------------------------------------------------------------------------------------- */
65 /*** file scope functions ************************************************************************/
66 /* --------------------------------------------------------------------------------------------- */
68 static WInput *
69 quick_create_input (int y, int x, const quick_widget_t * qw)
71 WInput *in;
73 in = input_new (y, x, input_colors, 8, qw->u.input.text, qw->u.input.histname,
74 qw->u.input.completion_flags);
76 in->is_password = qw->u.input.is_passwd;
77 in->strip_password = qw->u.input.strip_passwd;
79 return in;
82 /* --------------------------------------------------------------------------------------------- */
84 static void
85 quick_create_labeled_input (GArray * widgets, int *y, int x, quick_widget_t * quick_widget,
86 int *width)
88 quick_widget_item_t in, label;
90 label.quick_widget = g_new0 (quick_widget_t, 1);
91 label.quick_widget->widget_type = quick_label;
92 label.quick_widget->options = quick_widget->options;
93 /* FIXME: this should be turned in depend of label_location */
94 label.quick_widget->pos_flags = quick_widget->pos_flags;
96 switch (quick_widget->u.input.label_location)
98 case input_label_above:
99 label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text)));
100 *y += label.widget->lines - 1;
101 g_array_append_val (widgets, label);
103 in.widget = WIDGET (quick_create_input (++(*y), x, quick_widget));
104 in.quick_widget = quick_widget;
105 g_array_append_val (widgets, in);
107 *width = max (label.widget->cols, in.widget->cols);
108 break;
110 case input_label_left:
111 label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text)));
112 g_array_append_val (widgets, label);
114 in.widget = WIDGET (quick_create_input (*y, x + label.widget->cols + 1, quick_widget));
115 in.quick_widget = quick_widget;
116 g_array_append_val (widgets, in);
118 *width = label.widget->cols + in.widget->cols + 1;
119 break;
121 case input_label_right:
122 in.widget = WIDGET (quick_create_input (*y, x, quick_widget));
123 in.quick_widget = quick_widget;
124 g_array_append_val (widgets, in);
126 label.widget =
127 WIDGET (label_new
128 (*y, x + in.widget->cols + 1, I18N (quick_widget->u.input.label_text)));
129 g_array_append_val (widgets, label);
131 *width = label.widget->cols + in.widget->cols + 1;
132 break;
134 case input_label_below:
135 in.widget = WIDGET (quick_create_input (*y, x, quick_widget));
136 in.quick_widget = quick_widget;
137 g_array_append_val (widgets, in);
139 label.widget = WIDGET (label_new (++(*y), x, I18N (quick_widget->u.input.label_text)));
140 *y += label.widget->lines - 1;
141 g_array_append_val (widgets, label);
143 *width = max (label.widget->cols, in.widget->cols);
144 break;
146 default:
147 return;
150 INPUT (in.widget)->label = LABEL (label.widget);
151 /* cross references */
152 label.quick_widget->u.label.input = in.quick_widget;
153 in.quick_widget->u.input.label = label.quick_widget;
156 /* --------------------------------------------------------------------------------------------- */
157 /*** public functions ****************************************************************************/
158 /* --------------------------------------------------------------------------------------------- */
161 quick_dialog_skip (quick_dialog_t * quick_dlg, int nskip)
163 int len;
164 int blen = 0;
165 int x, y; /* current positions */
166 int y1 = 0; /* bottom of 1st column in case of two columns */
167 int y2 = -1; /* start of two columns */
168 int width1 = 0; /* width of single column */
169 int width2 = 0; /* width of each of two columns */
170 gboolean have_groupbox = FALSE;
171 gboolean two_columns = FALSE;
172 gboolean put_buttons = FALSE;
174 /* x position of 1st column is 3 */
175 const int x1 = 3;
176 /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */
177 int x2 = 4;
179 GArray *widgets;
180 size_t i;
181 quick_widget_t *quick_widget;
182 WGroupbox *g = NULL;
183 WDialog *dd;
184 GList *input_labels = NULL; /* Widgets not directly requested by the user. */
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)
240 quick_create_labeled_input (widgets, &y, x, quick_widget, &width);
241 input_labels = g_list_prepend (input_labels, quick_widget->u.input.label);
243 else
245 item.widget = WIDGET (quick_create_input (y, x, quick_widget));
246 g_array_append_val (widgets, item);
247 width = item.widget->cols;
249 if (g != NULL)
250 width += 2;
251 if (two_columns)
252 width2 = max (width2, width);
253 else
254 width1 = max (width1, width);
255 break;
257 case quick_label:
258 item.widget = WIDGET (label_new (++y, x, I18N (quick_widget->u.label.text)));
259 g_array_append_val (widgets, item);
260 y += item.widget->lines - 1;
261 width = item.widget->cols;
262 if (g != NULL)
263 width += 2;
264 if (two_columns)
265 width2 = max (width2, width);
266 else
267 width1 = max (width1, width);
268 break;
270 case quick_radio:
272 WRadio *r;
273 char **items = NULL;
275 /* create the copy of radio_items to avoid mwmory leak */
276 items = g_new (char *, quick_widget->u.radio.count + 1);
277 for (i = 0; i < (size_t) quick_widget->u.radio.count; i++)
278 items[i] = g_strdup (_(quick_widget->u.radio.items[i]));
279 items[i] = NULL;
281 r = radio_new (++y, x, quick_widget->u.radio.count, (const char **) items);
282 r->pos = r->sel = *quick_widget->u.radio.value;
283 g_strfreev (items);
284 item.widget = WIDGET (r);
285 g_array_append_val (widgets, item);
286 y += item.widget->lines - 1;
287 width = item.widget->cols;
288 if (g != NULL)
289 width += 2;
290 if (two_columns)
291 width2 = max (width2, width);
292 else
293 width1 = max (width1, width);
295 break;
297 case quick_start_groupbox:
298 I18N (quick_widget->u.groupbox.title);
299 len = str_term_width1 (quick_widget->u.groupbox.title);
300 g = groupbox_new (++y, x, 1, len + 4, quick_widget->u.groupbox.title);
301 item.widget = WIDGET (g);
302 g_array_append_val (widgets, item);
303 have_groupbox = TRUE;
304 break;
306 case quick_stop_groupbox:
307 if (g != NULL)
309 Widget *w = WIDGET (g);
311 y++;
312 w->lines = y + 1 - w->y;
313 g = NULL;
315 g_array_append_val (widgets, item);
317 break;
319 case quick_separator:
320 y++;
321 if (quick_widget->u.separator.line)
323 item.widget = WIDGET (hline_new (y, x, 1));
324 g_array_append_val (widgets, item);
326 break;
328 case quick_start_columns:
329 y2 = y;
330 g_array_append_val (widgets, item);
331 two_columns = TRUE;
332 break;
334 case quick_next_column:
335 x = x2;
336 y1 = y;
337 y = y2;
338 break;
340 case quick_stop_columns:
341 x = x1;
342 y = max (y1, y);
343 g_array_append_val (widgets, item);
344 two_columns = FALSE;
345 break;
347 case quick_buttons:
348 /* start put several buttons in bottom line */
349 if (quick_widget->u.separator.space)
351 y++;
353 if (quick_widget->u.separator.line)
354 item.widget = WIDGET (hline_new (y, 1, -1));
357 g_array_append_val (widgets, item);
359 /* several buttons in bottom line */
360 y++;
361 quick_widget++;
362 for (; quick_widget->widget_type == quick_button; quick_widget++)
364 item.widget = WIDGET (button_new (y, x++, quick_widget->u.button.action,
365 quick_widget->u.button.action == B_ENTER ?
366 DEFPUSH_BUTTON : NORMAL_BUTTON,
367 I18N (quick_widget->u.button.text),
368 quick_widget->u.button.callback));
369 item.quick_widget = quick_widget;
370 g_array_append_val (widgets, item);
371 blen += item.widget->cols + 1;
374 /* stop dialog build here */
375 blen--;
376 quick_widget->widget_type = quick_end;
377 quick_widget--;
378 break;
380 default:
381 break;
385 /* adjust dialog width */
386 quick_dlg->cols = max (quick_dlg->cols, blen + 6);
387 if (have_groupbox)
389 if (width1 != 0)
390 width1 += 2;
391 if (width2 != 0)
392 width2 += 2;
394 if (width2 == 0)
395 len = width1 + 6;
396 else
398 len = width2 * 2 + 7;
399 if (width1 != 0)
400 len = max (len, width1 + 6);
403 quick_dlg->cols = max (quick_dlg->cols, len);
404 width1 = quick_dlg->cols - 6;
405 width2 = (quick_dlg->cols - 7) / 2;
407 if (quick_dlg->x == -1 || quick_dlg->y == -1)
408 dd = dlg_create (TRUE, 0, 0, y + 3, quick_dlg->cols,
409 dialog_colors, quick_dlg->callback, quick_dlg->mouse_callback,
410 quick_dlg->help, quick_dlg->title, DLG_CENTER | DLG_TRYUP);
411 else
412 dd = dlg_create (TRUE, quick_dlg->y, quick_dlg->x, y + 3, quick_dlg->cols,
413 dialog_colors, quick_dlg->callback, quick_dlg->mouse_callback,
414 quick_dlg->help, quick_dlg->title, DLG_NONE);
416 /* add widgets into the dialog */
417 x2 = x1 + width2 + 1;
418 g = NULL;
419 two_columns = FALSE;
420 x = (WIDGET (dd)->cols - blen) / 2;
422 for (i = 0; i < widgets->len; i++)
424 quick_widget_item_t *item;
425 int column_width;
427 item = &g_array_index (widgets, quick_widget_item_t, i);
428 column_width = two_columns ? width2 : width1;
430 /* adjust widget width and x position */
431 switch (item->quick_widget->widget_type)
433 case quick_label:
435 quick_widget_t *input = item->quick_widget->u.label.input;
437 if (input != NULL && input->u.input.label_location == input_label_right)
439 /* location of this label will be adjusted later */
440 break;
443 /* fall through */
444 case quick_checkbox:
445 case quick_radio:
446 if (item->widget->x != x1)
447 item->widget->x = x2;
448 if (g != NULL)
449 item->widget->x += 2;
450 break;
452 case quick_button:
453 if (!put_buttons)
455 if (item->widget->x != x1)
456 item->widget->x = x2;
457 if (g != NULL)
458 item->widget->x += 2;
460 else
462 item->widget->x = x;
463 x += item->widget->cols + 1;
465 break;
467 case quick_input:
469 Widget *label = WIDGET (INPUT (item->widget)->label);
470 int width = column_width;
472 if (g != NULL)
473 width -= 4;
475 switch (item->quick_widget->u.input.label_location)
477 case input_label_left:
478 /* label was adjusted before; adjust input line */
479 item->widget->x = label->x + label->cols + 1 - WIDGET (label->owner)->x;
480 item->widget->cols = width - label->cols - 1;
481 break;
483 case input_label_right:
484 if (item->widget->x != x1)
485 item->widget->x = x2;
486 if (g != NULL)
487 item->widget->x += 2;
488 item->widget->cols = width - label->cols - 1;
489 label->x = item->widget->x + item->widget->cols + 1;
490 break;
492 default:
493 if (item->widget->x != x1)
494 item->widget->x = x2;
495 if (g != NULL)
496 item->widget->x += 2;
497 item->widget->cols = width;
498 break;
501 /* forced update internal variables of inpuit line */
502 widget_set_size (item->widget, item->widget->y, item->widget->x, 1,
503 item->widget->cols);
505 break;
507 case quick_start_groupbox:
508 g = GROUPBOX (item->widget);
509 if (item->widget->x != x1)
510 item->widget->x = x2;
511 item->widget->cols = column_width;
512 break;
514 case quick_stop_groupbox:
515 g = NULL;
516 break;
518 case quick_separator:
519 if (item->widget != NULL)
521 if (g != NULL)
523 Widget *wg = WIDGET (g);
525 HLINE (item->widget)->auto_adjust_cols = FALSE;
526 item->widget->x = wg->x + 1 - WIDGET (wg->owner)->x;
527 item->widget->cols = wg->cols;
529 else if (two_columns)
531 HLINE (item->widget)->auto_adjust_cols = FALSE;
532 if (item->widget->x != x1)
533 item->widget->x = x2;
534 item->widget->x--;
535 item->widget->cols = column_width + 2;
537 else
538 HLINE (item->widget)->auto_adjust_cols = TRUE;
540 break;
542 case quick_start_columns:
543 two_columns = TRUE;
544 break;
546 case quick_stop_columns:
547 two_columns = FALSE;
548 break;
550 case quick_buttons:
551 /* several buttons in bottom line */
552 put_buttons = TRUE;
553 break;
555 default:
556 break;
559 if (item->widget != NULL)
561 unsigned long id;
563 /* add widget into dialog */
564 item->widget->options |= item->quick_widget->options; /* FIXME: cannot reset flags, setup only */
565 id = add_widget_autopos (dd, item->widget, item->quick_widget->pos_flags, NULL);
566 if (item->quick_widget->id != NULL)
567 *item->quick_widget->id = id;
571 while (nskip-- != 0)
573 dd->current = g_list_next (dd->current);
574 if (dd->current == NULL)
575 dd->current = dd->widgets;
578 return_val = dlg_run (dd);
580 /* Get the data if we found something interesting */
581 if (return_val != B_CANCEL)
582 for (i = 0; i < widgets->len; i++)
584 quick_widget_item_t *item;
586 item = &g_array_index (widgets, quick_widget_item_t, i);
588 switch (item->quick_widget->widget_type)
590 case quick_checkbox:
591 *item->quick_widget->u.checkbox.state = CHECK (item->widget)->state & C_BOOL;
592 break;
594 case quick_input:
595 if ((quick_widget->u.input.completion_flags & INPUT_COMPLETE_CD) != 0)
596 *item->quick_widget->u.input.result =
597 tilde_expand (INPUT (item->widget)->buffer);
598 else
599 *item->quick_widget->u.input.result = g_strdup (INPUT (item->widget)->buffer);
600 break;
602 case quick_radio:
603 *item->quick_widget->u.radio.value = RADIO (item->widget)->sel;
604 break;
606 default:
607 break;
611 dlg_destroy (dd);
613 g_list_free_full (input_labels, g_free); /* destroy input labels created before */
614 g_array_free (widgets, TRUE);
616 return return_val;
619 /* --------------------------------------------------------------------------------------------- */