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

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