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 label
.quick_widget
->state
= quick_widget
->state
;
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
);
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;
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
);
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;
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
);
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
)
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 */
177 /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */
182 quick_widget_t
*quick_widget
;
185 GList
*input_labels
= NULL
; /* Widgets not directly requested by the user. */
188 len
= str_term_width1 (I18N (quick_dlg
->title
)) + 6;
189 quick_dlg
->cols
= MAX (quick_dlg
->cols
, len
);
195 widgets
= g_array_sized_new (FALSE
, FALSE
, sizeof (quick_widget_item_t
), 8);
197 for (quick_widget
= quick_dlg
->widgets
; quick_widget
->widget_type
!= quick_end
; quick_widget
++)
199 quick_widget_item_t item
= { NULL
, quick_widget
};
202 switch (quick_widget
->widget_type
)
207 (++y
, x
, *quick_widget
->u
.checkbox
.state
,
208 I18N (quick_widget
->u
.checkbox
.text
)));
209 g_array_append_val (widgets
, item
);
210 width
= item
.widget
->cols
;
214 width2
= MAX (width2
, width
);
216 width1
= MAX (width1
, width
);
221 item
.widget
= WIDGET (button_new (++y
, x
, quick_widget
->u
.button
.action
,
222 quick_widget
->u
.button
.action
== B_ENTER
?
223 DEFPUSH_BUTTON
: NORMAL_BUTTON
,
224 I18N (quick_widget
->u
.button
.text
),
225 quick_widget
->u
.button
.callback
));
226 g_array_append_val (widgets
, item
);
227 width
= item
.widget
->cols
;
231 width2
= MAX (width2
, width
);
233 width1
= MAX (width1
, width
);
237 *quick_widget
->u
.input
.result
= NULL
;
239 if (quick_widget
->u
.input
.label_location
!= input_label_none
)
241 quick_create_labeled_input (widgets
, &y
, x
, quick_widget
, &width
);
242 input_labels
= g_list_prepend (input_labels
, quick_widget
->u
.input
.label
);
246 item
.widget
= WIDGET (quick_create_input (y
, x
, quick_widget
));
247 g_array_append_val (widgets
, item
);
248 width
= item
.widget
->cols
;
253 width2
= MAX (width2
, width
);
255 width1
= MAX (width1
, width
);
259 item
.widget
= WIDGET (label_new (++y
, x
, I18N (quick_widget
->u
.label
.text
)));
260 g_array_append_val (widgets
, item
);
261 y
+= item
.widget
->lines
- 1;
262 width
= item
.widget
->cols
;
266 width2
= MAX (width2
, width
);
268 width1
= MAX (width1
, width
);
276 /* create the copy of radio_items to avoid mwmory leak */
277 items
= g_new (char *, quick_widget
->u
.radio
.count
+ 1);
278 for (i
= 0; i
< (size_t) quick_widget
->u
.radio
.count
; i
++)
279 items
[i
] = g_strdup (_(quick_widget
->u
.radio
.items
[i
]));
282 r
= radio_new (++y
, x
, quick_widget
->u
.radio
.count
, (const char **) items
);
283 r
->pos
= r
->sel
= *quick_widget
->u
.radio
.value
;
285 item
.widget
= WIDGET (r
);
286 g_array_append_val (widgets
, item
);
287 y
+= item
.widget
->lines
- 1;
288 width
= item
.widget
->cols
;
292 width2
= MAX (width2
, width
);
294 width1
= MAX (width1
, width
);
298 case quick_start_groupbox
:
299 I18N (quick_widget
->u
.groupbox
.title
);
300 len
= str_term_width1 (quick_widget
->u
.groupbox
.title
);
301 g
= groupbox_new (++y
, x
, 1, len
+ 4, quick_widget
->u
.groupbox
.title
);
302 item
.widget
= WIDGET (g
);
303 g_array_append_val (widgets
, item
);
304 have_groupbox
= TRUE
;
307 case quick_stop_groupbox
:
310 Widget
*w
= WIDGET (g
);
313 w
->lines
= y
+ 1 - w
->y
;
316 g_array_append_val (widgets
, item
);
320 case quick_separator
:
322 if (quick_widget
->u
.separator
.line
)
324 item
.widget
= WIDGET (hline_new (y
, x
, 1));
325 g_array_append_val (widgets
, item
);
329 case quick_start_columns
:
331 g_array_append_val (widgets
, item
);
335 case quick_next_column
:
341 case quick_stop_columns
:
344 g_array_append_val (widgets
, item
);
349 /* start put several buttons in bottom line */
350 if (quick_widget
->u
.separator
.space
)
354 if (quick_widget
->u
.separator
.line
)
355 item
.widget
= WIDGET (hline_new (y
, 1, -1));
358 g_array_append_val (widgets
, item
);
360 /* several buttons in bottom line */
363 for (; quick_widget
->widget_type
== quick_button
; quick_widget
++)
365 item
.widget
= WIDGET (button_new (y
, x
++, quick_widget
->u
.button
.action
,
366 quick_widget
->u
.button
.action
== B_ENTER
?
367 DEFPUSH_BUTTON
: NORMAL_BUTTON
,
368 I18N (quick_widget
->u
.button
.text
),
369 quick_widget
->u
.button
.callback
));
370 item
.quick_widget
= quick_widget
;
371 g_array_append_val (widgets
, item
);
372 blen
+= item
.widget
->cols
+ 1;
375 /* stop dialog build here */
377 quick_widget
->widget_type
= quick_end
;
386 /* adjust dialog width */
387 quick_dlg
->cols
= MAX (quick_dlg
->cols
, blen
+ 6);
399 len
= width2
* 2 + 7;
401 len
= MAX (len
, width1
+ 6);
404 quick_dlg
->cols
= MAX (quick_dlg
->cols
, len
);
405 width1
= quick_dlg
->cols
- 6;
406 width2
= (quick_dlg
->cols
- 7) / 2;
408 if (quick_dlg
->x
== -1 || quick_dlg
->y
== -1)
409 dd
= dlg_create (TRUE
, 0, 0, y
+ 3, quick_dlg
->cols
,
410 dialog_colors
, quick_dlg
->callback
, quick_dlg
->mouse_callback
,
411 quick_dlg
->help
, quick_dlg
->title
, DLG_CENTER
| DLG_TRYUP
);
413 dd
= dlg_create (TRUE
, quick_dlg
->y
, quick_dlg
->x
, y
+ 3, quick_dlg
->cols
,
414 dialog_colors
, quick_dlg
->callback
, quick_dlg
->mouse_callback
,
415 quick_dlg
->help
, quick_dlg
->title
, DLG_NONE
);
417 /* add widgets into the dialog */
418 x2
= x1
+ width2
+ 1;
421 x
= (WIDGET (dd
)->cols
- blen
) / 2;
423 for (i
= 0; i
< widgets
->len
; i
++)
425 quick_widget_item_t
*item
;
428 item
= &g_array_index (widgets
, quick_widget_item_t
, i
);
429 column_width
= two_columns
? width2
: width1
;
431 /* adjust widget width and x position */
432 switch (item
->quick_widget
->widget_type
)
436 quick_widget_t
*input
= item
->quick_widget
->u
.label
.input
;
438 if (input
!= NULL
&& input
->u
.input
.label_location
== input_label_right
)
440 /* location of this label will be adjusted later */
447 if (item
->widget
->x
!= x1
)
448 item
->widget
->x
= x2
;
450 item
->widget
->x
+= 2;
456 if (item
->widget
->x
!= x1
)
457 item
->widget
->x
= x2
;
459 item
->widget
->x
+= 2;
464 x
+= item
->widget
->cols
+ 1;
470 Widget
*label
= WIDGET (INPUT (item
->widget
)->label
);
471 int width
= column_width
;
476 switch (item
->quick_widget
->u
.input
.label_location
)
478 case input_label_left
:
479 /* label was adjusted before; adjust input line */
480 item
->widget
->x
= label
->x
+ label
->cols
+ 1 - WIDGET (label
->owner
)->x
;
481 item
->widget
->cols
= width
- label
->cols
- 1;
484 case input_label_right
:
485 if (item
->widget
->x
!= x1
)
486 item
->widget
->x
= x2
;
488 item
->widget
->x
+= 2;
489 item
->widget
->cols
= width
- label
->cols
- 1;
490 label
->x
= item
->widget
->x
+ item
->widget
->cols
+ 1;
494 if (item
->widget
->x
!= x1
)
495 item
->widget
->x
= x2
;
497 item
->widget
->x
+= 2;
498 item
->widget
->cols
= width
;
502 /* forced update internal variables of inpuit line */
503 widget_set_size (item
->widget
, item
->widget
->y
, item
->widget
->x
, 1,
508 case quick_start_groupbox
:
509 g
= GROUPBOX (item
->widget
);
510 if (item
->widget
->x
!= x1
)
511 item
->widget
->x
= x2
;
512 item
->widget
->cols
= column_width
;
515 case quick_stop_groupbox
:
519 case quick_separator
:
520 if (item
->widget
!= NULL
)
524 Widget
*wg
= WIDGET (g
);
526 HLINE (item
->widget
)->auto_adjust_cols
= FALSE
;
527 item
->widget
->x
= wg
->x
+ 1 - WIDGET (wg
->owner
)->x
;
528 item
->widget
->cols
= wg
->cols
;
530 else if (two_columns
)
532 HLINE (item
->widget
)->auto_adjust_cols
= FALSE
;
533 if (item
->widget
->x
!= x1
)
534 item
->widget
->x
= x2
;
536 item
->widget
->cols
= column_width
+ 2;
539 HLINE (item
->widget
)->auto_adjust_cols
= TRUE
;
543 case quick_start_columns
:
547 case quick_stop_columns
:
552 /* several buttons in bottom line */
560 if (item
->widget
!= NULL
)
564 /* add widget into dialog */
565 item
->widget
->options
|= item
->quick_widget
->options
; /* FIXME: cannot reset flags, setup only */
566 item
->widget
->state
|= item
->quick_widget
->state
; /* FIXME: cannot reset flags, setup only */
567 id
= add_widget_autopos (dd
, item
->widget
, item
->quick_widget
->pos_flags
, NULL
);
568 if (item
->quick_widget
->id
!= NULL
)
569 *item
->quick_widget
->id
= id
;
575 dd
->current
= g_list_next (dd
->current
);
576 if (dd
->current
== NULL
)
577 dd
->current
= dd
->widgets
;
580 return_val
= dlg_run (dd
);
582 /* Get the data if we found something interesting */
583 if (return_val
!= B_CANCEL
)
584 for (i
= 0; i
< widgets
->len
; i
++)
586 quick_widget_item_t
*item
;
588 item
= &g_array_index (widgets
, quick_widget_item_t
, i
);
590 switch (item
->quick_widget
->widget_type
)
593 *item
->quick_widget
->u
.checkbox
.state
= CHECK (item
->widget
)->state
& C_BOOL
;
597 if ((quick_widget
->u
.input
.completion_flags
& INPUT_COMPLETE_CD
) != 0)
598 *item
->quick_widget
->u
.input
.result
=
599 tilde_expand (INPUT (item
->widget
)->buffer
);
601 *item
->quick_widget
->u
.input
.result
= g_strdup (INPUT (item
->widget
)->buffer
);
605 *item
->quick_widget
->u
.radio
.value
= RADIO (item
->widget
)->sel
;
615 g_list_free_full (input_labels
, g_free
); /* destroy input labels created before */
616 g_array_free (widgets
, TRUE
);
621 /* --------------------------------------------------------------------------------------------- */