Fixed search for first symbol in string.
[midnight-commander.git] / src / viewer / display.c
blobbf020492dadd32e582a54634b46d7caed255647e
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 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009, 2010 Ilia Maslakov <il.smind@gmail.com>
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software; you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
38 #include <config.h>
39 #include <inttypes.h> /* uintmax_t */
41 #include "lib/global.h"
42 #include "lib/skin.h"
43 #include "lib/tty/tty.h"
44 #include "lib/tty/key.h"
45 #include "lib/strutil.h"
46 #include "lib/util.h"
47 #include "lib/widget.h"
48 #ifdef HAVE_CHARSET
49 #include "lib/charsets.h"
50 #endif
52 #include "src/setup.h" /* panels_options */
53 #include "src/main.h"
54 #include "src/keybind-defaults.h"
56 #include "internal.h"
57 #include "mcviewer.h"
59 /*** global variables ****************************************************************************/
61 /*** file scope macro definitions ****************************************************************/
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 Dlg_head *h = view->widget.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;
138 screen_dimen file_label_width;
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 = view->filename ? view->filename : view->command ? view->command : "";
148 file_label_width = str_term_width1 (file_label) - 2;
149 if (width > 40)
151 char buffer[BUF_TINY];
152 widget_move (view, top, width - 32);
153 if (view->hex_mode)
154 tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
155 else
157 size_trunc_len (buffer, 5, mcview_get_filesize (view), 0, panels_options.kilobyte_si);
158 tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
159 buffer, mcview_may_still_grow (view) ? "+" : " ",
160 #ifdef HAVE_CHARSET
161 mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage) : ""
162 #else
164 #endif
168 widget_move (view, top, left);
169 if (width > 40)
170 tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
171 else
172 tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
173 if (width > 26)
174 mcview_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end);
177 /* --------------------------------------------------------------------------------------------- */
178 /*** public functions ****************************************************************************/
179 /* --------------------------------------------------------------------------------------------- */
181 void
182 mcview_update (mcview_t * view)
184 static int dirt_limit = 1;
186 if (view->dpy_bbar_dirty)
188 view->dpy_bbar_dirty = FALSE;
189 mcview_set_buttonbar (view);
190 buttonbar_redraw (find_buttonbar (view->widget.owner));
193 if (view->dirty > dirt_limit)
195 /* Too many updates skipped -> force a update */
196 mcview_display (view);
197 view->dirty = 0;
198 /* Raise the update skipping limit */
199 dirt_limit++;
200 if (dirt_limit > mcview_max_dirt_limit)
201 dirt_limit = mcview_max_dirt_limit;
203 else if (view->dirty > 0)
205 if (is_idle ())
207 /* We have time to update the screen properly */
208 mcview_display (view);
209 view->dirty = 0;
210 if (dirt_limit > 1)
211 dirt_limit--;
213 else
215 /* We are busy -> skipping full update,
216 only the status line is updated */
217 mcview_display_status (view);
219 /* Here we had a refresh, if fast scrolling does not work
220 restore the refresh, although this should not happen */
224 /* --------------------------------------------------------------------------------------------- */
225 /** Displays as much data from view->dpy_start as fits on the screen */
227 void
228 mcview_display (mcview_t * view)
230 if (view->hex_mode)
232 mcview_display_hex (view);
234 else if (view->text_nroff_mode)
236 mcview_display_nroff (view);
238 else
240 mcview_display_text (view);
242 mcview_display_status (view);
245 /* --------------------------------------------------------------------------------------------- */
247 void
248 mcview_compute_areas (mcview_t * view)
250 struct area view_area;
251 screen_dimen height, rest, y;
253 /* The viewer is surrounded by a frame of size view->dpy_frame_size.
254 * Inside that frame, there are: The status line (at the top),
255 * the data area and an optional ruler, which is shown above or
256 * below the data area. */
258 view_area.top = view->dpy_frame_size;
259 view_area.left = view->dpy_frame_size;
260 view_area.height = mcview_dimen_doz (view->widget.lines, 2 * view->dpy_frame_size);
261 view_area.width = mcview_dimen_doz (view->widget.cols, 2 * view->dpy_frame_size);
263 /* Most coordinates of the areas equal those of the whole viewer */
264 view->status_area = view_area;
265 view->ruler_area = view_area;
266 view->data_area = view_area;
268 /* Compute the heights of the areas */
269 rest = view_area.height;
271 height = mcview_dimen_min (rest, 1);
272 view->status_area.height = height;
273 rest -= height;
275 height = mcview_dimen_min (rest, (ruler == RULER_NONE || view->hex_mode) ? 0 : 2);
276 view->ruler_area.height = height;
277 rest -= height;
279 view->data_area.height = rest;
281 /* Compute the position of the areas */
282 y = view_area.top;
284 view->status_area.top = y;
285 y += view->status_area.height;
287 if (ruler == RULER_TOP)
289 view->ruler_area.top = y;
290 y += view->ruler_area.height;
293 view->data_area.top = y;
294 y += view->data_area.height;
296 if (ruler == RULER_BOTTOM)
297 view->ruler_area.top = y;
300 /* --------------------------------------------------------------------------------------------- */
302 void
303 mcview_update_bytes_per_line (mcview_t * view)
305 const screen_dimen cols = view->data_area.width;
306 int bytes;
308 if (cols < 8 + 17)
309 bytes = 4;
310 else
311 bytes = 4 * ((cols - 8) / ((cols < 80) ? 17 : 18));
312 assert (bytes != 0);
314 view->bytes_per_line = bytes;
315 view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */
318 /* --------------------------------------------------------------------------------------------- */
320 void
321 mcview_display_toggle_ruler (mcview_t * view)
323 static const enum ruler_type next[3] =
325 RULER_TOP,
326 RULER_BOTTOM,
327 RULER_NONE
330 assert ((size_t) ruler < 3);
331 ruler = next[(size_t) ruler];
332 mcview_compute_areas (view);
333 view->dirty++;
336 /* --------------------------------------------------------------------------------------------- */
338 void
339 mcview_display_clean (mcview_t * view)
341 tty_setcolor (NORMAL_COLOR);
342 widget_erase ((Widget *) view);
343 if (view->dpy_frame_size != 0)
344 tty_draw_box (view->widget.y, view->widget.x, view->widget.lines, view->widget.cols, FALSE);
347 /* --------------------------------------------------------------------------------------------- */
349 void
350 mcview_display_ruler (mcview_t * view)
352 static const char ruler_chars[] = "|----*----";
353 const screen_dimen top = view->ruler_area.top;
354 const screen_dimen left = view->ruler_area.left;
355 const screen_dimen width = view->ruler_area.width;
356 const screen_dimen height = view->ruler_area.height;
357 const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
358 const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
360 char r_buff[10];
361 off_t cl;
362 screen_dimen c;
364 if (ruler == RULER_NONE || height < 1)
365 return;
367 tty_setcolor (VIEW_BOLD_COLOR);
368 for (c = 0; c < width; c++)
370 cl = view->dpy_text_column + c;
371 if (line_row < height)
373 widget_move (view, top + line_row, left + c);
374 tty_print_char (ruler_chars[cl % 10]);
377 if ((cl != 0) && (cl % 10) == 0)
379 g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl);
380 if (nums_row < height)
382 widget_move (view, top + nums_row, left + c - 1);
383 tty_print_string (r_buff);
387 tty_setcolor (NORMAL_COLOR);
390 /* --------------------------------------------------------------------------------------------- */
392 void
393 mcview_percent (mcview_t * view, off_t p)
395 const screen_dimen top = view->status_area.top;
396 const screen_dimen right = view->status_area.left + view->status_area.width;
397 const screen_dimen height = view->status_area.height;
398 int percent;
399 off_t filesize;
401 if (height < 1 || right < 4)
402 return;
403 if (mcview_may_still_grow (view))
404 return;
405 filesize = mcview_get_filesize (view);
407 if (filesize == 0 || view->dpy_end == filesize)
408 percent = 100;
409 else if (p > (INT_MAX / 100))
410 percent = p / (filesize / 100);
411 else
412 percent = p * 100 / filesize;
414 widget_move (view, top, right - 4);
415 tty_printf ("%3d%%", percent);
418 /* --------------------------------------------------------------------------------------------- */