2 Widget based utility functions.
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
8 Miguel de Icaza, 1994, 1995, 1996
9 Radek Doulik, 1994, 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/>.
31 * \brief Source: quick dialog engine
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 ****************************************************************/
49 #define I18N(x) (x = x != NULL && *x != '\0' ? _(x) : x)
51 #define I18N(x) (x = x)
54 /*** file scope type declarations ****************************************************************/
59 quick_widget_t
*quick_widget
;
60 } quick_widget_item_t
;
62 /*** file scope variables ************************************************************************/
64 /* --------------------------------------------------------------------------------------------- */
65 /*** file scope functions ************************************************************************/
66 /* --------------------------------------------------------------------------------------------- */
69 quick_create_input (int y
, int x
, const quick_widget_t
* qw
)
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
;
82 /* --------------------------------------------------------------------------------------------- */
85 quick_create_labeled_input (GArray
* widgets
, int *y
, int x
, quick_widget_t
* quick_widget
,
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
);
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;
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
);
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;
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
);
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
)
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 */
176 /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */
181 quick_widget_t
*quick_widget
;
184 GList
*input_labels
= NULL
; /* Widgets not directly requested by the user. */
187 len
= str_term_width1 (I18N (quick_dlg
->title
)) + 6;
188 quick_dlg
->cols
= MAX (quick_dlg
->cols
, len
);
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
};
201 switch (quick_widget
->widget_type
)
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
;
213 width2
= MAX (width2
, width
);
215 width1
= MAX (width1
, width
);
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
;
230 width2
= MAX (width2
, width
);
232 width1
= MAX (width1
, width
);
236 *quick_widget
->u
.input
.result
= NULL
;
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
);
245 item
.widget
= WIDGET (quick_create_input (y
, x
, quick_widget
));
246 g_array_append_val (widgets
, item
);
247 width
= item
.widget
->cols
;
252 width2
= MAX (width2
, width
);
254 width1
= MAX (width1
, width
);
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
;
265 width2
= MAX (width2
, width
);
267 width1
= MAX (width1
, width
);
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
]));
281 r
= radio_new (++y
, x
, quick_widget
->u
.radio
.count
, (const char **) items
);
282 r
->pos
= r
->sel
= *quick_widget
->u
.radio
.value
;
284 item
.widget
= WIDGET (r
);
285 g_array_append_val (widgets
, item
);
286 y
+= item
.widget
->lines
- 1;
287 width
= item
.widget
->cols
;
291 width2
= MAX (width2
, width
);
293 width1
= MAX (width1
, width
);
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
;
306 case quick_stop_groupbox
:
309 Widget
*w
= WIDGET (g
);
312 w
->lines
= y
+ 1 - w
->y
;
315 g_array_append_val (widgets
, item
);
319 case quick_separator
:
321 if (quick_widget
->u
.separator
.line
)
323 item
.widget
= WIDGET (hline_new (y
, x
, 1));
324 g_array_append_val (widgets
, item
);
328 case quick_start_columns
:
330 g_array_append_val (widgets
, item
);
334 case quick_next_column
:
340 case quick_stop_columns
:
343 g_array_append_val (widgets
, item
);
348 /* start put several buttons in bottom line */
349 if (quick_widget
->u
.separator
.space
)
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 */
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 */
376 quick_widget
->widget_type
= quick_end
;
385 /* adjust dialog width */
386 quick_dlg
->cols
= MAX (quick_dlg
->cols
, blen
+ 6);
398 len
= width2
* 2 + 7;
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
);
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;
420 x
= (WIDGET (dd
)->cols
- blen
) / 2;
422 for (i
= 0; i
< widgets
->len
; i
++)
424 quick_widget_item_t
*item
;
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
)
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 */
446 if (item
->widget
->x
!= x1
)
447 item
->widget
->x
= x2
;
449 item
->widget
->x
+= 2;
455 if (item
->widget
->x
!= x1
)
456 item
->widget
->x
= x2
;
458 item
->widget
->x
+= 2;
463 x
+= item
->widget
->cols
+ 1;
469 Widget
*label
= WIDGET (INPUT (item
->widget
)->label
);
470 int width
= column_width
;
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;
483 case input_label_right
:
484 if (item
->widget
->x
!= x1
)
485 item
->widget
->x
= x2
;
487 item
->widget
->x
+= 2;
488 item
->widget
->cols
= width
- label
->cols
- 1;
489 label
->x
= item
->widget
->x
+ item
->widget
->cols
+ 1;
493 if (item
->widget
->x
!= x1
)
494 item
->widget
->x
= x2
;
496 item
->widget
->x
+= 2;
497 item
->widget
->cols
= width
;
501 /* forced update internal variables of inpuit line */
502 widget_set_size (item
->widget
, item
->widget
->y
, item
->widget
->x
, 1,
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
;
514 case quick_stop_groupbox
:
518 case quick_separator
:
519 if (item
->widget
!= 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
;
535 item
->widget
->cols
= column_width
+ 2;
538 HLINE (item
->widget
)->auto_adjust_cols
= TRUE
;
542 case quick_start_columns
:
546 case quick_stop_columns
:
551 /* several buttons in bottom line */
559 if (item
->widget
!= NULL
)
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
;
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
)
591 *item
->quick_widget
->u
.checkbox
.state
= CHECK (item
->widget
)->state
& C_BOOL
;
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
);
599 *item
->quick_widget
->u
.input
.result
= g_strdup (INPUT (item
->widget
)->buffer
);
603 *item
->quick_widget
->u
.radio
.value
= RADIO (item
->widget
)->sel
;
613 g_list_free_full (input_labels
, g_free
); /* destroy input labels created before */
614 g_array_free (widgets
, TRUE
);
619 /* --------------------------------------------------------------------------------------------- */