root/src/viewer/move.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. mcview_scroll_to_cursor
  2. mcview_movement_fixups
  3. mcview_move_up
  4. mcview_move_down
  5. mcview_move_left
  6. mcview_move_right
  7. mcview_moveto_top
  8. mcview_moveto_bottom
  9. mcview_moveto_bol
  10. mcview_moveto_eol
  11. mcview_moveto_offset
  12. mcview_moveto
  13. mcview_coord_to_offset
  14. mcview_offset_to_coord
  15. mcview_place_cursor
  16. mcview_moveto_match

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Functions for handle cursor movement
   4 
   5    Copyright (C) 1994-2019
   6    Free Software Foundation, Inc.
   7 
   8    Written by:
   9    Miguel de Icaza, 1994, 1995, 1998
  10    Janne Kukonlehto, 1994, 1995
  11    Jakub Jelinek, 1995
  12    Joseph M. Hinkle, 1996
  13    Norbert Warmuth, 1997
  14    Pavel Machek, 1998
  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
  19 
  20    This file is part of the Midnight Commander.
  21 
  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.
  26 
  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.
  31 
  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/>.
  34  */
  35 
  36 /*
  37    The following variables have to do with the current position and are
  38    updated by the cursor movement functions.
  39 
  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.
  45 
  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().
  50  */
  51 
  52 #include <config.h>
  53 
  54 #include "lib/global.h"
  55 #include "lib/tty/tty.h"
  56 #include "internal.h"
  57 
  58 /*** global variables ****************************************************************************/
  59 
  60 /*** file scope macro definitions ****************************************************************/
  61 
  62 /*** file scope type declarations ****************************************************************/
  63 
  64 /*** file scope variables ************************************************************************/
  65 
  66 /* --------------------------------------------------------------------------------------------- */
  67 /*** file scope functions ************************************************************************/
  68 /* --------------------------------------------------------------------------------------------- */
  69 
  70 static void
  71 mcview_scroll_to_cursor (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  72 {
  73     if (view->mode_flags.hex)
  74     {
  75         off_t bytes = view->bytes_per_line;
  76         off_t cursor = view->hex_cursor;
  77         off_t topleft = view->dpy_start;
  78         off_t displaysize;
  79 
  80         displaysize = view->data_area.height * bytes;
  81         if (topleft + displaysize <= cursor)
  82             topleft = mcview_offset_rounddown (cursor, bytes) - (displaysize - bytes);
  83         if (cursor < topleft)
  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;
  88     }
  89 }
  90 
  91 /* --------------------------------------------------------------------------------------------- */
  92 
  93 static void
  94 mcview_movement_fixups (WView * view, gboolean reset_search)
     /* [previous][next][first][last][top][bottom][index][help]  */
  95 {
  96     mcview_scroll_to_cursor (view);
  97     if (reset_search)
  98     {
  99         view->search_start = view->mode_flags.hex ? view->hex_cursor : view->dpy_start;
 100         view->search_end = view->search_start;
 101     }
 102     view->dirty++;
 103 }
 104 
 105 /* --------------------------------------------------------------------------------------------- */
 106 /*** public functions ****************************************************************************/
 107 /* --------------------------------------------------------------------------------------------- */
 108 
 109 void
 110 mcview_move_up (WView * view, off_t lines)
     /* [previous][next][first][last][top][bottom][index][help]  */
 111 {
 112     if (view->mode_flags.hex)
 113     {
 114         off_t bytes = lines * view->bytes_per_line;
 115 
 116         if (view->hex_cursor >= bytes)
 117         {
 118             view->hex_cursor -= bytes;
 119             if (view->hex_cursor < view->dpy_start)
 120             {
 121                 view->dpy_start = mcview_offset_doz (view->dpy_start, bytes);
 122                 view->dpy_paragraph_skip_lines = 0;
 123                 view->dpy_wrap_dirty = TRUE;
 124             }
 125         }
 126         else
 127         {
 128             view->hex_cursor %= view->bytes_per_line;
 129         }
 130     }
 131     else
 132     {
 133         mcview_ascii_move_up (view, lines);
 134     }
 135     mcview_movement_fixups (view, TRUE);
 136 }
 137 
 138 /* --------------------------------------------------------------------------------------------- */
 139 
 140 void
 141 mcview_move_down (WView * view, off_t lines)
     /* [previous][next][first][last][top][bottom][index][help]  */
 142 {
 143     off_t last_byte;
 144 
 145     last_byte = mcview_get_filesize (view);
 146 
 147     if (view->mode_flags.hex)
 148     {
 149         off_t i, limit;
 150 
 151         limit = mcview_offset_doz (last_byte, (off_t) view->bytes_per_line);
 152 
 153         for (i = 0; i < lines && view->hex_cursor < limit; i++)
 154         {
 155             view->hex_cursor += view->bytes_per_line;
 156             if (lines != 1)
 157             {
 158                 view->dpy_start += view->bytes_per_line;
 159                 view->dpy_paragraph_skip_lines = 0;
 160                 view->dpy_wrap_dirty = TRUE;
 161             }
 162         }
 163     }
 164     else
 165     {
 166         mcview_ascii_move_down (view, lines);
 167     }
 168     mcview_movement_fixups (view, TRUE);
 169 }
 170 
 171 /* --------------------------------------------------------------------------------------------- */
 172 
 173 void
 174 mcview_move_left (WView * view, off_t columns)
     /* [previous][next][first][last][top][bottom][index][help]  */
 175 {
 176     if (view->mode_flags.hex)
 177     {
 178         off_t old_cursor = view->hex_cursor;
 179 
 180         g_assert (columns == 1);
 181 
 182         if (view->hexview_in_text || !view->hexedit_lownibble)
 183         {
 184             if (view->hex_cursor > 0)
 185                 view->hex_cursor--;
 186         }
 187         if (!view->hexview_in_text)
 188             if (old_cursor > 0 || view->hexedit_lownibble)
 189                 view->hexedit_lownibble = !view->hexedit_lownibble;
 190     }
 191     else if (!view->mode_flags.wrap)
 192         view->dpy_text_column = mcview_offset_doz (view->dpy_text_column, columns);
 193     mcview_movement_fixups (view, FALSE);
 194 }
 195 
 196 /* --------------------------------------------------------------------------------------------- */
 197 
 198 void
 199 mcview_move_right (WView * view, off_t columns)
     /* [previous][next][first][last][top][bottom][index][help]  */
 200 {
 201     if (view->mode_flags.hex)
 202     {
 203         off_t last_byte;
 204         off_t old_cursor = view->hex_cursor;
 205 
 206         last_byte = mcview_offset_doz (mcview_get_filesize (view), 1);
 207 
 208         g_assert (columns == 1);
 209 
 210         if (view->hexview_in_text || view->hexedit_lownibble)
 211         {
 212             if (view->hex_cursor < last_byte)
 213                 view->hex_cursor++;
 214         }
 215         if (!view->hexview_in_text)
 216             if (old_cursor < last_byte || !view->hexedit_lownibble)
 217                 view->hexedit_lownibble = !view->hexedit_lownibble;
 218     }
 219     else if (!view->mode_flags.wrap)
 220     {
 221         view->dpy_text_column += columns;
 222     }
 223     mcview_movement_fixups (view, FALSE);
 224 }
 225 
 226 /* --------------------------------------------------------------------------------------------- */
 227 
 228 void
 229 mcview_moveto_top (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 230 {
 231     view->dpy_start = 0;
 232     view->dpy_paragraph_skip_lines = 0;
 233     mcview_state_machine_init (&view->dpy_state_top, 0);
 234     view->hex_cursor = 0;
 235     view->dpy_text_column = 0;
 236     mcview_movement_fixups (view, TRUE);
 237 }
 238 
 239 /* --------------------------------------------------------------------------------------------- */
 240 
 241 void
 242 mcview_moveto_bottom (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 243 {
 244     off_t filesize;
 245 
 246     mcview_update_filesize (view);
 247 
 248     if (view->growbuf_in_use)
 249         mcview_growbuf_read_all_data (view);
 250 
 251     filesize = mcview_get_filesize (view);
 252 
 253     if (view->mode_flags.hex)
 254     {
 255         view->hex_cursor = mcview_offset_doz (filesize, 1);
 256         mcview_movement_fixups (view, TRUE);
 257     }
 258     else
 259     {
 260         const off_t datalines = view->data_area.height;
 261 
 262         view->dpy_start = filesize;
 263         view->dpy_paragraph_skip_lines = 0;
 264         view->dpy_wrap_dirty = TRUE;
 265         mcview_move_up (view, datalines);
 266     }
 267 }
 268 
 269 /* --------------------------------------------------------------------------------------------- */
 270 
 271 void
 272 mcview_moveto_bol (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 273 {
 274     if (view->mode_flags.hex)
 275     {
 276         view->hex_cursor -= view->hex_cursor % view->bytes_per_line;
 277         view->dpy_text_column = 0;
 278     }
 279     else
 280     {
 281         mcview_ascii_moveto_bol (view);
 282     }
 283     mcview_movement_fixups (view, TRUE);
 284 }
 285 
 286 /* --------------------------------------------------------------------------------------------- */
 287 
 288 void
 289 mcview_moveto_eol (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 290 {
 291     off_t bol;
 292 
 293     if (view->mode_flags.hex)
 294     {
 295         off_t filesize;
 296 
 297         bol = mcview_offset_rounddown (view->hex_cursor, view->bytes_per_line);
 298         if (mcview_get_byte_indexed (view, bol, view->bytes_per_line - 1, NULL) == TRUE)
 299         {
 300             view->hex_cursor = bol + view->bytes_per_line - 1;
 301         }
 302         else
 303         {
 304             filesize = mcview_get_filesize (view);
 305             view->hex_cursor = mcview_offset_doz (filesize, 1);
 306         }
 307     }
 308     else
 309     {
 310         mcview_ascii_moveto_eol (view);
 311     }
 312     mcview_movement_fixups (view, FALSE);
 313 }
 314 
 315 /* --------------------------------------------------------------------------------------------- */
 316 
 317 void
 318 mcview_moveto_offset (WView * view, off_t offset)
     /* [previous][next][first][last][top][bottom][index][help]  */
 319 {
 320     if (view->mode_flags.hex)
 321     {
 322         view->hex_cursor = offset;
 323         view->dpy_start = offset - offset % view->bytes_per_line;
 324         view->dpy_paragraph_skip_lines = 0;
 325         view->dpy_wrap_dirty = TRUE;
 326     }
 327     else
 328     {
 329         view->dpy_start = offset;
 330         view->dpy_paragraph_skip_lines = 0;
 331         view->dpy_wrap_dirty = TRUE;
 332     }
 333     mcview_movement_fixups (view, TRUE);
 334 }
 335 
 336 /* --------------------------------------------------------------------------------------------- */
 337 
 338 void
 339 mcview_moveto (WView * view, off_t line, off_t col)
     /* [previous][next][first][last][top][bottom][index][help]  */
 340 {
 341     off_t offset;
 342 
 343     mcview_coord_to_offset (view, &offset, line, col);
 344     mcview_moveto_offset (view, offset);
 345 }
 346 
 347 /* --------------------------------------------------------------------------------------------- */
 348 
 349 void
 350 mcview_coord_to_offset (WView * view, off_t * ret_offset, off_t line, off_t column)
     /* [previous][next][first][last][top][bottom][index][help]  */
 351 {
 352     coord_cache_entry_t coord;
 353 
 354     coord.cc_line = line;
 355     coord.cc_column = column;
 356     coord.cc_nroff_column = column;
 357     mcview_ccache_lookup (view, &coord, CCACHE_OFFSET);
 358     *ret_offset = coord.cc_offset;
 359 }
 360 
 361 /* --------------------------------------------------------------------------------------------- */
 362 
 363 void
 364 mcview_offset_to_coord (WView * view, off_t * ret_line, off_t * ret_column, off_t offset)
     /* [previous][next][first][last][top][bottom][index][help]  */
 365 {
 366     coord_cache_entry_t coord;
 367 
 368     coord.cc_offset = offset;
 369     mcview_ccache_lookup (view, &coord, CCACHE_LINECOL);
 370 
 371     *ret_line = coord.cc_line;
 372     *ret_column = view->mode_flags.nroff ? coord.cc_nroff_column : coord.cc_column;
 373 }
 374 
 375 /* --------------------------------------------------------------------------------------------- */
 376 
 377 void
 378 mcview_place_cursor (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 379 {
 380     const screen_dimen top = view->data_area.top;
 381     const screen_dimen left = view->data_area.left;
 382     screen_dimen col = view->cursor_col;
 383     if (!view->hexview_in_text && view->hexedit_lownibble)
 384         col++;
 385     widget_move (view, top + view->cursor_row, left + col);
 386 }
 387 
 388 /* --------------------------------------------------------------------------------------------- */
 389 /** we have set view->search_start and view->search_end and must set
 390  * view->dpy_text_column and view->dpy_start
 391  * try to display maximum of match */
 392 
 393 void
 394 mcview_moveto_match (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 395 {
 396     if (view->mode_flags.hex)
 397     {
 398         view->hex_cursor = view->search_start;
 399         view->hexedit_lownibble = FALSE;
 400         view->dpy_start = view->search_start - view->search_start % view->bytes_per_line;
 401         view->dpy_end = view->search_end - view->search_end % view->bytes_per_line;
 402         view->dpy_paragraph_skip_lines = 0;
 403         view->dpy_wrap_dirty = TRUE;
 404     }
 405     else
 406     {
 407         view->dpy_start = mcview_bol (view, view->search_start, 0);
 408         view->dpy_paragraph_skip_lines = 0;
 409         view->dpy_wrap_dirty = TRUE;
 410     }
 411 
 412     mcview_scroll_to_cursor (view);
 413     view->dirty++;
 414 }
 415 
 416 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */