Code indentation.
[midnight-commander.git] / src / viewer / display.c
blob92336c39932b26735dbe11c4806624c4b7cd5848
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 tty_draw_hline (view->widget.y + top, view->widget.x + left, ' ', 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 : "";
151 if (width > 40)
153 char buffer[BUF_TRUNC_LEN + 1];
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, BUF_TRUNC_LEN, mcview_get_filesize (view), 0,
161 panels_options.kilobyte_si);
162 tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
163 buffer, mcview_may_still_grow (view) ? "+" : " ",
164 #ifdef HAVE_CHARSET
165 mc_global.source_codepage >= 0 ?
166 get_codepage_id (mc_global.source_codepage) :
167 #endif
168 "");
171 widget_move (view, top, left);
172 if (width > 40)
173 tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
174 else
175 tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
176 if (width > 26)
177 mcview_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end);
180 /* --------------------------------------------------------------------------------------------- */
181 /*** public functions ****************************************************************************/
182 /* --------------------------------------------------------------------------------------------- */
184 void
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);
200 view->dirty = 0;
201 /* Raise the update skipping limit */
202 dirt_limit++;
203 if (dirt_limit > mcview_max_dirt_limit)
204 dirt_limit = mcview_max_dirt_limit;
206 else if (view->dirty > 0)
208 if (is_idle ())
210 /* We have time to update the screen properly */
211 mcview_display (view);
212 view->dirty = 0;
213 if (dirt_limit > 1)
214 dirt_limit--;
216 else
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 */
230 void
231 mcview_display (mcview_t * view)
233 if (view->hex_mode)
235 mcview_display_hex (view);
237 else if (view->text_nroff_mode)
239 mcview_display_nroff (view);
241 else
243 mcview_display_text (view);
245 mcview_display_status (view);
248 /* --------------------------------------------------------------------------------------------- */
250 void
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;
276 rest -= height;
278 height = mcview_dimen_min (rest, (ruler == RULER_NONE || view->hex_mode) ? 0 : 2);
279 view->ruler_area.height = height;
280 rest -= height;
282 view->data_area.height = rest;
284 /* Compute the position of the areas */
285 y = view_area.top;
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 /* --------------------------------------------------------------------------------------------- */
305 void
306 mcview_update_bytes_per_line (mcview_t * view)
308 const screen_dimen cols = view->data_area.width;
309 int bytes;
311 if (cols < 8 + 17)
312 bytes = 4;
313 else
314 bytes = 4 * ((cols - 8) / ((cols < 80) ? 17 : 18));
315 #ifdef HAVE_ASSERT_H
316 assert (bytes != 0);
317 #endif
319 view->bytes_per_line = bytes;
320 view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */
323 /* --------------------------------------------------------------------------------------------- */
325 void
326 mcview_display_toggle_ruler (mcview_t * view)
328 static const enum ruler_type next[3] =
330 RULER_TOP,
331 RULER_BOTTOM,
332 RULER_NONE
335 #ifdef HAVE_ASSERT_H
336 assert ((size_t) ruler < 3);
337 #endif
338 ruler = next[(size_t) ruler];
339 mcview_compute_areas (view);
340 view->dirty++;
343 /* --------------------------------------------------------------------------------------------- */
345 void
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 /* --------------------------------------------------------------------------------------------- */
356 void
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;
367 char r_buff[10];
368 off_t cl;
369 screen_dimen c;
371 if (ruler == RULER_NONE || height < 1)
372 return;
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 /* --------------------------------------------------------------------------------------------- */
399 void
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;
405 int percent;
406 off_t filesize;
408 if (height < 1 || right < 4)
409 return;
410 if (mcview_may_still_grow (view))
411 return;
412 filesize = mcview_get_filesize (view);
414 if (filesize == 0 || view->dpy_end == filesize)
415 percent = 100;
416 else if (p > (INT_MAX / 100))
417 percent = p / (filesize / 100);
418 else
419 percent = p * 100 / filesize;
421 widget_move (view, top, right - 4);
422 tty_printf ("%3d%%", percent);
425 /* --------------------------------------------------------------------------------------------- */