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-2020
   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-2019
  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 /*** file scope variables ************************************************************************/
  65 
  66 /*** file scope functions ************************************************************************/
  67 
  68 static cb_ret_t
  69 history_dlg_reposition (WDialog * dlg_head)
     /* [previous][next][first][last][top][bottom][index][help]  */
  70 {
  71     history_dlg_data *data;
  72     int x = 0, y, he, wi;
  73     WRect r;
  74 
  75     /* guard checks */
  76     if ((dlg_head == NULL) || (dlg_head->data == NULL))
  77         return MSG_NOT_HANDLED;
  78 
  79     data = (history_dlg_data *) dlg_head->data;
  80 
  81     y = data->y;
  82     he = data->count + 2;
  83 
  84     if (he <= y || y > (LINES - 6))
  85     {
  86         he = MIN (he, y - 1);
  87         y -= he;
  88     }
  89     else
  90     {
  91         y++;
  92         he = MIN (he, LINES - y);
  93     }
  94 
  95     if (data->x > 2)
  96         x = data->x - 2;
  97 
  98     wi = data->max_width + 4;
  99 
 100     if ((wi + x) > COLS)
 101     {
 102         wi = MIN (wi, COLS);
 103         x = COLS - wi;
 104     }
 105 
 106     rect_init (&r, y, x, he, wi);
 107 
 108     return dlg_default_callback (WIDGET (dlg_head), NULL, MSG_RESIZE, 0, &r);
 109 }
 110 
 111 /* --------------------------------------------------------------------------------------------- */
 112 
 113 static cb_ret_t
 114 history_dlg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 115 {
 116     switch (msg)
 117     {
 118     case MSG_RESIZE:
 119         return history_dlg_reposition (DIALOG (w));
 120 
 121     case MSG_NOTIFY:
 122         {
 123             /* message from listbox */
 124             WDialog *d = DIALOG (w);
 125 
 126             switch (parm)
 127             {
 128             case CK_View:
 129                 d->ret_value = B_VIEW;
 130                 break;
 131             case CK_Edit:
 132                 d->ret_value = B_EDIT;
 133                 break;
 134             case CK_Enter:
 135                 d->ret_value = B_ENTER;
 136                 break;
 137             default:
 138                 return MSG_NOT_HANDLED;
 139             }
 140 
 141             dlg_stop (d);
 142             return MSG_HANDLED;
 143         }
 144 
 145     default:
 146         return dlg_default_callback (w, sender, msg, parm, data);
 147     }
 148 }
 149 
 150 /* --------------------------------------------------------------------------------------------- */
 151 
 152 static void
 153 history_create_item (history_descriptor_t * hd, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 154 {
 155     char *text = (char *) data;
 156     size_t width;
 157 
 158     width = str_term_width1 (text);
 159     hd->max_width = MAX (width, hd->max_width);
 160 
 161     listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE);
 162 }
 163 
 164 /* --------------------------------------------------------------------------------------------- */
 165 
 166 static void *
 167 history_release_item (history_descriptor_t * hd, WLEntry * le)
     /* [previous][next][first][last][top][bottom][index][help]  */
 168 {
 169     void *text;
 170 
 171     (void) hd;
 172 
 173     text = le->text;
 174     le->text = NULL;
 175 
 176     return text;
 177 }
 178 
 179 /* --------------------------------------------------------------------------------------------- */
 180 /*** public functions ****************************************************************************/
 181 /* --------------------------------------------------------------------------------------------- */
 182 
 183 void
 184 history_descriptor_init (history_descriptor_t * hd, int y, int x, GList * history, int current)
     /* [previous][next][first][last][top][bottom][index][help]  */
 185 {
 186     hd->list = history;
 187     hd->y = y;
 188     hd->x = x;
 189     hd->current = current;
 190     hd->action = CK_IgnoreKey;
 191     hd->text = NULL;
 192     hd->max_width = 0;
 193     hd->listbox = listbox_new (1, 1, 2, 2, TRUE, NULL);
 194     /* in most cases history list contains string only and no any other data */
 195     hd->create = history_create_item;
 196     hd->release = history_release_item;
 197     hd->free = g_free;
 198 }
 199 
 200 /* --------------------------------------------------------------------------------------------- */
 201 
 202 void
 203 history_show (history_descriptor_t * hd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 204 {
 205     GList *z, *hi;
 206     size_t count;
 207     WDialog *query_dlg;
 208     history_dlg_data hist_data;
 209     int dlg_ret;
 210 
 211     if (hd == NULL || hd->list == NULL)
 212         return;
 213 
 214     hd->max_width = str_term_width1 (_("History")) + 2;
 215 
 216     for (z = hd->list; z != NULL; z = g_list_previous (z))
 217         hd->create (hd, z->data);
 218     /* after this, the order of history items is following: recent at begin, oldest at end */
 219 
 220     count = listbox_get_length (hd->listbox);
 221 
 222     hist_data.y = hd->y;
 223     hist_data.x = hd->x;
 224     hist_data.count = count;
 225     hist_data.max_width = hd->max_width;
 226 
 227     query_dlg =
 228         dlg_create (TRUE, 0, 0, 4, 4, WPOS_KEEP_DEFAULT, TRUE, dialog_colors, history_dlg_callback,
 229                     NULL, "[History-query]", _("History"));
 230     query_dlg->data = &hist_data;
 231 
 232     /* this call makes list stick to all sides of dialog, effectively make
 233        it be resized with dialog */
 234     group_add_widget_autopos (GROUP (query_dlg), hd->listbox, WPOS_KEEP_ALL, NULL);
 235 
 236     /* to avoid diplicating of (calculating sizes in two places)
 237        code, call history_dlg_callback function here, to set dialog and
 238        controls positions.
 239        The main idea - create 4x4 dialog and add 2x2 list in
 240        center of it, and let dialog function resize it to needed size. */
 241     send_message (query_dlg, NULL, MSG_RESIZE, 0, NULL);
 242 
 243     if (WIDGET (query_dlg)->y < hd->y)
 244     {
 245         /* history is above base widget -- revert order to place recent item at bottom */
 246         /* revert history direction */
 247         g_queue_reverse (hd->listbox->list);
 248         if (hd->current < 0 || (size_t) hd->current >= count)
 249             listbox_select_last (hd->listbox);
 250         else
 251             listbox_select_entry (hd->listbox, count - 1 - (size_t) hd->current);
 252     }
 253     else
 254     {
 255         /* history is below base widget -- keep order to place recent item on top  */
 256         if (hd->current > 0)
 257             listbox_select_entry (hd->listbox, hd->current);
 258     }
 259 
 260     dlg_ret = dlg_run (query_dlg);
 261     if (dlg_ret != B_CANCEL)
 262     {
 263         char *q;
 264 
 265         switch (dlg_ret)
 266         {
 267         case B_EDIT:
 268             hd->action = CK_Edit;
 269             break;
 270         case B_VIEW:
 271             hd->action = CK_View;
 272             break;
 273         default:
 274             hd->action = CK_Enter;
 275         }
 276 
 277         listbox_get_current (hd->listbox, &q, NULL);
 278         hd->text = g_strdup (q);
 279     }
 280 
 281     /* get modified history from dialog */
 282     z = NULL;
 283     for (hi = listbox_get_first_link (hd->listbox); hi != NULL; hi = g_list_next (hi))
 284         /* history is being reverted here again */
 285         z = g_list_prepend (z, hd->release (hd, LENTRY (hi->data)));
 286 
 287     /* restore history direction */
 288     if (WIDGET (query_dlg)->y < hd->y)
 289         z = g_list_reverse (z);
 290 
 291     dlg_destroy (query_dlg);
 292 
 293     hd->list = g_list_first (hd->list);
 294     g_list_free_full (hd->list, hd->free);
 295     hd->list = g_list_last (z);
 296 }
 297 
 298 /* --------------------------------------------------------------------------------------------- */

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