diff --git a/packages/qgis-js/src/QgisApiAdapter.ts b/packages/qgis-js/src/QgisApiAdapter.ts index 4dda873..7980b64 100644 --- a/packages/qgis-js/src/QgisApiAdapter.ts +++ b/packages/qgis-js/src/QgisApiAdapter.ts @@ -84,6 +84,15 @@ export class QgisApiAdapterImplementation implements QgisApiAdapter { } return result; } + + mapThemes(): readonly string[] { + const mapLayersRaw = this._api.mapThemes(); + const result = new Array(mapLayersRaw.size()); + for (let i = 0; i < mapLayersRaw.size(); i++) { + result[i] = mapLayersRaw.get(i); + } + return result; + } } export function getQgisApiProxy(api: InternalQgisApi): QgisApi { diff --git a/sites/dev/src/demo.css b/sites/dev/src/demo.css index 0ccdafa..b2cc161 100644 --- a/sites/dev/src/demo.css +++ b/sites/dev/src/demo.css @@ -58,19 +58,31 @@ a.source { right: 2em; } -#layers-control .layers { +#layers-control .layers, +.themes { width: 25em; padding: 1em 0.5em; border: 1px solid #ccc; + border-bottom: none; background-color: #ffffff; } -#layers-control .layers::before { +#layers-control .layers::before, +.themes::before { margin: 1em 0.5em; font-weight: bold; content: "Layers:"; } +#layers-control .themes::before { + content: "Map Theme:"; +} + +#layers-control .themes select { + float: right; + width: 18em; +} + #layers-control .layers :first-child { margin-top: 0.5em; } diff --git a/sites/dev/src/index.ts b/sites/dev/src/index.ts index bcfa528..7760341 100644 --- a/sites/dev/src/index.ts +++ b/sites/dev/src/index.ts @@ -114,6 +114,7 @@ async function initDemo() { if (timer) console.time("project"); api.loadProject(project); if (timer) console.timeEnd("project"); + // update all demos setTimeout(() => { updateCallbacks.forEach((update) => update()); diff --git a/sites/dev/src/layers.ts b/sites/dev/src/layers.ts index b9a50c8..d653d75 100644 --- a/sites/dev/src/layers.ts +++ b/sites/dev/src/layers.ts @@ -8,9 +8,9 @@ export function layersControl( const update = () => { target.innerHTML = ""; - const container = document.createElement("div"); - container.className = "layers"; - target.appendChild(container); + const layerContainer = document.createElement("div"); + layerContainer.className = "layers"; + target.appendChild(layerContainer); const layers = api.mapLayers(); for (const layer of layers) { @@ -26,6 +26,7 @@ export function layersControl( checkbox.addEventListener("change", () => { layer.visible = checkbox.checked; redraw(); + update(); }); node.appendChild(checkbox); @@ -49,7 +50,43 @@ export function layersControl( }); node.appendChild(slider); - container.appendChild(node); + layerContainer.appendChild(node); + } + + if (api.mapThemes().length > 0) { + const themeContainer = document.createElement("div"); + themeContainer.className = "themes"; + target.appendChild(themeContainer); + + const select = document.createElement("select"); + select.addEventListener("change", () => { + if (select.value) { + api.setMapTheme(select.value); + redraw(); + update(); + } + }); + themeContainer.appendChild(select); + + const currentTheme = api.getMapTheme(); + + const option = document.createElement("option"); + option.value = ""; + option.text = ""; + if (!currentTheme) { + option.selected = true; + } + select.appendChild(option); + + for (const theme of api.mapThemes()) { + const option = document.createElement("option"); + option.value = theme; + option.text = theme; + if (theme === currentTheme) { + option.selected = true; + } + select.appendChild(option); + } } }; diff --git a/src/api/QgisApi.cpp b/src/api/QgisApi.cpp index 8522763..ae0fed8 100644 --- a/src/api/QgisApi.cpp +++ b/src/api/QgisApi.cpp @@ -142,6 +142,40 @@ const std::vector QgisApi_mapLayers() { return result; } +const std::vector QgisApi_mapThemes() { + std::vector result = {}; + for (const QString &theme : QgsProject::instance()->mapThemeCollection()->mapThemes()) { + result.push_back(theme.toStdString()); + } + return result; +} + +const std::string QgisApi_getMapTheme() { + QgsLayerTree *layerTreeRoot = QgsProject::instance()->layerTreeRoot(); + QgsMapThemeCollection *collection = QgsProject::instance()->mapThemeCollection(); + QgsLayerTreeModel model(layerTreeRoot); + auto currentState = QgsMapThemeCollection::createThemeFromCurrentState(layerTreeRoot, &model); + for (const QString &theme : QgsProject::instance()->mapThemeCollection()->mapThemes()) { + if (currentState == QgsProject::instance()->mapThemeCollection()->mapThemeState(theme)) { + return theme.toStdString(); + } + } + return ""; +} + +const bool QgisApi_setMapTheme(std::string themeName) { + QString qThemeName = QString::fromStdString(themeName); + if (!QgsProject::instance()->mapThemeCollection()->hasMapTheme(qThemeName)) { + return false; + } else { + QgsLayerTree *layerTreeRoot = QgsProject::instance()->layerTreeRoot(); + QgsMapThemeCollection *collection = QgsProject::instance()->mapThemeCollection(); + QgsLayerTreeModel model(layerTreeRoot); + collection->applyTheme(qThemeName, layerTreeRoot, &model); + return true; + } +} + EMSCRIPTEN_BINDINGS(QgisApi) { emscripten::function("loadProject", &QgisApi_loadProject); emscripten::function("fullExtent", &QgisApi_fullExtent); @@ -151,4 +185,8 @@ EMSCRIPTEN_BINDINGS(QgisApi) { emscripten::function("transformRectangle", &QgisApi_transformRectangle); emscripten::function("mapLayers", &QgisApi_mapLayers, emscripten::allow_raw_pointers()); emscripten::register_vector("vector"); + emscripten::function("mapThemes", &QgisApi_mapThemes, emscripten::allow_raw_pointers()); + emscripten::function("getMapTheme", &QgisApi_getMapTheme); + emscripten::function("setMapTheme", &QgisApi_setMapTheme); + emscripten::register_vector("vector"); } diff --git a/src/api/QgisApi.ts b/src/api/QgisApi.ts index d4c765a..114b772 100644 --- a/src/api/QgisApi.ts +++ b/src/api/QgisApi.ts @@ -39,6 +39,21 @@ export interface CommonQgisApi extends QgisModelConstructors { inputSrid: string, outputSrid: string, ): Rectangle; + + /** + * Gets the current map theme of the current project. + * + * @returns The name of the current map theme. An empty string if no map theme is set. + */ + setMapTheme(mapTheme: string): boolean; + + /** + * Sets a map theme of the current project. + * + * @param + * @returns true if the map theme was loaded successfully, false otherwise. + */ + setMapTheme(mapTheme: string): boolean; } /** @@ -89,6 +104,13 @@ export interface QgisApiAdapter { * @returns The map layers of the loaded project. */ mapLayers(): readonly MapLayer[]; + + /** + * Returns the map themes of the loaded project. + * + * @returns The map themes of the loaded project. + */ + mapThemes(): readonly string[]; } /** @@ -120,4 +142,5 @@ export interface InternalQgisApi extends CommonQgisApi { callback: (tileData: ArrayBufferLike) => void, ): number; mapLayers(): any; + mapThemes(): any; }