Manual pages: mcmcdiffmceditmcview

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

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