Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Mouse.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: Mouse.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.146 $      $Date: 2011/02/17 16:50:58 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * The Mouse UI object, which maintains the current state of the 
00020  * mouse, including what it is currently used for, and how much it has moved
00021  * from one measurement to the next.  This also deals with any pop-up or
00022  * pull-down menus available by using the mouse, as well as picking objects.
00023  *
00024  * A three-button mouse is assumed here, with the following usage:
00025  *   1) Buttons 1 and 2 : manipulation and picking.
00026  *   2) Button 3 (right): pop-up menu
00027  *
00028  * This is the general base class definition; specific versions for each
00029  * windowing/graphics system must be supplied.
00030  *
00031  ***************************************************************************/
00032 
00033 #include "Mouse.h"
00034 #include "DisplayDevice.h"
00035 #include "TextEvent.h"
00036 #include "CommandQueue.h"
00037 #include "Inform.h"
00038 #include "PickList.h"
00039 #include "VMDApp.h"
00040 
00041 
00042 // constructor
00043 Mouse::Mouse(VMDApp *vmdapp) : UIObject(vmdapp) {
00044 
00045 #ifndef VMDGUI
00046   // tell the graphics display to queue events... 
00047   // only if there is no GUI available
00048   app->display->queue_events(); // enable GUI events from graphics window
00049 #endif
00050 
00051   // Initial detail level state would be set here
00052 
00053   // set the default translation and rotation increments
00054   rocking_enabled = 1;
00055   transInc = 0.002f;
00056   rotInc = 1.0f/15.0f;
00057   scaleInc = 0.0002f;
00058   RotVelScale = 0.4f;
00059   currX = currY = oldX = oldY = 0;
00060   stop_rotation();
00061   moveObj = 0;
00062   moveMode = ROTATION;
00063   pickInProgress = B_NONE;
00064   buttonDown = B_NONE;
00065 
00066 #ifdef VMDVRJUGGLER
00067   // needed for VR Juggler patches
00068   if (app && app->display)
00069     app->display->set_cursor(DisplayDevice::NORMAL_CURSOR); // set normal cursor
00070 #else
00071   app->display->set_cursor(DisplayDevice::NORMAL_CURSOR); // set normal cursor
00072 #endif
00073 
00074   reset();
00075 }
00076 
00077 
00078 // destructor
00079 Mouse::~Mouse(void) {
00080   move_mode(ROTATION);
00081 }
00082 
00083 const char* Mouse::get_mode_str(MoveMode mm) {
00084   const char* modestr;
00085   
00086   switch (mm) {
00087     default:
00088     case ROTATION:    
00089                       modestr = "rotate";     break; // default mouse cursor
00090     case TRANSLATION: modestr = "translate";  break;
00091     case SCALING:     modestr = "scale";      break;
00092     case LIGHT:       modestr = "light";      break;
00093     case USERPOINT:   modestr = "userpoint";  break;
00094   // All the picking modes follow:
00095     case PICK:        modestr = "pick";       break;
00096     case QUERY:       modestr = "query";      break;
00097     case CENTER:      modestr = "center";     break;
00098     case LABELATOM:   modestr = "labelatom";  break;
00099     case LABELBOND:   modestr = "labelbond";  break;
00100     case LABELANGLE:  modestr = "labelangle"; break;
00101     case LABELDIHEDRAL: modestr = "labeldihedral"; break;
00102     case MOVEATOM:    modestr = "moveatom";   break;
00103     case MOVERES:     modestr = "moveres";    break;
00104     case MOVEFRAG:    modestr = "movefrag";   break;
00105     case MOVEMOL:     modestr = "movemol";    break;
00106     case FORCEATOM:   modestr = "forceatom";  break;
00107     case FORCERES:    modestr = "forceres";   break;
00108     case FORCEFRAG:   modestr = "forcefrag";  break;
00109     case MOVEREP:     modestr = "moverep";    break;
00110     case ADDBOND:     modestr = "addbond";    break;
00111   }
00112   
00113   return modestr;
00114 }
00115 
00117 
00118 // stop rotation of object
00119 void Mouse::stop_rotation(void) {
00120   xRotVel = yRotVel = zRotVel = 0.0; // null out rotation rate
00121 }
00122 
00123 // set the mouse move mode to the given state; return success
00124 int Mouse::move_mode(MoveMode mm, int mobj) {
00125   const char *modestr;
00126 
00127   // we cannot change the mouse mode if an active pick is going on
00128   if (pickInProgress)
00129     return FALSE; // report failure
00130 
00131   // stop rotating no matter what mode we've changed to
00132   stop_rotation();
00133 
00134   // disable light highlight if previous mode was light mode
00135   if (moveMode == LIGHT) {
00136     app->light_highlight(moveObj, FALSE); // turn off old light
00137   }
00138 
00139   // special actions based on the new mode
00140   if (mm == LIGHT) {
00141     moveObj = mobj;
00142     app->light_highlight(moveObj, TRUE); // turn on new light number mobj
00143   }
00144 
00145   // change the mouse mode now
00146   moveMode = mm; 
00147 
00148   // Tell the text interpreter the new mouse mode
00149   // Set the variable "vmd_mouse_mode" to the correct string
00150   // and set the variable "vmd_mouse_submode" to the mobj number
00151   modestr = get_mode_str(moveMode);
00152   runcommand(new MouseModeEvent(modestr, mobj));    // and set the variables
00153 
00154   // set the cursor style to match the mouse mode
00155   switch (moveMode) {
00156     case ROTATION:
00157     case LIGHT:
00158     case USERPOINT:
00159       app->display->set_cursor(DisplayDevice::NORMAL_CURSOR);
00160       break;
00161 
00162     case TRANSLATION:
00163       app->display->set_cursor(DisplayDevice::TRANS_CURSOR);
00164       break;
00165 
00166     case SCALING:
00167       app->display->set_cursor(DisplayDevice::SCALE_CURSOR);
00168       break;
00169 
00170     // all the remaining are picking modes
00171     default:
00172       app->display->set_cursor(DisplayDevice::PICK_CURSOR);
00173       break;
00174   }
00175 
00176   return TRUE; // report success
00177 }
00178 
00179 
00180 
00181 // do action when the mouse is moved
00182 // arg: which buttons are currently being pressed
00183 // return: whether the mouse moved any
00184 int Mouse::mouse_moved() {
00185   int dx, dy, mymouseMoved;
00186   int b1Down, b2Down;
00187 
00188   b1Down = buttonDown == B_LEFT;
00189 
00190   // in order to better support old machines, the built-in mouse
00191   // modes of VMD treat the middle and right mouse buttons identically
00192   b2Down = (buttonDown == B_MIDDLE || buttonDown == B_RIGHT);
00193 
00194   if (b1Down || b2Down) {
00195     xRotVel = yRotVel = zRotVel = 0.0; // null out rotation rate
00196   }
00197 
00198   // get current mouse position
00199   currX = app->display->x();
00200   currY = app->display->y();
00201 
00202   // and calculate distance mouse has moved
00203   dx =  5 * (currX - oldX);
00204   dy = -5 * (currY - oldY); // negate Y coordinates
00205 
00206   mymouseMoved = (dx != 0 || dy != 0);
00207   if (!mymouseMoved)
00208     return FALSE;  // early-exit if nothing happened
00209 
00210   // report the mouse location to TCL
00211   if (make_callbacks && !b1Down && !b2Down) {
00212     float r[2], oldr[2];
00213     r[0] = (float) currX; 
00214     r[1] = (float) currY;
00215     oldr[0] = (float) oldX; 
00216     oldr[1] = (float) oldY;
00217     int tag;
00218 
00219     app->display->rel_screen_pos(r[0], r[1]);
00220     app->display->rel_screen_pos(oldr[0], oldr[1]);
00221     if ((r[0] >= 0.0 && r[0] <= 1.0 && r[1] >= 0.0 && r[1] <= 1.0)) {
00222       // must be in the screen to do a pick!
00223       app->pickList->pick_check(2, r, tag, NULL, 0.01f, (char *)"mouse");
00224     } else if (oldr[0] >= 0.0 && oldr[0] <= 1.0 && oldr[1] >= 0.0 &&
00225                oldr[1] <= 1.0) {
00226       // but if we just moved out, inform TCL.
00227       app->commandQueue->runcommand(new PickAtomCallbackEvent(-1,-1,"mouse"));
00228     }
00229   }
00230 
00231 
00232   // save mouse coordinates for future reference
00233   oldX = currX;
00234   oldY = currY;
00235 
00236   if (!b1Down && !b2Down) return FALSE;
00237 
00238   // check if we are picking something; if so, generate pick-move command
00239   if (pickInProgress) {
00240     float mx = (float) currX;
00241     float my = (float) currY;
00242     app->display->rel_screen_pos(mx, my);
00243     if (mx >= 0.0 && mx <= 1.0 && my >= 0.0 && my <= 1.0) {
00244       float p[2];
00245       p[0] = mx;
00246       p[1] = my;
00247       app->pickList->pick_move(p);
00248     }
00249     return TRUE; // report that the mouse has moved
00250   }
00251 
00252   // Otherwise, if a button is pressed, check how far the mouse moved,
00253   // and transform the view accordingly.
00254 
00255 #if defined(VMDXPLOR)
00256   // Mouse handling for VMD-XPLOR builds
00257   DisplayDevice* dispDev = app->display;
00258   // check for button 1 action
00259   if (b1Down) {
00260     if (dispDev->shift_state()==0 &&
00261         (moveMode == ROTATION || moveMode == LIGHT || moveMode >= PICK)) {
00262 #else
00263   // Mouse handling for normal VMD builds
00264   // check for button 1 action
00265   if (b1Down) {
00266     if (moveMode == ROTATION || moveMode == LIGHT || moveMode >= PICK) {
00267 #endif
00268       xRotVel = rotInc * (float)dy;
00269       yRotVel = rotInc * (float)dx;
00270       if (moveMode == ROTATION ||  moveMode >= PICK) {
00271         // rotate the scene
00272         if (xRotVel != 0.0) {
00273           app->scene_rotate_by(xRotVel, 'x');
00274           xRotVel *= RotVelScale;
00275         }
00276         if (yRotVel != 0.0) {
00277           app->scene_rotate_by(yRotVel, 'y');
00278           yRotVel *= RotVelScale;
00279         }
00280       } else {
00281         // rotate a particular light
00282         if (xRotVel != 0.0) {
00283           app->light_rotate(moveObj, xRotVel, 'x');
00284           xRotVel *= RotVelScale;
00285         }
00286         if (yRotVel != 0.0) {
00287           app->light_rotate(moveObj, yRotVel, 'y');
00288           yRotVel *= RotVelScale;
00289         }
00290       }
00291 
00292 #if defined(VMDXPLOR)
00293     // Mouse handling for VMD-XPLOR builds
00294     } else if ((dispDev->shift_state() & DisplayDevice::SHIFT ||
00295                 moveMode == TRANSLATION) && mymouseMoved) {
00296       app->scene_translate_by(transInc*(float)dx, -transInc*(float)dy, 0.0);
00297     } else if ((dispDev->shift_state() & DisplayDevice::CONTROL ||
00298                 moveMode == SCALING) && dx != 0) {
00299 #else
00300     // Mouse handling for normal VMD builds
00301     } else if (moveMode == TRANSLATION && mymouseMoved) {
00302       app->scene_translate_by(transInc*(float)dx, -transInc*(float)dy, 0.0);
00303     } else if (moveMode == SCALING && dx != 0) {
00304 #endif
00305       float scf = scaling + scaleInc * (float)dx;
00306       if(scf < 0.0)
00307         scf = 0.0;
00308       app->scene_scale_by(scf);
00309     }
00310   }
00311   
00312   // check for button 2 action
00313   if (b2Down) {
00314 #if defined(VMDXPLOR)
00315     // Mouse handling for VMD-XPLOR builds
00316     if (dispDev->shift_state()==0 &&
00317        (moveMode == ROTATION || moveMode == LIGHT || moveMode >= PICK)) {
00318 #else
00319     // Mouse handling for normal VMD builds
00320     if (moveMode == ROTATION || moveMode == LIGHT || moveMode >= PICK) {
00321 #endif
00322       zRotVel = rotInc * (float)dx;
00323       if (moveMode == ROTATION ||  moveMode >= PICK) {
00324         if (zRotVel != 0.0) {
00325           app->scene_rotate_by(zRotVel, 'z');
00326           zRotVel *= RotVelScale;
00327         }
00328       } else {
00329         if (zRotVel != 0.0) {
00330           app->light_rotate(moveObj, zRotVel, 'z');
00331           zRotVel *= RotVelScale;
00332         }
00333       }
00334 #if defined(VMDXPLOR)
00335     // Mouse handling for VMD-XPLOR builds
00336     } else if ((dispDev->shift_state() & DisplayDevice::SHIFT ||
00337                moveMode == TRANSLATION) && dx != 0) {
00338       app->scene_translate_by(0.0, 0.0, transInc * (float)dx);
00339     } else if ((dispDev->shift_state() & DisplayDevice::CONTROL ||
00340                moveMode == SCALING) && dx != 0) {
00341 #else
00342     // Mouse handling for normal VMD builds
00343     } else if(moveMode == TRANSLATION && dx != 0) {
00344       app->scene_translate_by(0.0, 0.0, transInc * (float)dx);
00345     } else if(moveMode == SCALING && dx != 0) {
00346 #endif
00347       float scf = scaling + 10.0f * scaleInc * (float)dx;
00348       if(scf < 0.0)
00349         scf = 0.0;
00350       app->scene_scale_by(scf);
00351     }
00352   }
00353 
00354   return TRUE; // report that the mouse has moved
00355 }
00356 
00357 
00358 
00359 // mouse mode for special navigation/flying plugins,
00360 // reports the mouse location and button state to TCL callbacks
00361 int Mouse::mouse_userpoint() {
00362   float mpos[2];
00363 
00364   xRotVel = yRotVel = zRotVel = 0.0; // null out rotation rate
00365 
00366   // get current mouse position
00367   currX = app->display->x();
00368   currY = app->display->y();
00369 
00370   mpos[0] = (float) currX;
00371   mpos[1] = (float) currY;
00372 
00373   app->display->rel_screen_pos(mpos[0], mpos[1]);
00374 
00375   // inform TCL
00376   app->commandQueue->runcommand(new MousePositionEvent(mpos[0], mpos[1], buttonDown));
00377 
00378   // save mouse coordinates for future reference
00379   oldX = currX;
00380   oldY = currY;
00381 
00382   // Nothing happened for VMD to worry about for changing detail levels etc,
00383   // the user's Tcl callback will have to deal with this.
00384   return FALSE;
00385 }
00386 
00387 
00388 
00390    
00391 // reset the mouse to original settings
00392 void Mouse::reset(void) {
00393   scaling = 1.0;
00394   stop_rotation();
00395   currX = oldX = app->display->x();
00396   currY = oldY = app->display->y();
00397 }
00398 
00399 void Mouse::handle_winevent(long dev, long val) {
00400   switch(dev) {
00401     case DisplayDevice::WIN_WHEELUP:
00402       app->scene_scale_by(1.200f); // mouse wheel up scales up
00403       break;
00404 
00405     case DisplayDevice::WIN_WHEELDOWN:
00406       app->scene_scale_by(0.833f); // mouse wheel down scales down
00407       break;
00408 
00409     case DisplayDevice::WIN_LEFT:
00410     case DisplayDevice::WIN_MIDDLE:
00411     case DisplayDevice::WIN_RIGHT:
00412       if (val == 1 && buttonDown == B_NONE) {
00413         // start of a fresh button down event.
00414         xRotVel = yRotVel = zRotVel = 0.0; // null out rotation rate
00415 
00416         oldX = currX = app->display->x(); // save current mouse coords
00417         oldY = currY = app->display->y();
00418   
00419         if (dev == DisplayDevice::WIN_LEFT)
00420           buttonDown = B_LEFT;
00421         else if (dev == DisplayDevice::WIN_MIDDLE)
00422           buttonDown = B_MIDDLE; 
00423         else
00424           buttonDown = B_RIGHT;
00425 
00426         // check for a picked item if we are in a picking mode
00427         if ( moveMode >= PICK && ! pickInProgress) {
00428           pickInProgress = buttonDown;
00429           float mx = (float) currX;
00430           float my = (float) currY;
00431           app->display->rel_screen_pos(mx, my);
00432   
00433           // if picking an object fails, assume we are rotating the object
00434           float p[2];
00435           p[0] = mx;
00436           p[1] = my;
00437           if (app->pickList->pick_start(pickInProgress, 2, p) < 0)
00438             pickInProgress = B_NONE;
00439         }
00440       } else if (val == 0 && buttonDown != B_NONE) {
00441         // we're done moving the mouse while the button is down
00442         if (pickInProgress) {
00443           pickInProgress = B_NONE;
00444           app->pickList->pick_end(); // must finish the picking process
00445         }
00446 
00447         // Would return to previous detail level here
00448         buttonDown = B_NONE;
00449       }
00450       break;
00451 
00452     case DisplayDevice::WIN_KBD:
00453     case DisplayDevice::WIN_KBD_ESCAPE:
00454     case DisplayDevice::WIN_KBD_UP:
00455     case DisplayDevice::WIN_KBD_DOWN:
00456     case DisplayDevice::WIN_KBD_LEFT: 
00457     case DisplayDevice::WIN_KBD_RIGHT: 
00458     case DisplayDevice::WIN_KBD_PAGE_UP:
00459     case DisplayDevice::WIN_KBD_PAGE_DOWN:
00460     case DisplayDevice::WIN_KBD_HOME:
00461     case DisplayDevice::WIN_KBD_END:
00462     case DisplayDevice::WIN_KBD_INSERT:
00463     case DisplayDevice::WIN_KBD_DELETE:
00464     case DisplayDevice::WIN_KBD_F1:
00465     case DisplayDevice::WIN_KBD_F2:
00466     case DisplayDevice::WIN_KBD_F3:
00467     case DisplayDevice::WIN_KBD_F4:
00468     case DisplayDevice::WIN_KBD_F5:
00469     case DisplayDevice::WIN_KBD_F6:
00470     case DisplayDevice::WIN_KBD_F7:
00471     case DisplayDevice::WIN_KBD_F8:
00472     case DisplayDevice::WIN_KBD_F9:
00473     case DisplayDevice::WIN_KBD_F10:
00474     case DisplayDevice::WIN_KBD_F11:
00475     case DisplayDevice::WIN_KBD_F12:
00476       runcommand(new UserKeyEvent((DisplayDevice::EventCodes) dev, (char) val, app->display->shift_state()));
00477       break;
00478 
00479     default:
00480       ; // ignore other events and just return
00481   }  // switch
00482 }
00483 
00484 void Mouse::set_rocking(int on) {
00485   rocking_enabled = on;
00486   if (!on) {
00487     xRotVel = yRotVel = zRotVel = 0; // null out rotation rate
00488   }
00489 }
00490 
00491 // check for and queue events.  Return TRUE if an event was generated.
00492 int Mouse::check_event(void) {
00493   int retval = FALSE;
00494   long dev=0, val=0; // we check for events ourselves
00495 
00496   if ((retval = app->display->read_event(dev, val)))
00497     handle_winevent(dev, val);
00498 
00499   if (moveMode == USERPOINT) {
00500     mouse_userpoint(); // user-defined mouse behavior
00501   } else if (make_callbacks || buttonDown != B_NONE) {
00502     if (mouse_moved()) {
00503       // Change to alternate detail level here...
00504     } 
00505   }
00506 
00507   if (rocking_enabled) {
00508     // apply ang velocity, if necessary
00509     if (xRotVel != 0.0 || yRotVel != 0.0 || zRotVel != 0.0) {
00510       if (moveMode != LIGHT) {          // (possibly) rotate app->scene
00511         if (xRotVel != 0.0)
00512           app->scene_rotate_by(xRotVel, 'x');
00513         if (yRotVel != 0.0)
00514           app->scene_rotate_by(yRotVel, 'y');
00515         if (zRotVel != 0.0)
00516           app->scene_rotate_by(zRotVel, 'z');
00517       } else {                         // (possibly) rotate particular light
00518         if (xRotVel != 0.0)
00519           app->light_rotate(moveObj, xRotVel, 'x');
00520         if (yRotVel != 0.0)
00521           app->light_rotate(moveObj, yRotVel, 'y');
00522         if (zRotVel != 0.0)
00523           app->light_rotate(moveObj, zRotVel, 'z');
00524       }
00525     }
00526   }
00527   return retval;
00528 }
00529 
00530 
00531 

Generated on Sat May 26 01:48:12 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002