root/lib/widget/wtools.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. query_default_callback
  2. do_create_message
  3. fg_message
  4. bg_message
  5. fg_input_dialog_help
  6. wtools_parent_call
  7. wtools_parent_call_string
  8. query_dialog
  9. query_set_sel
  10. create_message
  11. message
  12. mc_error_message
  13. input_dialog_help
  14. input_dialog
  15. input_expand_dialog
  16. status_msg_create
  17. status_msg_destroy
  18. status_msg_init
  19. status_msg_deinit
  20. status_msg_common_update
  21. simple_status_msg_init_cb

   1 /*
   2    Widget based utility functions.
   3 
   4    Copyright (C) 1994-2019
   5    Free Software Foundation, Inc.
   6 
   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-2014
  13 
  14    This file is part of the Midnight Commander.
  15 
  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.
  20 
  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.
  25 
  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/>.
  28  */
  29 
  30 /** \file wtools.c
  31  *  \brief Source: widget based utility functions
  32  */
  33 
  34 #include <config.h>
  35 
  36 #include <stdarg.h>
  37 #include <stdlib.h>
  38 
  39 #include "lib/global.h"
  40 #include "lib/tty/tty.h"
  41 #include "lib/tty/key.h"        /* tty_getch() */
  42 #include "lib/strutil.h"
  43 #include "lib/util.h"           /* tilde_expand() */
  44 #include "lib/widget.h"
  45 #include "lib/event.h"          /* mc_event_raise() */
  46 
  47 /*** global variables ****************************************************************************/
  48 
  49 /*** file scope macro definitions ****************************************************************/
  50 
  51 /*** file scope type declarations ****************************************************************/
  52 
  53 /*** file scope variables ************************************************************************/
  54 
  55 static WDialog *last_query_dlg;
  56 
  57 static int sel_pos = 0;
  58 
  59 /* --------------------------------------------------------------------------------------------- */
  60 /*** file scope functions ************************************************************************/
  61 /* --------------------------------------------------------------------------------------------- */
  62 
  63 /** default query callback, used to reposition query */
  64 
  65 static cb_ret_t
  66 query_default_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
  67 {
  68     WDialog *h = DIALOG (w);
  69 
  70     switch (msg)
  71     {
  72     case MSG_RESIZE:
  73         if ((w->pos_flags & WPOS_CENTER) == 0)
  74         {
  75             WDialog *prev_dlg = NULL;
  76             int ypos, xpos;
  77 
  78             /* get dialog under h */
  79             if (top_dlg != NULL)
  80             {
  81                 if (top_dlg->data != (void *) h)
  82                     prev_dlg = DIALOG (top_dlg->data);
  83                 else
  84                 {
  85                     GList *p;
  86 
  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);
  92                 }
  93             }
  94 
  95             /* if previous dialog is not fullscreen'd -- overlap it */
  96             if (prev_dlg == NULL || (WIDGET (prev_dlg)->pos_flags & WPOS_FULLSCREEN) != 0)
  97                 ypos = LINES / 3 - (w->lines - 3) / 2;
  98             else
  99                 ypos = WIDGET (prev_dlg)->y + 2;
 100 
 101             xpos = COLS / 2 - w->cols / 2;
 102 
 103             /* set position */
 104             dlg_set_position (h, ypos, xpos, w->lines, w->cols);
 105 
 106             return MSG_HANDLED;
 107         }
 108         MC_FALLTHROUGH;
 109 
 110     default:
 111         return dlg_default_callback (w, sender, msg, parm, data);
 112     }
 113 }
 114 
 115 /* --------------------------------------------------------------------------------------------- */
 116 /** Create message dialog */
 117 
 118 static WDialog *
 119 do_create_message (int flags, const char *title, const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 120 {
 121     char *p;
 122     WDialog *d;
 123 
 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;
 128 
 129     /* do resize before initing and running */
 130     send_message (d, NULL, MSG_RESIZE, 0, NULL);
 131 
 132     dlg_init (d);
 133     g_free (p);
 134 
 135     return d;
 136 }
 137 
 138 /* --------------------------------------------------------------------------------------------- */
 139 /**
 140  * Show message dialog.  Dismiss it when any key is pressed.
 141  * Not safe to call from background.
 142  */
 143 
 144 static void
 145 fg_message (int flags, const char *title, const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 146 {
 147     WDialog *d;
 148 
 149     d = do_create_message (flags, title, text);
 150     tty_getch ();
 151     dlg_run_done (d);
 152     dlg_destroy (d);
 153 }
 154 
 155 
 156 /* --------------------------------------------------------------------------------------------- */
 157 /** Show message box from background */
 158 
 159 #ifdef ENABLE_BACKGROUND
 160 static void
 161 bg_message (int dummy, int *flags, char *title, const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 162 {
 163     (void) dummy;
 164     title = g_strconcat (_("Background process:"), " ", title, (char *) NULL);
 165     fg_message (*flags, title, text);
 166     g_free (title);
 167 }
 168 #endif /* ENABLE_BACKGROUND */
 169 
 170 /* --------------------------------------------------------------------------------------------- */
 171 
 172 /**
 173  * Show dialog, not background safe.
 174  *
 175  * If the arguments "header" and "text" should be translated,
 176  * that MUST be done by the caller of fg_input_dialog_help().
 177  *
 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.
 181  *
 182  */
 183 static char *
 184 fg_input_dialog_help (const char *header, const char *text, const char *help,
     /* [previous][next][first][last][top][bottom][index][help]  */
 185                       const char *history_name, const char *def_text, gboolean strip_password,
 186                       input_complete_t completion_flags)
 187 {
 188     char *p_text;
 189     char histname[64] = "inp|";
 190     gboolean is_passwd = FALSE;
 191     char *my_str;
 192     int ret;
 193 
 194     /* label text */
 195     p_text = g_strstrip (g_strdup (text));
 196 
 197     /* input history */
 198     if (history_name != NULL && *history_name != '\0')
 199         g_strlcpy (histname + 3, history_name, sizeof (histname) - 3);
 200 
 201     /* The special value of def_text is used to identify password boxes
 202        and hide characters with "*".  Don't save passwords in history! */
 203     if (def_text == INPUT_PASSWORD)
 204     {
 205         is_passwd = TRUE;
 206         histname[3] = '\0';
 207         def_text = "";
 208     }
 209 
 210     {
 211         quick_widget_t quick_widgets[] = {
 212             /* *INDENT-OFF* */
 213             QUICK_LABELED_INPUT (p_text, input_label_above, def_text, histname, &my_str,
 214                                  NULL, is_passwd, strip_password, completion_flags),
 215             QUICK_BUTTONS_OK_CANCEL,
 216             QUICK_END
 217             /* *INDENT-ON* */
 218         };
 219 
 220         quick_dialog_t qdlg = {
 221             -1, -1, COLS / 2, header,
 222             help, quick_widgets, NULL, NULL
 223         };
 224 
 225         ret = quick_dialog (&qdlg);
 226     }
 227 
 228     g_free (p_text);
 229 
 230     return (ret != B_CANCEL) ? my_str : NULL;
 231 }
 232 
 233 /* --------------------------------------------------------------------------------------------- */
 234 
 235 #ifdef ENABLE_BACKGROUND
 236 static int
 237 wtools_parent_call (void *routine, gpointer ctx, int argc, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 238 {
 239     ev_background_parent_call_t event_data;
 240 
 241     event_data.routine = routine;
 242     event_data.ctx = ctx;
 243     event_data.argc = argc;
 244     va_start (event_data.ap, argc);
 245     mc_event_raise (MCEVENT_GROUP_CORE, "background_parent_call", (gpointer) & event_data);
 246     va_end (event_data.ap);
 247     return event_data.ret.i;
 248 }
 249 
 250 /* --------------------------------------------------------------------------------------------- */
 251 
 252 static char *
 253 wtools_parent_call_string (void *routine, int argc, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 254 {
 255     ev_background_parent_call_t event_data;
 256 
 257     event_data.routine = routine;
 258     event_data.argc = argc;
 259     va_start (event_data.ap, argc);
 260     mc_event_raise (MCEVENT_GROUP_CORE, "background_parent_call_string", (gpointer) & event_data);
 261     va_end (event_data.ap);
 262     return event_data.ret.s;
 263 }
 264 #endif /* ENABLE_BACKGROUND */
 265 
 266 /* --------------------------------------------------------------------------------------------- */
 267 /*** public functions ****************************************************************************/
 268 /* --------------------------------------------------------------------------------------------- */
 269 
 270 /** Used to ask questions to the user */
 271 int
 272 query_dialog (const char *header, const char *text, int flags, int count, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 273 {
 274     va_list ap;
 275     WDialog *query_dlg;
 276     WButton *button;
 277     int win_len = 0;
 278     int i;
 279     int result = -1;
 280     int cols, lines;
 281     const int *query_colors = (flags & D_ERROR) != 0 ? alarm_colors : dialog_colors;
 282     widget_pos_flags_t pos_flags =
 283         (flags & D_CENTER) != 0 ? (WPOS_CENTER | WPOS_TRYUP) : WPOS_KEEP_DEFAULT;
 284 
 285     if (header == MSG_ERROR)
 286         header = _("Error");
 287 
 288     if (count > 0)
 289     {
 290         va_start (ap, count);
 291         for (i = 0; i < count; i++)
 292         {
 293             char *cp = va_arg (ap, char *);
 294             win_len += str_term_width1 (cp) + 6;
 295             if (strchr (cp, '&') != NULL)
 296                 win_len--;
 297         }
 298         va_end (ap);
 299     }
 300 
 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);
 305 
 306     /* prepare dialog */
 307     query_dlg =
 308         dlg_create (TRUE, 0, 0, lines, cols, pos_flags, FALSE, query_colors, query_default_callback,
 309                     NULL, "[QueryBox]", header);
 310 
 311     if (count > 0)
 312     {
 313         WButton *defbutton = NULL;
 314 
 315         add_widget_autopos (query_dlg, label_new (2, 3, text), WPOS_KEEP_TOP | WPOS_CENTER_HORZ,
 316                             NULL);
 317         add_widget (query_dlg, hline_new (lines - 4, -1, -1));
 318 
 319         cols = (cols - win_len - 2) / 2 + 2;
 320         va_start (ap, count);
 321         for (i = 0; i < count; i++)
 322         {
 323             int xpos;
 324             char *cur_name;
 325 
 326             cur_name = va_arg (ap, char *);
 327             xpos = str_term_width1 (cur_name) + 6;
 328             if (strchr (cur_name, '&') != NULL)
 329                 xpos--;
 330 
 331             button = button_new (lines - 3, cols, B_USER + i, NORMAL_BUTTON, cur_name, NULL);
 332             add_widget (query_dlg, button);
 333             cols += xpos;
 334             if (i == sel_pos)
 335                 defbutton = button;
 336         }
 337         va_end (ap);
 338 
 339         /* do resize before running and selecting any widget */
 340         send_message (query_dlg, NULL, MSG_RESIZE, 0, NULL);
 341 
 342         if (defbutton != NULL)
 343             widget_select (WIDGET (defbutton));
 344 
 345         /* run dialog and make result */
 346         switch (dlg_run (query_dlg))
 347         {
 348         case B_CANCEL:
 349             break;
 350         default:
 351             result = query_dlg->ret_value - B_USER;
 352         }
 353 
 354         /* free used memory */
 355         dlg_destroy (query_dlg);
 356     }
 357     else
 358     {
 359         add_widget_autopos (query_dlg, label_new (2, 3, text), WPOS_KEEP_TOP | WPOS_CENTER_HORZ,
 360                             NULL);
 361         add_widget (query_dlg, button_new (0, 0, 0, HIDDEN_BUTTON, "-", NULL));
 362         last_query_dlg = query_dlg;
 363     }
 364     sel_pos = 0;
 365     return result;
 366 }
 367 
 368 /* --------------------------------------------------------------------------------------------- */
 369 
 370 void
 371 query_set_sel (int new_sel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 372 {
 373     sel_pos = new_sel;
 374 }
 375 
 376 /* --------------------------------------------------------------------------------------------- */
 377 /**
 378  * Create message dialog.  The caller must call dlg_run_done() and
 379  * dlg_destroy() to dismiss it.  Not safe to call from background.
 380  */
 381 
 382 WDialog *
 383 create_message (int flags, const char *title, const char *text, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 384 {
 385     va_list args;
 386     WDialog *d;
 387     char *p;
 388 
 389     va_start (args, text);
 390     p = g_strdup_vprintf (text, args);
 391     va_end (args);
 392 
 393     d = do_create_message (flags, title, p);
 394     g_free (p);
 395 
 396     return d;
 397 }
 398 
 399 /* --------------------------------------------------------------------------------------------- */
 400 /** Show message box, background safe */
 401 
 402 void
 403 message (int flags, const char *title, const char *text, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 404 {
 405     char *p;
 406     va_list ap;
 407 
 408     va_start (ap, text);
 409     p = g_strdup_vprintf (text, ap);
 410     va_end (ap);
 411 
 412     if (title == MSG_ERROR)
 413         title = _("Error");
 414 
 415 #ifdef ENABLE_BACKGROUND
 416     if (mc_global.we_are_background)
 417     {
 418         union
 419         {
 420             void *p;
 421             void (*f) (int, int *, char *, const char *);
 422         } func;
 423         func.f = bg_message;
 424 
 425         wtools_parent_call (func.p, NULL, 3, sizeof (flags), &flags, strlen (title), title,
 426                             strlen (p), p);
 427     }
 428     else
 429 #endif /* ENABLE_BACKGROUND */
 430         fg_message (flags, title, p);
 431 
 432     g_free (p);
 433 }
 434 
 435 /* --------------------------------------------------------------------------------------------- */
 436 /** Show error message box */
 437 
 438 gboolean
 439 mc_error_message (GError ** mcerror, int *code)
     /* [previous][next][first][last][top][bottom][index][help]  */
 440 {
 441     if (mcerror == NULL || *mcerror == NULL)
 442         return FALSE;
 443 
 444     if ((*mcerror)->code == 0)
 445         message (D_ERROR, MSG_ERROR, "%s", (*mcerror)->message);
 446     else
 447         message (D_ERROR, MSG_ERROR, _("%s (%d)"), (*mcerror)->message, (*mcerror)->code);
 448 
 449     if (code != NULL)
 450         *code = (*mcerror)->code;
 451 
 452     g_error_free (*mcerror);
 453     *mcerror = NULL;
 454 
 455     return TRUE;
 456 }
 457 
 458 /* --------------------------------------------------------------------------------------------- */
 459 /**
 460  * Show input dialog, background safe.
 461  *
 462  * If the arguments "header" and "text" should be translated,
 463  * that MUST be done by the caller of these wrappers.
 464  */
 465 
 466 char *
 467 input_dialog_help (const char *header, const char *text, const char *help,
     /* [previous][next][first][last][top][bottom][index][help]  */
 468                    const char *history_name, const char *def_text, gboolean strip_password,
 469                    input_complete_t completion_flags)
 470 {
 471 #ifdef ENABLE_BACKGROUND
 472     if (mc_global.we_are_background)
 473     {
 474         union
 475         {
 476             void *p;
 477             char *(*f) (const char *, const char *, const char *, const char *, const char *,
 478                         gboolean, input_complete_t);
 479         } func;
 480         func.f = fg_input_dialog_help;
 481         return wtools_parent_call_string (func.p, 7,
 482                                           strlen (header), header, strlen (text),
 483                                           text, strlen (help), help,
 484                                           strlen (history_name), history_name,
 485                                           strlen (def_text), def_text,
 486                                           sizeof (gboolean), strip_password,
 487                                           sizeof (input_complete_t), completion_flags);
 488     }
 489     else
 490 #endif /* ENABLE_BACKGROUND */
 491         return fg_input_dialog_help (header, text, help, history_name, def_text, strip_password,
 492                                      completion_flags);
 493 }
 494 
 495 /* --------------------------------------------------------------------------------------------- */
 496 /** Show input dialog with default help, background safe */
 497 
 498 char *
 499 input_dialog (const char *header, const char *text, const char *history_name, const char *def_text,
     /* [previous][next][first][last][top][bottom][index][help]  */
 500               input_complete_t completion_flags)
 501 {
 502     return input_dialog_help (header, text, "[Input Line Keys]", history_name, def_text, FALSE,
 503                               completion_flags);
 504 }
 505 
 506 /* --------------------------------------------------------------------------------------------- */
 507 
 508 char *
 509 input_expand_dialog (const char *header, const char *text,
     /* [previous][next][first][last][top][bottom][index][help]  */
 510                      const char *history_name, const char *def_text,
 511                      input_complete_t completion_flags)
 512 {
 513     char *result;
 514 
 515     result = input_dialog (header, text, history_name, def_text, completion_flags);
 516     if (result)
 517     {
 518         char *expanded;
 519 
 520         expanded = tilde_expand (result);
 521         g_free (result);
 522         return expanded;
 523     }
 524     return result;
 525 }
 526 
 527 /* --------------------------------------------------------------------------------------------- */
 528 /**
 529  * Create status message window object and initialize it
 530  *
 531  * @param title window title
 532  * @param delay initial delay to raise window in seconds
 533  * @param init_cb callback to initialize user-defined part of status message
 534  * @param update_cb callback to update of status message
 535  * @param deinit_cb callback to deinitialize user-defined part of status message
 536  *
 537  * @return newly allocate status message window
 538  */
 539 
 540 status_msg_t *
 541 status_msg_create (const char *title, double delay, status_msg_cb init_cb,
     /* [previous][next][first][last][top][bottom][index][help]  */
 542                    status_msg_update_cb update_cb, status_msg_cb deinit_cb)
 543 {
 544     status_msg_t *sm;
 545 
 546     sm = g_try_new (status_msg_t, 1);
 547     status_msg_init (sm, title, delay, init_cb, update_cb, deinit_cb);
 548 
 549     return sm;
 550 }
 551 
 552 /* --------------------------------------------------------------------------------------------- */
 553 /**
 554  * Destroy status message window object
 555  *
 556  * @param sm status message window object
 557  */
 558 
 559 void
 560 status_msg_destroy (status_msg_t * sm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 561 {
 562     status_msg_deinit (sm);
 563     g_free (sm);
 564 }
 565 
 566 /* --------------------------------------------------------------------------------------------- */
 567 /**
 568  * Initialize already created status message window object
 569  *
 570  * @param sm status message window object
 571  * @param title window title
 572  * @param delay initial delay to raise window in seconds
 573  * @param init_cb callback to initialize user-defined part of status message
 574  * @param update_cb callback to update of status message
 575  * @param deinit_cb callback to deinitialize user-defined part of status message
 576  */
 577 
 578 void
 579 status_msg_init (status_msg_t * sm, const char *title, double delay, status_msg_cb init_cb,
     /* [previous][next][first][last][top][bottom][index][help]  */
 580                  status_msg_update_cb update_cb, status_msg_cb deinit_cb)
 581 {
 582     guint64 start;
 583 
 584     /* repaint screen to remove previous finished dialog */
 585     mc_refresh ();
 586 
 587     start = mc_timer_elapsed (mc_global.timer);
 588 
 589     sm->dlg = dlg_create (TRUE, 0, 0, 7, MIN (MAX (40, COLS / 2), COLS), WPOS_CENTER, FALSE,
 590                           dialog_colors, NULL, NULL, NULL, title);
 591     sm->start = start;
 592     sm->delay = (guint64) (delay * G_USEC_PER_SEC);
 593     sm->block = FALSE;
 594 
 595     sm->init = init_cb;
 596     sm->update = update_cb;
 597     sm->deinit = deinit_cb;
 598 
 599     if (sm->init != NULL)
 600         sm->init (sm);
 601 
 602     if (mc_time_elapsed (&start, sm->delay))
 603     {
 604         /* We will manage the dialog without any help, that's why we have to call dlg_init */
 605         dlg_init (sm->dlg);
 606     }
 607 }
 608 
 609 /* --------------------------------------------------------------------------------------------- */
 610 /**
 611  * Deinitialize status message window object
 612  *
 613  * @param sm status message window object
 614  */
 615 
 616 void
 617 status_msg_deinit (status_msg_t * sm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 618 {
 619     if (sm == NULL)
 620         return;
 621 
 622     if (sm->deinit != NULL)
 623         sm->deinit (sm);
 624 
 625     /* close and destroy dialog */
 626     dlg_run_done (sm->dlg);
 627     dlg_destroy (sm->dlg);
 628 }
 629 
 630 /* --------------------------------------------------------------------------------------------- */
 631 /**
 632  * Update status message window
 633  *
 634  * @param sm status message window object
 635  *
 636  * @return value of pressed key
 637  */
 638 
 639 int
 640 status_msg_common_update (status_msg_t * sm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 641 {
 642     int c;
 643     Gpm_Event event;
 644 
 645     if (sm == NULL)
 646         return B_ENTER;
 647 
 648     /* This should not happen, but... */
 649     if (sm->dlg == NULL)
 650         return B_ENTER;
 651 
 652     if (widget_get_state (WIDGET (sm->dlg), WST_CONSTRUCT))
 653     {
 654         /* dialog is not shown yet */
 655 
 656         /* do not change sm->start */
 657         guint64 start = sm->start;
 658 
 659         if (mc_time_elapsed (&start, sm->delay))
 660             dlg_init (sm->dlg);
 661 
 662         return B_ENTER;
 663     }
 664 
 665     event.x = -1;               /* Don't show the GPM cursor */
 666     c = tty_get_event (&event, FALSE, sm->block);
 667     if (c == EV_NONE)
 668         return B_ENTER;
 669 
 670     /* Reinitialize by non-B_CANCEL value to avoid old values
 671        after events other than selecting a button */
 672     sm->dlg->ret_value = B_ENTER;
 673     dlg_process_event (sm->dlg, c, &event);
 674 
 675     return sm->dlg->ret_value;
 676 }
 677 
 678 /* --------------------------------------------------------------------------------------------- */
 679 /**
 680  * Callback to initialize already created simple status message window object
 681  *
 682  * @param sm status message window object
 683  */
 684 
 685 void
 686 simple_status_msg_init_cb (status_msg_t * sm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 687 {
 688     simple_status_msg_t *ssm = SIMPLE_STATUS_MSG (sm);
 689     Widget *wd = WIDGET (sm->dlg);
 690 
 691     const char *b_name = N_("&Abort");
 692     int b_width;
 693     int wd_width, y;
 694     Widget *b;
 695 
 696 #ifdef ENABLE_NLS
 697     b_name = _(b_name);
 698 #endif
 699 
 700     b_width = str_term_width1 (b_name) + 4;
 701     wd_width = MAX (wd->cols, b_width + 6);
 702 
 703     y = 2;
 704     ssm->label = label_new (y++, 3, "");
 705     add_widget_autopos (sm->dlg, ssm->label, WPOS_KEEP_TOP | WPOS_CENTER_HORZ, NULL);
 706     add_widget (sm->dlg, hline_new (y++, -1, -1));
 707     b = WIDGET (button_new (y++, 3, B_CANCEL, NORMAL_BUTTON, b_name, NULL));
 708     add_widget_autopos (sm->dlg, b, WPOS_KEEP_TOP | WPOS_CENTER_HORZ, NULL);
 709 
 710     widget_set_size (wd, wd->y, wd->x, y + 2, wd_width);
 711 }
 712 
 713 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */