diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3f05fcc..d49272b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -23,6 +23,7 @@ set(MLNQtCore_Headers utils.hpp style/style_parameter.hpp + style/filter_parameter.hpp style/layer_parameter.hpp style/source_parameter.hpp ) @@ -66,6 +67,7 @@ target_sources( utils.cpp style/style_parameter.cpp + style/filter_parameter.cpp style/layer_parameter.cpp style/source_parameter.cpp diff --git a/src/core/conversion_p.hpp b/src/core/conversion_p.hpp index 38b03d4..884779b 100644 --- a/src/core/conversion_p.hpp +++ b/src/core/conversion_p.hpp @@ -27,6 +27,9 @@ class ConversionTraits { static bool isArray(const QVariant &value) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (value.metaType() == QMetaType(QMetaType::QString)) { + return false; + } return QMetaType::canConvert(value.metaType(), QMetaType(QMetaType::QVariantList)); #else return value.canConvert(QVariant::List); diff --git a/src/core/map.cpp b/src/core/map.cpp index fbac15c..d8e6abd 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -1443,6 +1443,11 @@ void Map::setFilter(const QString &layerId, const QVariant &filter) { return; } + if (filter.isNull() || filter.toList().isEmpty()) { + layer->setFilter(mbgl::style::Filter()); + return; + } + mbgl::style::conversion::Error error; std::optional converted = mbgl::style::conversion::convert(filter, error); if (!converted) { diff --git a/src/core/style/filter_parameter.cpp b/src/core/style/filter_parameter.cpp new file mode 100644 index 0000000..0c10d61 --- /dev/null +++ b/src/core/style/filter_parameter.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2023 MapLibre contributors + +// SPDX-License-Identifier: BSD-2-Clause + +#include "filter_parameter.hpp" + +#include "style_parameter.hpp" + +namespace QMapLibre { + +/*! + \class FilterParameter + \brief A helper utility to manage filter parameters for a layer. + \ingroup QMapLibre + + \headerfile filter_parameter.hpp +*/ + +/*! + \brief Default constructor +*/ +FilterParameter::FilterParameter(QObject *parent) + : StyleParameter(parent) {} + +FilterParameter::~FilterParameter() = default; + +/*! + \fn void FilterParameter::expressionUpdated() + \brief Signal emitted when the filter expression is updated. +*/ + +/*! + \brief Filter expression. + \return \c QVariantList. +*/ +QVariantList FilterParameter::expression() const { + return m_expression; +} + +/*! + \brief Set the filter expression. + \param expression Filter expression as \c QVariantList. + + \ref expressionUpdated() signal is emitted when the expression is updated. +*/ +void FilterParameter::setExpression(const QVariantList &expression) { + if (m_expression == expression) { + return; + } + + m_expression = expression; + + Q_EMIT expressionUpdated(); +} + +/*! + \var FilterParameter::m_expression + \brief Filter expression +*/ + +} // namespace QMapLibre diff --git a/src/core/style/filter_parameter.hpp b/src/core/style/filter_parameter.hpp new file mode 100644 index 0000000..b6fc3f4 --- /dev/null +++ b/src/core/style/filter_parameter.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2023 MapLibre contributors + +// SPDX-License-Identifier: BSD-2-Clause + +#ifndef QMAPLIBRE_FILTER_PARAMETER_H +#define QMAPLIBRE_FILTER_PARAMETER_H + +#include "style_parameter.hpp" + +#include + +#include +#include +#include + +namespace QMapLibre { + +class Q_MAPLIBRE_CORE_EXPORT FilterParameter : public StyleParameter { + Q_OBJECT +public: + explicit FilterParameter(QObject *parent = nullptr); + ~FilterParameter() override; + + [[nodiscard]] QVariantList expression() const; + void setExpression(const QVariantList &expression); + +Q_SIGNALS: + void expressionUpdated(); + +protected: + QVariantList m_expression; + + Q_DISABLE_COPY(FilterParameter) +}; + +} // namespace QMapLibre + +#endif // QMAPLIBRE_FILTER_PARAMETER_H diff --git a/src/core/style/layer_style_change.cpp b/src/core/style/layer_style_change.cpp index b79de30..8236c09 100644 --- a/src/core/style/layer_style_change.cpp +++ b/src/core/style/layer_style_change.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: BSD-2-Clause +#include "filter_parameter.hpp" #include "layer_parameter.hpp" #include "layer_style_change_p.hpp" #include "style_change_utils_p.hpp" @@ -144,10 +145,14 @@ void StyleSetPaintProperties::apply(Map *map) { } // StyleSetFilter -StyleSetFilter::StyleSetFilter(QString layerId, QVariant expression) +StyleSetFilter::StyleSetFilter(QString layerId, QVariantList expression) : m_layerId(std::move(layerId)), m_expression(std::move(expression)) {} +StyleSetFilter::StyleSetFilter(const FilterParameter *parameter) + : m_layerId(parameter->styleId()), + m_expression(parameter->expression()) {} + void StyleSetFilter::apply(Map *map) { if (map == nullptr) { return; diff --git a/src/core/style/layer_style_change_p.hpp b/src/core/style/layer_style_change_p.hpp index 14a792e..acf458c 100644 --- a/src/core/style/layer_style_change_p.hpp +++ b/src/core/style/layer_style_change_p.hpp @@ -5,6 +5,7 @@ #pragma once #include "export_core.hpp" +#include "filter_parameter.hpp" #include "layer_parameter.hpp" #include "style_change_p.hpp" #include "types.hpp" @@ -72,13 +73,14 @@ class Q_MAPLIBRE_CORE_EXPORT StyleSetPaintProperties : public StyleChange { class Q_MAPLIBRE_CORE_EXPORT StyleSetFilter : public StyleChange { public: - explicit StyleSetFilter(QString layerId, QVariant expression); + explicit StyleSetFilter(QString layerId, QVariantList expression); + explicit StyleSetFilter(const FilterParameter *parameter); void apply(Map *map) override; private: QString m_layerId; - QVariant m_expression; + QVariantList m_expression; }; } // namespace QMapLibre diff --git a/src/core/style/style_change.cpp b/src/core/style/style_change.cpp index 3f42630..4533af9 100644 --- a/src/core/style/style_change.cpp +++ b/src/core/style/style_change.cpp @@ -49,6 +49,12 @@ std::vector> StyleChange::addParameter(const StyleP return changes; } + const auto *filterParameter = qobject_cast(parameter); + if (filterParameter != nullptr) { + changes.emplace_back(std::make_unique(filterParameter)); + return changes; + } + return changes; } @@ -67,6 +73,12 @@ std::vector> StyleChange::removeParameter(const Sty return changes; } + const auto *filterParameter = qobject_cast(parameter); + if (filterParameter != nullptr) { + changes.emplace_back(std::make_unique(filterParameter->styleId(), QVariantList())); + return changes; + } + return changes; } diff --git a/src/location/plugins/CMakeLists.txt b/src/location/plugins/CMakeLists.txt index fd84b20..38e543b 100644 --- a/src/location/plugins/CMakeLists.txt +++ b/src/location/plugins/CMakeLists.txt @@ -88,6 +88,7 @@ set(Plugin_Sources qml_types.hpp declarative_style.cpp declarative_style.hpp declarative_style_parameter.hpp + declarative_filter_parameter.cpp declarative_filter_parameter.hpp declarative_layer_parameter.cpp declarative_layer_parameter.hpp declarative_source_parameter.cpp declarative_source_parameter.hpp diff --git a/src/location/plugins/declarative_filter_parameter.cpp b/src/location/plugins/declarative_filter_parameter.cpp new file mode 100644 index 0000000..4d57e3b --- /dev/null +++ b/src/location/plugins/declarative_filter_parameter.cpp @@ -0,0 +1,12 @@ +// Copyright (C) 2023 MapLibre contributors + +// SPDX-License-Identifier: BSD-2-Clause + +#include "declarative_filter_parameter.hpp" + +namespace QMapLibre { + +DeclarativeFilterParameter::DeclarativeFilterParameter(QObject *parent) + : FilterParameter(parent) {} + +} // namespace QMapLibre diff --git a/src/location/plugins/declarative_filter_parameter.hpp b/src/location/plugins/declarative_filter_parameter.hpp new file mode 100644 index 0000000..05426c1 --- /dev/null +++ b/src/location/plugins/declarative_filter_parameter.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2023 MapLibre contributors + +// SPDX-License-Identifier: BSD-2-Clause + +#pragma once + +#include "declarative_style_parameter.hpp" + +#include + +#include +#include + +namespace QMapLibre { + +class DeclarativeFilterParameter : public FilterParameter, public QQmlParserStatus { + Q_OBJECT + QML_NAMED_ELEMENT(FilterParameter) +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QML_ADDED_IN_VERSION(3, 0) +#endif + Q_INTERFACES(QQmlParserStatus) + // from base class + Q_PROPERTY(QString styleId READ styleId WRITE setStyleId) + Q_PROPERTY(QVariantList expression READ expression WRITE setExpression NOTIFY expressionUpdated) + // this type must not declare any additional properties +public: + explicit DeclarativeFilterParameter(QObject *parent = nullptr); + ~DeclarativeFilterParameter() override = default; + +private: + // QQmlParserStatus implementation + MLN_DECLARATIVE_PARSER(DeclarativeFilterParameter) +}; + +} // namespace QMapLibre diff --git a/test/qml/qt6/tst_style_parameters.qml b/test/qml/qt6/tst_style_parameters.qml index c197487..3f5acfd 100644 --- a/test/qml/qt6/tst_style_parameters.qml +++ b/test/qml/qt6/tst_style_parameters.qml @@ -58,6 +58,12 @@ Item { "raster-opacity": 0.9 } } + + FilterParameter { + id: filterParam + styleId: "countries-fill" + expression: ["==", "ADM0_A3", "NLD"] + } } } @@ -72,7 +78,18 @@ Item { compare(radarSourceParam.url, "https://maplibre.org/maplibre-gl-js/docs/assets/radar1.gif") } - function test_style_1_image_change() { + function test_style_1_filter_change() { + filterParam.expression = ["==", "ADM0_A3", "USA"] + compare(filterParam.expression, ["==", "ADM0_A3", "USA"]) + wait(500) + } + + function test_style_2_filter_remove() { + style.removeParameter(filterParam) + wait(500) + } + + function test_style_3_image_change() { radarSourceParam.url = "https://maplibre.org/maplibre-gl-js/docs/assets/radar2.gif" compare(radarSourceParam.url, "https://maplibre.org/maplibre-gl-js/docs/assets/radar2.gif") wait(250) @@ -97,7 +114,7 @@ Item { wait(250) } - function test_style_2_paint_change() { + function test_style_4_paint_change() { radarLayerParam.paint = {"raster-opacity": 0.8} wait(250) radarLayerParam.paint = {"raster-opacity": 0.6} @@ -110,7 +127,7 @@ Item { wait(500) } - function test_style_3_paint_set() { + function test_style_5_paint_set() { radarLayerParam.setPaintProperty("raster-opacity", 0.8) wait(250) radarLayerParam.setPaintProperty("raster-opacity", 0.6) @@ -123,13 +140,13 @@ Item { wait(500) } - function test_style_4_remove_image() { + function test_style_6_remove_image() { style.removeParameter(radarLayerParam) style.removeParameter(radarSourceParam) wait(500) } - function test_style_5_tiles() { + function test_style_7_tiles() { let url = "https://s2maps-tiles.eu/wms?service=wms&bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:900913&width=256&height=256&layers=s2cloudless-2021_3857" let sourceParam = Qt.createQmlObject(`