diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index b7c2f9d10c..4333cacebb 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -61,6 +61,7 @@ #include "SoFCBoundingBox.h" #include "SoFCUnifiedSelection.h" #include "SoAxisCrossKit.h" +#include "SoQTQuarterAdaptor.h" #include "View3DInventor.h" #include "View3DInventorViewer.h" #include "ViewParams.h" @@ -2545,10 +2546,137 @@ bool StdViewZoomOut::isActive(void) { return (qobject_cast(getMainWindow()->activeWindow())); } +class SelectionCallbackHandler { +private: + static std::unique_ptr currentSelectionHandler; + QCursor* prevSelectionCursor; + typedef void (*FnCb)(void * userdata, SoEventCallback * node); + FnCb fnCb; + void* userData; + bool prevSelectionEn; + +public: + // Creates a selection handler used to implement the common behaviour of BoxZoom, BoxSelection and BoxElementSelection. + // Takes the viewer, a selection mode, a cursor, a function pointer to be called on success and a void pointer for user data to be passed to the given function. + // The selection handler class stores all necessary previous states, registers a event callback and starts the selection in the given mode. + // If there is still a selection handler active, this call will generate a message and returns. + static void Create(View3DInventorViewer* viewer, View3DInventorViewer::SelectionMode selectionMode, const QCursor& cursor, FnCb doFunction= NULL, void* ud=NULL) + { + if (currentSelectionHandler) + { + Base::Console().Message("SelectionCallbackHandler: A selection handler already active."); + return; + } + + currentSelectionHandler = std::unique_ptr(new SelectionCallbackHandler()); + if (viewer) + { + currentSelectionHandler->userData = ud; + currentSelectionHandler->fnCb = doFunction; + currentSelectionHandler->prevSelectionCursor = new QCursor(viewer->cursor()); + viewer->setEditingCursor(cursor); + viewer->addEventCallback(SoEvent::getClassTypeId(), + SelectionCallbackHandler::selectionCallback, currentSelectionHandler.get()); + currentSelectionHandler->prevSelectionEn = viewer->isSelectionEnabled(); + viewer->setSelectionEnabled(false); + viewer->startSelection(selectionMode); + } + }; + + void* getUserData() { return userData; }; + + // Implements the event handler. In the normal case the provided function is called. + // Also supports aborting the selection mode by pressing (releasing) the Escape key. + static void selectionCallback(void * ud, SoEventCallback * n) + { + SelectionCallbackHandler* selectionHandler = reinterpret_cast(ud); + Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData()); + const SoEvent* ev = n->getEvent(); + if (ev->isOfType(SoKeyboardEvent::getClassTypeId())) { + + n->setHandled(); + n->getAction()->setHandled(); + + const SoKeyboardEvent * ke = static_cast(ev); + const SbBool press = ke->getState() == SoButtonEvent::DOWN ? true : false; + if (ke->getKey() == SoKeyboardEvent::ESCAPE) { + + if (!press) { + view->abortSelection(); + restoreState(selectionHandler, view); + } + } + } + else if (ev->isOfType(SoMouseButtonEvent::getClassTypeId())) { + const SoMouseButtonEvent * mbe = static_cast(ev); + + // Mark all incoming mouse button events as handled, especially, to deactivate the selection node + n->getAction()->setHandled(); + + if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::UP) + { + if (selectionHandler && selectionHandler->fnCb) selectionHandler->fnCb(selectionHandler->getUserData(), n); + restoreState(selectionHandler, view); + } + // No other mouse events available from Coin3D to implement right mouse up abort + } + } + + static void restoreState(SelectionCallbackHandler * selectionHandler, View3DInventorViewer* view) + { + if(selectionHandler) selectionHandler->fnCb = NULL; + view->setEditingCursor(*selectionHandler->prevSelectionCursor); + view->removeEventCallback(SoEvent::getClassTypeId(), SelectionCallbackHandler::selectionCallback, selectionHandler); + view->setSelectionEnabled(selectionHandler->prevSelectionEn); + Application::Instance->commandManager().testActive(); + currentSelectionHandler = NULL; + } +}; + +std::unique_ptr SelectionCallbackHandler::currentSelectionHandler = std::unique_ptr(); //=========================================================================== // Std_ViewBoxZoom //=========================================================================== +/* XPM */ +static const char * cursor_box_zoom[] = { +"32 32 3 1", +" c None", +". c #FFFFFF", +"@ c #FF0000", +" . ", +" . ", +" . ", +" . ", +" . ", +" ", +"..... ..... ", +" ", +" . @@@@@@@ ", +" . @@@@@@@@@@@ ", +" . @@ @@ ", +" . @@. . . . . .@@ ", +" . @ @ ", +" @@ . . @@ ", +" @@ @@ ", +" @@ . . @@ ", +" @@ @@ ", +" @@ . . @@ ", +" @@ @@ ", +" @@ . . @@ ", +" @ @ ", +" @@. . . . . .@@@ ", +" @@ @@@@ ", +" @@@@@@@@@@@@ @@ ", +" @@@@@@@ @@ @@ ", +" @@ @@ ", +" @@ @@ ", +" @@ @@ ", +" @@ @@ ", +" @@@@ ", +" @@ ", +" " }; + DEF_3DV_CMD(StdViewBoxZoom) StdViewBoxZoom::StdViewBoxZoom() @@ -2570,8 +2698,9 @@ void StdViewBoxZoom::activated(int iMsg) View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if ( view ) { View3DInventorViewer* viewer = view->getViewer(); - if (!viewer->isSelecting()) - viewer->startSelection(View3DInventorViewer::BoxZoom); + if (!viewer->isSelecting()) { + SelectionCallbackHandler::Create(viewer, View3DInventorViewer::BoxZoom, QCursor(QPixmap(cursor_box_zoom), 7, 7)); + } } } @@ -2580,6 +2709,46 @@ void StdViewBoxZoom::activated(int iMsg) //=========================================================================== DEF_3DV_CMD(StdBoxSelection) +/* XPM */ +static const char * cursor_box_select[] = { +"32 32 4 1", +" c None", +". c #FFFFFF", +"+ c #FF0000", +"@ c #000000", +" . ", +" . ", +" . ", +" . ", +" . ", +" ", +"..... ..... ", +" ", +" . ", +" . ", +" . + +++ +++ +++ ", +" . +@@ ", +" . +@.@@@ ", +" @...@@@ ", +" @......@@ ", +" @........@@@ + ", +" @..........@@ + ", +" + @............@ + ", +" + @........@@@ ", +" + @.......@ ", +" @........@ ", +" @........@ + ", +" @...@.....@ + ", +" + @..@ @.....@ + ", +" + @.@ @.....@ ", +" + @.@ @.....@ ", +" @ @.....@ ", +" @...@ ", +" @.@ + ", +" @ + ", +" +++ +++ +++ + ", +" " }; + StdBoxSelection::StdBoxSelection() : Command("Std_BoxSelection") { @@ -2718,18 +2887,18 @@ static std::vector getBoxSelection( return ret; } -static void selectionCallback(void * ud, SoEventCallback * cb) +static void doSelect(void* ud, SoEventCallback * cb) { - bool selectElement = ud?true:false; - Gui::View3DInventorViewer* view = reinterpret_cast(cb->getUserData()); - view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud); - SoNode* root = view->getSceneGraph(); + bool selectElement = ud ? true : false; + Gui::View3DInventorViewer* viewer = reinterpret_cast(cb->getUserData()); + + SoNode* root = viewer->getSceneGraph(); static_cast(root)->selectionRole.setValue(true); SelectionMode selectionMode = CENTER; - std::vector picked = view->getGLPolygon(); - SoCamera* cam = view->getSoRenderManager()->getCamera(); + std::vector picked = viewer->getGLPolygon(); + SoCamera* cam = viewer->getSoRenderManager()->getCamera(); SbViewVolume vv = cam->getViewVolume(); Gui::ViewVolumeProjection proj(vv); Base::Polygon2d polygon; @@ -2789,8 +2958,7 @@ void StdBoxSelection::activated(int iMsg) SoKeyboardEvent ev; viewer->navigationStyle()->processEvent(&ev); } - viewer->startSelection(View3DInventorViewer::Rubberband); - viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback); + SelectionCallbackHandler::Create(viewer, View3DInventorViewer::Rubberband, QCursor(QPixmap(cursor_box_select), 7, 7), doSelect, NULL); SoNode* root = viewer->getSceneGraph(); static_cast(root)->selectionRole.setValue(false); } @@ -2800,6 +2968,48 @@ void StdBoxSelection::activated(int iMsg) //=========================================================================== // Std_BoxElementSelection //=========================================================================== +/* XPM */ +static char * cursor_box_element_select[] = { +"32 32 6 1", +" c None", +". c #FFFFFF", +"+ c #00FF1B", +"@ c #19A428", +"# c #FF0000", +"$ c #000000", +" . ", +" . ", +" . ", +" . ", +" . ", +" ", +"..... ..... ", +" ++++++++++++ ", +" .+@@@@@@@@@@+ ", +" .+@@@@@@@@@@+ ", +" .+@@#@@@@###+ ### ### ", +" .+@@#$$@@@@@+ ", +" .+@@#$.$$$@@+ ", +" +@@@@$...$$$ ", +" +@@@@$......$$ ", +" +@@@@$........$$$ # ", +" +@@@@@$..........$$ # ", +" +@@#@@$............$ # ", +" +++#+++$........$$$ ", +" # $.......$ ", +" $........$ ", +" $........$ # ", +" $...$.....$ # ", +" # $..$ $.....$ # ", +" # $.$ $.....$ ", +" # $.$ $.....$ ", +" $ $.....$ ", +" $...$ ", +" $.$ # ", +" $ # ", +" ### ### ### # ", +" " }; + DEF_3DV_CMD(StdBoxElementSelection) StdBoxElementSelection::StdBoxElementSelection() @@ -2829,8 +3039,7 @@ void StdBoxElementSelection::activated(int iMsg) SoKeyboardEvent ev; viewer->navigationStyle()->processEvent(&ev); } - viewer->startSelection(View3DInventorViewer::Rubberband); - viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, this); + SelectionCallbackHandler::Create(viewer, View3DInventorViewer::Rubberband, QCursor(QPixmap(cursor_box_element_select), 7, 7), doSelect, this); SoNode* root = viewer->getSceneGraph(); static_cast(root)->selectionRole.setValue(false); } diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp index 4ce967eada..0551d15951 100644 --- a/src/Gui/MouseSelection.cpp +++ b/src/Gui/MouseSelection.cpp @@ -63,11 +63,11 @@ void AbstractMouseSelection::grabMouseModel(Gui::View3DInventorViewer* viewer) initialize(); } -void AbstractMouseSelection::releaseMouseModel() +void AbstractMouseSelection::releaseMouseModel(bool abort) { if (_pcView3D) { // do termination of your mousemodel - terminate(); + terminate(abort); _pcView3D->getWidget()->setCursor(m_cPrevCursor); _pcView3D = 0; @@ -278,7 +278,7 @@ void PolyPickerSelection::initialize() lastConfirmed = false; } -void PolyPickerSelection::terminate() +void PolyPickerSelection::terminate(bool abort) { _pcView3D->removeGraphicsItem(&polyline); _pcView3D->setRenderType(View3DInventorViewer::Native); @@ -671,7 +671,7 @@ void RubberbandSelection::initialize() _pcView3D->redraw(); } -void RubberbandSelection::terminate() +void RubberbandSelection::terminate(bool abort) { _pcView3D->removeGraphicsItem(&rubberband); if (QtGLFramebufferObject::hasOpenGLFramebufferObjects()) { @@ -763,14 +763,15 @@ BoxZoomSelection::~BoxZoomSelection() { } -void BoxZoomSelection::terminate() +void BoxZoomSelection::terminate(bool abort) { - RubberbandSelection::terminate(); - - int xmin = std::min(m_iXold, m_iXnew); - int xmax = std::max(m_iXold, m_iXnew); - int ymin = std::min(m_iYold, m_iYnew); - int ymax = std::max(m_iYold, m_iYnew); - SbBox2s box(xmin, ymin, xmax, ymax); - _pcView3D->boxZoom(box); + RubberbandSelection::terminate(abort); + if (!abort) { + int xmin = std::min(m_iXold, m_iXnew); + int xmax = std::max(m_iXold, m_iXnew); + int ymin = std::min(m_iYold, m_iYnew); + int ymax = std::max(m_iYold, m_iYnew); + SbBox2s box(xmin, ymin, xmax, ymax); + _pcView3D->boxZoom(box); + } } diff --git a/src/Gui/MouseSelection.h b/src/Gui/MouseSelection.h index 667a8be901..b54bc87fa8 100644 --- a/src/Gui/MouseSelection.h +++ b/src/Gui/MouseSelection.h @@ -64,9 +64,9 @@ public: /// implement this in derived classes virtual void initialize() = 0; /// implement this in derived classes - virtual void terminate() = 0; + virtual void terminate(bool abort = false) = 0; void grabMouseModel(Gui::View3DInventorViewer*); - void releaseMouseModel(void); + void releaseMouseModel(bool abort = false); const std::vector& getPositions() const { return _clPoly; } @@ -134,7 +134,7 @@ public: void setColor(float r, float g, float b, float a = 1.0); virtual void initialize(); - virtual void terminate(); + virtual void terminate(bool abort = false); protected: virtual int mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos); @@ -213,7 +213,7 @@ public: void setColor(float r, float g, float b, float a = 1.0); virtual void initialize(); - virtual void terminate(); + virtual void terminate(bool abort = false); protected: virtual int mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos); @@ -253,7 +253,7 @@ class GuiExport BoxZoomSelection : public RubberbandSelection public: BoxZoomSelection(); ~BoxZoomSelection(); - void terminate(); + void terminate(bool abort = false); }; } // namespace Gui diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 61f15f02a7..43a4a73045 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -1305,6 +1305,16 @@ void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode) mouseSelection->grabMouseModel(viewer); } +void NavigationStyle::abortSelection() +{ + pcPolygon.clear(); + if (mouseSelection) { + mouseSelection->releaseMouseModel(true); + delete mouseSelection; + mouseSelection = 0; + } +} + void NavigationStyle::stopSelection() { pcPolygon.clear(); diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index 2c163c708d..2903ac0caa 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -157,6 +157,7 @@ public: void startSelection(AbstractMouseSelection*); void startSelection(SelectionMode = Lasso); + void abortSelection(); void stopSelection(); SbBool isSelecting() const; const std::vector& getPolygon(SelectionRole* role=0) const; diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index a39e61fbad..bedc3c6d22 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -1736,8 +1736,15 @@ void View3DInventorViewer::startSelection(View3DInventorViewer::SelectionMode mo navigation->startSelection(NavigationStyle::SelectionMode(mode)); } +void View3DInventorViewer::abortSelection() +{ + setCursorEnabled(true); + navigation->abortSelection(); +} + void View3DInventorViewer::stopSelection() { + setCursorEnabled(true); navigation->stopSelection(); } diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index 8591f648b0..b34e402a4a 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -236,6 +236,7 @@ public: /** @name Selection methods */ //@{ void startSelection(SelectionMode = Lasso); + void abortSelection(); void stopSelection(); bool isSelecting() const; std::vector getGLPolygon(SelectionRole* role=0) const; diff --git a/src/Gui/ViewProvider.cpp b/src/Gui/ViewProvider.cpp index 561711ce3e..074b74562a 100644 --- a/src/Gui/ViewProvider.cpp +++ b/src/Gui/ViewProvider.cpp @@ -224,12 +224,25 @@ void ViewProvider::eventCallback(void * ud, SoEventCallback * node) // holding the mouse button while using some SoDragger. // Therefore, we shall ignore ESC while any mouse button is // pressed, until this Coin bug is fixed. - - Gui::TimerFunction* func = new Gui::TimerFunction(); - func->setAutoDelete(true); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - func->setFunction(boost::bind(&Document::resetEdit, doc)); - QTimer::singleShot(0, func, SLOT(timeout())); + if (!press) { + // react only on key release + // Let first selection mode terminate + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + Gui::View3DInventor* view = static_cast(doc->getActiveView()); + if (view) + { + Gui::View3DInventorViewer* viewer = view->getViewer(); + if (viewer->isSelecting()) + { + return; + } + } + + Gui::TimerFunction* func = new Gui::TimerFunction(); + func->setAutoDelete(true); + func->setFunction(boost::bind(&Document::resetEdit, doc)); + QTimer::singleShot(0, func, SLOT(timeout())); + } } else if (press) { FC_WARN("Please release all mouse buttons before exiting editing"); diff --git a/src/Gui/ViewProviderMeasureDistance.cpp b/src/Gui/ViewProviderMeasureDistance.cpp index 17ecf1e554..10d651e102 100644 --- a/src/Gui/ViewProviderMeasureDistance.cpp +++ b/src/Gui/ViewProviderMeasureDistance.cpp @@ -53,6 +53,7 @@ #include #include #include +#include using namespace Gui; @@ -242,11 +243,14 @@ PointMarker::PointMarker(View3DInventorViewer* iv) : view(iv), vp(new ViewProviderPointMarker) { view->addViewProvider(vp); + previousSelectionEn = view->isSelectionEnabled(); + view->setSelectionEnabled(false); } PointMarker::~PointMarker() { view->removeViewProvider(vp); + view->setSelectionEnabled(previousSelectionEn); delete vp; } @@ -318,11 +322,10 @@ void ViewProviderMeasureDistance::measureDistanceCallback(void * ud, SoEventCall const SoKeyboardEvent * ke = static_cast(ev); const SbBool press = ke->getState() == SoButtonEvent::DOWN ? true : false; if (ke->getKey() == SoKeyboardEvent::ESCAPE) { + n->setHandled(); + // Handle it on key up, because otherwise upper layer will handle it too. if (!press) { - n->setHandled(); - view->setEditing(false); - view->removeEventCallback(SoEvent::getClassTypeId(), measureDistanceCallback, ud); - pm->deleteLater(); + endMeasureDistanceMode(ud, view, n, pm); } } } @@ -350,10 +353,16 @@ void ViewProviderMeasureDistance::measureDistanceCallback(void * ud, SoEventCall } } else if (mbe->getButton() != SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::UP) { - n->setHandled(); - view->setEditing(false); - view->removeEventCallback(SoEvent::getClassTypeId(), measureDistanceCallback, ud); - pm->deleteLater(); + endMeasureDistanceMode(ud, view, n, pm); } } } + +void ViewProviderMeasureDistance::endMeasureDistanceMode(void * ud, Gui::View3DInventorViewer* view, SoEventCallback * n, PointMarker *pm) +{ + n->setHandled(); + view->setEditing(false); + view->removeEventCallback(SoEvent::getClassTypeId(), ViewProviderMeasureDistance::measureDistanceCallback, ud); + Application::Instance->commandManager().testActive(); + pm->deleteLater(); +} diff --git a/src/Gui/ViewProviderMeasureDistance.h b/src/Gui/ViewProviderMeasureDistance.h index 92f0b23d0e..149246306e 100644 --- a/src/Gui/ViewProviderMeasureDistance.h +++ b/src/Gui/ViewProviderMeasureDistance.h @@ -56,6 +56,7 @@ protected: private: View3DInventorViewer *view; ViewProviderPointMarker *vp; + bool previousSelectionEn; }; class GuiExport ViewProviderPointMarker : public ViewProviderDocumentObject @@ -107,6 +108,8 @@ private: SoTranslation * pTranslation; SoCoordinate3 * pCoords; SoIndexedLineSet * pLines; + + static void endMeasureDistanceMode(void * ud, Gui::View3DInventorViewer* view, SoEventCallback * n, PointMarker *pm); }; } //namespace Gui