Fix of viewer status bar draw.
[midnight-commander.git] / src / viewer / display.c
blob56a1bb754811d3a47362dce65ad569809f019f84
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 tty_draw_hline (view->widget.y + top, view->widget.x + left, ' ', width);
145 file_label =
146 view->filename_vpath != NULL ?
147 vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ?
148 view->command : "";
149 file_label_width = str_term_width1 (file_label) - 2;
150 if (width > 40)
152 char buffer[BUF_TINY];
154 widget_move (view, top, width - 32);
155 if (view->hex_mode)
156 tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
157 else
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) ? "+" : " ",
162 #ifdef HAVE_CHARSET
163 mc_global.source_codepage >=
164 0 ? get_codepage_id (mc_global.source_codepage) : ""
165 #else
167 #endif
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 /* --------------------------------------------------------------------------------------------- */