change type of some parameters from int to long.
[midnight-commander.git] / src / viewer / move.c
blob96455e84f41658634fe2482525ac76c6e8396374
1 /*
2 Internal file viewer for the Midnight Commander
3 Functions for handle cursor movement
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 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.
39 The following variables have to do with the current position and are
40 updated by the cursor movement functions.
42 In hex view and wrapped text view mode, dpy_start marks the offset of
43 the top-left corner on the screen, in non-wrapping text mode it is
44 the beginning of the current line. In hex mode, hex_cursor is the
45 offset of the cursor. In non-wrapping text mode, dpy_text_column is
46 the number of columns that are hidden on the left side on the screen.
48 In hex mode, dpy_start is updated by the view_fix_cursor_position()
49 function in order to keep the other functions simple. In
50 non-wrapping text mode dpy_start and dpy_text_column are normalized
51 such that dpy_text_column < view_get_datacolumns().
54 #include <config.h>
56 #include "../src/global.h"
57 #include "../src/tty/tty.h"
58 #include "internal.h"
60 /*** global variables ****************************************************************************/
62 /*** file scope macro definitions ****************************************************************/
64 /*** file scope type declarations ****************************************************************/
66 /*** file scope variables ************************************************************************/
68 /*** file scope functions ************************************************************************/
70 static void
71 mcview_movement_fixups (mcview_t * view, gboolean reset_search)
73 mcview_scroll_to_cursor (view);
74 if (reset_search) {
75 view->search_start = view->dpy_start;
76 view->search_end = view->dpy_start;
78 view->dirty++;
81 /* --------------------------------------------------------------------------------------------- */
83 /*** public functions ****************************************************************************/
85 /* --------------------------------------------------------------------------------------------- */
87 void
88 mcview_move_up (mcview_t * view, off_t lines)
90 if (view->hex_mode) {
91 off_t bytes = lines * view->bytes_per_line;
92 if (view->hex_cursor >= bytes) {
93 view->hex_cursor -= bytes;
94 if (view->hex_cursor < view->dpy_start)
95 view->dpy_start = mcview_offset_doz (view->dpy_start, bytes);
96 } else {
97 view->hex_cursor %= view->bytes_per_line;
99 } else if (view->text_wrap_mode) {
100 const screen_dimen width = view->data_area.width;
101 off_t i, col, line, linestart;
103 for (i = 0; i < lines; i++) {
104 mcview_offset_to_coord (view, &line, &col, view->dpy_start);
105 if (col >= width) {
106 col -= width;
107 } else if (line >= 1) {
108 mcview_coord_to_offset (view, &linestart, line, 0);
109 mcview_offset_to_coord (view, &line, &col, linestart - 1);
111 /* if the only thing that would be displayed were a
112 * single newline character, advance to the previous
113 * part of the line. */
114 if (col > 0 && col % width == 0)
115 col -= width;
116 else
117 col -= col % width;
118 } else {
119 /* nothing to do */
121 mcview_coord_to_offset (view, &(view->dpy_start), line, col);
123 } else {
124 off_t line, column;
126 mcview_offset_to_coord (view, &line, &column, view->dpy_start);
127 line = mcview_offset_doz (line, lines);
128 mcview_coord_to_offset (view, &(view->dpy_start), line, column);
130 mcview_movement_fixups (view, (lines != 1));
133 /* --------------------------------------------------------------------------------------------- */
135 void
136 mcview_move_down (mcview_t * view, off_t lines)
138 if (view->hex_mode) {
139 off_t i, limit, last_byte;
141 last_byte = mcview_get_filesize (view);
142 if (last_byte >= (off_t) view->bytes_per_line)
143 limit = last_byte - view->bytes_per_line;
144 else
145 limit = 0;
146 for (i = 0; i < lines && view->hex_cursor < limit; i++) {
147 view->hex_cursor += view->bytes_per_line;
148 if (lines != 1)
149 view->dpy_start += view->bytes_per_line;
152 } else if (view->dpy_end == mcview_get_filesize (view)) {
153 /* don't move further down. There's nothing more to see. */
155 } else if (view->text_wrap_mode) {
156 off_t line, col, i;
157 int c;
159 for (i = 0; i < lines; i++) {
160 off_t new_offset, chk_line, chk_col;
162 mcview_offset_to_coord (view, &line, &col, view->dpy_start);
163 col += view->data_area.width;
164 mcview_coord_to_offset (view, &new_offset, line, col);
166 /* skip to the next line if the only thing that would be
167 * displayed is the newline character. */
168 mcview_offset_to_coord (view, &chk_line, &chk_col, new_offset);
169 if (chk_line == line && chk_col == col && mcview_get_byte (view, new_offset, &c) == TRUE
170 && c == '\n')
171 new_offset++;
173 view->dpy_start = new_offset;
176 } else {
177 off_t line, col;
179 mcview_offset_to_coord (view, &line, &col, view->dpy_start);
180 line += lines;
181 mcview_coord_to_offset (view, &(view->dpy_start), line, col);
183 mcview_movement_fixups (view, (lines != 1));
186 /* --------------------------------------------------------------------------------------------- */
188 void
189 mcview_move_left (mcview_t * view, off_t columns)
191 if (view->hex_mode) {
192 assert (columns == 1);
193 if (view->hexview_in_text || !view->hexedit_lownibble) {
194 if (view->hex_cursor > 0)
195 view->hex_cursor--;
197 if (!view->hexview_in_text)
198 view->hexedit_lownibble = !view->hexedit_lownibble;
199 } else if (view->text_wrap_mode) {
200 /* nothing to do */
201 } else {
202 if (view->dpy_text_column >= columns)
203 view->dpy_text_column -= columns;
204 else
205 view->dpy_text_column = 0;
207 mcview_movement_fixups (view, FALSE);
210 /* --------------------------------------------------------------------------------------------- */
212 void
213 mcview_move_right (mcview_t * view, off_t columns)
215 if (view->hex_mode) {
216 assert (columns == 1);
217 if (view->hexview_in_text || view->hexedit_lownibble) {
218 view->hex_cursor++;
220 if (!view->hexview_in_text)
221 view->hexedit_lownibble = !view->hexedit_lownibble;
222 } else if (view->text_wrap_mode) {
223 /* nothing to do */
224 } else {
225 view->dpy_text_column += columns;
227 mcview_movement_fixups (view, FALSE);
230 /* --------------------------------------------------------------------------------------------- */
232 void
233 mcview_scroll_to_cursor (mcview_t * view)
235 if (view->hex_mode) {
236 const off_t bytes = view->bytes_per_line;
237 const off_t displaysize = view->data_area.height * bytes;
238 const off_t cursor = view->hex_cursor;
239 off_t topleft = view->dpy_start;
241 if (topleft + displaysize <= cursor)
242 topleft = mcview_offset_rounddown (cursor, bytes)
243 - (displaysize - bytes);
244 if (cursor < topleft)
245 topleft = mcview_offset_rounddown (cursor, bytes);
246 view->dpy_start = topleft;
247 } else if (view->text_wrap_mode) {
248 off_t line, col, columns;
250 columns = view->data_area.width;
251 mcview_offset_to_coord (view, &line, &col, view->dpy_start + view->dpy_text_column);
252 if (columns != 0)
253 col = mcview_offset_rounddown (col, columns);
254 mcview_coord_to_offset (view, &(view->dpy_start), line, col);
255 view->dpy_text_column = 0;
256 } else {
257 /* nothing to do */
261 /* --------------------------------------------------------------------------------------------- */
263 void
264 mcview_moveto_top (mcview_t * view)
266 view->dpy_start = 0;
267 view->hex_cursor = 0;
268 view->dpy_text_column = 0;
269 mcview_movement_fixups (view, TRUE);
272 /* --------------------------------------------------------------------------------------------- */
274 void
275 mcview_moveto_bottom (mcview_t * view)
277 off_t datalines, lines_up, filesize, last_offset;
279 if (view->growbuf_in_use)
280 mcview_growbuf_read_until (view, OFFSETTYPE_MAX);
282 filesize = mcview_get_filesize (view);
283 last_offset = mcview_offset_doz (filesize, 1);
284 datalines = view->data_area.height;
285 lines_up = mcview_offset_doz (datalines, 1);
287 if (view->hex_mode) {
288 view->hex_cursor = filesize;
289 mcview_move_up (view, lines_up);
290 view->hex_cursor = last_offset;
291 } else {
292 view->dpy_start = last_offset;
293 mcview_moveto_bol (view);
294 mcview_move_up (view, lines_up);
296 mcview_movement_fixups (view, TRUE);
299 /* --------------------------------------------------------------------------------------------- */
301 void
302 mcview_moveto_bol (mcview_t * view)
304 if (view->hex_mode) {
305 view->hex_cursor -= view->hex_cursor % view->bytes_per_line;
306 } else if (view->text_wrap_mode) {
307 /* do nothing */
308 } else {
309 off_t line, column;
310 mcview_offset_to_coord (view, &line, &column, view->dpy_start);
311 mcview_coord_to_offset (view, &(view->dpy_start), line, 0);
312 view->dpy_text_column = 0;
314 mcview_movement_fixups (view, TRUE);
317 /* --------------------------------------------------------------------------------------------- */
319 void
320 mcview_moveto_eol (mcview_t * view)
322 if (view->hex_mode) {
323 off_t filesize, bol;
325 bol = mcview_offset_rounddown (view->hex_cursor, view->bytes_per_line);
326 if (mcview_get_byte_indexed (view, bol, view->bytes_per_line - 1, NULL) == TRUE) {
327 view->hex_cursor = bol + view->bytes_per_line - 1;
328 } else {
329 filesize = mcview_get_filesize (view);
330 view->hex_cursor = mcview_offset_doz (filesize, 1);
332 } else if (view->text_wrap_mode) {
333 /* nothing to do */
334 } else {
335 off_t line, col;
337 mcview_offset_to_coord (view, &line, &col, view->dpy_start);
338 mcview_coord_to_offset (view, &(view->dpy_start), line, OFFSETTYPE_MAX);
340 mcview_movement_fixups (view, FALSE);
343 /* --------------------------------------------------------------------------------------------- */
345 void
346 mcview_moveto_offset (mcview_t * view, off_t offset)
348 if (view->hex_mode) {
349 view->hex_cursor = offset;
350 view->dpy_start = offset - offset % view->bytes_per_line;
351 } else {
352 view->dpy_start = offset;
354 mcview_movement_fixups (view, TRUE);
357 /* --------------------------------------------------------------------------------------------- */
359 void
360 mcview_moveto (mcview_t * view, off_t line, off_t col)
362 off_t offset;
364 mcview_coord_to_offset (view, &offset, line, col);
365 mcview_moveto_offset (view, offset);
368 /* --------------------------------------------------------------------------------------------- */
370 void
371 mcview_coord_to_offset (mcview_t * view, off_t * ret_offset, off_t line, off_t column)
373 struct coord_cache_entry coord;
375 coord.cc_line = line;
376 coord.cc_column = column;
377 coord.cc_nroff_column = column;
378 mcview_ccache_lookup (view, &coord, CCACHE_OFFSET);
379 *ret_offset = coord.cc_offset;
382 /* --------------------------------------------------------------------------------------------- */
384 void
385 mcview_offset_to_coord (mcview_t * view, off_t * ret_line, off_t * ret_column, off_t offset)
387 struct coord_cache_entry coord;
389 coord.cc_offset = offset;
390 mcview_ccache_lookup (view, &coord, CCACHE_LINECOL);
392 if (ret_line)
393 *ret_line = coord.cc_line;
395 if (ret_column)
396 *ret_column = (view->text_nroff_mode)
397 ? coord.cc_nroff_column : coord.cc_column;
400 /* --------------------------------------------------------------------------------------------- */
402 void
403 mcview_place_cursor (mcview_t * view)
405 const screen_dimen top = view->data_area.top;
406 const screen_dimen left = view->data_area.left;
407 screen_dimen col;
409 col = view->cursor_col;
410 if (!view->hexview_in_text && view->hexedit_lownibble)
411 col++;
412 widget_move (&view->widget, top + view->cursor_row, left + col);
415 /* --------------------------------------------------------------------------------------------- */
417 /* we have set view->search_start and view->search_end and must set
418 * view->dpy_text_column and view->dpy_start
419 * try to display maximum of match */
420 void
421 mcview_moveto_match (mcview_t * view)
423 off_t search_line, search_col, offset;
425 mcview_offset_to_coord (view, &search_line, &search_col, view->search_start);
426 if (!view->hex_mode)
427 search_col = 0;
429 mcview_coord_to_offset (view, &offset, search_line, search_col);
431 if (view->hex_mode) {
432 view->hex_cursor = offset;
433 view->dpy_start = offset - offset % view->bytes_per_line;
434 } else {
435 view->dpy_start = offset;
438 mcview_scroll_to_cursor (view);
439 view->dirty++;
442 /* --------------------------------------------------------------------------------------------- */