Merge branch '2956_mouse_protocol_1006'
[midnight-commander.git] / src / viewer / display.c
blob41606c52f9fd6f6a4132e7e54b0a7df01fbbb904
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/keybind-defaults.h"
54 #include "internal.h"
55 #include "mcviewer.h"
57 /*** global variables ****************************************************************************/
59 /*** file scope macro definitions ****************************************************************/
61 #define BUF_TRUNC_LEN 5 /* The length of the line displays the file size */
63 /*** file scope type declarations ****************************************************************/
65 /*** file scope variables ************************************************************************/
67 /* If set, show a ruler */
68 static enum ruler_type
70 RULER_NONE,
71 RULER_TOP,
72 RULER_BOTTOM
73 } ruler = RULER_NONE;
75 /*** file scope functions ************************************************************************/
76 /* --------------------------------------------------------------------------------------------- */
78 /** Define labels and handlers for functional keys */
80 static void
81 mcview_set_buttonbar (mcview_t * view)
83 WDialog *h = WIDGET (view)->owner;
84 WButtonBar *b = find_buttonbar (h);
85 const global_keymap_t *keymap = view->hex_mode ? viewer_hex_map : viewer_map;
87 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), keymap, WIDGET (view));
89 if (view->hex_mode)
91 if (view->hexedit_mode)
92 buttonbar_set_label (b, 2, Q_ ("ButtonBar|View"), keymap, WIDGET (view));
93 else if (view->datasource == DS_FILE)
94 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Edit"), keymap, WIDGET (view));
95 else
96 buttonbar_set_label (b, 2, "", keymap, WIDGET (view));
98 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Ascii"), keymap, WIDGET (view));
99 buttonbar_set_label (b, 6, Q_ ("ButtonBar|Save"), keymap, WIDGET (view));
100 buttonbar_set_label (b, 7, Q_ ("ButtonBar|HxSrch"), keymap, WIDGET (view));
103 else
105 buttonbar_set_label (b, 2, view->text_wrap_mode ? Q_ ("ButtonBar|UnWrap")
106 : Q_ ("ButtonBar|Wrap"), keymap, WIDGET (view));
107 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Hex"), keymap, WIDGET (view));
108 buttonbar_set_label (b, 6, "", keymap, WIDGET (view));
109 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), keymap, WIDGET (view));
112 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Goto"), keymap, WIDGET (view));
113 buttonbar_set_label (b, 8, view->magic_mode ? Q_ ("ButtonBar|Raw")
114 : Q_ ("ButtonBar|Parse"), keymap, WIDGET (view));
116 if (mcview_is_in_panel (view))
117 buttonbar_set_label (b, 10, "", keymap, WIDGET (view));
118 else
120 /* don't override some panel buttonbar keys */
121 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Quit"), keymap, WIDGET (view));
122 buttonbar_set_label (b, 9, view->text_nroff_mode ? Q_ ("ButtonBar|Unform")
123 : Q_ ("ButtonBar|Format"), keymap, WIDGET (view));
124 buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), keymap, WIDGET (view));
128 /* --------------------------------------------------------------------------------------------- */
130 static void
131 mcview_display_status (mcview_t * view)
133 const screen_dimen top = view->status_area.top;
134 const screen_dimen left = view->status_area.left;
135 const screen_dimen width = view->status_area.width;
136 const screen_dimen height = view->status_area.height;
137 const char *file_label;
139 if (height < 1)
140 return;
142 tty_setcolor (STATUSBAR_COLOR);
143 tty_draw_hline (WIDGET (view)->y + top, WIDGET (view)->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 : "";
150 if (width > 40)
152 char buffer[BUF_TRUNC_LEN + 1];
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, BUF_TRUNC_LEN, mcview_get_filesize (view), 0,
160 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 >= 0 ?
165 get_codepage_id (mc_global.source_codepage) :
166 #endif
167 "");
170 widget_move (view, top, left);
171 if (width > 40)
172 tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
173 else
174 tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
175 if (width > 26)
176 mcview_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end);
179 /* --------------------------------------------------------------------------------------------- */
180 /*** public functions ****************************************************************************/
181 /* --------------------------------------------------------------------------------------------- */
183 void
184 mcview_update (mcview_t * view)
186 static int dirt_limit = 1;
188 if (view->dpy_bbar_dirty)
190 view->dpy_bbar_dirty = FALSE;
191 mcview_set_buttonbar (view);
192 buttonbar_redraw (find_buttonbar (WIDGET (view)->owner));
195 if (view->dirty > dirt_limit)
197 /* Too many updates skipped -> force a update */
198 mcview_display (view);
199 view->dirty = 0;
200 /* Raise the update skipping limit */
201 dirt_limit++;
202 if (dirt_limit > mcview_max_dirt_limit)
203 dirt_limit = mcview_max_dirt_limit;
205 else if (view->dirty > 0)
207 if (is_idle ())
209 /* We have time to update the screen properly */
210 mcview_display (view);
211 view->dirty = 0;
212 if (dirt_limit > 1)
213 dirt_limit--;
215 else
217 /* We are busy -> skipping full update,
218 only the status line is updated */
219 mcview_display_status (view);
221 /* Here we had a refresh, if fast scrolling does not work
222 restore the refresh, although this should not happen */
226 /* --------------------------------------------------------------------------------------------- */
227 /** Displays as much data from view->dpy_start as fits on the screen */
229 void
230 mcview_display (mcview_t * view)
232 if (view->hex_mode)
234 mcview_display_hex (view);
236 else if (view->text_nroff_mode)
238 mcview_display_nroff (view);
240 else
242 mcview_display_text (view);
244 mcview_display_status (view);
247 /* --------------------------------------------------------------------------------------------- */
249 void
250 mcview_compute_areas (mcview_t * view)
252 struct area view_area;
253 screen_dimen height, rest, y;
255 /* The viewer is surrounded by a frame of size view->dpy_frame_size.
256 * Inside that frame, there are: The status line (at the top),
257 * the data area and an optional ruler, which is shown above or
258 * below the data area. */
260 view_area.top = view->dpy_frame_size;
261 view_area.left = view->dpy_frame_size;
262 view_area.height = mcview_dimen_doz (WIDGET (view)->lines, 2 * view->dpy_frame_size);
263 view_area.width = mcview_dimen_doz (WIDGET (view)->cols, 2 * view->dpy_frame_size);
265 /* Most coordinates of the areas equal those of the whole viewer */
266 view->status_area = view_area;
267 view->ruler_area = view_area;
268 view->data_area = view_area;
270 /* Compute the heights of the areas */
271 rest = view_area.height;
273 height = mcview_dimen_min (rest, 1);
274 view->status_area.height = height;
275 rest -= height;
277 height = mcview_dimen_min (rest, (ruler == RULER_NONE || view->hex_mode) ? 0 : 2);
278 view->ruler_area.height = height;
279 rest -= height;
281 view->data_area.height = rest;
283 /* Compute the position of the areas */
284 y = view_area.top;
286 view->status_area.top = y;
287 y += view->status_area.height;
289 if (ruler == RULER_TOP)
291 view->ruler_area.top = y;
292 y += view->ruler_area.height;
295 view->data_area.top = y;
296 y += view->data_area.height;
298 if (ruler == RULER_BOTTOM)
299 view->ruler_area.top = y;
302 /* --------------------------------------------------------------------------------------------- */
304 void
305 mcview_update_bytes_per_line (mcview_t * view)
307 const screen_dimen cols = view->data_area.width;
308 int bytes;
310 if (cols < 8 + 17)
311 bytes = 4;
312 else
313 bytes = 4 * ((cols - 8) / ((cols < 80) ? 17 : 18));
314 #ifdef HAVE_ASSERT_H
315 assert (bytes != 0);
316 #endif
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 #ifdef HAVE_ASSERT_H
335 assert ((size_t) ruler < 3);
336 #endif
337 ruler = next[(size_t) ruler];
338 mcview_compute_areas (view);
339 view->dirty++;
342 /* --------------------------------------------------------------------------------------------- */
344 void
345 mcview_display_clean (mcview_t * view)
347 Widget *w = WIDGET (view);
349 tty_setcolor (NORMAL_COLOR);
350 widget_erase (w);
351 if (view->dpy_frame_size != 0)
352 tty_draw_box (w->y, w->x, w->lines, w->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 /* --------------------------------------------------------------------------------------------- */