blob: 23993fafc444d15419b35e4902919fa6387f25ab [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdeclarativegeomapitembase_p.h"
#include "qgeocameradata_p.h"
#include <QtLocation/private/qgeomap_p.h>
#include <QtQml/QQmlInfo>
#include <QtQuick/QSGOpacityNode>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/private/qquickitem_p.h>
QT_BEGIN_NAMESPACE
QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent()
: zoomLevelChanged(false),
centerChanged(false),
mapSizeChanged(false),
tiltChanged(false),
bearingChanged(false),
rollChanged(false)
{
}
QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other)
{
this->operator=(other);
}
QGeoMapViewportChangeEvent &QGeoMapViewportChangeEvent::operator=(const QGeoMapViewportChangeEvent &other)
{
if (this == &other)
return (*this);
cameraData = other.cameraData;
mapSize = other.mapSize;
zoomLevelChanged = other.zoomLevelChanged;
centerChanged = other.centerChanged;
mapSizeChanged = other.mapSizeChanged;
tiltChanged = other.tiltChanged;
bearingChanged = other.bearingChanged;
rollChanged = other.rollChanged;
return (*this);
}
QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
: QQuickItem(parent), map_(0), quickMap_(0), parentGroup_(0)
{
setFiltersChildMouseEvents(true);
connect(this, SIGNAL(childrenChanged()),
this, SLOT(afterChildrenChanged()));
// Changing opacity on a mapItemGroup should affect also the opacity on the children.
// This must be notified to plugins, if they are to render the item.
connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
}
QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
{
disconnect(this, SLOT(afterChildrenChanged()));
if (quickMap_)
quickMap_->removeMapItem(this);
}
/*!
\internal
*/
void QDeclarativeGeoMapItemBase::afterChildrenChanged()
{
QList<QQuickItem *> kids = childItems();
if (kids.size() > 0) {
bool printedWarning = false;
foreach (QQuickItem *i, kids) {
if (i->flags() & QQuickItem::ItemHasContents
&& !qobject_cast<QQuickMouseArea *>(i)) {
if (!printedWarning) {
qmlWarning(this) << "Geographic map items do not support child items";
printedWarning = true;
}
qmlWarning(i) << "deleting this child";
i->deleteLater();
}
}
}
}
/*!
\internal
*/
void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
{
if (quickMap == quickMap_)
return;
if (quickMap && quickMap_)
return; // don't allow association to more than one map
quickMap_ = quickMap;
map_ = map;
if (map_ && quickMap_) {
// For performance reasons we're not connecting map_'s and quickMap_'s signals to this.
// Rather, the handling of cameraDataChanged, visibleAreaChanged, heightChanged and widthChanged is done explicitly in QDeclarativeGeoMap by directly calling methods on the items.
// See QTBUG-76950
lastSize_ = QSizeF(quickMap_->width(), quickMap_->height());
lastCameraData_ = map_->cameraData();
}
}
/*!
\internal
*/
void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData)
{
QGeoMapViewportChangeEvent evt;
evt.cameraData = cameraData;
evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
if (evt.mapSize != lastSize_)
evt.mapSizeChanged = true;
if (cameraData.bearing() != lastCameraData_.bearing())
evt.bearingChanged = true;
if (cameraData.center() != lastCameraData_.center())
evt.centerChanged = true;
if (cameraData.roll() != lastCameraData_.roll())
evt.rollChanged = true;
if (cameraData.tilt() != lastCameraData_.tilt())
evt.tiltChanged = true;
if (cameraData.zoomLevel() != lastCameraData_.zoomLevel())
evt.zoomLevelChanged = true;
lastSize_ = evt.mapSize;
lastCameraData_ = cameraData;
afterViewportChanged(evt);
}
void QDeclarativeGeoMapItemBase::visibleAreaChanged()
{
QGeoMapViewportChangeEvent evt;
evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
afterViewportChanged(evt);
}
/*!
\internal
*/
void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset)
{
if (!map_ || !quickMap_)
return;
QDoubleVector2D pos;
if (map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) {
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
QDoubleVector2D wrappedProjection = p.geoToWrappedMapProjection(coordinate);
if (!p.isProjectable(wrappedProjection))
return;
pos = p.wrappedMapProjectionToItemPosition(wrappedProjection);
} else {
pos = map()->geoProjection().coordinateToItemPosition(coordinate, false);
if (qIsNaN(pos.x()))
return;
}
QPointF topLeft = pos.toPointF() - offset;
setPosition(topLeft);
}
bool QDeclarativeGeoMapItemBase::autoFadeIn() const
{
return m_autoFadeIn;
}
static const double opacityRampMin = 1.5;
static const double opacityRampMax = 2.5;
void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn)
{
if (fadeIn == m_autoFadeIn)
return;
m_autoFadeIn = fadeIn;
if (quickMap_ && quickMap_->zoomLevel() < opacityRampMax)
polishAndUpdate();
}
/*!
\internal
*/
float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const
{
if (!m_autoFadeIn) // Consider skipping the opacity node instead.
return 1.0;
else if (quickMap_->zoomLevel() > opacityRampMax)
return 1.0;
else if (quickMap_->zoomLevel() > opacityRampMin)
return quickMap_->zoomLevel() - opacityRampMin;
else
return 0.0;
}
bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event)
{
Q_UNUSED(item);
if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) {
// In case of items that are not rectangles, this filter is used to test if the event has landed
// inside the actual item shape.
// If so, the method returns true, meaning that it prevents the event delivery to child "*item" (for example,
// a mouse area that is on top of this map item).
// However, this method sets "accepted" to false, so that the event can still be passed further up,
// specifically to the parent Map, that is a sort of flickable.
// Otherwise, if the event is not contained within the map item, the method returns false, meaning the event
// is delivered to the child *item (like the mouse area associated).
event->setAccepted(false);
return true;
}
return false;
}
/*!
\internal
*/
QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd)
{
if (!map_ || !quickMap_ || map_->supportedMapItemTypes() & itemType()) {
if (oldNode)
delete oldNode;
oldNode = 0;
return 0;
}
QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode);
if (!opn)
opn = new QSGOpacityNode();
opn->setOpacity(zoomLevelOpacity());
QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0;
opn->removeAllChildNodes();
if (opn->opacity() > 0.0) {
QSGNode *n = this->updateMapItemPaintNode(oldN, pd);
if (n)
opn->appendChildNode(n);
} else {
delete oldN;
}
return opn;
}
/*!
\internal
*/
QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
delete oldNode;
return 0;
}
QGeoMap::ItemType QDeclarativeGeoMapItemBase::itemType() const
{
return m_itemType;
}
/*!
\internal
The actual combined opacity of the item. Needed by custom renderer to look like
the scene-graph one.
*/
qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const
{
if (parentGroup_)
return parentGroup_->mapItemOpacity() * opacity();
return opacity();
}
void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup)
{
parentGroup_ = &parentGroup;
if (parentGroup_) {
connect(parentGroup_, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged,
this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
}
}
bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
{
return QQuickItemPrivate::get(this)->polishScheduled;
}
void QDeclarativeGeoMapItemBase::polishAndUpdate()
{
polish();
update();
}
QT_END_NAMESPACE