/*----------------------------------------------------------------------------
 *     input.c
 *
 *   This file contains the routines to handle user input via the mouse and
 * menus.  The routines farm out the users requests to appropriate input
 * handler routines if necessary.
 *----------------------------------------------------------------------------
*/

#include   <exec/types.h>
#include   <intuition/intuition.h>
#include   "defs.h"
#include   "ds.h"
#include   "menu.h"
#include   "input.h"


get_input ()
{
 struct IntuiMessage  *message ;
 extern struct IntuiMessage   *GetMsg() ;
 ULONG   class ;
 USHORT  code ;
 APTR    address ;

 /*---------------------------------------------------------------------------
  *   The program waits for user input from the mouse.  The Wait() function
  * puts the program to sleep while waiting.  The Class and Code field of the
  * IntuiMessage contains the information required to decide what the user
  * request was.
  *   Input is in 2 major classes, menu selections and requester gadget
  * selections.  All the requester gadget selections are sent to
  * "handle_gadget()" in the req.c file.
  *---------------------------------------------------------------------------
 */

 LOOP_FOREVER   {
     Wait (1 << window->UserPort->mp_SigBit) ;

     while (message = GetMsg (window->UserPort))   {

         class    = message->Class ;       /* store message info */
         code     = message->Code ;        /* before replying */
         address  = message->IAddress ;
         ReplyMsg (message) ;

         switch (class)   {

            case MENUPICK:     execute_menu_selection (code) ;
                               break ;

            case GADGETUP:     handle_gadget ((struct Gadget *) address) ;
                               break ;

            default:           close_down ("Error: Bad Intuition message\n") ;
                               break ;
         }
     }
 }
} 


execute_menu_selection (menu_num)

USHORT  menu_num ;
{
 struct MenuItem  *item ;
 extern struct MenuItem   *ItemAddress() ;

 /*---------------------------------------------------------------------------
  *   The user has requested a menu function.  The MENUNUM macro extracts the
  * menu selected by the user.
  *   The NextSelect field of the selected menu items data structure will point
  * to a valid menu item (or subitem) if the user has selected more than one
  * menu function, before releasing the left mouse button..
  *---------------------------------------------------------------------------
 */
 while (menu_num != MENUNULL)   {
     switch (MENUNUM (menu_num))   {

        case ANIMATE_MENU:  animate (menu_num) ;
                            break ;

        case GOAL_MENU:     set_goal (menu_num) ;
                            break ;

        case ROTATE_MENU:   rotate (menu_num) ;
                            break ;

        case VIEW_MENU:     set_view (menu_num) ;
                            break ;

        case PROJECT_MENU:  project (menu_num) ;
                            break ;

        default:            close_down ("Error: Bad menu number\n") ;
                            break ;
     }
     item  = ItemAddress (first_menu, menu_num) ;
     menu_num  = item->NextSelect ; 
 }
}


animate (menu_num)

USHORT  menu_num ;
{
 int  restore_ref_axes = NO ; ;

 /*---------------------------------------------------------------------------
  *   The user has selected an Animate menu function.  The ITEMNUM macro
  * extracts the menu item selected by the user.
  *   The "arm" menu item animates the arm using the joint settings specified
  * with the "set all joints" menu item.  The window is closed down and the
  * the double buffered screen is used to display the animation.  See the
  * anim.c file for the details.
  *   The "flypast" menu item does a flypast of the current arm position
  * using a set of viewing transformations pre-calculated and stored in
  * "flypast_trans[][][]".  See the fly.c file for the details.
  *   The "both" menu item is not yet implemented.  It will do both of the
  * above at the same time.
  *---------------------------------------------------------------------------
 */
 switch (ITEMNUM (menu_num))   {

  case ARM_ITEM:     if (SPCmp (rot_info.max_angle_change, ffp.zero.i) == 0)
                        Request (&no_change, window) ;
                     else  {
                        if (menu_choices.ref_axes == ON)   {
                           restore_ref_axes = YES ;
                           menu_choices.ref_axes   = OFF ;
                        }
                        ClearMenuStrip (window) ;  
                        CloseWindow (window) ;
                        open_db_screen_for_animation () ;
                        make_window () ;                 
                        setup_window_temporary_draw_area () ;
                       if (restore_ref_axes)  
                           menu_choices.ref_axes   = ON ;
                        update_joint_transformations () ;
                        transform_links () ;
                        set_screen_coords () ;
                        draw_image (window->RPort) ;
                       if (menu_choices.viewtype != PARALLEL)
                          change_persp_option (ON, YES) ;
                     }
                     menu_choices.goaltype  = ROTATE ;
                     break ;

  case FLYPAST_ITEM: if (menu_choices.ref_axes == ON)   {
                         restore_ref_axes = YES ;
                         menu_choices.ref_axes   = OFF ;
                     }
                     ClearMenuStrip (window) ;
                     CloseWindow (window) ;
                     open_db_screen_for_flypast () ;
                     make_window () ;
                     setup_window_temporary_draw_area () ;
                     if (restore_ref_axes)  
                        menu_choices.ref_axes   = ON ;       
                     transform_links () ;
                     set_screen_coords () ;
                     draw_image (window->RPort) ;  
                     if (menu_choices.viewtype != PARALLEL)
                        change_persp_option (ON, YES) ;  
                     break ;

    case BOTH_ITEM:  /* not yet implemented */
                     dummy_ack ("Both") ;
                     break ;  

    default:         close_down ("Error: Bad menu item number\n") ;
                     break ;
 }
}


set_goal (menu_num)

USHORT  menu_num ;
{
 /*---------------------------------------------------------------------------
  *   The user has selected a Goal menu function.  The ITEMNUM macro
  * extracts the menu item selected by the user.
  *---------------------------------------------------------------------------
 */
 switch (ITEMNUM (menu_num))   {

    case SET_ALL_JOINTS_ITEM:   if (menu_choices.goaltype  == SET_ALL_JOINTS)
                                   Request (&anim_cancel_set, window) ;
                                else  {
                                   menu_choices.goaltype  = SET_ALL_JOINTS ;
                                   Request (&get_shoulder_angles, window) ;
                                }
                                break ;

    case DISTAL_GOAL_ITEM:      /* not yet implemented */
                                dummy_ack ("Distal") ;
                                break ;

    case PLACE_OBSTACLES_ITEM:  /* not yet implemented */ 
                                dummy_ack ("Place") ;
                                break ;

    default:                    close_down ("Error: Bad menu item number\n") ;
                                break ;
 }
}


rotate (menu_num)

USHORT  menu_num ;
{
 /*---------------------------------------------------------------------------
  *   The user has selected a Rotate menu function.  The ITEMNUM macro
  * extracts the menu item selected by the user.
  *   One of the joints has been selected for rotation.  A requester is 
  * presented for the users joint settings input.
  *---------------------------------------------------------------------------
 */
 switch (ITEMNUM (menu_num))   {

    case SHOULDER_ITEM:    if (menu_choices.goaltype  == SET_ALL_JOINTS)
                              Request (&anim_cancel_rot, window) ;  
                           else 
                              Request (&get_shoulder_angles, window) ;
                           break ;

    case ELBOW_ITEM:       if (menu_choices.goaltype  == SET_ALL_JOINTS)
                              Request (&anim_cancel_rot, window) ; 
                           else  
                              Request (&get_elbow_angle, window) ;
                           break ;

    case WRIST_ITEM:       if (menu_choices.goaltype  == SET_ALL_JOINTS)
                              Request (&anim_cancel_rot, window) ;  
                           else 
                              Request (&get_wrist_angles, window) ;
                           break ;

    default:               close_down  ("Error: Bad menu item number\n") ;
                           break ;
 }
}


set_view (menu_num)

USHORT  menu_num ;
{
 /*---------------------------------------------------------------------------
  *   The user has selected a View menu function.  The ITEMNUM macro
  * extracts the menu item selected by the user.
  *   The user may select the rendering type (wire frame or solid view with
  * hidden surfaces removed), whether the reference axes are to be displayed,
  * the viewpoint, and a choice of parallel or perspective view.
  *---------------------------------------------------------------------------
 */
 switch (ITEMNUM (menu_num))   {

    case WIRE_FRAME_ITEM:      if (menu_choices.render == SOLID_VIEW)   {
                                  menu_choices.render  = WIRE_FRAME ; 
                                  draw_image (window->RPort) ; 
                               }
                               break ;

    case SOLID_VIEW_ITEM:      if (menu_choices.render == WIRE_FRAME)   {
                                  menu_choices.render  = SOLID_VIEW ; 
                                  draw_image (window->RPort) ;
                               }
                               break ;

    case REF_AXES_ITEM:        adjust_ref_axes (menu_num) ;
                               break ;

    case VIEWPOINT_ITEM:       change_viewpoint (menu_num) ;
                               break ;

    case PERSPECTIVE_ITEM:     set_perspective (menu_num) ;
                               break ;

    default:                   close_down ("Error: Bad menu item number\n") ;
                               break ;
 }  
}


set_perspective (menu_num)

USHORT  menu_num ;
{
 short  draw_persp  = NO ;

 /*---------------------------------------------------------------------------
  *   The user has selected a a Perspective subitem from the View menu.
  * The SUBNUM macro extracts the menu subitem selected by the user.
  *   The choices are parallel, wide angle or telephoto views.
  *------------------ ---------------------------------------------------------
 */
 switch (SUBNUM (menu_num))   {

    case PARALLEL_SUBITEM:   if (menu_choices.viewtype != PARALLEL)  {
                                menu_choices.viewtype = PARALLEL ;
                                change_persp_option (ON, NO) ;
                                SetRast (window->RPort, COLOR0) ;  
                                transform_links () ;
                                set_screen_coords () ;
                                draw_image (window->RPort) ;                              
                             }
                             break ;

    case WIDE_ANGLE_SUBITEM: if (menu_choices.viewtype == PARALLEL)  {
                                draw_persp  = YES ;
                                menu_choices.viewtype = WIDE_ANGLE ;
                                SetRast (window->RPort, COLOR0) ;
                                perspective_transformation
                                                 (ffp.wide_angle_aperture.i) ;
                             }
                             break ;

    case TELEPHOTO_SUBITEM:  if (menu_choices.viewtype == PARALLEL)  {
                                draw_persp  = YES ;
                                menu_choices.viewtype = TELEPHOTO ;
                                SetRast (window->RPort, COLOR0) ;
                                perspective_transformation
                                                  (ffp.telephoto_aperture.i) ;                                         
                             }
                             break ;

    default:                 close_down ("Error: Bad menu sub item number\n") ;
                             break ;
 }
 if (draw_persp)   {
    set_screen_coords () ;
    draw_image (window->RPort) ; 
    change_persp_option (OFF, NO) ;   
 }
}


change_viewpoint (menu_num)

USHORT  menu_num ;
{
 int  change  = NO ;
 /*---------------------------------------------------------------------------
  *   The user has selected a a Viewpoint subitem from the View menu.
  * The SUBNUM macro extracts the menu subitem selected by the user.
  *   The viewpoints are front, side, top and 3 angled views.
  *------------------ ---------------------------------------------------------
 */
 switch (SUBNUM (menu_num))   {
                                                    
   case FRONT_SUBITEM: if (menu_choices.viewpoint != FRONT_VIEW)   { 
                         menu_choices.viewpoint  = FRONT_VIEW ;
                         rot_info.curr_view_trans = (int *)&view_trans.front ;
                         change  = YES ;
                       }
                       break ;

   case SIDE_SUBITEM:  if (menu_choices.viewpoint != SIDE_VIEW)  { 
                         menu_choices.viewpoint  = SIDE_VIEW ;
                         rot_info.curr_view_trans = (int *)&view_trans.side ;
                         change  = YES ;
                       }

                       break ;
   case TOP_SUBITEM:   if (menu_choices.viewpoint != TOP_VIEW)   {  
                         menu_choices.viewpoint  = TOP_VIEW ;
                         rot_info.curr_view_trans = (int *)&view_trans.top ;
                         change  = YES ;
                       }
                       break ;

  case ANGLE1_SUBITEM: if (menu_choices.viewpoint != ANGLE1_VIEW)  { 
                         menu_choices.viewpoint  = ANGLE1_VIEW ;
                         rot_info.curr_view_trans = (int *)&view_trans.angle1 ;
                         change  = YES ;
                       }
                       break ;

  case ANGLE2_SUBITEM: if (menu_choices.viewpoint != ANGLE2_VIEW)   {
                         menu_choices.viewpoint  = ANGLE2_VIEW ;
                         rot_info.curr_view_trans = (int *)&view_trans.angle2 ;
                         change  = YES ;
                       }
                       break ;

  case ANGLE3_SUBITEM: if (menu_choices.viewpoint != ANGLE3_VIEW)   {
                         menu_choices.viewpoint  = ANGLE3_VIEW ;
                         rot_info.curr_view_trans = (int *)&view_trans.angle3 ;
                         change  = YES ;
                       }
                       break ;

  default:             close_down ("Error: Bad menu sub item number\n") ;
                       break ;
 }
 if (change)   {
    change_persp_option (ON, YES) ;
    SetRast (window->RPort, COLOR0) ;
    transform_links () ;
    set_screen_coords () ;
    draw_image (window->RPort) ;
 }
}


adjust_ref_axes (menu_num)

USHORT  menu_num ;
{
static short  first_time = YES ;

 /*---------------------------------------------------------------------------
  *   Turn the reference axes on or off.
  *---------------------------------------------------------------------------
 */
 switch (SUBNUM (menu_num))   {
                                                    
   case ON_SUBITEM:      if (menu_choices.ref_axes != ON)  {
                            if (first_time)   {
                               first_time  = NO ;
                               Request (&req_rot_info, window) ;
                            }
                            menu_choices.ref_axes  = ON ;
                            draw_ref_axes (window->RPort) ;
                         }
                         break ;

   case OFF_SUBITEM:     if (menu_choices.ref_axes != OFF)   {
                            menu_choices.ref_axes  = OFF ;
                            SetRast (window->RPort, COLOR0) ;
                            transform_links () ;
                            set_screen_coords () ;
                            draw_image (window->RPort) ;
                         }
                         break ;

 default:                close_down ("Error: Bad menu sub item number\n") ;
                         break ;
 }
}


project (menu_num)

USHORT  menu_num ;
{
 /*---------------------------------------------------------------------------
  *   The user has selected a Project menu function.  The ITEMNUM macro
  * extracts the menu item selected by the user.
  *   The choices available are to quit the program, change the color
  *  settings, on screen help, information on yours truly, or to start over.
  *---------------------------------------------------------------------------
 */
 switch (ITEMNUM (menu_num))   {

    case QUIT_ITEM:        close_down (NORMAL_EXIT) ;
                           break ;

    case COLORS_ITEM:      set_colors (menu_num) ;
                           break ;

    case HELP_ITEM:        /* not yet implemented */
                           dummy_ack ("Help") ;
                           break ;

    case AUTHOR_ITEM:      Request (&author_info, window) ;
                           break ;

    case NEW_ITEM:         start_over () ;
                           break ;

    default:               close_down ("Error: Bad menu item number\n") ;
                           break ;
 }
}
 

set_colors (menu_num)

USHORT  menu_num ;
{
 /*---------------------------------------------------------------------------
  *   The user has selected a Colors subitem from the Project menu.
  * The SUBNUM macro extracts the menu subitem selected by the user.
  *   There is a  choice of 4 color settings, each using colors selected
  * from the 4096 available.
  *---------------------------------------------------------------------------
 */
 switch (SUBNUM (menu_num))   {
                                                    
   case DEFAULT_SUBITEM:    LoadRGB4 (&screen->ViewPort,
                                      colortable.start, NUM_COLORS) ;
                            menu_choices.colors  = START ;
                            break ;

  case SET1_SUBITEM:        LoadRGB4 (&screen->ViewPort,
                                      colortable.set1, NUM_COLORS) ;
                            menu_choices.colors  = SET1 ;
                            break ;

  case SET2_SUBITEM:        LoadRGB4 (&screen->ViewPort,
                                      colortable.set2, NUM_COLORS) ;
                            menu_choices.colors  = SET2 ;
                            break ;

  case SET3_SUBITEM:        LoadRGB4 (&screen->ViewPort,
                                      colortable.set3, NUM_COLORS) ;
                            menu_choices.colors  = SET3 ;
                            break ;

 default:                   close_down ("Error: Bad menu sub item number\n") ;
                            break ;
 }
}


change_persp_option (turn_on, alter_flags)

short  turn_on,  alter_flags ;
{
 /*---------------------------------------------------------------------------
  *    Turn the wide angle and telephoto perspective options off if the user
  * selects one.  The menu items will be ghosted.
  *    Turn them back on if a change of viewpoint or joint rotation is 
  * specified.  Reset the perspective item checkmark accordingly.
  *---------------------------------------------------------------------------
*/
 if (alter_flags)  {
    menu_choices.viewtype = PARALLEL ;
    ClearMenuStrip (window) ;
    wide_angle_subitem.Flags   =  CHECKIT | ITEMTEXT | HIGHCOMP | ITEMENABLED ;
    telephoto_subitem.Flags    =  CHECKIT | ITEMTEXT | HIGHCOMP | ITEMENABLED ;
    parallel_subitem.Flags     =  CHECKIT | CHECKED | ITEMTEXT | HIGHCOMP
                                  | ITEMENABLED ;
    SetMenuStrip (window, first_menu) ;
 }
 if (turn_on)  {
    OnMenu (window, 0x0881) ;
    OnMenu (window, 0x1081) ;
 }
 else  {
    OffMenu (window, 0x0881) ;
    OffMenu (window, 0x1081) ;
 }
}


dummy_ack (message)

UBYTE  *message ;
 /*----------------------------------------------------------------------------
  *   Used when the dummy menu tester below is not in use.
  *----------------------------------------------------------------------------
 */
{ message++ ; }


/*----------------------------------------------------------------------------
dummy_ack (message)

UBYTE  *message ;
{
 struct IntuiText  test ;
 static int  yoffset = -5 ;
 static int  xoffset = 540 ;
 struct RastPort *r ;

 r  = window->RPort ;
 
 test.FrontPen  = COLOR1 ;
 test.BackPen   = COLOR5 ;
 test.DrawMode  = JAM1 ;
 test.LeftEdge  = 0 ;
 test.TopEdge   = 0 ;
 test.ITextFont = &prog_font ;
 test.IText     = message ;
 test.NextText  = NULL ;

 yoffset  = yoffset + 10 ;
 if (yoffset > 170)  {
    yoffset  = 5 ;
    xoffset  = xoffset - 100 ;
 }
 PrintIText (r, &test, xoffset, yoffset) ;
}
 *-----------------------------------------------------------------------------
*/

