/***************************************************************************** # Copyright (C) 1994-2008 by David Gordon. # All rights reserved. # # This software is part of a beta-test version of the Consed/Autofinish # package. It should not be redistributed or # used for any commercial purpose, including commercially funded # sequencing, without written permission from the author and the # University of Washington. # # This software is provided ``AS IS'' and any express or implied # warranties, including, but not limited to, the implied warranties of # merchantability and fitness for a particular purpose, are disclaimed. # In no event shall the authors or the University of Washington be # liable for any direct, indirect, incidental, special, exemplary, or # consequential damages (including, but not limited to, procurement of # substitute goods or services; loss of use, data, or profits; or # business interruption) however caused and on any theory of liability, # whether in contract, strict liability, or tort (including negligence # or otherwise) arising in any way out of the use of this software, even # if advised of the possibility of such damage. # # Building Consed from source is error prone and not simple which is # why I provide executables. Due to time limitations I cannot # provide any assistance in building Consed. Even if you do not # modify the source, you may introduce errors due to using a # different version of the compiler, a different version of motif, # different versions of other libraries than I used, etc. For this # reason, if you discover Consed bugs, I can only offer help with # those bugs if you first reproduce those bugs with an executable # provided by me--not an executable you have built. # # Modifying Consed is also difficult. Although Consed is modular, # some modules are used by many other modules. Thus making a change # in one place can have unforeseen effects on many other features. # It may takes months for you to notice these other side-effects # which may not seen connected at all. It is not feasable for me to # provide help with modifying Consed sources because of the # potentially huge amount of time involved. # #*****************************************************************************/ // // guiinput.cpp // // handles user's mouse clicks and character inputs // // gordon 7-Mar-95 // #include #include #include #include #include #include #include #include #include #include #include "motifutils.h" #include "guiapp.h" #include "guicontigwin.h" #include "mbt_errors.h" #include "numutil.h" #include "contigwin.h" #include "consed.h" #include "hp_exception_kludge.h" // catch drawing window input events, translate to char coords // and pass it on to the GuiContigWin's callback void inputXtCb(Widget widCw, GuiContigWin* pGcw, XmDrawingAreaCallbackStruct *pCb) { TRY_CATCH_WRAPPER(pGcw->GuiInputCallback( pCb )); } //////////////////////////////////////////////////////////// // // PURPOSE: low level (pixel) processing of Mouse and Char press events // // HOW TO USE IT: called from a non-class callback // // REV: (David Gordon) Feb. 28, 1995 // //////////////////////////////////////////////////////////// void GuiContigWin :: GuiInputCallback( XmDrawingAreaCallbackStruct *pCb ) { // to humor people who click on the window before they have put a // contig in it if ( !pContigWin_->pGetContig() ) return; int nPixelX; int nPixelY; if ( pCb->event->xany.type == ButtonPress ) { // before doing anything, clear any highlight/selection // from a previous ButtonPress pContigWin_->clearHighlight(); // I've found that pCb->event->xbutton.state == ControlMask // is not set on a button release event. Thus there must be // some other method of determining if the user had pushed // control on button down. uButtonPressState_ = pCb->event->xbutton.state; // printf( "button state = %o\n", uButtonPressState_ ); if (pCb->event->xbutton.button == Button2) { nPixelX = pCb->event->xbutton.x; nPixelY = pCb->event->xbutton.y; bool bControl = uButtonPressState_ & ControlMask; bool bShift = uButtonPressState_ & ShiftMask; if ( bIsInConsensusBasesArea( nPixelX, nPixelY ) ) { if ( ( bControl && !bShift ) || ( !bControl && !bShift ) ) guiStartHighlight( nPixelX, nPixelY ); else if ( bShift && !bControl ) pContigWin_->popup4BestTracesByCursorPosition( nCharXFromPixel( nPixelX ) ); } else if ( bIsInFragmentBasesArea( nPixelX, nPixelY ) ) { if ( !bControl && !bShift ) pContigWin_->popupTracesByCursorPosition(nCharXFromPixel(nPixelX), pContigWin_->nFragLineFromPixelY(nPixelY) ); } } else if (pCb->event->xbutton.button == Button1) { nPixelX = pCb->event->xbutton.x; nPixelY = pCb->event->xbutton.y; pContigWin_->nButton1PressedScreenX_ = nCharXFromPixel( nPixelX ); int nScreenCharX = nCharXFromPixel(nPixelX); if (bIsInFragmentBasesArea( nPixelX, nPixelY ) ) { pContigWin_->bButton1PressedInReadBasesArea_ = true; pContigWin_->bButton1PressedInConsensusBasesArea_ = false; pContigWin_->nButton1PressedReadLine_ = pContigWin_->nFragLineFromPixelY(nPixelY); pContigWin_->moveCursorToFragChar( nScreenCharX, pContigWin_->nButton1PressedReadLine_ ); pContigWin_->showBaseQuality( nScreenCharX, pContigWin_->nFragLineFromPixelY(nPixelY), true ); // read base guiStartHighlight( nPixelX, nPixelY ); if ( pCP->bPutHorizontalLineAtCursor_ ) { guiDrawHorizontalLineAtCursor( pContigWin_->nButton1PressedReadLine_ ); } } else if (bIsInConsensusBasesArea(nPixelX, nPixelY)) { pContigWin_->bButton1PressedInReadBasesArea_ = false; pContigWin_->bButton1PressedInConsensusBasesArea_ = true; pContigWin_->moveCursorToConsCharXPos(nCharXFromPixel(nPixelX)); pContigWin_->showBaseQuality( nScreenCharX, 0, false ); // consensus base guiStartHighlight( nPixelX, nPixelY ); } else { pContigWin_->bButton1PressedInReadBasesArea_ = false; pContigWin_->bButton1PressedInConsensusBasesArea_ = false; if (bIsOnAReadName( nPixelX, nPixelY ) ) { pContigWin_->toggleHighlightOfReadName( nPixelX, nPixelY ); } //cout << "not in bases area, x = " << // nPixelX << " y = " << nPixelY << endl; cout.flush(); } } /* if (pCb->event->xbutton.button == Button2) */ else if (pCb->event->xbutton.button == Button3) { nPixelX = pCb->event->xbutton.x; nPixelY = pCb->event->xbutton.y; nPixelXBeforePopupMenu_ = nPixelX; nPixelYBeforePopupMenu_ = nPixelY; if (pCb->event->xbutton.state == ControlMask ) guiPopupTagInfoForTagsAtThisLocation(); else { popupMenu( (XButtonPressedEvent*) pCb->event ); } // set cursor if (bIsInFragmentBasesArea( nPixelX, nPixelY ) ) { int nScreenCharX = nCharXFromPixel(nPixelX); int nReadIndex = pContigWin_->nFragLineFromPixelY(nPixelY); pContigWin_->moveCursorToFragChar(nScreenCharX, nReadIndex ); } else if (bIsInConsensusBasesArea(nPixelX, nPixelY)) { pContigWin_->moveCursorToConsCharXPos(nCharXFromPixel(nPixelX)); } } /* if (pCb->event->xbutton.button == Button2) */ } /* if ( pCb->event->xany.type == ButtonPress ) */ else if ( pCb->event->xany.type == ButtonRelease ) { nPixelX = pCb->event->xbutton.x; nPixelY = pCb->event->xbutton.y; if (pCb->event->xbutton.button == Button1 ) { pContigWin_->userReleasedMouseButton1( nPixelX, nPixelY ); } else if (pCb->event->xbutton.button == Button2 ) { // I've found that pCb->event->xbutton.state == ControlMask // is not set on a button release event. Thus there must be // some other method of determining if the user had pushed // control on button down. bool bControl = uButtonPressState_ & ControlMask; bool bShift = uButtonPressState_ & ShiftMask; if ( ( bControl && !bShift ) || ( !bControl && !bShift ) ) pContigWin_->highlightFinished(); } bMouseIsOnBasesWithButtonDown_ = false; } else if ( pCb->event->xany.type == KeyPress ) { // translate the key const int nBufSize = 20; char szBuf[ nBufSize]; KeySym keySym; XComposeStatus xcsStatus; int nRetLength = XLookupString( (XKeyEvent* ) pCb->event, szBuf, nBufSize, &keySym, &xcsStatus ); char c = szBuf[0]; if ( (keySym == XK_Shift_L) || (keySym == XK_Shift_R) || (keySym == XK_Control_L) || (keySym == XK_Control_R) ) { // ignore the user pushing down the control key or pushing // down the shift key } else if ( keySym == XK_Right ) { pContigWin_->userPushedRightArrow(); } else if ( keySym == XK_Left ) { pContigWin_->userPushedLeftArrow(); } else if ( keySym == XK_Down ) { pContigWin_->userPushedDownArrow(); } else if ( keySym == XK_Up ) { pContigWin_->userPushedUpArrow(); } else { switch (c) { case '\x01' : // control A pContigWin_->userPushedControlA(); break; case '\x05' : // control E pContigWin_->userPushedControlE(); break; case '\x14' : // control T nPixelX = pCb->event->xbutton.x; nPixelY = pCb->event->xbutton.y; if ( bIsInFragmentBasesArea( nPixelX, nPixelY ) ) { pContigWin_->popupTracesByCursorPosition( nCharXFromPixel(nPixelX), pContigWin_->nFragLineFromPixelY(nPixelY) ); } break; case '<' : pContigWin_->userPushedLeftArrowAboveComma(); break; case '>' : pContigWin_->userPushedRightArrowAbovePeriod(); break; default: // is this key a user-defined key? bool bFoundUserDefinedKey = false; for( int n = 0; n < pCP->aUserDefinedKeys_.length(); ++n ) { if ( c == pCP->aUserDefinedKeys_[ n ] ) { RWCString soProgram = pCP->aProgramsForUserDefinedKeys_[ n ]; RWCString soArgument1 = pCP->aArgumentsToPassToUserDefinedPrograms_[ n ]; RWCString soTagWithUserDefinedKey = pCP->aTagsToApplyWithUserDefinedKeys_[ n ]; pContigWin_->userPressedUserDefinedKey( soProgram, soArgument1, soTagWithUserDefinedKey ); bFoundUserDefinedKey = true; break; } } if ( bFoundUserDefinedKey ) break; // couldn't find this key. Could it be an overstrike with a // letter or a pad? if ( pContigWin_->bIsEditCursorVisible() && pContigWin_->editCursor_.bCursorOnCons() ) { int nConsPos = pContigWin_->editCursor_.nConsPosGet(); char cLower = tolower(c); if ( ( 'a' <= cLower && cLower <= 'z' ) || ( cLower == '*' ) ) { pContigWin_->userOverstrikingConsensus( nConsPos, cLower ); break; } } // if got here, user pushed an illegal key GuiApp::beep(); } // switch } // if ( (keySym == XK_Shift_L) || (keySym == XK_Shift_R) ... else } // else if ( pCb->event->xany.type == KeyPress ) { } // void GuiContigWin :: GuiInputCallback( XmDrawingAreaCallbackStruct *pCb ) bool GuiContigWin :: bIsInFragmentBasesArea(const int nPixelX, const int nPixelY) const { bool b1 = (nFragmentBasesStartPixelX() <= nPixelX); bool b2 = (nForFragLineTopPixelY() <= nPixelY); bool b3 = (nPixelY <= pContigWin_->nGetFragmentBasesMaxPixelY()); bool b = b1 && b2 && b3; return( b ); } bool GuiContigWin :: bIsOnAReadName( const int nPixelX, const int nPixelY ) { return ( ( nPixelX < nFragmentBasesStartPixelX() ) && ( nForFragLineTopPixelY() <= nPixelY ) && ( nPixelY <= pContigWin_->nGetFragmentBasesMaxPixelY() ) ); } bool GuiContigWin :: bIsOnARead( const int nPixelY ) { return( ( nForFragLineTopPixelY() <= nPixelY ) && ( nPixelY <= pContigWin_->nGetFragmentBasesMaxPixelY() ) ); } void GuiContigWin :: guiStartHighlight( const int nPixelX, const int nPixelY ) { if ( bIsInConsensusBasesArea( nPixelX, nPixelY ) ) { int nScreenCharX = nCharXFromPixel(nPixelX); pContigWin_->startHighlight( nScreenCharX, true, // is on consensus 0 ); } else if ( bIsInFragmentBasesArea( nPixelX, nPixelY ) ) { int nScreenCharX = nCharXFromPixel(nPixelX); int nReadIndex = pContigWin_->nFragLineFromPixelY(nPixelY); pContigWin_->startHighlight( nScreenCharX, false, // is not on consensus nReadIndex ); } }