2 Internal file viewer for the Midnight Commander
3 Function for whow info on display
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009, 2011
7 The Free Software Foundation, Inc.
10 Miguel de Icaza, 1994, 1995, 1998
11 Janne Kukonlehto, 1994, 1995
13 Joseph M. Hinkle, 1996
16 Roland Illig <roland.illig@gmx.de>, 2004, 2005
17 Slava Zanko <slavazanko@google.com>, 2009
18 Andrew Borodin <aborodin@vmail.ru>, 2009
19 Ilia Maslakov <il.smind@gmail.com>, 2009, 2010
21 This file is part of the Midnight Commander.
23 The Midnight Commander is free software: you can redistribute it
24 and/or modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation, either version 3 of the License,
26 or (at your option) any later version.
28 The Midnight Commander is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with this program. If not, see <http://www.gnu.org/licenses/>.
38 #include <inttypes.h> /* uintmax_t */
40 #include "lib/global.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/key.h"
44 #include "lib/strutil.h"
46 #include "lib/widget.h"
48 #include "lib/charsets.h"
51 #include "src/setup.h" /* panels_options */
53 #include "src/keybind-defaults.h"
58 /*** global variables ****************************************************************************/
60 /*** file scope macro definitions ****************************************************************/
62 /*** file scope type declarations ****************************************************************/
64 /*** file scope variables ************************************************************************/
66 /* If set, show a ruler */
67 static enum ruler_type
74 /*** file scope functions ************************************************************************/
75 /* --------------------------------------------------------------------------------------------- */
77 /** Define labels and handlers for functional keys */
80 mcview_set_buttonbar (mcview_t
* view
)
82 Dlg_head
*h
= view
->widget
.owner
;
83 WButtonBar
*b
= find_buttonbar (h
);
84 const global_keymap_t
*keymap
= view
->hex_mode
? viewer_hex_map
: viewer_map
;
86 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), keymap
, (Widget
*) view
);
90 if (view
->hexedit_mode
)
91 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|View"), keymap
, (Widget
*) view
);
92 else if (view
->datasource
== DS_FILE
)
93 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Edit"), keymap
, (Widget
*) view
);
95 buttonbar_set_label (b
, 2, "", keymap
, (Widget
*) view
);
97 buttonbar_set_label (b
, 4, Q_ ("ButtonBar|Ascii"), keymap
, (Widget
*) view
);
98 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|Save"), keymap
, (Widget
*) view
);
99 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|HxSrch"), keymap
, (Widget
*) view
);
104 buttonbar_set_label (b
, 2, view
->text_wrap_mode
? Q_ ("ButtonBar|UnWrap")
105 : Q_ ("ButtonBar|Wrap"), keymap
, (Widget
*) view
);
106 buttonbar_set_label (b
, 4, Q_ ("ButtonBar|Hex"), keymap
, (Widget
*) view
);
107 buttonbar_set_label (b
, 6, "", keymap
, (Widget
*) view
);
108 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Search"), keymap
, (Widget
*) view
);
111 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Goto"), keymap
, (Widget
*) view
);
112 buttonbar_set_label (b
, 8, view
->magic_mode
? Q_ ("ButtonBar|Raw")
113 : Q_ ("ButtonBar|Parse"), keymap
, (Widget
*) view
);
115 if (mcview_is_in_panel (view
))
116 buttonbar_set_label (b
, 10, "", keymap
, (Widget
*) view
);
119 /* don't override some panel buttonbar keys */
120 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Quit"), keymap
, (Widget
*) view
);
121 buttonbar_set_label (b
, 9, view
->text_nroff_mode
? Q_ ("ButtonBar|Unform")
122 : Q_ ("ButtonBar|Format"), keymap
, (Widget
*) view
);
123 buttonbar_set_label (b
, 10, Q_ ("ButtonBar|Quit"), keymap
, (Widget
*) view
);
127 /* --------------------------------------------------------------------------------------------- */
130 mcview_display_status (mcview_t
* view
)
132 const screen_dimen top
= view
->status_area
.top
;
133 const screen_dimen left
= view
->status_area
.left
;
134 const screen_dimen width
= view
->status_area
.width
;
135 const screen_dimen height
= view
->status_area
.height
;
136 const char *file_label
;
137 screen_dimen file_label_width
;
142 tty_setcolor (STATUSBAR_COLOR
);
143 tty_draw_hline (view
->widget
.y
+ top
, view
->widget
.x
+ left
, ' ', width
);
146 view
->filename_vpath
!= NULL
?
147 vfs_path_get_last_path_str (view
->filename_vpath
) : view
->command
!= NULL
?
149 file_label_width
= str_term_width1 (file_label
) - 2;
152 char buffer
[BUF_TINY
];
154 widget_move (view
, top
, width
- 32);
156 tty_printf ("0x%08" PRIxMAX
, (uintmax_t) view
->hex_cursor
);
159 size_trunc_len (buffer
, 5, mcview_get_filesize (view
), 0, panels_options
.kilobyte_si
);
160 tty_printf ("%9" PRIuMAX
"/%s%s %s", (uintmax_t) view
->dpy_end
,
161 buffer
, mcview_may_still_grow (view
) ? "+" : " ",
163 mc_global
.source_codepage
>=
164 0 ? get_codepage_id (mc_global
.source_codepage
) : ""
171 widget_move (view
, top
, left
);
173 tty_print_string (str_fit_to_term (file_label
, width
- 34, J_LEFT_FIT
));
175 tty_print_string (str_fit_to_term (file_label
, width
- 5, J_LEFT_FIT
));
177 mcview_percent (view
, view
->hex_mode
? view
->hex_cursor
: view
->dpy_end
);
180 /* --------------------------------------------------------------------------------------------- */
181 /*** public functions ****************************************************************************/
182 /* --------------------------------------------------------------------------------------------- */
185 mcview_update (mcview_t
* view
)
187 static int dirt_limit
= 1;
189 if (view
->dpy_bbar_dirty
)
191 view
->dpy_bbar_dirty
= FALSE
;
192 mcview_set_buttonbar (view
);
193 buttonbar_redraw (find_buttonbar (view
->widget
.owner
));
196 if (view
->dirty
> dirt_limit
)
198 /* Too many updates skipped -> force a update */
199 mcview_display (view
);
201 /* Raise the update skipping limit */
203 if (dirt_limit
> mcview_max_dirt_limit
)
204 dirt_limit
= mcview_max_dirt_limit
;
206 else if (view
->dirty
> 0)
210 /* We have time to update the screen properly */
211 mcview_display (view
);
218 /* We are busy -> skipping full update,
219 only the status line is updated */
220 mcview_display_status (view
);
222 /* Here we had a refresh, if fast scrolling does not work
223 restore the refresh, although this should not happen */
227 /* --------------------------------------------------------------------------------------------- */
228 /** Displays as much data from view->dpy_start as fits on the screen */
231 mcview_display (mcview_t
* view
)
235 mcview_display_hex (view
);
237 else if (view
->text_nroff_mode
)
239 mcview_display_nroff (view
);
243 mcview_display_text (view
);
245 mcview_display_status (view
);
248 /* --------------------------------------------------------------------------------------------- */
251 mcview_compute_areas (mcview_t
* view
)
253 struct area view_area
;
254 screen_dimen height
, rest
, y
;
256 /* The viewer is surrounded by a frame of size view->dpy_frame_size.
257 * Inside that frame, there are: The status line (at the top),
258 * the data area and an optional ruler, which is shown above or
259 * below the data area. */
261 view_area
.top
= view
->dpy_frame_size
;
262 view_area
.left
= view
->dpy_frame_size
;
263 view_area
.height
= mcview_dimen_doz (view
->widget
.lines
, 2 * view
->dpy_frame_size
);
264 view_area
.width
= mcview_dimen_doz (view
->widget
.cols
, 2 * view
->dpy_frame_size
);
266 /* Most coordinates of the areas equal those of the whole viewer */
267 view
->status_area
= view_area
;
268 view
->ruler_area
= view_area
;
269 view
->data_area
= view_area
;
271 /* Compute the heights of the areas */
272 rest
= view_area
.height
;
274 height
= mcview_dimen_min (rest
, 1);
275 view
->status_area
.height
= height
;
278 height
= mcview_dimen_min (rest
, (ruler
== RULER_NONE
|| view
->hex_mode
) ? 0 : 2);
279 view
->ruler_area
.height
= height
;
282 view
->data_area
.height
= rest
;
284 /* Compute the position of the areas */
287 view
->status_area
.top
= y
;
288 y
+= view
->status_area
.height
;
290 if (ruler
== RULER_TOP
)
292 view
->ruler_area
.top
= y
;
293 y
+= view
->ruler_area
.height
;
296 view
->data_area
.top
= y
;
297 y
+= view
->data_area
.height
;
299 if (ruler
== RULER_BOTTOM
)
300 view
->ruler_area
.top
= y
;
303 /* --------------------------------------------------------------------------------------------- */
306 mcview_update_bytes_per_line (mcview_t
* view
)
308 const screen_dimen cols
= view
->data_area
.width
;
314 bytes
= 4 * ((cols
- 8) / ((cols
< 80) ? 17 : 18));
319 view
->bytes_per_line
= bytes
;
320 view
->dirty
= mcview_max_dirt_limit
+ 1; /* To force refresh */
323 /* --------------------------------------------------------------------------------------------- */
326 mcview_display_toggle_ruler (mcview_t
* view
)
328 static const enum ruler_type next
[3] =
336 assert ((size_t) ruler
< 3);
338 ruler
= next
[(size_t) ruler
];
339 mcview_compute_areas (view
);
343 /* --------------------------------------------------------------------------------------------- */
346 mcview_display_clean (mcview_t
* view
)
348 tty_setcolor (NORMAL_COLOR
);
349 widget_erase ((Widget
*) view
);
350 if (view
->dpy_frame_size
!= 0)
351 tty_draw_box (view
->widget
.y
, view
->widget
.x
, view
->widget
.lines
, view
->widget
.cols
, FALSE
);
354 /* --------------------------------------------------------------------------------------------- */
357 mcview_display_ruler (mcview_t
* view
)
359 static const char ruler_chars
[] = "|----*----";
360 const screen_dimen top
= view
->ruler_area
.top
;
361 const screen_dimen left
= view
->ruler_area
.left
;
362 const screen_dimen width
= view
->ruler_area
.width
;
363 const screen_dimen height
= view
->ruler_area
.height
;
364 const screen_dimen line_row
= (ruler
== RULER_TOP
) ? 0 : 1;
365 const screen_dimen nums_row
= (ruler
== RULER_TOP
) ? 1 : 0;
371 if (ruler
== RULER_NONE
|| height
< 1)
374 tty_setcolor (VIEW_BOLD_COLOR
);
375 for (c
= 0; c
< width
; c
++)
377 cl
= view
->dpy_text_column
+ c
;
378 if (line_row
< height
)
380 widget_move (view
, top
+ line_row
, left
+ c
);
381 tty_print_char (ruler_chars
[cl
% 10]);
384 if ((cl
!= 0) && (cl
% 10) == 0)
386 g_snprintf (r_buff
, sizeof (r_buff
), "%" PRIuMAX
, (uintmax_t) cl
);
387 if (nums_row
< height
)
389 widget_move (view
, top
+ nums_row
, left
+ c
- 1);
390 tty_print_string (r_buff
);
394 tty_setcolor (NORMAL_COLOR
);
397 /* --------------------------------------------------------------------------------------------- */
400 mcview_percent (mcview_t
* view
, off_t p
)
402 const screen_dimen top
= view
->status_area
.top
;
403 const screen_dimen right
= view
->status_area
.left
+ view
->status_area
.width
;
404 const screen_dimen height
= view
->status_area
.height
;
408 if (height
< 1 || right
< 4)
410 if (mcview_may_still_grow (view
))
412 filesize
= mcview_get_filesize (view
);
414 if (filesize
== 0 || view
->dpy_end
== filesize
)
416 else if (p
> (INT_MAX
/ 100))
417 percent
= p
/ (filesize
/ 100);
419 percent
= p
* 100 / filesize
;
421 widget_move (view
, top
, right
- 4);
422 tty_printf ("%3d%%", percent
);
425 /* --------------------------------------------------------------------------------------------- */