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-2019
   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 
  74     /* guard checks */
  75     if ((dlg_head == NULL) || (dlg_head->data == NULL))
  76         return MSG_NOT_HANDLED;
  77 
  78     data = (history_dlg_data *) dlg_head->data;
  79 
  80     y = data->y;
  81     he = data->count + 2;
  82 
  83     if (he <= y || y > (LINES - 6))
  84     {
  85         he = MIN (he, y - 1);
  86         y -= he;
  87     }
  88     else
  89     {
  90         y++;
  91         he = MIN (he, LINES - y);
  92     }
  93 
  94     if (data->x > 2)
  95         x = data->x - 2;
  96 
  97     wi = data->max_width + 4;
  98 
  99     if ((wi + x) > COLS)
 100     {
 101         wi = MIN (wi, COLS);
 102         x = COLS - wi;
 103     }
 104 
 105     dlg_set_position (dlg_head, y, x, he, wi);
 106 
 107     return MSG_HANDLED;
 108 }
 109 
 110 /* --------------------------------------------------------------------------------------------- */
 111 
 112 static cb_ret_t
 113 history_dlg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 114 {
 115     switch (msg)
 116     {
 117     case MSG_RESIZE:
 118         return history_dlg_reposition (DIALOG (w));
 119 
 120     case MSG_NOTIFY:
 121         {
 122             /* message from listbox */
 123             WDialog *d = DIALOG (w);
 124 
 125             switch (parm)
 126             {
 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;
 138             }
 139 
 140             dlg_stop (d);
 141             return MSG_HANDLED;
 142         }
 143 
 144     default:
 145         return dlg_default_callback (w, sender, msg, parm, data);
 146     }
 147 }
 148 
 149 /* --------------------------------------------------------------------------------------------- */
 150 
 151 static void
 152 history_create_item (history_descriptor_t * hd, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 153 {
 154     char *text = (char *) data;
 155     size_t width;
 156 
 157     width = str_term_width1 (text);
 158     hd->max_width = MAX (width, hd->max_width);
 159 
 160     listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, text, NULL, TRUE);
 161 }
 162 
 163 /* --------------------------------------------------------------------------------------------- */
 164 
 165 static void *
 166 history_release_item (history_descriptor_t * hd, WLEntry * le)
     /* [previous][next][first][last][top][bottom][index][help]  */
 167 {
 168     void *text;
 169 
 170     (void) hd;
 171 
 172     text = le->text;
 173     le->text = NULL;
 174 
 175     return text;
 176 }
 177 
 178 /* --------------------------------------------------------------------------------------------- */
 179 /*** public functions ****************************************************************************/
 180 /* --------------------------------------------------------------------------------------------- */
 181 
 182 void
 183 history_descriptor_init (history_descriptor_t * hd, int y, int x, GList * history, int current)
     /* [previous][next][first][last][top][bottom][index][help]  */
 184 {
 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;
 197 }
 198 
 199 /* --------------------------------------------------------------------------------------------- */
 200 
 201 void
 202 history_show (history_descriptor_t * hd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 203 {
 204     GList *z, *hi;
 205     size_t count;
 206     WDialog *query_dlg;
 207     history_dlg_data hist_data;
 208     int dlg_ret;
 209 
 210     if (hd == NULL || hd->list == NULL)
 211         return;
 212 
 213     hd->max_width = str_term_width1 (_("History")) + 2;
 214 
 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 */
 218 
 219     count = listbox_get_length (hd->listbox);
 220 
 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;
 225 
 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;
 230 
 231     /* this call makes list stick to all sides of dialog, effectively make
 232        it be resized with dialog */
 233     add_widget_autopos (query_dlg, hd->listbox, WPOS_KEEP_ALL, NULL);
 234 
 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);
 241 
 242     if (WIDGET (query_dlg)->y < hd->y)
 243     {
 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);
 251     }
 252     else
 253     {
 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);
 257     }
 258 
 259     dlg_ret = dlg_run (query_dlg);
 260     if (dlg_ret != B_CANCEL)
 261     {
 262         char *q;
 263 
 264         switch (dlg_ret)
 265         {
 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;
 274         }
 275 
 276         listbox_get_current (hd->listbox, &q, NULL);
 277         hd->text = g_strdup (q);
 278     }
 279 
 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)));
 285 
 286     /* restore history direction */
 287     if (WIDGET (query_dlg)->y < hd->y)
 288         z = g_list_reverse (z);
 289 
 290     dlg_destroy (query_dlg);
 291 
 292     hd->list = g_list_first (hd->list);
 293     g_list_free_full (hd->list, hd->free);
 294     hd->list = g_list_last (z);
 295 }
 296 
 297 /* --------------------------------------------------------------------------------------------- */

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