2 Internal file viewer for the Midnight Commander
3 Function for whow info on display
5 Copyright (C) 1994-2025
6 Free Software Foundation, Inc.
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
12 Joseph M. Hinkle, 1996
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
20 This file is part of the Midnight Commander.
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.
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.
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/>.
37 #include <inttypes.h> /* uintmax_t */
39 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/tty/key.h"
43 #include "lib/strutil.h"
45 #include "lib/widget.h"
47 #include "lib/charsets.h"
50 #include "src/setup.h" /* panels_options */
51 #include "src/keymap.h"
55 /*** global variables ****************************************************************************/
57 /*** file scope macro definitions ****************************************************************/
59 #define BUF_TRUNC_LEN 5 /* The length of the line displays the file size */
61 /*** file scope type declarations ****************************************************************/
63 /*** forward declarations (file scope functions) *************************************************/
65 /*** file scope variables ************************************************************************/
67 /* If set, show a ruler */
68 static enum ruler_type
75 /* --------------------------------------------------------------------------------------------- */
76 /*** file scope functions ************************************************************************/
77 /* --------------------------------------------------------------------------------------------- */
79 /** Define labels and handlers for functional keys */
82 mcview_set_buttonbar (WView
*view
)
84 Widget
*w
= WIDGET (view
);
85 WDialog
*h
= DIALOG (w
->owner
);
87 const global_keymap_t
*keymap
= view
->mode_flags
.hex
? view
->hex_keymap
: w
->keymap
;
89 b
= buttonbar_find (h
);
90 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), keymap
, w
);
92 if (view
->mode_flags
.hex
)
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
);
99 buttonbar_set_label (b
, 2, "", keymap
, WIDGET (view
));
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
);
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
);
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
);
119 if (!mcview_is_in_panel (view
)) /* don't override some panel buttonbar keys */
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
);
128 /* --------------------------------------------------------------------------------------------- */
131 mcview_display_percent (WView
*view
, off_t p
)
135 percent
= mcview_calc_percent (view
, p
);
138 int top
= view
->status_area
.y
;
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);
149 /* --------------------------------------------------------------------------------------------- */
152 mcview_display_status (WView
*view
)
154 const WRect
*r
= &view
->status_area
;
155 const char *file_label
;
160 tty_setcolor (STATUSBAR_COLOR
);
161 tty_draw_hline (WIDGET (view
)->rect
.y
+ r
->y
, WIDGET (view
)->rect
.x
+ r
->x
, ' ', r
->cols
);
164 view
->filename_vpath
!= NULL
?
165 vfs_path_get_last_path_str (view
->filename_vpath
) : view
->command
!= NULL
?
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
);
175 char buffer
[BUF_TRUNC_LEN
+ 1];
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
) ? "+" : " ",
182 mc_global
.source_codepage
>= 0 ?
183 get_codepage_id (mc_global
.source_codepage
) :
188 widget_gotoyx (view
, r
->y
, r
->x
);
190 tty_print_string (str_fit_to_term (file_label
, r
->cols
- 34, J_LEFT_FIT
));
192 tty_print_string (str_fit_to_term (file_label
, r
->cols
- 5, J_LEFT_FIT
));
194 mcview_display_percent (view
, view
->mode_flags
.hex
? view
->hex_cursor
: view
->dpy_end
);
197 /* --------------------------------------------------------------------------------------------- */
198 /*** public functions ****************************************************************************/
199 /* --------------------------------------------------------------------------------------------- */
202 mcview_update (WView
*view
)
204 static int dirt_limit
= 1;
206 if (view
->dpy_bbar_dirty
)
208 view
->dpy_bbar_dirty
= FALSE
;
209 mcview_set_buttonbar (view
);
210 widget_draw (WIDGET (buttonbar_find (DIALOG (WIDGET (view
)->owner
))));
213 if (view
->dirty
> dirt_limit
)
215 /* Too many updates skipped -> force a update */
216 mcview_display (view
);
218 /* Raise the update skipping limit */
220 if (dirt_limit
> mcview_max_dirt_limit
)
221 dirt_limit
= mcview_max_dirt_limit
;
223 else if (view
->dirty
> 0)
227 /* We have time to update the screen properly */
228 mcview_display (view
);
235 /* We are busy -> skipping full update,
236 only the status line is updated */
237 mcview_display_status (view
);
239 /* Here we had a refresh, if fast scrolling does not work
240 restore the refresh, although this should not happen */
244 /* --------------------------------------------------------------------------------------------- */
245 /** Displays as much data from view->dpy_start as fits on the screen */
248 mcview_display (WView
*view
)
250 if (view
->mode_flags
.hex
)
251 mcview_display_hex (view
);
253 mcview_display_text (view
);
254 mcview_display_status (view
);
257 /* --------------------------------------------------------------------------------------------- */
260 mcview_compute_areas (WView
*view
)
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. */
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
);
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
;
280 /* Compute the heights of the areas */
281 rest
= view_area
.lines
;
283 height
= MIN (rest
, 1);
284 view
->status_area
.lines
= height
;
287 height
= (ruler
== RULER_NONE
|| view
->mode_flags
.hex
) ? 0 : 2;
288 height
= MIN (rest
, height
);
289 view
->ruler_area
.lines
= height
;
292 view
->data_area
.lines
= rest
;
294 /* Compute the position of the areas */
297 view
->status_area
.y
= y
;
298 y
+= view
->status_area
.lines
;
300 if (ruler
== RULER_TOP
)
302 view
->ruler_area
.y
= y
;
303 y
+= view
->ruler_area
.lines
;
306 view
->data_area
.y
= y
;
307 y
+= view
->data_area
.lines
;
309 if (ruler
== RULER_BOTTOM
)
310 view
->ruler_area
.y
= y
;
313 /* --------------------------------------------------------------------------------------------- */
316 mcview_update_bytes_per_line (WView
*view
)
318 int cols
= view
->data_area
.cols
;
324 bytes
= 4 * ((cols
- 9) / ((cols
<= 80) ? 17 : 18));
326 g_assert (bytes
!= 0);
328 view
->bytes_per_line
= bytes
;
329 view
->dirty
= mcview_max_dirt_limit
+ 1; /* To force refresh */
332 /* --------------------------------------------------------------------------------------------- */
335 mcview_display_toggle_ruler (WView
*view
)
337 static const enum ruler_type next
[3] = {
343 g_assert ((size_t) ruler
< 3);
345 ruler
= next
[(size_t) ruler
];
346 mcview_compute_areas (view
);
350 /* --------------------------------------------------------------------------------------------- */
353 mcview_display_clean (WView
*view
)
355 Widget
*w
= WIDGET (view
);
357 tty_setcolor (VIEW_NORMAL_COLOR
);
359 if (view
->dpy_frame_size
!= 0)
360 tty_draw_box (w
->rect
.y
, w
->rect
.x
, w
->rect
.lines
, w
->rect
.cols
, FALSE
);
363 /* --------------------------------------------------------------------------------------------- */
366 mcview_display_ruler (WView
*view
)
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;
377 if (ruler
== RULER_NONE
|| r
->lines
< 1)
380 tty_setcolor (VIEW_BOLD_COLOR
);
381 for (c
= 0; c
< r
->cols
; c
++)
383 cl
= view
->dpy_text_column
+ c
;
384 if (line_row
< r
->lines
)
386 widget_gotoyx (view
, r
->y
+ line_row
, r
->x
+ c
);
387 tty_print_char (ruler_chars
[cl
% 10]);
390 if ((cl
!= 0) && (cl
% 10) == 0)
392 g_snprintf (r_buff
, sizeof (r_buff
), "%" PRIuMAX
, (uintmax_t) cl
);
393 if (nums_row
< r
->lines
)
395 widget_gotoyx (view
, r
->y
+ nums_row
, r
->x
+ c
- 1);
396 tty_print_string (r_buff
);
400 tty_setcolor (VIEW_NORMAL_COLOR
);
403 /* --------------------------------------------------------------------------------------------- */