| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <Inventor/SbViewportRegion.h> |
| | #include <Inventor/SoPickedPoint.h> |
| | #include <Inventor/actions/SoGetBoundingBoxAction.h> |
| | #include <Inventor/draggers/SoDragger.h> |
| | #include <Inventor/errors/SoDebugError.h> |
| | #include <Inventor/nodes/SoSeparator.h> |
| | #include <Inventor/nodes/SoCamera.h> |
| | #include <Inventor/nodes/SoOrthographicCamera.h> |
| | #include <Inventor/nodes/SoPerspectiveCamera.h> |
| | #include <Inventor/projectors/SbSphereSheetProjector.h> |
| | #include <QAction> |
| | #include <QActionGroup> |
| | #include <QApplication> |
| | #include <QByteArray> |
| | #include <QCursor> |
| | #include <QMenu> |
| |
|
| |
|
| | #include <cmath> |
| | #include <limits> |
| |
|
| | #include <Base/Interpreter.h> |
| | #include <App/Application.h> |
| |
|
| | #include "Navigation/NavigationStyle.h" |
| | #include "Navigation/NavigationStylePy.h" |
| | #include "Application.h" |
| | #include "Command.h" |
| | #include "Action.h" |
| | #include "Inventor/SoMouseWheelEvent.h" |
| | #include "MenuManager.h" |
| | #include "MouseSelection.h" |
| | #include "Navigation/NavigationAnimator.h" |
| | #include "Navigation/NavigationAnimation.h" |
| | #include "View3DInventorViewer.h" |
| |
|
| | using namespace Gui; |
| |
|
| | class FCSphereSheetProjector: public SbSphereSheetProjector |
| | { |
| | using inherited = SbSphereSheetProjector; |
| |
|
| | public: |
| | enum OrbitStyle |
| | { |
| | Turntable, |
| | Trackball, |
| | FreeTurntable, |
| | TrackballClassic, |
| | RoundedArcball |
| | }; |
| |
|
| | static constexpr float defaultSphereRadius = 0.8F; |
| |
|
| | FCSphereSheetProjector(const SbSphere& sph, const SbBool orienttoeye = true) |
| | : SbSphereSheetProjector(sph, orienttoeye) |
| | {} |
| |
|
| | void setViewVolume(const SbViewVolume& vol) override |
| | { |
| | inherited::setViewVolume(vol); |
| | } |
| |
|
| | void setWorkingSpace(const SbMatrix& space) override |
| | { |
| | |
| | this->worldToScreen = space.inverse(); |
| | } |
| |
|
| | SbVec3f project(const SbVec2f& point) override |
| | { |
| | if (orbit != RoundedArcball) { |
| | return inherited::project(point); |
| | } |
| |
|
| | |
| | |
| | SbVec3f result; |
| | SbLine workingLine = getWorkingLine(point); |
| |
|
| | if (needSetup) { |
| | setupPlane(); |
| | } |
| |
|
| | SbVec3f planeIntersection; |
| |
|
| | SbVec3f sphereIntersection, dontCare; |
| | SbBool hitSphere; |
| | if (intersectFront == TRUE) { |
| | hitSphere = sphere.intersect(workingLine, sphereIntersection, dontCare); |
| | } |
| | else { |
| | hitSphere = sphere.intersect(workingLine, dontCare, sphereIntersection); |
| | } |
| |
|
| | if (hitSphere) { |
| | |
| |
|
| | SbLine projectLine(sphereIntersection, sphereIntersection + planeDir); |
| | if (!tolPlane.intersect(projectLine, planeIntersection)) { |
| | #ifdef FC_DEBUG |
| | SoDebugError::post( |
| | "SbSphereSheetProjector::project", |
| | "Could not intersect working line with plane" |
| | ); |
| | #endif |
| | } |
| | } |
| | else if (!tolPlane.intersect(workingLine, planeIntersection)) { |
| | #ifdef FC_DEBUG |
| | SoDebugError::post("SbSphereSheetProjector::project", "Could not intersect with plane"); |
| | #endif |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | float distance = (planeIntersection - planePoint).length(); |
| |
|
| | |
| | |
| | |
| | float border = 0.5; |
| |
|
| | |
| | float r_a = 1.0F + border; |
| | |
| | float r_i = 2.0 / (r_a + 1.0 / r_a); |
| |
|
| | |
| | float d_2 = (distance * distance) * r_a * r_a; |
| | |
| | float d = std::sqrt(d_2); |
| |
|
| | |
| | float offsetDist = 0.0; |
| |
|
| | if (d > r_a) { |
| | |
| | offsetDist = 0.0; |
| | } |
| | else if (d < r_i) { |
| | |
| | offsetDist = std::sqrt(1.0 - d_2); |
| | } |
| | else { |
| | |
| | float d_r = r_a - d; |
| | float a = border * (1.0 + border / 2.0); |
| | offsetDist = a - std::sqrt((a + d_r) * (a - d_r)); |
| | } |
| |
|
| | SbVec3f offset; |
| | if (orientToEye) { |
| | if (viewVol.getProjectionType() == SbViewVolume::PERSPECTIVE) { |
| | offset = workingProjPoint - planeIntersection; |
| | } |
| | else { |
| | worldToWorking.multDirMatrix(viewVol.zVector(), offset); |
| | } |
| |
|
| | offset.normalize(); |
| | } |
| | else { |
| | offset.setValue(0, 0, 1); |
| | } |
| | if (intersectFront == FALSE) { |
| | offset *= -1.0; |
| | } |
| |
|
| | offset *= offsetDist; |
| | result = planeIntersection + offset; |
| |
|
| | lastPoint = result; |
| | return result; |
| | } |
| |
|
| | SbRotation getRotation(const SbVec3f& point1, const SbVec3f& point2) override |
| | { |
| | SbRotation rot = inherited::getRotation(point1, point2); |
| | if (orbit == Turntable || orbit == FreeTurntable) { |
| | return getTurntable(rot, point1, point2); |
| | } |
| | if (orbit == TrackballClassic) { |
| | return getTrackballClassic(point1, point2); |
| | } |
| |
|
| | return rot; |
| | } |
| |
|
| | void setOrbitStyle(OrbitStyle style) |
| | { |
| | this->orbit = style; |
| | } |
| |
|
| | OrbitStyle getOrbitStyle() const |
| | { |
| | return this->orbit; |
| | } |
| |
|
| | private: |
| | SbRotation getTurntable(SbRotation rot, const SbVec3f& point1, const SbVec3f& point2) const |
| | { |
| | |
| | SbVec3f axis; |
| | float angle {}; |
| | rot.getValue(axis, angle); |
| | SbVec3f dif = point1 - point2; |
| | if (fabs(dif[1]) > fabs(dif[0])) { |
| | SbVec3f xaxis(1, 0, 0); |
| | if (dif[1] < 0) { |
| | angle = -angle; |
| | } |
| | rot.setValue(xaxis, angle); |
| | } |
| | else { |
| | SbVec3f zaxis(0, 0, 1); |
| | this->worldToScreen.multDirMatrix(zaxis, zaxis); |
| | if (zaxis[1] < 0) { |
| | if (dif[0] < 0) { |
| | angle = -angle; |
| | } |
| | } |
| | else { |
| | if (dif[0] > 0) { |
| | angle = -angle; |
| | } |
| | } |
| | rot.setValue(zaxis, angle); |
| | } |
| |
|
| | return rot; |
| | } |
| |
|
| | SbRotation getTrackballClassic(const SbVec3f& point1, const SbVec3f& point2) const |
| | { |
| | |
| | SbRotation zrot; |
| | SbRotation yrot; |
| | SbVec3f dif = point1 - point2; |
| |
|
| | SbVec3f zaxis(1, 0, 0); |
| | zrot.setValue(zaxis, dif[1]); |
| |
|
| | SbVec3f yaxis(0, 1, 0); |
| | yrot.setValue(yaxis, -dif[0]); |
| |
|
| | return zrot * yrot; |
| | } |
| |
|
| | private: |
| | SbMatrix worldToScreen; |
| | OrbitStyle orbit {RoundedArcball}; |
| | }; |
| |
|
| | NavigationStyleEvent::NavigationStyleEvent(const Base::Type& s) |
| | : QEvent(QEvent::User) |
| | , t(s) |
| | {} |
| |
|
| | NavigationStyleEvent::~NavigationStyleEvent() = default; |
| |
|
| | const Base::Type& NavigationStyleEvent::style() const |
| | { |
| | return t; |
| | } |
| |
|
| | TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStyle, Base::BaseClass) |
| |
|
| | NavigationStyle::NavigationStyle() |
| | : viewer(nullptr) |
| | , mouseSelection(nullptr) |
| | , pythonObject(nullptr) |
| | { |
| | this->rotationCenterMode = NavigationStyle::RotationCenterMode::ScenePointAtCursor |
| | | NavigationStyle::RotationCenterMode::FocalPointAtCursor; |
| | initialize(); |
| | } |
| |
|
| | NavigationStyle::~NavigationStyle() |
| | { |
| | finalize(); |
| | delete this->animator; |
| |
|
| | if (!pythonObject.is(nullptr)) { |
| | Base::PyGILStateLocker lock; |
| | Base::PyObjectBase* obj = static_cast<Base::PyObjectBase*>(pythonObject.ptr()); |
| | obj->setInvalid(); |
| | } |
| | } |
| |
|
| | NavigationStyle& NavigationStyle::operator=(const NavigationStyle& ns) |
| | { |
| | this->panningplane = ns.panningplane; |
| | this->menuenabled = ns.menuenabled; |
| | this->animationEnabled = ns.animationEnabled; |
| | this->spinningAnimationEnabled = ns.spinningAnimationEnabled; |
| | static_cast<FCSphereSheetProjector*>(this->spinprojector) |
| | ->setOrbitStyle(static_cast<FCSphereSheetProjector*>(ns.spinprojector)->getOrbitStyle()); |
| | return *this; |
| | } |
| |
|
| | void NavigationStyle::setViewer(View3DInventorViewer* view) |
| | { |
| | this->viewer = view; |
| | } |
| |
|
| | void NavigationStyle::initialize() |
| | { |
| | this->animator = new NavigationAnimator(); |
| |
|
| | this->sensitivity = 2.0f; |
| | this->resetcursorpos = false; |
| | this->currentmode = NavigationStyle::IDLE; |
| | this->animationEnabled = true; |
| | this->spinningAnimationEnabled = false; |
| | this->spinsamplecounter = 0; |
| | this->spinincrement = SbRotation::identity(); |
| | this->rotationCenterFound = false; |
| | this->rotationCenterIsScenePointAtCursor = false; |
| |
|
| | |
| | |
| | |
| | this->spinprojector = new FCSphereSheetProjector( |
| | SbSphere(SbVec3f(0, 0, 0), FCSphereSheetProjector::defaultSphereRadius) |
| | ); |
| | SbViewVolume volume; |
| | volume.ortho(-1, 1, -1, 1, -1, 1); |
| | this->spinprojector->setViewVolume(volume); |
| |
|
| | this->log.size = 16; |
| | this->log.position = new SbVec2s[16]; |
| | this->log.time = new SbTime[16]; |
| | this->log.historysize = 0; |
| |
|
| | this->menuenabled = true; |
| | this->button1down = false; |
| | this->button2down = false; |
| | this->button3down = false; |
| | this->ctrldown = false; |
| | this->shiftdown = false; |
| | this->altdown = false; |
| | this->invertZoom = App::GetApplication() |
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View") |
| | ->GetBool("InvertZoom", true); |
| | this->zoomAtCursor = App::GetApplication() |
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View") |
| | ->GetBool("ZoomAtCursor", true); |
| | this->zoomStep = App::GetApplication() |
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View") |
| | ->GetFloat("ZoomStep", 0.2f); |
| | long mode = App::GetApplication() |
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View") |
| | ->GetInt("RotationMode", 0); |
| | if (mode == 0) { |
| | setRotationCenterMode(NavigationStyle::RotationCenterMode::WindowCenter); |
| | } |
| | else if (mode == 1) { |
| | setRotationCenterMode( |
| | NavigationStyle::RotationCenterMode::ScenePointAtCursor |
| | | NavigationStyle::RotationCenterMode::FocalPointAtCursor |
| | ); |
| | } |
| | else if (mode == 2) { |
| | setRotationCenterMode( |
| | NavigationStyle::RotationCenterMode::ScenePointAtCursor |
| | | NavigationStyle::RotationCenterMode::BoundingBoxCenter |
| | ); |
| | } |
| |
|
| | this->hasDragged = false; |
| | this->hasPanned = false; |
| | this->hasZoomed = false; |
| | } |
| |
|
| | void NavigationStyle::finalize() |
| | { |
| | delete this->spinprojector; |
| | delete[] this->log.position; |
| | delete[] this->log.time; |
| | } |
| |
|
| | void NavigationStyle::interactiveCountInc() |
| | { |
| | viewer->interactiveCountInc(); |
| | } |
| |
|
| | void NavigationStyle::interactiveCountDec() |
| | { |
| | viewer->interactiveCountDec(); |
| | } |
| |
|
| | int NavigationStyle::getInteractiveCount() const |
| | { |
| | return viewer->getInteractiveCount(); |
| | } |
| |
|
| | void NavigationStyle::setOrbitStyle(NavigationStyle::OrbitStyle style) |
| | { |
| | auto projector = static_cast<FCSphereSheetProjector*>(this->spinprojector); |
| | projector->setOrbitStyle(FCSphereSheetProjector::OrbitStyle(style)); |
| | } |
| |
|
| | NavigationStyle::OrbitStyle NavigationStyle::getOrbitStyle() const |
| | { |
| | auto projector = static_cast<FCSphereSheetProjector*>(this->spinprojector); |
| | return NavigationStyle::OrbitStyle(projector->getOrbitStyle()); |
| | } |
| |
|
| | SbBool NavigationStyle::isViewing() const |
| | { |
| | return viewer->isViewing(); |
| | } |
| |
|
| | void NavigationStyle::setViewing(SbBool enable) |
| | { |
| | viewer->setViewing(enable); |
| | } |
| |
|
| | SbBool NavigationStyle::isSeekMode() const |
| | { |
| | return viewer->isSeekMode(); |
| | } |
| |
|
| | void NavigationStyle::setSeekMode(SbBool enable) |
| | { |
| | viewer->setSeekMode(enable); |
| | } |
| |
|
| | SbBool NavigationStyle::seekToPoint(const SbVec2s screenpos) |
| | { |
| | return viewer->seekToPoint(screenpos); |
| | } |
| |
|
| | void NavigationStyle::seekToPoint(const SbVec3f& scenepos) |
| | { |
| | viewer->seekToPoint(scenepos); |
| | } |
| |
|
| | void NavigationStyle::lookAtPoint(const SbVec2s screenpos) |
| | { |
| | const SoCamera* camera = viewer->getCamera(); |
| | if (!camera) { |
| | return; |
| | } |
| |
|
| | SoRayPickAction rpaction(viewer->getViewportRegion()); |
| | rpaction.setPoint(screenpos); |
| | rpaction.setRadius(viewer->getPickRadius()); |
| | rpaction.apply(viewer->getSoRenderManager()->getSceneGraph()); |
| |
|
| | const SoPickedPoint* picked = rpaction.getPickedPoint(); |
| |
|
| | |
| | SbVec3f point; |
| | if (picked) { |
| | point = picked->getPoint(); |
| | } |
| | else { |
| | const SbViewportRegion& vp = viewer->getViewportRegion(); |
| | const float aspectratio = vp.getViewportAspectRatio(); |
| | SbViewVolume vv = camera->getViewVolume(aspectratio); |
| |
|
| | |
| | if (aspectratio < 1.0) { |
| | vv.scale(1.0 / aspectratio); |
| | } |
| |
|
| | SbLine line; |
| | vv.projectPointToLine(normalizePixelPos(screenpos), line); |
| | panningplane.intersect(line, point); |
| | } |
| |
|
| | lookAtPoint(point); |
| | } |
| |
|
| | void NavigationStyle::lookAtPoint(const SbVec3f& position) |
| | { |
| | this->rotationCenterFound = false; |
| | translateCamera(position - getFocalPoint()); |
| | } |
| |
|
| | SoCamera* NavigationStyle::getCamera() const |
| | { |
| | return this->viewer->getCamera(); |
| | } |
| |
|
| | std::shared_ptr<NavigationAnimation> NavigationStyle::setCameraOrientation( |
| | const SbRotation& orientation, |
| | const SbBool moveToCenter |
| | ) const |
| | { |
| | SoCamera* camera = getCamera(); |
| | if (!camera) { |
| | return {}; |
| | } |
| |
|
| | animator->stop(); |
| |
|
| | const SbVec3f focalPoint = getFocalPoint(); |
| | SbVec3f translation(0, 0, 0); |
| |
|
| | if (moveToCenter) { |
| | SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion()); |
| | action.apply(viewer->getSceneGraph()); |
| | SbBox3f box = action.getBoundingBox(); |
| | if (!box.isEmpty()) { |
| | translation = box.getCenter() - focalPoint; |
| | } |
| | } |
| |
|
| | |
| | if (isAnimationEnabled()) { |
| | return viewer->startAnimation(orientation, focalPoint, translation); |
| | } |
| |
|
| | |
| |
|
| | |
| | const SbVec3f rotationCenterDistanceCam = camera->focalDistance.getValue() * SbVec3f(0, 0, 1); |
| |
|
| | |
| | camera->orientation = orientation; |
| |
|
| | |
| | SbVec3f newRotationCenterDistance; |
| | camera->orientation.getValue().multVec(rotationCenterDistanceCam, newRotationCenterDistance); |
| |
|
| | |
| | |
| | camera->position = focalPoint + newRotationCenterDistance + translation; |
| |
|
| | return {}; |
| | } |
| |
|
| | std::shared_ptr<NavigationAnimation> NavigationStyle::translateCamera(const SbVec3f& translation) const |
| | { |
| | SoCamera* camera = getCamera(); |
| | if (!camera) { |
| | return {}; |
| | } |
| |
|
| | animator->stop(); |
| |
|
| | |
| | if (isAnimationEnabled()) { |
| | return viewer->startAnimation(camera->orientation.getValue(), SbVec3f(0, 0, 0), translation); |
| | } |
| |
|
| | |
| |
|
| | camera->position = camera->position.getValue() + translation; |
| |
|
| | return {}; |
| | } |
| |
|
| | void NavigationStyle::boxZoom(const SbBox2s& box) |
| | { |
| | SoCamera* cam = viewer->getSoRenderManager()->getCamera(); |
| | if (!cam) { |
| | return; |
| | } |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | SbViewVolume vv = cam->getViewVolume(vp.getViewportAspectRatio()); |
| |
|
| | short sizeX {}, sizeY {}; |
| | box.getSize(sizeX, sizeY); |
| | SbVec2s size = vp.getViewportSizePixels(); |
| |
|
| | |
| | |
| | if (sizeX == 0 && sizeY == 0) { |
| | return; |
| | } |
| |
|
| | |
| | short xmin {}, xmax {}, ymin {}, ymax {}; |
| | box.getBounds(xmin, ymin, xmax, ymax); |
| | const SbVec2f center( |
| | (float)((xmin + xmax) / 2) / (float)std::max((int)(size[0] - 1), 1), |
| | (float)(size[1] - (ymin + ymax) / 2) / (float)std::max((int)(size[1] - 1), 1) |
| | ); |
| |
|
| | SbPlane plane = vv.getPlane(cam->focalDistance.getValue()); |
| | panCamera(cam, vp.getViewportAspectRatio(), plane, SbVec2f(0.5, 0.5), center); |
| |
|
| | |
| | float scaleX = (float)sizeX / (float)size[0]; |
| | float scaleY = (float)sizeY / (float)size[1]; |
| | float scaleFactor = std::max<float>(scaleX, scaleY); |
| |
|
| | doScale(cam, scaleFactor); |
| | } |
| | void NavigationStyle::scale(float factor) |
| | { |
| | SoCamera* cam = viewer->getSoRenderManager()->getCamera(); |
| | if (!cam) { |
| | return; |
| | } |
| |
|
| | |
| | SbVec3f direction; |
| | cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); |
| | SbVec3f initCenter = cam->position.getValue() + cam->focalDistance.getValue() * direction; |
| |
|
| | |
| | cam->position = cam->position.getValue() - initCenter; |
| |
|
| | |
| | doScale(cam, factor); |
| |
|
| | |
| | cam->position = cam->position.getValue() + initCenter * factor; |
| | } |
| |
|
| | void NavigationStyle::viewAll() |
| | { |
| | |
| | SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion()); |
| | action.apply(viewer->getSceneGraph()); |
| | SbBox3f box = action.getBoundingBox(); |
| | if (box.isEmpty()) { |
| | return; |
| | } |
| |
|
| |
|
| | SoCamera* cam = viewer->getSoRenderManager()->getCamera(); |
| | if (!cam) { |
| | return; |
| | } |
| |
|
| | SbViewVolume vol = cam->getViewVolume(); |
| | if (vol.ulf == vol.llf) { |
| | return; |
| | } |
| | SbVec2f s = vol.projectBox(box); |
| | SbVec2s size = viewer->getSoRenderManager()->getSize(); |
| |
|
| | SbVec3f pt1, pt2, pt3, tmp; |
| | vol.projectPointToLine(SbVec2f(0.0f, 0.0f), pt1, tmp); |
| | vol.projectPointToLine(SbVec2f(s[0], 0.0f), pt2, tmp); |
| | vol.projectPointToLine(SbVec2f(0.0f, s[1]), pt3, tmp); |
| |
|
| | float cam_width = (pt2 - pt1).length(); |
| | float cam_height = (pt3 - pt1).length(); |
| |
|
| | |
| | cam_height = 1.08f * std::max<float>((cam_width * (float)size[1]) / (float)size[0], cam_height); |
| |
|
| | float aspect = cam->aspectRatio.getValue(); |
| |
|
| | if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) { |
| | auto ocam = static_cast<SoOrthographicCamera*>(cam); |
| | if (aspect < 1.0f) { |
| | ocam->height = cam_height / aspect; |
| | } |
| | else { |
| | ocam->height = cam_height; |
| | } |
| | } |
| | } |
| |
|
| | #if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403) |
| | void NavigationStyle::findBoundingSphere() |
| | { |
| | |
| | SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion()); |
| | action.apply(viewer->getSceneGraph()); |
| | boundingSphere.circumscribe(action.getBoundingBox()); |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation) |
| | { |
| | reorientCamera(camera, rotation, getFocalPoint()); |
| | } |
| |
|
| | |
| | |
| | |
| | void NavigationStyle::reorientCamera( |
| | SoCamera* camera, |
| | const SbRotation& rotation, |
| | const SbVec3f& rotationCenter |
| | ) |
| | { |
| | if (!camera) { |
| | return; |
| | } |
| |
|
| | |
| | SbVec3f rotationCenterDistanceCam; |
| | camera->orientation.getValue().inverse().multVec( |
| | camera->position.getValue() - rotationCenter, |
| | rotationCenterDistanceCam |
| | ); |
| |
|
| | |
| | camera->orientation = rotation * camera->orientation.getValue(); |
| |
|
| | |
| | SbVec3f newRotationCenterDistance; |
| | camera->orientation.getValue().multVec(rotationCenterDistanceCam, newRotationCenterDistance); |
| |
|
| | |
| | camera->position = rotationCenter + newRotationCenterDistance; |
| |
|
| | if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) { |
| | |
| | |
| | |
| |
|
| | SbVec3f direction; |
| | camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); |
| |
|
| | #if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 405) |
| | |
| | |
| | |
| | constexpr float orthographicFocalDistance = 250; |
| | #else |
| | constexpr float orthographicFocalDistance = 1; |
| | #endif |
| | camera->position = getFocalPoint() - orthographicFocalDistance * direction; |
| | camera->focalDistance = orthographicFocalDistance; |
| | } |
| |
|
| | #if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403) |
| | |
| | if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) { |
| |
|
| | |
| | SbVec3f center; |
| | camera->orientation.getValue().inverse().multVec( |
| | boundingSphere.getCenter() - camera->position.getValue(), |
| | center |
| | ); |
| |
|
| | SbVec3f dir; |
| | camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), dir); |
| |
|
| | |
| | |
| | float repositionDistance = -center.getValue()[2] - boundingSphere.getRadius(); |
| | camera->position = camera->position.getValue() + repositionDistance * dir; |
| | camera->nearDistance = 0; |
| | camera->farDistance = 2 * boundingSphere.getRadius() + 1; |
| | camera->focalDistance = camera->focalDistance.getValue() - repositionDistance; |
| | } |
| | #endif |
| | } |
| |
|
| | void NavigationStyle::panCamera( |
| | SoCamera* cam, |
| | float aspectratio, |
| | const SbPlane& panplane, |
| | const SbVec2f& currpos, |
| | const SbVec2f& prevpos |
| | ) |
| | { |
| | if (!cam) { |
| | return; |
| | } |
| | if (currpos == prevpos) { |
| | return; |
| | } |
| |
|
| |
|
| | |
| | SbViewVolume vv = cam->getViewVolume(aspectratio); |
| |
|
| | |
| | if (aspectratio < 1.0) { |
| | vv.scale(1.0 / aspectratio); |
| | } |
| |
|
| | SbLine line; |
| | vv.projectPointToLine(currpos, line); |
| | SbVec3f current_planept; |
| | panplane.intersect(line, current_planept); |
| | vv.projectPointToLine(prevpos, line); |
| | SbVec3f old_planept; |
| | panplane.intersect(line, old_planept); |
| |
|
| | |
| | |
| | cam->position = cam->position.getValue() - (current_planept - old_planept); |
| |
|
| | if (this->currentmode != NavigationStyle::IDLE) { |
| | hasPanned = true; |
| | } |
| | } |
| |
|
| | void NavigationStyle::setupPanningPlane(const SoCamera* camera) |
| | { |
| | |
| | |
| | |
| | if (!camera) { |
| | this->panningplane = SbPlane(SbVec3f(0, 0, 1), 0); |
| | } |
| | else { |
| | const SbViewportRegion& vp = viewer->getViewportRegion(); |
| | const float aspectratio = vp.getViewportAspectRatio(); |
| | SbViewVolume vv = camera->getViewVolume(aspectratio); |
| |
|
| | |
| | if (aspectratio < 1.0) { |
| | vv.scale(1.0 / aspectratio); |
| | } |
| |
|
| | this->panningplane = vv.getPlane(camera->focalDistance.getValue()); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void NavigationStyle::zoom(SoCamera* cam, float diffvalue) |
| | { |
| | if (!cam) { |
| | return; |
| | } |
| |
|
| | animator->stop(); |
| |
|
| | SoType t = cam->getTypeId(); |
| | SbName tname = t.getName(); |
| |
|
| | |
| | auto multiplicator = float(exp(diffvalue)); |
| |
|
| | if (t.isDerivedFrom(SoOrthographicCamera::getClassTypeId())) { |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | auto oc = static_cast<SoOrthographicCamera*>(cam); |
| | oc->height = oc->height.getValue() * multiplicator; |
| | } |
| | else { |
| | |
| | |
| | |
| | if (!t.isDerivedFrom(SoPerspectiveCamera::getClassTypeId()) && tname != "FrustumCamera") { |
| | #ifdef FC_DEBUG |
| | static SbBool first = true; |
| | if (first) { |
| | SoDebugError::postWarning( |
| | "NavigationStyle::zoom", |
| | "Unknown camera type, " |
| | "will zoom by moving position, " |
| | "but this might not be correct." |
| | ); |
| | first = false; |
| | } |
| | #endif |
| | } |
| |
|
| | const float oldfocaldist = cam->focalDistance.getValue(); |
| | const float newfocaldist = oldfocaldist * multiplicator; |
| |
|
| | SbVec3f direction; |
| | cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); |
| |
|
| | const SbVec3f oldpos = cam->position.getValue(); |
| | const SbVec3f newpos = oldpos + (newfocaldist - oldfocaldist) * -direction; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const float distorigo = newpos.length(); |
| | |
| | |
| | float maxDistance = std::sqrt(std::numeric_limits<float>::max()); |
| | if (distorigo > maxDistance) { |
| | |
| | } |
| | else { |
| | cam->position = newpos; |
| | cam->focalDistance = newfocaldist; |
| | } |
| | } |
| |
|
| | if (this->currentmode != NavigationStyle::IDLE) { |
| | hasZoomed = true; |
| | } |
| | } |
| |
|
| | |
| | |
| | void NavigationStyle::zoomByCursor(const SbVec2f& thispos, const SbVec2f& prevpos) |
| | { |
| | |
| | |
| | float value = (thispos[1] - prevpos[1]) * 10.0f ; |
| | if (this->invertZoom) { |
| | value = -value; |
| | } |
| | zoom(viewer->getSoRenderManager()->getCamera(), value); |
| | } |
| |
|
| | void NavigationStyle::zoomIn() |
| | { |
| | zoom(viewer->getSoRenderManager()->getCamera(), -this->zoomStep); |
| | } |
| |
|
| | void NavigationStyle::zoomOut() |
| | { |
| | zoom(viewer->getSoRenderManager()->getCamera(), this->zoomStep); |
| | } |
| |
|
| | |
| | |
| | |
| | int NavigationStyle::getDelta() const |
| | { |
| | return 120; |
| | } |
| |
|
| | void NavigationStyle::doZoom(SoCamera* camera, int wheeldelta, const SbVec2f& pos) |
| | { |
| | float value = this->zoomStep * wheeldelta / float(getDelta()); |
| | if (this->invertZoom) { |
| | value = -value; |
| | } |
| | doZoom(camera, value, pos); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void NavigationStyle::doZoom(SoCamera* camera, float logfactor, const SbVec2f& pos) |
| | { |
| | |
| | |
| | if (fabs(logfactor) > 4.0) { |
| | return; |
| | } |
| | SbBool zoomAtCur = this->zoomAtCursor; |
| | if (zoomAtCur) { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | float ratio = vp.getViewportAspectRatio(); |
| | SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio()); |
| | SbPlane panplane = vv.getPlane(camera->focalDistance.getValue()); |
| | panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, SbVec2f(0.5, 0.5), pos); |
| | } |
| |
|
| | zoom(camera, logfactor); |
| |
|
| | if (zoomAtCur) { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | float ratio = vp.getViewportAspectRatio(); |
| | SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio()); |
| | SbPlane panplane = vv.getPlane(camera->focalDistance.getValue()); |
| | panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, pos, SbVec2f(0.5, 0.5)); |
| |
|
| | |
| | |
| | if (!rotationCenterMode) { |
| | viewer->changeRotationCenterPosition(getFocalPoint()); |
| |
|
| | #if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403) |
| | findBoundingSphere(); |
| | #endif |
| | } |
| | } |
| | } |
| | void NavigationStyle::doScale(SoCamera* cam, float factor) |
| | { |
| | if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) { |
| | float height = static_cast<SoOrthographicCamera*>(cam)->height.getValue() * factor; |
| | static_cast<SoOrthographicCamera*>(cam)->height = height; |
| | } |
| | else if (cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) { |
| | float height = static_cast<SoPerspectiveCamera*>(cam)->heightAngle.getValue() / 2.0f; |
| | height = 2.0f * atan(tan(height) * factor); |
| | static_cast<SoPerspectiveCamera*>(cam)->heightAngle = height; |
| | } |
| | } |
| | void NavigationStyle::doRotate(SoCamera* camera, float angle, const SbVec2f& pos) |
| | { |
| | SbBool zoomAtCur = this->zoomAtCursor; |
| | if (zoomAtCur) { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | float ratio = vp.getViewportAspectRatio(); |
| | SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio()); |
| | SbPlane panplane = vv.getPlane(camera->focalDistance.getValue()); |
| | panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, SbVec2f(0.5, 0.5), pos); |
| | } |
| |
|
| | SbRotation rotcam = camera->orientation.getValue(); |
| | |
| | SbVec3f vdir; |
| | rotcam.multVec(SbVec3f(0, 0, -1), vdir); |
| | |
| | SbRotation drot(vdir, angle); |
| | camera->orientation.setValue(rotcam * drot); |
| |
|
| | if (zoomAtCur) { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | float ratio = vp.getViewportAspectRatio(); |
| | SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio()); |
| | SbPlane panplane = vv.getPlane(camera->focalDistance.getValue()); |
| | panCamera(viewer->getSoRenderManager()->getCamera(), ratio, panplane, pos, SbVec2f(0.5, 0.5)); |
| | } |
| | } |
| |
|
| | SbVec3f NavigationStyle::getRotationCenter(SbBool& found) const |
| | { |
| | found = this->rotationCenterFound; |
| | return this->rotationCenter; |
| | } |
| |
|
| | std::optional<SbVec2s>& NavigationStyle::getRightClickPosition() |
| | { |
| | return rightClickPosition; |
| | } |
| |
|
| | void NavigationStyle::setRotationCenter(const SbVec3f& cnt) |
| | { |
| | this->rotationCenter = cnt; |
| | this->rotationCenterFound = true; |
| |
|
| | const auto camera = getCamera(); |
| | if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) { |
| | SbVec3f direction; |
| | camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); |
| |
|
| | |
| | const auto rotationCenterDistance = rotationCenter - camera->position.getValue(); |
| | const auto rotationCenterDepth = rotationCenterDistance.dot(direction); |
| |
|
| | |
| | |
| | camera->focalDistance.setValue(rotationCenterDepth); |
| | } |
| | } |
| |
|
| | SbVec3f NavigationStyle::getFocalPoint() const |
| | { |
| | SoCamera* cam = viewer->getSoRenderManager()->getCamera(); |
| | if (!cam) { |
| | return {0, 0, 0}; |
| | } |
| |
|
| | |
| | SbVec3f direction; |
| | cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); |
| | SbVec3f focal = cam->position.getValue() + cam->focalDistance.getValue() * direction; |
| | return focal; |
| | } |
| |
|
| | |
| | |
| | |
| | void NavigationStyle::spin(const SbVec2f& pointerpos) |
| | { |
| | if (this->log.historysize < 2) { |
| | return; |
| | } |
| | assert(this->spinprojector); |
| |
|
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | SbVec2s glsize(vp.getViewportSizePixels()); |
| | SbVec2f lastpos; |
| | lastpos[0] = float(this->log.position[1][0]) / float(std::max((int)(glsize[0] - 1), 1)); |
| | lastpos[1] = float(this->log.position[1][1]) / float(std::max((int)(glsize[1] - 1), 1)); |
| |
|
| | if (getOrbitStyle() == FreeTurntable) { |
| | SbVec2f midpos(lastpos[0], pointerpos[1]); |
| | spinInternal(pointerpos, midpos); |
| | spinInternal(midpos, lastpos); |
| | } |
| | else { |
| | spinInternal(pointerpos, lastpos); |
| | } |
| |
|
| | if (this->currentmode != NavigationStyle::IDLE) { |
| | hasDragged = true; |
| | } |
| | } |
| |
|
| | void NavigationStyle::spinInternal(const SbVec2f& pointerpos, const SbVec2f& lastpos) |
| | { |
| | float sensitivity = getSensitivity(); |
| |
|
| | |
| | |
| | if ((getOrbitStyle() == Trackball || getOrbitStyle() == TrackballClassic |
| | || getOrbitStyle() == RoundedArcball) |
| | && rotationCenterMode & RotationCenterMode::ScenePointAtCursor && rotationCenterFound |
| | && rotationCenterIsScenePointAtCursor) { |
| | const auto pointOnScreen = viewer->getPointOnViewport(rotationCenter); |
| | const auto sphereCenter = 2 * normalizePixelPos(pointOnScreen) - SbVec2f {1, 1}; |
| |
|
| | float x, y; |
| | sphereCenter.getValue(x, y); |
| |
|
| | const float sphereScale = 1 + sphereCenter.length(); |
| | const float radius = FCSphereSheetProjector::defaultSphereRadius * sphereScale; |
| | sensitivity *= sphereScale; |
| |
|
| | spinprojector->setSphere(SbSphere {SbVec3f {x, y, 0}, radius}); |
| | } |
| | else { |
| | spinprojector->setSphere( |
| | SbSphere {SbVec3f {0, 0, 0}, FCSphereSheetProjector::defaultSphereRadius} |
| | ); |
| | } |
| |
|
| | |
| | SbMatrix mat; |
| | viewer->getSoRenderManager()->getCamera()->orientation.getValue().getValue(mat); |
| | this->spinprojector->setWorkingSpace(mat); |
| |
|
| | this->spinprojector->project(lastpos); |
| | SbRotation r; |
| | this->spinprojector->projectAndGetRotation(pointerpos, r); |
| | if (sensitivity > 1.0f) { |
| | SbVec3f axis; |
| | float radians {}; |
| | r.getValue(axis, radians); |
| | radians = sensitivity * radians; |
| | r.setValue(axis, radians); |
| | } |
| | r.invert(); |
| |
|
| | if (this->rotationCenterMode && this->rotationCenterFound) { |
| | this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r, rotationCenter); |
| | } |
| | else { |
| | this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r); |
| | } |
| |
|
| | |
| | |
| |
|
| | SbVec3f dummy_axis, newaxis; |
| | float acc_angle {}, newangle {}; |
| | this->spinincrement.getValue(dummy_axis, acc_angle); |
| | acc_angle *= this->spinsamplecounter; |
| | r.getValue(newaxis, newangle); |
| | acc_angle += newangle; |
| |
|
| | this->spinsamplecounter++; |
| | acc_angle /= this->spinsamplecounter; |
| | |
| | this->spinincrement.setValue(newaxis, acc_angle); |
| |
|
| | |
| | |
| | |
| | if (this->spinsamplecounter > 3) { |
| | this->spinsamplecounter = 3; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void NavigationStyle::spin_simplified(SbVec2f curpos, SbVec2f prevpos) |
| | { |
| | assert(this->spinprojector); |
| |
|
| | if (getOrbitStyle() == FreeTurntable) { |
| | SbVec2f midpos(prevpos[0], curpos[1]); |
| | spinSimplifiedInternal(curpos, midpos); |
| | spinSimplifiedInternal(midpos, prevpos); |
| | } |
| | else { |
| | spinSimplifiedInternal(curpos, prevpos); |
| | } |
| |
|
| | hasDragged = true; |
| | } |
| |
|
| | void NavigationStyle::spinSimplifiedInternal(SbVec2f curpos, SbVec2f prevpos) |
| | { |
| | |
| | SbMatrix mat; |
| | viewer->getSoRenderManager()->getCamera()->orientation.getValue().getValue(mat); |
| | this->spinprojector->setWorkingSpace(mat); |
| |
|
| | this->spinprojector->project(prevpos); |
| | SbRotation r; |
| | this->spinprojector->projectAndGetRotation(curpos, r); |
| | float sensitivity = getSensitivity(); |
| | if (sensitivity > 1.0f) { |
| | SbVec3f axis; |
| | float radians {}; |
| | r.getValue(axis, radians); |
| | radians = sensitivity * radians; |
| | r.setValue(axis, radians); |
| | } |
| | r.invert(); |
| |
|
| | if (this->rotationCenterMode && this->rotationCenterFound) { |
| | this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r, rotationCenter); |
| | } |
| | else { |
| | this->reorientCamera(viewer->getSoRenderManager()->getCamera(), r); |
| | } |
| | } |
| |
|
| | SbBool NavigationStyle::doSpin() |
| | { |
| | if (this->log.historysize >= 3) { |
| | SbTime stoptime = (SbTime::getTimeOfDay() - this->log.time[0]); |
| | if (isSpinningAnimationEnabled() && stoptime.getValue() < 0.100) { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | const SbVec2s glsize(vp.getViewportSizePixels()); |
| | SbVec3f from = this->spinprojector->project(SbVec2f( |
| | float(this->log.position[2][0]) / float(std::max(glsize[0] - 1, 1)), |
| | float(this->log.position[2][1]) / float(std::max(glsize[1] - 1, 1)) |
| | )); |
| | SbVec3f to = this->spinprojector->project(this->lastmouseposition); |
| | SbRotation rot = this->spinprojector->getRotation(from, to); |
| |
|
| | SbTime delta = (this->log.time[0] - this->log.time[2]); |
| | double deltatime = delta.getValue(); |
| | rot.invert(); |
| | rot.scaleAngle(float(0.200 / deltatime)); |
| |
|
| | SbVec3f axis; |
| | float radians {}; |
| | rot.getValue(axis, radians); |
| | if ((radians > 0.01f) && (deltatime < 0.300)) { |
| | viewer->startSpinningAnimation(axis, radians * 5); |
| | return true; |
| | } |
| | } |
| | } |
| |
|
| | return false; |
| | } |
| |
|
| | void NavigationStyle::saveCursorPosition(const SoEvent* const ev) |
| | { |
| | this->globalPos.setValue(QCursor::pos().x(), QCursor::pos().y()); |
| | this->localPos = ev->getPosition(); |
| | rotationCenterIsScenePointAtCursor = false; |
| |
|
| | |
| | if (!this->rotationCenterMode) { |
| | setRotationCenter(getFocalPoint()); |
| | } |
| |
|
| | |
| | |
| | |
| | if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::ScenePointAtCursor) { |
| | SoRayPickAction rpaction(viewer->getSoRenderManager()->getViewportRegion()); |
| | rpaction.setPoint(this->localPos); |
| | rpaction.setRadius(viewer->getPickRadius()); |
| | rpaction.apply(viewer->getSoRenderManager()->getSceneGraph()); |
| |
|
| | SoPickedPoint* picked = rpaction.getPickedPoint(); |
| | if (picked) { |
| | setRotationCenter(picked->getPoint()); |
| | rotationCenterIsScenePointAtCursor = true; |
| | return; |
| | } |
| | } |
| |
|
| | |
| | if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::FocalPointAtCursor) { |
| | |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | float ratio = vp.getViewportAspectRatio(); |
| |
|
| | SoCamera* cam = viewer->getSoRenderManager()->getCamera(); |
| | if (!cam) { |
| | return; |
| | } |
| | SbViewVolume vv = cam->getViewVolume(ratio); |
| |
|
| | SbLine line; |
| | SbVec2f currpos = ev->getNormalizedPosition(vp); |
| | vv.projectPointToLine(currpos, line); |
| | SbVec3f current_planept; |
| | SbPlane panplane = vv.getPlane(cam->focalDistance.getValue()); |
| | panplane.intersect(line, current_planept); |
| |
|
| | setRotationCenter(current_planept); |
| | } |
| |
|
| | |
| | if (this->rotationCenterMode & NavigationStyle::RotationCenterMode::BoundingBoxCenter) { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | float ratio = vp.getViewportAspectRatio(); |
| |
|
| | SoCamera* cam = viewer->getSoRenderManager()->getCamera(); |
| | if (!cam) { |
| | return; |
| | } |
| |
|
| | |
| | SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion()); |
| | action.apply(viewer->objectGroup); |
| | SbBox3f boundingBox = action.getBoundingBox(); |
| | SbVec3f boundingBoxCenter = boundingBox.getCenter(); |
| | setRotationCenter(boundingBoxCenter); |
| |
|
| | |
| | |
| | |
| | SbViewVolume vv = cam->getViewVolume(ratio); |
| | vv.projectToScreen(boundingBoxCenter, boundingBoxCenter); |
| | SbVec2s size = vp.getViewportSizePixels(); |
| | auto tox = static_cast<short>(boundingBoxCenter[0] * size[0]); |
| | auto toy = static_cast<short>(boundingBoxCenter[1] * size[1]); |
| | this->localPos.setValue(tox, toy); |
| | } |
| | } |
| |
|
| | SbVec2f NavigationStyle::normalizePixelPos(SbVec2s pixpos) |
| | { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | const SbVec2s size(vp.getViewportSizePixels()); |
| | return { |
| | (float)pixpos[0] / (float)std::max((int)(size[0] - 1), 1), |
| | (float)pixpos[1] / (float)std::max((int)(size[1] - 1), 1) |
| | }; |
| | } |
| |
|
| | SbVec2f NavigationStyle::normalizePixelPos(SbVec2f pixpos) |
| | { |
| | const SbViewportRegion& vp = viewer->getSoRenderManager()->getViewportRegion(); |
| | const SbVec2s size(vp.getViewportSizePixels()); |
| | return { |
| | pixpos[0] / (float)std::max((int)(size[0] - 1), 1), |
| | pixpos[1] / (float)std::max((int)(size[1] - 1), 1) |
| | }; |
| | } |
| |
|
| | void NavigationStyle::moveCursorPosition() |
| | { |
| | if (!isResetCursorPosition()) { |
| | return; |
| | } |
| |
|
| | QPoint cpos = QCursor::pos(); |
| | if (abs(cpos.x() - globalPos[0]) > 10 || abs(cpos.y() - globalPos[1]) > 10) { |
| | QCursor::setPos(globalPos[0], globalPos[1] - 1); |
| | this->log.position[0] = localPos; |
| | } |
| | } |
| |
|
| |
|
| | SbBool NavigationStyle::handleEventInForeground(const SoEvent* const e) |
| | { |
| | SoHandleEventAction action(viewer->getSoRenderManager()->getViewportRegion()); |
| | action.setEvent(e); |
| | action.setPickRadius(viewer->getPickRadius()); |
| | action.apply(viewer->foregroundroot); |
| | return action.isHandled(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void NavigationStyle::setAnimationEnabled(const SbBool enable) |
| | { |
| | animationEnabled = enable; |
| | if (!enable && isAnimating()) { |
| | animator->stop(); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | void NavigationStyle::setSpinningAnimationEnabled(const SbBool enable) |
| | { |
| | spinningAnimationEnabled = enable; |
| | if (!enable && isSpinning()) { |
| | animator->stop(); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | SbBool NavigationStyle::isAnimationEnabled() const |
| | { |
| | return animationEnabled; |
| | } |
| |
|
| | |
| | |
| | |
| | SbBool NavigationStyle::isSpinningAnimationEnabled() const |
| | { |
| | return animationEnabled && spinningAnimationEnabled; |
| | } |
| |
|
| | |
| | |
| | |
| | SbBool NavigationStyle::isAnimating() const |
| | { |
| | return animator->isAnimating(); |
| | } |
| |
|
| | |
| | |
| | |
| | SbBool NavigationStyle::isSpinning() const |
| | { |
| | return currentmode == NavigationStyle::SPINNING; |
| | } |
| |
|
| | void NavigationStyle::startAnimating(const std::shared_ptr<NavigationAnimation>& animation, bool wait) const |
| | { |
| | if (wait) { |
| | animator->startAndWait(animation); |
| | } |
| | else { |
| | animator->start(animation); |
| | } |
| | } |
| |
|
| | void NavigationStyle::stopAnimating() const |
| | { |
| | animator->stop(); |
| | } |
| |
|
| | void NavigationStyle::setSensitivity(float val) |
| | { |
| | this->sensitivity = val; |
| | } |
| |
|
| | float NavigationStyle::getSensitivity() const |
| | { |
| | return this->sensitivity; |
| | } |
| |
|
| | void NavigationStyle::setResetCursorPosition(SbBool on) |
| | { |
| | this->resetcursorpos = on; |
| | } |
| |
|
| | SbBool NavigationStyle::isResetCursorPosition() const |
| | { |
| | return this->resetcursorpos; |
| | } |
| |
|
| | void NavigationStyle::setZoomInverted(SbBool on) |
| | { |
| | this->invertZoom = on; |
| | } |
| |
|
| | SbBool NavigationStyle::isZoomInverted() const |
| | { |
| | return this->invertZoom; |
| | } |
| |
|
| | void NavigationStyle::setZoomStep(float val) |
| | { |
| | this->zoomStep = val; |
| | } |
| |
|
| | void NavigationStyle::setZoomAtCursor(SbBool on) |
| | { |
| | this->zoomAtCursor = on; |
| | } |
| |
|
| | SbBool NavigationStyle::isZoomAtCursor() const |
| | { |
| | return this->zoomAtCursor; |
| | } |
| |
|
| | void NavigationStyle::setRotationCenterMode(NavigationStyle::RotationCenterModes mode) |
| | { |
| | this->rotationCenterMode = mode; |
| | } |
| |
|
| | NavigationStyle::RotationCenterModes NavigationStyle::getRotationCenterMode() const |
| | { |
| | return this->rotationCenterMode; |
| | } |
| |
|
| | void NavigationStyle::startSelection(AbstractMouseSelection* mouse) |
| | { |
| | if (!mouse) { |
| | return; |
| | } |
| |
|
| | if (mouseSelection) { |
| | SoDebugError::postWarning( |
| | "NavigationStyle::startSelection", |
| | "Set new mouse selection while an old is still active." |
| | ); |
| | } |
| |
|
| | mouseSelection = mouse; |
| | mouseSelection->grabMouseModel(viewer); |
| | } |
| |
|
| | void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode) |
| | { |
| | if (mouseSelection) { |
| | return; |
| | } |
| | if (isSelecting()) { |
| | stopSelection(); |
| | } |
| |
|
| | switch (mode) { |
| | case Lasso: |
| | mouseSelection = new PolyPickerSelection(); |
| | break; |
| | case Rectangle: |
| | mouseSelection = new RectangleSelection(); |
| | break; |
| | case Rubberband: |
| | mouseSelection = new RubberbandSelection(); |
| | break; |
| | case BoxZoom: |
| | mouseSelection = new BoxZoomSelection(); |
| | break; |
| | case Clip: |
| | mouseSelection = new PolyClipSelection(); |
| | break; |
| | default: |
| | break; |
| | } |
| |
|
| | if (mouseSelection) { |
| | mouseSelection->grabMouseModel(viewer); |
| | } |
| | } |
| |
|
| | void NavigationStyle::abortSelection() |
| | { |
| | pcPolygon.clear(); |
| | if (mouseSelection) { |
| | mouseSelection->releaseMouseModel(true); |
| | delete mouseSelection; |
| | mouseSelection = nullptr; |
| | } |
| | } |
| |
|
| | void NavigationStyle::stopSelection() |
| | { |
| | pcPolygon.clear(); |
| | if (mouseSelection) { |
| | mouseSelection->releaseMouseModel(); |
| | delete mouseSelection; |
| | mouseSelection = nullptr; |
| | } |
| | } |
| |
|
| | SbBool NavigationStyle::isSelecting() const |
| | { |
| | return (mouseSelection ? true : false); |
| | } |
| |
|
| | const std::vector<SbVec2s>& NavigationStyle::getPolygon(SelectionRole* role) const |
| | { |
| | if (role) { |
| | *role = this->selectedRole; |
| | } |
| | return pcPolygon; |
| | } |
| |
|
| | bool NavigationStyle::isDraggerUnderCursor(const SbVec2s pos) const |
| | { |
| | SoRayPickAction rp(this->viewer->getSoRenderManager()->getViewportRegion()); |
| | rp.setRadius(viewer->getPickRadius()); |
| | rp.setPoint(pos); |
| | rp.apply(this->viewer->getSoRenderManager()->getSceneGraph()); |
| | SoPickedPoint* pick = rp.getPickedPoint(); |
| | if (pick) { |
| | const auto fullpath = static_cast<const SoFullPath*>(pick->getPath()); |
| | for (int i = 0; i < fullpath->getLength(); ++i) { |
| | if (fullpath->getNode(i)->isOfType(SoDragger::getClassTypeId())) { |
| | return true; |
| | } |
| | } |
| | return false; |
| | } |
| | return false; |
| | } |
| |
|
| | |
| | |
| | void NavigationStyle::addToLog(const SbVec2s pos, const SbTime time) |
| | { |
| | |
| | |
| | assert(this->log.size > 2 && "mouse log too small!"); |
| |
|
| | if (this->log.historysize > 0 && pos == this->log.position[0]) { |
| | return; |
| | } |
| |
|
| | int lastidx = this->log.historysize; |
| | |
| | if (lastidx == this->log.size) { |
| | lastidx--; |
| | } |
| |
|
| | assert(lastidx < this->log.size); |
| | for (int i = lastidx; i > 0; i--) { |
| | this->log.position[i] = this->log.position[i - 1]; |
| | this->log.time[i] = this->log.time[i - 1]; |
| | } |
| |
|
| | this->log.position[0] = pos; |
| | this->log.time[0] = time; |
| | if (this->log.historysize < this->log.size) { |
| | this->log.historysize += 1; |
| | } |
| | } |
| |
|
| | |
| | |
| | void NavigationStyle::clearLog() |
| | { |
| | this->log.historysize = 0; |
| | } |
| |
|
| | void NavigationStyle::syncModifierKeys(const SoEvent* const ev) |
| | { |
| | |
| | |
| | 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(); |
| | } |
| | } |
| |
|
| | |
| | |
| | void NavigationStyle::setViewingMode(const ViewerMode newmode) |
| | { |
| | const ViewerMode oldmode = this->currentmode; |
| |
|
| | |
| | |
| | if ((oldmode == IDLE && newmode != IDLE) |
| | || (newmode == IDLE && !button1down && !button2down && !button3down)) { |
| | hasPanned = false; |
| | hasDragged = false; |
| | hasZoomed = false; |
| | } |
| |
|
| | if (newmode == oldmode) { |
| |
|
| | |
| | if (newmode == NavigationStyle::DRAGGING && rotationCenterFound) { |
| | viewer->changeRotationCenterPosition(rotationCenter); |
| | } |
| |
|
| | return; |
| | } |
| |
|
| | switch (newmode) { |
| | case DRAGGING: |
| | |
| | |
| | animator->stop(); |
| | viewer->showRotationCenter(true); |
| |
|
| | #if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403) |
| | findBoundingSphere(); |
| | #endif |
| |
|
| | this->spinprojector->project(this->lastmouseposition); |
| | this->interactiveCountInc(); |
| | this->clearLog(); |
| | break; |
| |
|
| | case SPINNING: |
| | this->interactiveCountInc(); |
| | viewer->getSoRenderManager()->scheduleRedraw(); |
| | break; |
| |
|
| | case PANNING: |
| | animator->stop(); |
| | setupPanningPlane(viewer->getSoRenderManager()->getCamera()); |
| | this->interactiveCountInc(); |
| | break; |
| |
|
| | case ZOOMING: |
| | animator->stop(); |
| | this->interactiveCountInc(); |
| | break; |
| |
|
| | case BOXZOOM: |
| | animator->stop(); |
| | this->interactiveCountInc(); |
| | break; |
| |
|
| | default: |
| | break; |
| | } |
| |
|
| | switch (oldmode) { |
| | case SPINNING: |
| | case DRAGGING: |
| | viewer->showRotationCenter(false); |
| | [[fallthrough]]; |
| | case PANNING: |
| | case ZOOMING: |
| | case BOXZOOM: |
| | this->interactiveCountDec(); |
| | break; |
| |
|
| | default: |
| | break; |
| | } |
| |
|
| | viewer->setCursorRepresentation(newmode); |
| | this->currentmode = newmode; |
| | } |
| |
|
| | int NavigationStyle::getViewingMode() const |
| | { |
| | return (int)this->currentmode; |
| | } |
| |
|
| | SbBool NavigationStyle::processEvent(const SoEvent* const ev) |
| | { |
| | |
| | |
| | if (mouseSelection) { |
| | int hd = mouseSelection->handleEvent(ev, viewer->getSoRenderManager()->getViewportRegion()); |
| | if (hd == AbstractMouseSelection::Continue || hd == AbstractMouseSelection::Restart) { |
| | return true; |
| | } |
| | else if (hd == AbstractMouseSelection::Finish) { |
| | pcPolygon = mouseSelection->getPositions(); |
| | selectedRole = mouseSelection->selectedRole(); |
| | delete mouseSelection; |
| | mouseSelection = nullptr; |
| | syncWithEvent(ev); |
| | return NavigationStyle::processSoEvent(ev); |
| | } |
| | else if (hd == AbstractMouseSelection::Cancel) { |
| | pcPolygon.clear(); |
| | delete mouseSelection; |
| | mouseSelection = nullptr; |
| | syncWithEvent(ev); |
| | return NavigationStyle::processSoEvent(ev); |
| | } |
| | } |
| |
|
| | const ViewerMode curmode = this->currentmode; |
| |
|
| | SbBool processed = false; |
| | processed = this->processSoEvent(ev); |
| |
|
| | |
| | if ((curmode == NavigationStyle::SELECTION || curmode == NavigationStyle::IDLE) && !processed) { |
| | if (SoMouseButtonEvent::isButtonReleaseEvent(ev, SoMouseButtonEvent::BUTTON1)) { |
| | if (!ev->wasCtrlDown()) { |
| | Gui::Selection().clearSelection(); |
| | } |
| | } |
| | } |
| |
|
| | return processed; |
| | } |
| |
|
| | SbBool NavigationStyle::processSoEvent(const SoEvent* const ev) |
| | { |
| | bool processed = false; |
| | bool offeredtoViewerEventBase = false; |
| |
|
| | |
| | if (ev->isOfType(SoMouseWheelEvent::getClassTypeId())) { |
| | auto const event = static_cast<const SoMouseWheelEvent*>(ev); |
| | processed = processWheelEvent(event); |
| | viewer->processSoEventBase(ev); |
| | offeredtoViewerEventBase = true; |
| | } |
| |
|
| | if (!processed && !offeredtoViewerEventBase) { |
| | processed = viewer->processSoEventBase(ev); |
| | } |
| |
|
| | return processed; |
| | } |
| |
|
| | void NavigationStyle::syncWithEvent(const SoEvent* const ev) |
| | { |
| | |
| | |
| | |
| | if (this->isSeekMode()) { |
| | return; |
| | } |
| |
|
| | const SoType type(ev->getTypeId()); |
| |
|
| | |
| | |
| | syncModifierKeys(ev); |
| |
|
| | |
| | if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { |
| | auto const event = static_cast<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; |
| | default: |
| | break; |
| | } |
| | } |
| |
|
| | |
| | if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { |
| | auto const event = static_cast<const SoMouseButtonEvent*>(ev); |
| | const int button = event->getButton(); |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; |
| | #ifdef FC_DEBUG |
| | SoDebugError::postInfo("processSoEvent", "button = %d", button); |
| | #endif |
| | switch (button) { |
| | case SoMouseButtonEvent::BUTTON1: |
| | this->button1down = press; |
| | break; |
| | case SoMouseButtonEvent::BUTTON2: |
| | this->button2down = press; |
| | break; |
| | case SoMouseButtonEvent::BUTTON3: |
| | this->button3down = press; |
| | break; |
| | default: |
| | break; |
| | } |
| | } |
| | } |
| |
|
| | SbBool NavigationStyle::processMotionEvent(const SoMotion3Event* const ev) |
| | { |
| | SoCamera* const camera = viewer->getSoRenderManager()->getCamera(); |
| | if (!camera) { |
| | return false; |
| | } |
| |
|
| | SbViewVolume volume(camera->getViewVolume()); |
| | SbVec3f center(volume.getSightPoint(camera->focalDistance.getValue())); |
| | float scale(volume.getWorldToScreenScale(center, 1.0)); |
| | float translationFactor = scale * .0001; |
| |
|
| | SbVec3f dir = ev->getTranslation(); |
| |
|
| | if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())) { |
| | auto oCam = static_cast<SoOrthographicCamera*>(camera); |
| | oCam->scaleHeight(1.0 + (dir[2] * 0.0001)); |
| | dir[2] = 0.0; |
| | } |
| |
|
| | SbRotation newRotation(ev->getRotation() * camera->orientation.getValue()); |
| | SbVec3f newPosition, newDirection; |
| | newRotation.multVec(SbVec3f(0.0, 0.0, -1.0), newDirection); |
| | newPosition = center - (newDirection * camera->focalDistance.getValue()); |
| |
|
| | camera->orientation.setValue(newRotation); |
| | camera->orientation.getValue().multVec(dir, dir); |
| | camera->position = newPosition + (dir * translationFactor); |
| |
|
| | return true; |
| | } |
| |
|
| | SbBool NavigationStyle::processKeyboardEvent(const SoKeyboardEvent* const event) |
| | { |
| | SbBool processed = false; |
| | 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::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: { |
| | processed = true; |
| | const SbVec2f posn = normalizePixelPos(event->getPosition()); |
| | doZoom(viewer->getSoRenderManager()->getCamera(), getDelta(), posn); |
| | break; |
| | } |
| | case SoKeyboardEvent::PAGE_DOWN: { |
| | processed = true; |
| | const SbVec2f posn = normalizePixelPos(event->getPosition()); |
| | doZoom(viewer->getSoRenderManager()->getCamera(), -getDelta(), posn); |
| | break; |
| | } |
| | default: |
| | break; |
| | } |
| |
|
| | return processed; |
| | } |
| |
|
| | SbBool NavigationStyle::processClickEvent(const SoMouseButtonEvent* const event) |
| | { |
| | |
| | |
| | SbBool processed = false; |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; |
| | if (press) { |
| | SbTime tmp = (event->getTime() - mouseDownConsumedEvent.getTime()); |
| | float dci = (float)QApplication::doubleClickInterval() / 1000.0f; |
| | |
| | if (tmp.getValue() < dci) { |
| | mouseDownConsumedEvent = *event; |
| | mouseDownConsumedEvent.setTime(event->getTime()); |
| | processed = true; |
| | } |
| | else { |
| | mouseDownConsumedEvent.setTime(event->getTime()); |
| | |
| | |
| | mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); |
| | } |
| | } |
| | else if (!press) { |
| | if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { |
| | |
| | NavigationStyle::processSoEvent(&mouseDownConsumedEvent); |
| | mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); |
| | } |
| | } |
| |
|
| | return processed; |
| | } |
| |
|
| | SbBool NavigationStyle::processWheelEvent(const SoMouseWheelEvent* const event) |
| | { |
| | const SbVec2s pos(event->getPosition()); |
| | const SbVec2f posn = normalizePixelPos(pos); |
| |
|
| | |
| | doZoom(viewer->getSoRenderManager()->getCamera(), event->getDelta(), posn); |
| | return true; |
| | } |
| |
|
| | void NavigationStyle::setPopupMenuEnabled(const SbBool on) |
| | { |
| | this->menuenabled = on; |
| | } |
| |
|
| | SbBool NavigationStyle::isPopupMenuEnabled() const |
| | { |
| | return this->menuenabled; |
| | } |
| |
|
| | bool NavigationStyle::isNavigationStyleAction(QAction* action, QActionGroup* navMenuGroup) const |
| | { |
| | return action && navMenuGroup->actions().indexOf(action) >= 0 && action->isChecked(); |
| | } |
| |
|
| | QWidget* NavigationStyle::findView3DInventorWidget() const |
| | { |
| | QWidget* widget = viewer->getWidget(); |
| | while (widget && !widget->inherits("Gui::View3DInventor")) { |
| | widget = widget->parentWidget(); |
| | } |
| | return widget; |
| | } |
| |
|
| | void NavigationStyle::applyNavigationStyleChange(QAction* selectedAction) |
| | { |
| | QByteArray navigationStyleTypeName = selectedAction->data().toByteArray(); |
| | QWidget* view3DWidget = findView3DInventorWidget(); |
| |
|
| | if (view3DWidget) { |
| | Base::Type newNavigationStyle = Base::Type::fromName(navigationStyleTypeName.constData()); |
| | if (newNavigationStyle != this->getTypeId()) { |
| | QEvent* navigationChangeEvent = new NavigationStyleEvent(newNavigationStyle); |
| | QApplication::postEvent(view3DWidget, navigationChangeEvent); |
| | } |
| | } |
| | } |
| |
|
| | void NavigationStyle::openPopupMenu(const SbVec2s& position) |
| | { |
| | |
| | rightClickPosition = position; |
| |
|
| | |
| | MenuItem view; |
| | Gui::Application::Instance->setupContextMenu("View", &view); |
| |
|
| | auto contextMenu = new QMenu(viewer->getGLWidget()); |
| | MenuManager::getInstance()->setupContextMenu(&view, *contextMenu); |
| | contextMenu->setAttribute(Qt::WA_DeleteOnClose); |
| |
|
| | auto navMenu = contextMenu->addMenu(QObject::tr("Navigation styles")); |
| | auto navMenuGroup = new QActionGroup(navMenu); |
| |
|
| | |
| | const std::map<Base::Type, std::string> styles = UserNavigationStyle::getUserFriendlyNames(); |
| | for (const auto& style : styles) { |
| | const QString name = QApplication::translate(style.first.getName(), style.second.c_str()); |
| | QAction* item = navMenuGroup->addAction(name); |
| | navMenu->addAction(item); |
| | item->setCheckable(true); |
| | item->setData(QByteArray(style.first.getName())); |
| |
|
| | if (const Base::Type item_style = style.first; item_style != this->getTypeId()) { |
| | auto triggeredFun = [this, item_style]() { |
| | QWidget* widget = viewer->getWidget(); |
| | while (widget && !widget->inherits("Gui::View3DInventor")) { |
| | widget = widget->parentWidget(); |
| | } |
| | if (widget) { |
| | |
| | QEvent* ns_event = new NavigationStyleEvent(item_style); |
| | QApplication::postEvent(widget, ns_event); |
| | } |
| | }; |
| | item->connect(item, &QAction::triggered, triggeredFun); |
| | } |
| | else { |
| | item->setChecked(true); |
| | } |
| | } |
| |
|
| | |
| | bool separator = false; |
| | auto posAction = !contextMenu->actions().empty() ? contextMenu->actions().front() : nullptr; |
| |
|
| | |
| | SoRayPickAction rp(viewer->getSoRenderManager()->getViewportRegion()); |
| | rp.setPoint(position); |
| | rp.setRadius(viewer->getPickRadius()); |
| | rp.setPickAll(true); |
| | rp.apply(viewer->getSoRenderManager()->getSceneGraph()); |
| |
|
| | const SoPickedPointList& pplist = rp.getPickedPointList(); |
| | QAction* pickAction = nullptr; |
| |
|
| | if (pplist.getLength() > 0) { |
| | separator = true; |
| | if (auto cmd |
| | = Application::Instance->commandManager().getCommandByName("Std_ClarifySelection")) { |
| | pickAction = new QAction(cmd->getAction()->text(), contextMenu); |
| | pickAction->setShortcut(cmd->getAction()->shortcut()); |
| | } |
| | else { |
| | pickAction = new QAction(QObject::tr("Clarify Selection"), contextMenu); |
| | } |
| | if (posAction) { |
| | contextMenu->insertAction(posAction, pickAction); |
| | contextMenu->insertSeparator(posAction); |
| | } |
| | else { |
| | contextMenu->addAction(pickAction); |
| | } |
| | } |
| |
|
| | if (separator && posAction) { |
| | contextMenu->insertSeparator(posAction); |
| | } |
| |
|
| | auto navigationFunction = [this, navMenuGroup](QAction* selectedAction) { |
| | |
| | if (isNavigationStyleAction(selectedAction, navMenuGroup)) { |
| | applyNavigationStyleChange(selectedAction); |
| | rightClickPosition.reset(); |
| | } |
| | }; |
| |
|
| | auto clarifyFunction = [pickAction](QAction* selectedAction) { |
| | if (selectedAction == pickAction) { |
| | |
| | auto cmd = Application::Instance->commandManager().getCommandByName("Std_ClarifySelection"); |
| | if (cmd && cmd->isActive()) { |
| | cmd->invoke(0); |
| | } |
| | } |
| | }; |
| |
|
| | QObject::connect(contextMenu, &QMenu::triggered, navigationFunction); |
| | QObject::connect(contextMenu, &QMenu::triggered, clarifyFunction); |
| |
|
| | contextMenu->popup(QCursor::pos()); |
| |
|
| | rightClickPosition.reset(); |
| | } |
| |
|
| | PyObject* NavigationStyle::getPyObject() |
| | { |
| | if (pythonObject.is(nullptr)) { |
| | |
| | pythonObject = Py::asObject(new NavigationStylePy(this)); |
| | } |
| | return Py::new_reference_to(pythonObject); |
| | } |
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE_ABSTRACT(Gui::UserNavigationStyle, Gui::NavigationStyle) |
| |
|
| | std::string UserNavigationStyle::userFriendlyName() const |
| | { |
| | std::string name = this->getTypeId().getName(); |
| | |
| | std::size_t pos = name.rfind("::"); |
| | if (pos != std::string::npos) { |
| | name = name.substr(pos + 2); |
| | } |
| |
|
| | |
| | pos = name.find("NavigationStyle"); |
| | if (pos != std::string::npos) { |
| | name = name.substr(0, pos); |
| | } |
| | return name; |
| | } |
| |
|
| | std::map<Base::Type, std::string> UserNavigationStyle::getUserFriendlyNames() |
| | { |
| | std::map<Base::Type, std::string> names; |
| | std::vector<Base::Type> types; |
| | Base::Type::getAllDerivedFrom(UserNavigationStyle::getClassTypeId(), types); |
| |
|
| | for (auto& type : types) { |
| | if (type != UserNavigationStyle::getClassTypeId()) { |
| | std::unique_ptr<UserNavigationStyle> inst( |
| | static_cast<UserNavigationStyle*>(type.createInstance()) |
| | ); |
| | if (inst) { |
| | names[type] = inst->userFriendlyName(); |
| | } |
| | } |
| | } |
| | return names; |
| | } |
| |
|