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     {
 339         RULER_TOP,
 340         RULER_BOTTOM,
 341         RULER_NONE
 342     };
 343 
 344     g_assert ((size_t) ruler < 3);
 345 
 346     ruler = next[(size_t) ruler];
 347     mcview_compute_areas (view);
 348     view->dirty++;
 349 }
 350 
 351 /* --------------------------------------------------------------------------------------------- */
 352 
 353 void
 354 mcview_display_clean (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 355 {
 356     Widget *w = WIDGET (view);
 357 
 358     tty_setcolor (VIEW_NORMAL_COLOR);
 359     widget_erase (w);
 360     if (view->dpy_frame_size != 0)
 361         tty_draw_box (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, FALSE);
 362 }
 363 
 364 /* --------------------------------------------------------------------------------------------- */
 365 
 366 void
 367 mcview_display_ruler (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 368 {
 369     static const char ruler_chars[] = "|----*----";
 370     const WRect *r = &view->ruler_area;
 371     const int line_row = (ruler == RULER_TOP) ? 0 : 1;
 372     const int nums_row = (ruler == RULER_TOP) ? 1 : 0;
 373 
 374     char r_buff[10];
 375     off_t cl;
 376     int c;
 377 
 378     if (ruler == RULER_NONE || r->lines < 1)
 379         return;
 380 
 381     tty_setcolor (VIEW_BOLD_COLOR);
 382     for (c = 0; c < r->cols; c++)
 383     {
 384         cl = view->dpy_text_column + c;
 385         if (line_row < r->lines)
 386         {
 387             widget_gotoyx (view, r->y + line_row, r->x + 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 < r->lines)
 395             {
 396                 widget_gotoyx (view, r->y + nums_row, r->x + 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]  */