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

Mouse.C

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

Generated on Thu Apr 25 02:42:55 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002