SoFCSelection.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2005 Jürgen Riegel <juergen.riegel@web.de>              *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 #include "PreCompiled.h"
00024 
00025 #ifndef _PreComp_
00026 # include <qstatusbar.h>
00027 # include <qstring.h>
00028 # include <Inventor/details/SoFaceDetail.h>
00029 # include <Inventor/details/SoLineDetail.h>
00030 #endif
00031 
00032 #include <Inventor/elements/SoOverrideElement.h>
00033 #include <Inventor/elements/SoLazyElement.h>
00034 #include <Inventor/elements/SoCacheElement.h>
00035 #include <Inventor/elements/SoOverrideElement.h>
00036 #include <Inventor/elements/SoWindowElement.h>
00037 
00038 #include <Inventor/SoFullPath.h>
00039 #include <Inventor/actions/SoGLRenderAction.h>
00040 #include <Inventor/actions/SoHandleEventAction.h>
00041 #include <Inventor/events/SoKeyboardEvent.h>
00042 #include <Inventor/events/SoMouseButtonEvent.h>
00043 #include <Inventor/misc/SoState.h>
00044 #include <Inventor/misc/SoChildList.h>
00045 #include <Inventor/events/SoLocation2Event.h>
00046 #include <Inventor/SoPickedPoint.h>
00047 
00048 #include "View3DInventor.h"
00049 #include "View3DInventorViewer.h"
00050 
00051 #include <Base/Console.h>
00052 #include "SoFCSelection.h"
00053 #include "MainWindow.h"
00054 #include "Selection.h"
00055 #include "SoFCSelectionAction.h"
00056 #include "SoFCInteractiveElement.h"
00057 
00058 // For 64-bit system the method using the front buffer doesn't work at all for lines.
00059 // Thus, use the method which forces a redraw every time. This is a bit slower but at
00060 // least it works.
00061 #if defined(_OCC64) // is set by configure or cmake
00062 # define NO_FRONTBUFFER
00063 #endif
00064 
00065 using namespace Gui;
00066 
00067 SoFullPath * Gui::SoFCSelection::currenthighlight = NULL;
00068 
00069 
00070 // *************************************************************************
00071 
00072 SO_NODE_SOURCE(SoFCSelection);
00073 
00077 SoFCSelection::SoFCSelection()
00078 {
00079     SO_NODE_CONSTRUCTOR(SoFCSelection);
00080 
00081     SO_NODE_ADD_FIELD(colorHighlight, (SbColor(0.8f, 0.1f, 0.1f)));
00082     SO_NODE_ADD_FIELD(colorSelection, (SbColor(0.1f, 0.8f, 0.1f)));
00083     SO_NODE_ADD_FIELD(style,          (EMISSIVE));
00084     SO_NODE_ADD_FIELD(highlightMode,  (AUTO));
00085     SO_NODE_ADD_FIELD(selectionMode,  (SEL_ON));
00086     SO_NODE_ADD_FIELD(selected,       (NOTSELECTED));
00087     SO_NODE_ADD_FIELD(documentName,   (""));
00088     SO_NODE_ADD_FIELD(objectName,     (""));
00089     SO_NODE_ADD_FIELD(subElementName, (""));
00090 
00091     SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE);
00092     SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE_DIFFUSE);
00093     SO_NODE_DEFINE_ENUM_VALUE(Styles, BOX);
00094     SO_NODE_SET_SF_ENUM_TYPE(style,   Styles);
00095 
00096     SO_NODE_DEFINE_ENUM_VALUE(HighlightModes, AUTO);
00097     SO_NODE_DEFINE_ENUM_VALUE(HighlightModes, ON);
00098     SO_NODE_DEFINE_ENUM_VALUE(HighlightModes, OFF);
00099     SO_NODE_SET_SF_ENUM_TYPE (highlightMode, HighlightModes);
00100 
00101     SO_NODE_DEFINE_ENUM_VALUE(SelectionModes, SEL_ON);
00102     SO_NODE_DEFINE_ENUM_VALUE(SelectionModes, SEL_OFF);
00103     SO_NODE_SET_SF_ENUM_TYPE (selectionMode,  SelectionModes);
00104 
00105     SO_NODE_DEFINE_ENUM_VALUE(Selected, NOTSELECTED);
00106     SO_NODE_DEFINE_ENUM_VALUE(Selected, SELECTED);
00107     SO_NODE_SET_SF_ENUM_TYPE(selected,  Selected);
00108 
00109     highlighted = FALSE;
00110     bShift      = FALSE;
00111     bCtrl       = FALSE;
00112 
00113     selected = NOTSELECTED;
00114 }
00115 
00119 SoFCSelection::~SoFCSelection()
00120 {
00121     // If we're being deleted and we're the current highlight,
00122     // NULL out that variable
00123     if (currenthighlight != NULL &&
00124         (!currenthighlight->getTail()->isOfType(SoFCSelection::getClassTypeId()))) {
00125         currenthighlight->unref();
00126         currenthighlight = NULL;
00127     }
00128     //delete THIS;
00129 }
00130 
00131 // doc from parent
00132 void
00133 SoFCSelection::initClass(void)
00134 {
00135     SO_NODE_INIT_CLASS(SoFCSelection,SoGroup,"Group");
00136 }
00137 
00138 void SoFCSelection::finish()
00139 {
00140     atexit_cleanup();
00141 }
00142 
00146 void
00147 SoFCSelection::turnOffCurrentHighlight(SoGLRenderAction * action)
00148 {
00149     SoFCSelection::turnoffcurrent(action);
00150 }
00151 
00152 void SoFCSelection::doAction(SoAction *action)
00153 {
00154     if (action->getTypeId() == SoFCDocumentAction::getClassTypeId()) {
00155         SoFCDocumentAction *docaction = (SoFCDocumentAction*)action;
00156         this->documentName = docaction->documentName;
00157     }
00158 
00159     if (action->getTypeId() == SoFCDocumentObjectAction::getClassTypeId()) {
00160         SoFCDocumentObjectAction* objaction = static_cast<SoFCDocumentObjectAction*>(action);
00161         objaction->documentName  = this->documentName.getValue();
00162         objaction->objectName    = this->objectName.getValue();
00163         objaction->componentName = this->subElementName.getValue();
00164         objaction->setHandled();
00165     }
00166 
00167     if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
00168         SoFCEnableHighlightAction *preaction = (SoFCEnableHighlightAction*)action;
00169         if (preaction->highlight) {
00170             this->highlightMode = SoFCSelection::AUTO;
00171         }
00172         else {
00173             this->highlightMode = SoFCSelection::OFF;
00174         }
00175     }
00176 
00177     if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
00178         SoFCEnableSelectionAction *selaction = (SoFCEnableSelectionAction*)action;
00179         if (selaction->selection) {
00180             this->selectionMode = SoFCSelection::SEL_ON;
00181         }
00182         else {
00183             this->selectionMode = SoFCSelection::SEL_OFF;
00184             if (selected.getValue() == SELECTED) {
00185                 this->selected = NOTSELECTED;
00186             }
00187         }
00188     }
00189 
00190     if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
00191         SoFCSelectionColorAction *colaction = (SoFCSelectionColorAction*)action;
00192         this->colorSelection = colaction->selectionColor;
00193     }
00194 
00195     if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
00196         SoFCHighlightColorAction *colaction = (SoFCHighlightColorAction*)action;
00197         this->colorHighlight = colaction->highlightColor;
00198     }
00199 
00200     if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
00201         SoFCSelectionAction *selaction = static_cast<SoFCSelectionAction*>(action);
00202 
00203         if (selaction->SelChange.Type == SelectionChanges::AddSelection || 
00204             selaction->SelChange.Type == SelectionChanges::RmvSelection) {
00205             if (documentName.getValue() == selaction->SelChange.pDocName &&
00206                 objectName.getValue() == selaction->SelChange.pObjectName &&
00207                 (subElementName.getValue() == selaction->SelChange.pSubName || 
00208                 *(selaction->SelChange.pSubName) == '\0') ) {
00209                 if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
00210                     if(selected.getValue() == NOTSELECTED){
00211                         selected = SELECTED;
00212                     }
00213                 }
00214                 else {
00215                     if(selected.getValue() == SELECTED){
00216                         selected = NOTSELECTED;
00217                     }
00218                 }
00219                 return;
00220             }
00221         }
00222         else if (selaction->SelChange.Type == SelectionChanges::ClrSelection) {
00223             if (documentName.getValue() == selaction->SelChange.pDocName ||
00224                 strcmp(selaction->SelChange.pDocName,"") == 0){
00225                 if(selected.getValue() == SELECTED){
00226                     selected = NOTSELECTED;
00227                 }
00228                
00229             }
00230         }
00231         else if (selaction->SelChange.Type == SelectionChanges::SetSelection) {
00232             bool sel = Selection().isSelected(
00233                     documentName.getValue().getString(),
00234                     objectName.getValue().getString()/*,
00235                     subElementName.getValue().getString()*/);
00236             if (sel) {
00237                 if (selected.getValue() == NOTSELECTED) {
00238                     selected = SELECTED;
00239                 }
00240             }
00241             else {
00242                 if (selected.getValue() == SELECTED) {
00243                     selected = NOTSELECTED;
00244                 }
00245             }
00246         }
00247     }
00248 
00249     inherited::doAction( action );
00250 }
00251 
00252 int SoFCSelection::getPriority(const SoPickedPoint* p)
00253 {
00254     const SoDetail* detail = p->getDetail();
00255     if(!detail) return 0;
00256     if(detail->isOfType(SoFaceDetail::getClassTypeId())) return 1;
00257     if(detail->isOfType(SoLineDetail::getClassTypeId())) return 2;
00258     if(detail->isOfType(SoPointDetail::getClassTypeId())) return 3;
00259     return 0;
00260 }
00261 
00262 const SoPickedPoint*
00263 SoFCSelection::getPickedPoint(SoHandleEventAction* action) const
00264 {
00265     // To identify the picking of lines in a concave area we have to 
00266     // get all intersection points. If we have two or more intersection
00267     // points where the first is of a face and the second of a line with
00268     // almost similar coordinates we use the second point, instead.
00269     const SoPickedPointList & points = action->getPickedPointList();
00270     if (points.getLength() == 0)
00271         return 0;
00272     else if (points.getLength() == 1)
00273         return points[0];
00274     //const SoPickedPoint* pp0 = points[0];
00275     //const SoPickedPoint* pp1 = points[1];
00276     //const SoDetail* det0 = pp0->getDetail();
00277     //const SoDetail* det1 = pp1->getDetail();
00278     //if (det0 && det0->isOfType(SoFaceDetail::getClassTypeId()) &&
00279     //    det1 && det1->isOfType(SoLineDetail::getClassTypeId())) {
00280     //    const SbVec3f& pt0 = pp0->getPoint();
00281     //    const SbVec3f& pt1 = pp1->getPoint();
00282     //    if (pt0.equals(pt1, 0.01f))
00283     //        return pp1;
00284     //}
00285 
00286     //return pp0;
00287     
00288     const SoPickedPoint* picked = points[0];
00289 
00290     int picked_prio = getPriority(picked);
00291     const SbVec3f& picked_pt = picked->getPoint();
00292 
00293    
00294     for(int i=1; i<points.getLength();i++) {
00295         const SoPickedPoint* cur = points[i];
00296         int cur_prio = getPriority(cur);
00297         const SbVec3f& cur_pt = cur->getPoint();
00298 
00299         if ((cur_prio > picked_prio) && picked_pt.equals(cur_pt, 0.01f)) {
00300             picked = cur;
00301             picked_prio = cur_prio;
00302         }
00303     }
00304     return picked;
00305 
00306 }
00307 
00308 // doc from parent
00309 void
00310 SoFCSelection::handleEvent(SoHandleEventAction * action)
00311 {
00312     static char buf[513];
00313     HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
00314     const SoEvent * event = action->getEvent();
00315 #ifdef NO_FRONTBUFFER
00316     // mouse move events for preselection
00317     if (event->isOfType(SoLocation2Event::getClassTypeId())) {
00318         // NOTE: If preselection is off then we do not check for a picked point because otherwise this search may slow
00319         // down extremely the system on really big data sets. In this case we just check for a picked point if the data
00320         // set has been selected.
00321         if (mymode == AUTO || mymode == ON) {
00322             const SoPickedPoint * pp = this->getPickedPoint(action);
00323             if (pp && pp->getPath()->containsPath(action->getCurPath())) {
00324                 if (!highlighted) {
00325                     if (Gui::Selection().setPreselect(documentName.getValue().getString()
00326                                            ,objectName.getValue().getString()
00327                                            ,subElementName.getValue().getString()
00328                                            ,pp->getPoint()[0]
00329                                            ,pp->getPoint()[1]
00330                                            ,pp->getPoint()[2])){
00331                         SoFCSelection::turnoffcurrent(action);
00332                         SoFCSelection::currenthighlight = (SoFullPath*)action->getCurPath()->copy();
00333                         SoFCSelection::currenthighlight->ref();
00334                         highlighted = TRUE;
00335                         this->touch(); // force scene redraw
00336                         this->redrawHighlighted(action, TRUE);
00337                     }
00338                 }
00339                 
00340                 snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
00341                                            ,objectName.getValue().getString()
00342                                            ,subElementName.getValue().getString()
00343                                            ,pp->getPoint()[0]
00344                                            ,pp->getPoint()[1]
00345                                            ,pp->getPoint()[2]);
00346 
00347                 getMainWindow()->showMessage(QString::fromAscii(buf),3000);
00348             }
00349             else { // picked point
00350                 if (highlighted) {
00351                     if (mymode == AUTO)
00352                         SoFCSelection::turnoffcurrent(action);
00353                     //FIXME: I think we should set 'highlighted' to false whenever no point is picked
00354                     //else
00355                     highlighted = FALSE;
00356                     Gui::Selection().rmvPreselect();
00357                 }
00358             }
00359         }
00360     } // key press events
00361     else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) {
00362         SoKeyboardEvent  * const e = (SoKeyboardEvent  *) event;
00363         if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT)     ||
00364             SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT)     )
00365             bShift = true;
00366         if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT)   ||
00367             SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT)   )
00368             bShift = false;
00369         if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL)   ||
00370             SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL)   )
00371             bCtrl = true;
00372         if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
00373             SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
00374             bCtrl = false;
00375     } // mouse press events for (de)selection
00376     else if (event->isOfType(SoMouseButtonEvent::getClassTypeId())) {
00377         SoMouseButtonEvent * const e = (SoMouseButtonEvent *) event;
00378         if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
00379             //FIXME: Shouldn't we remove the preselection for newly selected objects?
00380             //       Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
00381             const SoPickedPoint * pp = this->getPickedPoint(action);
00382             if (pp && pp->getPath()->containsPath(action->getCurPath())) {
00383                 if (bCtrl) {
00384                     if (Gui::Selection().isSelected(documentName.getValue().getString()
00385                                          ,objectName.getValue().getString()
00386                                          ,subElementName.getValue().getString())) {
00387                         Gui::Selection().rmvSelection(documentName.getValue().getString()
00388                                           ,objectName.getValue().getString()
00389                                           ,subElementName.getValue().getString());
00390                     } else {
00391                         Gui::Selection().addSelection(documentName.getValue().getString()
00392                                           ,objectName.getValue().getString()
00393                                           ,subElementName.getValue().getString()
00394                                           ,pp->getPoint()[0]
00395                                           ,pp->getPoint()[1]
00396                                           ,pp->getPoint()[2]);
00397 
00398                         if (mymode == OFF) {
00399                             snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
00400                                                        ,objectName.getValue().getString()
00401                                                        ,subElementName.getValue().getString()
00402                                                        ,pp->getPoint()[0]
00403                                                        ,pp->getPoint()[1]
00404                                                        ,pp->getPoint()[2]);
00405 
00406                             getMainWindow()->showMessage(QString::fromAscii(buf),3000);
00407                         }
00408                     }
00409                 }
00410                 else { // Ctrl
00411                     if (!Gui::Selection().isSelected(documentName.getValue().getString()
00412                                          ,objectName.getValue().getString()
00413                                          ,subElementName.getValue().getString())) {
00414                         Gui::Selection().clearSelection(documentName.getValue().getString());
00415                         Gui::Selection().addSelection(documentName.getValue().getString()
00416                                               ,objectName.getValue().getString()
00417                                               ,subElementName.getValue().getString()
00418                                               ,pp->getPoint()[0]
00419                                               ,pp->getPoint()[1]
00420                                               ,pp->getPoint()[2]);
00421                     }
00422                     else {
00423                         Gui::Selection().clearSelection(documentName.getValue().getString());
00424                         Gui::Selection().addSelection(documentName.getValue().getString()
00425                                               ,objectName.getValue().getString()
00426                                               ,0
00427                                               ,pp->getPoint()[0]
00428                                               ,pp->getPoint()[1]
00429                                               ,pp->getPoint()[2]);
00430                     }
00431 
00432                     if (mymode == OFF) {
00433                         snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
00434                                                    ,objectName.getValue().getString()
00435                                                    ,subElementName.getValue().getString()
00436                                                    ,pp->getPoint()[0]
00437                                                    ,pp->getPoint()[1]
00438                                                    ,pp->getPoint()[2]);
00439 
00440                         getMainWindow()->showMessage(QString::fromAscii(buf),3000);
00441                     }
00442                 }
00443 
00444                 action->setHandled(); 
00445             } // picked point
00446         } // mouse release
00447     }
00448 
00449     inherited::handleEvent(action);
00450 #else
00451     // If we don't need to pick for locate highlighting,
00452     // then just behave as separator and return.
00453     // NOTE: we still have to pick for ON even though we don't have
00454     // to re-render, because the app needs to be notified as the mouse
00455     // goes over locate highlight nodes.
00456     //if (highlightMode.getValue() == OFF) {
00457     //    inherited::handleEvent( action );
00458     //    return;
00459     //}
00460 
00461     
00462     //
00463     // If this is a mouseMotion event, then check for locate highlighting
00464     //
00465     if (event->isOfType(SoLocation2Event::getClassTypeId())) {
00466         // check to see if the mouse is over our geometry...
00467         SbBool underTheMouse = FALSE;
00468         const SoPickedPoint * pp = this->getPickedPoint(action);
00469         SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL;
00470         if (pPath && pPath->containsPath(action->getCurPath())) {
00471             // Make sure I'm the lowest LocHL in the pick path!
00472             underTheMouse = TRUE;
00473             for (int i = 0; i < pPath->getLength(); i++) {
00474                 SoNode *node = pPath->getNodeFromTail(i);
00475                 if (node->isOfType(SoFCSelection::getClassTypeId())) {
00476                     if (node != this)
00477                     underTheMouse = FALSE;
00478                     break; // found the lowest LocHL - look no further
00479                 }
00480             }
00481         }
00482         // Am I currently highlighted?
00483         if (isHighlighted(action)) {
00484             if (! underTheMouse) {
00485                 // re-draw the object with it's normal color
00486                 //if(mymode != OFF)
00487                 redrawHighlighted(action, FALSE);
00488                 Gui::Selection().rmvPreselect();
00489             }
00490             else {
00491                 action->setHandled();
00492                 //const SoPickedPoint * pp = action->getPickedPoint();
00493                 Gui::Selection().setPreselectCoord(pp->getPoint()[0]
00494                                                  ,pp->getPoint()[1]
00495                                                  ,pp->getPoint()[2]);
00496             }
00497         }
00498         // Else I am not currently highlighted
00499         else {
00500             // If under the mouse, then highlight!
00501             if (underTheMouse) {
00502                 // draw this object highlighted
00503                 if (mymode != OFF)
00504                     redrawHighlighted(action, TRUE);
00505                 //const SoPickedPoint * pp = action->getPickedPoint();
00506                 Gui::Selection().setPreselect(documentName.getValue().getString()
00507                                                  ,objectName.getValue().getString()
00508                                                  ,subElementName.getValue().getString()
00509                                                  ,pp->getPoint()[0]
00510                                                  ,pp->getPoint()[1]
00511                                                  ,pp->getPoint()[2]);
00512             }
00513         }
00514         //if(selected == SELECTED){
00515         //    redrawHighlighted(action, TRUE);
00516         //}
00517         //if(selectionCleared ){
00518         //    redrawHighlighted(action, FALSE);
00519         //    selectionCleared = false;
00520         //}
00521     }
00522     // key press events
00523     else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) {
00524         SoKeyboardEvent  * const e = (SoKeyboardEvent  *) event;
00525         if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT)     ||
00526             SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT)     )
00527             bShift = true;
00528         if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT)   ||
00529             SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT)   )
00530             bShift = false;
00531         if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL)   ||
00532             SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL)   )
00533             bCtrl = true;
00534         if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
00535             SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
00536             bCtrl = false;
00537     }
00538     // mouse press events for (de)selection (only if selection is enabled on this node)
00539     else if (event->isOfType(SoMouseButtonEvent::getClassTypeId()) && 
00540              selectionMode.getValue() == SoFCSelection::SEL_ON) {
00541         SoMouseButtonEvent * const e = (SoMouseButtonEvent *) event;
00542         if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
00543             //FIXME: Shouldn't we remove the preselection for newly selected objects?
00544             //       Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
00545             const SoPickedPoint * pp = this->getPickedPoint(action);
00546             if (pp && pp->getPath()->containsPath(action->getCurPath())) {
00547                 if (bCtrl) {
00548                     if (Gui::Selection().isSelected(documentName.getValue().getString()
00549                                          ,objectName.getValue().getString()
00550                                          ,subElementName.getValue().getString())) {
00551                         Gui::Selection().rmvSelection(documentName.getValue().getString()
00552                                           ,objectName.getValue().getString()
00553                                           ,subElementName.getValue().getString());
00554                     }
00555                     else {
00556                         Gui::Selection().addSelection(documentName.getValue().getString()
00557                                           ,objectName.getValue().getString()
00558                                           ,subElementName.getValue().getString()
00559                                           ,pp->getPoint()[0]
00560                                           ,pp->getPoint()[1]
00561                                           ,pp->getPoint()[2]);
00562 
00563                         if (mymode == OFF) {
00564                             snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
00565                                                        ,objectName.getValue().getString()
00566                                                        ,subElementName.getValue().getString()
00567                                                        ,pp->getPoint()[0]
00568                                                        ,pp->getPoint()[1]
00569                                                        ,pp->getPoint()[2]);
00570 
00571                             getMainWindow()->statusBar()->showMessage(QString::fromAscii(buf),3000);
00572                         }
00573                     }
00574                 }
00575                 else { // Ctrl
00576                     if (!Gui::Selection().isSelected(documentName.getValue().getString()
00577                                          ,objectName.getValue().getString()
00578                                          ,subElementName.getValue().getString())) {
00579                         Gui::Selection().clearSelection(documentName.getValue().getString());
00580                         Gui::Selection().addSelection(documentName.getValue().getString()
00581                                               ,objectName.getValue().getString()
00582                                               ,subElementName.getValue().getString()
00583                                               ,pp->getPoint()[0]
00584                                               ,pp->getPoint()[1]
00585                                               ,pp->getPoint()[2]);
00586                     }
00587                     else {
00588                         Gui::Selection().clearSelection(documentName.getValue().getString());
00589                         Gui::Selection().addSelection(documentName.getValue().getString()
00590                                               ,objectName.getValue().getString()
00591                                               ,0
00592                                               ,pp->getPoint()[0]
00593                                               ,pp->getPoint()[1]
00594                                               ,pp->getPoint()[2]);
00595                     }
00596  
00597                     if (mymode == OFF) {
00598                         snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
00599                                                    ,objectName.getValue().getString()
00600                                                    ,subElementName.getValue().getString()
00601                                                    ,pp->getPoint()[0]
00602                                                    ,pp->getPoint()[1]
00603                                                    ,pp->getPoint()[2]);
00604 
00605                         getMainWindow()->statusBar()->showMessage(QString::fromAscii(buf),3000);
00606                     }
00607                 }
00608 
00609                 action->setHandled(); 
00610             } // picked point
00611         } // mouse release
00612     }
00613 
00614     // Let the base class traverse the children.
00615     if (action->getGrabber() != this)
00616         inherited::handleEvent(action);
00617 #endif
00618 }
00619 
00620 // doc from parent
00621 void
00622 SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
00623 {
00624 #ifdef NO_FRONTBUFFER
00625     // check if preselection is active
00626     HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
00627     bool preselected = highlighted && mymode == AUTO;
00628     SoState * state = action->getState();
00629     state->push();
00630     if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
00631         this->setOverride(action);
00632     }
00633     inherited::GLRenderBelowPath(action);
00634     state->pop();
00635 #else
00636     // Set up state for locate highlighting (if necessary)
00637     GLint oldDepthFunc;
00638     SbBool drawHighlighted = preRender(action, oldDepthFunc);
00639 
00640     // now invoke the parent method
00641     inherited::GLRenderBelowPath(action);
00642 
00643     // Restore old depth buffer model if needed
00644     if (drawHighlighted || highlighted)
00645         glDepthFunc((GLenum)oldDepthFunc);
00646 
00647     // Clean up state if needed
00648     if (drawHighlighted)
00649         action->getState()->pop();
00650 #endif
00651 }
00652 
00653 void SoFCSelection::GLRender(SoGLRenderAction * action)
00654 {
00655     inherited::GLRender(action);
00656 }
00657 
00658 // doc from parent
00659 void
00660 SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
00661 {
00662 #ifdef NO_FRONTBUFFER
00663     // check if preselection is active
00664     HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
00665     bool preselected = highlighted && mymode == AUTO;
00666     SoState * state = action->getState();
00667     state->push();
00668     if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
00669         this->setOverride(action);
00670     }
00671     inherited::GLRenderInPath(action);
00672     state->pop();
00673 #else
00674     // Set up state for locate highlighting (if necessary)
00675     GLint oldDepthFunc;
00676     SbBool drawHighlighted = preRender(action, oldDepthFunc);
00677 
00678     // now invoke the parent method
00679     inherited::GLRenderInPath(action);
00680 
00681     // Restore old depth buffer model if needed
00682     if (drawHighlighted || highlighted)
00683         glDepthFunc((GLenum)oldDepthFunc);
00684 
00685     // Clean up state if needed
00686     if (drawHighlighted)
00687         action->getState()->pop();
00688 #endif
00689 }
00690 
00691 SbBool
00692 SoFCSelection::preRender(SoGLRenderAction *action, GLint &oldDepthFunc)
00693 //
00695 {
00696     // If not performing locate highlighting, just return.
00697     if (highlightMode.getValue() == OFF)
00698         return FALSE;
00699 
00700     SoState *state = action->getState();
00701 
00702     // ??? prevent caching at this level - for some reason the
00703     // ??? SoWindowElement::copyMatchInfo() method get called, which should
00704     // ??? never be called. We are not caching this node correctly yet....
00705     //SoCacheElement::invalidate(state);
00706 
00707     SbBool drawHighlighted = (highlightMode.getValue() == ON || isHighlighted(action) || selected.getValue() == SELECTED);
00708 
00709     if (drawHighlighted) {
00710         // prevent diffuse & emissive color from leaking out...
00711         state->push();
00712         SbColor col;
00713         if (selected.getValue() == SELECTED)
00714             col = colorSelection.getValue();
00715         else
00716             col = colorHighlight.getValue();
00717 
00718         // Emissive Color
00719         SoLazyElement::setEmissive(state, &col);
00720         SoOverrideElement::setEmissiveColorOverride(state, this, TRUE);
00721 
00722         // Diffuse Color
00723         if (style.getValue() == EMISSIVE_DIFFUSE) {
00724             SoLazyElement::setDiffuse(state, this, 1, &col, &colorpacker);
00725             SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);
00726         }
00727     }
00728 
00729     // Draw on top of other things at same z-buffer depth if:
00730     // [a] we're highlighted
00731     // [b] this is the highlighting pass. This occurs when changing from
00732     //     non-hilit to lit OR VICE VERSA.
00733     // Otherwise, leave it alone...
00734     if (drawHighlighted || highlighted) {
00735         glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunc);
00736         if (oldDepthFunc != GL_LEQUAL)
00737             glDepthFunc(GL_LEQUAL);
00738     }
00739 
00740     return drawHighlighted;
00741 }
00742 
00747 void
00748 SoFCSelection::redrawHighlighted(SoAction *  action , SbBool  doHighlight )
00749 {
00750     //Base::Console().Log("SoFCSelection::redrawHighlighted() (%p) doHigh=%d \n",this,doHighlight?1:0);
00751 
00752 #ifdef NO_FRONTBUFFER
00753 #else
00754     // If we are about to highlight, and there is something else highlighted,
00755     // that something else needs to unhighlight.
00756     if (doHighlight && currenthighlight != NULL &&
00757         !(*((SoFullPath *)action->getCurPath()) == *currenthighlight)) {
00758 
00759         SoNode *tail = currenthighlight->getTail();
00760         if (tail->isOfType( SoFCSelection::getClassTypeId()))
00761             ((SoFCSelection *)tail)->redrawHighlighted(action, FALSE);
00762         else {
00763             // Just get rid of the path. It's no longer valid for redraw.
00764             currenthighlight->unref();
00765             currenthighlight = NULL;
00766         }
00767     }
00768 
00769     SoPath *pathToRender;
00770     // save the path to ourself for later de-highlight
00771     if (doHighlight) {
00772         if (currenthighlight != NULL)
00773             currenthighlight->unref();
00774         currenthighlight = (SoFullPath *) action->getCurPath()->copy();
00775         currenthighlight->ref();
00776 
00777         // We will be rendering this new path to highlight it
00778         pathToRender = currenthighlight;
00779         pathToRender->ref();
00780     }
00781     // delete our path if we are no longer highlighted
00782     else {
00783         if (currenthighlight) {
00784             // We will be rendering this old path to unhighlight it
00785             pathToRender = currenthighlight;
00786             pathToRender->ref();
00787 
00788             currenthighlight->unref();
00789             currenthighlight = NULL;
00790         }
00791     }
00792 
00793     // If highlighting is forced on for this node, we don't need this special render.
00794     if (highlightMode.getValue() != AUTO) {
00795         pathToRender->unref();
00796         return;
00797     }
00798 
00799     SoState *state = action->getState();
00800 
00801     //void* window;
00802     //void* context;
00803     //void *display;
00804     QGLWidget* window;
00805     SoGLRenderAction *glAction;
00806     //SoWindowElement::get(state, window, context, display, glAction);
00807     SoGLWidgetElement::get(state, window);
00808     SoGLRenderActionElement::get(state, glAction);
00809 
00810     // If we don't have a current window, then simply return...
00811     if (window == 0 /*|| context == NULL || display == NULL*/ || glAction == NULL)
00812         return;
00813 
00814     window->makeCurrent();
00815 #ifndef WIN32
00816     // set the current window
00817     //glXMakeCurrent(display, window, context);
00818 #endif
00819     // render into the front buffer (save the current buffering type)
00820     GLint whichBuffer;
00821     glGetIntegerv(GL_DRAW_BUFFER, &whichBuffer);
00822     if (whichBuffer != GL_FRONT)
00823         glDrawBuffer(GL_FRONT);
00824 
00825     highlighted = TRUE;
00826     glAction->apply(pathToRender);
00827     highlighted = FALSE;
00828 
00829     // restore the buffering type
00830     if (whichBuffer != GL_FRONT)
00831         glDrawBuffer((GLenum)whichBuffer);
00832     glFlush();
00833 
00834     pathToRender->unref();
00835 #endif
00836 }
00837 
00838 SbBool 
00839 SoFCSelection::readInstance  (  SoInput *  in, unsigned short  flags )
00840 {
00841     // Note: The read in document name can be false, so the caller must ensure pointing to the correct documemt
00842     SbBool ret = inherited::readInstance(in, flags);
00843     return ret;
00844 }
00845 //
00846 // update override state before rendering
00847 //
00848 void
00849 SoFCSelection::setOverride(SoGLRenderAction * action)
00850 {
00851     //Base::Console().Log("SoFCSelection::setOverride() (%p)\n",this);
00852     SoState * state = action->getState();
00853     if(this->selected.getValue() == SELECTED)
00854         SoLazyElement::setEmissive(state, &this->colorSelection.getValue());
00855     else
00856         SoLazyElement::setEmissive(state, &this->colorHighlight.getValue());
00857     SoOverrideElement::setEmissiveColorOverride(state, this, TRUE);
00858 
00859     Styles mystyle = (Styles) this->style.getValue();
00860     if (mystyle == SoFCSelection::EMISSIVE_DIFFUSE) {
00861         if(this->selected.getValue() == SELECTED)
00862             SoLazyElement::setDiffuse(state, this,1, &this->colorSelection.getValue(),&colorpacker);
00863         else
00864             SoLazyElement::setDiffuse(state, this,1, &this->colorHighlight.getValue(),&colorpacker);
00865         SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);
00866     }
00867 }
00868 
00869 // private convenience method
00870 void
00871 SoFCSelection::turnoffcurrent(SoAction * action)
00872 {
00873 #ifdef NO_FRONTBUFFER
00874     if (SoFCSelection::currenthighlight &&
00875         SoFCSelection::currenthighlight->getLength()) {
00876         SoNode * tail = SoFCSelection::currenthighlight->getTail();
00877         if (tail->isOfType(SoFCSelection::getClassTypeId())) {
00878             ((SoFCSelection*)tail)->highlighted = FALSE;
00879             ((SoFCSelection*)tail)->touch(); // force scene redraw
00880             if (action) ((SoFCSelection*)tail)->redrawHighlighted(action, FALSE);
00881         }
00882     }
00883     if (SoFCSelection::currenthighlight) {
00884         SoFCSelection::currenthighlight->unref();
00885         SoFCSelection::currenthighlight = NULL;
00886     }
00887 #else
00888     if (currenthighlight == NULL)
00889         return;
00890 
00891     SoNode *tail = currenthighlight->getTail();
00892     if (tail->isOfType(SoFCSelection::getClassTypeId())) {
00893 
00894         // don't redraw if we already are in the middle of rendering
00895         // (processing events during render abort might cause this)
00896         SoState *state = action->getState();
00897         if (state && state->getDepth() == 1)
00898             ((SoFCSelection *)tail)->redrawHighlighted(action, FALSE);
00899     }
00900     else {
00901         // Just get rid of the path. It's no longer valid for redraw.
00902         currenthighlight->unref();
00903         currenthighlight = NULL;
00904     }
00905 #endif
00906 }
00907 
00908 SbBool
00909 SoFCSelection::isHighlighted(SoAction *action)
00910 //
00912 {
00913     SoFullPath *actionPath = (SoFullPath *) action->getCurPath();
00914     return (currenthighlight != NULL &&
00915         currenthighlight->getTail() == actionPath->getTail() && // nested SoHL!
00916         *currenthighlight == *actionPath);
00917 }
00918 
00919 //#undef THIS

Generated on Wed Nov 23 19:00:40 2011 for FreeCAD by  doxygen 1.6.1