#include<stdio.h> 
 
/* 




                 VV                   VV    EEEEEEEEEEEEEE   
                  VV                 VV     EE  
                   VV               VV      EE
                    VV             VV       EE
                     VV           VV        EE
                      VV         VV         EEEEEEEEEEEEEE
                       VV       VV          EE
                        VV     VV           EE
                         VV   VV            EE
                          VV VV             EE
                           VVV              EE
                            V               EEEEEEEEEEEEEE
                                                       
 
 
 
 
                       MODULE  : cursor.c
 
                       VERSION : v3.5
 
                       REVISED : 10 Jul 2005

                       AUTHOR  : Michael A. Campbell
 
 
 
 
 
 


                          FUNCTIONAL DESCRIPTION
                          ----------------------
 
               This module contains the cursor commands that are executed
 
               when the user types up-arrow, down-arrow, left-arrow,
 
               and right-arrow.  As well, the HOME command is implemented
 
               here.










*/

/* .page */

/*****************
 * INCLUDE FILES *
 *****************/

#include <curses.h>

#include "../def/common.def"
#include "../def/cmdix.def"

#include "../str/vestruct.str"

#include "../inc/vedbase.inc"
#include "../inc/termif.inc"
#include "../inc/kbdif.inc"

#include "../ext/termif.ext"
#include "../ext/veutils.ext"
#include "../ext/lnklst.ext"
#include "../ext/cursor.ext"

/* .page */

/*************************
 * PUBLIC PROCEDURES     *
 *************************/

void cursor_top_of_page_cmd ()

/****************************************************************************
 *                                                                          *
 * This command moves the cursor to the top of the file display page.       *
 *                                                                          *
 ****************************************************************************/

begin

   update_curr_line ();

   curr_line = curr_screen.top;
   ti_move_cursor ( curr_screen.cx, (curr_screen.cy = 2) );

end /* cursor_top_of_page_cmd */


void cursor_middle_of_page_cmd ()

/****************************************************************************
 *                                                                          *
 * This command moves the cursor to the middle of the file display page.    *
 *                                                                          *
 ****************************************************************************/

begin
   int actual, status;

   update_curr_line ();

   curr_line = traverse_list ( &curr_file, curr_screen.top, '+', &actual, 
                              (lines - 3)/2, &status );

   ti_move_cursor ( curr_screen.cx, (curr_screen.cy = actual+2) );

end /* cursor_middle_of_page_cmd */


void cursor_bottom_of_page_cmd ()

/****************************************************************************
 *                                                                          *
 * This command moves the cursor to the bottom of the file display page.    *
 *                                                                          *
 ****************************************************************************/

begin

   int actual, status;

   update_curr_line ();

   curr_line = traverse_list ( &curr_file, curr_screen.top, '+', &actual, 
                              (lines - 3), &status );

   ti_move_cursor ( curr_screen.cx, (curr_screen.cy = actual+2) );

end /* cursor_bottom_of_page_cmd */

/* .page */

void cursor_left_cmd ()

/****************************************************************************
 *                                                                          *
 *   Move the cursor one position to the left.                              *
 *                                                                          *
 ****************************************************************************/

begin
    update_curr_line ();

    if (curr_screen.cx > 0) 
    begin
        curr_screen.cx -= 1;
        if (curr_screen.cx < columns - 1) then
            ti_cursor_left ();
    end

    else if (curr_screen.cx == 0) 
    begin
       /* User has entered cursor left at the left margin. Attempt to wrap  */
       /* up to the end of the previous line, if it exists.                 */

       if ( curr_line->bwd_link != (struct node *) &curr_file ) begin
          cursor_up_cmd ();
          ext_end_cmd ();
       end
    end

    curr_screen.direction = rcl;

end /* cursor_left_cmd */

/* .page */

void cursor_right_cmd ()

/****************************************************************************
 *                                                                          *
 *   Move the cursor one position to the right.                             *
 *                                                                          *
 ****************************************************************************/

begin
    update_curr_line ();

    if (curr_screen.cx < MAX_LINE_SIZE - 2) 
    begin
        curr_screen.cx += 1;
    
        if (curr_screen.cx < columns) then
            ti_cursor_right ();
    end
    else
       write_ve_msg ( "Maximum line size reached" );

    curr_screen.direction = rcr;

end /* cursor_right_cmd */

/* .page */

void cursor_down_cmd ()

/****************************************************************************
 *                                                                          *
 *   Move the cursor down one line. If this moves beyond the end of the     *
 *   currently displayed screen, scroll the screen by one line.             *
 *                                                                          *
 ****************************************************************************/

begin
    register int length;

    update_curr_line ();

    if (curr_line->fwd_link != EOL) begin

        /* If not at end of file, then proceed */

        curr_line = curr_line->fwd_link;

        if (curr_screen.cy == lines - 1) 
        begin
            /* Delete a line at the top, creating a blank line at bottom,   */
            /* and then clear that line. Write out the new line.            */
            
            ti_delete_line ( 2 );
            mv_writeln (ti_get_left_cx(), lines-1, TRUE, 
                        curr_line->text, curr_line->length, 0);

            /* Update curr_screen and we are done.                          */

            curr_screen.top    = curr_screen.top->fwd_link;
            curr_screen.bottom = curr_screen.bottom->fwd_link;

        end

        else 
        begin
           /* Not bottom of screen - just move to next line                 */

            curr_screen.cy++;
            ti_cursor_down ();
        end

    end

    curr_screen.direction = rcd;

end /* cursor_down */

/* .page */

void cursor_up_cmd ()

/******************************************************************************
 *                                                                            *
 *   Move the cursor up one line.  If this runs off the top of the displayed  *
 *   screen, scroll the screen by one line.                                   *
 *                                                                            *
 ******************************************************************************/

begin
    update_curr_line ();    /* Update the curr line before moving on        */

    /* If we have not reached the top of the file, then move the cursor     */

    if (curr_line->bwd_link != (struct node *) &curr_file) 
    begin
        curr_line = curr_line->bwd_link;

        /* If we have reached the top of the displayed screen, then we must */
        /* scroll the screen to account for this                            */

        if (curr_screen.cy == 2) 
        begin
            ti_insert_line ( 2 );
            mv_writeln (ti_get_left_cx(), 2, TRUE, curr_line->text, curr_line->length, 0);

            /* Update the curr_screen structure, taking account of the case */
            /* where we may not have a full screen beneath us - if so use   */
            /* longer update_curr_screen approach (does a line traverse)    */

            if ( curr_screen.bottom-> fwd_link != NULL )
            begin
               curr_screen.top    = curr_screen.top->bwd_link;
               curr_screen.bottom = curr_screen.bottom->bwd_link;
            end
            else
               update_curr_screen (curr_screen.cy);
        end

        /* Else we have not reached the end of the screen, and a simple move */
        /* of the cursor will suffice                                        */

        else 
        begin
            curr_screen.cy--;
            ti_cursor_up ();
        end

    end

    curr_screen.direction = rcu;

end /* cursor_up_cmd */

/* .page */

void page_down ()

/****************************************************************************
 *                                                                          *
 *   Move down one screen in the file, and display the new screen. If       *
 *   possible, leave the cursor at the same (x,y) as it was on the last     *
 *   screen. Called from extended_motion_cmd.                               *
 *                                                                          *
 ****************************************************************************/

begin
    int cy, actual1, actual2;

    if (displayed (curr_file.tail, &cy)) begin

        /* Check for collision with end of file. If the end of file is      */
        /* already on screen, we can't go down any further. Just go to it.  */

        curr_line = curr_file.tail;

        curr_screen.cy = cy;
        curr_screen.cx = ti_get_left_cx ();

        restore_cursor ();
    end

    else begin
        /* Page down by making the top of the new screen the bottom of the  */
        /* old one, and then traversing a screen's worth of file lines to   */
        /* reach the bottom of the new screen. Do this in two hops, one     */
        /* to the old .cy position (to set the current line equal to the    */
        /* previous .cy) and then the remainder, to the bottom of the       */
        /* the screen.                                                      */

        curr_screen.top = curr_screen.bottom;

        curr_line = traverse_list (&curr_file, curr_screen.top, '+', &actual1,
                                   curr_screen.cy-2, &status);
        curr_screen.cy = cy = actual1 + 2;

        curr_screen.bottom = traverse_list (&curr_file, curr_line, '+', 
                                            &actual2, lines-cy-1, &status);
        draw_curr_screen ();
    end

    /* Now display the "current position in file" info as the VE message    */

    if ( last_cmd_ix == ext_pgup_ix || last_cmd_ix == info_ix || 
         last_cmd_ix == ext_pgdn_ix || last_cmd_ix == jump_ix ) 
    begin

      /* Last command executed was one of PgUp, PgDn or Info. In all cases, */
      /* the curr_line_num var is valid. Simply increment it and use it.    */

      curr_line_num = curr_line_num + (lines - 3);

      if ( curr_line_num > curr_file.nodes ) 
         curr_line_num = curr_file.nodes;

      display_curr_position ();
   end

   else
      info_cmd ();

end /* page_down */

/* .page */

void page_up ()

/****************************************************************************
 *                                                                          *
 *   Move up one screen in the file, and display the new screen. If         *
 *   possible, leave the cursor at the same (x,y) as it was on the last     *
 *   screen. Called from extended_motion_cmd.                               *
 *                                                                          *
 ****************************************************************************/

begin
   int lines1, lines2, actual1, actual2;

   /* Page up by making the bottom of the new screen the top of the    */
   /* old one, and then traversing a screen's worth of file lines to   */
   /* reach the top of the new screen. Do this in two hops, one        */
   /* to the old .cy position (to set the current line equal to the    */
   /* previous .cy) and then the remainder, to the bottom of the       */
   /* screen.                                                          */

   curr_screen.bottom = curr_screen.top;

   lines1 = lines - curr_screen.cy - 1;
   curr_line = traverse_list (&curr_file, curr_screen.bottom, '-', &actual1,
                              lines1, &status);

   curr_screen.cy = lines - actual1 - 1;

   lines2 = curr_screen.cy - 2;
   curr_screen.top = traverse_list (&curr_file, curr_line, '-', 
                                    &actual2, lines2, &status);

   /* Check for a collision with the top of file. If the top of file   */
   /* was less than one screen height away, we haven't moved forward a */
   /* full screen. In this case, simply jump to the top of file.       */

   if ( actual1+actual2 != lines-3 ) begin
      curr_screen.top = curr_line = curr_file.head;
      curr_screen.bottom = traverse_list ( &curr_file, curr_line, '+', 
                                                &actual1, lines-3, &status );
      curr_screen.cx = ti_get_left_cx ();
      curr_screen.cy = 2;
   end

   draw_curr_screen ();

   /* Now display the "current position in file" info as the VE message    */

   if ( last_cmd_ix == ext_pgup_ix || last_cmd_ix == info_ix || 
        last_cmd_ix == ext_pgdn_ix || last_cmd_ix == jump_ix )
   begin
     /* Last command executed was one of PgUp, PgDn or Info. In all cases, */
     /* the curr_line_num var is valid. Simply increment it and use it.    */

     curr_line_num = curr_line_num - (lines - 3);

     if ( curr_line_num < 1 ) 
        curr_line_num = 1;

     display_curr_position ();
  end

  else
     info_cmd ();

end /* page_up */

/* .page */

void extended_motion_cmd ()

/****************************************************************************
 *                                                                          *
 *   Move the cursor to the end of a block in the direction that has been   *
 *   defined in the last cursor movement.                                   *
 *                                                                          *
 ****************************************************************************/

begin
    update_curr_line ();

    /* Move to start of a line                                              */

    if (curr_screen.direction == rcl) begin
        curr_screen.cx = 0;
        restore_cursor ();
    end

    /* Move to the end of a line                                            */

    if (curr_screen.direction == rcr) begin
        curr_screen.cx = curr_line->length;
        restore_cursor ();
    end

    /* Move to the next page                                                */

    if (curr_screen.direction == rcd) then
        page_down ();

    /* Move to the previous page                                            */

    if (curr_screen.direction == rcu) then
        page_up ();

end /* extended_motion_cmd */

/* .page */

void edge_cmd ()

/****************************************************************************
 *                                                                          *
 *   Move the cursor to the screen edge indicated by the direction defined  *
 *   in the last cursor movement.                                           *
 *                                                                          *
 ****************************************************************************/

begin
    update_curr_line ();

    /* Move to the left screen edge                                         */

    if (curr_screen.direction == rcl) begin
        curr_screen.cx = ti_get_left_cx();
        restore_cursor ();
    end

    /* Move to the right screen edge                                        */

    if (curr_screen.direction == rcr) begin
        curr_screen.cx = ti_get_right_cx();
        restore_cursor ();
    end

    /* Move to the bottom screen edge                                       */

    if (curr_screen.direction == rcd) then
        cursor_bottom_of_page_cmd ();

    /* Move to the top screen edge                                          */

    if (curr_screen.direction == rcu) then
        cursor_top_of_page_cmd ();

end /* edge_cmd */

/* .page */

void ext_home_cmd ()

/*************************************************************************
 * This command implements the logical intent of the HOME key on the     *
 * "standard" PC extended keyboard. The "normal" intent of this key is   *
 * to move the cursor to the start of the line. This function returns    *
 * no value.                                                             *
 *************************************************************************/

begin
    /* Simply directly set the HOME direction, and then call the existing */
    /* extended_motion_cmd ().                                            */

    curr_screen.direction = rcl;
    extended_motion_cmd ();

end /* ext_home_cmd */

/* .page */

void ext_end_cmd ()

/*************************************************************************
 * This command implements the logical intent of the END key on the      *
 * "standard" PC extended keyboard. The "normal" intent of this key is   *
 * to move the cursor to the end of the line. This function returns      *
 * no value.                                                             *
 *************************************************************************/

begin
    /* Simply directly set the HOME direction, and then call the existing */
    /* extended_motion_cmd ().                                            */

    curr_screen.direction = rcr;
    extended_motion_cmd ();

end /* ext_end_cmd */

/* .page */

void ext_pgup_cmd ()

/*************************************************************************
 * This command implements the logical intent of the PageUp key on the   *
 * "standard" PC extended keyboard. The "normal" intent of this key is   *
 * to move the screen up by one page. This function returns no value.    *
 *************************************************************************/

begin
    /* Simply directly set the HOME direction, and then call the existing */
    /* home_cmd ().                                                       */

    update_curr_line ();

    curr_screen.direction = rcu;
    page_up ();

end /* ext_pgup_cmd */

/* .page */

void ext_pgdn_cmd ()

/*************************************************************************
 * This command implements the logical intent of the PageDown key on the *
 * "standard" PC extended keyboard. The "normal" intent of this key is   *
 * to move the screen down by one page. This function returns no value.  *
 *************************************************************************/

begin
    /* Simply directly set the HOME direction, and then call the existing */
    /* home_cmd ().                                                       */

    update_curr_line ();

    curr_screen.direction = rcd;
    page_down ();

end /* ext_pgdn_cmd */

/* .page */

void half_up_cmd ()

/*************************************************************************
 * This command scrolls the screen up by half a page.                    *
 *************************************************************************/

begin
    int actual;

    update_curr_line ();

    if ( curr_screen.top != curr_file.head )
       curr_screen.top = traverse_list (&curr_file, curr_screen.top, '+', 
                                        &actual, ((lines - 3)/ 2), &status);
    curr_screen.direction = rcu;
    page_up ();

end /* half_up_cmd */

/* .page */

void half_down_cmd ()

/*************************************************************************
 * This command scrolls the screen down by half a page.                  *
 *************************************************************************/

begin
    int actual;

    update_curr_line ();

    if ( curr_screen.bottom != curr_file.tail )
       curr_screen.bottom = traverse_list (&curr_file, curr_screen.bottom, '-', 
                                           &actual, ((lines - 3) / 2), &status);
    curr_screen.direction = rcd;
    page_down ();

end /* half_down_cmd */

/* .page */

void half_left_cmd ()

/*************************************************************************
 * This command scrolls the screen left by half a screen width           *
 *************************************************************************/

begin
    char msg_buf [82];

    curr_screen.cx -= physical_cols / 2;
    if ( curr_screen.cx < 0 ) 
       curr_screen.cx = 0;

    ti_scroll_left ( 50 );    /* scroll left by 50% of screen width      */

   sprintf ( msg_buf, "%s %d", "Scrolled left to column", ti_get_left_cx() );
   write_ve_msg ( msg_buf );

end /* half_left_cmd */

/* .page */

void half_right_cmd ()

/*************************************************************************
 * This command scrolls the screen right by half a screen width          *
 *************************************************************************/

begin
    char msg_buf [82];

    curr_screen.cx += physical_cols / 2;
    if ( curr_screen.cx > columns - 1 )
       curr_screen.cx = columns - 1;

    ti_scroll_right ( 50 );   /* scroll right by 50% of screen width     */

   sprintf ( msg_buf, "%s %d", "Scrolled right to column", ti_get_left_cx() );
   write_ve_msg ( msg_buf );

end /* half_right_cmd */

