e01d05c30c4faa6af18adb2c249a0211584786ba
[midnight-commander.git] / lib / widget / wtools.c
blobe01d05c30c4faa6af18adb2c249a0211584786ba
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, 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 wtools.c
32 * \brief Source: widget based utility functions
35 #include <config.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
40 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/tty/key.h" /* tty_getch() */
43 #include "lib/strutil.h"
44 #include "lib/util.h" /* tilde_expand() */
45 #include "lib/widget.h"
46 #include "lib/event.h" /* mc_event_raise() */
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** file scope variables ************************************************************************/
56 static WDialog *last_query_dlg;
58 static int sel_pos = 0;
60 /*** file scope functions ************************************************************************/
61 /* --------------------------------------------------------------------------------------------- */
63 /** default query callback, used to reposition query */
65 static cb_ret_t
66 query_default_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
68 WDialog *h = DIALOG (w);
70 switch (msg)
72 case MSG_RESIZE:
73 if ((h->flags & DLG_CENTER) == 0)
75 WDialog *prev_dlg = NULL;
76 int ypos, xpos;
78 /* get dialog under h */
79 if (top_dlg != NULL)
81 if (top_dlg->data != (void *) h)
82 prev_dlg = DIALOG (top_dlg->data);
83 else
85 GList *p;
87 /* Top dialog is current if it is visible.
88 Get previous dialog in stack */
89 p = g_list_next (top_dlg);
90 if (p != NULL)
91 prev_dlg = DIALOG (p->data);
95 /* if previous dialog is not fullscreen'd -- overlap it */
96 if (prev_dlg == NULL || prev_dlg->fullscreen)
97 ypos = LINES / 3 - (w->lines - 3) / 2;
98 else
99 ypos = WIDGET (prev_dlg)->y + 2;
101 xpos = COLS / 2 - w->cols / 2;
103 /* set position */
104 dlg_set_position (h, ypos, xpos, ypos + w->lines, xpos + w->cols);
106 return MSG_HANDLED;
108 /* fallthrough */
110 default:
111 return dlg_default_callback (w, sender, msg, parm, data);
115 /* --------------------------------------------------------------------------------------------- */
116 /** Create message dialog */
118 static struct WDialog *
119 do_create_message (int flags, const char *title, const char *text)
121 char *p;
122 WDialog *d;
124 /* Add empty lines before and after the message */
125 p = g_strconcat ("\n", text, "\n", (char *) NULL);
126 query_dialog (title, p, flags, 0);
127 d = last_query_dlg;
129 /* do resize before initing and running */
130 send_message (d, NULL, MSG_RESIZE, 0, NULL);
132 init_dlg (d);
133 g_free (p);
135 return d;
138 /* --------------------------------------------------------------------------------------------- */
140 * Show message dialog. Dismiss it when any key is pressed.
141 * Not safe to call from background.
144 static void
145 fg_message (int flags, const char *title, const char *text)
147 WDialog *d;
149 d = do_create_message (flags, title, text);
150 tty_getch ();
151 dlg_run_done (d);
152 destroy_dlg (d);
156 /* --------------------------------------------------------------------------------------------- */
157 /** Show message box from background */
159 #ifdef ENABLE_BACKGROUND
160 static void
161 bg_message (int dummy, int *flags, char *title, const char *text)
163 (void) dummy;
164 title = g_strconcat (_("Background process:"), " ", title, (char *) NULL);
165 fg_message (*flags, title, text);
166 g_free (title);
168 #endif /* ENABLE_BACKGROUND */
170 /* --------------------------------------------------------------------------------------------- */
173 * Show dialog, not background safe.
175 * If the arguments "header" and "text" should be translated,
176 * that MUST be done by the caller of fg_input_dialog_help().
178 * The argument "history_name" holds the name of a section
179 * in the history file. Data entered in the input field of
180 * the dialog box will be stored there.
183 static char *
184 fg_input_dialog_help (const char *header, const char *text, const char *help,
185 const char *history_name, const char *def_text, gboolean strip_password)
187 char *p_text;
188 char histname[64] = "inp|";
189 int flags = strip_password ? 4 : 0;
190 char *my_str;
191 int ret;
193 /* label text */
194 p_text = g_strstrip (g_strdup (text));
196 /* input history */
197 if (history_name != NULL && *history_name != '\0')
198 g_strlcpy (histname + 3, history_name, sizeof (histname) - 3);
200 /* The special value of def_text is used to identify password boxes
201 and hide characters with "*". Don't save passwords in history! */
202 if (def_text == INPUT_PASSWORD)
204 flags = 1;
205 histname[3] = '\0';
206 def_text = "";
210 quick_widget_t quick_widgets[] = {
211 /* *INDENT-OFF* */
212 QUICK_LABELED_INPUT (p_text, input_label_above, def_text, flags, histname, &my_str,
213 NULL),
214 QUICK_BUTTONS_OK_CANCEL,
215 QUICK_END
216 /* *INDENT-ON* */
219 quick_dialog_t qdlg = {
220 -1, -1, COLS / 2, header,
221 help, quick_widgets, NULL, NULL
224 ret = quick_dialog (&qdlg);
227 g_free (p_text);
229 return (ret != B_CANCEL) ? my_str : NULL;
232 /* --------------------------------------------------------------------------------------------- */
234 #ifdef ENABLE_BACKGROUND
235 static int
236 wtools_parent_call (void *routine, gpointer ctx, int argc, ...)
238 ev_background_parent_call_t event_data;
240 event_data.routine = routine;
241 event_data.ctx = ctx;
242 event_data.argc = argc;
243 va_start (event_data.ap, argc);
244 mc_event_raise (MCEVENT_GROUP_CORE, "background_parent_call", (gpointer) & event_data);
245 va_end (event_data.ap);
246 return event_data.ret.i;
249 /* --------------------------------------------------------------------------------------------- */
251 static char *
252 wtools_parent_call_string (void *routine, int argc, ...)
254 ev_background_parent_call_t event_data;
256 event_data.routine = routine;
257 event_data.argc = argc;
258 va_start (event_data.ap, argc);
259 mc_event_raise (MCEVENT_GROUP_CORE, "background_parent_call_string", (gpointer) & event_data);
260 va_end (event_data.ap);
261 return event_data.ret.s;
263 #endif /* ENABLE_BACKGROUND */
265 /* --------------------------------------------------------------------------------------------- */
266 /*** public functions ****************************************************************************/
267 /* --------------------------------------------------------------------------------------------- */
269 /** Used to ask questions to the user */
271 query_dialog (const char *header, const char *text, int flags, int count, ...)
273 va_list ap;
274 WDialog *query_dlg;
275 WButton *button;
276 WButton *defbutton = NULL;
277 int win_len = 0;
278 int i;
279 int result = -1;
280 int cols, lines;
281 char *cur_name;
282 const int *query_colors = (flags & D_ERROR) != 0 ? alarm_colors : dialog_colors;
283 dlg_flags_t dlg_flags = (flags & D_CENTER) != 0 ? (DLG_CENTER | DLG_TRYUP) : DLG_NONE;
285 if (header == MSG_ERROR)
286 header = _("Error");
288 if (count > 0)
290 va_start (ap, count);
291 for (i = 0; i < count; i++)
293 char *cp = va_arg (ap, char *);
294 win_len += str_term_width1 (cp) + 6;
295 if (strchr (cp, '&') != NULL)
296 win_len--;
298 va_end (ap);
301 /* count coordinates */
302 str_msg_term_size (text, &lines, &cols);
303 cols = 6 + max (win_len, max (str_term_width1 (header), cols));
304 lines += 4 + (count > 0 ? 2 : 0);
306 /* prepare dialog */
307 query_dlg =
308 create_dlg (TRUE, 0, 0, lines, cols, query_colors, query_default_callback, NULL,
309 "[QueryBox]", header, dlg_flags);
311 if (count > 0)
313 add_widget_autopos (query_dlg, label_new (2, 3, text), WPOS_KEEP_TOP | WPOS_CENTER_HORZ,
314 NULL);
316 add_widget (query_dlg, hline_new (lines - 4, -1, -1));
318 cols = (cols - win_len - 2) / 2 + 2;
319 va_start (ap, count);
320 for (i = 0; i < count; i++)
322 int xpos;
324 cur_name = va_arg (ap, char *);
325 xpos = str_term_width1 (cur_name) + 6;
326 if (strchr (cur_name, '&') != NULL)
327 xpos--;
329 button = button_new (lines - 3, cols, B_USER + i, NORMAL_BUTTON, cur_name, NULL);
330 add_widget (query_dlg, button);
331 cols += xpos;
332 if (i == sel_pos)
333 defbutton = button;
335 va_end (ap);
337 /* do resize before running and selecting any widget */
338 send_message (query_dlg, NULL, MSG_RESIZE, 0, NULL);
340 if (defbutton != NULL)
341 dlg_select_widget (defbutton);
343 /* run dialog and make result */
344 switch (run_dlg (query_dlg))
346 case B_CANCEL:
347 break;
348 default:
349 result = query_dlg->ret_value - B_USER;
352 /* free used memory */
353 destroy_dlg (query_dlg);
355 else
357 add_widget_autopos (query_dlg, label_new (2, 3, text), WPOS_KEEP_TOP | WPOS_CENTER_HORZ,
358 NULL);
359 add_widget (query_dlg, button_new (0, 0, 0, HIDDEN_BUTTON, "-", NULL));
360 last_query_dlg = query_dlg;
362 sel_pos = 0;
363 return result;
366 /* --------------------------------------------------------------------------------------------- */
368 void
369 query_set_sel (int new_sel)
371 sel_pos = new_sel;
374 /* --------------------------------------------------------------------------------------------- */
376 * Create message dialog. The caller must call dlg_run_done() and
377 * destroy_dlg() to dismiss it. Not safe to call from background.
380 struct WDialog *
381 create_message (int flags, const char *title, const char *text, ...)
383 va_list args;
384 WDialog *d;
385 char *p;
387 va_start (args, text);
388 p = g_strdup_vprintf (text, args);
389 va_end (args);
391 d = do_create_message (flags, title, p);
392 g_free (p);
394 return d;
397 /* --------------------------------------------------------------------------------------------- */
398 /** Show message box, background safe */
400 void
401 message (int flags, const char *title, const char *text, ...)
403 char *p;
404 va_list ap;
406 va_start (ap, text);
407 p = g_strdup_vprintf (text, ap);
408 va_end (ap);
410 if (title == MSG_ERROR)
411 title = _("Error");
413 #ifdef ENABLE_BACKGROUND
414 if (mc_global.we_are_background)
416 union
418 void *p;
419 void (*f) (int, int *, char *, const char *);
420 } func;
421 func.f = bg_message;
423 wtools_parent_call (func.p, NULL, 3, sizeof (flags), &flags, strlen (title), title,
424 strlen (p), p);
426 else
427 #endif /* ENABLE_BACKGROUND */
428 fg_message (flags, title, p);
430 g_free (p);
433 /* --------------------------------------------------------------------------------------------- */
435 * Show input dialog, background safe.
437 * If the arguments "header" and "text" should be translated,
438 * that MUST be done by the caller of these wrappers.
441 char *
442 input_dialog_help (const char *header, const char *text, const char *help,
443 const char *history_name, const char *def_text, gboolean strip_password)
445 #ifdef ENABLE_BACKGROUND
446 if (mc_global.we_are_background)
448 union
450 void *p;
451 char *(*f) (const char *, const char *, const char *, const char *, const char *,
452 gboolean);
453 } func;
454 func.f = fg_input_dialog_help;
455 return wtools_parent_call_string (func.p, 6,
456 strlen (header), header, strlen (text),
457 text, strlen (help), help,
458 strlen (history_name), history_name,
459 strlen (def_text), def_text,
460 sizeof (gboolean), strip_password);
462 else
463 #endif /* ENABLE_BACKGROUND */
464 return fg_input_dialog_help (header, text, help, history_name, def_text, strip_password);
467 /* --------------------------------------------------------------------------------------------- */
468 /** Show input dialog with default help, background safe */
470 char *
471 input_dialog (const char *header, const char *text, const char *history_name, const char *def_text)
473 return input_dialog_help (header, text, "[Input Line Keys]", history_name, def_text, FALSE);
476 /* --------------------------------------------------------------------------------------------- */
478 char *
479 input_expand_dialog (const char *header, const char *text,
480 const char *history_name, const char *def_text)
482 char *result;
483 char *expanded;
485 result = input_dialog (header, text, history_name, def_text);
486 if (result)
488 expanded = tilde_expand (result);
489 g_free (result);
490 return expanded;
492 return result;
495 /* --------------------------------------------------------------------------------------------- */