2 Internal file viewer for the Midnight Commander
3 Functions for handle cursor movement
5 Copyright (C) 1994-2016
6 Free Software Foundation, Inc.
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
12 Joseph M. Hinkle, 1996
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009
17 Andrew Borodin <aborodin@vmail.ru>, 2009, 2013
18 Ilia Maslakov <il.smind@gmail.com>, 2009, 2010
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 3 of the License,
25 or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU 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, see <http://www.gnu.org/licenses/>.
37 The following variables have to do with the current position and are
38 updated by the cursor movement functions.
40 In hex view and wrapped text view mode, dpy_start marks the offset of
41 the top-left corner on the screen, in non-wrapping text mode it is
42 the beginning of the current line. In hex mode, hex_cursor is the
43 offset of the cursor. In non-wrapping text mode, dpy_text_column is
44 the number of columns that are hidden on the left side on the screen.
46 In hex mode, dpy_start is updated by the view_fix_cursor_position()
47 function in order to keep the other functions simple. In
48 non-wrapping text mode dpy_start and dpy_text_column are normalized
49 such that dpy_text_column < view_get_datacolumns().
54 #include "lib/global.h"
55 #include "lib/tty/tty.h"
58 /*** global variables ****************************************************************************/
60 /*** file scope macro definitions ****************************************************************/
62 /*** file scope type declarations ****************************************************************/
64 /*** file scope variables ************************************************************************/
66 /* --------------------------------------------------------------------------------------------- */
67 /*** file scope functions ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
71 mcview_scroll_to_cursor (WView
* view
)
75 off_t bytes
= view
->bytes_per_line
;
76 off_t cursor
= view
->hex_cursor
;
77 off_t topleft
= view
->dpy_start
;
80 displaysize
= view
->data_area
.height
* bytes
;
81 if (topleft
+ displaysize
<= cursor
)
82 topleft
= mcview_offset_rounddown (cursor
, bytes
) - (displaysize
- bytes
);
84 topleft
= mcview_offset_rounddown (cursor
, bytes
);
85 view
->dpy_start
= topleft
;
86 view
->dpy_paragraph_skip_lines
= 0;
87 view
->dpy_wrap_dirty
= TRUE
;
91 /* --------------------------------------------------------------------------------------------- */
94 mcview_movement_fixups (WView
* view
, gboolean reset_search
)
96 mcview_scroll_to_cursor (view
);
99 view
->search_start
= view
->hex_mode
? view
->hex_cursor
: view
->dpy_start
;
100 view
->search_end
= view
->search_start
;
105 /* --------------------------------------------------------------------------------------------- */
106 /*** public functions ****************************************************************************/
107 /* --------------------------------------------------------------------------------------------- */
110 mcview_move_up (WView
* view
, off_t lines
)
114 off_t bytes
= lines
* view
->bytes_per_line
;
115 if (view
->hex_cursor
>= bytes
)
117 view
->hex_cursor
-= bytes
;
118 if (view
->hex_cursor
< view
->dpy_start
)
120 view
->dpy_start
= mcview_offset_doz (view
->dpy_start
, bytes
);
121 view
->dpy_paragraph_skip_lines
= 0;
122 view
->dpy_wrap_dirty
= TRUE
;
127 view
->hex_cursor
%= view
->bytes_per_line
;
132 mcview_ascii_move_up (view
, lines
);
134 mcview_movement_fixups (view
, TRUE
);
137 /* --------------------------------------------------------------------------------------------- */
140 mcview_move_down (WView
* view
, off_t lines
)
143 last_byte
= mcview_get_filesize (view
);
148 limit
= mcview_offset_doz (last_byte
, (off_t
) view
->bytes_per_line
);
150 for (i
= 0; i
< lines
&& view
->hex_cursor
< limit
; i
++)
152 view
->hex_cursor
+= view
->bytes_per_line
;
155 view
->dpy_start
+= view
->bytes_per_line
;
156 view
->dpy_paragraph_skip_lines
= 0;
157 view
->dpy_wrap_dirty
= TRUE
;
163 mcview_ascii_move_down (view
, lines
);
165 mcview_movement_fixups (view
, TRUE
);
168 /* --------------------------------------------------------------------------------------------- */
171 mcview_move_left (WView
* view
, off_t columns
)
175 off_t old_cursor
= view
->hex_cursor
;
177 g_assert (columns
== 1);
179 if (view
->hexview_in_text
|| !view
->hexedit_lownibble
)
181 if (view
->hex_cursor
> 0)
184 if (!view
->hexview_in_text
)
185 if (old_cursor
> 0 || view
->hexedit_lownibble
)
186 view
->hexedit_lownibble
= !view
->hexedit_lownibble
;
188 else if (!view
->text_wrap_mode
)
189 view
->dpy_text_column
= mcview_offset_doz (view
->dpy_text_column
, columns
);
190 mcview_movement_fixups (view
, FALSE
);
193 /* --------------------------------------------------------------------------------------------- */
196 mcview_move_right (WView
* view
, off_t columns
)
201 off_t old_cursor
= view
->hex_cursor
;
203 last_byte
= mcview_offset_doz (mcview_get_filesize (view
), 1);
205 g_assert (columns
== 1);
207 if (view
->hexview_in_text
|| view
->hexedit_lownibble
)
209 if (view
->hex_cursor
< last_byte
)
212 if (!view
->hexview_in_text
)
213 if (old_cursor
< last_byte
|| !view
->hexedit_lownibble
)
214 view
->hexedit_lownibble
= !view
->hexedit_lownibble
;
216 else if (!view
->text_wrap_mode
)
218 view
->dpy_text_column
+= columns
;
220 mcview_movement_fixups (view
, FALSE
);
223 /* --------------------------------------------------------------------------------------------- */
226 mcview_moveto_top (WView
* view
)
229 view
->dpy_paragraph_skip_lines
= 0;
230 mcview_state_machine_init (&view
->dpy_state_top
, 0);
231 view
->hex_cursor
= 0;
232 view
->dpy_text_column
= 0;
233 mcview_movement_fixups (view
, TRUE
);
236 /* --------------------------------------------------------------------------------------------- */
239 mcview_moveto_bottom (WView
* view
)
243 mcview_update_filesize (view
);
245 if (view
->growbuf_in_use
)
246 mcview_growbuf_read_until (view
, OFFSETTYPE_MAX
);
248 filesize
= mcview_get_filesize (view
);
252 view
->hex_cursor
= mcview_offset_doz (filesize
, 1);
253 mcview_movement_fixups (view
, TRUE
);
257 const off_t datalines
= view
->data_area
.height
;
259 view
->dpy_start
= filesize
;
260 view
->dpy_paragraph_skip_lines
= 0;
261 view
->dpy_wrap_dirty
= TRUE
;
262 mcview_move_up (view
, datalines
);
266 /* --------------------------------------------------------------------------------------------- */
269 mcview_moveto_bol (WView
* view
)
273 view
->hex_cursor
-= view
->hex_cursor
% view
->bytes_per_line
;
274 view
->dpy_text_column
= 0;
278 mcview_ascii_moveto_bol (view
);
280 mcview_movement_fixups (view
, TRUE
);
283 /* --------------------------------------------------------------------------------------------- */
286 mcview_moveto_eol (WView
* view
)
293 bol
= mcview_offset_rounddown (view
->hex_cursor
, view
->bytes_per_line
);
294 if (mcview_get_byte_indexed (view
, bol
, view
->bytes_per_line
- 1, NULL
) == TRUE
)
296 view
->hex_cursor
= bol
+ view
->bytes_per_line
- 1;
300 filesize
= mcview_get_filesize (view
);
301 view
->hex_cursor
= mcview_offset_doz (filesize
, 1);
306 mcview_ascii_moveto_eol (view
);
308 mcview_movement_fixups (view
, FALSE
);
311 /* --------------------------------------------------------------------------------------------- */
314 mcview_moveto_offset (WView
* view
, off_t offset
)
318 view
->hex_cursor
= offset
;
319 view
->dpy_start
= offset
- offset
% view
->bytes_per_line
;
320 view
->dpy_paragraph_skip_lines
= 0;
321 view
->dpy_wrap_dirty
= TRUE
;
325 view
->dpy_start
= offset
;
326 view
->dpy_paragraph_skip_lines
= 0;
327 view
->dpy_wrap_dirty
= TRUE
;
329 mcview_movement_fixups (view
, TRUE
);
332 /* --------------------------------------------------------------------------------------------- */
335 mcview_moveto (WView
* view
, off_t line
, off_t col
)
339 mcview_coord_to_offset (view
, &offset
, line
, col
);
340 mcview_moveto_offset (view
, offset
);
343 /* --------------------------------------------------------------------------------------------- */
346 mcview_coord_to_offset (WView
* view
, off_t
* ret_offset
, off_t line
, off_t column
)
348 coord_cache_entry_t coord
;
350 coord
.cc_line
= line
;
351 coord
.cc_column
= column
;
352 coord
.cc_nroff_column
= column
;
353 mcview_ccache_lookup (view
, &coord
, CCACHE_OFFSET
);
354 *ret_offset
= coord
.cc_offset
;
357 /* --------------------------------------------------------------------------------------------- */
360 mcview_offset_to_coord (WView
* view
, off_t
* ret_line
, off_t
* ret_column
, off_t offset
)
362 coord_cache_entry_t coord
;
364 coord
.cc_offset
= offset
;
365 mcview_ccache_lookup (view
, &coord
, CCACHE_LINECOL
);
367 *ret_line
= coord
.cc_line
;
368 *ret_column
= (view
->text_nroff_mode
) ? coord
.cc_nroff_column
: coord
.cc_column
;
371 /* --------------------------------------------------------------------------------------------- */
374 mcview_place_cursor (WView
* view
)
376 const screen_dimen top
= view
->data_area
.top
;
377 const screen_dimen left
= view
->data_area
.left
;
378 screen_dimen col
= view
->cursor_col
;
379 if (!view
->hexview_in_text
&& view
->hexedit_lownibble
)
381 widget_move (view
, top
+ view
->cursor_row
, left
+ col
);
384 /* --------------------------------------------------------------------------------------------- */
385 /** we have set view->search_start and view->search_end and must set
386 * view->dpy_text_column and view->dpy_start
387 * try to display maximum of match */
390 mcview_moveto_match (WView
* view
)
394 view
->hex_cursor
= view
->search_start
;
395 view
->hexedit_lownibble
= FALSE
;
396 view
->dpy_start
= view
->search_start
- view
->search_start
% view
->bytes_per_line
;
397 view
->dpy_end
= view
->search_end
- view
->search_end
% view
->bytes_per_line
;
398 view
->dpy_paragraph_skip_lines
= 0;
399 view
->dpy_wrap_dirty
= TRUE
;
403 view
->dpy_start
= mcview_bol (view
, view
->search_start
, 0);
404 view
->dpy_paragraph_skip_lines
= 0;
405 view
->dpy_wrap_dirty
= TRUE
;
408 mcview_scroll_to_cursor (view
);
412 /* --------------------------------------------------------------------------------------------- */