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

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