diff options
Diffstat (limited to 'src/viewer/display.c')
-rw-r--r-- | src/viewer/display.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/src/viewer/display.c b/src/viewer/display.c new file mode 100644 index 0000000..fe47ec5 --- /dev/null +++ b/src/viewer/display.c @@ -0,0 +1,401 @@ +/* + Internal file viewer for the Midnight Commander + Function for whow info on display + + Copyright (C) 1994-2022 + Free Software Foundation, Inc. + + Written by: + Miguel de Icaza, 1994, 1995, 1998 + Janne Kukonlehto, 1994, 1995 + Jakub Jelinek, 1995 + Joseph M. Hinkle, 1996 + Norbert Warmuth, 1997 + Pavel Machek, 1998 + Roland Illig <roland.illig@gmx.de>, 2004, 2005 + Slava Zanko <slavazanko@google.com>, 2009 + Andrew Borodin <aborodin@vmail.ru>, 2009-2022 + Ilia Maslakov <il.smind@gmail.com>, 2009, 2010 + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <inttypes.h> /* uintmax_t */ + +#include "lib/global.h" +#include "lib/skin.h" +#include "lib/tty/tty.h" +#include "lib/tty/key.h" +#include "lib/strutil.h" +#include "lib/util.h" +#include "lib/widget.h" +#ifdef HAVE_CHARSET +#include "lib/charsets.h" +#endif + +#include "src/setup.h" /* panels_options */ +#include "src/keymap.h" + +#include "internal.h" + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +#define BUF_TRUNC_LEN 5 /* The length of the line displays the file size */ + +/*** file scope type declarations ****************************************************************/ + +/*** file scope variables ************************************************************************/ + +/* If set, show a ruler */ +static enum ruler_type +{ + RULER_NONE, + RULER_TOP, + RULER_BOTTOM +} ruler = RULER_NONE; + +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +/** Define labels and handlers for functional keys */ + +static void +mcview_set_buttonbar (WView * view) +{ + Widget *w = WIDGET (view); + WDialog *h = DIALOG (w->owner); + WButtonBar *b; + const global_keymap_t *keymap = view->mode_flags.hex ? view->hex_keymap : w->keymap; + + b = find_buttonbar (h); + buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), keymap, w); + + if (view->mode_flags.hex) + { + if (view->hexedit_mode) + buttonbar_set_label (b, 2, Q_ ("ButtonBar|View"), keymap, w); + else if (view->datasource == DS_FILE) + buttonbar_set_label (b, 2, Q_ ("ButtonBar|Edit"), keymap, w); + else + buttonbar_set_label (b, 2, "", keymap, WIDGET (view)); + + buttonbar_set_label (b, 4, Q_ ("ButtonBar|Ascii"), keymap, w); + buttonbar_set_label (b, 6, Q_ ("ButtonBar|Save"), keymap, w); + buttonbar_set_label (b, 7, Q_ ("ButtonBar|HxSrch"), keymap, w); + + } + else + { + buttonbar_set_label (b, 2, view->mode_flags.wrap ? Q_ ("ButtonBar|UnWrap") + : Q_ ("ButtonBar|Wrap"), keymap, w); + buttonbar_set_label (b, 4, Q_ ("ButtonBar|Hex"), keymap, w); + buttonbar_set_label (b, 6, "", keymap, WIDGET (view)); + buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), keymap, w); + } + + buttonbar_set_label (b, 5, Q_ ("ButtonBar|Goto"), keymap, w); + buttonbar_set_label (b, 8, view->mode_flags.magic ? Q_ ("ButtonBar|Raw") + : Q_ ("ButtonBar|Parse"), keymap, w); + + if (!mcview_is_in_panel (view)) /* don't override some panel buttonbar keys */ + { + buttonbar_set_label (b, 3, Q_ ("ButtonBar|Quit"), keymap, w); + buttonbar_set_label (b, 9, view->mode_flags.nroff ? Q_ ("ButtonBar|Unform") + : Q_ ("ButtonBar|Format"), keymap, w); + buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), keymap, w); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +mcview_display_percent (WView * view, off_t p) +{ + int percent; + + percent = mcview_calc_percent (view, p); + if (percent >= 0) + { + int top = view->status_area.y; + int right; + + right = view->status_area.x + view->status_area.cols; + widget_gotoyx (view, top, right - 4); + tty_printf ("%3d%%", percent); + /* avoid cursor wrapping in NCurses-base MC */ + widget_gotoyx (view, top, right - 1); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +mcview_display_status (WView * view) +{ + const WRect *r = &view->status_area; + const char *file_label; + + if (r->lines < 1) + return; + + tty_setcolor (STATUSBAR_COLOR); + tty_draw_hline (WIDGET (view)->rect.y + r->y, WIDGET (view)->rect.x + r->x, ' ', r->cols); + + file_label = + view->filename_vpath != NULL ? + vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ? + view->command : ""; + + if (r->cols > 40) + { + widget_gotoyx (view, r->y, r->cols - 32); + if (view->mode_flags.hex) + tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor); + else + { + char buffer[BUF_TRUNC_LEN + 1]; + + size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0, + panels_options.kilobyte_si); + tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end, + buffer, mcview_may_still_grow (view) ? "+" : " ", +#ifdef HAVE_CHARSET + mc_global.source_codepage >= 0 ? + get_codepage_id (mc_global.source_codepage) : +#endif + ""); + } + } + widget_gotoyx (view, r->y, r->x); + if (r->cols > 40) + tty_print_string (str_fit_to_term (file_label, r->cols - 34, J_LEFT_FIT)); + else + tty_print_string (str_fit_to_term (file_label, r->cols - 5, J_LEFT_FIT)); + if (r->cols > 26) + mcview_display_percent (view, view->mode_flags.hex ? view->hex_cursor : view->dpy_end); +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +void +mcview_update (WView * view) +{ + static int dirt_limit = 1; + + if (view->dpy_bbar_dirty) + { + view->dpy_bbar_dirty = FALSE; + mcview_set_buttonbar (view); + widget_draw (WIDGET (find_buttonbar (DIALOG (WIDGET (view)->owner)))); + } + + if (view->dirty > dirt_limit) + { + /* Too many updates skipped -> force a update */ + mcview_display (view); + view->dirty = 0; + /* Raise the update skipping limit */ + dirt_limit++; + if (dirt_limit > mcview_max_dirt_limit) + dirt_limit = mcview_max_dirt_limit; + } + else if (view->dirty > 0) + { + if (is_idle ()) + { + /* We have time to update the screen properly */ + mcview_display (view); + view->dirty = 0; + if (dirt_limit > 1) + dirt_limit--; + } + else + { + /* We are busy -> skipping full update, + only the status line is updated */ + mcview_display_status (view); + } + /* Here we had a refresh, if fast scrolling does not work + restore the refresh, although this should not happen */ + } +} + +/* --------------------------------------------------------------------------------------------- */ +/** Displays as much data from view->dpy_start as fits on the screen */ + +void +mcview_display (WView * view) +{ + if (view->mode_flags.hex) + mcview_display_hex (view); + else + mcview_display_text (view); + mcview_display_status (view); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +mcview_compute_areas (WView * view) +{ + WRect view_area; + int height, rest, y; + + /* The viewer is surrounded by a frame of size view->dpy_frame_size. + * Inside that frame, there are: The status line (at the top), + * the data area and an optional ruler, which is shown above or + * below the data area. */ + + view_area.y = view->dpy_frame_size; + view_area.x = view->dpy_frame_size; + view_area.lines = DOZ (WIDGET (view)->rect.lines, 2 * view->dpy_frame_size); + view_area.cols = DOZ (WIDGET (view)->rect.cols, 2 * view->dpy_frame_size); + + /* Most coordinates of the areas equal those of the whole viewer */ + view->status_area = view_area; + view->ruler_area = view_area; + view->data_area = view_area; + + /* Compute the heights of the areas */ + rest = view_area.lines; + + height = MIN (rest, 1); + view->status_area.lines = height; + rest -= height; + + height = (ruler == RULER_NONE || view->mode_flags.hex) ? 0 : 2; + height = MIN (rest, height); + view->ruler_area.lines = height; + rest -= height; + + view->data_area.lines = rest; + + /* Compute the position of the areas */ + y = view_area.y; + + view->status_area.y = y; + y += view->status_area.lines; + + if (ruler == RULER_TOP) + { + view->ruler_area.y = y; + y += view->ruler_area.lines; + } + + view->data_area.y = y; + y += view->data_area.lines; + + if (ruler == RULER_BOTTOM) + view->ruler_area.y = y; +} + +/* --------------------------------------------------------------------------------------------- */ + +void +mcview_update_bytes_per_line (WView * view) +{ + int cols = view->data_area.cols; + int bytes; + + if (cols < 9 + 17) + bytes = 4; + else + bytes = 4 * ((cols - 9) / ((cols <= 80) ? 17 : 18)); + + g_assert (bytes != 0); + + view->bytes_per_line = bytes; + view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */ +} + +/* --------------------------------------------------------------------------------------------- */ + +void +mcview_display_toggle_ruler (WView * view) +{ + static const enum ruler_type next[3] = + { + RULER_TOP, + RULER_BOTTOM, + RULER_NONE + }; + + g_assert ((size_t) ruler < 3); + + ruler = next[(size_t) ruler]; + mcview_compute_areas (view); + view->dirty++; +} + +/* --------------------------------------------------------------------------------------------- */ + +void +mcview_display_clean (WView * view) +{ + Widget *w = WIDGET (view); + + tty_setcolor (VIEW_NORMAL_COLOR); + widget_erase (w); + if (view->dpy_frame_size != 0) + tty_draw_box (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, FALSE); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +mcview_display_ruler (WView * view) +{ + static const char ruler_chars[] = "|----*----"; + const WRect *r = &view->ruler_area; + const int line_row = (ruler == RULER_TOP) ? 0 : 1; + const int nums_row = (ruler == RULER_TOP) ? 1 : 0; + + char r_buff[10]; + off_t cl; + int c; + + if (ruler == RULER_NONE || r->lines < 1) + return; + + tty_setcolor (VIEW_BOLD_COLOR); + for (c = 0; c < r->cols; c++) + { + cl = view->dpy_text_column + c; + if (line_row < r->lines) + { + widget_gotoyx (view, r->y + line_row, r->x + c); + tty_print_char (ruler_chars[cl % 10]); + } + + if ((cl != 0) && (cl % 10) == 0) + { + g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl); + if (nums_row < r->lines) + { + widget_gotoyx (view, r->y + nums_row, r->x + c - 1); + tty_print_string (r_buff); + } + } + } + tty_setcolor (VIEW_NORMAL_COLOR); +} + +/* --------------------------------------------------------------------------------------------- */ |