Merge branch '4524_cleanup'
[midnight-commander.git] / lib / widget / history.c
blob7076d137358cb88e77237afcdcb7188e54ce2a25
1 /*
2 Widgets for the Midnight Commander
4 Copyright (C) 1994-2024
5 Free Software Foundation, Inc.
7 Authors:
8 Radek Doulik, 1994, 1995
9 Miguel de Icaza, 1994, 1995
10 Jakub Jelinek, 1995
11 Andrej Borsenkow, 1996
12 Norbert Warmuth, 1997
13 Andrew Borodin <aborodin@vmail.ru>, 2009-2022
15 This file is part of the Midnight Commander.
17 The Midnight Commander is free software: you can redistribute it
18 and/or modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation, either version 3 of the License,
20 or (at your option) any later version.
22 The Midnight Commander is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 /** \file history.c
32 * \brief Source: show history
35 #include <config.h>
37 #include <stdlib.h>
38 #include <sys/types.h>
40 #include "lib/global.h"
42 #include "lib/tty/tty.h" /* LINES, COLS */
43 #include "lib/strutil.h"
44 #include "lib/widget.h"
45 #include "lib/keybind.h" /* CK_* */
47 /*** global variables ****************************************************************************/
49 /*** file scope macro definitions ****************************************************************/
51 #define B_VIEW (B_USER + 1)
52 #define B_EDIT (B_USER + 2)
54 /*** file scope type declarations ****************************************************************/
56 typedef struct
58 int y;
59 int x;
60 size_t count;
61 size_t max_width;
62 } history_dlg_data;
64 /*** forward declarations (file scope functions) *************************************************/
66 /*** file scope variables ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
69 /*** file scope functions ************************************************************************/
70 /* --------------------------------------------------------------------------------------------- */
72 static cb_ret_t
73 history_dlg_reposition (WDialog * dlg_head)
75 history_dlg_data *data;
76 int x = 0, y, he, wi;
77 WRect r;
79 /* guard checks */
80 if (dlg_head == NULL || dlg_head->data.p == NULL)
81 return MSG_NOT_HANDLED;
83 data = (history_dlg_data *) dlg_head->data.p;
85 y = data->y;
86 he = data->count + 2;
88 if (he <= y || y > (LINES - 6))
90 he = MIN (he, y - 1);
91 y -= he;
93 else
95 y++;
96 he = MIN (he, LINES - y);
99 if (data->x > 2)
100 x = data->x - 2;
102 wi = data->max_width + 4;
104 if ((wi + x) > COLS)
106 wi = MIN (wi, COLS);
107 x = COLS - wi;
110 rect_init (&r, y, x, he, wi);
112 return dlg_default_callback (WIDGET (dlg_head), NULL, MSG_RESIZE, 0, &r);
115 /* --------------------------------------------------------------------------------------------- */
117 static cb_ret_t
118 history_dlg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
120 switch (msg)
122 case MSG_RESIZE:
123 return history_dlg_reposition (DIALOG (w));
125 case MSG_NOTIFY:
127 /* message from listbox */
128 WDialog *d = DIALOG (w);
130 switch (parm)
132 case CK_View:
133 d->ret_value = B_VIEW;
134 break;
135 case CK_Edit:
136 d->ret_value = B_EDIT;
137 break;
138 case CK_Enter:
139 d->ret_value = B_ENTER;
140 break;
141 default:
142 return MSG_NOT_HANDLED;
145 dlg_close (d);
146 return MSG_HANDLED;
149 default:
150 return dlg_default_callback (w, sender, msg, parm, data);
154 /* --------------------------------------------------------------------------------------------- */
156 static void
157 history_create_item (history_descriptor_t * hd, void *data)
159 char *text = (char *) data;
160 size_t width;
162 width = str_term_width1 (text);
163 hd->max_width = MAX (width, hd->max_width);
165 listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE);
168 /* --------------------------------------------------------------------------------------------- */
170 static void *
171 history_release_item (history_descriptor_t * hd, WLEntry * le)
173 void *text;
175 (void) hd;
177 text = le->text;
178 le->text = NULL;
180 return text;
183 /* --------------------------------------------------------------------------------------------- */
184 /*** public functions ****************************************************************************/
185 /* --------------------------------------------------------------------------------------------- */
187 void
188 history_descriptor_init (history_descriptor_t * hd, int y, int x, GList * history, int current)
190 hd->list = history;
191 hd->y = y;
192 hd->x = x;
193 hd->current = current;
194 hd->action = CK_IgnoreKey;
195 hd->text = NULL;
196 hd->max_width = 0;
197 hd->listbox = listbox_new (1, 1, 2, 2, TRUE, NULL);
198 /* in most cases history list contains string only and no any other data */
199 hd->create = history_create_item;
200 hd->release = history_release_item;
201 hd->free = g_free;
204 /* --------------------------------------------------------------------------------------------- */
206 void
207 history_show (history_descriptor_t * hd)
209 GList *z, *hi;
210 size_t count;
211 WDialog *query_dlg;
212 history_dlg_data hist_data;
213 int dlg_ret;
215 if (hd == NULL || hd->list == NULL)
216 return;
218 hd->max_width = str_term_width1 (_("History")) + 2;
220 for (z = hd->list; z != NULL; z = g_list_previous (z))
221 hd->create (hd, z->data);
222 /* after this, the order of history items is following: recent at begin, oldest at end */
224 count = listbox_get_length (hd->listbox);
226 hist_data.y = hd->y;
227 hist_data.x = hd->x;
228 hist_data.count = count;
229 hist_data.max_width = hd->max_width;
231 query_dlg =
232 dlg_create (TRUE, 0, 0, 4, 4, WPOS_KEEP_DEFAULT, TRUE, dialog_colors, history_dlg_callback,
233 NULL, "[History-query]", _("History"));
234 query_dlg->data.p = &hist_data;
236 /* this call makes list stick to all sides of dialog, effectively make
237 it be resized with dialog */
238 group_add_widget_autopos (GROUP (query_dlg), hd->listbox, WPOS_KEEP_ALL, NULL);
240 /* to avoid diplicating of (calculating sizes in two places)
241 code, call history_dlg_callback function here, to set dialog and
242 controls positions.
243 The main idea - create 4x4 dialog and add 2x2 list in
244 center of it, and let dialog function resize it to needed size. */
245 send_message (query_dlg, NULL, MSG_RESIZE, 0, NULL);
247 if (WIDGET (query_dlg)->rect.y < hd->y)
249 /* history is above base widget -- revert order to place recent item at bottom */
250 /* revert history direction */
251 g_queue_reverse (hd->listbox->list);
252 if (hd->current < 0 || (size_t) hd->current >= count)
253 listbox_select_last (hd->listbox);
254 else
255 listbox_set_current (hd->listbox, count - 1 - (size_t) hd->current);
257 else
259 /* history is below base widget -- keep order to place recent item on top */
260 if (hd->current > 0)
261 listbox_set_current (hd->listbox, hd->current);
264 dlg_ret = dlg_run (query_dlg);
265 if (dlg_ret != B_CANCEL)
267 char *q;
269 switch (dlg_ret)
271 case B_EDIT:
272 hd->action = CK_Edit;
273 break;
274 case B_VIEW:
275 hd->action = CK_View;
276 break;
277 default:
278 hd->action = CK_Enter;
281 listbox_get_current (hd->listbox, &q, NULL);
282 hd->text = g_strdup (q);
285 /* get modified history from dialog */
286 z = NULL;
287 for (hi = listbox_get_first_link (hd->listbox); hi != NULL; hi = g_list_next (hi))
288 /* history is being reverted here again */
289 z = g_list_prepend (z, hd->release (hd, LENTRY (hi->data)));
291 /* restore history direction */
292 if (WIDGET (query_dlg)->rect.y < hd->y)
293 z = g_list_reverse (z);
295 widget_destroy (WIDGET (query_dlg));
297 hd->list = g_list_first (hd->list);
298 g_list_free_full (hd->list, hd->free);
299 hd->list = g_list_last (z);
302 /* --------------------------------------------------------------------------------------------- */