root/lib/widget/history.c

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

DEFINITIONS

This source file includes following definitions.
  1. history_dlg_reposition
  2. history_dlg_callback
  3. history_create_item
  4. history_release_item
  5. history_descriptor_init
  6. history_show

   1 /*
   2    Widgets for the Midnight Commander
   3 
   4    Copyright (C) 1994-2024
   5    Free Software Foundation, Inc.
   6 
   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
  14 
  15    This file is part of the Midnight Commander.
  16 
  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.
  21 
  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.
  26 
  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/>.
  29  */
  30 
  31 /** \file history.c
  32  *  \brief Source: show history
  33  */
  34 
  35 #include <config.h>
  36 
  37 #include <stdlib.h>
  38 #include <sys/types.h>
  39 
  40 #include "lib/global.h"
  41 
  42 #include "lib/tty/tty.h"        /* LINES, COLS */
  43 #include "lib/strutil.h"
  44 #include "lib/widget.h"
  45 #include "lib/keybind.h"        /* CK_* */
  46 
  47 /*** global variables ****************************************************************************/
  48 
  49 /*** file scope macro definitions ****************************************************************/
  50 
  51 #define B_VIEW (B_USER + 1)
  52 #define B_EDIT (B_USER + 2)
  53 
  54 /*** file scope type declarations ****************************************************************/
  55 
  56 typedef struct
  57 {
  58     int y;
  59     int x;
  60     size_t count;
  61     size_t max_width;
  62 } history_dlg_data;
  63 
  64 /*** forward declarations (file scope functions) *************************************************/
  65 
  66 /*** file scope variables ************************************************************************/
  67 
  68 /* --------------------------------------------------------------------------------------------- */
  69 /*** file scope functions ************************************************************************/
  70 /* --------------------------------------------------------------------------------------------- */
  71 
  72 static cb_ret_t
  73 history_dlg_reposition (WDialog *dlg_head)
     /* [previous][next][first][last][top][bottom][index][help]  */
  74 {
  75     history_dlg_data *data;
  76     int x = 0, y, he, wi;
  77     WRect r;
  78 
  79     /* guard checks */
  80     if (dlg_head == NULL || dlg_head->data.p == NULL)
  81         return MSG_NOT_HANDLED;
  82 
  83     data = (history_dlg_data *) dlg_head->data.p;
  84 
  85     y = data->y;
  86     he = data->count + 2;
  87 
  88     if (he <= y || y > (LINES - 6))
  89     {
  90         he = MIN (he, y - 1);
  91         y -= he;
  92     }
  93     else
  94     {
  95         y++;
  96         he = MIN (he, LINES - y);
  97     }
  98 
  99     if (data->x > 2)
 100         x = data->x - 2;
 101 
 102     wi = data->max_width + 4;
 103 
 104     if ((wi + x) > COLS)
 105     {
 106         wi = MIN (wi, COLS);
 107         x = COLS - wi;
 108     }
 109 
 110     rect_init (&r, y, x, he, wi);
 111 
 112     return dlg_default_callback (WIDGET (dlg_head), NULL, MSG_RESIZE, 0, &r);
 113 }
 114 
 115 /* --------------------------------------------------------------------------------------------- */
 116 
 117 static cb_ret_t
 118 history_dlg_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 119 {
 120     switch (msg)
 121     {
 122     case MSG_RESIZE:
 123         return history_dlg_reposition (DIALOG (w));
 124 
 125     case MSG_NOTIFY:
 126         {
 127             /* message from listbox */
 128             WDialog *d = DIALOG (w);
 129 
 130             switch (parm)
 131             {
 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;
 143             }
 144 
 145             dlg_close (d);
 146             return MSG_HANDLED;
 147         }
 148 
 149     default:
 150         return dlg_default_callback (w, sender, msg, parm, data);
 151     }
 152 }
 153 
 154 /* --------------------------------------------------------------------------------------------- */
 155 
 156 static void
 157 history_create_item (history_descriptor_t *hd, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 158 {
 159     char *text = (char *) data;
 160     size_t width;
 161 
 162     width = str_term_width1 (text);
 163     hd->max_width = MAX (width, hd->max_width);
 164 
 165     listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE);
 166 }
 167 
 168 /* --------------------------------------------------------------------------------------------- */
 169 
 170 static void *
 171 history_release_item (history_descriptor_t *hd, WLEntry *le)
     /* [previous][next][first][last][top][bottom][index][help]  */
 172 {
 173     void *text;
 174 
 175     (void) hd;
 176 
 177     text = le->text;
 178     le->text = NULL;
 179 
 180     return text;
 181 }
 182 
 183 /* --------------------------------------------------------------------------------------------- */
 184 /*** public functions ****************************************************************************/
 185 /* --------------------------------------------------------------------------------------------- */
 186 
 187 void
 188 history_descriptor_init (history_descriptor_t *hd, int y, int x, GList *history, int current)
     /* [previous][next][first][last][top][bottom][index][help]  */
 189 {
 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;
 202 }
 203 
 204 /* --------------------------------------------------------------------------------------------- */
 205 
 206 void
 207 history_show (history_descriptor_t *hd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 208 {
 209     GList *z, *hi;
 210     size_t count;
 211     WDialog *query_dlg;
 212     history_dlg_data hist_data;
 213     int dlg_ret;
 214 
 215     if (hd == NULL || hd->list == NULL)
 216         return;
 217 
 218     hd->max_width = str_term_width1 (_("History")) + 2;
 219 
 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 */
 223 
 224     count = listbox_get_length (hd->listbox);
 225 
 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;
 230 
 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;
 235 
 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);
 239 
 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);
 246 
 247     if (WIDGET (query_dlg)->rect.y < hd->y)
 248     {
 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);
 256     }
 257     else
 258     {
 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);
 262     }
 263 
 264     dlg_ret = dlg_run (query_dlg);
 265     if (dlg_ret != B_CANCEL)
 266     {
 267         char *q;
 268 
 269         switch (dlg_ret)
 270         {
 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;
 279         }
 280 
 281         listbox_get_current (hd->listbox, &q, NULL);
 282         hd->text = g_strdup (q);
 283     }
 284 
 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)));
 290 
 291     /* restore history direction */
 292     if (WIDGET (query_dlg)->rect.y < hd->y)
 293         z = g_list_reverse (z);
 294 
 295     widget_destroy (WIDGET (query_dlg));
 296 
 297     hd->list = g_list_first (hd->list);
 298     g_list_free_full (hd->list, hd->free);
 299     hd->list = g_list_last (z);
 300 }
 301 
 302 /* --------------------------------------------------------------------------------------------- */

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