Merge branch '2835_treeview' into 4.8.1-stable
[midnight-commander.git] / src / viewer / display.c
bloba3fd6624528c3441f5f8000e86b36a4f799fa2c4
1 /*
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.
9 Written by:
10 Miguel de Icaza, 1994, 1995, 1998
11 Janne Kukonlehto, 1994, 1995
12 Jakub Jelinek, 1995
13 Joseph M. Hinkle, 1996
14 Norbert Warmuth, 1997
15 Pavel Machek, 1998
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/>.
37 #include <config.h>
38 #include <inttypes.h> /* uintmax_t */
40 #include "lib/global.h"
41 #include "lib/skin.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/key.h"
44 #include "lib/strutil.h"
45 #include "lib/util.h"
46 #include "lib/widget.h"
47 #ifdef HAVE_CHARSET
48 #include "lib/charsets.h"
49 #endif
51 #include "src/setup.h" /* panels_options */
52 #include "src/main.h"
53 #include "src/keybind-defaults.h"
55 #include "internal.h"
56 #include "mcviewer.h"
58 /*** global variables ****************************************************************************/
60 /*** file scope macro definitions ****************************************************************/
62 #define BUF_TRUNC_LEN 5 /* The length of the line displays the file size */
64 /*** file scope type declarations ****************************************************************/
66 /*** file scope variables ************************************************************************/
68 /* If set, show a ruler */
69 static enum ruler_type
71 RULER_NONE,
72 RULER_TOP,
73 RULER_BOTTOM
74 } ruler = RULER_NONE;
76 /*** file scope functions ************************************************************************/
77 /* --------------------------------------------------------------------------------------------- */
79 /** Define labels and handlers for functional keys */
81 static void
82 mcview_set_buttonbar (mcview_t * view)
84 Dlg_head *h = view->widget.owner;
85 WButtonBar *b = find_buttonbar (h);
86 const global_keymap_t *keymap = view->hex_mode ? viewer_hex_map : viewer_map;
88 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), keymap, (Widget *) view);
90 if (view->hex_mode)
92 if (view->hexedit_mode)
93 buttonbar_set_label (b, 2, Q_ ("ButtonBar|View"), keymap, (Widget *) view);
94 else if (view->datasource == DS_FILE)
95 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Edit"), keymap, (Widget *) view);
96 else
97 buttonbar_set_label (b, 2, "", keymap, (Widget *) view);
99 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Ascii"), keymap, (Widget *) view);
100 buttonbar_set_label (b, 6, Q_ ("ButtonBar|Save"), keymap, (Widget *) view);
101 buttonbar_set_label (b, 7, Q_ ("ButtonBar|HxSrch"), keymap, (Widget *) view);
104 else
106 buttonbar_set_label (b, 2, view->text_wrap_mode ? Q_ ("ButtonBar|UnWrap")
107 : Q_ ("ButtonBar|Wrap"), keymap, (Widget *) view);
108 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Hex"), keymap, (Widget *) view);
109 buttonbar_set_label (b, 6, "", keymap, (Widget *) view);
110 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), keymap, (Widget *) view);
113 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Goto"), keymap, (Widget *) view);
114 buttonbar_set_label (b, 8, view->magic_mode ? Q_ ("ButtonBar|Raw")
115 : Q_ ("ButtonBar|Parse"), keymap, (Widget *) view);
117 if (mcview_is_in_panel (view))
118 buttonbar_set_label (b, 10, "", keymap, (Widget *) view);
119 else
121 /* don't override some panel buttonbar keys */
122 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Quit"), keymap, (Widget *) view);
123 buttonbar_set_label (b, 9, view->text_nroff_mode ? Q_ ("ButtonBar|Unform")
124 : Q_ ("ButtonBar|Format"), keymap, (Widget *) view);
125 buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), keymap, (Widget *) view);
129 /* --------------------------------------------------------------------------------------------- */
131 static void
132 mcview_display_status (mcview_t * view)
134 const screen_dimen top = view->status_area.top;
135 const screen_dimen left = view->status_area.left;
136 const screen_dimen width = view->status_area.width;
137 const screen_dimen height = view->status_area.height;
138 const char *file_label;
140 if (height < 1)
141 return;
143 tty_setcolor (STATUSBAR_COLOR);
144 widget_move (view, top, left);
145 tty_draw_hline (-1, -1, ' ', width);
147 file_label =
148 view->filename_vpath != NULL ?
149 vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ?
150 view->command : "";
152 if (width > 40)
154 char buffer[BUF_TRUNC_LEN + 1];
156 widget_move (view, top, width - 32);
157 if (view->hex_mode)
158 tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
159 else
161 size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0,
162 panels_options.kilobyte_si);
163 tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
164 buffer, mcview_may_still_grow (view) ? "+" : " ",
165 #ifdef HAVE_CHARSET
166 mc_global.source_codepage >= 0 ?
167 get_codepage_id (mc_global.source_codepage) :
168 #endif
169 "");
172 widget_move (view, top, left);
173 if (width > 40)
174 tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
175 else
176 tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
177 if (width > 26)
178 mcview_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end);
181 /* --------------------------------------------------------------------------------------------- */
182 /*** public functions ****************************************************************************/
183 /* --------------------------------------------------------------------------------------------- */
185 void
186 mcview_update (mcview_t * view)
188 static int dirt_limit = 1;
190 if (view->dpy_bbar_dirty)
192 view->dpy_bbar_dirty = FALSE;
193 mcview_set_buttonbar (view);
194 buttonbar_redraw (find_buttonbar (view->widget.owner));
197 if (view->dirty > dirt_limit)
199 /* Too many updates skipped -> force a update */
200 mcview_display (view);
201 view->dirty = 0;
202 /* Raise the update skipping limit */
203 dirt_limit++;
204 if (dirt_limit > mcview_max_dirt_limit)
205 dirt_limit = mcview_max_dirt_limit;
207 else if (view->dirty > 0)
209 if (is_idle ())
211 /* We have time to update the screen properly */
212 mcview_display (view);
213 view->dirty = 0;
214 if (dirt_limit > 1)
215 dirt_limit--;
217 else
219 /* We are busy -> skipping full update,
220 only the status line is updated */
221 mcview_display_status (view);
223 /* Here we had a refresh, if fast scrolling does not work
224 restore the refresh, although this should not happen */
228 /* --------------------------------------------------------------------------------------------- */
229 /** Displays as much data from view->dpy_start as fits on the screen */
231 void
232 mcview_display (mcview_t * view)
234 if (view->hex_mode)
236 mcview_display_hex (view);
238 else if (view->text_nroff_mode)
240 mcview_display_nroff (view);
242 else
244 mcview_display_text (view);
246 mcview_display_status (view);
249 /* --------------------------------------------------------------------------------------------- */
251 void
252 mcview_compute_areas (mcview_t * view)
254 struct area view_area;
255 screen_dimen height, rest, y;
257 /* The viewer is surrounded by a frame of size view->dpy_frame_size.
258 * Inside that frame, there are: The status line (at the top),
259 * the data area and an optional ruler, which is shown above or
260 * below the data area. */
262 view_area.top = view->dpy_frame_size;
263 view_area.left = view->dpy_frame_size;
264 view_area.height = mcview_dimen_doz (view->widget.lines, 2 * view->dpy_frame_size);
265 view_area.width = mcview_dimen_doz (view->widget.cols, 2 * view->dpy_frame_size);
267 /* Most coordinates of the areas equal those of the whole viewer */
268 view->status_area = view_area;
269 view->ruler_area = view_area;
270 view->data_area = view_area;
272 /* Compute the heights of the areas */
273 rest = view_area.height;
275 height = mcview_dimen_min (rest, 1);
276 view->status_area.height = height;
277 rest -= height;
279 height = mcview_dimen_min (rest, (ruler == RULER_NONE || view->hex_mode) ? 0 : 2);
280 view->ruler_area.height = height;
281 rest -= height;
283 view->data_area.height = rest;
285 /* Compute the position of the areas */
286 y = view_area.top;
288 view->status_area.top = y;
289 y += view->status_area.height;
291 if (ruler == RULER_TOP)
293 view->ruler_area.top = y;
294 y += view->ruler_area.height;
297 view->data_area.top = y;
298 y += view->data_area.height;
300 if (ruler == RULER_BOTTOM)
301 view->ruler_area.top = y;
304 /* --------------------------------------------------------------------------------------------- */
306 void
307 mcview_update_bytes_per_line (mcview_t * view)
309 const screen_dimen cols = view->data_area.width;
310 int bytes;
312 if (cols < 8 + 17)
313 bytes = 4;
314 else
315 bytes = 4 * ((cols - 8) / ((cols < 80) ? 17 : 18));
316 #ifdef HAVE_ASSERT_H
317 assert (bytes != 0);
318 #endif
320 view->bytes_per_line = bytes;
321 view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */
324 /* --------------------------------------------------------------------------------------------- */
326 void
327 mcview_display_toggle_ruler (mcview_t * view)
329 static const enum ruler_type next[3] =
331 RULER_TOP,
332 RULER_BOTTOM,
333 RULER_NONE
336 #ifdef HAVE_ASSERT_H
337 assert ((size_t) ruler < 3);
338 #endif
339 ruler = next[(size_t) ruler];
340 mcview_compute_areas (view);
341 view->dirty++;
344 /* --------------------------------------------------------------------------------------------- */
346 void
347 mcview_display_clean (mcview_t * view)
349 tty_setcolor (NORMAL_COLOR);
350 widget_erase ((Widget *) view);
351 if (view->dpy_frame_size != 0)
352 tty_draw_box (view->widget.y, view->widget.x, view->widget.lines, view->widget.cols, FALSE);
355 /* --------------------------------------------------------------------------------------------- */
357 void
358 mcview_display_ruler (mcview_t * view)
360 static const char ruler_chars[] = "|----*----";
361 const screen_dimen top = view->ruler_area.top;
362 const screen_dimen left = view->ruler_area.left;
363 const screen_dimen width = view->ruler_area.width;
364 const screen_dimen height = view->ruler_area.height;
365 const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
366 const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
368 char r_buff[10];
369 off_t cl;
370 screen_dimen c;
372 if (ruler == RULER_NONE || height < 1)
373 return;
375 tty_setcolor (VIEW_BOLD_COLOR);
376 for (c = 0; c < width; c++)
378 cl = view->dpy_text_column + c;
379 if (line_row < height)
381 widget_move (view, top + line_row, left + c);
382 tty_print_char (ruler_chars[cl % 10]);
385 if ((cl != 0) && (cl % 10) == 0)
387 g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl);
388 if (nums_row < height)
390 widget_move (view, top + nums_row, left + c - 1);
391 tty_print_string (r_buff);
395 tty_setcolor (NORMAL_COLOR);
398 /* --------------------------------------------------------------------------------------------- */
400 void
401 mcview_percent (mcview_t * view, off_t p)
403 const screen_dimen top = view->status_area.top;
404 const screen_dimen right = view->status_area.left + view->status_area.width;
405 const screen_dimen height = view->status_area.height;
406 int percent;
407 off_t filesize;
409 if (height < 1 || right < 4)
410 return;
411 if (mcview_may_still_grow (view))
412 return;
413 filesize = mcview_get_filesize (view);
415 if (filesize == 0 || view->dpy_end == filesize)
416 percent = 100;
417 else if (p > (INT_MAX / 100))
418 percent = p / (filesize / 100);
419 else
420 percent = p * 100 / filesize;
422 widget_move (view, top, right - 4);
423 tty_printf ("%3d%%", percent);
426 /* --------------------------------------------------------------------------------------------- */