MarbleInputHandler.cpp 31.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2006-2007 Torsten Rahn <tackat@kde.org>
// Copyright 2007      Inge Wallin  <ingwa@kde.org>
// Copyright 2014      Adam Dabrowski <adamdbrw@gmail.com>
//

#include "MarbleInputHandler.h"

#include <QPoint>
#include <QPointer>
#include <QTimer>
#include <QCursor>
#include <QMouseEvent>
#include <QPixmap>
#include <QGestureEvent>
#include <QPinchGesture>

#include "kineticmodel.h"
#include "MarbleGlobal.h"
#include "MarbleDebug.h"
27
#include "MarbleMap.h"
28
29
30
31
32
33
34
35
36
37
38
#include "GeoDataCoordinates.h"
#include "MarbleAbstractPresenter.h"
#include "ViewportParams.h"
#include "AbstractFloatItem.h"
#include "AbstractDataPluginItem.h"
#include "RenderPlugin.h"

namespace Marble {

const int TOOLTIP_START_INTERVAL = 1000;

39
class Q_DECL_HIDDEN MarbleInputHandler::Protected
40
41
42
43
44
45
46
47
48
49
50
{
public:
    Protected(MarbleAbstractPresenter *marblePresenter);

    MarbleAbstractPresenter *const m_marblePresenter;
    bool m_positionSignalConnected;
    QTimer *m_mouseWheelTimer;
    Qt::MouseButtons m_disabledMouseButtons;
    qreal m_wheelZoomTargetDistance;
    bool m_panViaArrowsEnabled;
    bool m_inertialEarthRotation;
51
    bool m_mouseViewRotation;
52
53
    int m_steps;
    const int m_discreteZoomSteps = 120;
54
55
56
57
58
};

MarbleInputHandler::Protected::Protected(MarbleAbstractPresenter *marblePresenter)
    : m_marblePresenter( marblePresenter ),
      m_positionSignalConnected( false ),
59
      m_mouseWheelTimer( nullptr ),
60
61
62
      m_disabledMouseButtons( Qt::NoButton ),
      m_wheelZoomTargetDistance( 0.0 ),
      m_panViaArrowsEnabled( true ),
63
      m_inertialEarthRotation( true ),
64
      m_mouseViewRotation( true ),
65
      m_steps(0)
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{
}

MarbleInputHandler::MarbleInputHandler(MarbleAbstractPresenter *marblePresenter)
    : d(new Protected(marblePresenter))
{
    d->m_mouseWheelTimer = new QTimer( this );
    connect(d->m_mouseWheelTimer, SIGNAL(timeout()), this, SLOT(restoreViewContext()));

    connect(d->m_marblePresenter->map(), SIGNAL(renderPluginInitialized(RenderPlugin*)),
             this, SLOT(installPluginEventFilter(RenderPlugin*)));
}

MarbleInputHandler::~MarbleInputHandler()
{
    delete d->m_mouseWheelTimer;
    delete d;
}

void MarbleInputHandler::setPositionSignalConnected(bool connected)
{
    d->m_positionSignalConnected = connected;
}

bool MarbleInputHandler::isPositionSignalConnected() const
{
    return d->m_positionSignalConnected;
}

void MarbleInputHandler::setMouseButtonPopupEnabled(Qt::MouseButton mouseButton, bool enabled)
{
    if (enabled)
    {
        d->m_disabledMouseButtons &= ~Qt::MouseButtons(mouseButton);
    }
    else
    {
        d->m_disabledMouseButtons |= mouseButton;
    }
}

bool MarbleInputHandler::isMouseButtonPopupEnabled(Qt::MouseButton mouseButton) const
{
    return !(d->m_disabledMouseButtons & mouseButton);
}

void MarbleInputHandler::setPanViaArrowsEnabled(bool enabled)
{
    d->m_panViaArrowsEnabled = enabled;
}

bool MarbleInputHandler::panViaArrowsEnabled() const
{
    return d->m_panViaArrowsEnabled;
}

void MarbleInputHandler::setInertialEarthRotationEnabled(bool enabled)
{
    d->m_inertialEarthRotation = enabled;
}

bool MarbleInputHandler::inertialEarthRotationEnabled() const
{
    return d->m_inertialEarthRotation;
}

132
133
134
135
136
137
138
139
140
141
void MarbleInputHandler::setMouseViewRotationEnabled(bool enabled)
{
    d->m_mouseViewRotation = enabled;
}

bool MarbleInputHandler::mouseViewRotationEnabled() const
{
    return d->m_mouseViewRotation;
}

142
143
144
145
void MarbleInputHandler::stopInertialEarthRotation()
{
}

146
class Q_DECL_HIDDEN MarbleDefaultInputHandler::Private
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
{
 public:
    Private();
    ~Private();

    QPixmap m_curpmtl;
    QPixmap m_curpmtc;
    QPixmap m_curpmtr;
    QPixmap m_curpmcr;
    QPixmap m_curpmcl;
    QPixmap m_curpmbl;
    QPixmap m_curpmbc;
    QPixmap m_curpmbr;

    QCursor m_arrowCur[3][3];

    // Indicates if the left mouse button has been pressed already.
    bool m_leftPressed;
    // Indicates if the middle mouse button has been pressed already.
    bool m_midPressed;
    // The mouse pointer x position when the left mouse button has been pressed.
    int m_leftPressedX;
    // The mouse pointer y position when the left mouse button has been pressed.
    int m_leftPressedY;
    // The mouse pointer y position when the middle mouse button has been pressed.
    int m_midPressedY;
    int m_startingRadius;
174

175
176
177
178
179
180
181
182
183
184
185
    // Indicates if the right mouse button has been pressed already.
    bool m_rightPressed;
    // Point where the right mouse button has been pressed on.
    QPoint m_rightOrigin;
    // Position to calculate the heading.
    // Indicates previous position since mouse has been moved.
    QPoint m_rightPosition;
    // Indicates the heading when the right mouse button has been pressed
    // and mouse is moving.
    qreal m_heading;

186
187
188
189
190
191
192
    // The center longitude in radian when the left mouse button has been pressed.
    qreal m_leftPressedLon;
    // The center latitude in radian when the left mouse button has been pressed.
    qreal m_leftPressedLat;

    int m_dragThreshold;
    QTimer m_lmbTimer;
193
    QTimer m_pressAndHoldTimer;
194
195
196
197
198
199
200
201
202
203
204
205
206
207

    // Models to handle the kinetic spinning.
    KineticModel m_kineticSpinning;

    QPoint m_selectionOrigin;

    QPointer<AbstractDataPluginItem> m_lastToolTipItem;
    QTimer m_toolTipTimer;
    QPoint m_toolTipPosition;
};

MarbleDefaultInputHandler::Private::Private()
    : m_leftPressed(false),
      m_midPressed(false),
208
209
      m_rightPressed(false),
      m_heading(0),
210
211
      m_dragThreshold(MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ? 15 : 3)
{
212
213
214
215
216
217
218
219
    m_curpmtl.load(QStringLiteral(":/marble/cursor/tl.png"));
    m_curpmtc.load(QStringLiteral(":/marble/cursor/tc.png"));
    m_curpmtr.load(QStringLiteral(":/marble/cursor/tr.png"));
    m_curpmcr.load(QStringLiteral(":/marble/cursor/cr.png"));
    m_curpmcl.load(QStringLiteral(":/marble/cursor/cl.png"));
    m_curpmbl.load(QStringLiteral(":/marble/cursor/bl.png"));
    m_curpmbc.load(QStringLiteral(":/marble/cursor/bc.png"));
    m_curpmbr.load(QStringLiteral(":/marble/cursor/br.png"));
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

    m_arrowCur[0][0] = QCursor( m_curpmtl, 2, 2 );
    m_arrowCur[1][0] = QCursor( m_curpmtc, 10, 3 );
    m_arrowCur[2][0] = QCursor( m_curpmtr, 19, 2 );
    m_arrowCur[0][1] = QCursor( m_curpmcl, 3, 10 );
    m_arrowCur[1][1] = QCursor( Qt::OpenHandCursor );
    m_arrowCur[2][1] = QCursor( m_curpmcr, 18, 10 );
    m_arrowCur[0][2] = QCursor( m_curpmbl, 2, 19 );
    m_arrowCur[1][2] = QCursor( m_curpmbc, 11, 18 );
    m_arrowCur[2][2] = QCursor( m_curpmbr, 19, 19 );
}

MarbleDefaultInputHandler::Private::~Private()
{
}

MarbleDefaultInputHandler::MarbleDefaultInputHandler(MarbleAbstractPresenter *marblePresenter)
    : MarbleInputHandler(marblePresenter),
      d(new Private())
{
    d->m_toolTipTimer.setSingleShot(true);
    d->m_toolTipTimer.setInterval(TOOLTIP_START_INTERVAL);
    connect(&d->m_toolTipTimer, SIGNAL(timeout()), this, SLOT(openItemToolTip()));
    d->m_lmbTimer.setSingleShot(true);
    connect(&d->m_lmbTimer, SIGNAL(timeout()), this, SLOT(lmbTimeout()));

    d->m_kineticSpinning.setUpdateInterval(35);
    connect(&d->m_kineticSpinning, SIGNAL(positionChanged(qreal,qreal)),
             MarbleInputHandler::d->m_marblePresenter, SLOT(centerOn(qreal,qreal)));
249
250
    connect(&d->m_kineticSpinning, SIGNAL(headingChanged(qreal)),
             MarbleInputHandler::d->m_marblePresenter, SLOT(headingOn(qreal)));
251
252
253
254
255
    connect(&d->m_kineticSpinning, SIGNAL(finished()), SLOT(restoreViewContext()));

    // Left and right mouse button signals.
    connect(this, SIGNAL(rmbRequest(int,int)), this, SLOT(showRmbMenu(int,int)));
    connect(this, SIGNAL(lmbRequest(int,int)), this, SLOT(showLmbMenu(int,int)));
256
257
258
259

    d->m_pressAndHoldTimer.setInterval(800);
    d->m_pressAndHoldTimer.setSingleShot(true);
    connect(&d->m_pressAndHoldTimer, SIGNAL(timeout()), this, SLOT(handlePressAndHold()));
260
261
262
263
264
265
266
}

MarbleDefaultInputHandler::~MarbleDefaultInputHandler()
{
    delete d;
}

267
268
269
270
271
void MarbleDefaultInputHandler::stopInertialEarthRotation()
{
    d->m_kineticSpinning.stop();
}

272
273
274
275
void MarbleDefaultInputHandler::lmbTimeout()
{
    if (!selectionRubber()->isVisible())
    {
276
277
278
279
280
281
        qreal clickedLon = 0;
        qreal clickedLat = 0;

        bool isPointOnGlobe = MarbleInputHandler::d->m_marblePresenter->map()->geoCoordinates( d->m_leftPressedX, d->m_leftPressedY,
                                                                        clickedLon, clickedLat,
                                                                        GeoDataCoordinates::Degree );
282
        emit lmbRequest(d->m_leftPressedX, d->m_leftPressedY);
283
284
285
286
287
288
289
290
291

        /**
         * emit mouse click only when the clicked
         * position is within the globe.
         */
        if ( isPointOnGlobe ) {
            emit mouseClickGeoPosition( clickedLon, clickedLat,
                                        GeoDataCoordinates::Degree );
        }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    }
}

void MarbleInputHandler::restoreViewContext()
{
    // Needs to stop the timer since it repeats otherwise.
    d->m_mouseWheelTimer->stop();

    // Redraw the map with the quality set for Still (if necessary).
    d->m_marblePresenter->setViewContext(Still);
    d->m_marblePresenter->map()->viewport()->resetFocusPoint();
    d->m_wheelZoomTargetDistance = 0.0;
}

void MarbleDefaultInputHandler::hideSelectionIfCtrlReleased(QEvent *e)
{
    if (selectionRubber()->isVisible() && e->type() == QEvent::MouseMove)
    {
        QMouseEvent *event = static_cast<QMouseEvent*>(e);
        if (!(event->modifiers() & Qt::ControlModifier))
        {
            selectionRubber()->hide();
        }
    }
}

bool MarbleDefaultInputHandler::handleDoubleClick(QMouseEvent *event)
{
320
321
322
323
324
325
    qreal mouseLon;
    qreal mouseLat;
    const bool isMouseAboveMap = MarbleInputHandler::d->m_marblePresenter->map()->geoCoordinates(event->x(), event->y(),
                                             mouseLon, mouseLat, GeoDataCoordinates::Radian);
    if(isMouseAboveMap)
    {
326
        d->m_pressAndHoldTimer.stop();
327
328
329
        d->m_lmbTimer.stop();
        MarbleInputHandler::d->m_marblePresenter->moveTo(event->pos(), 0.67);
    }
330
    return acceptMouse();
331
332
333
334
335
336
337
}

bool MarbleDefaultInputHandler::handleWheel(QWheelEvent *wheelevt)
{
    MarbleAbstractPresenter *marblePresenter = MarbleInputHandler::d->m_marblePresenter;
    marblePresenter->setViewContext(Animation);

338
339
340
341
342
343
344
345
346
    if( (MarbleInputHandler::d->m_steps > 0 && wheelevt->delta() < 0) ||
        (MarbleInputHandler::d->m_steps < 0 && wheelevt->delta() > 0) )
    {
        MarbleInputHandler::d->m_steps = wheelevt->delta();
    }
    else
    {
        MarbleInputHandler::d->m_steps += wheelevt->delta();
    }
347
348

    if (marblePresenter->map()->discreteZoom())
349
    {
350
351
352
353
354
        if(qAbs(MarbleInputHandler::d->m_steps) >= MarbleInputHandler::d->m_discreteZoomSteps)
        {
            marblePresenter->zoomAtBy(wheelevt->pos(), MarbleInputHandler::d->m_steps);
            MarbleInputHandler::d->m_steps = 0;
        }
355
    }
356
    else
357
    {
358
359
360
361
362
363
364
        qreal zoom = marblePresenter->zoom();
        qreal target = MarbleInputHandler::d->m_wheelZoomTargetDistance;
        if (marblePresenter->animationsEnabled() && target > 0.0)
        {
            // Do not use intermediate (interpolated) distance values caused by animations
            zoom = marblePresenter->zoomFromDistance(target);
        }
365
        qreal newDistance = marblePresenter->distanceFromZoom(zoom + MarbleInputHandler::d->m_steps);
366
367
368
369
370
371
372
        MarbleInputHandler::d->m_wheelZoomTargetDistance = newDistance;
        marblePresenter->zoomAt(wheelevt->pos(), newDistance);
        if (MarbleInputHandler::d->m_inertialEarthRotation)
        {
            d->m_kineticSpinning.jumpToPosition(MarbleInputHandler::d->m_marblePresenter->centerLongitude(),
                                                MarbleInputHandler::d->m_marblePresenter->centerLatitude());
        }
373
        MarbleInputHandler::d->m_steps = 0;
374
375
376
377
378
379
    }

    MarbleInputHandler::d->m_mouseWheelTimer->start(400);
    return true;
}

380
bool MarbleDefaultInputHandler::handlePinch(const QPointF &center, qreal scaleFactor, Qt::GestureState state)
381
382
383
{
    qreal  destLat;
    qreal  destLon;
384

385
386
387
388
389
390
391
392
393
394
    MarbleAbstractPresenter *marblePresenter = MarbleInputHandler::d->m_marblePresenter;

    bool isValid = marblePresenter->map()->geoCoordinates(center.x(), center.y(),
                 destLon, destLat, GeoDataCoordinates::Radian );

    if (isValid)
    {
        marblePresenter->map()->viewport()->setFocusPoint(GeoDataCoordinates(destLon, destLat));
    }

395
396
397
398
    qreal zoom, target, newDistance;

    qreal zoomDelta = scaleFactor > 1.0 ? scaleFactor : -1.0/scaleFactor;

399
400
401
402
403
404
    switch (state)
    {
    case Qt::NoGesture:
        break;
    case Qt::GestureStarted:
        marblePresenter->setViewContext(Animation);
405
406
        d->m_pressAndHoldTimer.stop();
        d->m_lmbTimer.stop();
407
408
409
410
        d->m_midPressed = false;
        d->m_leftPressed = false;
        break;
    case Qt::GestureUpdated:
411
412
413
414
415
416
417
        zoom = marblePresenter->zoom();
        target = MarbleInputHandler::d->m_wheelZoomTargetDistance;
        if (marblePresenter->animationsEnabled() && target > 0.0)
        {
            // Do not use intermediate (interpolated) distance values caused by animations
            zoom = marblePresenter->zoomFromDistance(target);
        }
418
        newDistance = marblePresenter->distanceFromZoom(zoom + 20 * zoomDelta);
419
420
        MarbleInputHandler::d->m_wheelZoomTargetDistance = newDistance;
        marblePresenter->zoomAt(center.toPoint(), newDistance);
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
        break;
    case Qt::GestureFinished:
        marblePresenter->map()->viewport()->resetFocusPoint();
        marblePresenter->setViewContext(Still);
        break;
    case Qt::GestureCanceled:
        marblePresenter->map()->viewport()->resetFocusPoint();
        marblePresenter->setViewContext(Still);
        break;
    }
    return true;
}

bool MarbleDefaultInputHandler::handleGesture(QGestureEvent *ge)
{
    QPinchGesture *pinch = static_cast<QPinchGesture*>(ge->gesture(Qt::PinchGesture));
    if (!pinch)
    {
        return false;
    }

    qreal scaleFactor = pinch->scaleFactor();
    QPointF center = pinch->centerPoint();

    return handlePinch(center, scaleFactor, pinch->state());
}

void MarbleDefaultInputHandler::checkReleasedMove(QMouseEvent *event)
{
    // To prevent error from lost MouseButtonRelease events
    if (event->type() == QEvent::MouseMove && !(event->buttons() & Qt::LeftButton))
    {
        if (d->m_leftPressed)
        {
            d->m_leftPressed = false;

            if (MarbleInputHandler::d->m_inertialEarthRotation)
            {
                d->m_kineticSpinning.start();
            }
            else
            {
                MarbleInputHandler::d->m_marblePresenter->setViewContext(Still);
            }
        }
    }
467
    if (event->type() == QEvent::MouseMove && !(event->buttons() & Qt::MiddleButton))
468
469
470
471
472
473
474
475
476
    {
        d->m_midPressed = false;
    }
}

void MarbleDefaultInputHandler::handleMouseButtonPress(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton )
    {
477
        d->m_pressAndHoldTimer.start();
478
479
480
       handleLeftMouseButtonPress(event);
    }

481
    if ( event->button() == Qt::MiddleButton )
482
483
484
485
486
487
488
489
490
491
492
493
    {
       handleMiddleMouseButtonPress(event);
    }

    if ( event->button() == Qt::RightButton )
    {
       handleRightMouseButtonPress(event);
    }
}

void MarbleDefaultInputHandler::handleLeftMouseButtonPress(QMouseEvent *event)
{
494
495
496
497
498
    // silently enable the animation context without triggering a repaint
    MarbleInputHandler::d->m_marblePresenter->map()->blockSignals(true);
    MarbleInputHandler::d->m_marblePresenter->setViewContext(Animation);
    MarbleInputHandler::d->m_marblePresenter->map()->blockSignals(false);

499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
    if (isMouseButtonPopupEnabled(Qt::LeftButton))
    {
        d->m_lmbTimer.start(400);
    }

    d->m_leftPressed = true;
    d->m_midPressed = false;
    selectionRubber()->hide();

    // On the single event of a mouse button press these
    // values get stored, to enable us to e.g. calculate the
    // distance of a mouse drag while the mouse button is
    // still down.
    d->m_leftPressedX = event->x();
    d->m_leftPressedY = event->y();

    // Calculate translation of center point
    d->m_leftPressedLon = MarbleInputHandler::d->m_marblePresenter->centerLongitude();
    d->m_leftPressedLat = MarbleInputHandler::d->m_marblePresenter->centerLatitude();

    if (MarbleInputHandler::d->m_inertialEarthRotation)
    {
        d->m_kineticSpinning.stop();
        d->m_kineticSpinning.setPosition(d->m_leftPressedLon, d->m_leftPressedLat);
    }

    if (event->modifiers() & Qt::ControlModifier)
    {
Bernhard Beschow's avatar
Bernhard Beschow committed
527
        mDebug() << Q_FUNC_INFO << "Starting selection";
528
        d->m_pressAndHoldTimer.stop();
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
        d->m_lmbTimer.stop();
        d->m_selectionOrigin = event->pos();
        selectionRubber()->setGeometry(QRect(d->m_selectionOrigin, QSize()));
        selectionRubber()->show();
    }
}

void MarbleDefaultInputHandler::handleMiddleMouseButtonPress(QMouseEvent *event)
{
    d->m_midPressed = true;
    d->m_leftPressed = false;
    d->m_startingRadius = MarbleInputHandler::d->m_marblePresenter->radius();
    d->m_midPressedY = event->y();

    if (MarbleInputHandler::d->m_inertialEarthRotation)
    {
        d->m_kineticSpinning.start();
    }

    selectionRubber()->hide();
    MarbleInputHandler::d->m_marblePresenter->setViewContext(Animation);
}

void MarbleDefaultInputHandler::handleRightMouseButtonPress(QMouseEvent *event)
{
554
555
556
557
558
559
560
561
562
    d->m_rightPressed = true;
    d->m_rightOrigin = event->pos();
    d->m_rightPosition = event->pos();
    d->m_heading = MarbleInputHandler::d->m_marblePresenter->map()->heading();
    if (MarbleInputHandler::d->m_inertialEarthRotation)
    {
        d->m_kineticSpinning.stop();
        d->m_kineticSpinning.setHeading(d->m_heading);
    }
563
564
565
566
567
568
}

void MarbleDefaultInputHandler::handleMouseButtonRelease(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
569
        d->m_pressAndHoldTimer.stop();
570
        //emit current coordinates to be interpreted
571
572
573
574
575
576
577
578
579
580
581
582
583
584
        //as requested
        emit mouseClickScreenPosition(d->m_leftPressedX, d->m_leftPressedY);

        d->m_leftPressed = false;
        if (MarbleInputHandler::d->m_inertialEarthRotation)
        {
            d->m_kineticSpinning.start();
        }
        else
        {
            MarbleInputHandler::d->m_marblePresenter->setViewContext(Still);
        }
    }

585
    if (event->button() == Qt::MiddleButton)
586
587
588
589
590
591
592
593
    {
        d->m_midPressed = false;

        MarbleInputHandler::d->m_marblePresenter->setViewContext(Still);
    }

    if (event->type() == QEvent::MouseButtonRelease && event->button() == Qt::RightButton)
    {
594
595
596
597
598
599
600
601
602
603
604
605
606
607
        if (d->m_rightOrigin == event->pos())
        {
            emit rmbRequest(event->x(), event->y());
        }
        d->m_rightPressed = false;

        if (MarbleInputHandler::d->m_inertialEarthRotation)
        {
            d->m_kineticSpinning.start();
        }
        else
        {
            MarbleInputHandler::d->m_marblePresenter->setViewContext(Still);
        }
608
609
610
611
612
    }

    if (event->type() == QEvent::MouseButtonRelease && event->button() == Qt::LeftButton
         && selectionRubber()->isVisible())
    {
Bernhard Beschow's avatar
Bernhard Beschow committed
613
        mDebug() << Q_FUNC_INFO << "Leaving selection";
614
615
616
617
618
619
620
621
622
623
624
        MarbleInputHandler::d->m_marblePresenter->setSelection(selectionRubber()->geometry());
        selectionRubber()->hide();
    }
}

void MarbleDefaultInputHandler::notifyPosition(bool isMouseAboveMap, qreal mouseLon, qreal mouseLat)
{
    // emit the position string only if the signal got attached
    if (MarbleInputHandler::d->m_positionSignalConnected) {
        if (!isMouseAboveMap)
        {
625
            emit mouseMoveGeoPosition(QCoreApplication::translate( "Marble", NOT_AVAILABLE));
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
        }
        else
        {
            QString position = GeoDataCoordinates(mouseLon, mouseLat).toString();
            emit mouseMoveGeoPosition(position);
        }
    }
}

void MarbleDefaultInputHandler::adjustCursorShape(const QPoint &mousePosition, const QPoint &mouseDirection)
{
    // Find out if there are data items and if one has defined an action
    QList<AbstractDataPluginItem *> dataItems
        = MarbleInputHandler::d->m_marblePresenter->map()->whichItemAt(mousePosition);
    bool dataAction = false;
    QPointer<AbstractDataPluginItem> toolTipItem;
    QList<AbstractDataPluginItem *>::iterator it = dataItems.begin();
    QList<AbstractDataPluginItem *>::iterator const end = dataItems.end();
    for (; it != end && dataAction == false && toolTipItem.isNull(); ++it)
    {
        if ((*it)->action())
        {
            dataAction = true;
        }

        if (!(*it)->toolTip().isNull() && toolTipItem.isNull())
        {
            toolTipItem = (*it);
        }
    }

    if (toolTipItem.isNull()) {
        d->m_toolTipTimer.stop();
    }
    else if (!( d->m_lastToolTipItem.data() == toolTipItem.data()))
    {
        d->m_toolTipTimer.start();
        d->m_lastToolTipItem = toolTipItem;
        d->m_toolTipPosition = mousePosition;
    }
    else
    {
        if (!d->m_toolTipTimer.isActive())
        {
            d->m_toolTipTimer.start();
        }
        d->m_toolTipPosition = mousePosition;
    }

675
    if (!dataAction && !MarbleInputHandler::d->m_marblePresenter->map()->hasFeatureAt(mousePosition)) {
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
        if (!d->m_leftPressed)
        {
            d->m_arrowCur [1][1] = QCursor(Qt::OpenHandCursor);
        }
        else
        {
            d->m_arrowCur [1][1] = QCursor(Qt::ClosedHandCursor);
        }
    }
    else
    {
        if (!d->m_leftPressed)
        {
            d->m_arrowCur [1][1] = QCursor(Qt::PointingHandCursor);
        }
    }

    if (panViaArrowsEnabled())
    {
        setCursor(d->m_arrowCur[mouseDirection.x()+1][mouseDirection.y()+1]);
    }
    else
    {
        setCursor(d->m_arrowCur[1][1]);
    }
}

QPoint MarbleDefaultInputHandler::mouseMovedOutside(QMouseEvent *event)
{   //Returns a 2d vector representing the direction in which the mouse left
    int dirX = 0;
    int dirY = 0;
    int polarity = MarbleInputHandler::d->m_marblePresenter->viewport()->polarity();

709
710
    if (d->m_leftPressed) {
        d->m_leftPressed = false;
711

712
713
714
715
        if (MarbleInputHandler::d->m_inertialEarthRotation)
        {
            d->m_kineticSpinning.start();
        }
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
    }

    QRect boundingRect = MarbleInputHandler::d->m_marblePresenter->viewport()->mapRegion().boundingRect();

    if (boundingRect.width() != 0)
    {
        dirX = (int)( 3 * (event->x() - boundingRect.left()) / boundingRect.width()) - 1;
    }
    if (dirX > 1)
    {
        dirX = 1;
    }
    if (dirX < -1)
    {
        dirX = -1;
    }

    if (boundingRect.height() != 0)
    {
        dirY = (int)(3 * (event->y() - boundingRect.top()) / boundingRect.height()) - 1;
    }
    if (dirY > 1)
    {
        dirY = 1;
    }
    if (dirY < -1)
    {
        dirY = -1;
    }

    if (event->button() == Qt::LeftButton && event->type() == QEvent::MouseButtonPress
747
            && panViaArrowsEnabled() && !d->m_kineticSpinning.hasVelocity())
748
    {
749
        d->m_pressAndHoldTimer.stop();
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
        d->m_lmbTimer.stop();
        qreal moveStep = MarbleInputHandler::d->m_marblePresenter->moveStep();
        if (polarity < 0)
        {
            MarbleInputHandler::d->m_marblePresenter->rotateBy(-moveStep * (qreal)(+dirX), moveStep * (qreal)(+dirY));
        }
        else
        {
            MarbleInputHandler::d->m_marblePresenter->rotateBy(-moveStep * (qreal)(-dirX), moveStep * (qreal)(+dirY));
        }
    }

    if (!MarbleInputHandler::d->m_inertialEarthRotation)
    {
        MarbleInputHandler::d->m_marblePresenter->setViewContext(Still);
    }

    return QPoint(dirX, dirY);
}

bool MarbleDefaultInputHandler::handleMouseEvent(QMouseEvent *event)
{
    QPoint direction;

    checkReleasedMove(event);

    // Do not handle (and therefore eat) mouse press and release events
    // that occur above visible float items. Mouse motion events are still
    // handled, however.
    if (event->type() != QEvent::MouseMove && !selectionRubber()->isVisible())
    {
Dennis Nienhüser's avatar
Dennis Nienhüser committed
781
		auto const floatItems = MarbleInputHandler::d->m_marblePresenter->map()->floatItems();
Dennis Nienhüser's avatar
Dennis Nienhüser committed
782
        for (AbstractFloatItem *floatItem: floatItems)
783
784
785
786
        {
            if ( floatItem->enabled() && floatItem->visible()
                 && floatItem->contains( event->pos() ) )
            {
787
                d->m_pressAndHoldTimer.stop();
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
                d->m_lmbTimer.stop();
                return false;
            }
        }
    }

    qreal mouseLon;
    qreal mouseLat;
    const bool isMouseAboveMap = MarbleInputHandler::d->m_marblePresenter->map()->geoCoordinates(event->x(), event->y(),
                                             mouseLon, mouseLat, GeoDataCoordinates::Radian);
    notifyPosition(isMouseAboveMap, mouseLon, mouseLat);

    QPoint mousePosition(event->x(), event->y());

    if (isMouseAboveMap || selectionRubber()->isVisible()
803
         || MarbleInputHandler::d->m_marblePresenter->map()->hasFeatureAt(mousePosition))
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            handleMouseButtonPress(event);
        }

        if (event->type() == QEvent::MouseButtonRelease)
        {
            handleMouseButtonRelease(event);
        }

        // Regarding all kinds of mouse moves:
        if (d->m_leftPressed && !selectionRubber()->isVisible())
        {
            qreal radius = (qreal)(MarbleInputHandler::d->m_marblePresenter->radius());
819
820
            qreal deltax = event->x() - d->m_leftPressedX;
            qreal deltay = event->y() - d->m_leftPressedY;
821

822
823
            if (qAbs(deltax) > d->m_dragThreshold
                 || qAbs(deltay) > d->m_dragThreshold
824
825
                 || !d->m_lmbTimer.isActive())
            {
826
827
                MarbleInputHandler::d->m_marblePresenter->setViewContext(Animation);

828
                d->m_pressAndHoldTimer.stop();
829
                d->m_lmbTimer.stop();
830
831
832
833
834
835
836
                const Quaternion rotation = Quaternion::fromEuler( 0, 0, MarbleInputHandler::d->m_marblePresenter->map()->heading() * DEG2RAD );
                Quaternion quat = Quaternion::fromSpherical( - M_PI/2 * deltax / radius, + M_PI/2 * deltay / radius );
                quat.rotateAroundAxis( rotation );
                qreal lon, lat;
                quat.getSpherical( lon, lat );
                const qreal posLon = d->m_leftPressedLon + RAD2DEG * lon;
                const qreal posLat = d->m_leftPressedLat + RAD2DEG * lat;
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
                MarbleInputHandler::d->m_marblePresenter->centerOn(posLon, posLat);
                if (MarbleInputHandler::d->m_inertialEarthRotation)
                {
                    d->m_kineticSpinning.setPosition(posLon, posLat);
                }
            }
        }

        if (d->m_midPressed)
        {
            int eventy = event->y();
            int dy = d->m_midPressedY - eventy;
            MarbleInputHandler::d->m_marblePresenter->setRadius(d->m_startingRadius * pow(1.005, dy));
        }

852
        if (d->m_rightPressed && MarbleInputHandler::d->m_mouseViewRotation)
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
        {
            qreal centerX, centerY;
            MarbleInputHandler::d->m_marblePresenter->map()->screenCoordinates(
                MarbleInputHandler::d->m_marblePresenter->centerLongitude(),
                MarbleInputHandler::d->m_marblePresenter->centerLatitude(), centerX, centerY);

            // Deltas from previous position.
            int dx = event->x() - d->m_rightPosition.x();
            int dy = event->y() - d->m_rightPosition.y();

            d->m_rightPosition = event->pos();

            // Moving on the bottom should be opposite direction.
            int sign = event->y() > centerY ? -1 : 1;
            // Left top and right bottom sides for y axis should be opposite direction.
            if ((event->x() < centerX && event->y() < centerY) || (event->x() > centerX && event->y() > centerY))
            {
                dy *= -1;
            }

            const qreal speedFactor = 0.3;
            d->m_heading += (dx + dy) * sign * speedFactor;
            MarbleInputHandler::d->m_marblePresenter->map()->setHeading(d->m_heading);
            if (MarbleInputHandler::d->m_inertialEarthRotation)
            {
                d->m_kineticSpinning.setHeading(d->m_heading);
            }
        }

882
883
884
885
886
887
888
889
890
891
892
        if (selectionRubber()->isVisible())
        {
            // We change selection.
            selectionRubber()->setGeometry(QRect(d->m_selectionOrigin, event->pos()).normalized());
        }
    }
    else
    {
        direction = mouseMovedOutside(event);
    }

893
894
895
    if (MarbleInputHandler::d->m_marblePresenter->viewContext() != Animation) {
        adjustCursorShape(mousePosition, direction);
    }
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
    return acceptMouse();
}

bool MarbleDefaultInputHandler::acceptMouse()
{
    // let others, especially float items, still process the event
    // Note: This caused a bug in combination with oxygen, see https://bugs.kde.org/show_bug.cgi?id=242414
    // and changing it a related regression, see https://bugs.kde.org/show_bug.cgi?id=324862
    return false;
}

bool MarbleDefaultInputHandler::eventFilter(QObject* o, QEvent* e)
{
    Q_UNUSED(o);

    if (layersEventFilter(o, e))
    {
        return true;
    }

    hideSelectionIfCtrlReleased(e);

    switch (e->type())
    {
    case QEvent::TouchBegin:
    case QEvent::TouchUpdate:
    case QEvent::TouchEnd:
        return handleTouch(static_cast<QTouchEvent *>(e));
    case QEvent::KeyPress:
        return handleKeyPress(static_cast<QKeyEvent *>(e));
    case QEvent::Gesture:
        return handleGesture(static_cast<QGestureEvent *>(e));
    case QEvent::Wheel:
        return handleWheel(static_cast<QWheelEvent*>(e));
    case QEvent::MouseButtonDblClick:
        return handleDoubleClick(static_cast<QMouseEvent*>(e));
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseMove:
        return handleMouseEvent(static_cast<QMouseEvent*>(e));
    default:
        return false;
    }
}

bool MarbleDefaultInputHandler::handleTouch(QTouchEvent*)
{
    return false; //reimplement to handle in cases of QML and PinchArea element
}

bool MarbleDefaultInputHandler::handleKeyPress(QKeyEvent* event)
{
    if ( event->type() == QEvent::KeyPress ) {
        MarbleAbstractPresenter *marblePresenter = MarbleInputHandler::d->m_marblePresenter;
        bool handled = true;
        switch ( event->key() ) {
        case Qt::Key_Left:
953
            stopInertialEarthRotation();
954
955
956
            marblePresenter->moveByStep(-1, 0);
            break;
        case Qt::Key_Right:
957
            stopInertialEarthRotation();
958
959
960
            marblePresenter->moveByStep(1, 0);
            break;
        case Qt::Key_Up:
961
            stopInertialEarthRotation();
962
963
964
            marblePresenter->moveByStep(0, -1);
            break;
        case Qt::Key_Down:
965
            stopInertialEarthRotation();
966
967
968
            marblePresenter->moveByStep(0, 1);
            break;
        case Qt::Key_Plus:
969
            if (event->modifiers() != Qt::ControlModifier) {
970
                stopInertialEarthRotation();
971
972
                marblePresenter->zoomIn();
            }
973
974
            break;
        case Qt::Key_Minus:
975
            if (event->modifiers() != Qt::ControlModifier) {
976
                stopInertialEarthRotation();
977
978
                marblePresenter->zoomOut();
            }
979
980
            break;
        case Qt::Key_Home:
981
            stopInertialEarthRotation();
982
983
984
985
986
987
988
989
990
991
992
993
            marblePresenter->goHome();
            break;
        default:
            handled = false;
            break;
        }

        return handled;
    }
    return false;
}

994
995
996
997
998
999
1000
1001
1002
1003
void MarbleDefaultInputHandler::handleMouseButtonPressAndHold(const QPoint &)
{
    // Default implementation does nothing
}

void MarbleDefaultInputHandler::handlePressAndHold()
{
    handleMouseButtonPressAndHold(QPoint(d->m_leftPressedX, d->m_leftPressedY));
}

1004
const AbstractDataPluginItem *MarbleDefaultInputHandler::lastToolTipItem() const
1005
1006
1007
1008
1009
1010
1011
1012
1013
{
    return d->m_lastToolTipItem;
}

QTimer* MarbleDefaultInputHandler::toolTipTimer()
{
    return &d->m_toolTipTimer;
}

1014
QPoint MarbleDefaultInputHandler::toolTipPosition() const
1015
1016
1017
1018
1019
1020
{
    return d->m_toolTipPosition;
}

}

1021
#include "moc_MarbleInputHandler.cpp"
1022