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, 2010 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 "lib/global.h"
57 #include "lib/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
)
92 off_t bytes
= lines
* view
->bytes_per_line
;
93 if (view
->hex_cursor
>= bytes
) {
94 view
->hex_cursor
-= bytes
;
95 if (view
->hex_cursor
< view
->dpy_start
)
96 view
->dpy_start
= mcview_offset_doz (view
->dpy_start
, bytes
);
98 view
->hex_cursor
%= view
->bytes_per_line
;
102 for (i
= 0; i
< lines
; i
++) {
103 new_offset
= mcview_bol (view
, view
->dpy_start
);
106 new_offset
= mcview_bol (view
, new_offset
);
109 view
->dpy_start
= new_offset
;
112 mcview_movement_fixups (view
, TRUE
);
115 /* --------------------------------------------------------------------------------------------- */
118 mcview_move_down (mcview_t
* view
, off_t lines
)
121 last_byte
= mcview_get_filesize (view
);
122 if (view
->hex_mode
) {
125 if (last_byte
>= (off_t
) view
->bytes_per_line
)
126 limit
= last_byte
- view
->bytes_per_line
;
129 for (i
= 0; i
< lines
&& view
->hex_cursor
< limit
; i
++) {
130 view
->hex_cursor
+= view
->bytes_per_line
;
132 view
->dpy_start
+= view
->bytes_per_line
;
136 for (i
= 0; i
< lines
; i
++) {
138 new_offset
= mcview_eol (view
, view
->dpy_start
);
139 view
->dpy_start
= new_offset
;
142 mcview_movement_fixups (view
, TRUE
);
145 /* --------------------------------------------------------------------------------------------- */
148 mcview_move_left (mcview_t
* view
, off_t columns
)
150 if (view
->hex_mode
) {
151 off_t old_cursor
= view
->hex_cursor
;
152 assert (columns
== 1);
153 if (view
->hexview_in_text
|| !view
->hexedit_lownibble
) {
154 if (view
->hex_cursor
> 0)
157 if (!view
->hexview_in_text
)
158 if (old_cursor
> 0 || view
->hexedit_lownibble
)
159 view
->hexedit_lownibble
= !view
->hexedit_lownibble
;
160 } else if (view
->text_wrap_mode
) {
163 if (view
->dpy_text_column
>= columns
)
164 view
->dpy_text_column
-= columns
;
166 view
->dpy_text_column
= 0;
168 mcview_movement_fixups (view
, FALSE
);
171 /* --------------------------------------------------------------------------------------------- */
174 mcview_move_right (mcview_t
* view
, off_t columns
)
176 if (view
->hex_mode
) {
178 off_t old_cursor
= view
->hex_cursor
;
179 last_byte
= mcview_offset_doz(mcview_get_filesize (view
), 1);
180 assert (columns
== 1);
181 if (view
->hexview_in_text
|| view
->hexedit_lownibble
) {
182 if (view
->hex_cursor
< last_byte
)
185 if (!view
->hexview_in_text
)
186 if (old_cursor
< last_byte
|| !view
->hexedit_lownibble
)
187 view
->hexedit_lownibble
= !view
->hexedit_lownibble
;
188 } else if (view
->text_wrap_mode
) {
191 view
->dpy_text_column
+= columns
;
193 mcview_movement_fixups (view
, FALSE
);
196 /* --------------------------------------------------------------------------------------------- */
199 mcview_scroll_to_cursor (mcview_t
* view
)
201 if (view
->hex_mode
) {
202 const off_t bytes
= view
->bytes_per_line
;
203 const off_t displaysize
= view
->data_area
.height
* bytes
;
204 const off_t cursor
= view
->hex_cursor
;
205 off_t topleft
= view
->dpy_start
;
207 if (topleft
+ displaysize
<= cursor
)
208 topleft
= mcview_offset_rounddown (cursor
, bytes
)
209 - (displaysize
- bytes
);
210 if (cursor
< topleft
)
211 topleft
= mcview_offset_rounddown (cursor
, bytes
);
212 view
->dpy_start
= topleft
;
216 /* --------------------------------------------------------------------------------------------- */
219 mcview_moveto_top (mcview_t
* view
)
222 view
->hex_cursor
= 0;
223 view
->dpy_text_column
= 0;
224 mcview_movement_fixups (view
, TRUE
);
227 /* --------------------------------------------------------------------------------------------- */
230 mcview_moveto_bottom (mcview_t
* view
)
232 off_t datalines
, lines_up
, filesize
, last_offset
;
234 mcview_update_filesize (view
);
236 if (view
->growbuf_in_use
)
237 mcview_growbuf_read_until (view
, OFFSETTYPE_MAX
);
239 filesize
= mcview_get_filesize (view
);
240 datalines
= view
->data_area
.height
;
241 lines_up
= mcview_offset_doz (datalines
, 1);
243 if (view
->hex_mode
) {
244 last_offset
= mcview_offset_doz (filesize
, 1);
245 view
->hex_cursor
= filesize
;
246 mcview_move_up (view
, lines_up
);
247 view
->hex_cursor
= last_offset
;
249 view
->dpy_start
= filesize
;
250 mcview_move_up (view
, 1);
254 /* --------------------------------------------------------------------------------------------- */
257 mcview_moveto_bol (mcview_t
* view
)
259 if (view
->hex_mode
) {
260 view
->hex_cursor
-= view
->hex_cursor
% view
->bytes_per_line
;
261 } else if (!view
->text_wrap_mode
) {
262 view
->dpy_start
= mcview_bol (view
, view
->dpy_start
);
264 mcview_movement_fixups (view
, TRUE
);
267 /* --------------------------------------------------------------------------------------------- */
270 mcview_moveto_eol (mcview_t
* view
)
272 if (view
->hex_mode
) {
275 bol
= mcview_offset_rounddown (view
->hex_cursor
, view
->bytes_per_line
);
276 if (mcview_get_byte_indexed (view
, bol
, view
->bytes_per_line
- 1, NULL
) == TRUE
) {
277 view
->hex_cursor
= bol
+ view
->bytes_per_line
- 1;
279 filesize
= mcview_get_filesize (view
);
280 view
->hex_cursor
= mcview_offset_doz (filesize
, 1);
283 mcview_movement_fixups (view
, FALSE
);
286 /* --------------------------------------------------------------------------------------------- */
289 mcview_moveto_offset (mcview_t
* view
, off_t offset
)
291 if (view
->hex_mode
) {
292 view
->hex_cursor
= offset
;
293 view
->dpy_start
= offset
- offset
% view
->bytes_per_line
;
295 view
->dpy_start
= offset
;
297 mcview_movement_fixups (view
, TRUE
);
300 /* --------------------------------------------------------------------------------------------- */
303 mcview_moveto (mcview_t
* view
, off_t line
, off_t col
)
307 mcview_coord_to_offset (view
, &offset
, line
, col
);
308 mcview_moveto_offset (view
, offset
);
311 /* --------------------------------------------------------------------------------------------- */
314 mcview_coord_to_offset (mcview_t
* view
, off_t
* ret_offset
, off_t line
, off_t column
)
316 coord_cache_entry_t coord
;
318 coord
.cc_line
= line
;
319 coord
.cc_column
= column
;
320 coord
.cc_nroff_column
= column
;
321 mcview_ccache_lookup (view
, &coord
, CCACHE_OFFSET
);
322 *ret_offset
= coord
.cc_offset
;
325 /* --------------------------------------------------------------------------------------------- */
328 mcview_offset_to_coord (mcview_t
* view
, off_t
* ret_line
, off_t
* ret_column
, off_t offset
)
330 coord_cache_entry_t coord
;
332 coord
.cc_offset
= offset
;
333 mcview_ccache_lookup (view
, &coord
, CCACHE_LINECOL
);
335 *ret_line
= coord
.cc_line
;
336 *ret_column
= (view
->text_nroff_mode
)
337 ? coord
.cc_nroff_column
: coord
.cc_column
;
340 /* --------------------------------------------------------------------------------------------- */
343 mcview_place_cursor (mcview_t
* view
)
345 const screen_dimen top
= view
->data_area
.top
;
346 const screen_dimen left
= view
->data_area
.left
;
347 screen_dimen col
= view
->cursor_col
;
348 if (!view
->hexview_in_text
&& view
->hexedit_lownibble
)
350 widget_move (&view
->widget
, top
+ view
->cursor_row
, left
+ col
);
353 /* --------------------------------------------------------------------------------------------- */
355 /* we have set view->search_start and view->search_end and must set
356 * view->dpy_text_column and view->dpy_start
357 * try to display maximum of match */
359 mcview_moveto_match (mcview_t
* view
)
363 offset
= view
->search_start
;
365 if (view
->hex_mode
) {
366 view
->hex_cursor
= offset
;
367 view
->dpy_start
= offset
- offset
% view
->bytes_per_line
;
369 view
->dpy_start
= mcview_bol (view
, offset
);
372 mcview_scroll_to_cursor (view
);
376 /* --------------------------------------------------------------------------------------------- */