diff options
Diffstat (limited to '')
-rw-r--r-- | lib/widget/quick.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/lib/widget/quick.c b/lib/widget/quick.c new file mode 100644 index 0000000..35f5d68 --- /dev/null +++ b/lib/widget/quick.c @@ -0,0 +1,626 @@ +/* + Widget based utility functions. + + Copyright (C) 1994-2023 + Free Software Foundation, Inc. + + Authors: + Miguel de Icaza, 1994, 1995, 1996 + Radek Doulik, 1994, 1995 + Jakub Jelinek, 1995 + Andrej Borsenkow, 1995 + Andrew Borodin <aborodin@vmail.ru>, 2009-2022 + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file quick.c + * \brief Source: quick dialog engine + */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> /* fprintf() */ + +#include "lib/global.h" +#include "lib/strutil.h" /* str_term_width1() */ +#include "lib/util.h" /* tilde_expand() */ +#include "lib/widget.h" + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +#ifdef ENABLE_NLS +#define I18N(x) (x = x != NULL && *x != '\0' ? _(x) : x) +#else +#define I18N(x) (x = x) +#endif + +/*** file scope type declarations ****************************************************************/ + +typedef struct +{ + Widget *widget; + quick_widget_t *quick_widget; +} quick_widget_item_t; + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +static WInput * +quick_create_input (int y, int x, const quick_widget_t * qw) +{ + WInput *in; + + in = input_new (y, x, input_colors, 8, qw->u.input.text, qw->u.input.histname, + qw->u.input.completion_flags); + + in->is_password = qw->u.input.is_passwd; + in->strip_password = qw->u.input.strip_passwd; + + return in; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +quick_create_labeled_input (GArray * widgets, int *y, int x, quick_widget_t * quick_widget, + int *width) +{ + quick_widget_item_t in, label; + + label.quick_widget = g_new0 (quick_widget_t, 1); + label.quick_widget->widget_type = quick_label; + label.quick_widget->options = quick_widget->options; + label.quick_widget->state = quick_widget->state; + /* FIXME: this should be turned in depend of label_location */ + label.quick_widget->pos_flags = quick_widget->pos_flags; + + switch (quick_widget->u.input.label_location) + { + case input_label_above: + label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text))); + *y += label.widget->rect.lines - 1; + g_array_append_val (widgets, label); + + in.widget = WIDGET (quick_create_input (++(*y), x, quick_widget)); + in.quick_widget = quick_widget; + g_array_append_val (widgets, in); + + *width = MAX (label.widget->rect.cols, in.widget->rect.cols); + break; + + case input_label_left: + label.widget = WIDGET (label_new (*y, x, I18N (quick_widget->u.input.label_text))); + g_array_append_val (widgets, label); + + in.widget = WIDGET (quick_create_input (*y, x + label.widget->rect.cols + 1, quick_widget)); + in.quick_widget = quick_widget; + g_array_append_val (widgets, in); + + *width = label.widget->rect.cols + in.widget->rect.cols + 1; + break; + + case input_label_right: + in.widget = WIDGET (quick_create_input (*y, x, quick_widget)); + in.quick_widget = quick_widget; + g_array_append_val (widgets, in); + + label.widget = + WIDGET (label_new + (*y, x + in.widget->rect.cols + 1, I18N (quick_widget->u.input.label_text))); + g_array_append_val (widgets, label); + + *width = label.widget->rect.cols + in.widget->rect.cols + 1; + break; + + case input_label_below: + in.widget = WIDGET (quick_create_input (*y, x, quick_widget)); + in.quick_widget = quick_widget; + g_array_append_val (widgets, in); + + label.widget = WIDGET (label_new (++(*y), x, I18N (quick_widget->u.input.label_text))); + *y += label.widget->rect.lines - 1; + g_array_append_val (widgets, label); + + *width = MAX (label.widget->rect.cols, in.widget->rect.cols); + break; + + default: + return; + } + + INPUT (in.widget)->label = LABEL (label.widget); + /* cross references */ + label.quick_widget->u.label.input = in.quick_widget; + in.quick_widget->u.input.label = label.quick_widget; +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +int +quick_dialog_skip (quick_dialog_t * quick_dlg, int nskip) +{ + int len; + int blen = 0; + int x, y; /* current positions */ + int y1 = 0; /* bottom of 1st column in case of two columns */ + int y2 = -1; /* start of two columns */ + int width1 = 0; /* width of single column */ + int width2 = 0; /* width of each of two columns */ + gboolean have_groupbox = FALSE; + gboolean two_columns = FALSE; + gboolean put_buttons = FALSE; + + /* x position of 1st column is 3 */ + const int x1 = 3; + /* x position of 2nd column is 4 and it will be fixed later, after creation of all widgets */ + int x2 = 4; + + GArray *widgets; + size_t i; + quick_widget_t *quick_widget; + WGroupbox *g = NULL; + WDialog *dd; + GList *input_labels = NULL; /* Widgets not directly requested by the user. */ + int return_val; + + len = str_term_width1 (I18N (quick_dlg->title)) + 6; + quick_dlg->rect.cols = MAX (quick_dlg->rect.cols, len); + + y = 1; + x = x1; + + /* create widgets */ + widgets = g_array_sized_new (FALSE, FALSE, sizeof (quick_widget_item_t), 8); + + for (quick_widget = quick_dlg->widgets; quick_widget->widget_type != quick_end; quick_widget++) + { + quick_widget_item_t item = { NULL, quick_widget }; + int width = 0; + + switch (quick_widget->widget_type) + { + case quick_checkbox: + item.widget = + WIDGET (check_new + (++y, x, *quick_widget->u.checkbox.state, + I18N (quick_widget->u.checkbox.text))); + g_array_append_val (widgets, item); + width = item.widget->rect.cols; + if (g != NULL) + width += 2; + if (two_columns) + width2 = MAX (width2, width); + else + width1 = MAX (width1, width); + break; + + case quick_button: + /* single button */ + item.widget = WIDGET (button_new (++y, x, quick_widget->u.button.action, + quick_widget->u.button.action == B_ENTER ? + DEFPUSH_BUTTON : NORMAL_BUTTON, + I18N (quick_widget->u.button.text), + quick_widget->u.button.callback)); + g_array_append_val (widgets, item); + width = item.widget->rect.cols; + if (g != NULL) + width += 2; + if (two_columns) + width2 = MAX (width2, width); + else + width1 = MAX (width1, width); + break; + + case quick_input: + *quick_widget->u.input.result = NULL; + y++; + if (quick_widget->u.input.label_location != input_label_none) + { + quick_create_labeled_input (widgets, &y, x, quick_widget, &width); + input_labels = g_list_prepend (input_labels, quick_widget->u.input.label); + } + else + { + item.widget = WIDGET (quick_create_input (y, x, quick_widget)); + g_array_append_val (widgets, item); + width = item.widget->rect.cols; + } + if (g != NULL) + width += 2; + if (two_columns) + width2 = MAX (width2, width); + else + width1 = MAX (width1, width); + break; + + case quick_label: + item.widget = WIDGET (label_new (++y, x, I18N (quick_widget->u.label.text))); + g_array_append_val (widgets, item); + y += item.widget->rect.lines - 1; + width = item.widget->rect.cols; + if (g != NULL) + width += 2; + if (two_columns) + width2 = MAX (width2, width); + else + width1 = MAX (width1, width); + break; + + case quick_radio: + { + WRadio *r; + char **items = NULL; + + /* create the copy of radio_items to avoid mwmory leak */ + items = g_new (char *, quick_widget->u.radio.count + 1); + for (i = 0; i < (size_t) quick_widget->u.radio.count; i++) + items[i] = g_strdup (_(quick_widget->u.radio.items[i])); + items[i] = NULL; + + r = radio_new (++y, x, quick_widget->u.radio.count, (const char **) items); + r->pos = r->sel = *quick_widget->u.radio.value; + g_strfreev (items); + item.widget = WIDGET (r); + g_array_append_val (widgets, item); + y += item.widget->rect.lines - 1; + width = item.widget->rect.cols; + if (g != NULL) + width += 2; + if (two_columns) + width2 = MAX (width2, width); + else + width1 = MAX (width1, width); + } + break; + + case quick_start_groupbox: + I18N (quick_widget->u.groupbox.title); + len = str_term_width1 (quick_widget->u.groupbox.title); + g = groupbox_new (++y, x, 1, len + 4, quick_widget->u.groupbox.title); + item.widget = WIDGET (g); + g_array_append_val (widgets, item); + have_groupbox = TRUE; + break; + + case quick_stop_groupbox: + if (g != NULL) + { + Widget *w = WIDGET (g); + + y++; + w->rect.lines = y + 1 - w->rect.y; + g = NULL; + + g_array_append_val (widgets, item); + } + break; + + case quick_separator: + y++; + if (quick_widget->u.separator.line) + { + item.widget = WIDGET (hline_new (y, x, 1)); + g_array_append_val (widgets, item); + } + break; + + case quick_start_columns: + y2 = y; + g_array_append_val (widgets, item); + two_columns = TRUE; + break; + + case quick_next_column: + x = x2; + y1 = y; + y = y2; + break; + + case quick_stop_columns: + x = x1; + y = MAX (y1, y); + g_array_append_val (widgets, item); + two_columns = FALSE; + break; + + case quick_buttons: + /* start put several buttons in bottom line */ + if (quick_widget->u.separator.space) + { + y++; + + if (quick_widget->u.separator.line) + item.widget = WIDGET (hline_new (y, 1, -1)); + } + + g_array_append_val (widgets, item); + + /* several buttons in bottom line */ + y++; + quick_widget++; + for (; quick_widget->widget_type == quick_button; quick_widget++) + { + item.widget = WIDGET (button_new (y, x++, quick_widget->u.button.action, + quick_widget->u.button.action == B_ENTER ? + DEFPUSH_BUTTON : NORMAL_BUTTON, + I18N (quick_widget->u.button.text), + quick_widget->u.button.callback)); + item.quick_widget = quick_widget; + g_array_append_val (widgets, item); + blen += item.widget->rect.cols + 1; + } + + /* stop dialog build here */ + blen--; + quick_widget->widget_type = quick_end; + quick_widget--; + break; + + default: + break; + } + } + + /* adjust dialog width */ + quick_dlg->rect.cols = MAX (quick_dlg->rect.cols, blen + 6); + if (have_groupbox) + { + if (width1 != 0) + width1 += 2; + if (width2 != 0) + width2 += 2; + } + if (width2 == 0) + len = width1 + 6; + else + { + len = width2 * 2 + 7; + if (width1 != 0) + len = MAX (len, width1 + 6); + } + + quick_dlg->rect.cols = MAX (quick_dlg->rect.cols, len); + width1 = quick_dlg->rect.cols - 6; + width2 = (quick_dlg->rect.cols - 7) / 2; + + if (quick_dlg->rect.x == -1 || quick_dlg->rect.y == -1) + dd = dlg_create (TRUE, 0, 0, y + 3, quick_dlg->rect.cols, WPOS_CENTER | WPOS_TRYUP, FALSE, + dialog_colors, quick_dlg->callback, quick_dlg->mouse_callback, + quick_dlg->help, quick_dlg->title); + else + dd = dlg_create (TRUE, quick_dlg->rect.y, quick_dlg->rect.x, y + 3, quick_dlg->rect.cols, + WPOS_KEEP_DEFAULT, FALSE, dialog_colors, quick_dlg->callback, + quick_dlg->mouse_callback, quick_dlg->help, quick_dlg->title); + + /* add widgets into the dialog */ + x2 = x1 + width2 + 1; + g = NULL; + two_columns = FALSE; + x = (WIDGET (dd)->rect.cols - blen) / 2; + + for (i = 0; i < widgets->len; i++) + { + quick_widget_item_t *item; + int column_width; + WRect *r; + + item = &g_array_index (widgets, quick_widget_item_t, i); + r = &item->widget->rect; + column_width = two_columns ? width2 : width1; + + /* adjust widget width and x position */ + switch (item->quick_widget->widget_type) + { + case quick_label: + { + quick_widget_t *input = item->quick_widget->u.label.input; + + if (input != NULL && input->u.input.label_location == input_label_right) + { + /* location of this label will be adjusted later */ + break; + } + } + MC_FALLTHROUGH; + case quick_checkbox: + case quick_radio: + if (r->x != x1) + r->x = x2; + if (g != NULL) + r->x += 2; + break; + + case quick_button: + if (!put_buttons) + { + if (r->x != x1) + r->x = x2; + if (g != NULL) + r->x += 2; + } + else + { + r->x = x; + x += r->cols + 1; + } + break; + + case quick_input: + { + Widget *label = WIDGET (INPUT (item->widget)->label); + int width = column_width; + + if (g != NULL) + width -= 4; + + switch (item->quick_widget->u.input.label_location) + { + case input_label_left: + /* label was adjusted before; adjust input line */ + r->x = label->rect.x + label->rect.cols + 1 - WIDGET (label->owner)->rect.x; + r->cols = width - label->rect.cols - 1; + break; + + case input_label_right: + if (r->x != x1) + r->x = x2; + if (g != NULL) + r->x += 2; + r->cols = width - label->rect.cols - 1; + label->rect.x = r->x + r->cols + 1; + break; + + default: + if (r->x != x1) + r->x = x2; + if (g != NULL) + r->x += 2; + r->cols = width; + break; + } + + /* forced update internal variables of input line */ + r->lines = 1; + widget_set_size_rect (item->widget, r); + } + break; + + case quick_start_groupbox: + g = GROUPBOX (item->widget); + if (r->x != x1) + r->x = x2; + r->cols = column_width; + break; + + case quick_stop_groupbox: + g = NULL; + break; + + case quick_separator: + if (item->widget != NULL) + { + if (g != NULL) + { + Widget *wg = WIDGET (g); + + HLINE (item->widget)->auto_adjust_cols = FALSE; + r->x = wg->rect.x + 1 - WIDGET (wg->owner)->rect.x; + r->cols = wg->rect.cols; + } + else if (two_columns) + { + HLINE (item->widget)->auto_adjust_cols = FALSE; + if (r->x != x1) + r->x = x2; + r->x--; + r->cols = column_width + 2; + } + else + HLINE (item->widget)->auto_adjust_cols = TRUE; + } + break; + + case quick_start_columns: + two_columns = TRUE; + break; + + case quick_stop_columns: + two_columns = FALSE; + break; + + case quick_buttons: + /* several buttons in bottom line */ + put_buttons = TRUE; + break; + + default: + break; + } + + if (item->widget != NULL) + { + unsigned long id; + + /* add widget into dialog */ + item->widget->options |= item->quick_widget->options; /* FIXME: cannot reset flags, setup only */ + item->widget->state |= item->quick_widget->state; /* FIXME: cannot reset flags, setup only */ + id = group_add_widget_autopos (GROUP (dd), item->widget, item->quick_widget->pos_flags, + NULL); + if (item->quick_widget->id != NULL) + *item->quick_widget->id = id; + } + } + + /* skip frame widget */ + if (dd->bg != NULL) + nskip++; + + while (nskip-- != 0) + group_set_current_widget_next (GROUP (dd)); + + return_val = dlg_run (dd); + + /* Get the data if we found something interesting */ + if (return_val != B_CANCEL) + for (i = 0; i < widgets->len; i++) + { + quick_widget_item_t *item; + + item = &g_array_index (widgets, quick_widget_item_t, i); + + switch (item->quick_widget->widget_type) + { + case quick_checkbox: + *item->quick_widget->u.checkbox.state = CHECK (item->widget)->state; + break; + + case quick_input: + if ((item->quick_widget->u.input.completion_flags & INPUT_COMPLETE_CD) != 0) + *item->quick_widget->u.input.result = + tilde_expand (input_get_ctext (INPUT (item->widget))); + else + *item->quick_widget->u.input.result = input_get_text (INPUT (item->widget)); + break; + + case quick_radio: + *item->quick_widget->u.radio.value = RADIO (item->widget)->sel; + break; + + default: + break; + } + } + + widget_destroy (WIDGET (dd)); + + g_list_free_full (input_labels, g_free); /* destroy input labels created before */ + g_array_free (widgets, TRUE); + + return return_val; +} + +/* --------------------------------------------------------------------------------------------- */ |