diff options
Diffstat (limited to 'lib/widget/history.c')
-rw-r--r-- | lib/widget/history.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/lib/widget/history.c b/lib/widget/history.c new file mode 100644 index 0000000..8197db8 --- /dev/null +++ b/lib/widget/history.c @@ -0,0 +1,302 @@ +/* + Widgets for the Midnight Commander + + Copyright (C) 1994-2023 + Free Software Foundation, Inc. + + Authors: + Radek Doulik, 1994, 1995 + Miguel de Icaza, 1994, 1995 + Jakub Jelinek, 1995 + Andrej Borsenkow, 1996 + Norbert Warmuth, 1997 + 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 history.c + * \brief Source: show history + */ + +#include <config.h> + +#include <stdlib.h> +#include <sys/types.h> + +#include "lib/global.h" + +#include "lib/tty/tty.h" /* LINES, COLS */ +#include "lib/strutil.h" +#include "lib/widget.h" +#include "lib/keybind.h" /* CK_* */ + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +#define B_VIEW (B_USER + 1) +#define B_EDIT (B_USER + 2) + +/*** file scope type declarations ****************************************************************/ + +typedef struct +{ + int y; + int x; + size_t count; + size_t max_width; +} history_dlg_data; + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +static cb_ret_t +history_dlg_reposition (WDialog * dlg_head) +{ + history_dlg_data *data; + int x = 0, y, he, wi; + WRect r; + + /* guard checks */ + if (dlg_head == NULL || dlg_head->data.p == NULL) + return MSG_NOT_HANDLED; + + data = (history_dlg_data *) dlg_head->data.p; + + y = data->y; + he = data->count + 2; + + if (he <= y || y > (LINES - 6)) + { + he = MIN (he, y - 1); + y -= he; + } + else + { + y++; + he = MIN (he, LINES - y); + } + + if (data->x > 2) + x = data->x - 2; + + wi = data->max_width + 4; + + if ((wi + x) > COLS) + { + wi = MIN (wi, COLS); + x = COLS - wi; + } + + rect_init (&r, y, x, he, wi); + + return dlg_default_callback (WIDGET (dlg_head), NULL, MSG_RESIZE, 0, &r); +} + +/* --------------------------------------------------------------------------------------------- */ + +static cb_ret_t +history_dlg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) +{ + switch (msg) + { + case MSG_RESIZE: + return history_dlg_reposition (DIALOG (w)); + + case MSG_NOTIFY: + { + /* message from listbox */ + WDialog *d = DIALOG (w); + + switch (parm) + { + case CK_View: + d->ret_value = B_VIEW; + break; + case CK_Edit: + d->ret_value = B_EDIT; + break; + case CK_Enter: + d->ret_value = B_ENTER; + break; + default: + return MSG_NOT_HANDLED; + } + + dlg_close (d); + return MSG_HANDLED; + } + + default: + return dlg_default_callback (w, sender, msg, parm, data); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +history_create_item (history_descriptor_t * hd, void *data) +{ + char *text = (char *) data; + size_t width; + + width = str_term_width1 (text); + hd->max_width = MAX (width, hd->max_width); + + listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void * +history_release_item (history_descriptor_t * hd, WLEntry * le) +{ + void *text; + + (void) hd; + + text = le->text; + le->text = NULL; + + return text; +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +void +history_descriptor_init (history_descriptor_t * hd, int y, int x, GList * history, int current) +{ + hd->list = history; + hd->y = y; + hd->x = x; + hd->current = current; + hd->action = CK_IgnoreKey; + hd->text = NULL; + hd->max_width = 0; + hd->listbox = listbox_new (1, 1, 2, 2, TRUE, NULL); + /* in most cases history list contains string only and no any other data */ + hd->create = history_create_item; + hd->release = history_release_item; + hd->free = g_free; +} + +/* --------------------------------------------------------------------------------------------- */ + +void +history_show (history_descriptor_t * hd) +{ + GList *z, *hi; + size_t count; + WDialog *query_dlg; + history_dlg_data hist_data; + int dlg_ret; + + if (hd == NULL || hd->list == NULL) + return; + + hd->max_width = str_term_width1 (_("History")) + 2; + + for (z = hd->list; z != NULL; z = g_list_previous (z)) + hd->create (hd, z->data); + /* after this, the order of history items is following: recent at begin, oldest at end */ + + count = listbox_get_length (hd->listbox); + + hist_data.y = hd->y; + hist_data.x = hd->x; + hist_data.count = count; + hist_data.max_width = hd->max_width; + + query_dlg = + dlg_create (TRUE, 0, 0, 4, 4, WPOS_KEEP_DEFAULT, TRUE, dialog_colors, history_dlg_callback, + NULL, "[History-query]", _("History")); + query_dlg->data.p = &hist_data; + + /* this call makes list stick to all sides of dialog, effectively make + it be resized with dialog */ + group_add_widget_autopos (GROUP (query_dlg), hd->listbox, WPOS_KEEP_ALL, NULL); + + /* to avoid diplicating of (calculating sizes in two places) + code, call history_dlg_callback function here, to set dialog and + controls positions. + The main idea - create 4x4 dialog and add 2x2 list in + center of it, and let dialog function resize it to needed size. */ + send_message (query_dlg, NULL, MSG_RESIZE, 0, NULL); + + if (WIDGET (query_dlg)->rect.y < hd->y) + { + /* history is above base widget -- revert order to place recent item at bottom */ + /* revert history direction */ + g_queue_reverse (hd->listbox->list); + if (hd->current < 0 || (size_t) hd->current >= count) + listbox_select_last (hd->listbox); + else + listbox_set_current (hd->listbox, count - 1 - (size_t) hd->current); + } + else + { + /* history is below base widget -- keep order to place recent item on top */ + if (hd->current > 0) + listbox_set_current (hd->listbox, hd->current); + } + + dlg_ret = dlg_run (query_dlg); + if (dlg_ret != B_CANCEL) + { + char *q; + + switch (dlg_ret) + { + case B_EDIT: + hd->action = CK_Edit; + break; + case B_VIEW: + hd->action = CK_View; + break; + default: + hd->action = CK_Enter; + } + + listbox_get_current (hd->listbox, &q, NULL); + hd->text = g_strdup (q); + } + + /* get modified history from dialog */ + z = NULL; + for (hi = listbox_get_first_link (hd->listbox); hi != NULL; hi = g_list_next (hi)) + /* history is being reverted here again */ + z = g_list_prepend (z, hd->release (hd, LENTRY (hi->data))); + + /* restore history direction */ + if (WIDGET (query_dlg)->rect.y < hd->y) + z = g_list_reverse (z); + + widget_destroy (WIDGET (query_dlg)); + + hd->list = g_list_first (hd->list); + g_list_free_full (hd->list, hd->free); + hd->list = g_list_last (z); +} + +/* --------------------------------------------------------------------------------------------- */ |