root/src/viewer/display.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcview_set_buttonbar
  2. mcview_display_percent
  3. mcview_display_status
  4. mcview_update
  5. mcview_display
  6. mcview_compute_areas
  7. mcview_update_bytes_per_line
  8. mcview_display_toggle_ruler
  9. mcview_display_clean
  10. mcview_display_ruler

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Function for whow info on display
   4 
   5    Copyright (C) 1994-2019
   6    Free Software Foundation, Inc.
   7 
   8    Written by:
   9    Miguel de Icaza, 1994, 1995, 1998
  10    Janne Kukonlehto, 1994, 1995
  11    Jakub Jelinek, 1995
  12    Joseph M. Hinkle, 1996
  13    Norbert Warmuth, 1997
  14    Pavel Machek, 1998
  15    Roland Illig <roland.illig@gmx.de>, 2004, 2005
  16    Slava Zanko <slavazanko@google.com>, 2009
  17    Andrew Borodin <aborodin@vmail.ru>, 2009, 2013
  18    Ilia Maslakov <il.smind@gmail.com>, 2009, 2010
  19 
  20    This file is part of the Midnight Commander.
  21 
  22    The Midnight Commander is free software: you can redistribute it
  23    and/or modify it under the terms of the GNU General Public License as
  24    published by the Free Software Foundation, either version 3 of the License,
  25    or (at your option) any later version.
  26 
  27    The Midnight Commander is distributed in the hope that it will be useful,
  28    but WITHOUT ANY WARRANTY; without even the implied warranty of
  29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  30    GNU General Public License for more details.
  31 
  32    You should have received a copy of the GNU General Public License
  33    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  34  */
  35 
  36 #include <config.h>
  37 #include <inttypes.h>           /* uintmax_t */
  38 
  39 #include "lib/global.h"
  40 #include "lib/skin.h"
  41 #include "lib/tty/tty.h"
  42 #include "lib/tty/key.h"
  43 #include "lib/strutil.h"
  44 #include "lib/util.h"
  45 #include "lib/widget.h"
  46 #ifdef HAVE_CHARSET
  47 #include "lib/charsets.h"
  48 #endif
  49 
  50 #include "src/setup.h"          /* panels_options */
  51 #include "src/keybind-defaults.h"
  52 
  53 #include "internal.h"
  54 
  55 /*** global variables ****************************************************************************/
  56 
  57 /*** file scope macro definitions ****************************************************************/
  58 
  59 #define BUF_TRUNC_LEN 5         /* The length of the line displays the file size */
  60 
  61 /*** file scope type declarations ****************************************************************/
  62 
  63 /*** file scope variables ************************************************************************/
  64 
  65 /* If set, show a ruler */
  66 static enum ruler_type
  67 {
  68     RULER_NONE,
  69     RULER_TOP,
  70     RULER_BOTTOM
  71 } ruler = RULER_NONE;
  72 
  73 /*** file scope functions ************************************************************************/
  74 /* --------------------------------------------------------------------------------------------- */
  75 
  76 /** Define labels and handlers for functional keys */
  77 
  78 static void
  79 mcview_set_buttonbar (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  80 {
  81     WDialog *h = WIDGET (view)->owner;
  82     WButtonBar *b = find_buttonbar (h);
  83     const global_keymap_t *keymap = view->mode_flags.hex ? viewer_hex_map : viewer_map;
  84 
  85     buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), keymap, WIDGET (view));
  86 
  87     if (view->mode_flags.hex)
  88     {
  89         if (view->hexedit_mode)
  90             buttonbar_set_label (b, 2, Q_ ("ButtonBar|View"), keymap, WIDGET (view));
  91         else if (view->datasource == DS_FILE)
  92             buttonbar_set_label (b, 2, Q_ ("ButtonBar|Edit"), keymap, WIDGET (view));
  93         else
  94             buttonbar_set_label (b, 2, "", keymap, WIDGET (view));
  95 
  96         buttonbar_set_label (b, 4, Q_ ("ButtonBar|Ascii"), keymap, WIDGET (view));
  97         buttonbar_set_label (b, 6, Q_ ("ButtonBar|Save"), keymap, WIDGET (view));
  98         buttonbar_set_label (b, 7, Q_ ("ButtonBar|HxSrch"), keymap, WIDGET (view));
  99 
 100     }
 101     else
 102     {
 103         buttonbar_set_label (b, 2, view->mode_flags.wrap ? Q_ ("ButtonBar|UnWrap")
 104                              : Q_ ("ButtonBar|Wrap"), keymap, WIDGET (view));
 105         buttonbar_set_label (b, 4, Q_ ("ButtonBar|Hex"), keymap, WIDGET (view));
 106         buttonbar_set_label (b, 6, "", keymap, WIDGET (view));
 107         buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), keymap, WIDGET (view));
 108     }
 109 
 110     buttonbar_set_label (b, 5, Q_ ("ButtonBar|Goto"), keymap, WIDGET (view));
 111     buttonbar_set_label (b, 8, view->mode_flags.magic ? Q_ ("ButtonBar|Raw")
 112                          : Q_ ("ButtonBar|Parse"), keymap, WIDGET (view));
 113 
 114     if (!mcview_is_in_panel (view))     /* don't override some panel buttonbar keys  */
 115     {
 116         buttonbar_set_label (b, 3, Q_ ("ButtonBar|Quit"), keymap, WIDGET (view));
 117         buttonbar_set_label (b, 9, view->mode_flags.nroff ? Q_ ("ButtonBar|Unform")
 118                              : Q_ ("ButtonBar|Format"), keymap, WIDGET (view));
 119         buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), keymap, WIDGET (view));
 120     }
 121 }
 122 
 123 /* --------------------------------------------------------------------------------------------- */
 124 
 125 static void
 126 mcview_display_percent (WView * view, off_t p)
     /* [previous][next][first][last][top][bottom][index][help]  */
 127 {
 128     int percent;
 129 
 130     percent = mcview_calc_percent (view, p);
 131     if (percent >= 0)
 132     {
 133         const screen_dimen top = view->status_area.top;
 134         const screen_dimen right = view->status_area.left + view->status_area.width;
 135 
 136         widget_move (view, top, right - 4);
 137         tty_printf ("%3d%%", percent);
 138         /* avoid cursor wrapping in NCurses-base MC */
 139         widget_move (view, top, right - 1);
 140     }
 141 }
 142 
 143 /* --------------------------------------------------------------------------------------------- */
 144 
 145 static void
 146 mcview_display_status (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 147 {
 148     const screen_dimen top = view->status_area.top;
 149     const screen_dimen left = view->status_area.left;
 150     const screen_dimen width = view->status_area.width;
 151     const screen_dimen height = view->status_area.height;
 152     const char *file_label;
 153 
 154     if (height < 1)
 155         return;
 156 
 157     tty_setcolor (STATUSBAR_COLOR);
 158     tty_draw_hline (WIDGET (view)->y + top, WIDGET (view)->x + left, ' ', width);
 159 
 160     file_label =
 161         view->filename_vpath != NULL ?
 162         vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ?
 163         view->command : "";
 164 
 165     if (width > 40)
 166     {
 167         widget_move (view, top, width - 32);
 168         if (view->mode_flags.hex)
 169             tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
 170         else
 171         {
 172             char buffer[BUF_TRUNC_LEN + 1];
 173 
 174             size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0,
 175                             panels_options.kilobyte_si);
 176             tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
 177                         buffer, mcview_may_still_grow (view) ? "+" : " ",
 178 #ifdef HAVE_CHARSET
 179                         mc_global.source_codepage >= 0 ?
 180                         get_codepage_id (mc_global.source_codepage) :
 181 #endif
 182                         "");
 183         }
 184     }
 185     widget_move (view, top, left);
 186     if (width > 40)
 187         tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
 188     else
 189         tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
 190     if (width > 26)
 191         mcview_display_percent (view, view->mode_flags.hex ? view->hex_cursor : view->dpy_end);
 192 }
 193 
 194 /* --------------------------------------------------------------------------------------------- */
 195 /*** public functions ****************************************************************************/
 196 /* --------------------------------------------------------------------------------------------- */
 197 
 198 void
 199 mcview_update (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 200 {
 201     static int dirt_limit = 1;
 202 
 203     if (view->dpy_bbar_dirty)
 204     {
 205         view->dpy_bbar_dirty = FALSE;
 206         mcview_set_buttonbar (view);
 207         widget_redraw (WIDGET (find_buttonbar (WIDGET (view)->owner)));
 208     }
 209 
 210     if (view->dirty > dirt_limit)
 211     {
 212         /* Too many updates skipped -> force a update */
 213         mcview_display (view);
 214         view->dirty = 0;
 215         /* Raise the update skipping limit */
 216         dirt_limit++;
 217         if (dirt_limit > mcview_max_dirt_limit)
 218             dirt_limit = mcview_max_dirt_limit;
 219     }
 220     else if (view->dirty > 0)
 221     {
 222         if (is_idle ())
 223         {
 224             /* We have time to update the screen properly */
 225             mcview_display (view);
 226             view->dirty = 0;
 227             if (dirt_limit > 1)
 228                 dirt_limit--;
 229         }
 230         else
 231         {
 232             /* We are busy -> skipping full update,
 233                only the status line is updated */
 234             mcview_display_status (view);
 235         }
 236         /* Here we had a refresh, if fast scrolling does not work
 237            restore the refresh, although this should not happen */
 238     }
 239 }
 240 
 241 /* --------------------------------------------------------------------------------------------- */
 242 /** Displays as much data from view->dpy_start as fits on the screen */
 243 
 244 void
 245 mcview_display (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 246 {
 247     if (view->mode_flags.hex)
 248         mcview_display_hex (view);
 249     else
 250         mcview_display_text (view);
 251     mcview_display_status (view);
 252 }
 253 
 254 /* --------------------------------------------------------------------------------------------- */
 255 
 256 void
 257 mcview_compute_areas (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 258 {
 259     struct area view_area;
 260     screen_dimen height, rest, y;
 261 
 262     /* The viewer is surrounded by a frame of size view->dpy_frame_size.
 263      * Inside that frame, there are: The status line (at the top),
 264      * the data area and an optional ruler, which is shown above or
 265      * below the data area. */
 266 
 267     view_area.top = view->dpy_frame_size;
 268     view_area.left = view->dpy_frame_size;
 269     view_area.height = mcview_dimen_doz (WIDGET (view)->lines, 2 * view->dpy_frame_size);
 270     view_area.width = mcview_dimen_doz (WIDGET (view)->cols, 2 * view->dpy_frame_size);
 271 
 272     /* Most coordinates of the areas equal those of the whole viewer */
 273     view->status_area = view_area;
 274     view->ruler_area = view_area;
 275     view->data_area = view_area;
 276 
 277     /* Compute the heights of the areas */
 278     rest = view_area.height;
 279 
 280     height = MIN (rest, 1);
 281     view->status_area.height = height;
 282     rest -= height;
 283 
 284     height = (ruler == RULER_NONE || view->mode_flags.hex) ? 0 : 2;
 285     height = MIN (rest, height);
 286     view->ruler_area.height = height;
 287     rest -= height;
 288 
 289     view->data_area.height = rest;
 290 
 291     /* Compute the position of the areas */
 292     y = view_area.top;
 293 
 294     view->status_area.top = y;
 295     y += view->status_area.height;
 296 
 297     if (ruler == RULER_TOP)
 298     {
 299         view->ruler_area.top = y;
 300         y += view->ruler_area.height;
 301     }
 302 
 303     view->data_area.top = y;
 304     y += view->data_area.height;
 305 
 306     if (ruler == RULER_BOTTOM)
 307         view->ruler_area.top = y;
 308 }
 309 
 310 /* --------------------------------------------------------------------------------------------- */
 311 
 312 void
 313 mcview_update_bytes_per_line (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 314 {
 315     const screen_dimen cols = view->data_area.width;
 316     int bytes;
 317 
 318     if (cols < 9 + 17)
 319         bytes = 4;
 320     else
 321         bytes = 4 * ((cols - 9) / ((cols <= 80) ? 17 : 18));
 322 
 323     g_assert (bytes != 0);
 324 
 325     view->bytes_per_line = bytes;
 326     view->dirty = mcview_max_dirt_limit + 1;    /* To force refresh */
 327 }
 328 
 329 /* --------------------------------------------------------------------------------------------- */
 330 
 331 void
 332 mcview_display_toggle_ruler (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 333 {
 334     static const enum ruler_type next[3] =
 335     {
 336         RULER_TOP,
 337         RULER_BOTTOM,
 338         RULER_NONE
 339     };
 340 
 341     g_assert ((size_t) ruler < 3);
 342 
 343     ruler = next[(size_t) ruler];
 344     mcview_compute_areas (view);
 345     view->dirty++;
 346 }
 347 
 348 /* --------------------------------------------------------------------------------------------- */
 349 
 350 void
 351 mcview_display_clean (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 352 {
 353     Widget *w = WIDGET (view);
 354 
 355     tty_setcolor (VIEW_NORMAL_COLOR);
 356     widget_erase (w);
 357     if (view->dpy_frame_size != 0)
 358         tty_draw_box (w->y, w->x, w->lines, w->cols, FALSE);
 359 }
 360 
 361 /* --------------------------------------------------------------------------------------------- */
 362 
 363 void
 364 mcview_display_ruler (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 365 {
 366     static const char ruler_chars[] = "|----*----";
 367     const screen_dimen top = view->ruler_area.top;
 368     const screen_dimen left = view->ruler_area.left;
 369     const screen_dimen width = view->ruler_area.width;
 370     const screen_dimen height = view->ruler_area.height;
 371     const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
 372     const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
 373 
 374     char r_buff[10];
 375     off_t cl;
 376     screen_dimen c;
 377 
 378     if (ruler == RULER_NONE || height < 1)
 379         return;
 380 
 381     tty_setcolor (VIEW_BOLD_COLOR);
 382     for (c = 0; c < width; c++)
 383     {
 384         cl = view->dpy_text_column + c;
 385         if (line_row < height)
 386         {
 387             widget_move (view, top + line_row, left + c);
 388             tty_print_char (ruler_chars[cl % 10]);
 389         }
 390 
 391         if ((cl != 0) && (cl % 10) == 0)
 392         {
 393             g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl);
 394             if (nums_row < height)
 395             {
 396                 widget_move (view, top + nums_row, left + c - 1);
 397                 tty_print_string (r_buff);
 398             }
 399         }
 400     }
 401     tty_setcolor (VIEW_NORMAL_COLOR);
 402 }
 403 
 404 /* --------------------------------------------------------------------------------------------- */

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