root/lib/widget/quick.c

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

DEFINITIONS

This source file includes following definitions.
  1. quick_create_input
  2. quick_create_labeled_input
  3. quick_dialog_skip

   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, 2010, 2011, 2012, 2013
  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 quick.c
  31  *  \brief Source: quick dialog engine
  32  */
  33 
  34 #include <config.h>
  35 
  36 #include <stdlib.h>
  37 #include <stdio.h>              /* fprintf() */
  38 
  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"
  43 
  44 /*** global variables ****************************************************************************/
  45 
  46 /*** file scope macro definitions ****************************************************************/
  47 
  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
  53 
  54 /*** file scope type declarations ****************************************************************/
  55 
  56 typedef struct
  57 {
  58     Widget *widget;
  59     quick_widget_t *quick_widget;
  60 } quick_widget_item_t;
  61 
  62 /*** file scope variables ************************************************************************/
  63 
  64 /* --------------------------------------------------------------------------------------------- */
  65 /*** file scope functions ************************************************************************/
  66 /* --------------------------------------------------------------------------------------------- */
  67 
  68 static WInput *
  69 quick_create_input (int y, int x, const quick_widget_t * qw)
     /* [previous][next][first][last][top][bottom][index][help]  */
  70 {
  71     WInput *in;
  72 
  73     in = input_new (y, x, input_colors, 8, qw->u.input.text, qw->u.input.histname,
  74                     qw->u.input.completion_flags);
  75 
  76     in->is_password = qw->u.input.is_passwd;
  77     in->strip_password = qw->u.input.strip_passwd;
  78 
  79     return in;
  80 }
  81 
  82 /* --------------------------------------------------------------------------------------------- */
  83 
  84 static void
  85 quick_create_labeled_input (GArray * widgets, int *y, int x, quick_widget_t * quick_widget,
     /* [previous][next][first][last][top][bottom][index][help]  */
  86                             int *width)
  87 {
  88     quick_widget_item_t in, label;
  89 
  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;
  96 
  97     switch (quick_widget->u.input.label_location)
  98     {
  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);
 103 
 104         in.widget = WIDGET (quick_create_input (++(*y), x, quick_widget));
 105         in.quick_widget = quick_widget;
 106         g_array_append_val (widgets, in);
 107 
 108         *width = MAX (label.widget->cols, in.widget->cols);
 109         break;
 110 
 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);
 114 
 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);
 118 
 119         *width = label.widget->cols + in.widget->cols + 1;
 120         break;
 121 
 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);
 126 
 127         label.widget =
 128             WIDGET (label_new
 129                     (*y, x + in.widget->cols + 1, I18N (quick_widget->u.input.label_text)));
 130         g_array_append_val (widgets, label);
 131 
 132         *width = label.widget->cols + in.widget->cols + 1;
 133         break;
 134 
 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);
 139 
 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);
 143 
 144         *width = MAX (label.widget->cols, in.widget->cols);
 145         break;
 146 
 147     default:
 148         return;
 149     }
 150 
 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;
 155 }
 156 
 157 /* --------------------------------------------------------------------------------------------- */
 158 /*** public functions ****************************************************************************/
 159 /* --------------------------------------------------------------------------------------------- */
 160 
 161 int
 162 quick_dialog_skip (quick_dialog_t * quick_dlg, int nskip)
     /* [previous][next][first][last][top][bottom][index][help]  */
 163 {
 164     int len;
 165     int blen = 0;
 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;
 174 
 175     /* x position of 1st column is 3 */
 176     const int x1 = 3;
 177     /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */
 178     int x2 = 4;
 179 
 180     GArray *widgets;
 181     size_t i;
 182     quick_widget_t *quick_widget;
 183     WGroupbox *g = NULL;
 184     WDialog *dd;
 185     GList *input_labels = NULL; /* Widgets not directly requested by the user. */
 186     int return_val;
 187 
 188     len = str_term_width1 (I18N (quick_dlg->title)) + 6;
 189     quick_dlg->cols = MAX (quick_dlg->cols, len);
 190 
 191     y = 1;
 192     x = x1;
 193 
 194     /* create widgets */
 195     widgets = g_array_sized_new (FALSE, FALSE, sizeof (quick_widget_item_t), 8);
 196 
 197     for (quick_widget = quick_dlg->widgets; quick_widget->widget_type != quick_end; quick_widget++)
 198     {
 199         quick_widget_item_t item = { NULL, quick_widget };
 200         int width = 0;
 201 
 202         switch (quick_widget->widget_type)
 203         {
 204         case quick_checkbox:
 205             item.widget =
 206                 WIDGET (check_new
 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;
 211             if (g != NULL)
 212                 width += 2;
 213             if (two_columns)
 214                 width2 = MAX (width2, width);
 215             else
 216                 width1 = MAX (width1, width);
 217             break;
 218 
 219         case quick_button:
 220             /* single button */
 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;
 228             if (g != NULL)
 229                 width += 2;
 230             if (two_columns)
 231                 width2 = MAX (width2, width);
 232             else
 233                 width1 = MAX (width1, width);
 234             break;
 235 
 236         case quick_input:
 237             *quick_widget->u.input.result = NULL;
 238             y++;
 239             if (quick_widget->u.input.label_location != input_label_none)
 240             {
 241                 quick_create_labeled_input (widgets, &y, x, quick_widget, &width);
 242                 input_labels = g_list_prepend (input_labels, quick_widget->u.input.label);
 243             }
 244             else
 245             {
 246                 item.widget = WIDGET (quick_create_input (y, x, quick_widget));
 247                 g_array_append_val (widgets, item);
 248                 width = item.widget->cols;
 249             }
 250             if (g != NULL)
 251                 width += 2;
 252             if (two_columns)
 253                 width2 = MAX (width2, width);
 254             else
 255                 width1 = MAX (width1, width);
 256             break;
 257 
 258         case quick_label:
 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;
 263             if (g != NULL)
 264                 width += 2;
 265             if (two_columns)
 266                 width2 = MAX (width2, width);
 267             else
 268                 width1 = MAX (width1, width);
 269             break;
 270 
 271         case quick_radio:
 272             {
 273                 WRadio *r;
 274                 char **items = NULL;
 275 
 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]));
 280                 items[i] = NULL;
 281 
 282                 r = radio_new (++y, x, quick_widget->u.radio.count, (const char **) items);
 283                 r->pos = r->sel = *quick_widget->u.radio.value;
 284                 g_strfreev (items);
 285                 item.widget = WIDGET (r);
 286                 g_array_append_val (widgets, item);
 287                 y += item.widget->lines - 1;
 288                 width = item.widget->cols;
 289                 if (g != NULL)
 290                     width += 2;
 291                 if (two_columns)
 292                     width2 = MAX (width2, width);
 293                 else
 294                     width1 = MAX (width1, width);
 295             }
 296             break;
 297 
 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;
 305             break;
 306 
 307         case quick_stop_groupbox:
 308             if (g != NULL)
 309             {
 310                 Widget *w = WIDGET (g);
 311 
 312                 y++;
 313                 w->lines = y + 1 - w->y;
 314                 g = NULL;
 315 
 316                 g_array_append_val (widgets, item);
 317             }
 318             break;
 319 
 320         case quick_separator:
 321             y++;
 322             if (quick_widget->u.separator.line)
 323             {
 324                 item.widget = WIDGET (hline_new (y, x, 1));
 325                 g_array_append_val (widgets, item);
 326             }
 327             break;
 328 
 329         case quick_start_columns:
 330             y2 = y;
 331             g_array_append_val (widgets, item);
 332             two_columns = TRUE;
 333             break;
 334 
 335         case quick_next_column:
 336             x = x2;
 337             y1 = y;
 338             y = y2;
 339             break;
 340 
 341         case quick_stop_columns:
 342             x = x1;
 343             y = MAX (y1, y);
 344             g_array_append_val (widgets, item);
 345             two_columns = FALSE;
 346             break;
 347 
 348         case quick_buttons:
 349             /* start put several buttons in bottom line */
 350             if (quick_widget->u.separator.space)
 351             {
 352                 y++;
 353 
 354                 if (quick_widget->u.separator.line)
 355                     item.widget = WIDGET (hline_new (y, 1, -1));
 356             }
 357 
 358             g_array_append_val (widgets, item);
 359 
 360             /* several buttons in bottom line */
 361             y++;
 362             quick_widget++;
 363             for (; quick_widget->widget_type == quick_button; quick_widget++)
 364             {
 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;
 373             }
 374 
 375             /* stop dialog build here */
 376             blen--;
 377             quick_widget->widget_type = quick_end;
 378             quick_widget--;
 379             break;
 380 
 381         default:
 382             break;
 383         }
 384     }
 385 
 386     /* adjust dialog width */
 387     quick_dlg->cols = MAX (quick_dlg->cols, blen + 6);
 388     if (have_groupbox)
 389     {
 390         if (width1 != 0)
 391             width1 += 2;
 392         if (width2 != 0)
 393             width2 += 2;
 394     }
 395     if (width2 == 0)
 396         len = width1 + 6;
 397     else
 398     {
 399         len = width2 * 2 + 7;
 400         if (width1 != 0)
 401             len = MAX (len, width1 + 6);
 402     }
 403 
 404     quick_dlg->cols = MAX (quick_dlg->cols, len);
 405     width1 = quick_dlg->cols - 6;
 406     width2 = (quick_dlg->cols - 7) / 2;
 407 
 408     if (quick_dlg->x == -1 || quick_dlg->y == -1)
 409         dd = dlg_create (TRUE, 0, 0, y + 3, quick_dlg->cols, WPOS_CENTER | WPOS_TRYUP, FALSE,
 410                          dialog_colors, quick_dlg->callback, quick_dlg->mouse_callback,
 411                          quick_dlg->help, quick_dlg->title);
 412     else
 413         dd = dlg_create (TRUE, quick_dlg->y, quick_dlg->x, y + 3, quick_dlg->cols,
 414                          WPOS_KEEP_DEFAULT, FALSE, dialog_colors, quick_dlg->callback,
 415                          quick_dlg->mouse_callback, quick_dlg->help, quick_dlg->title);
 416 
 417     /* add widgets into the dialog */
 418     x2 = x1 + width2 + 1;
 419     g = NULL;
 420     two_columns = FALSE;
 421     x = (WIDGET (dd)->cols - blen) / 2;
 422 
 423     for (i = 0; i < widgets->len; i++)
 424     {
 425         quick_widget_item_t *item;
 426         int column_width;
 427 
 428         item = &g_array_index (widgets, quick_widget_item_t, i);
 429         column_width = two_columns ? width2 : width1;
 430 
 431         /* adjust widget width and x position */
 432         switch (item->quick_widget->widget_type)
 433         {
 434         case quick_label:
 435             {
 436                 quick_widget_t *input = item->quick_widget->u.label.input;
 437 
 438                 if (input != NULL && input->u.input.label_location == input_label_right)
 439                 {
 440                     /* location of this label will be adjusted later */
 441                     break;
 442                 }
 443             }
 444             MC_FALLTHROUGH;
 445         case quick_checkbox:
 446         case quick_radio:
 447             if (item->widget->x != x1)
 448                 item->widget->x = x2;
 449             if (g != NULL)
 450                 item->widget->x += 2;
 451             break;
 452 
 453         case quick_button:
 454             if (!put_buttons)
 455             {
 456                 if (item->widget->x != x1)
 457                     item->widget->x = x2;
 458                 if (g != NULL)
 459                     item->widget->x += 2;
 460             }
 461             else
 462             {
 463                 item->widget->x = x;
 464                 x += item->widget->cols + 1;
 465             }
 466             break;
 467 
 468         case quick_input:
 469             {
 470                 Widget *label = WIDGET (INPUT (item->widget)->label);
 471                 int width = column_width;
 472 
 473                 if (g != NULL)
 474                     width -= 4;
 475 
 476                 switch (item->quick_widget->u.input.label_location)
 477                 {
 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;
 482                     break;
 483 
 484                 case input_label_right:
 485                     if (item->widget->x != x1)
 486                         item->widget->x = x2;
 487                     if (g != NULL)
 488                         item->widget->x += 2;
 489                     item->widget->cols = width - label->cols - 1;
 490                     label->x = item->widget->x + item->widget->cols + 1;
 491                     break;
 492 
 493                 default:
 494                     if (item->widget->x != x1)
 495                         item->widget->x = x2;
 496                     if (g != NULL)
 497                         item->widget->x += 2;
 498                     item->widget->cols = width;
 499                     break;
 500                 }
 501 
 502                 /* forced update internal variables of inpuit line */
 503                 widget_set_size (item->widget, item->widget->y, item->widget->x, 1,
 504                                  item->widget->cols);
 505             }
 506             break;
 507 
 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;
 513             break;
 514 
 515         case quick_stop_groupbox:
 516             g = NULL;
 517             break;
 518 
 519         case quick_separator:
 520             if (item->widget != NULL)
 521             {
 522                 if (g != NULL)
 523                 {
 524                     Widget *wg = WIDGET (g);
 525 
 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;
 529                 }
 530                 else if (two_columns)
 531                 {
 532                     HLINE (item->widget)->auto_adjust_cols = FALSE;
 533                     if (item->widget->x != x1)
 534                         item->widget->x = x2;
 535                     item->widget->x--;
 536                     item->widget->cols = column_width + 2;
 537                 }
 538                 else
 539                     HLINE (item->widget)->auto_adjust_cols = TRUE;
 540             }
 541             break;
 542 
 543         case quick_start_columns:
 544             two_columns = TRUE;
 545             break;
 546 
 547         case quick_stop_columns:
 548             two_columns = FALSE;
 549             break;
 550 
 551         case quick_buttons:
 552             /* several buttons in bottom line */
 553             put_buttons = TRUE;
 554             break;
 555 
 556         default:
 557             break;
 558         }
 559 
 560         if (item->widget != NULL)
 561         {
 562             unsigned long id;
 563 
 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;
 570         }
 571     }
 572 
 573     while (nskip-- != 0)
 574         dlg_set_current_widget_next (dd);
 575 
 576     return_val = dlg_run (dd);
 577 
 578     /* Get the data if we found something interesting */
 579     if (return_val != B_CANCEL)
 580         for (i = 0; i < widgets->len; i++)
 581         {
 582             quick_widget_item_t *item;
 583 
 584             item = &g_array_index (widgets, quick_widget_item_t, i);
 585 
 586             switch (item->quick_widget->widget_type)
 587             {
 588             case quick_checkbox:
 589                 *item->quick_widget->u.checkbox.state = CHECK (item->widget)->state;
 590                 break;
 591 
 592             case quick_input:
 593                 if ((item->quick_widget->u.input.completion_flags & INPUT_COMPLETE_CD) != 0)
 594                     *item->quick_widget->u.input.result =
 595                         tilde_expand (INPUT (item->widget)->buffer);
 596                 else
 597                     *item->quick_widget->u.input.result = g_strdup (INPUT (item->widget)->buffer);
 598                 break;
 599 
 600             case quick_radio:
 601                 *item->quick_widget->u.radio.value = RADIO (item->widget)->sel;
 602                 break;
 603 
 604             default:
 605                 break;
 606             }
 607         }
 608 
 609     dlg_destroy (dd);
 610 
 611     g_list_free_full (input_labels, g_free);    /* destroy input labels created before */
 612     g_array_free (widgets, TRUE);
 613 
 614     return return_val;
 615 }
 616 
 617 /* --------------------------------------------------------------------------------------------- */

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