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
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,
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().
56 #include "../src/global.h"
57 #include "../src/tty/tty.h"
60 /*** global variables ****************************************************************************/
62 /*** file scope macro definitions ****************************************************************/
64 /*** file scope type declarations ****************************************************************/
66 /*** file scope variables ************************************************************************/
68 /*** file scope functions ************************************************************************/
71 mcview_movement_fixups (mcview_t
* view
, gboolean reset_search
)
73 mcview_scroll_to_cursor (view
);
75 view
->search_start
= view
->dpy_start
;
76 view
->search_end
= view
->dpy_start
;
81 /* --------------------------------------------------------------------------------------------- */
83 /*** public functions ****************************************************************************/
85 /* --------------------------------------------------------------------------------------------- */
88 mcview_move_up (mcview_t
* view
, off_t lines
)
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
);
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
);
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)
121 mcview_coord_to_offset (view
, &(view
->dpy_start
), line
, col
);
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 /* --------------------------------------------------------------------------------------------- */
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
;
146 for (i
= 0; i
< lines
&& view
->hex_cursor
< limit
; i
++) {
147 view
->hex_cursor
+= view
->bytes_per_line
;
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
) {
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
173 view
->dpy_start
= new_offset
;
179 mcview_offset_to_coord (view
, &line
, &col
, view
->dpy_start
);
181 mcview_coord_to_offset (view
, &(view
->dpy_start
), line
, col
);
183 mcview_movement_fixups (view
, (lines
!= 1));
186 /* --------------------------------------------------------------------------------------------- */
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)
197 if (!view
->hexview_in_text
)
198 view
->hexedit_lownibble
= !view
->hexedit_lownibble
;
199 } else if (view
->text_wrap_mode
) {
202 if (view
->dpy_text_column
>= columns
)
203 view
->dpy_text_column
-= columns
;
205 view
->dpy_text_column
= 0;
207 mcview_movement_fixups (view
, FALSE
);
210 /* --------------------------------------------------------------------------------------------- */
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
) {
220 if (!view
->hexview_in_text
)
221 view
->hexedit_lownibble
= !view
->hexedit_lownibble
;
222 } else if (view
->text_wrap_mode
) {
225 view
->dpy_text_column
+= columns
;
227 mcview_movement_fixups (view
, FALSE
);
230 /* --------------------------------------------------------------------------------------------- */
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
);
253 col
= mcview_offset_rounddown (col
, columns
);
254 mcview_coord_to_offset (view
, &(view
->dpy_start
), line
, col
);
255 view
->dpy_text_column
= 0;
261 /* --------------------------------------------------------------------------------------------- */
264 mcview_moveto_top (mcview_t
* view
)
267 view
->hex_cursor
= 0;
268 view
->dpy_text_column
= 0;
269 mcview_movement_fixups (view
, TRUE
);
272 /* --------------------------------------------------------------------------------------------- */
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
;
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 /* --------------------------------------------------------------------------------------------- */
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
) {
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 /* --------------------------------------------------------------------------------------------- */
320 mcview_moveto_eol (mcview_t
* view
)
322 if (view
->hex_mode
) {
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;
329 filesize
= mcview_get_filesize (view
);
330 view
->hex_cursor
= mcview_offset_doz (filesize
, 1);
332 } else if (view
->text_wrap_mode
) {
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 /* --------------------------------------------------------------------------------------------- */
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
;
352 view
->dpy_start
= offset
;
354 mcview_movement_fixups (view
, TRUE
);
357 /* --------------------------------------------------------------------------------------------- */
360 mcview_moveto (mcview_t
* view
, off_t line
, off_t col
)
364 mcview_coord_to_offset (view
, &offset
, line
, col
);
365 mcview_moveto_offset (view
, offset
);
368 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
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
);
393 *ret_line
= coord
.cc_line
;
396 *ret_column
= (view
->text_nroff_mode
)
397 ? coord
.cc_nroff_column
: coord
.cc_column
;
400 /* --------------------------------------------------------------------------------------------- */
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
;
409 col
= view
->cursor_col
;
410 if (!view
->hexview_in_text
&& view
->hexedit_lownibble
)
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 */
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
);
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
;
435 view
->dpy_start
= offset
;
438 mcview_scroll_to_cursor (view
);
442 /* --------------------------------------------------------------------------------------------- */