/**************************************************************************** ** ** 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 #include #include #include #include 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 kids = childItems(); if (kids.size() > 0) { bool printedWarning = false; foreach (QQuickItem *i, kids) { if (i->flags() & QQuickItem::ItemHasContents && !qobject_cast(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(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(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(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