diff --git a/kstars/skymapevents.cpp b/kstars/skymapevents.cpp index 45858a14e..08c340512 100644 --- a/kstars/skymapevents.cpp +++ b/kstars/skymapevents.cpp @@ -1,823 +1,823 @@ /*************************************************************************** skymapevents.cpp - K Desktop Planetarium ------------------- begin : Sat Feb 10 2001 copyright : (C) 2001 by Jason Harris email : jharris@30doradus.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //This file contains Event handlers for the SkyMap class. #include "skymap.h" #include "ksplanetbase.h" #include "kspopupmenu.h" #include "kstars.h" #include "observinglist.h" #include "Options.h" #include "skyglpainter.h" #include "skyqpainter.h" #include "printing/simplefovexporter.h" #include "skycomponents/skylabeler.h" #include "skycomponents/skymapcomposite.h" #include "skycomponents/starcomponent.h" #include "widgets/infoboxwidget.h" #include #include #include void SkyMap::resizeEvent(QResizeEvent *) { computeSkymap = true; // skymap must be new computed //FIXME: No equivalent for this line in Qt4 ?? // if ( testWState( Qt::WState_AutoMask ) ) updateMask(); // Resize the widget that draws the sky map. // FIXME: The resize event doesn't pass to children. Any better way of doing this? m_SkyMapDraw->resize(size()); // Resize infoboxes container. // FIXME: this is not really pretty. Maybe there are some better way to this??? m_iboxes->resize(size()); } void SkyMap::keyPressEvent(QKeyEvent *e) { bool arrowKeyPressed(false); bool shiftPressed(false); float step = 1.0; if (e->modifiers() & Qt::ShiftModifier) { step = 10.0; shiftPressed = true; } //If the DBus resume key is not empty, then DBus processing is //paused while we wait for a keypress if (!data->resumeKey.isEmpty() && QKeySequence(e->key()) == data->resumeKey) { //The resumeKey was pressed. Signal that it was pressed by //resetting it to empty; this will break the loop in //KStars::waitForKey() data->resumeKey = QKeySequence(); return; } if (m_previewLegend) { slotCancelLegendPreviewMode(); } switch (e->key()) { case Qt::Key_Left: if (Options::useAltAz()) { focus()->setAz(dms(focus()->az().Degrees() - step * MINZOOM / Options::zoomFactor()).reduce()); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { focus()->setRA(focus()->ra().Hours() + 0.05 * step * MINZOOM / Options::zoomFactor()); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } arrowKeyPressed = true; slewing = true; break; case Qt::Key_Right: if (Options::useAltAz()) { focus()->setAz(dms(focus()->az().Degrees() + step * MINZOOM / Options::zoomFactor()).reduce()); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { focus()->setRA(focus()->ra().Hours() - 0.05 * step * MINZOOM / Options::zoomFactor()); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } arrowKeyPressed = true; slewing = true; break; case Qt::Key_Up: if (Options::useAltAz()) { focus()->setAlt(focus()->alt().Degrees() + step * MINZOOM / Options::zoomFactor()); if (focus()->alt().Degrees() > 90.0) focus()->setAlt(90.0); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { focus()->setDec(focus()->dec().Degrees() + step * MINZOOM / Options::zoomFactor()); if (focus()->dec().Degrees() > 90.0) focus()->setDec(90.0); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } arrowKeyPressed = true; slewing = true; break; case Qt::Key_Down: if (Options::useAltAz()) { focus()->setAlt(focus()->alt().Degrees() - step * MINZOOM / Options::zoomFactor()); if (focus()->alt().Degrees() < -90.0) focus()->setAlt(-90.0); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { focus()->setDec(focus()->dec().Degrees() - step * MINZOOM / Options::zoomFactor()); if (focus()->dec().Degrees() < -90.0) focus()->setDec(-90.0); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } arrowKeyPressed = true; slewing = true; break; case Qt::Key_Plus: //Zoom in case Qt::Key_Equal: zoomInOrMagStep(e->modifiers()); break; case Qt::Key_Minus: //Zoom out case Qt::Key_Underscore: zoomOutOrMagStep(e->modifiers()); break; case Qt::Key_0: //center on Sun setClickedObject(data->skyComposite()->planet(KSPlanetBase::SUN)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_1: //center on Mercury setClickedObject(data->skyComposite()->planet(KSPlanetBase::MERCURY)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_2: //center on Venus setClickedObject(data->skyComposite()->planet(KSPlanetBase::VENUS)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_3: //center on Moon setClickedObject(data->skyComposite()->planet(KSPlanetBase::MOON)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_4: //center on Mars setClickedObject(data->skyComposite()->planet(KSPlanetBase::MARS)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_5: //center on Jupiter setClickedObject(data->skyComposite()->planet(KSPlanetBase::JUPITER)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_6: //center on Saturn setClickedObject(data->skyComposite()->planet(KSPlanetBase::SATURN)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_7: //center on Uranus setClickedObject(data->skyComposite()->planet(KSPlanetBase::URANUS)); setClickedPoint(clickedObject()); slotCenter(); break; case Qt::Key_8: //center on Neptune setClickedObject(data->skyComposite()->planet(KSPlanetBase::NEPTUNE)); setClickedPoint(clickedObject()); slotCenter(); break; /*case Qt::Key_9: //center on Pluto setClickedObject( data->skyComposite()->planet( KSPlanetBase::PLUTO ) ); setClickedPoint( clickedObject() ); slotCenter(); break;*/ case Qt::Key_BracketLeft: // Begin measuring angular distance if (!rulerMode) slotBeginAngularDistance(); break; case Qt::Key_Escape: // Cancel angular distance measurement { if (rulerMode) slotCancelRulerMode(); if (m_fovCaptureMode) slotFinishFovCaptureMode(); break; } case Qt::Key_C: //Center clicked object if (clickedObject()) slotCenter(); break; case Qt::Key_D: //Details window for Clicked/Centered object { SkyObject *orig = nullptr; if (shiftPressed) { orig = clickedObject(); setClickedObject(focusObject()); } if (clickedObject()) { slotDetail(); } if (orig) { setClickedObject(orig); } break; } case Qt::Key_P: //Show Popup menu for Clicked/Centered object if (shiftPressed) { if (focusObject()) focusObject()->showPopupMenu(pmenu, QCursor::pos()); } else { if (clickedObject()) clickedObject()->showPopupMenu(pmenu, QCursor::pos()); } break; case Qt::Key_O: //Add object to Observing List { SkyObject *orig = nullptr; if (shiftPressed) { orig = clickedObject(); setClickedObject(focusObject()); } if (clickedObject()) { data->observingList()->slotAddObject(); } if (orig) { setClickedObject(orig); } break; } case Qt::Key_L: //Toggle User label on Clicked/Centered object { SkyObject *orig = nullptr; if (shiftPressed) { orig = clickedObject(); setClickedObject(focusObject()); } if (clickedObject()) { if (isObjectLabeled(clickedObject())) slotRemoveObjectLabel(); else slotAddObjectLabel(); } if (orig) { setClickedObject(orig); } break; } case Qt::Key_T: //Toggle planet trail on Clicked/Centered object (if solsys) { SkyObject *orig = nullptr; if (shiftPressed) { orig = clickedObject(); setClickedObject(focusObject()); } KSPlanetBase *planet = dynamic_cast(clickedObject()); if (planet) { if (planet->hasTrail()) slotRemovePlanetTrail(); else slotAddPlanetTrail(); } if (orig) { setClickedObject(orig); } break; } case Qt::Key_R: { // Toggle relativistic corrections Options::setUseRelativistic(!Options::useRelativistic()); qDebug() << "Relativistc corrections: " << Options::useRelativistic(); forceUpdate(); break; } case Qt::Key_A: Options::setUseAntialias(!Options::useAntialias()); qDebug() << "Use Antialiasing: " << Options::useAntialias(); forceUpdate(); break; case Qt::Key_K: { if (m_fovCaptureMode) slotCaptureFov(); break; } case Qt::Key_PageUp: { KStars::Instance()->selectPreviousFov(); break; } case Qt::Key_PageDown: { KStars::Instance()->selectNextFov(); break; } default: // We don't want to do anything in this case. Key is unknown return; } if (arrowKeyPressed) { stopTracking(); setDestination(*focus()); } forceUpdate(); //need a total update, or slewing with the arrow keys doesn't work. } void SkyMap::stopTracking() { KStars *kstars = KStars::Instance(); emit positionChanged(focus()); if (kstars && Options::isTracking()) kstars->slotTrack(); } bool SkyMap::event(QEvent *event) { #if !defined(KSTARS_LITE) if (event->type() == QEvent::TouchBegin) { m_touchMode = true; m_pinchScale = -1; } - if (event->type() == QEvent::Gesture) + if (event->type() == QEvent::Gesture && m_touchMode) { QGestureEvent* gestureEvent = static_cast(event); if (QPinchGesture *pinch = static_cast(gestureEvent->gesture(Qt::PinchGesture))) { QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags(); m_pinchMode = true; if (changeFlags & QPinchGesture::ScaleFactorChanged) { if (m_pinchScale == -1) { m_pinchScale = pinch->totalScaleFactor(); return true; } if (pinch->totalScaleFactor()-m_pinchScale > 0.1) { m_pinchScale = pinch->totalScaleFactor(); zoomInOrMagStep(0); return true; } if (pinch->totalScaleFactor()-m_pinchScale < -0.1) { m_pinchScale = pinch->totalScaleFactor(); zoomOutOrMagStep(0); return true; } } } if (QTapAndHoldGesture *tapAndHold = static_cast(gestureEvent->gesture(Qt::TapAndHoldGesture))) { m_tapAndHoldMode = true; if (tapAndHold->state() == Qt::GestureFinished) { if (clickedObject()) { clickedObject()->showPopupMenu(pmenu, tapAndHold->position().toPoint()); } else { pmenu->createEmptyMenu(clickedPoint()); pmenu->popup(tapAndHold->position().toPoint()); } m_touchMode = false; m_pinchMode = false; m_tapAndHoldMode = false; } } return true; } #endif return QGraphicsView::event(event); } void SkyMap::keyReleaseEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Plus: //Zoom in case Qt::Key_Equal: case Qt::Key_Minus: //Zoom out case Qt::Key_Underscore: case Qt::Key_Left: //no break; continue to Qt::Key_Down case Qt::Key_Right: //no break; continue to Qt::Key_Down case Qt::Key_Up: //no break; continue to Qt::Key_Down case Qt::Key_Down: slewing = false; if (Options::useAltAz()) setDestinationAltAz(focus()->alt(), focus()->az()); else setDestination(*focus()); showFocusCoords(); forceUpdate(); // Need a full update to draw faint objects that are not drawn while slewing. break; } } void SkyMap::mouseMoveEvent(QMouseEvent *e) { #if !defined(KSTARS_LITE) // Skip touch points if (m_pinchMode || m_tapAndHoldMode || (m_touchMode && e->globalX() == 0 && e->globalY() == 0)) return; #endif if (Options::useHoverLabel()) { //Start a single-shot timer to monitor whether we are currently hovering. //The idea is that whenever a moveEvent occurs, the timer is reset. It //will only timeout if there are no move events for HOVER_INTERVAL ms m_HoverTimer.start(HOVER_INTERVAL); QToolTip::hideText(); } //Are we defining a ZoomRect? if (ZoomRect.center().x() > 0 && ZoomRect.center().y() > 0) { //cancel operation if the user let go of CTRL if (!(e->modifiers() & Qt::ControlModifier)) { ZoomRect = QRect(); //invalidate ZoomRect update(); } else { //Resize the rectangle so that it passes through the cursor position QPoint pcenter = ZoomRect.center(); int dx = abs(e->x() - pcenter.x()); int dy = abs(e->y() - pcenter.y()); if (dx == 0 || float(dy) / float(dx) > float(height()) / float(width())) { //Size rect by height ZoomRect.setHeight(2 * dy); ZoomRect.setWidth(2 * dy * width() / height()); } else { //Size rect by height ZoomRect.setWidth(2 * dx); ZoomRect.setHeight(2 * dx * height() / width()); } ZoomRect.moveCenter(pcenter); //reset center update(); return; } } if (projector()->unusablePoint(e->pos())) return; // break if point is unusable //determine RA, Dec of mouse pointer m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat()); double dyPix = 0.5 * height() - e->y(); if (midMouseButtonDown) //zoom according to y-offset { float yoff = dyPix - y0; if (yoff > 10) { y0 = dyPix; slotZoomIn(); } if (yoff < -10) { y0 = dyPix; slotZoomOut(); } } if (mouseButtonDown) { // set the mouseMoveCursor and set slewing=true, if they are not set yet if (!mouseMoveCursor) setMouseMoveCursor(); if (!slewing) { slewing = true; stopTracking(); //toggle tracking off } //Update focus such that the sky coords at mouse cursor remain approximately constant if (Options::useAltAz()) { m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat()); clickedPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); dms dAz = m_MousePoint.az() - clickedPoint()->az(); dms dAlt = m_MousePoint.alt() - clickedPoint()->alt(); focus()->setAz(focus()->az().Degrees() - dAz.Degrees()); //move focus in opposite direction focus()->setAz(focus()->az().reduce()); focus()->setAlt(KSUtils::clamp(focus()->alt().Degrees() - dAlt.Degrees(), -90.0, 90.0)); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { dms dRA = m_MousePoint.ra() - clickedPoint()->ra(); dms dDec = m_MousePoint.dec() - clickedPoint()->dec(); focus()->setRA(focus()->ra().Hours() - dRA.Hours()); //move focus in opposite direction focus()->setRA(focus()->ra().reduce()); focus()->setDec(KSUtils::clamp(focus()->dec().Degrees() - dDec.Degrees(), -90.0, 90.0)); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } showFocusCoords(); //redetermine RA, Dec of mouse pointer, using new focus m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat()); setClickedPoint(&m_MousePoint); forceUpdate(); // must be new computed } else //mouse button not down { if (Options::useAltAz()) m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat()); emit mousePointChanged(&m_MousePoint); } } void SkyMap::wheelEvent(QWheelEvent *e) { if (e->delta() > 0) zoomInOrMagStep(e->modifiers()); else if (e->delta() < 0) zoomOutOrMagStep(e->modifiers()); } void SkyMap::mouseReleaseEvent(QMouseEvent *) { #if !defined(KSTARS_LITE) if (m_touchMode) { m_touchMode = false; m_pinchMode = false; m_tapAndHoldMode = false; } #endif if (ZoomRect.isValid()) { stopTracking(); SkyPoint newcenter = projector()->fromScreen(ZoomRect.center(), data->lst(), data->geo()->lat()); setFocus(&newcenter); setDestination(newcenter); //Zoom in on center of Zoom Circle, by a factor equal to the ratio //of the sky pixmap's width to the Zoom Circle's diameter float factor = float(width()) / float(ZoomRect.width()); setZoomFactor(Options::zoomFactor() * factor); } setDefaultMouseCursor(); ZoomRect = QRect(); //invalidate ZoomRect if (m_previewLegend) { slotCancelLegendPreviewMode(); } //false if double-clicked, because it's unset there. if (mouseButtonDown) { mouseButtonDown = false; if (slewing) { slewing = false; if (Options::useAltAz()) setDestinationAltAz(focus()->alt(), focus()->az()); else setDestination(*focus()); } forceUpdate(); // is needed because after moving the sky not all stars are shown } // if middle button was pressed unset here midMouseButtonDown = false; } void SkyMap::mousePressEvent(QMouseEvent *e) { KStars *kstars = KStars::Instance(); if ((e->modifiers() & Qt::ControlModifier) && (e->button() == Qt::LeftButton)) { ZoomRect.moveCenter(e->pos()); setZoomMouseCursor(); update(); //refresh without redrawing skymap return; } // if button is down and cursor is not moved set the move cursor after 500 ms QTimer::singleShot(500, this, SLOT(setMouseMoveCursor())); // break if point is unusable if (projector()->unusablePoint(e->pos())) return; if (!midMouseButtonDown && e->button() == Qt::MidButton) { y0 = 0.5 * height() - e->y(); //record y pixel coordinate for middle-button zooming midMouseButtonDown = true; } if (!mouseButtonDown) { if (e->button() == Qt::LeftButton) { mouseButtonDown = true; } //determine RA, Dec of mouse pointer m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat()); setClickedPoint(&m_MousePoint); //Find object nearest to clickedPoint() double maxrad = 1000.0 / Options::zoomFactor(); SkyObject *obj = data->skyComposite()->objectNearest(clickedPoint(), maxrad); setClickedObject(obj); if (obj) setClickedPoint(obj); switch (e->button()) { case Qt::LeftButton: { QString name; if (clickedObject()) { name = clickedObject()->translatedLongName(); emit objectClicked(clickedObject()); } else name = i18n("Empty sky"); //kstars->statusBar()->changeItem(name, 0 ); kstars->statusBar()->showMessage(name, 0); emit positionClicked(&m_MousePoint); } break; case Qt::RightButton: if (rulerMode) { // Compute angular distance. slotEndRulerMode(); } else { // Show popup menu if (clickedObject()) { clickedObject()->showPopupMenu(pmenu, QCursor::pos()); } else { pmenu->createEmptyMenu(clickedPoint()); pmenu->popup(QCursor::pos()); } } break; default:; } } } void SkyMap::mouseDoubleClickEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton && !projector()->unusablePoint(e->pos())) { mouseButtonDown = false; if (e->x() != width() / 2 || e->y() != height() / 2) slotCenter(); } } double SkyMap::zoomFactor(const int modifier) { double factor = (modifier & Qt::ControlModifier) ? DZOOM : (Options::zoomScrollFactor() + 1); if (modifier & Qt::ShiftModifier) factor = sqrt(factor); return factor; } void SkyMap::zoomInOrMagStep(const int modifier) { if (modifier & Qt::AltModifier) incMagLimit(modifier); else setZoomFactor(Options::zoomFactor() * zoomFactor(modifier)); } void SkyMap::zoomOutOrMagStep(const int modifier) { if (modifier & Qt::AltModifier) decMagLimit(modifier); else setZoomFactor(Options::zoomFactor() / zoomFactor(modifier)); } double SkyMap::magFactor(const int modifier) { double factor = (modifier & Qt::ControlModifier) ? 0.1 : 0.5; if (modifier & Qt::ShiftModifier) factor *= 2.0; return factor; } void SkyMap::incMagLimit(const int modifier) { double limit = 2.222 * log10(static_cast(Options::starDensity())) + 0.35; limit += magFactor(modifier); if (limit > 5.75954) limit = 5.75954; Options::setStarDensity(pow(10, (limit - 0.35) / 2.222)); //printf("maglim set to %3.1f\n", limit); forceUpdate(); } void SkyMap::decMagLimit(const int modifier) { double limit = 2.222 * log10(static_cast(Options::starDensity())) + 0.35; limit -= magFactor(modifier); if (limit < 1.18778) limit = 1.18778; Options::setStarDensity(pow(10, (limit - 0.35) / 2.222)); //printf("maglim set to %3.1f\n", limit); forceUpdate(); }