Move widget add/del API from WDialog to WGroup.
[midnight-commander.git] / lib / widget / history.c
blob5079c33262145733ded470e27b681d843cb15e55
1 /*
2 Widgets for the Midnight Commander
4 Copyright (C) 1994-2020
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-2019
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 /*** file scope variables ************************************************************************/
66 /*** file scope functions ************************************************************************/
68 static cb_ret_t
69 history_dlg_reposition (WDialog * dlg_head)
71 history_dlg_data *data;
72 int x = 0, y, he, wi;
74 /* guard checks */
75 if ((dlg_head == NULL) || (dlg_head->data == NULL))
76 return MSG_NOT_HANDLED;
78 data = (history_dlg_data *) dlg_head->data;
80 y = data->y;
81 he = data->count + 2;
83 if (he <= y || y > (LINES - 6))
85 he = MIN (he, y - 1);
86 y -= he;
88 else
90 y++;
91 he = MIN (he, LINES - y);
94 if (data->x > 2)
95 x = data->x - 2;
97 wi = data->max_width + 4;
99 if ((wi + x) > COLS)
101 wi = MIN (wi, COLS);
102 x = COLS - wi;
105 dlg_set_position (dlg_head, y, x, he, wi);
107 return MSG_HANDLED;
110 /* --------------------------------------------------------------------------------------------- */
112 static cb_ret_t
113 history_dlg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
115 switch (msg)
117 case MSG_RESIZE:
118 return history_dlg_reposition (DIALOG (w));
120 case MSG_NOTIFY:
122 /* message from listbox */
123 WDialog *d = DIALOG (w);
125 switch (parm)
127 case CK_View:
128 d->ret_value = B_VIEW;
129 break;
130 case CK_Edit:
131 d->ret_value = B_EDIT;
132 break;
133 case CK_Enter:
134 d->ret_value = B_ENTER;
135 break;
136 default:
137 return MSG_NOT_HANDLED;
140 dlg_stop (d);
141 return MSG_HANDLED;
144 default:
145 return dlg_default_callback (w, sender, msg, parm, data);
149 /* --------------------------------------------------------------------------------------------- */
151 static void
152 history_create_item (history_descriptor_t * hd, void *data)
154 char *text = (char *) data;
155 size_t width;
157 width = str_term_width1 (text);
158 hd->max_width = MAX (width, hd->max_width);
160 listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE);
163 /* --------------------------------------------------------------------------------------------- */
165 static void *
166 history_release_item (history_descriptor_t * hd, WLEntry * le)
168 void *text;
170 (void) hd;
172 text = le->text;
173 le->text = NULL;
175 return text;
178 /* --------------------------------------------------------------------------------------------- */
179 /*** public functions ****************************************************************************/
180 /* --------------------------------------------------------------------------------------------- */
182 void
183 history_descriptor_init (history_descriptor_t * hd, int y, int x, GList * history, int current)
185 hd->list = history;
186 hd->y = y;
187 hd->x = x;
188 hd->current = current;
189 hd->action = CK_IgnoreKey;
190 hd->text = NULL;
191 hd->max_width = 0;
192 hd->listbox = listbox_new (1, 1, 2, 2, TRUE, NULL);
193 /* in most cases history list contains string only and no any other data */
194 hd->create = history_create_item;
195 hd->release = history_release_item;
196 hd->free = g_free;
199 /* --------------------------------------------------------------------------------------------- */
201 void
202 history_show (history_descriptor_t * hd)
204 GList *z, *hi;
205 size_t count;
206 WDialog *query_dlg;
207 history_dlg_data hist_data;
208 int dlg_ret;
210 if (hd == NULL || hd->list == NULL)
211 return;
213 hd->max_width = str_term_width1 (_("History")) + 2;
215 for (z = hd->list; z != NULL; z = g_list_previous (z))
216 hd->create (hd, z->data);
217 /* after this, the order of history items is following: recent at begin, oldest at end */
219 count = listbox_get_length (hd->listbox);
221 hist_data.y = hd->y;
222 hist_data.x = hd->x;
223 hist_data.count = count;
224 hist_data.max_width = hd->max_width;
226 query_dlg =
227 dlg_create (TRUE, 0, 0, 4, 4, WPOS_KEEP_DEFAULT, TRUE, dialog_colors, history_dlg_callback,
228 NULL, "[History-query]", _("History"));
229 query_dlg->data = &hist_data;
231 /* this call makes list stick to all sides of dialog, effectively make
232 it be resized with dialog */
233 group_add_widget_autopos (GROUP (query_dlg), hd->listbox, WPOS_KEEP_ALL, NULL);
235 /* to avoid diplicating of (calculating sizes in two places)
236 code, call history_dlg_callback function here, to set dialog and
237 controls positions.
238 The main idea - create 4x4 dialog and add 2x2 list in
239 center of it, and let dialog function resize it to needed size. */
240 send_message (query_dlg, NULL, MSG_RESIZE, 0, NULL);
242 if (WIDGET (query_dlg)->y < hd->y)
244 /* history is above base widget -- revert order to place recent item at bottom */
245 /* revert history direction */
246 g_queue_reverse (hd->listbox->list);
247 if (hd->current < 0 || (size_t) hd->current >= count)
248 listbox_select_last (hd->listbox);
249 else
250 listbox_select_entry (hd->listbox, count - 1 - (size_t) hd->current);
252 else
254 /* history is below base widget -- keep order to place recent item on top */
255 if (hd->current > 0)
256 listbox_select_entry (hd->listbox, hd->current);
259 dlg_ret = dlg_run (query_dlg);
260 if (dlg_ret != B_CANCEL)
262 char *q;
264 switch (dlg_ret)
266 case B_EDIT:
267 hd->action = CK_Edit;
268 break;
269 case B_VIEW:
270 hd->action = CK_View;
271 break;
272 default:
273 hd->action = CK_Enter;
276 listbox_get_current (hd->listbox, &q, NULL);
277 hd->text = g_strdup (q);
280 /* get modified history from dialog */
281 z = NULL;
282 for (hi = listbox_get_first_link (hd->listbox); hi != NULL; hi = g_list_next (hi))
283 /* history is being reverted here again */
284 z = g_list_prepend (z, hd->release (hd, LENTRY (hi->data)));
286 /* restore history direction */
287 if (WIDGET (query_dlg)->y < hd->y)
288 z = g_list_reverse (z);
290 dlg_destroy (query_dlg);
292 hd->list = g_list_first (hd->list);
293 g_list_free_full (hd->list, hd->free);
294 hd->list = g_list_last (z);
297 /* --------------------------------------------------------------------------------------------- */