1 /*
2     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 //This file contains Event handlers for the SkyMap class.
8 
9 #include "skymap.h"
10 
11 #include "ksplanetbase.h"
12 #include "kspopupmenu.h"
13 #include "kstars.h"
14 #include "observinglist.h"
15 #include "Options.h"
16 #include "skyglpainter.h"
17 #include "skyqpainter.h"
18 #include "printing/simplefovexporter.h"
19 #include "skycomponents/skylabeler.h"
20 #include "skycomponents/skymapcomposite.h"
21 #include "skycomponents/starcomponent.h"
22 #include "widgets/infoboxwidget.h"
23 
24 #include <QGestureEvent>
25 #include <QStatusBar>
26 #include <QToolTip>
27 
resizeEvent(QResizeEvent *)28 void SkyMap::resizeEvent(QResizeEvent *)
29 {
30     computeSkymap = true; // skymap must be new computed
31 
32     //FIXME: No equivalent for this line in Qt4 ??
33     //	if ( testWState( Qt::WState_AutoMask ) ) updateMask();
34 
35     // Resize the widget that draws the sky map.
36     // FIXME: The resize event doesn't pass to children. Any better way of doing this?
37     m_SkyMapDraw->resize(size());
38 
39     // Resize infoboxes container.
40     // FIXME: this is not really pretty. Maybe there are some better way to this???
41     m_iboxes->resize(size());
42 }
43 
keyPressEvent(QKeyEvent * e)44 void SkyMap::keyPressEvent(QKeyEvent *e)
45 {
46     bool arrowKeyPressed(false);
47     bool shiftPressed(false);
48     float step = 1.0;
49     if (e->modifiers() & Qt::ShiftModifier)
50     {
51         step         = 10.0;
52         shiftPressed = true;
53     }
54 
55     //If the DBus resume key is not empty, then DBus processing is
56     //paused while we wait for a keypress
57     if (!data->resumeKey.isEmpty() && QKeySequence(e->key()) == data->resumeKey)
58     {
59         //The resumeKey was pressed.  Signal that it was pressed by
60         //resetting it to empty; this will break the loop in
61         //KStars::waitForKey()
62         data->resumeKey = QKeySequence();
63         return;
64     }
65 
66     if (m_previewLegend)
67     {
68         slotCancelLegendPreviewMode();
69     }
70 
71     switch (e->key())
72     {
73         case Qt::Key_Left:
74             if (Options::useAltAz())
75             {
76                 focus()->setAz(dms(focus()->az().Degrees() - step * MINZOOM / Options::zoomFactor()).reduce());
77                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
78             }
79             else
80             {
81                 focus()->setRA(focus()->ra().Hours() + 0.05 * step * MINZOOM / Options::zoomFactor());
82                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
83             }
84 
85             arrowKeyPressed = true;
86             slewing         = true;
87             break;
88 
89         case Qt::Key_Right:
90             if (Options::useAltAz())
91             {
92                 focus()->setAz(dms(focus()->az().Degrees() + step * MINZOOM / Options::zoomFactor()).reduce());
93                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
94             }
95             else
96             {
97                 focus()->setRA(focus()->ra().Hours() - 0.05 * step * MINZOOM / Options::zoomFactor());
98                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
99             }
100 
101             arrowKeyPressed = true;
102             slewing         = true;
103             break;
104 
105         case Qt::Key_Up:
106             if (Options::useAltAz())
107             {
108                 focus()->setAltRefracted(focus()->altRefracted().Degrees() + step * MINZOOM / Options::zoomFactor());
109                 if (focus()->alt().Degrees() > 90.0)
110                     focus()->setAlt(90.0);
111                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
112             }
113             else
114             {
115                 focus()->setDec(focus()->dec().Degrees() + step * MINZOOM / Options::zoomFactor());
116                 if (focus()->dec().Degrees() > 90.0)
117                     focus()->setDec(90.0);
118                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
119             }
120 
121             arrowKeyPressed = true;
122             slewing         = true;
123             break;
124 
125         case Qt::Key_Down:
126             if (Options::useAltAz())
127             {
128                 focus()->setAltRefracted(focus()->altRefracted().Degrees() - step * MINZOOM / Options::zoomFactor());
129                 if (focus()->alt().Degrees() < -90.0)
130                     focus()->setAlt(-90.0);
131                 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
132             }
133             else
134             {
135                 focus()->setDec(focus()->dec().Degrees() - step * MINZOOM / Options::zoomFactor());
136                 if (focus()->dec().Degrees() < -90.0)
137                     focus()->setDec(-90.0);
138                 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
139             }
140 
141             arrowKeyPressed = true;
142             slewing         = true;
143             break;
144 
145         case Qt::Key_Plus: //Zoom in
146         case Qt::Key_Equal:
147             zoomInOrMagStep(e->modifiers());
148             break;
149 
150         case Qt::Key_Minus: //Zoom out
151         case Qt::Key_Underscore:
152             zoomOutOrMagStep(e->modifiers());
153             break;
154 
155         case Qt::Key_0: //center on Sun
156             setClickedObject(data->skyComposite()->planet(KSPlanetBase::SUN));
157             setClickedPoint(clickedObject());
158             slotCenter();
159             break;
160 
161         case Qt::Key_1: //center on Mercury
162             setClickedObject(data->skyComposite()->planet(KSPlanetBase::MERCURY));
163             setClickedPoint(clickedObject());
164             slotCenter();
165             break;
166 
167         case Qt::Key_2: //center on Venus
168             setClickedObject(data->skyComposite()->planet(KSPlanetBase::VENUS));
169             setClickedPoint(clickedObject());
170             slotCenter();
171             break;
172 
173         case Qt::Key_3: //center on Moon
174             setClickedObject(data->skyComposite()->planet(KSPlanetBase::MOON));
175             setClickedPoint(clickedObject());
176             slotCenter();
177             break;
178 
179         case Qt::Key_4: //center on Mars
180             setClickedObject(data->skyComposite()->planet(KSPlanetBase::MARS));
181             setClickedPoint(clickedObject());
182             slotCenter();
183             break;
184 
185         case Qt::Key_5: //center on Jupiter
186             setClickedObject(data->skyComposite()->planet(KSPlanetBase::JUPITER));
187             setClickedPoint(clickedObject());
188             slotCenter();
189             break;
190 
191         case Qt::Key_6: //center on Saturn
192             setClickedObject(data->skyComposite()->planet(KSPlanetBase::SATURN));
193             setClickedPoint(clickedObject());
194             slotCenter();
195             break;
196 
197         case Qt::Key_7: //center on Uranus
198             setClickedObject(data->skyComposite()->planet(KSPlanetBase::URANUS));
199             setClickedPoint(clickedObject());
200             slotCenter();
201             break;
202 
203         case Qt::Key_8: //center on Neptune
204             setClickedObject(data->skyComposite()->planet(KSPlanetBase::NEPTUNE));
205             setClickedPoint(clickedObject());
206             slotCenter();
207             break;
208 
209         /*case Qt::Key_9: //center on Pluto
210             setClickedObject( data->skyComposite()->planet( KSPlanetBase::PLUTO ) );
211             setClickedPoint( clickedObject() );
212             slotCenter();
213             break;*/
214 
215         case Qt::Key_BracketLeft: // Begin measuring angular distance
216             if (!rulerMode)
217                 slotBeginAngularDistance();
218             break;
219         case Qt::Key_Escape: // Cancel angular distance measurement
220         {
221             if (rulerMode)
222                 slotCancelRulerMode();
223 
224             if (m_fovCaptureMode)
225                 slotFinishFovCaptureMode();
226             break;
227         }
228 
229         case Qt::Key_C: //Center clicked object
230             if (clickedObject())
231                 slotCenter();
232             break;
233 
234         case Qt::Key_D: //Details window for Clicked/Centered object
235         {
236             SkyObject *orig = nullptr;
237             if (shiftPressed)
238             {
239                 orig = clickedObject();
240                 setClickedObject(focusObject());
241             }
242 
243             if (clickedObject())
244             {
245                 slotDetail();
246             }
247 
248             if (orig)
249             {
250                 setClickedObject(orig);
251             }
252             break;
253         }
254 
255         case Qt::Key_P: //Show Popup menu for Clicked/Centered object
256             if (shiftPressed)
257             {
258                 if (focusObject())
259                     focusObject()->showPopupMenu(pmenu, QCursor::pos());
260             }
261             else
262             {
263                 if (clickedObject())
264                     clickedObject()->showPopupMenu(pmenu, QCursor::pos());
265             }
266             break;
267 
268         case Qt::Key_O: //Add object to Observing List
269         {
270             SkyObject *orig = nullptr;
271             if (shiftPressed)
272             {
273                 orig = clickedObject();
274                 setClickedObject(focusObject());
275             }
276 
277             if (clickedObject())
278             {
279                 data->observingList()->slotAddObject();
280             }
281 
282             if (orig)
283             {
284                 setClickedObject(orig);
285             }
286             break;
287         }
288 
289         case Qt::Key_L: //Toggle User label on Clicked/Centered object
290         {
291             SkyObject *orig = nullptr;
292             if (shiftPressed)
293             {
294                 orig = clickedObject();
295                 setClickedObject(focusObject());
296             }
297 
298             if (clickedObject())
299             {
300                 if (isObjectLabeled(clickedObject()))
301                     slotRemoveObjectLabel();
302                 else
303                     slotAddObjectLabel();
304             }
305 
306             if (orig)
307             {
308                 setClickedObject(orig);
309             }
310             break;
311         }
312 
313         case Qt::Key_T: //Toggle planet trail on Clicked/Centered object (if solsys)
314         {
315             SkyObject *orig = nullptr;
316             if (shiftPressed)
317             {
318                 orig = clickedObject();
319                 setClickedObject(focusObject());
320             }
321 
322             KSPlanetBase *planet = dynamic_cast<KSPlanetBase *>(clickedObject());
323             if (planet)
324             {
325                 if (planet->hasTrail())
326                     slotRemovePlanetTrail();
327                 else
328                     slotAddPlanetTrail();
329             }
330 
331             if (orig)
332             {
333                 setClickedObject(orig);
334             }
335             break;
336         }
337 
338         case Qt::Key_R:
339         {
340             // Toggle relativistic corrections
341             Options::setUseRelativistic(!Options::useRelativistic());
342             qDebug() << "Relativistic corrections: " << Options::useRelativistic();
343             forceUpdate();
344             break;
345         }
346 
347         case Qt::Key_A:
348             Options::setUseAntialias(!Options::useAntialias());
349             qDebug() << "Use Antialiasing: " << Options::useAntialias();
350             forceUpdate();
351             break;
352 
353         case Qt::Key_K:
354         {
355             if (m_fovCaptureMode)
356                 slotCaptureFov();
357             break;
358         }
359 
360         case Qt::Key_PageUp:
361         {
362             KStars::Instance()->selectPreviousFov();
363             break;
364         }
365 
366         case Qt::Key_PageDown:
367         {
368             KStars::Instance()->selectNextFov();
369             break;
370         }
371 
372         default:
373             // We don't want to do anything in this case. Key is unknown
374             return;
375     }
376 
377     if (arrowKeyPressed)
378     {
379         stopTracking();
380         setDestination(*focus());
381     }
382 
383     forceUpdate(); //need a total update, or slewing with the arrow keys doesn't work.
384 }
385 
stopTracking()386 void SkyMap::stopTracking()
387 {
388     KStars *kstars = KStars::Instance();
389 
390     emit positionChanged(focus());
391     if (kstars && Options::isTracking())
392         kstars->slotTrack();
393 }
394 
event(QEvent * event)395 bool SkyMap::event(QEvent *event)
396 {
397 #if !defined(KSTARS_LITE)
398     if (event->type() == QEvent::TouchBegin)
399     {
400         m_touchMode = true;
401         m_pinchScale = -1;
402     }
403 
404     if (event->type() == QEvent::Gesture && m_touchMode)
405     {
406         QGestureEvent* gestureEvent = static_cast<QGestureEvent*>(event);
407 
408         if (QPinchGesture *pinch = static_cast<QPinchGesture*>(gestureEvent->gesture(Qt::PinchGesture)))
409         {
410             QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags();
411 
412             m_pinchMode = true;
413             if (changeFlags & QPinchGesture::ScaleFactorChanged)
414             {
415                 if (m_pinchScale == -1)
416                 {
417                     m_pinchScale = pinch->totalScaleFactor();
418                     return true;
419                 }
420                 if (pinch->totalScaleFactor() - m_pinchScale > 0.1)
421                 {
422                     m_pinchScale = pinch->totalScaleFactor();
423                     zoomInOrMagStep(0);
424                     return true;
425                 }
426                 if (pinch->totalScaleFactor() - m_pinchScale < -0.1)
427                 {
428                     m_pinchScale = pinch->totalScaleFactor();
429                     zoomOutOrMagStep(0);
430                     return true;
431                 }
432             }
433         }
434         if (QTapAndHoldGesture *tapAndHold = static_cast<QTapAndHoldGesture*>(gestureEvent->gesture(Qt::TapAndHoldGesture)))
435         {
436             m_tapAndHoldMode = true;
437             if (tapAndHold->state() == Qt::GestureFinished)
438             {
439                 if (clickedObject())
440                 {
441                     clickedObject()->showPopupMenu(pmenu, tapAndHold->position().toPoint());
442                 }
443                 else
444                 {
445                     pmenu->createEmptyMenu(clickedPoint());
446                     pmenu->popup(tapAndHold->position().toPoint());
447                 }
448                 m_touchMode = false;
449                 m_pinchMode = false;
450                 m_tapAndHoldMode = false;
451             }
452         }
453         return true;
454     }
455 #endif
456     return QGraphicsView::event(event);
457 }
458 
keyReleaseEvent(QKeyEvent * e)459 void SkyMap::keyReleaseEvent(QKeyEvent *e)
460 {
461     switch (e->key())
462     {
463         case Qt::Key_Plus: //Zoom in
464         case Qt::Key_Equal:
465         case Qt::Key_Minus: //Zoom out
466         case Qt::Key_Underscore:
467 
468         case Qt::Key_Left:  //no break; continue to Qt::Key_Down
469         case Qt::Key_Right: //no break; continue to Qt::Key_Down
470         case Qt::Key_Up:    //no break; continue to Qt::Key_Down
471         case Qt::Key_Down:
472             slewing = false;
473 
474             if (Options::useAltAz())
475                 setDestinationAltAz(focus()->alt(), focus()->az(), false);
476             else
477                 setDestination(*focus());
478 
479             showFocusCoords();
480             forceUpdate(); // Need a full update to draw faint objects that are not drawn while slewing.
481             break;
482     }
483 }
484 
mouseMoveEvent(QMouseEvent * e)485 void SkyMap::mouseMoveEvent(QMouseEvent *e)
486 {
487 #if !defined(KSTARS_LITE)
488     // Skip touch points
489     if (m_pinchMode || m_tapAndHoldMode || (m_touchMode && e->globalX() == 0 && e->globalY() == 0))
490         return;
491 #endif
492 
493     if (Options::useHoverLabel())
494     {
495         //Start a single-shot timer to monitor whether we are currently hovering.
496         //The idea is that whenever a moveEvent occurs, the timer is reset.  It
497         //will only timeout if there are no move events for HOVER_INTERVAL ms
498         m_HoverTimer.start(HOVER_INTERVAL);
499         QToolTip::hideText();
500     }
501 
502     //Are we defining a ZoomRect?
503     if (ZoomRect.center().x() > 0 && ZoomRect.center().y() > 0)
504     {
505         //cancel operation if the user let go of CTRL
506         if (!(e->modifiers() & Qt::ControlModifier))
507         {
508             ZoomRect = QRect(); //invalidate ZoomRect
509             update();
510         }
511         else
512         {
513             //Resize the rectangle so that it passes through the cursor position
514             QPoint pcenter = ZoomRect.center();
515             int dx         = abs(e->x() - pcenter.x());
516             int dy         = abs(e->y() - pcenter.y());
517             if (dx == 0 || float(dy) / float(dx) > float(height()) / float(width()))
518             {
519                 //Size rect by height
520                 ZoomRect.setHeight(2 * dy);
521                 ZoomRect.setWidth(2 * dy * width() / height());
522             }
523             else
524             {
525                 //Size rect by height
526                 ZoomRect.setWidth(2 * dx);
527                 ZoomRect.setHeight(2 * dx * height() / width());
528             }
529             ZoomRect.moveCenter(pcenter); //reset center
530 
531             update();
532             return;
533         }
534     }
535 
536     if (projector()->unusablePoint(e->pos()))
537         return; // break if point is unusable
538 
539     //determine RA, Dec of mouse pointer
540     m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
541 
542     double dyPix = 0.5 * height() - e->y();
543     if (midMouseButtonDown) //zoom according to y-offset
544     {
545         float yoff = dyPix - y0;
546         if (yoff > 10)
547         {
548             y0 = dyPix;
549             slotZoomIn();
550         }
551         if (yoff < -10)
552         {
553             y0 = dyPix;
554             slotZoomOut();
555         }
556     }
557 
558     if (mouseButtonDown)
559     {
560         // set the mouseMoveCursor and set slewing=true, if they are not set yet
561         if (!mouseMoveCursor)
562             setMouseMoveCursor();
563         if (!slewing)
564         {
565             slewing = true;
566             stopTracking(); //toggle tracking off
567         }
568 
569         //Update focus such that the sky coords at mouse cursor remain approximately constant
570         if (Options::useAltAz())
571         {
572             m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat());
573             clickedPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
574             dms dAz  = m_MousePoint.az() - clickedPoint()->az();
575             dms dAlt = m_MousePoint.altRefracted() - clickedPoint()->altRefracted();
576             focus()->setAz(focus()->az().Degrees() - dAz.Degrees()); //move focus in opposite direction
577             focus()->setAz(focus()->az().reduce());
578             focus()->setAltRefracted(KSUtils::clamp(focus()->altRefracted().Degrees() - dAlt.Degrees(), -90.0, 90.0));
579             focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
580         }
581         else
582         {
583             dms dRA  = m_MousePoint.ra() - clickedPoint()->ra();
584             dms dDec = m_MousePoint.dec() - clickedPoint()->dec();
585             focus()->setRA(focus()->ra().Hours() - dRA.Hours()); //move focus in opposite direction
586             focus()->setRA(focus()->ra().reduce());
587             focus()->setDec(KSUtils::clamp(focus()->dec().Degrees() - dDec.Degrees(), -90.0, 90.0));
588             focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
589         }
590         showFocusCoords();
591 
592         //redetermine RA, Dec of mouse pointer, using new focus
593         m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
594         setClickedPoint(&m_MousePoint);
595 
596         forceUpdate(); // must be new computed
597     }
598     else //mouse button not down
599     {
600         if (Options::useAltAz())
601             m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat());
602         emit mousePointChanged(&m_MousePoint);
603     }
604 }
605 
wheelEvent(QWheelEvent * e)606 void SkyMap::wheelEvent(QWheelEvent *e)
607 {
608     if (e->delta() > 0)
609         zoomInOrMagStep(e->modifiers());
610     else if (e->delta() < 0)
611         zoomOutOrMagStep(e->modifiers());
612 }
613 
mouseReleaseEvent(QMouseEvent * e)614 void SkyMap::mouseReleaseEvent(QMouseEvent *e)
615 {
616 #if !defined(KSTARS_LITE)
617     if (m_touchMode)
618     {
619         m_touchMode = false;
620         m_pinchMode = false;
621         m_tapAndHoldMode = false;
622     }
623 #endif
624 
625     if (ZoomRect.isValid())
626     {
627         stopTracking();
628         SkyPoint newcenter = projector()->fromScreen(ZoomRect.center(), data->lst(), data->geo()->lat());
629         setFocus(&newcenter);
630         setDestination(newcenter);
631 
632         //Zoom in on center of Zoom Circle, by a factor equal to the ratio
633         //of the sky pixmap's width to the Zoom Circle's diameter
634         float factor = float(width()) / float(ZoomRect.width());
635         setZoomFactor(Options::zoomFactor() * factor);
636     }
637 
638     setMouseCursorShape(static_cast<Cursor>(Options::defaultCursor()));
639 
640     ZoomRect = QRect(); //invalidate ZoomRect
641 
642     if (m_previewLegend)
643     {
644         slotCancelLegendPreviewMode();
645     }
646 
647     //false if double-clicked, because it's unset there.
648     if (mouseButtonDown)
649     {
650         mouseButtonDown = false;
651         if (slewing)
652         {
653             slewing = false;
654             if (Options::useAltAz())
655                 setDestinationAltAz(focus()->alt(), focus()->az(), false);
656             else
657                 setDestination(*focus());
658         }
659         else if (Options::leftClickSelectsObject())
660             mouseDoubleClickEvent(e);
661         forceUpdate(); // is needed because after moving the sky not all stars are shown
662     }
663     // if middle button was pressed unset here
664     midMouseButtonDown = false;
665 }
666 
mousePressEvent(QMouseEvent * e)667 void SkyMap::mousePressEvent(QMouseEvent *e)
668 {
669     KStars *kstars = KStars::Instance();
670 
671     if ((e->modifiers() & Qt::ControlModifier) && (e->button() == Qt::LeftButton))
672     {
673         ZoomRect.moveCenter(e->pos());
674         setZoomMouseCursor();
675         update(); //refresh without redrawing skymap
676         return;
677     }
678 
679     // if button is down and cursor is not moved set the move cursor after 500 ms
680     QTimer::singleShot(500, this, SLOT(setMouseMoveCursor()));
681 
682     // break if point is unusable
683     if (projector()->unusablePoint(e->pos()))
684         return;
685 
686     if (!midMouseButtonDown && e->button() == Qt::MidButton)
687     {
688         y0                 = 0.5 * height() - e->y(); //record y pixel coordinate for middle-button zooming
689         midMouseButtonDown = true;
690     }
691 
692     if (!mouseButtonDown)
693     {
694         if (e->button() == Qt::LeftButton)
695         {
696             mouseButtonDown = true;
697         }
698 
699         //determine RA, Dec of mouse pointer
700         m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
701         setClickedPoint(&m_MousePoint);
702 
703         //Find object nearest to clickedPoint()
704         double maxrad  = 5000.0 / Options::zoomFactor();
705         SkyObject *obj = data->skyComposite()->objectNearest(clickedPoint(), maxrad);
706         setClickedObject(obj);
707         if (obj)
708             setClickedPoint(obj);
709 
710         switch (e->button())
711         {
712             case Qt::LeftButton:
713             {
714                 QString name;
715                 if (clickedObject())
716                 {
717                     name = clickedObject()->translatedLongName();
718                     emit objectClicked(clickedObject());
719                 }
720                 else
721                     name = i18n("Empty sky");
722                 //kstars->statusBar()->changeItem(name, 0 );
723                 kstars->statusBar()->showMessage(name, 0);
724 
725                 emit positionClicked(&m_MousePoint);
726             }
727 
728             break;
729             case Qt::RightButton:
730                 if (rulerMode)
731                 {
732                     // Compute angular distance.
733                     slotEndRulerMode();
734                 }
735                 else
736                 {
737                     // Show popup menu
738                     if (clickedObject())
739                     {
740                         clickedObject()->showPopupMenu(pmenu, QCursor::pos());
741                     }
742                     else
743                     {
744                         pmenu->createEmptyMenu(clickedPoint());
745                         pmenu->popup(QCursor::pos());
746                     }
747                 }
748                 break;
749             default:
750                 ;
751         }
752     }
753 }
754 
mouseDoubleClickEvent(QMouseEvent * e)755 void SkyMap::mouseDoubleClickEvent(QMouseEvent *e)
756 {
757     if (e->button() == Qt::LeftButton && !projector()->unusablePoint(e->pos()))
758     {
759         mouseButtonDown = false;
760         if (e->x() != width() / 2 || e->y() != height() / 2)
761             slotCenter();
762     }
763 }
764 
zoomFactor(const int modifier)765 double SkyMap::zoomFactor(const int modifier)
766 {
767     double factor = (modifier & Qt::ControlModifier) ? DZOOM : (Options::zoomScrollFactor() + 1);
768     if (modifier & Qt::ShiftModifier)
769         factor = sqrt(factor);
770     return factor;
771 }
772 
zoomInOrMagStep(const int modifier)773 void SkyMap::zoomInOrMagStep(const int modifier)
774 {
775     if (modifier & Qt::AltModifier)
776         incMagLimit(modifier);
777     else
778         setZoomFactor(Options::zoomFactor() * zoomFactor(modifier));
779 }
780 
zoomOutOrMagStep(const int modifier)781 void SkyMap::zoomOutOrMagStep(const int modifier)
782 {
783     if (modifier & Qt::AltModifier)
784         decMagLimit(modifier);
785     else
786         setZoomFactor(Options::zoomFactor() / zoomFactor(modifier));
787 }
788 
magFactor(const int modifier)789 double SkyMap::magFactor(const int modifier)
790 {
791     double factor = (modifier & Qt::ControlModifier) ? 0.1 : 0.5;
792     if (modifier & Qt::ShiftModifier)
793         factor *= 2.0;
794     return factor;
795 }
796 
incMagLimit(const int modifier)797 void SkyMap::incMagLimit(const int modifier)
798 {
799     double limit = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35;
800     limit += magFactor(modifier);
801     if (limit > 5.75954)
802         limit = 5.75954;
803     Options::setStarDensity(pow(10, (limit - 0.35) / 2.222));
804     //printf("maglim set to %3.1f\n", limit);
805     forceUpdate();
806 }
807 
decMagLimit(const int modifier)808 void SkyMap::decMagLimit(const int modifier)
809 {
810     double limit = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35;
811     limit -= magFactor(modifier);
812     if (limit < 1.18778)
813         limit = 1.18778;
814     Options::setStarDensity(pow(10, (limit - 0.35) / 2.222));
815     //printf("maglim set to %3.1f\n", limit);
816     forceUpdate();
817 }
818