Changes to handle vfs_path_t object:
[midnight-commander.git] / src / viewer / display.c
blobd819bbece5d60b7de4c8f30d271aea14e7e5d65d
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 /*** file scope type declarations ****************************************************************/
64 /*** file scope variables ************************************************************************/
66 /* If set, show a ruler */
67 static enum ruler_type
69 RULER_NONE,
70 RULER_TOP,
71 RULER_BOTTOM
72 } ruler = RULER_NONE;
74 /*** file scope functions ************************************************************************/
75 /* --------------------------------------------------------------------------------------------- */
77 /** Define labels and handlers for functional keys */
79 static void
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);
88 if (view->hex_mode)
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);
94 else
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);
102 else
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);
117 else
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 /* --------------------------------------------------------------------------------------------- */
129 static void
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;
139 if (height < 1)
140 return;
142 tty_setcolor (STATUSBAR_COLOR);
143 widget_move (view, top, left);
144 tty_draw_hline (-1, -1, ' ', width);
146 file_label =
147 view->filename_vpath != NULL ?
148 vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ?
149 view->command : "";
150 file_label_width = str_term_width1 (file_label) - 2;
151 if (width > 40)
153 char buffer[BUF_TINY];
155 widget_move (view, top, width - 32);
156 if (view->hex_mode)
157 tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
158 else
160 size_trunc_len (buffer, 5, mcview_get_filesize (view), 0, panels_options.kilobyte_si);
161 tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
162 buffer, mcview_may_still_grow (view) ? "+" : " ",
163 #ifdef HAVE_CHARSET
164 mc_global.source_codepage >=
165 0 ? get_codepage_id (mc_global.source_codepage) : ""
166 #else
168 #endif
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 assert (bytes != 0);
318 view->bytes_per_line = bytes;
319 view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */
322 /* --------------------------------------------------------------------------------------------- */
324 void
325 mcview_display_toggle_ruler (mcview_t * view)
327 static const enum ruler_type next[3] =
329 RULER_TOP,
330 RULER_BOTTOM,
331 RULER_NONE
334 assert ((size_t) ruler < 3);
335 ruler = next[(size_t) ruler];
336 mcview_compute_areas (view);
337 view->dirty++;
340 /* --------------------------------------------------------------------------------------------- */
342 void
343 mcview_display_clean (mcview_t * view)
345 tty_setcolor (NORMAL_COLOR);
346 widget_erase ((Widget *) view);
347 if (view->dpy_frame_size != 0)
348 tty_draw_box (view->widget.y, view->widget.x, view->widget.lines, view->widget.cols, FALSE);
351 /* --------------------------------------------------------------------------------------------- */
353 void
354 mcview_display_ruler (mcview_t * view)
356 static const char ruler_chars[] = "|----*----";
357 const screen_dimen top = view->ruler_area.top;
358 const screen_dimen left = view->ruler_area.left;
359 const screen_dimen width = view->ruler_area.width;
360 const screen_dimen height = view->ruler_area.height;
361 const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
362 const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
364 char r_buff[10];
365 off_t cl;
366 screen_dimen c;
368 if (ruler == RULER_NONE || height < 1)
369 return;
371 tty_setcolor (VIEW_BOLD_COLOR);
372 for (c = 0; c < width; c++)
374 cl = view->dpy_text_column + c;
375 if (line_row < height)
377 widget_move (view, top + line_row, left + c);
378 tty_print_char (ruler_chars[cl % 10]);
381 if ((cl != 0) && (cl % 10) == 0)
383 g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl);
384 if (nums_row < height)
386 widget_move (view, top + nums_row, left + c - 1);
387 tty_print_string (r_buff);
391 tty_setcolor (NORMAL_COLOR);
394 /* --------------------------------------------------------------------------------------------- */
396 void
397 mcview_percent (mcview_t * view, off_t p)
399 const screen_dimen top = view->status_area.top;
400 const screen_dimen right = view->status_area.left + view->status_area.width;
401 const screen_dimen height = view->status_area.height;
402 int percent;
403 off_t filesize;
405 if (height < 1 || right < 4)
406 return;
407 if (mcview_may_still_grow (view))
408 return;
409 filesize = mcview_get_filesize (view);
411 if (filesize == 0 || view->dpy_end == filesize)
412 percent = 100;
413 else if (p > (INT_MAX / 100))
414 percent = p / (filesize / 100);
415 else
416 percent = p * 100 / filesize;
418 widget_move (view, top, right - 4);
419 tty_printf ("%3d%%", percent);
422 /* --------------------------------------------------------------------------------------------- */