void SoEnabledElementsList::enable(SoType elementType, int stackIndex) // //////////////////////////////////////////////////////////////////////// { SoType prev = elements[stackIndex]; // If not enabled before or if enabled before but we are now // enabling a more-specific subclass, add the element. if (prev.isBad() || (elementType != prev && elementType.isDerivedFrom(prev))) { elements.set(stackIndex, elementType); // Increment global counter to indicate that lists have changed counter++; } #ifdef DEBUG // If we aren't enabling a more general super-class (and therefore // don't need to do anything), error: else if (! prev.isDerivedFrom(elementType)) { const char *eltName = elementType.getName().getString(); SoDebugError::post("SoAction::enableElement", "Cannot enable element %s because element %s " "is already enabled", eltName, prev.getName().getString()); } #endif }
// Documented in superclass. void SoWinExaminerViewer::setCamera(SoCamera * newCamera) { // This method overridden from parent class to toggle the camera // type selection button pixmap and string of the zoom/dolly // thumbwheel. inherited::setCamera(newCamera); if (! newCamera) return; SoType camtype = newCamera->getTypeId(); SbBool orthogonal = camtype.isDerivedFrom(SoOrthographicCamera::getClassTypeId()); const char * oldLabel = this->getRightWheelString(); if (oldLabel) { if (orthogonal) { if (strcmp("Dolly",oldLabel) == 0) this->setRightWheelString("Zoom"); } else if (strcmp("Zoom",oldLabel) == 0) this->setRightWheelString("Dolly"); } SoWinBitmapButton * wbtn = PRIVATE(this)->camerabutton; // If viewer was made without decorations, button will not have been // made yet. if (wbtn) { wbtn->setBitmap(orthogonal ? 1 : 0); } }
/*! Set the node compatibility mask for node type \a nodetype. The mask specifies for which file formats the node is supported. \COIN_FUNCTION_EXTENSION \sa getCompatibilityMode() \since Coin 2.0 */ void SoNode::setCompatibilityTypes(const SoType & nodetype, const uint32_t bitmask) { assert(compatibility_dict); assert(nodetype.isDerivedFrom(SoNode::getClassTypeId())); compatibility_dict->put(nodetype.getKey(), bitmask); }
void SoUnknownNode::createFromIsA(SoMFString *isA) // //////////////////////////////////////////////////////////////////////// { for (int i = 0; i < isA->getNum(); i++) { SoType t = SoType::fromName((*isA)[i]); if (t.canCreateInstance() && t.isDerivedFrom(SoNode::getClassTypeId())) { SoNode *alternateRep = (SoNode *)t.createInstance(); alternateRep->ref(); #ifdef DEBUG if (alternateRep == NULL) { SoDebugError::post("SoUnknownNode::createFromIsA", "SoType.createInstance returned " "NULL (type %s)", t.getName().getString()); return; } #endif // Copy over all fields that are shared: int num = instanceFieldData->getNumFields(); for (int j=0; j<num; j++) { const SbName &fieldName = instanceFieldData->getFieldName(j); SoField *f = instanceFieldData->getField(this, j); // Don't copy over fields with default values: if (f->isDefault()) continue; SoField *nf = alternateRep->getField(fieldName); if (nf != NULL && nf->getTypeId() == f->getTypeId()) { nf->copyFrom(*f); if (f->isConnectedFromField()) { SoField *cf; f->getConnectedField(cf); nf->connectFrom(cf); } else if (f->isConnectedFromEngine()) { SoEngineOutput *eo; f->getConnectedEngine(eo); nf->connectFrom(eo); } } } // And if alternateRep is a group, copy over hidden // children: if (alternateRep->isOfType(SoGroup::getClassTypeId())) { SoGroup *g = (SoGroup *)alternateRep; for (int kid = 0; kid < hiddenChildren.getLength(); kid++) { g->addChild(hiddenChildren[kid]); } } addChild(alternateRep); return; } } }
int main(void) { SoDB::init(); SoNodeKit::init(); SoInteraction::init(); SoTypeList tl; const unsigned int n = SoType::getAllDerivedFrom(SoNode::getClassTypeId(), tl); for (unsigned int i=0; i < n; i++) { (void)fprintf(stdout, "%s", tl[i].getName().getString()); SoFieldContainer * fc = (SoFieldContainer *) (tl[i].canCreateInstance() ? tl[i].createInstance() : NULL); if (fc == NULL) { (void)fprintf(stdout, " (abstract)\n"); continue; } (void)fprintf(stdout, "\n"); SoFieldList fl; const unsigned int nrf = fc->getAllFields(fl); for (unsigned int j=0; j < nrf; j++) { SoField * f = fl[j]; SoType ftype = f->getTypeId(); SbName fname; f->getContainer()->getFieldName(f, fname); (void)fprintf(stdout, " %s (%s)\n", fname.getString(), ftype.getName().getString()); if (ftype.isDerivedFrom(SoSFEnum::getClassTypeId())) { list_enums((SoSFEnum *)f); } else if (ftype.isDerivedFrom(SoMFEnum::getClassTypeId())) { list_enums((SoMFEnum *)f); } } } return 0; }
/*! Get the node compatibility mask for node type \a nodetype. The return value will be a bit mask of SoNode::NodeType flags, containing one or several flags. \COIN_FUNCTION_EXTENSION \since Coin 2.0 */ uint32_t SoNode::getCompatibilityTypes(const SoType & nodetype) { assert(compatibility_dict); assert(nodetype.isDerivedFrom(SoNode::getClassTypeId())); uint32_t tmp; if (compatibility_dict->get(nodetype.getKey(), tmp)) { return tmp; } return SoNode::EXTENSION; }
SoCallbackAction::Response SoIntersectionDetectionAction::PImpl::dragger(SoCallbackAction * action, const SoNode *) { if ( !this->draggersenabled ) // dragger setting overrides setting for manipulators return SoCallbackAction::PRUNE; #ifdef HAVE_MANIPULATORS if ( !this->manipsenabled ) { const SoPath * path = action->getCurPath(); SoNode * tail = path->getTail(); SoType type = tail->getTypeId(); if ( type.isDerivedFrom(SoTransformManip::getClassTypeId()) || type.isDerivedFrom(SoClipPlaneManip::getClassTypeId()) || type.isDerivedFrom(SoDirectionalLightManip::getClassTypeId()) || type.isDerivedFrom(SoPointLightManip::getClassTypeId()) || type.isDerivedFrom(SoSpotLightManip::getClassTypeId()) ) return SoCallbackAction::PRUNE; } #endif // HAVE_MANIPULATORS return SoCallbackAction::CONTINUE; }
void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::setCameraType(SoType type) { if(!getSoRenderManager()->getCamera()->isOfType(SoPerspectiveCamera::getClassTypeId()) && !getSoRenderManager()->getCamera()->isOfType(SoOrthographicCamera::getClassTypeId())) { Base::Console().Warning("Quarter::setCameraType", "Only SoPerspectiveCamera and SoOrthographicCamera is supported."); return; } SoType perspectivetype = SoPerspectiveCamera::getClassTypeId(); SbBool oldisperspective = getSoRenderManager()->getCamera()->getTypeId().isDerivedFrom(perspectivetype); SbBool newisperspective = type.isDerivedFrom(perspectivetype); if((oldisperspective && newisperspective) || (!oldisperspective && !newisperspective)) // Same old, same old.. return; SoCamera* currentcam = getSoRenderManager()->getCamera(); SoCamera* newcamera = (SoCamera*)type.createInstance(); // Transfer and convert values from one camera type to the other. if(newisperspective) { convertOrtho2Perspective((SoOrthographicCamera*)currentcam, (SoPerspectiveCamera*)newcamera); } else { convertPerspective2Ortho((SoPerspectiveCamera*)currentcam, (SoOrthographicCamera*)newcamera); } getSoRenderManager()->setCamera(newcamera); getSoEventManager()->setCamera(newcamera); //if the superscene has a camera we need to replace it too SoSeparator* superscene = (SoSeparator*) getSoRenderManager()->getSceneGraph(); SoSearchAction sa; sa.setInterest(SoSearchAction::FIRST); sa.setType(SoCamera::getClassTypeId()); sa.apply(superscene); if(sa.getPath()) { SoNode* node = sa.getPath()->getTail(); SoGroup* parent = (SoGroup*) sa.getPath()->getNodeFromTail(1); if(node && node->isOfType(SoCamera::getClassTypeId())) { parent->replaceChild(node, newcamera); } } };
SbBool SoIntersectionDetectionAction::isTypeEnabled(SoType type, SbBool checkgroups) const { if ( PRIVATE(this)->prunetypes->find(type) != -1 ) return FALSE; if ( checkgroups ) { // is type a dragger? #ifdef HAVE_DRAGGERS if ( !PRIVATE(this)->draggersenabled && type.isDerivedFrom(SoDragger::getClassTypeId()) ) return FALSE; #endif // HAVE_DRAGGERS #ifdef HAVE_MANIPULATORS // is type a manip? if ( !PRIVATE(this)->manipsenabled ) { if ( type.isDerivedFrom(SoTransformManip::getClassTypeId()) || type.isDerivedFrom(SoClipPlaneManip::getClassTypeId()) || type.isDerivedFrom(SoDirectionalLightManip::getClassTypeId()) || type.isDerivedFrom(SoPointLightManip::getClassTypeId()) || type.isDerivedFrom(SoSpotLightManip::getClassTypeId()) ) return FALSE; } #endif // HAVE_MANIPULATORS } return TRUE; }
void SoActionMethodList::addMethod(SoType nodeType, SoActionMethod method) // //////////////////////////////////////////////////////////////////////// { #ifdef DEBUG // Make sure nodeType is a kind of node! if (! nodeType.isDerivedFrom(SoNode::getClassTypeId())) SoDebugError::post("SoAction::addMethod", "%s is not a node type", nodeType.getName().getString()); #endif /* DEBUG */ numValidTypes = 0; (*this)[SoNode::getActionMethodIndex(nodeType)] = method; }
void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::saveHomePosition(void) { SoType t = getSoRenderManager()->getCamera()->getTypeId(); assert(t.isDerivedFrom(SoNode::getClassTypeId())); assert(t.canCreateInstance()); if(m_storedcamera) { m_storedcamera->unref(); } m_storedcamera = (SoNode*)t.createInstance(); m_storedcamera->ref(); m_storedcamera->copyFieldValues(getSoRenderManager()->getCamera()); }
/*! This method appends all the class types derived from \a type to \a list, and returns the number of types added to the list. Internal types are not included in the list, nor are they counted. \a type itself is also added to the list, as a type is seen as a derivation of its own type. NB: do not write code which depends in any way on the order of the elements returned in \a list. Here is a small, stand-alone example which shows how this method can be used for introspection, listing all subclasses of the SoBase superclass: \code #include <stdio.h> #include <Inventor/SoDB.h> #include <Inventor/lists/SoTypeList.h> static void list_subtypes(SoType t, unsigned int indent = 0) { SoTypeList tl; SoType::getAllDerivedFrom(t, tl); for (unsigned int i=0; i < indent; i++) { printf(" "); } printf("%s\n", t.getName().getString()); indent++; for (int j=0; j < tl.getLength(); j++) { if (tl[j].getParent() == t) { // only interested in direct descendents list_subtypes(tl[j], indent); } } } int main(void) { SoDB::init(); list_subtypes(SoType::fromName("SoBase")); return 0; } \endcode */ int SoType::getAllDerivedFrom(const SoType type, SoTypeList & list) { assert(type != SoType::badType() && "argument is badType()"); int counter = 0; int n = SoType::typedatalist->getLength(); for (int i = 0; i < n; i++) { if ((*SoType::typedatalist)[i]) { SoType chktype = (*SoType::typedatalist)[i]->type; if (!chktype.isInternal() && chktype.isDerivedFrom(type)) { list.append(chktype); counter++; } } } return counter; }
SbBool SoGate::readInstance(SoInput *in, unsigned short flags) // //////////////////////////////////////////////////////////////////////// { SbName typeName; if (!in->read(typeName, TRUE) || typeName != "type" || !typeField.read(in, "type")) { SoReadError::post(in, "SoGate is missing type field"); return FALSE; } SoType inputType = SoType::fromName(typeField.getValue()); if (! inputType.isDerivedFrom(SoMField::getClassTypeId())) { SoReadError::post(in, "\"%s\" is not a type of MField", typeField.getValue().getString()); return FALSE; } setup(inputType); return SoEngine::readInstance(in, flags); }
SbBool GestureNavigationStyle::processSoEvent(const SoEvent * const ev) { // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode (Bug #0000911) if (!this->isSeekMode()&& !this->isAnimating() && this->isViewing() ) this->setViewing(false); // by default disable viewing mode to render the scene //setViewing() is never used in this style, so the previous if is very unlikely to be hit. const SoType type(ev->getTypeId()); //define some shortcuts... bool evIsButton = type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId()); bool evIsKeyboard = type.isDerivedFrom(SoKeyboardEvent::getClassTypeId()); bool evIsLoc2 = type.isDerivedFrom(SoLocation2Event::getClassTypeId());//mouse movement bool evIsLoc3 = type.isDerivedFrom(SoMotion3Event::getClassTypeId());//spaceball/joystick movement bool evIsGesture = type.isDerivedFrom(SoGestureEvent::getClassTypeId());//touchscreen gesture const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition());//not valid for gestures const SbVec2f posn = this->normalizePixelPos(pos); //pos: local coordinates of event, in pixels //posn: normalized local coordinates of event ((0,0) = lower left corner, (1,1) = upper right corner) float ratio = viewer->getSoRenderManager()->getViewportRegion().getViewportAspectRatio(); if (evIsButton || evIsLoc2){ this->lastmouseposition = posn; } const ViewerMode curmode = this->currentmode; //ViewerMode newmode = curmode; //make a unified mouse+modifiers state value (combo) enum { BUTTON1DOWN = 1 << 0, BUTTON2DOWN = 1 << 1, BUTTON3DOWN = 1 << 2, CTRLDOWN = 1 << 3, SHIFTDOWN = 1 << 4, ALTDOWN = 1 << 5, MASKBUTTONS = BUTTON1DOWN | BUTTON2DOWN | BUTTON3DOWN, MASKMODIFIERS = CTRLDOWN | SHIFTDOWN | ALTDOWN }; unsigned int comboBefore = //before = state before this event (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0) | (this->altdown ? ALTDOWN : 0); //test for complex clicks int cntMBBefore = (comboBefore & BUTTON1DOWN ? 1 : 0 ) //cntMBBefore = how many buttons were down when this event arrived? +(comboBefore & BUTTON2DOWN ? 1 : 0 ) +(comboBefore & BUTTON3DOWN ? 1 : 0 ); if (cntMBBefore>=2) this->thisClickIsComplex = true; if (cntMBBefore==0) {//a good chance to reset some click-related stuff this->thisClickIsComplex = false; this->mousedownConsumedCount = 0;//shouldn't be necessary, just a fail-safe. } // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. this->ctrldown = ev->wasCtrlDown(); this->shiftdown = ev->wasShiftDown(); this->altdown = ev->wasAltDown(); //before this block, mouse button states in NavigationStyle::buttonXdown reflected those before current event arrived. //track mouse button states if (evIsButton) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press //the button was pressed (if false -> released) = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch (button) { case SoMouseButtonEvent::BUTTON1: this->button1down = press; break; case SoMouseButtonEvent::BUTTON2: this->button2down = press; break; case SoMouseButtonEvent::BUTTON3: this->button3down = press; break; //whatever else, we don't track } } //after this block, the new states of the buttons are already in. unsigned int comboAfter = //after = state after this event (current, essentially) (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0) | (this->altdown ? ALTDOWN : 0); //test for complex clicks (again) int cntMBAfter = (comboAfter & BUTTON1DOWN ? 1 : 0 ) //cntMBAfter = how many buttons were down when this event arrived? +(comboAfter & BUTTON2DOWN ? 1 : 0 ) +(comboAfter & BUTTON3DOWN ? 1 : 0 ); if (cntMBAfter>=2) this->thisClickIsComplex = true; //if (cntMBAfter==0) this->thisClickIsComplex = false;//don't reset the flag now, we need to know that this mouseUp was an end of a click that was complex. The flag will reset by the before-check in the next event. //test for move detection if (evIsLoc2 || evIsButton){ this->mouseMoveThresholdBroken |= this->testMoveThreshold(pos); } //track gestures if (evIsGesture) { const SoGestureEvent* gesture = static_cast<const SoGestureEvent*>(ev); switch(gesture->state) { case SoGestureEvent::SbGSStart: //assert(!inGesture);//start of another gesture before the first finished? Happens all the time for Pan gesture... No idea why! --DeepSOIC inGesture = true; break; case SoGestureEvent::SbGSUpdate: assert(inGesture);//gesture update without start? inGesture = true; break; case SoGestureEvent::SbGSEnd: assert(inGesture);//gesture ended without starting? inGesture = false; break; case SoGestureEvent::SbGsCanceled: assert(inGesture);//gesture canceled without starting? inGesture=false; break; default: assert(0);//shouldn't happen inGesture = false; } } if (evIsButton) { if(inGesture){ inGesture = false;//reset the flag when mouse clicks are received, to ensure enabling mouse navigation back. setViewingMode(NavigationStyle::SELECTION);//exit navigation asap, to proceed with regular processing of the click } } bool suppressLMBDrag = false; if(viewer->isEditing()){ //in edit mode, disable lmb dragging (spinning). Holding Alt enables it. suppressLMBDrag = !(comboAfter & ALTDOWN); } //----------all this were preparations. Now comes the event handling! ---------- SbBool processed = FALSE;//a return value for the BlahblahblahNavigationStyle::processSoEvent bool propagated = false;//an internal flag indicating that the event has been already passed to inherited, to suppress the automatic doing of this at the end. //goto finalize = return processed. Might be important to do something before done (none now). // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { processed = handleEventInForeground(ev); } if (processed) goto finalize; // Mode-independent keyboard handling if (evIsKeyboard) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch (event->getKey()) { case SoKeyboardEvent::H: processed = TRUE; if(!press){ SbBool ret = NavigationStyle::lookAtPoint(event->getPosition()); if(!ret){ Base::Console().Warning( "No object under cursor! Can't set new center of rotation.\n"); } } break; default: break; } } if (processed) goto finalize; //mode-independent spaceball/joystick handling if (evIsLoc3) { const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev); if (event) this->processMotionEvent(event); processed = TRUE; } if (processed) goto finalize; //all mode-dependent stuff is within this switch. switch(curmode){ case NavigationStyle::IDLE: case NavigationStyle::SELECTION: case NavigationStyle::INTERACT: { //idle and interaction //keyboard if (evIsKeyboard) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch(event->getKey()){ case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: processed = inherited::processSoEvent(ev); propagated = true; break; case SoKeyboardEvent::PAGE_UP: if(press){ doZoom(viewer->getSoRenderManager()->getCamera(), TRUE, posn); } processed = TRUE; break; case SoKeyboardEvent::PAGE_DOWN: if(press){ doZoom(viewer->getSoRenderManager()->getCamera(), FALSE, posn); } processed = TRUE; break; default: break; }//switch key } if (processed) goto finalize; // Mouse Button / Spaceball Button handling if (evIsButton) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press //the button was pressed (if false -> released) = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch(button){ case SoMouseButtonEvent::BUTTON1: case SoMouseButtonEvent::BUTTON2: if(press){ if(this->thisClickIsComplex && this->mouseMoveThresholdBroken){ //this should prevent re-attempts to enter navigation when doing more clicks after a move. } else { //on LMB-down or RMB-down, we don't know yet if we should propagate it or process it. Save the event to be refired later, when it becomes clear. //reset/start move detection machine this->mousedownPos = pos; this->mouseMoveThresholdBroken = false; pan(viewer->getSoRenderManager()->getCamera());//set up panningplane int &cnt = this->mousedownConsumedCount; this->mousedownConsumedEvent[cnt] = *event;//hopefully, a shallow copy is enough. There are no pointers stored in events, apparently. Will loose a subclass, though. cnt++; assert(cnt<=2); if(cnt>static_cast<int>(sizeof(mousedownConsumedEvent))){ cnt=sizeof(mousedownConsumedEvent);//we are in trouble } processed = true;//just consume this event, and wait for the move threshold to be broken to start dragging/panning } } else {//release if (button == SoMouseButtonEvent::BUTTON2 && !this->thisClickIsComplex) { if (!viewer->isEditing() && this->isPopupMenuEnabled()) { processed=true; this->openPopupMenu(event->getPosition()); } } if(! processed) { //re-synthesize all previously-consumed mouseDowns, if any. They might have been re-synthesized already when threshold was broken. for( int i=0; i < this->mousedownConsumedCount; i++ ){ inherited::processSoEvent(& (this->mousedownConsumedEvent[i]));//simulate the previously-comsumed mousedown. } this->mousedownConsumedCount = 0; processed = inherited::processSoEvent(ev);//explicitly, just for clarity that we are sending a full click sequence. propagated = true; } } break; case SoMouseButtonEvent::BUTTON3://press the wheel processed = TRUE; if(press){ SbBool ret = NavigationStyle::lookAtPoint(event->getPosition()); if(!ret){ Base::Console().Warning( "No object under cursor! Can't set new center of rotation.\n"); } } break; case SoMouseButtonEvent::BUTTON4: //(wheel?) doZoom(viewer->getSoRenderManager()->getCamera(), TRUE, posn); processed = TRUE; break; case SoMouseButtonEvent::BUTTON5: //(wheel?) doZoom(viewer->getSoRenderManager()->getCamera(), FALSE, posn); processed = TRUE; break; } } //mouse moves - test for move threshold breaking if (evIsLoc2) { if (this->mouseMoveThresholdBroken && (this->button1down || this->button2down) && mousedownConsumedCount > 0) { //mousemovethreshold has JUST been broken //test if we should enter navigation if ((this->button1down && !suppressLMBDrag) || this->button2down) { //yes, we are entering navigation. //throw away consumed mousedowns. this->mousedownConsumedCount = 0; setViewingMode(this->button1down ? NavigationStyle::DRAGGING : NavigationStyle::PANNING); processed = true; } else { //no, we are not entering navigation. //re-synthesize all previously-consumed mouseDowns, if any, and propagate this mousemove. for( int i=0; i < this->mousedownConsumedCount; i++ ){ inherited::processSoEvent(& (this->mousedownConsumedEvent[i]));//simulate the previously-comsumed mousedown. } this->mousedownConsumedCount = 0; processed = inherited::processSoEvent(ev);//explicitly, just for clarity that we are sending a full click sequence. propagated = true; } } if (mousedownConsumedCount > 0) processed = true;//if we are still deciding if it's a drag or not, consume mouseMoves. } //gesture start if (evIsGesture && /*!this->button1down &&*/ !this->button2down){//ignore gestures when mouse buttons are down. Button1down check was disabled because of wrong state after doubleclick on sketcher constraint to edit datum const SoGestureEvent* gesture = static_cast<const SoGestureEvent*>(ev); if (gesture->state == SoGestureEvent::SbGSStart || gesture->state == SoGestureEvent::SbGSUpdate) {//even if we didn't get a start, assume the first update is a start (sort-of fail-safe). if (type.isDerivedFrom(SoGesturePanEvent::getClassTypeId())) { pan(viewer->getSoRenderManager()->getCamera());//set up panning plane setViewingMode(NavigationStyle::PANNING); processed = true; } else if (type.isDerivedFrom(SoGesturePinchEvent::getClassTypeId())) { pan(viewer->getSoRenderManager()->getCamera());//set up panning plane setViewingMode(NavigationStyle::DRAGGING); processed = true; } //all other gestures - ignore! } } //loc2 (mousemove) - ignore. } break;//end of idle and interaction case NavigationStyle::DRAGGING: case NavigationStyle::ZOOMING: case NavigationStyle::PANNING:{ //actual navigation //no keyboard. // Mouse Button / Spaceball Button handling if (evIsButton) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); //const SbBool press //the button was pressed (if false -> released) // = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch(button){ case SoMouseButtonEvent::BUTTON1: case SoMouseButtonEvent::BUTTON2: if(comboAfter & BUTTON1DOWN || comboAfter & BUTTON2DOWN) { //don't leave navigation till all buttons have been released setViewingMode((comboAfter & BUTTON1DOWN) ? NavigationStyle::DRAGGING : NavigationStyle::PANNING); processed = true; } else { //all buttons are released //end of dragging/panning/whatever setViewingMode(NavigationStyle::SELECTION); processed = true; } //else of if (some bottons down) break; } //switch(button) } //if(evIsButton) //the essence part 1! //mouse movement into camera motion. Suppress if in gesture. Ignore until threshold is surpassed. if (evIsLoc2 && ! this->inGesture && this->mouseMoveThresholdBroken) { //const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (curmode == NavigationStyle::ZOOMING) {//doesn't happen this->zoomByCursor(posn, prevnormalized); processed = TRUE; } else if (curmode == NavigationStyle::PANNING) { panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = TRUE; } else if (curmode == NavigationStyle::DRAGGING) { if (comboAfter & BUTTON1DOWN && comboAfter & BUTTON2DOWN) { //two mouse buttons down - tilting! NavigationStyle::doRotate(viewer->getSoRenderManager()->getCamera(), (posn - prevnormalized)[0]*(-2), SbVec2f(0.5,0.5)); processed = TRUE; } else {//one mouse button - normal spinning //this will also handle the single-finger drag (there's no gesture used, pseudomouse is enough) //this->addToLog(event->getPosition(), event->getTime()); this->spin_simplified(viewer->getSoRenderManager()->getCamera(), posn, prevnormalized); processed = TRUE; } } } //the essence part 2! //gesture into camera motion if (evIsGesture){ const SoGestureEvent* gesture = static_cast<const SoGestureEvent*>(ev); assert(gesture); if (gesture->state == SoGestureEvent::SbGSEnd) { setViewingMode(NavigationStyle::SELECTION); processed=true; } else if (gesture->state == SoGestureEvent::SbGSUpdate){ if(type.isDerivedFrom(SoGesturePinchEvent::getClassTypeId())){ const SoGesturePinchEvent* const event = static_cast<const SoGesturePinchEvent* const>(ev); if (this->zoomAtCursor){ //this is just dealing with the pan part of pinch gesture. Taking care of zooming to pos is done in doZoom. SbVec2f panDist = this->normalizePixelPos(event->deltaCenter.getValue()); NavigationStyle::panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, panDist, SbVec2f(0,0)); } NavigationStyle::doZoom(viewer->getSoRenderManager()->getCamera(),-logf(event->deltaZoom),this->normalizePixelPos(event->curCenter)); if (event->deltaAngle != 0) NavigationStyle::doRotate(viewer->getSoRenderManager()->getCamera(),event->deltaAngle,this->normalizePixelPos(event->curCenter)); processed = true; } if(type.isDerivedFrom(SoGesturePanEvent::getClassTypeId())){ const SoGesturePanEvent* const event = static_cast<const SoGesturePanEvent* const>(ev); //this is just dealing with the pan part of pinch gesture. Taking care of zooming to pos is done in doZoom. SbVec2f panDist = this->normalizePixelPos(event->deltaOffset); NavigationStyle::panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, panDist, SbVec2f(0,0)); processed = true; } } else { //shouldn't happen. Gestures are not expected to start in the middle of navigation. //we'll consume it, without reacting. processed=true; //This does, unfortunately, happen on regular basis for pan gesture on Windows8.1+Qt4.8 } } } break;//end of actual navigation case NavigationStyle::SEEK_WAIT_MODE:{ if (evIsButton) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; if (button == SoMouseButtonEvent::BUTTON1 && press) { this->seekToPoint(pos); // implicitly calls interactiveCountInc() this->setViewingMode(NavigationStyle::SEEK_MODE); processed = true; } } } ; //not end of SEEK_WAIT_MODE. Fall through by design!!! case NavigationStyle::SPINNING: case NavigationStyle::SEEK_MODE: { //animation modes if (!processed) { if (evIsButton || evIsGesture || evIsKeyboard || evIsLoc3) setViewingMode(NavigationStyle::SELECTION); } } break; //end of animation modes case NavigationStyle::BOXZOOM: default: //all the rest - will be pass on to inherited, later. break; } if (! processed && ! propagated) { processed = inherited::processSoEvent(ev); propagated = true; } //-----------------------end of event handling--------------------- finalize: return processed; }
SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) { #if 0 // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } #else if (!this->isSeekMode() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene #endif const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getViewportRegion(); const SbVec2s size(vp.getViewportSizePixels()); const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); const SbVec2f posn((float) pos[0] / (float) SoQtMax((int)(size[0] - 1), 1), (float) pos[1] / (float) SoQtMax((int)(size[1] - 1), 1)); this->lastmouseposition = posn; // Set to TRUE if any event processing happened. Note that it is not // necessary to restrict ourselves to only do one "action" for an // event, we only need this flag to see if any processing happened // at all. SbBool processed = FALSE; const ViewerMode curmode = this->currentmode; ViewerMode newmode = curmode; // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. if (this->ctrldown != ev->wasCtrlDown()) { this->ctrldown = ev->wasCtrlDown(); } if (this->shiftdown != ev->wasShiftDown()) { this->shiftdown = ev->wasShiftDown(); } if (this->altdown != ev->wasAltDown()) { this->altdown = ev->wasAltDown(); } // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!processed && !viewer->isEditing()) { processed = handleEventInForeground(ev); if (processed) return TRUE; } // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch (event->getKey()) { case SoKeyboardEvent::LEFT_CONTROL: case SoKeyboardEvent::RIGHT_CONTROL: this->ctrldown = press; break; case SoKeyboardEvent::LEFT_SHIFT: case SoKeyboardEvent::RIGHT_SHIFT: this->shiftdown = press; break; case SoKeyboardEvent::LEFT_ALT: case SoKeyboardEvent::RIGHT_ALT: this->altdown = press; break; case SoKeyboardEvent::H: processed = TRUE; viewer->saveHomePosition(); break; case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: if (!this->isViewing()) this->setViewing(true); break; default: break; } } // Mouse Button / Spaceball Button handling if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; // SoDebugError::postInfo("processSoEvent", "button = %d", button); switch (button) { case SoMouseButtonEvent::BUTTON1: this->lockrecenter = TRUE; this->button1down = press; #if 0 // disable to avoid interferences where this key combination is used, too if (press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue()); this->lockrecenter = FALSE; } else if (!press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // is it just a left click? if (tmp.getValue() < dci && !this->lockrecenter) { if (!this->moveToPoint(pos)) { panToCenter(panningplane, posn); this->interactiveCountDec(); } processed = TRUE; } } else #endif if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = TRUE; } //else if (press && (this->currentmode == NavigationStyle::IDLE)) { // this->setViewing(true); // processed = TRUE; //} else if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; this->centerTime = ev->getTime(); processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; if (tmp.getValue() < dci) { newmode = NavigationStyle::ZOOMING; } processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { this->setViewing(false); processed = TRUE; } else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = TRUE; } break; case SoMouseButtonEvent::BUTTON2: // If we are in edit mode then simply ignore the RMB events // to pass the event to the base class. this->lockrecenter = TRUE; if (!viewer->isEditing()) { // If we are in zoom or pan mode ignore RMB events otherwise // the canvas doesn't get any release events if (this->currentmode != NavigationStyle::ZOOMING && this->currentmode != NavigationStyle::PANNING && this->currentmode != NavigationStyle::DRAGGING) { if (this->isPopupMenuEnabled()) { if (!press) { // release right mouse button this->openPopupMenu(event->getPosition()); } } } } // Alternative way of rotating & zooming if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; this->centerTime = ev->getTime(); processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; if (tmp.getValue() < dci) { newmode = NavigationStyle::ZOOMING; } processed = TRUE; } this->button2down = press; break; case SoMouseButtonEvent::BUTTON3: if (press) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue()); this->lockrecenter = FALSE; } else { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // is it just a middle click? if (tmp.getValue() < dci && !this->lockrecenter) { if (!this->lookAtPoint(pos)) { panToCenter(panningplane, posn); this->interactiveCountDec(); } processed = TRUE; } } this->button3down = press; break; case SoMouseButtonEvent::BUTTON4: doZoom(viewer->getCamera(), TRUE, posn); processed = TRUE; break; case SoMouseButtonEvent::BUTTON5: doZoom(viewer->getCamera(), FALSE, posn); processed = TRUE; break; default: break; } } // Mouse Movement handling if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { this->lockrecenter = TRUE; const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (this->currentmode == NavigationStyle::ZOOMING) { this->zoomByCursor(posn, prevnormalized); processed = TRUE; } else if (this->currentmode == NavigationStyle::PANNING) { float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = TRUE; } else if (this->currentmode == NavigationStyle::DRAGGING) { this->addToLog(event->getPosition(), event->getTime()); this->spin(posn); processed = TRUE; } } // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev); if (event) this->processMotionEvent(event); processed = TRUE; } enum { BUTTON1DOWN = 1 << 0, BUTTON3DOWN = 1 << 1, CTRLDOWN = 1 << 2, SHIFTDOWN = 1 << 3, BUTTON2DOWN = 1 << 4 }; unsigned int combo = (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0); switch (combo) { case 0: if (curmode == NavigationStyle::SPINNING) { break; } newmode = NavigationStyle::IDLE; // The left mouse button has been released right now but // we want to avoid that the event is procesed elsewhere if (this->lockButton1) { this->lockButton1 = FALSE; processed = TRUE; } //if (curmode == NavigationStyle::DRAGGING) { // if (doSpin()) // newmode = NavigationStyle::SPINNING; //} break; case BUTTON1DOWN: // make sure not to change the selection when stopping spinning if (curmode == NavigationStyle::SPINNING || this->lockButton1) newmode = NavigationStyle::IDLE; else newmode = NavigationStyle::SELECTION; break; case BUTTON3DOWN: if (curmode == NavigationStyle::SPINNING) { break; } else if (newmode == NavigationStyle::ZOOMING) { break; } newmode = NavigationStyle::PANNING; if (curmode == NavigationStyle::DRAGGING) { if (doSpin()) { newmode = NavigationStyle::SPINNING; break; } } break; case CTRLDOWN|BUTTON2DOWN: newmode = NavigationStyle::PANNING; break; case SHIFTDOWN|BUTTON2DOWN: newmode = NavigationStyle::DRAGGING; break; case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN: newmode = NavigationStyle::ZOOMING; break; //case CTRLDOWN: //case CTRLDOWN|BUTTON1DOWN: //case CTRLDOWN|SHIFTDOWN: //case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN: // newmode = NavigationStyle::SELECTION; // break; //case BUTTON1DOWN|BUTTON3DOWN: //case CTRLDOWN|BUTTON3DOWN: // newmode = NavigationStyle::ZOOMING; // break; // There are many cases we don't handle that just falls through to // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN, // SHIFTDOWN|BUTTON3DOWN, SHIFTDOWN|CTRLDOWN|BUTTON3DOWN, etc. // This is a feature, not a bug. :-) // // mortene. default: // The default will make a spin stop and otherwise not do // anything. //if ((curmode != NavigationStyle::SEEK_WAIT_MODE) && // (curmode != NavigationStyle::SEEK_MODE)) { // newmode = NavigationStyle::IDLE; //} break; } if (newmode != curmode) { this->setViewingMode(newmode); } // If for dragging the buttons 1 and 3 are pressed // but then button 3 is relaesed we shouldn't switch // into selection mode. if (this->button1down && this->button3down) this->lockButton1 = TRUE; // If not handled in this class, pass on upwards in the inheritance // hierarchy. if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) processed = inherited::processSoEvent(ev); else return TRUE; return processed; }
SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) { // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode (Bug #0000911) if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); const SbVec2s size(vp.getViewportSizePixels()); const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); this->lastmouseposition = posn; // Set to TRUE if any event processing happened. Note that it is not // necessary to restrict ourselves to only do one "action" for an // event, we only need this flag to see if any processing happened // at all. SbBool processed = FALSE; const ViewerMode curmode = this->currentmode; ViewerMode newmode = curmode; // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. if (this->ctrldown != ev->wasCtrlDown()) { this->ctrldown = ev->wasCtrlDown(); } if (this->shiftdown != ev->wasShiftDown()) { this->shiftdown = ev->wasShiftDown(); } if (this->altdown != ev->wasAltDown()) { this->altdown = ev->wasAltDown(); } // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!processed && !viewer->isEditing()) { processed = handleEventInForeground(ev); if (processed) return TRUE; } // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch (event->getKey()) { case SoKeyboardEvent::LEFT_CONTROL: case SoKeyboardEvent::RIGHT_CONTROL: this->ctrldown = press; break; case SoKeyboardEvent::LEFT_SHIFT: case SoKeyboardEvent::RIGHT_SHIFT: this->shiftdown = press; break; case SoKeyboardEvent::LEFT_ALT: case SoKeyboardEvent::RIGHT_ALT: this->altdown = press; break; case SoKeyboardEvent::H: processed = TRUE; viewer->saveHomePosition(); break; case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: if (!this->isViewing()) this->setViewing(true); break; case SoKeyboardEvent::PAGE_UP: doZoom(viewer->getSoRenderManager()->getCamera(), TRUE, posn); processed = TRUE; break; case SoKeyboardEvent::PAGE_DOWN: doZoom(viewer->getSoRenderManager()->getCamera(), FALSE, posn); processed = TRUE; break; default: break; } } // Mouse Button / Spaceball Button handling if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; // SoDebugError::postInfo("processSoEvent", "button = %d", button); switch (button) { case SoMouseButtonEvent::BUTTON1: this->lockrecenter = TRUE; this->button1down = press; if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = TRUE; } else if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; saveCursorPosition(ev); this->centerTime = ev->getTime(); processed = TRUE; } else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = TRUE; } break; case SoMouseButtonEvent::BUTTON2: // If we are in edit mode then simply ignore the RMB events // to pass the event to the base class. this->lockrecenter = TRUE; if (!viewer->isEditing()) { // If we are in zoom or pan mode ignore RMB events otherwise // the canvas doesn't get any release events if (this->currentmode != NavigationStyle::ZOOMING && this->currentmode != NavigationStyle::PANNING && this->currentmode != NavigationStyle::DRAGGING) { if (this->isPopupMenuEnabled()) { if (!press) { // release right mouse button this->openPopupMenu(event->getPosition()); } } } } // Alternative way of rotating & zooming if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; saveCursorPosition(ev); this->centerTime = ev->getTime(); processed = TRUE; } this->button2down = press; break; case SoMouseButtonEvent::BUTTON4: doZoom(viewer->getSoRenderManager()->getCamera(), TRUE, posn); processed = TRUE; break; case SoMouseButtonEvent::BUTTON5: doZoom(viewer->getSoRenderManager()->getCamera(), FALSE, posn); processed = TRUE; break; default: break; } } // Mouse Movement handling if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { this->lockrecenter = TRUE; const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (this->currentmode == NavigationStyle::ZOOMING) { this->zoomByCursor(posn, prevnormalized); processed = TRUE; } else if (this->currentmode == NavigationStyle::PANNING) { float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = TRUE; } else if (this->currentmode == NavigationStyle::DRAGGING) { this->addToLog(event->getPosition(), event->getTime()); this->spin(posn); moveCursorPosition(); processed = TRUE; } } // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev); if (event) this->processMotionEvent(event); processed = TRUE; } enum { BUTTON1DOWN = 1 << 0, BUTTON2DOWN = 1 << 1, CTRLDOWN = 1 << 2, SHIFTDOWN = 1 << 3, ALTDOWN = 1 << 4 }; unsigned int combo = (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0) | (this->altdown ? ALTDOWN : 0); switch (combo) { case 0: if (curmode == NavigationStyle::SPINNING) { break; } newmode = NavigationStyle::IDLE; break; case BUTTON1DOWN: // make sure not to change the selection when stopping spinning if (curmode == NavigationStyle::SPINNING) newmode = NavigationStyle::IDLE; else newmode = NavigationStyle::SELECTION; break; case CTRLDOWN: newmode = NavigationStyle::IDLE; break; case SHIFTDOWN: newmode = NavigationStyle::PANNING; break; case ALTDOWN: if (newmode != NavigationStyle::DRAGGING) { saveCursorPosition(ev); } newmode = NavigationStyle::DRAGGING; break; case CTRLDOWN|SHIFTDOWN: case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN: newmode = NavigationStyle::ZOOMING; break; default: break; } if (newmode != curmode) { this->setViewingMode(newmode); } // If not handled in this class, pass on upwards in the inheritance // hierarchy. if (!processed) processed = inherited::processSoEvent(ev); else return TRUE; return processed; }
void SoGate::setup(SoType inputType) // //////////////////////////////////////////////////////////////////////// { #ifdef DEBUG if (input != NULL) { SoDebugError::post("SoGate::setup", "Already initialized!"); } #endif if (inputType.isDerivedFrom(SoMField::getClassTypeId())) { input = (SoMField *)inputType.createInstance(); } else { input = NULL; } if (input == NULL) { #ifdef DEBUG SoDebugError::post("SoGate::setup", "Couldn't create field of type %s", inputType.getName().getString()); #endif conversionCase = BAD_TYPE; } else { input->setContainer(this); // Pass in the static field data as the parent field data for // the per-instance field data: myInputData->addField(this, "input", input); // Construct the output: output = new SoEngineOutput; output->setContainer(this); myOutputData->addOutput(this, "output", output, inputType); // This handy macro sets up conversionCase, which is used to quickly // decide what type we're hooked up to at evaluate() time: #define DECIDE(class) \ (inputType == SO__CONCAT(SoMF,class)::getClassTypeId()) { \ conversionCase = class; \ } // Set up for which switch to use in evaluate() routine: if DECIDE(BitMask) else if DECIDE(Bool) else if DECIDE(Color) else if DECIDE(Enum) else if DECIDE(Float) else if DECIDE(Int32) else if DECIDE(Matrix) else if DECIDE(Name) else if DECIDE(Node) else if DECIDE(Path) else if DECIDE(Plane) else if DECIDE(Rotation) else if DECIDE(Short) else if DECIDE(String) else if DECIDE(Time) else if DECIDE(UInt32) else if DECIDE(UShort) else if DECIDE(Vec2f) else if DECIDE(Vec3f) else if DECIDE(Vec4f) #undef DECIDE else { #ifdef DEBUG SoDebugError::post("SoGate::setup", "Can't gate field of type %s", inputType.getName().getString()); #endif conversionCase = BAD_TYPE; } } }
SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) { // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); const SbVec2s size(vp.getViewportSizePixels()); const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not // necessary to restrict ourselves to only do one "action" for an // event, we only need this flag to see if any processing happened // at all. SbBool processed = false; const ViewerMode curmode = this->currentmode; ViewerMode newmode = curmode; // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. if (this->ctrldown != ev->wasCtrlDown()) { this->ctrldown = ev->wasCtrlDown(); } if (this->shiftdown != ev->wasShiftDown()) { this->shiftdown = ev->wasShiftDown(); } if (this->altdown != ev->wasAltDown()) { this->altdown = ev->wasAltDown(); } // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!processed && !viewer->isEditing()) { processed = handleEventInForeground(ev); if (processed) return true; } // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; switch (event->getKey()) { case SoKeyboardEvent::LEFT_CONTROL: case SoKeyboardEvent::RIGHT_CONTROL: this->ctrldown = press; break; case SoKeyboardEvent::LEFT_SHIFT: case SoKeyboardEvent::RIGHT_SHIFT: this->shiftdown = press; break; case SoKeyboardEvent::LEFT_ALT: case SoKeyboardEvent::RIGHT_ALT: this->altdown = press; break; case SoKeyboardEvent::H: processed = true; viewer->saveHomePosition(); break; case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: if (!this->isViewing()) this->setViewing(true); break; default: break; } } // Mouse Button / Spaceball Button handling if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; switch (button) { case SoMouseButtonEvent::BUTTON1: this->lockrecenter = true; this->button1down = press; if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = true; } else if (!press && (this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::IDLE; processed = true; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { this->setViewing(false); processed = true; } else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } // issue #0002433: avoid to swallow the UP event if down the // scene graph somewhere a dialog gets opened else if (press) { SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // a double-click? if (tmp.getValue() < dci) { mouseDownConsumedEvent = *event; mouseDownConsumedEvent.setTime(ev->getTime()); processed = true; } else { mouseDownConsumedEvent.setTime(ev->getTime()); // 'ANY' is used to mark that we don't know yet if it will // be a double-click event. mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); } } else if (!press) { if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { // now handle the postponed event inherited::processSoEvent(&mouseDownConsumedEvent); mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); } } break; case SoMouseButtonEvent::BUTTON2: // If we are in edit mode then simply ignore the RMB events // to pass the event to the base class. this->lockrecenter = true; if (!viewer->isEditing()) { // If we are in zoom or pan mode ignore RMB events otherwise // the canvas doesn't get any release events if (this->currentmode != NavigationStyle::ZOOMING && this->currentmode != NavigationStyle::PANNING && this->currentmode != NavigationStyle::DRAGGING) { if (this->isPopupMenuEnabled()) { if (!press) { // release right mouse button this->openPopupMenu(event->getPosition()); } } } } // Alternative way of rotating & zooming if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; saveCursorPosition(ev); this->centerTime = ev->getTime(); processed = true; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { newmode = NavigationStyle::IDLE; processed = true; } this->button2down = press; break; case SoMouseButtonEvent::BUTTON3: if (press) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue()); this->lockrecenter = false; } else if (!press && (this->currentmode == NavigationStyle::PANNING)) { newmode = NavigationStyle::IDLE; processed = true; } this->button3down = press; break; case SoMouseButtonEvent::BUTTON4: case SoMouseButtonEvent::BUTTON5: doZoom(viewer->getSoRenderManager()->getCamera(), button == SoMouseButtonEvent::BUTTON4, posn); processed = true; break; default: break; } } enum { BUTTON1DOWN = 1 << 0, BUTTON3DOWN = 1 << 1, CTRLDOWN = 1 << 2, SHIFTDOWN = 1 << 3, BUTTON2DOWN = 1 << 4 }; unsigned int combo = (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0); // Mouse Movement handling if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { this->lockrecenter = true; const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (this->currentmode == NavigationStyle::ZOOMING) { // OCCT uses horizontal mouse position, not vertical // this->zoomByCursor(posn, prevnormalized); float value = (posn[0] - prevnormalized[0]) * 10.0f; if (this->invertZoom) value = -value; zoom(viewer->getSoRenderManager()->getCamera(), value); processed = true; } else if (this->currentmode == NavigationStyle::PANNING) { float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = true; } else if (this->currentmode == NavigationStyle::DRAGGING) { this->addToLog(event->getPosition(), event->getTime()); this->spin(posn); moveCursorPosition(); processed = true; } else if (combo == (CTRLDOWN|BUTTON1DOWN)) { newmode = NavigationStyle::ZOOMING; } } // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev); if (event) this->processMotionEvent(event); processed = true; } switch (combo) { case 0: if (curmode == NavigationStyle::SPINNING) { break; } newmode = NavigationStyle::IDLE; break; case CTRLDOWN|BUTTON1DOWN: case BUTTON1DOWN: if (newmode != NavigationStyle::ZOOMING) newmode = NavigationStyle::SELECTION; break; case CTRLDOWN|BUTTON3DOWN: case BUTTON3DOWN: newmode = NavigationStyle::PANNING; break; case CTRLDOWN|BUTTON2DOWN: newmode = NavigationStyle::DRAGGING; break; case BUTTON2DOWN: newmode = NavigationStyle::IDLE; break; default: break; } if (newmode != curmode) { this->setViewingMode(newmode); } // If not handled in this class, pass on upwards in the inheritance // hierarchy. if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) processed = inherited::processSoEvent(ev); else return true; return processed; }