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-2020
   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     Widget *w = WIDGET (view);
  82     WDialog *h = DIALOG (w->owner);
  83     WButtonBar *b;
  84     const global_keymap_t *keymap = view->mode_flags.hex ? view->hex_keymap : w->keymap;
  85 
  86     b = find_buttonbar (h);
  87     buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), keymap, w);
  88 
  89     if (view->mode_flags.hex)
  90     {
  91         if (view->hexedit_mode)
  92             buttonbar_set_label (b, 2, Q_ ("ButtonBar|View"), keymap, w);
  93         else if (view->datasource == DS_FILE)
  94             buttonbar_set_label (b, 2, Q_ ("ButtonBar|Edit"), keymap, w);
  95         else
  96             buttonbar_set_label (b, 2, "", keymap, WIDGET (view));
  97 
  98         buttonbar_set_label (b, 4, Q_ ("ButtonBar|Ascii"), keymap, w);
  99         buttonbar_set_label (b, 6, Q_ ("ButtonBar|Save"), keymap, w);
 100         buttonbar_set_label (b, 7, Q_ ("ButtonBar|HxSrch"), keymap, w);
 101 
 102     }
 103     else
 104     {
 105         buttonbar_set_label (b, 2, view->mode_flags.wrap ? Q_ ("ButtonBar|UnWrap")
 106                              : Q_ ("ButtonBar|Wrap"), keymap, w);
 107         buttonbar_set_label (b, 4, Q_ ("ButtonBar|Hex"), keymap, w);
 108         buttonbar_set_label (b, 6, "", keymap, WIDGET (view));
 109         buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), keymap, w);
 110     }
 111 
 112     buttonbar_set_label (b, 5, Q_ ("ButtonBar|Goto"), keymap, w);
 113     buttonbar_set_label (b, 8, view->mode_flags.magic ? Q_ ("ButtonBar|Raw")
 114                          : Q_ ("ButtonBar|Parse"), keymap, w);
 115 
 116     if (!mcview_is_in_panel (view))     /* don't override some panel buttonbar keys  */
 117     {
 118         buttonbar_set_label (b, 3, Q_ ("ButtonBar|Quit"), keymap, w);
 119         buttonbar_set_label (b, 9, view->mode_flags.nroff ? Q_ ("ButtonBar|Unform")
 120                              : Q_ ("ButtonBar|Format"), keymap, w);
 121         buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), keymap, w);
 122     }
 123 }
 124 
 125 /* --------------------------------------------------------------------------------------------- */
 126 
 127 static void
 128 mcview_display_percent (WView * view, off_t p)
     /* [previous][next][first][last][top][bottom][index][help]  */
 129 {
 130     int percent;
 131 
 132     percent = mcview_calc_percent (view, p);
 133     if (percent >= 0)
 134     {
 135         const screen_dimen top = view->status_area.top;
 136         const screen_dimen right = view->status_area.left + view->status_area.width;
 137 
 138         widget_gotoyx (view, top, right - 4);
 139         tty_printf ("%3d%%", percent);
 140         /* avoid cursor wrapping in NCurses-base MC */
 141         widget_gotoyx (view, top, right - 1);
 142     }
 143 }
 144 
 145 /* --------------------------------------------------------------------------------------------- */
 146 
 147 static void
 148 mcview_display_status (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 149 {
 150     const screen_dimen top = view->status_area.top;
 151     const screen_dimen left = view->status_area.left;
 152     const screen_dimen width = view->status_area.width;
 153     const screen_dimen height = view->status_area.height;
 154     const char *file_label;
 155 
 156     if (height < 1)
 157         return;
 158 
 159     tty_setcolor (STATUSBAR_COLOR);
 160     tty_draw_hline (WIDGET (view)->y + top, WIDGET (view)->x + left, ' ', width);
 161 
 162     file_label =
 163         view->filename_vpath != NULL ?
 164         vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ?
 165         view->command : "";
 166 
 167     if (width > 40)
 168     {
 169         widget_gotoyx (view, top, width - 32);
 170         if (view->mode_flags.hex)
 171             tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
 172         else
 173         {
 174             char buffer[BUF_TRUNC_LEN + 1];
 175 
 176             size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0,
 177                             panels_options.kilobyte_si);
 178             tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
 179                         buffer, mcview_may_still_grow (view) ? "+" : " ",
 180 #ifdef HAVE_CHARSET
 181                         mc_global.source_codepage >= 0 ?
 182                         get_codepage_id (mc_global.source_codepage) :
 183 #endif
 184                         "");
 185         }
 186     }
 187     widget_gotoyx (view, top, left);
 188     if (width > 40)
 189         tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
 190     else
 191         tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
 192     if (width > 26)
 193         mcview_display_percent (view, view->mode_flags.hex ? view->hex_cursor : view->dpy_end);
 194 }
 195 
 196 /* --------------------------------------------------------------------------------------------- */
 197 /*** public functions ****************************************************************************/
 198 /* --------------------------------------------------------------------------------------------- */
 199 
 200 void
 201 mcview_update (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 202 {
 203     static int dirt_limit = 1;
 204 
 205     if (view->dpy_bbar_dirty)
 206     {
 207         view->dpy_bbar_dirty = FALSE;
 208         mcview_set_buttonbar (view);
 209         widget_draw (WIDGET (find_buttonbar (DIALOG (WIDGET (view)->owner))));
 210     }
 211 
 212     if (view->dirty > dirt_limit)
 213     {
 214         /* Too many updates skipped -> force a update */
 215         mcview_display (view);
 216         view->dirty = 0;
 217         /* Raise the update skipping limit */
 218         dirt_limit++;
 219         if (dirt_limit > mcview_max_dirt_limit)
 220             dirt_limit = mcview_max_dirt_limit;
 221     }
 222     else if (view->dirty > 0)
 223     {
 224         if (is_idle ())
 225         {
 226             /* We have time to update the screen properly */
 227             mcview_display (view);
 228             view->dirty = 0;
 229             if (dirt_limit > 1)
 230                 dirt_limit--;
 231         }
 232         else
 233         {
 234             /* We are busy -> skipping full update,
 235                only the status line is updated */
 236             mcview_display_status (view);
 237         }
 238         /* Here we had a refresh, if fast scrolling does not work
 239            restore the refresh, although this should not happen */
 240     }
 241 }
 242 
 243 /* --------------------------------------------------------------------------------------------- */
 244 /** Displays as much data from view->dpy_start as fits on the screen */
 245 
 246 void
 247 mcview_display (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 248 {
 249     if (view->mode_flags.hex)
 250         mcview_display_hex (view);
 251     else
 252         mcview_display_text (view);
 253     mcview_display_status (view);
 254 }
 255 
 256 /* --------------------------------------------------------------------------------------------- */
 257 
 258 void
 259 mcview_compute_areas (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 260 {
 261     struct area view_area;
 262     screen_dimen height, rest, y;
 263 
 264     /* The viewer is surrounded by a frame of size view->dpy_frame_size.
 265      * Inside that frame, there are: The status line (at the top),
 266      * the data area and an optional ruler, which is shown above or
 267      * below the data area. */
 268 
 269     view_area.top = view->dpy_frame_size;
 270     view_area.left = view->dpy_frame_size;
 271     view_area.height = mcview_dimen_doz (WIDGET (view)->lines, 2 * view->dpy_frame_size);
 272     view_area.width = mcview_dimen_doz (WIDGET (view)->cols, 2 * view->dpy_frame_size);
 273 
 274     /* Most coordinates of the areas equal those of the whole viewer */
 275     view->status_area = view_area;
 276     view->ruler_area = view_area;
 277     view->data_area = view_area;
 278 
 279     /* Compute the heights of the areas */
 280     rest = view_area.height;
 281 
 282     height = MIN (rest, 1);
 283     view->status_area.height = height;
 284     rest -= height;
 285 
 286     height = (ruler == RULER_NONE || view->mode_flags.hex) ? 0 : 2;
 287     height = MIN (rest, height);
 288     view->ruler_area.height = height;
 289     rest -= height;
 290 
 291     view->data_area.height = rest;
 292 
 293     /* Compute the position of the areas */
 294     y = view_area.top;
 295 
 296     view->status_area.top = y;
 297     y += view->status_area.height;
 298 
 299     if (ruler == RULER_TOP)
 300     {
 301         view->ruler_area.top = y;
 302         y += view->ruler_area.height;
 303     }
 304 
 305     view->data_area.top = y;
 306     y += view->data_area.height;
 307 
 308     if (ruler == RULER_BOTTOM)
 309         view->ruler_area.top = y;
 310 }
 311 
 312 /* --------------------------------------------------------------------------------------------- */
 313 
 314 void
 315 mcview_update_bytes_per_line (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 316 {
 317     const screen_dimen cols = view->data_area.width;
 318     int bytes;
 319 
 320     if (cols < 9 + 17)
 321         bytes = 4;
 322     else
 323         bytes = 4 * ((cols - 9) / ((cols <= 80) ? 17 : 18));
 324 
 325     g_assert (bytes != 0);
 326 
 327     view->bytes_per_line = bytes;
 328     view->dirty = mcview_max_dirt_limit + 1;    /* To force refresh */
 329 }
 330 
 331 /* --------------------------------------------------------------------------------------------- */
 332 
 333 void
 334 mcview_display_toggle_ruler (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 335 {
 336     static const enum ruler_type next[3] =
 337     {
 338         RULER_TOP,
 339         RULER_BOTTOM,
 340         RULER_NONE
 341     };
 342 
 343     g_assert ((size_t) ruler < 3);
 344 
 345     ruler = next[(size_t) ruler];
 346     mcview_compute_areas (view);
 347     view->dirty++;
 348 }
 349 
 350 /* --------------------------------------------------------------------------------------------- */
 351 
 352 void
 353 mcview_display_clean (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 354 {
 355     Widget *w = WIDGET (view);
 356 
 357     tty_setcolor (VIEW_NORMAL_COLOR);
 358     widget_erase (w);
 359     if (view->dpy_frame_size != 0)
 360         tty_draw_box (w->y, w->x, w->lines, w->cols, FALSE);
 361 }
 362 
 363 /* --------------------------------------------------------------------------------------------- */
 364 
 365 void
 366 mcview_display_ruler (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 367 {
 368     static const char ruler_chars[] = "|----*----";
 369     const screen_dimen top = view->ruler_area.top;
 370     const screen_dimen left = view->ruler_area.left;
 371     const screen_dimen width = view->ruler_area.width;
 372     const screen_dimen height = view->ruler_area.height;
 373     const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
 374     const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
 375 
 376     char r_buff[10];
 377     off_t cl;
 378     screen_dimen c;
 379 
 380     if (ruler == RULER_NONE || height < 1)
 381         return;
 382 
 383     tty_setcolor (VIEW_BOLD_COLOR);
 384     for (c = 0; c < width; c++)
 385     {
 386         cl = view->dpy_text_column + c;
 387         if (line_row < height)
 388         {
 389             widget_gotoyx (view, top + line_row, left + c);
 390             tty_print_char (ruler_chars[cl % 10]);
 391         }
 392 
 393         if ((cl != 0) && (cl % 10) == 0)
 394         {
 395             g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl);
 396             if (nums_row < height)
 397             {
 398                 widget_gotoyx (view, top + nums_row, left + c - 1);
 399                 tty_print_string (r_buff);
 400             }
 401         }
 402     }
 403     tty_setcolor (VIEW_NORMAL_COLOR);
 404 }
 405 
 406 /* --------------------------------------------------------------------------------------------- */

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