1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2008 Dennis Nienhüser <nienhueser@kde.org>
4 // SPDX-FileCopyrightText: 2010 Bastian Holst <bastianholst@gmx.de>
5 // SPDX-FileCopyrightText: 2013 Mohammed Nafees <nafees.technocool@gmail.com>
6 //
7 
8 #include "NavigationFloatItem.h"
9 
10 #include <qmath.h>
11 #include <QContextMenuEvent>
12 #include <QRect>
13 #include <QSlider>
14 #include <QWidget>
15 #include <QPainter>
16 #include <QPixmapCache>
17 
18 #include "ui_navigation.h"
19 #include "ViewportParams.h"
20 #include "MarbleDebug.h"
21 #include "MarbleWidget.h"
22 #include "MarbleModel.h"
23 #include "PositionTracking.h"
24 #include "WidgetGraphicsItem.h"
25 #include "MarbleGraphicsGridLayout.h"
26 
27 using namespace Marble;
28 /* TRANSLATOR Marble::NavigationFloatItem */
29 
NavigationFloatItem(const MarbleModel * marbleModel)30 NavigationFloatItem::NavigationFloatItem( const MarbleModel *marbleModel )
31     : AbstractFloatItem( marbleModel, QPointF( -10, -30 ) ),
32       m_marbleWidget( nullptr ),
33       m_widgetItem( nullptr ),
34       m_navigationWidget( nullptr ),
35       m_oldViewportRadius( 0 ),
36       m_contextMenu( nullptr ),
37       m_showHomeButton( true )
38 {
39     // Plugin is visible by default on desktop systems
40     const bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
41     setEnabled( !smallScreen );
42     setVisible( true );
43 
44     setCacheMode( NoCache );
45     setBackground( QBrush( QColor( Qt::transparent ) ) );
46     setFrame( NoFrame );
47 }
48 
~NavigationFloatItem()49 NavigationFloatItem::~NavigationFloatItem()
50 {
51     delete m_navigationWidget;
52 }
53 
backendTypes() const54 QStringList NavigationFloatItem::backendTypes() const
55 {
56     return QStringList(QStringLiteral("navigation"));
57 }
58 
name() const59 QString NavigationFloatItem::name() const
60 {
61     return tr("Navigation");
62 }
63 
guiString() const64 QString NavigationFloatItem::guiString() const
65 {
66     return tr("&Navigation");
67 }
68 
nameId() const69 QString NavigationFloatItem::nameId() const
70 {
71     return QStringLiteral("navigation");
72 }
73 
version() const74 QString NavigationFloatItem::version() const
75 {
76     return QStringLiteral("1.0");
77 }
78 
description() const79 QString NavigationFloatItem::description() const
80 {
81     return tr("A mouse control to zoom and move the map");
82 }
83 
copyrightYears() const84 QString NavigationFloatItem::copyrightYears() const
85 {
86     return QStringLiteral("2008, 2010, 2013");
87 }
88 
pluginAuthors() const89 QVector<PluginAuthor> NavigationFloatItem::pluginAuthors() const
90 {
91     return QVector<PluginAuthor>()
92             << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org"))
93             << PluginAuthor(QStringLiteral("Bastian Holst"), QStringLiteral("bastianholst@gmx.de"))
94             << PluginAuthor(QStringLiteral("Mohammed Nafees"), QStringLiteral("nafees.technocool@gmail.com"));
95 }
96 
icon() const97 QIcon NavigationFloatItem::icon() const
98 {
99     return QIcon(QStringLiteral(":/icons/navigation.png"));
100 }
101 
initialize()102 void NavigationFloatItem::initialize()
103 {
104     QWidget *navigationParent = new QWidget( nullptr );
105     navigationParent->setAttribute( Qt::WA_NoSystemBackground, true );
106 
107     m_navigationWidget = new Ui::Navigation;
108     m_navigationWidget->setupUi( navigationParent );
109 
110     m_widgetItem = new WidgetGraphicsItem( this );
111     m_widgetItem->setWidget( navigationParent );
112 
113     MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 );
114     layout->addItem( m_widgetItem, 0, 0 );
115 
116     setLayout( layout );
117 
118     if ( m_showHomeButton ) {
119       activateHomeButton();
120     } else {
121       activateCurrentPositionButton();
122     }
123 }
124 
isInitialized() const125 bool NavigationFloatItem::isInitialized() const
126 {
127     return m_widgetItem;
128 }
129 
setProjection(const ViewportParams * viewport)130 void NavigationFloatItem::setProjection( const ViewportParams *viewport )
131 {
132     if ( viewport->radius() != m_oldViewportRadius ) {
133         m_oldViewportRadius = viewport->radius();
134         // The slider depends on the map state (zoom factor)
135         update();
136     }
137 
138     AbstractFloatItem::setProjection( viewport );
139 }
140 
eventFilter(QObject * object,QEvent * e)141 bool NavigationFloatItem::eventFilter( QObject *object, QEvent *e )
142 {
143     if ( !enabled() || !visible() ) {
144         return false;
145     }
146 
147     MarbleWidget *widget = dynamic_cast<MarbleWidget*> (object);
148     if ( !widget ) {
149         return AbstractFloatItem::eventFilter( object, e );
150     }
151 
152     if ( m_marbleWidget != widget ) {
153         // Delayed initialization
154         m_marbleWidget = widget;
155 
156         m_maxZoom = m_marbleWidget->maximumZoom();
157         m_minZoom = m_marbleWidget->minimumZoom();
158 
159         m_navigationWidget->arrowDisc->setMarbleWidget( m_marbleWidget );
160         connect( m_navigationWidget->arrowDisc, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
161 
162         connect( m_navigationWidget->homeButton, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
163         if ( m_showHomeButton ) {
164           activateHomeButton();
165         } else {
166           activateCurrentPositionButton();
167         }
168 
169         connect( m_navigationWidget->zoomInButton, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
170         connect( m_navigationWidget->zoomInButton, SIGNAL(clicked()),
171                  m_marbleWidget, SLOT(zoomIn()) );
172 
173         m_navigationWidget->zoomSlider->setMaximum( m_maxZoom );
174         m_navigationWidget->zoomSlider->setMinimum( m_minZoom );
175         connect( m_navigationWidget->zoomSlider, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
176         connect( m_navigationWidget->zoomSlider, SIGNAL(valueChanged(int)),
177                  m_marbleWidget, SLOT(setZoom(int)) );
178 
179         connect( m_navigationWidget->zoomOutButton, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
180         connect( m_navigationWidget->zoomOutButton, SIGNAL(clicked()),
181                  m_marbleWidget, SLOT(zoomOut()) );
182 
183         connect( m_marbleWidget, SIGNAL(zoomChanged(int)), SLOT(updateButtons(int)) );
184         updateButtons( m_marbleWidget->zoom() );
185         connect( m_marbleWidget, SIGNAL(themeChanged(QString)), this, SLOT(selectTheme(QString)) );
186      }
187 
188     return AbstractFloatItem::eventFilter(object, e);
189 }
190 
selectTheme(const QString &)191 void NavigationFloatItem::selectTheme( const QString& )
192 {
193     if ( m_marbleWidget ) {
194         m_maxZoom = m_marbleWidget->maximumZoom();
195         m_minZoom = m_marbleWidget->minimumZoom();
196         m_navigationWidget->zoomSlider->setMaximum( m_maxZoom );
197         m_navigationWidget->zoomSlider->setMinimum( m_minZoom );
198         updateButtons( m_marbleWidget->zoom() );
199     }
200 }
201 
updateButtons(int zoomValue)202 void NavigationFloatItem::updateButtons( int zoomValue )
203 {
204     bool const zoomInEnabled = m_navigationWidget->zoomInButton->isEnabled();
205     bool const zoomOutEnabled = m_navigationWidget->zoomOutButton->isEnabled();
206     int const oldZoomValue = m_navigationWidget->zoomSlider->value();
207     m_navigationWidget->zoomInButton->setEnabled( zoomValue < m_maxZoom );
208     m_navigationWidget->zoomOutButton->setEnabled( zoomValue > m_minZoom );
209     m_navigationWidget->zoomSlider->setValue( zoomValue );
210     if ( zoomInEnabled != m_navigationWidget->zoomInButton->isEnabled() ||
211          zoomOutEnabled != m_navigationWidget->zoomOutButton->isEnabled() ||
212          oldZoomValue != zoomValue ) {
213         update();
214     }
215 }
216 
pixmap(const QString & id)217 QPixmap NavigationFloatItem::pixmap( const QString &id )
218 {
219     QPixmap result;
220     if ( !QPixmapCache::find( id, &result ) ) {
221         result = QPixmap(QLatin1String(":/") + id + QLatin1String(".png"));
222         QPixmapCache::insert( id, result );
223     }
224     return result;
225 }
226 
paintContent(QPainter * painter)227 void NavigationFloatItem::paintContent( QPainter *painter )
228 {
229     painter->drawPixmap( 0, 0, pixmap( "marble/navigation/navigational_backdrop_top" ) );
230     painter->drawPixmap( 0, 70, pixmap( "marble/navigation/navigational_backdrop_center" ) );
231     painter->drawPixmap( 0, 311, pixmap( "marble/navigation/navigational_backdrop_bottom" ) );
232 }
233 
contextMenuEvent(QWidget * w,QContextMenuEvent * e)234 void NavigationFloatItem::contextMenuEvent( QWidget *w, QContextMenuEvent *e )
235 {
236     if ( !m_contextMenu ) {
237         m_contextMenu = contextMenu();
238 
239         m_activateCurrentPositionButtonAction = new QAction( QIcon(),
240                                                              tr( "Current Location Button" ),
241                                                              m_contextMenu );
242         m_activateHomeButtonAction = new QAction(QIcon(QStringLiteral(":/icons/go-home.png")),
243                                                              tr( "Home Button" ),
244                                                              m_contextMenu );
245         m_activateHomeButtonAction->setVisible( !m_showHomeButton );
246         m_activateCurrentPositionButtonAction->setVisible( m_showHomeButton );
247         m_contextMenu->addSeparator();
248         m_contextMenu->addAction( m_activateCurrentPositionButtonAction );
249         m_contextMenu->addAction( m_activateHomeButtonAction );
250 
251         connect( m_activateCurrentPositionButtonAction, SIGNAL(triggered()), SLOT(activateCurrentPositionButton()) );
252         connect( m_activateHomeButtonAction, SIGNAL(triggered()), SLOT(activateHomeButton()) );
253     }
254 
255     Q_ASSERT( m_contextMenu );
256     m_contextMenu->exec( w->mapToGlobal( e->pos() ) );
257 }
258 
activateCurrentPositionButton()259 void NavigationFloatItem::activateCurrentPositionButton()
260 {
261     if ( !isInitialized() ) {
262         return;
263     }
264 
265     QIcon icon;
266     icon.addPixmap( pixmap("marble/navigation/navigational_currentlocation"), QIcon::Normal );
267     icon.addPixmap( pixmap("marble/navigation/navigational_currentlocation_hover"), QIcon::Active );
268     icon.addPixmap( pixmap("marble/navigation/navigational_currentlocation_pressed"), QIcon::Selected );
269     m_navigationWidget->homeButton->setProperty("icon", QVariant(icon));
270 
271     if ( m_contextMenu ) {
272         m_activateCurrentPositionButtonAction->setVisible( false );
273         m_activateHomeButtonAction->setVisible( true );
274     }
275 
276     if (m_marbleWidget) {
277       disconnect( m_navigationWidget->homeButton, SIGNAL(clicked()), m_marbleWidget, SLOT(goHome()) );
278     }
279     connect( m_navigationWidget->homeButton, SIGNAL(clicked()), SLOT(centerOnCurrentLocation()) );
280     emit repaintNeeded();
281     m_showHomeButton = false;
282     emit settingsChanged( nameId() );
283 }
284 
activateHomeButton()285 void NavigationFloatItem::activateHomeButton()
286 {
287     if ( !isInitialized() ) {
288         return;
289     }
290 
291     QIcon icon;
292     icon.addPixmap( pixmap("marble/navigation/navigational_homebutton"), QIcon::Normal );
293     icon.addPixmap( pixmap("marble/navigation/navigational_homebutton_hover"), QIcon::Active );
294     icon.addPixmap( pixmap("marble/navigation/navigational_homebutton_press"), QIcon::Selected );
295     m_navigationWidget->homeButton->setProperty("icon", QVariant(icon));
296 
297     if ( m_contextMenu ) {
298         m_activateCurrentPositionButtonAction->setVisible( true );
299         m_activateHomeButtonAction->setVisible( false );
300     }
301 
302     disconnect( m_navigationWidget->homeButton, SIGNAL(clicked()), this, SLOT(centerOnCurrentLocation()) );
303     if (m_marbleWidget) {
304       connect( m_navigationWidget->homeButton, SIGNAL(clicked()), m_marbleWidget, SLOT(goHome()) );
305     }
306     emit repaintNeeded();
307     m_showHomeButton = true;
308     emit settingsChanged( nameId() );
309 }
310 
centerOnCurrentLocation()311 void NavigationFloatItem::centerOnCurrentLocation()
312 {
313     if ( m_marbleWidget->model()->positionTracking()->currentLocation().isValid() ) {
314         m_marbleWidget->centerOn( m_marbleWidget->model()->positionTracking()->currentLocation(), true );
315     }
316 }
317 
settings() const318 QHash<QString,QVariant> NavigationFloatItem::settings() const
319 {
320     QHash<QString, QVariant> settings = AbstractFloatItem::settings();
321     settings.insert(QStringLiteral("showHomeButton"), m_showHomeButton);
322     return settings;
323 }
324 
setSettings(const QHash<QString,QVariant> & settings)325 void NavigationFloatItem::setSettings( const QHash<QString, QVariant> &settings )
326 {
327     AbstractFloatItem::setSettings( settings );
328     m_showHomeButton = settings.value(QStringLiteral("showHomeButton"), true).toBool();
329     if ( m_showHomeButton ) {
330         activateHomeButton();
331     } else {
332         activateCurrentPositionButton();
333     }
334 }
335 
336 #include "moc_NavigationFloatItem.cpp"
337