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-2022
   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-2022
  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->rect.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->rect.cols, in.widget->rect.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->rect.cols + 1, quick_widget));
 116         in.quick_widget = quick_widget;
 117         g_array_append_val (widgets, in);
 118 
 119         *width = label.widget->rect.cols + in.widget->rect.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->rect.cols + 1, I18N (quick_widget->u.input.label_text)));
 130         g_array_append_val (widgets, label);
 131 
 132         *width = label.widget->rect.cols + in.widget->rect.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->rect.lines - 1;
 142         g_array_append_val (widgets, label);
 143 
 144         *width = MAX (label.widget->rect.cols, in.widget->rect.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->rect.cols = MAX (quick_dlg->rect.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->rect.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->rect.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->rect.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->rect.lines - 1;
 262             width = item.widget->rect.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->rect.lines - 1;
 288                 width = item.widget->rect.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->rect.lines = y + 1 - w->rect.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->rect.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->rect.cols = MAX (quick_dlg->rect.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->rect.cols = MAX (quick_dlg->rect.cols, len);
 405     width1 = quick_dlg->rect.cols - 6;
 406     width2 = (quick_dlg->rect.cols - 7) / 2;
 407 
 408     if (quick_dlg->rect.x == -1 || quick_dlg->rect.y == -1)
 409         dd = dlg_create (TRUE, 0, 0, y + 3, quick_dlg->rect.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->rect.y, quick_dlg->rect.x, y + 3, quick_dlg->rect.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)->rect.cols - blen) / 2;
 422 
 423     for (i = 0; i < widgets->len; i++)
 424     {
 425         quick_widget_item_t *item;
 426         int column_width;
 427         WRect *r;
 428 
 429         item = &g_array_index (widgets, quick_widget_item_t, i);
 430         r = &item->widget->rect;
 431         column_width = two_columns ? width2 : width1;
 432 
 433         /* adjust widget width and x position */
 434         switch (item->quick_widget->widget_type)
 435         {
 436         case quick_label:
 437             {
 438                 quick_widget_t *input = item->quick_widget->u.label.input;
 439 
 440                 if (input != NULL && input->u.input.label_location == input_label_right)
 441                 {
 442                     /* location of this label will be adjusted later */
 443                     break;
 444                 }
 445             }
 446             MC_FALLTHROUGH;
 447         case quick_checkbox:
 448         case quick_radio:
 449             if (r->x != x1)
 450                 r->x = x2;
 451             if (g != NULL)
 452                 r->x += 2;
 453             break;
 454 
 455         case quick_button:
 456             if (!put_buttons)
 457             {
 458                 if (r->x != x1)
 459                     r->x = x2;
 460                 if (g != NULL)
 461                     r->x += 2;
 462             }
 463             else
 464             {
 465                 r->x = x;
 466                 x += r->cols + 1;
 467             }
 468             break;
 469 
 470         case quick_input:
 471             {
 472                 Widget *label = WIDGET (INPUT (item->widget)->label);
 473                 int width = column_width;
 474 
 475                 if (g != NULL)
 476                     width -= 4;
 477 
 478                 switch (item->quick_widget->u.input.label_location)
 479                 {
 480                 case input_label_left:
 481                     /* label was adjusted before; adjust input line */
 482                     r->x = label->rect.x + label->rect.cols + 1 - WIDGET (label->owner)->rect.x;
 483                     r->cols = width - label->rect.cols - 1;
 484                     break;
 485 
 486                 case input_label_right:
 487                     if (r->x != x1)
 488                         r->x = x2;
 489                     if (g != NULL)
 490                         r->x += 2;
 491                     r->cols = width - label->rect.cols - 1;
 492                     label->rect.x = r->x + r->cols + 1;
 493                     break;
 494 
 495                 default:
 496                     if (r->x != x1)
 497                         r->x = x2;
 498                     if (g != NULL)
 499                         r->x += 2;
 500                     r->cols = width;
 501                     break;
 502                 }
 503 
 504                 /* forced update internal variables of input line */
 505                 r->lines = 1;
 506                 widget_set_size_rect (item->widget, r);
 507             }
 508             break;
 509 
 510         case quick_start_groupbox:
 511             g = GROUPBOX (item->widget);
 512             if (r->x != x1)
 513                 r->x = x2;
 514             r->cols = column_width;
 515             break;
 516 
 517         case quick_stop_groupbox:
 518             g = NULL;
 519             break;
 520 
 521         case quick_separator:
 522             if (item->widget != NULL)
 523             {
 524                 if (g != NULL)
 525                 {
 526                     Widget *wg = WIDGET (g);
 527 
 528                     HLINE (item->widget)->auto_adjust_cols = FALSE;
 529                     r->x = wg->rect.x + 1 - WIDGET (wg->owner)->rect.x;
 530                     r->cols = wg->rect.cols;
 531                 }
 532                 else if (two_columns)
 533                 {
 534                     HLINE (item->widget)->auto_adjust_cols = FALSE;
 535                     if (r->x != x1)
 536                         r->x = x2;
 537                     r->x--;
 538                     r->cols = column_width + 2;
 539                 }
 540                 else
 541                     HLINE (item->widget)->auto_adjust_cols = TRUE;
 542             }
 543             break;
 544 
 545         case quick_start_columns:
 546             two_columns = TRUE;
 547             break;
 548 
 549         case quick_stop_columns:
 550             two_columns = FALSE;
 551             break;
 552 
 553         case quick_buttons:
 554             /* several buttons in bottom line */
 555             put_buttons = TRUE;
 556             break;
 557 
 558         default:
 559             break;
 560         }
 561 
 562         if (item->widget != NULL)
 563         {
 564             unsigned long id;
 565 
 566             /* add widget into dialog */
 567             item->widget->options |= item->quick_widget->options;       /* FIXME: cannot reset flags, setup only */
 568             item->widget->state |= item->quick_widget->state;   /* FIXME: cannot reset flags, setup only */
 569             id = group_add_widget_autopos (GROUP (dd), item->widget, item->quick_widget->pos_flags,
 570                                            NULL);
 571             if (item->quick_widget->id != NULL)
 572                 *item->quick_widget->id = id;
 573         }
 574     }
 575 
 576     /* skip frame widget */
 577     if (dd->bg != NULL)
 578         nskip++;
 579 
 580     while (nskip-- != 0)
 581         group_set_current_widget_next (GROUP (dd));
 582 
 583     return_val = dlg_run (dd);
 584 
 585     /* Get the data if we found something interesting */
 586     if (return_val != B_CANCEL)
 587         for (i = 0; i < widgets->len; i++)
 588         {
 589             quick_widget_item_t *item;
 590 
 591             item = &g_array_index (widgets, quick_widget_item_t, i);
 592 
 593             switch (item->quick_widget->widget_type)
 594             {
 595             case quick_checkbox:
 596                 *item->quick_widget->u.checkbox.state = CHECK (item->widget)->state;
 597                 break;
 598 
 599             case quick_input:
 600                 if ((item->quick_widget->u.input.completion_flags & INPUT_COMPLETE_CD) != 0)
 601                     *item->quick_widget->u.input.result =
 602                         tilde_expand (INPUT (item->widget)->buffer->str);
 603                 else
 604                     *item->quick_widget->u.input.result = input_get_text (INPUT (item->widget));
 605                 break;
 606 
 607             case quick_radio:
 608                 *item->quick_widget->u.radio.value = RADIO (item->widget)->sel;
 609                 break;
 610 
 611             default:
 612                 break;
 613             }
 614         }
 615 
 616     widget_destroy (WIDGET (dd));
 617 
 618     g_list_free_full (input_labels, g_free);    /* destroy input labels created before */
 619     g_array_free (widgets, TRUE);
 620 
 621     return return_val;
 622 }
 623 
 624 /* --------------------------------------------------------------------------------------------- */

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