1
1
mc/src/viewer/move.c
Slava Zanko e3f7a0544b Code cleanup for compile with -Werror option
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2010-05-26 10:17:04 +04:00

482 строки
14 KiB
C

/*
Internal file viewer for the Midnight Commander
Functions for handle cursor movement
Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
Written by: 1994, 1995, 1998 Miguel de Icaza
1994, 1995 Janne Kukonlehto
1995 Jakub Jelinek
1996 Joseph M. Hinkle
1997 Norbert Warmuth
1998 Pavel Machek
2004 Roland Illig <roland.illig@gmx.de>
2005 Roland Illig <roland.illig@gmx.de>
2009 Slava Zanko <slavazanko@google.com>
2009 Andrew Borodin <aborodin@vmail.ru>
2009, 2010 Ilia Maslakov <il.smind@gmail.com>
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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
/*
The following variables have to do with the current position and are
updated by the cursor movement functions.
In hex view and wrapped text view mode, dpy_start marks the offset of
the top-left corner on the screen, in non-wrapping text mode it is
the beginning of the current line. In hex mode, hex_cursor is the
offset of the cursor. In non-wrapping text mode, dpy_text_column is
the number of columns that are hidden on the left side on the screen.
In hex mode, dpy_start is updated by the view_fix_cursor_position()
function in order to keep the other functions simple. In
non-wrapping text mode dpy_start and dpy_text_column are normalized
such that dpy_text_column < view_get_datacolumns().
*/
#include <config.h>
#include "lib/global.h"
#include "lib/tty/tty.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
static void
mcview_movement_fixups (mcview_t * view, gboolean reset_search)
{
mcview_scroll_to_cursor (view);
if (reset_search)
{
view->search_start = view->dpy_start;
view->search_end = view->dpy_start;
}
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_up (mcview_t * view, off_t lines)
{
off_t new_offset;
if (view->hex_mode)
{
off_t bytes = lines * view->bytes_per_line;
if (view->hex_cursor >= bytes)
{
view->hex_cursor -= bytes;
if (view->hex_cursor < view->dpy_start)
view->dpy_start = mcview_offset_doz (view->dpy_start, bytes);
}
else
{
view->hex_cursor %= view->bytes_per_line;
}
}
else
{
off_t i;
for (i = 0; i < lines; i++)
{
off_t cur_bol;
cur_bol = new_offset = mcview_bol (view, view->dpy_start);
if (new_offset > 0)
new_offset--;
new_offset = mcview_bol (view, new_offset);
if (new_offset < 0)
new_offset = 0;
if (view->text_wrap_mode)
{
size_t last_row_length = (view->dpy_start - new_offset) % view->data_area.width;
if (last_row_length != 0 && cur_bol == view->dpy_start)
new_offset = max (new_offset, (off_t) (view->dpy_start - last_row_length));
else
new_offset = max (new_offset, view->dpy_start - view->data_area.width);
}
view->dpy_start = new_offset;
}
}
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_down (mcview_t * view, off_t lines)
{
off_t last_byte;
last_byte = mcview_get_filesize (view);
if (view->hex_mode)
{
off_t i, limit;
if (last_byte >= (off_t) view->bytes_per_line)
limit = last_byte - view->bytes_per_line;
else
limit = 0;
for (i = 0; i < lines && view->hex_cursor < limit; i++)
{
view->hex_cursor += view->bytes_per_line;
if (lines != 1)
view->dpy_start += view->bytes_per_line;
}
}
else
{
off_t i;
off_t new_offset = 0;
if (view->dpy_end - view->dpy_start > last_byte - view->dpy_end)
{
i = 0;
new_offset = view->dpy_end;
while (view->dpy_end < last_byte && lines-- > 0)
{
new_offset = mcview_eol (view, view->dpy_end);
if (view->text_wrap_mode)
new_offset = min (new_offset, view->dpy_end + view->data_area.width);
view->dpy_end = new_offset;
new_offset = mcview_eol (view, view->dpy_start);
if (view->text_wrap_mode)
new_offset = min (new_offset, view->dpy_start + view->data_area.width);
view->dpy_start = new_offset;
}
view->dpy_end = last_byte;
}
else
{
for (i = 0; i < lines && view->dpy_end < last_byte && new_offset < last_byte; i++)
{
new_offset = mcview_eol (view, view->dpy_start);
if (view->text_wrap_mode)
new_offset = min (new_offset, view->dpy_start + view->data_area.width);
view->dpy_start = new_offset;
}
}
}
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_left (mcview_t * view, off_t columns)
{
if (view->hex_mode)
{
off_t old_cursor = view->hex_cursor;
assert (columns == 1);
if (view->hexview_in_text || !view->hexedit_lownibble)
{
if (view->hex_cursor > 0)
view->hex_cursor--;
}
if (!view->hexview_in_text)
if (old_cursor > 0 || view->hexedit_lownibble)
view->hexedit_lownibble = !view->hexedit_lownibble;
}
else
{
if (view->dpy_text_column >= columns)
view->dpy_text_column -= columns;
else
view->dpy_text_column = 0;
}
mcview_movement_fixups (view, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_right (mcview_t * view, off_t columns)
{
if (view->hex_mode)
{
off_t last_byte;
off_t old_cursor = view->hex_cursor;
last_byte = mcview_offset_doz (mcview_get_filesize (view), 1);
assert (columns == 1);
if (view->hexview_in_text || view->hexedit_lownibble)
{
if (view->hex_cursor < last_byte)
view->hex_cursor++;
}
if (!view->hexview_in_text)
if (old_cursor < last_byte || !view->hexedit_lownibble)
view->hexedit_lownibble = !view->hexedit_lownibble;
}
else
{
view->dpy_text_column += columns;
}
mcview_movement_fixups (view, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_scroll_to_cursor (mcview_t * view)
{
if (view->hex_mode)
{
const off_t bytes = view->bytes_per_line;
const off_t displaysize = view->data_area.height * bytes;
const off_t cursor = view->hex_cursor;
off_t topleft = view->dpy_start;
if (topleft + displaysize <= cursor)
topleft = mcview_offset_rounddown (cursor, bytes) - (displaysize - bytes);
if (cursor < topleft)
topleft = mcview_offset_rounddown (cursor, bytes);
view->dpy_start = topleft;
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_top (mcview_t * view)
{
view->dpy_start = 0;
view->hex_cursor = 0;
view->dpy_text_column = 0;
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_bottom (mcview_t * view)
{
const off_t datalines = view->data_area.height;
off_t filesize;
mcview_update_filesize (view);
if (view->growbuf_in_use)
mcview_growbuf_read_until (view, OFFSETTYPE_MAX);
filesize = mcview_get_filesize (view);
if (view->hex_mode)
{
off_t lines_up, last_offset;
lines_up = mcview_offset_doz (datalines, 1);
last_offset = mcview_offset_doz (filesize, 1);
view->hex_cursor = filesize;
mcview_move_up (view, lines_up);
view->hex_cursor = last_offset;
}
else
{
view->dpy_start = filesize;
mcview_move_up (view, datalines);
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_bol (mcview_t * view)
{
if (view->hex_mode)
{
view->hex_cursor -= view->hex_cursor % view->bytes_per_line;
}
else if (!view->text_wrap_mode)
{
view->dpy_start = mcview_bol (view, view->dpy_start);
}
view->dpy_text_column = 0;
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_eol (mcview_t * view)
{
off_t bol;
if (view->hex_mode)
{
off_t filesize;
bol = mcview_offset_rounddown (view->hex_cursor, view->bytes_per_line);
if (mcview_get_byte_indexed (view, bol, view->bytes_per_line - 1, NULL) == TRUE)
{
view->hex_cursor = bol + view->bytes_per_line - 1;
}
else
{
filesize = mcview_get_filesize (view);
view->hex_cursor = mcview_offset_doz (filesize, 1);
}
}
else
{
off_t eol;
bol = mcview_bol (view, view->dpy_start);
eol = mcview_eol (view, view->dpy_start);
if (!view->utf8)
{
if (eol > bol)
view->dpy_text_column = eol - bol;
}
else
{
char *str = NULL;
switch (view->datasource)
{
case DS_STDIO_PIPE:
case DS_VFS_PIPE:
str = mcview_get_ptr_growing_buffer (view, bol);
break;
case DS_FILE:
str = mcview_get_ptr_file (view, bol);
break;
case DS_STRING:
str = mcview_get_ptr_string (view, bol);
break;
case DS_NONE:
break;
}
if (str != NULL && eol > bol)
view->dpy_text_column = g_utf8_strlen (str, eol - bol);
else
view->dpy_text_column = eol - bol;
}
view->dpy_text_column = max (0, view->dpy_text_column - view->data_area.width);
}
mcview_movement_fixups (view, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_offset (mcview_t * view, off_t offset)
{
if (view->hex_mode)
{
view->hex_cursor = offset;
view->dpy_start = offset - offset % view->bytes_per_line;
}
else
{
view->dpy_start = offset;
}
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto (mcview_t * view, off_t line, off_t col)
{
off_t offset;
mcview_coord_to_offset (view, &offset, line, col);
mcview_moveto_offset (view, offset);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_coord_to_offset (mcview_t * view, off_t * ret_offset, off_t line, off_t column)
{
coord_cache_entry_t coord;
coord.cc_line = line;
coord.cc_column = column;
coord.cc_nroff_column = column;
mcview_ccache_lookup (view, &coord, CCACHE_OFFSET);
*ret_offset = coord.cc_offset;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_offset_to_coord (mcview_t * view, off_t * ret_line, off_t * ret_column, off_t offset)
{
coord_cache_entry_t coord;
coord.cc_offset = offset;
mcview_ccache_lookup (view, &coord, CCACHE_LINECOL);
*ret_line = coord.cc_line;
*ret_column = (view->text_nroff_mode) ? coord.cc_nroff_column : coord.cc_column;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_place_cursor (mcview_t * view)
{
const screen_dimen top = view->data_area.top;
const screen_dimen left = view->data_area.left;
screen_dimen col = view->cursor_col;
if (!view->hexview_in_text && view->hexedit_lownibble)
col++;
widget_move (&view->widget, top + view->cursor_row, left + col);
}
/* --------------------------------------------------------------------------------------------- */
/* we have set view->search_start and view->search_end and must set
* view->dpy_text_column and view->dpy_start
* try to display maximum of match */
void
mcview_moveto_match (mcview_t * view)
{
off_t offset;
offset = view->search_start;
if (view->hex_mode)
{
view->hex_cursor = offset;
view->dpy_start = offset - offset % view->bytes_per_line;
}
else
{
view->dpy_start = mcview_bol (view, offset);
}
mcview_scroll_to_cursor (view);
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */