summaryrefslogtreecommitdiffstats
path: root/src/viewer/display.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/viewer/display.c')
-rw-r--r--src/viewer/display.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/viewer/display.c b/src/viewer/display.c
new file mode 100644
index 0000000..e76c4dd
--- /dev/null
+++ b/src/viewer/display.c
@@ -0,0 +1,404 @@
+/*
+ Internal file viewer for the Midnight Commander
+ Function for whow info on display
+
+ Copyright (C) 1994-2023
+ 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 ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** 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 = buttonbar_find (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 (buttonbar_find (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);
+}
+
+/* --------------------------------------------------------------------------------------------- */