/**************************************************************************\ * * This file is part of the Coin 3D visualization library. * Copyright (C) 1998-2007 by Systems in Motion. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * ("GPL") version 2 as published by the Free Software Foundation. * See the file LICENSE.GPL at the root directory of this source * distribution for additional information about the GNU GPL. * * For using Coin with software that can not be combined with the GNU * GPL, and for taking advantage of the additional benefits of our * support services, please contact Systems in Motion about acquiring * a Coin Professional Edition License. * * See http://www.coin3d.org/ for more information. * * Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY. * http://www.sim.no/ sales@sim.no coin-support@coin3d.org * \**************************************************************************/ /*! \class SoLocateHighlight SoLocateHighlight.h Inventor/nodes/SoLocateHighlight.h \brief The SoLocateHighlight class highlights geometry under the cursor. \ingroup nodes Note: this node is supposed to draw to the front buffer. However, in Coin we always draw to the back buffer, forcing a scene redraw whenever a highlight state changes. FILE FORMAT/DEFAULTS: \code LocateHighlight { renderCaching AUTO boundingBoxCaching AUTO renderCulling AUTO pickCulling AUTO color 0.3 0.3 0.3 style EMISSIVE mode AUTO } \endcode */ // ************************************************************************* #include #include #include #include #include #include #include #include #include #include #include #include // ************************************************************************* /*! \enum SoLocateHighlight::Modes Enum type for behaviour modes. */ /*! \var SoLocateHighlight::Modes SoLocateHighlight::AUTO Highlight when mouse cursor is over the contents of the node. */ /*! \var SoLocateHighlight::Modes SoLocateHighlight::ON Always highlight. */ /*! \var SoLocateHighlight::Modes SoLocateHighlight::OFF Never highlight. */ /*! \enum SoLocateHighlight::Styles Enum type for highlight styles. */ /*! \var SoLocateHighlight::Styles SoLocateHighlight::EMISSIVE Highlight using emissive color override. */ /*! \var SoLocateHighlight::Styles SoLocateHighlight::EMISSIVE_DIFFUSE Highlight useing emissive and diffuse color override. */ /*! \var SoSFColor SoLocateHighlight::color The color used for highlighting. Default is [0.3, 0.3, 0.3], a dark gray. */ /*! \var SoSFEnum SoLocateHighlight::style The highlight style. Default is SoLocateHighlight::EMISSIVE. */ /*! \var SoSFEnum SoLocateHighlight::mode The highlight mode. Default is SoLocateHighlight::AUTO. */ // ************************************************************************* class SoLocateHighlightP { public: SbBool highlighted; SoColorPacker colorpacker; static SoFullPath * currenthighlight; static void atexit_cleanup(void) { if (SoLocateHighlightP::currenthighlight) { SoLocateHighlightP::currenthighlight->unref(); SoLocateHighlightP::currenthighlight = NULL; } } }; SoFullPath * SoLocateHighlightP::currenthighlight = NULL; // ************************************************************************* #undef PRIVATE #define PRIVATE(p) ((p)->pimpl) // ************************************************************************* SO_NODE_SOURCE(SoLocateHighlight); // ************************************************************************* /*! Constructor. */ SoLocateHighlight::SoLocateHighlight() { PRIVATE(this) = new SoLocateHighlightP; SO_NODE_INTERNAL_CONSTRUCTOR(SoLocateHighlight); SO_NODE_ADD_FIELD(color, (SbColor(0.3f, 0.3f, 0.3f))); SO_NODE_ADD_FIELD(style, (EMISSIVE)); SO_NODE_ADD_FIELD(mode, (AUTO)); SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE); SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE_DIFFUSE); SO_NODE_SET_SF_ENUM_TYPE(style, Styles); SO_NODE_DEFINE_ENUM_VALUE(Modes, AUTO); SO_NODE_DEFINE_ENUM_VALUE(Modes, ON); SO_NODE_DEFINE_ENUM_VALUE(Modes, OFF); SO_NODE_SET_SF_ENUM_TYPE(mode, Modes); PRIVATE(this)->highlighted = FALSE; } /*! Destructor. */ SoLocateHighlight::~SoLocateHighlight() { delete PRIVATE(this); } // doc from parent void SoLocateHighlight::initClass(void) { SO_NODE_INTERNAL_INIT_CLASS(SoLocateHighlight, SO_FROM_INVENTOR_1); coin_atexit((coin_atexit_f*)SoLocateHighlightP::atexit_cleanup, CC_ATEXIT_NORMAL); } /*! Static method that can be used to turn off the current highlight. */ void SoLocateHighlight::turnOffCurrentHighlight(SoGLRenderAction * action) { SoLocateHighlight::turnoffcurrent(action); } // doc from parent void SoLocateHighlight::handleEvent(SoHandleEventAction * action) { Modes mymode = (Modes) this->mode.getValue(); if (mymode == AUTO) { const SoEvent * event = action->getEvent(); if (event->isOfType(SoLocation2Event::getClassTypeId())) { const SoPickedPoint * pp = action->getPickedPoint(); if (pp && pp->getPath()->containsPath(action->getCurPath())) { if (!PRIVATE(this)->highlighted) { SoLocateHighlight::turnoffcurrent(action); SoLocateHighlightP::currenthighlight = (SoFullPath*) action->getCurPath()->copy(); SoLocateHighlightP::currenthighlight->ref(); PRIVATE(this)->highlighted = TRUE; this->touch(); // force scene redraw this->redrawHighlighted(action, TRUE); } } else { if (PRIVATE(this)->highlighted) { SoLocateHighlight::turnoffcurrent(action); } } } } inherited::handleEvent(action); } // doc from parent void SoLocateHighlight::GLRenderBelowPath(SoGLRenderAction * action) { SoState * state = action->getState(); state->push(); if (PRIVATE(this)->highlighted || this->mode.getValue() == ON) { this->setOverride(action); } inherited::GLRenderBelowPath(action); state->pop(); } // doc from parent void SoLocateHighlight::GLRenderInPath(SoGLRenderAction * action) { SoState * state = action->getState(); state->push(); if (PRIVATE(this)->highlighted || this->mode.getValue() == ON) { this->setOverride(action); } inherited::GLRenderInPath(action); state->pop(); } /*! Empty method in Coin. Can be used by subclasses to be told when status change. */ void SoLocateHighlight::redrawHighlighted(SoAction * /* act */, SbBool /* flag */) { } // // update override state before rendering // void SoLocateHighlight::setOverride(SoGLRenderAction * action) { SoState * state = action->getState(); SoLazyElement::setEmissive(state, &this->color.getValue()); SoOverrideElement::setEmissiveColorOverride(state, this, TRUE); Styles mystyle = (Styles) this->style.getValue(); if (mystyle == SoLocateHighlight::EMISSIVE_DIFFUSE) { SoLazyElement::setDiffuse(state, this, 1, &this->color.getValue(), &PRIVATE(this)->colorpacker); SoOverrideElement::setDiffuseColorOverride(state, this, TRUE); } } // private convenience method void SoLocateHighlight::turnoffcurrent(SoAction * action) { if (SoLocateHighlightP::currenthighlight && SoLocateHighlightP::currenthighlight->getLength()) { SoNode * tail = SoLocateHighlightP::currenthighlight->getTail(); if (tail->isOfType(SoLocateHighlight::getClassTypeId())) { ((SoLocateHighlight*)tail)->pimpl->highlighted = FALSE; ((SoLocateHighlight*)tail)->touch(); // force scene redraw if (action) ((SoLocateHighlight*)tail)->redrawHighlighted(action, FALSE); } } if (SoLocateHighlightP::currenthighlight) { SoLocateHighlightP::currenthighlight->unref(); SoLocateHighlightP::currenthighlight = NULL; } } #undef PRIVATE