File indexing completed on 2022-12-06 18:58:53

0001 /*
0002     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 //This file contains Event handlers for the SkyMap class.
0008 
0009 #include "skymap.h"
0010 
0011 #include "ksplanetbase.h"
0012 #include "kspopupmenu.h"
0013 #include "kstars.h"
0014 #include "observinglist.h"
0015 #include "Options.h"
0016 #include "skyglpainter.h"
0017 #include "skyqpainter.h"
0018 #include "printing/simplefovexporter.h"
0019 #include "skycomponents/skylabeler.h"
0020 #include "skycomponents/skymapcomposite.h"
0021 #include "skycomponents/starcomponent.h"
0022 #include "skycomponents/mosaiccomponent.h"
0023 #ifdef HAVE_INDI
0024 #include "skyobjects/mosaictiles.h"
0025 #endif
0026 #include "widgets/infoboxwidget.h"
0027 
0028 #include <QGestureEvent>
0029 #include <QStatusBar>
0030 #include <QToolTip>
0031 
0032 void SkyMap::resizeEvent(QResizeEvent *)
0033 {
0034     computeSkymap = true; // skymap must be new computed
0035 
0036     //FIXME: No equivalent for this line in Qt4 ??
0037     //  if ( testWState( Qt::WState_AutoMask ) ) updateMask();
0038 
0039     // Resize the widget that draws the sky map.
0040     // FIXME: The resize event doesn't pass to children. Any better way of doing this?
0041     m_SkyMapDraw->resize(size());
0042 
0043     // Resize infoboxes container.
0044     // FIXME: this is not really pretty. Maybe there are some better way to this???
0045     m_iboxes->resize(size());
0046 }
0047 
0048 void SkyMap::keyPressEvent(QKeyEvent *e)
0049 {
0050     bool arrowKeyPressed(false);
0051     bool shiftPressed(false);
0052     float step = 1.0;
0053     if (e->modifiers() & Qt::ShiftModifier)
0054     {
0055         step         = 10.0;
0056         shiftPressed = true;
0057     }
0058 
0059     //If the DBus resume key is not empty, then DBus processing is
0060     //paused while we wait for a keypress
0061     if (!data->resumeKey.isEmpty() && QKeySequence(e->key()) == data->resumeKey)
0062     {
0063         //The resumeKey was pressed.  Signal that it was pressed by
0064         //resetting it to empty; this will break the loop in
0065         //KStars::waitForKey()
0066         data->resumeKey = QKeySequence();
0067         return;
0068     }
0069 
0070     if (m_previewLegend)
0071     {
0072         slotCancelLegendPreviewMode();
0073     }
0074 
0075     switch (e->key())
0076     {
0077         case Qt::Key_Left:
0078             if (Options::useAltAz())
0079             {
0080                 focus()->setAz(dms(focus()->az().Degrees() - step * MINZOOM / Options::zoomFactor()).reduce());
0081                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0082             }
0083             else
0084             {
0085                 focus()->setRA(focus()->ra().Hours() + 0.05 * step * MINZOOM / Options::zoomFactor());
0086                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0087             }
0088 
0089             arrowKeyPressed = true;
0090             slewing         = true;
0091             break;
0092 
0093         case Qt::Key_Right:
0094             if (Options::useAltAz())
0095             {
0096                 focus()->setAz(dms(focus()->az().Degrees() + step * MINZOOM / Options::zoomFactor()).reduce());
0097                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0098             }
0099             else
0100             {
0101                 focus()->setRA(focus()->ra().Hours() - 0.05 * step * MINZOOM / Options::zoomFactor());
0102                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0103             }
0104 
0105             arrowKeyPressed = true;
0106             slewing         = true;
0107             break;
0108 
0109         case Qt::Key_Up:
0110             if (Options::useAltAz())
0111             {
0112                 focus()->setAltRefracted(focus()->altRefracted().Degrees() + step * MINZOOM / Options::zoomFactor());
0113                 if (focus()->alt().Degrees() > 90.0)
0114                     focus()->setAlt(90.0);
0115                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0116             }
0117             else
0118             {
0119                 focus()->setDec(focus()->dec().Degrees() + step * MINZOOM / Options::zoomFactor());
0120                 if (focus()->dec().Degrees() > 90.0)
0121                     focus()->setDec(90.0);
0122                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0123             }
0124 
0125             arrowKeyPressed = true;
0126             slewing         = true;
0127             break;
0128 
0129         case Qt::Key_Down:
0130             if (Options::useAltAz())
0131             {
0132                 focus()->setAltRefracted(focus()->altRefracted().Degrees() - step * MINZOOM / Options::zoomFactor());
0133                 if (focus()->alt().Degrees() < -90.0)
0134                     focus()->setAlt(-90.0);
0135                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0136             }
0137             else
0138             {
0139                 focus()->setDec(focus()->dec().Degrees() - step * MINZOOM / Options::zoomFactor());
0140                 if (focus()->dec().Degrees() < -90.0)
0141                     focus()->setDec(-90.0);
0142                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0143             }
0144 
0145             arrowKeyPressed = true;
0146             slewing         = true;
0147             break;
0148 
0149         case Qt::Key_Plus: //Zoom in
0150         case Qt::Key_Equal:
0151             zoomInOrMagStep(e->modifiers());
0152             break;
0153 
0154         case Qt::Key_Minus: //Zoom out
0155         case Qt::Key_Underscore:
0156             zoomOutOrMagStep(e->modifiers());
0157             break;
0158 
0159         case Qt::Key_0: //center on Sun
0160             setClickedObject(data->skyComposite()->planet(KSPlanetBase::SUN));
0161             setClickedPoint(clickedObject());
0162             slotCenter();
0163             break;
0164 
0165         case Qt::Key_1: //center on Mercury
0166             setClickedObject(data->skyComposite()->planet(KSPlanetBase::MERCURY));
0167             setClickedPoint(clickedObject());
0168             slotCenter();
0169             break;
0170 
0171         case Qt::Key_2: //center on Venus
0172             setClickedObject(data->skyComposite()->planet(KSPlanetBase::VENUS));
0173             setClickedPoint(clickedObject());
0174             slotCenter();
0175             break;
0176 
0177         case Qt::Key_3: //center on Moon
0178             setClickedObject(data->skyComposite()->planet(KSPlanetBase::MOON));
0179             setClickedPoint(clickedObject());
0180             slotCenter();
0181             break;
0182 
0183         case Qt::Key_4: //center on Mars
0184             setClickedObject(data->skyComposite()->planet(KSPlanetBase::MARS));
0185             setClickedPoint(clickedObject());
0186             slotCenter();
0187             break;
0188 
0189         case Qt::Key_5: //center on Jupiter
0190             setClickedObject(data->skyComposite()->planet(KSPlanetBase::JUPITER));
0191             setClickedPoint(clickedObject());
0192             slotCenter();
0193             break;
0194 
0195         case Qt::Key_6: //center on Saturn
0196             setClickedObject(data->skyComposite()->planet(KSPlanetBase::SATURN));
0197             setClickedPoint(clickedObject());
0198             slotCenter();
0199             break;
0200 
0201         case Qt::Key_7: //center on Uranus
0202             setClickedObject(data->skyComposite()->planet(KSPlanetBase::URANUS));
0203             setClickedPoint(clickedObject());
0204             slotCenter();
0205             break;
0206 
0207         case Qt::Key_8: //center on Neptune
0208             setClickedObject(data->skyComposite()->planet(KSPlanetBase::NEPTUNE));
0209             setClickedPoint(clickedObject());
0210             slotCenter();
0211             break;
0212 
0213         /*case Qt::Key_9: //center on Pluto
0214             setClickedObject( data->skyComposite()->planet( KSPlanetBase::PLUTO ) );
0215             setClickedPoint( clickedObject() );
0216             slotCenter();
0217             break;*/
0218 
0219         case Qt::Key_BracketLeft: // Begin measuring angular distance
0220             if (!rulerMode)
0221                 slotBeginAngularDistance();
0222             break;
0223         case Qt::Key_Escape: // Cancel angular distance measurement
0224         {
0225             if (rulerMode)
0226                 slotCancelRulerMode();
0227 
0228             if (m_fovCaptureMode)
0229                 slotFinishFovCaptureMode();
0230             break;
0231         }
0232 
0233         case Qt::Key_C: //Center clicked object
0234             if (clickedObject())
0235                 slotCenter();
0236             break;
0237 
0238         case Qt::Key_D: //Details window for Clicked/Centered object
0239         {
0240             SkyObject *orig = nullptr;
0241             if (shiftPressed)
0242             {
0243                 orig = clickedObject();
0244                 setClickedObject(focusObject());
0245             }
0246 
0247             if (clickedObject())
0248             {
0249                 slotDetail();
0250             }
0251 
0252             if (orig)
0253             {
0254                 setClickedObject(orig);
0255             }
0256             break;
0257         }
0258 
0259         case Qt::Key_P: //Show Popup menu for Clicked/Centered object
0260             if (shiftPressed)
0261             {
0262                 if (focusObject())
0263                     focusObject()->showPopupMenu(pmenu, QCursor::pos());
0264             }
0265             else
0266             {
0267                 if (clickedObject())
0268                     clickedObject()->showPopupMenu(pmenu, QCursor::pos());
0269             }
0270             break;
0271 
0272         case Qt::Key_O: //Add object to Observing List
0273         {
0274             SkyObject *orig = nullptr;
0275             if (shiftPressed)
0276             {
0277                 orig = clickedObject();
0278                 setClickedObject(focusObject());
0279             }
0280 
0281             if (clickedObject())
0282             {
0283                 data->observingList()->slotAddObject();
0284             }
0285 
0286             if (orig)
0287             {
0288                 setClickedObject(orig);
0289             }
0290             break;
0291         }
0292 
0293         case Qt::Key_L: //Toggle User label on Clicked/Centered object
0294         {
0295             SkyObject *orig = nullptr;
0296             if (shiftPressed)
0297             {
0298                 orig = clickedObject();
0299                 setClickedObject(focusObject());
0300             }
0301 
0302             if (clickedObject())
0303             {
0304                 if (isObjectLabeled(clickedObject()))
0305                     slotRemoveObjectLabel();
0306                 else
0307                     slotAddObjectLabel();
0308             }
0309 
0310             if (orig)
0311             {
0312                 setClickedObject(orig);
0313             }
0314             break;
0315         }
0316 
0317         case Qt::Key_T: //Toggle planet trail on Clicked/Centered object (if solsys)
0318         {
0319             SkyObject *orig = nullptr;
0320             if (shiftPressed)
0321             {
0322                 orig = clickedObject();
0323                 setClickedObject(focusObject());
0324             }
0325 
0326             KSPlanetBase *planet = dynamic_cast<KSPlanetBase *>(clickedObject());
0327             if (planet)
0328             {
0329                 if (planet->hasTrail())
0330                     slotRemovePlanetTrail();
0331                 else
0332                     slotAddPlanetTrail();
0333             }
0334 
0335             if (orig)
0336             {
0337                 setClickedObject(orig);
0338             }
0339             break;
0340         }
0341 
0342         case Qt::Key_R:
0343         {
0344             // Toggle relativistic corrections
0345             Options::setUseRelativistic(!Options::useRelativistic());
0346             qDebug() << Q_FUNC_INFO << "Relativistic corrections: " << Options::useRelativistic();
0347             forceUpdate();
0348             break;
0349         }
0350 
0351         case Qt::Key_A:
0352             Options::setUseAntialias(!Options::useAntialias());
0353             qDebug() << Q_FUNC_INFO << "Use Antialiasing: " << Options::useAntialias();
0354             forceUpdate();
0355             break;
0356 
0357         case Qt::Key_K:
0358         {
0359             if (m_fovCaptureMode)
0360                 slotCaptureFov();
0361             break;
0362         }
0363 
0364         case Qt::Key_PageUp:
0365         {
0366             KStars::Instance()->selectPreviousFov();
0367             break;
0368         }
0369 
0370         case Qt::Key_PageDown:
0371         {
0372             KStars::Instance()->selectNextFov();
0373             break;
0374         }
0375 
0376         default:
0377             // We don't want to do anything in this case. Key is unknown
0378             return;
0379     }
0380 
0381     if (arrowKeyPressed)
0382     {
0383         stopTracking();
0384         setDestination(*focus());
0385     }
0386 
0387     forceUpdate(); //need a total update, or slewing with the arrow keys doesn't work.
0388 }
0389 
0390 void SkyMap::stopTracking()
0391 {
0392     KStars *kstars = KStars::Instance();
0393 
0394     emit positionChanged(focus());
0395     if (kstars && Options::isTracking())
0396         kstars->slotTrack();
0397 }
0398 
0399 bool SkyMap::event(QEvent *event)
0400 {
0401 #if !defined(KSTARS_LITE)
0402     if (event->type() == QEvent::TouchBegin)
0403     {
0404         m_touchMode = true;
0405         m_pinchScale = -1;
0406     }
0407 
0408     if (event->type() == QEvent::Gesture && m_touchMode)
0409     {
0410         QGestureEvent* gestureEvent = static_cast<QGestureEvent*>(event);
0411 
0412         if (QPinchGesture *pinch = static_cast<QPinchGesture*>(gestureEvent->gesture(Qt::PinchGesture)))
0413         {
0414             QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags();
0415 
0416             m_pinchMode = true;
0417             if (changeFlags & QPinchGesture::ScaleFactorChanged)
0418             {
0419                 if (m_pinchScale == -1)
0420                 {
0421                     m_pinchScale = pinch->totalScaleFactor();
0422                     return true;
0423                 }
0424                 if (pinch->totalScaleFactor() - m_pinchScale > 0.1)
0425                 {
0426                     m_pinchScale = pinch->totalScaleFactor();
0427                     zoomInOrMagStep(0);
0428                     return true;
0429                 }
0430                 if (pinch->totalScaleFactor() - m_pinchScale < -0.1)
0431                 {
0432                     m_pinchScale = pinch->totalScaleFactor();
0433                     zoomOutOrMagStep(0);
0434                     return true;
0435                 }
0436             }
0437         }
0438         if (QTapAndHoldGesture *tapAndHold = static_cast<QTapAndHoldGesture*>(gestureEvent->gesture(Qt::TapAndHoldGesture)))
0439         {
0440             m_tapAndHoldMode = true;
0441             if (tapAndHold->state() == Qt::GestureFinished)
0442             {
0443                 if (clickedObject())
0444                 {
0445                     clickedObject()->showPopupMenu(pmenu, tapAndHold->position().toPoint());
0446                 }
0447                 else
0448                 {
0449                     pmenu->createEmptyMenu(clickedPoint());
0450                     pmenu->popup(tapAndHold->position().toPoint());
0451                 }
0452                 m_touchMode = false;
0453                 m_pinchMode = false;
0454                 m_tapAndHoldMode = false;
0455             }
0456         }
0457         return true;
0458     }
0459 #endif
0460     return QGraphicsView::event(event);
0461 }
0462 
0463 void SkyMap::keyReleaseEvent(QKeyEvent *e)
0464 {
0465     switch (e->key())
0466     {
0467         case Qt::Key_Plus: //Zoom in
0468         case Qt::Key_Equal:
0469         case Qt::Key_Minus: //Zoom out
0470         case Qt::Key_Underscore:
0471 
0472         case Qt::Key_Left:  //no break; continue to Qt::Key_Down
0473         case Qt::Key_Right: //no break; continue to Qt::Key_Down
0474         case Qt::Key_Up:    //no break; continue to Qt::Key_Down
0475         case Qt::Key_Down:
0476             slewing = false;
0477 
0478             if (Options::useAltAz())
0479                 setDestinationAltAz(focus()->alt(), focus()->az(), false);
0480             else
0481                 setDestination(*focus());
0482 
0483             showFocusCoords();
0484             forceUpdate(); // Need a full update to draw faint objects that are not drawn while slewing.
0485             break;
0486     }
0487 }
0488 
0489 void SkyMap::mouseMoveEvent(QMouseEvent *e)
0490 {
0491 #if !defined(KSTARS_LITE)
0492     // Skip touch points
0493     if (m_pinchMode || m_tapAndHoldMode || (m_touchMode && e->globalX() == 0 && e->globalY() == 0))
0494         return;
0495 #endif
0496 
0497     if (Options::useHoverLabel())
0498     {
0499         //Start a single-shot timer to monitor whether we are currently hovering.
0500         //The idea is that whenever a moveEvent occurs, the timer is reset.  It
0501         //will only timeout if there are no move events for HOVER_INTERVAL ms
0502         m_HoverTimer.start(HOVER_INTERVAL);
0503         QToolTip::hideText();
0504     }
0505 
0506     //Are we defining a ZoomRect?
0507     if (ZoomRect.center().x() > 0 && ZoomRect.center().y() > 0)
0508     {
0509         //cancel operation if the user let go of CTRL
0510         if (!(e->modifiers() & Qt::ControlModifier))
0511         {
0512             ZoomRect = QRect(); //invalidate ZoomRect
0513             update();
0514         }
0515         else
0516         {
0517             //Resize the rectangle so that it passes through the cursor position
0518             QPoint pcenter = ZoomRect.center();
0519             int dx         = abs(e->x() - pcenter.x());
0520             int dy         = abs(e->y() - pcenter.y());
0521             if (dx == 0 || float(dy) / float(dx) > float(height()) / float(width()))
0522             {
0523                 //Size rect by height
0524                 ZoomRect.setHeight(2 * dy);
0525                 ZoomRect.setWidth(2 * dy * width() / height());
0526             }
0527             else
0528             {
0529                 //Size rect by height
0530                 ZoomRect.setWidth(2 * dx);
0531                 ZoomRect.setHeight(2 * dx * height() / width());
0532             }
0533             ZoomRect.moveCenter(pcenter); //reset center
0534 
0535             update();
0536             return;
0537         }
0538     }
0539 
0540     if (projector()->unusablePoint(e->pos()))
0541         return; // break if point is unusable
0542 
0543     //determine RA, Dec of mouse pointer
0544     m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
0545 
0546     double dyPix = 0.5 * height() - e->y();
0547     if (midMouseButtonDown) //zoom according to y-offset
0548     {
0549         float yoff = dyPix - y0;
0550         if (yoff > 10)
0551         {
0552             y0 = dyPix;
0553             slotZoomIn();
0554         }
0555         if (yoff < -10)
0556         {
0557             y0 = dyPix;
0558             slotZoomOut();
0559         }
0560     }
0561 
0562     if (mouseButtonDown)
0563     {
0564 #ifdef HAVE_INDI
0565         if (Options::showMosaicPanel())
0566         {
0567             auto tiles = KStarsData::Instance()->skyComposite()->mosaicComponent()->tiles();
0568 
0569             if (tiles->operationMode() == MosaicTiles::MODE_PLANNING)
0570             {
0571                 // Check if mouse point within Mosaic FOV bounds.
0572                 auto mosaicFOV = tiles->mosaicFOV();
0573                 auto upperRA = tiles->ra0().Degrees() + mosaicFOV.width() / 60;
0574                 auto lowerRA = tiles->ra0().Degrees() - mosaicFOV.width() / 60;
0575                 auto upperDE = tiles->dec0().Degrees() + mosaicFOV.height() / 60;
0576                 auto lowerDE = tiles->dec0().Degrees() - mosaicFOV.height() / 60;
0577 
0578                 auto mouseRA = m_MousePoint.ra().Degrees();
0579                 auto mouseDE = m_MousePoint.dec().Degrees();
0580 
0581                 // If mouse point is within, then behave like drag and drop
0582                 if (mouseRA > lowerRA && mouseRA < upperRA && mouseDE > lowerDE && mouseDE < upperDE)
0583                 {
0584                     if (!mouseDragCursor)
0585                         setMouseDragCursor();
0586 
0587                     dms dRA  = m_MousePoint.ra() - clickedPoint()->ra();
0588                     dms dDec = m_MousePoint.dec() - clickedPoint()->dec();
0589 
0590                     // Emit difference between mouse point and clicked point.
0591                     emit mosaicCenterChanged(dRA, dDec);
0592 
0593                     // Update mouse and clicked points.
0594                     m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
0595                     setClickedPoint(&m_MousePoint);
0596                     update();
0597                     return;
0598                 }
0599             }
0600         }
0601 #endif
0602 
0603         // set the mouseMoveCursor and set slewing=true, if they are not set yet
0604         if (!mouseMoveCursor)
0605             setMouseMoveCursor();
0606         if (!slewing)
0607         {
0608             slewing = true;
0609             stopTracking(); //toggle tracking off
0610         }
0611 
0612         //Update focus such that the sky coords at mouse cursor remain approximately constant
0613         if (Options::useAltAz())
0614         {
0615             m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat());
0616             clickedPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0617             dms dAz  = m_MousePoint.az() - clickedPoint()->az();
0618             dms dAlt = m_MousePoint.altRefracted() - clickedPoint()->altRefracted();
0619             focus()->setAz(focus()->az().Degrees() - dAz.Degrees()); //move focus in opposite direction
0620             focus()->setAz(focus()->az().reduce());
0621             focus()->setAltRefracted(KSUtils::clamp(focus()->altRefracted().Degrees() - dAlt.Degrees(), -90.0, 90.0));
0622             focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
0623         }
0624         else
0625         {
0626             dms dRA  = m_MousePoint.ra() - clickedPoint()->ra();
0627             dms dDec = m_MousePoint.dec() - clickedPoint()->dec();
0628             focus()->setRA(focus()->ra().Hours() - dRA.Hours()); //move focus in opposite direction
0629             focus()->setRA(focus()->ra().reduce());
0630             focus()->setDec(KSUtils::clamp(focus()->dec().Degrees() - dDec.Degrees(), -90.0, 90.0));
0631             focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0632         }
0633         showFocusCoords();
0634 
0635         //redetermine RA, Dec of mouse pointer, using new focus
0636         m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
0637         setClickedPoint(&m_MousePoint);
0638         forceUpdate(); // must be new computed
0639     }
0640     else //mouse button not down
0641     {
0642         if (Options::useAltAz())
0643             m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat());
0644         emit mousePointChanged(&m_MousePoint);
0645     }
0646 }
0647 
0648 void SkyMap::wheelEvent(QWheelEvent *e)
0649 {
0650     if (e->angleDelta().y() > 0)
0651         zoomInOrMagStep(e->modifiers());
0652     else if (e->angleDelta().y() < 0)
0653         zoomOutOrMagStep(e->modifiers());
0654 }
0655 
0656 void SkyMap::mouseReleaseEvent(QMouseEvent *e)
0657 {
0658 #if !defined(KSTARS_LITE)
0659     if (m_touchMode)
0660     {
0661         m_touchMode = false;
0662         m_pinchMode = false;
0663         m_tapAndHoldMode = false;
0664     }
0665 #endif
0666 
0667     if (ZoomRect.isValid())
0668     {
0669         stopTracking();
0670         SkyPoint newcenter = projector()->fromScreen(ZoomRect.center(), data->lst(), data->geo()->lat());
0671         setFocus(&newcenter);
0672         setDestination(newcenter);
0673 
0674         //Zoom in on center of Zoom Circle, by a factor equal to the ratio
0675         //of the sky pixmap's width to the Zoom Circle's diameter
0676         float factor = float(width()) / float(ZoomRect.width());
0677         setZoomFactor(Options::zoomFactor() * factor);
0678     }
0679 
0680     setMouseCursorShape(static_cast<Cursor>(Options::defaultCursor()));
0681 
0682     ZoomRect = QRect(); //invalidate ZoomRect
0683 
0684     if (m_previewLegend)
0685     {
0686         slotCancelLegendPreviewMode();
0687     }
0688 
0689     //false if double-clicked, because it's unset there.
0690     if (mouseButtonDown)
0691     {
0692         mouseButtonDown = false;
0693         if (slewing)
0694         {
0695             slewing = false;
0696             if (Options::useAltAz())
0697                 setDestinationAltAz(focus()->alt(), focus()->az(), false);
0698             else
0699                 setDestination(*focus());
0700         }
0701         else if (Options::leftClickSelectsObject())
0702             mouseDoubleClickEvent(e);
0703         forceUpdate(); // is needed because after moving the sky not all stars are shown
0704     }
0705     // if middle button was pressed unset here
0706     midMouseButtonDown = false;
0707 }
0708 
0709 void SkyMap::mousePressEvent(QMouseEvent *e)
0710 {
0711     KStars *kstars = KStars::Instance();
0712 
0713     if ((e->modifiers() & Qt::ControlModifier) && (e->button() == Qt::LeftButton))
0714     {
0715         ZoomRect.moveCenter(e->pos());
0716         setZoomMouseCursor();
0717         update(); //refresh without redrawing skymap
0718         return;
0719     }
0720 
0721     // if button is down and cursor is not moved set the move cursor after 500 ms
0722     //QTimer::singleShot(500, this, SLOT(setMouseMoveCursor()));
0723 
0724     // break if point is unusable
0725     if (projector()->unusablePoint(e->pos()))
0726         return;
0727 
0728     if (!midMouseButtonDown && e->button() == Qt::MidButton)
0729     {
0730         y0                 = 0.5 * height() - e->y(); //record y pixel coordinate for middle-button zooming
0731         midMouseButtonDown = true;
0732     }
0733 
0734     if (!mouseButtonDown)
0735     {
0736         if (e->button() == Qt::LeftButton)
0737         {
0738             mouseButtonDown = true;
0739         }
0740 
0741         //determine RA, Dec of mouse pointer
0742         m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
0743         setClickedPoint(&m_MousePoint);
0744 
0745         //Find object nearest to clickedPoint()
0746         double maxrad  = 5000.0 / Options::zoomFactor();
0747         SkyObject *obj = data->skyComposite()->objectNearest(clickedPoint(), maxrad);
0748         setClickedObject(obj);
0749         if (obj)
0750             setClickedPoint(obj);
0751 
0752         switch (e->button())
0753         {
0754             case Qt::LeftButton:
0755             {
0756                 QString name;
0757                 if (clickedObject())
0758                 {
0759                     name = clickedObject()->translatedLongName();
0760                     emit objectClicked(clickedObject());
0761                 }
0762                 else
0763                     name = i18n("Empty sky");
0764                 //kstars->statusBar()->changeItem(name, 0 );
0765                 kstars->statusBar()->showMessage(name, 0);
0766 
0767                 emit positionClicked(&m_MousePoint);
0768             }
0769 
0770             break;
0771             case Qt::RightButton:
0772                 if (rulerMode)
0773                 {
0774                     // Compute angular distance.
0775                     slotEndRulerMode();
0776                 }
0777                 else
0778                 {
0779                     // Show popup menu
0780                     if (clickedObject())
0781                     {
0782                         clickedObject()->showPopupMenu(pmenu, QCursor::pos());
0783                     }
0784                     else
0785                     {
0786                         pmenu->createEmptyMenu(clickedPoint());
0787                         pmenu->popup(QCursor::pos());
0788                     }
0789                 }
0790                 break;
0791             default:
0792                 ;
0793         }
0794     }
0795 }
0796 
0797 void SkyMap::mouseDoubleClickEvent(QMouseEvent *e)
0798 {
0799     if (e->button() == Qt::LeftButton && !projector()->unusablePoint(e->pos()))
0800     {
0801         mouseButtonDown = false;
0802         if (e->x() != width() / 2 || e->y() != height() / 2)
0803             slotCenter();
0804     }
0805 }
0806 
0807 double SkyMap::zoomFactor(const int modifier)
0808 {
0809     double factor = (modifier & Qt::ControlModifier) ? DZOOM : (Options::zoomScrollFactor() + 1);
0810     if (modifier & Qt::ShiftModifier)
0811         factor = sqrt(factor);
0812     return factor;
0813 }
0814 
0815 void SkyMap::zoomInOrMagStep(const int modifier)
0816 {
0817     if (modifier & Qt::AltModifier)
0818         incMagLimit(modifier);
0819     else
0820         setZoomFactor(Options::zoomFactor() * zoomFactor(modifier));
0821 }
0822 
0823 void SkyMap::zoomOutOrMagStep(const int modifier)
0824 {
0825     if (modifier & Qt::AltModifier)
0826         decMagLimit(modifier);
0827     else
0828         setZoomFactor(Options::zoomFactor() / zoomFactor(modifier));
0829 }
0830 
0831 double SkyMap::magFactor(const int modifier)
0832 {
0833     double factor = (modifier & Qt::ControlModifier) ? 0.1 : 0.5;
0834     if (modifier & Qt::ShiftModifier)
0835         factor *= 2.0;
0836     return factor;
0837 }
0838 
0839 void SkyMap::incMagLimit(const int modifier)
0840 {
0841     double limit = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35;
0842     limit += magFactor(modifier);
0843     if (limit > 5.75954)
0844         limit = 5.75954;
0845     Options::setStarDensity(pow(10, (limit - 0.35) / 2.222));
0846     //printf("maglim set to %3.1f\n", limit);
0847     forceUpdate();
0848 }
0849 
0850 void SkyMap::decMagLimit(const int modifier)
0851 {
0852     double limit = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35;
0853     limit -= magFactor(modifier);
0854     if (limit < 1.18778)
0855         limit = 1.18778;
0856     Options::setStarDensity(pow(10, (limit - 0.35) / 2.222));
0857     //printf("maglim set to %3.1f\n", limit);
0858     forceUpdate();
0859 }