mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-20 11:10:23 -06:00
373 lines
12 KiB
C++
373 lines
12 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2021 *
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
|
* software and associated documentation files (the "Software"), to deal in the Software *
|
|
* without restriction, including without limitation the rights to use, copy, modify, *
|
|
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
|
* permit persons to whom the Software is furnished to do so, subject to the following *
|
|
* conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in all copies *
|
|
* or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
|
****************************************************************************************/
|
|
|
|
#include <modules/imgui/include/guiglobebrowsingcomponent.h>
|
|
|
|
#include <modules/globebrowsing/globebrowsingmodule.h>
|
|
#include <modules/globebrowsing/src/renderableglobe.h>
|
|
#include <modules/imgui/include/imgui_include.h>
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/engine/moduleengine.h>
|
|
#include <openspace/interaction/navigationhandler.h>
|
|
#include <openspace/interaction/orbitalnavigator.h>
|
|
#include <openspace/rendering/renderable.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
#include <openspace/scene/scene.h>
|
|
#include <openspace/scripting/scriptengine.h>
|
|
#include <ghoul/fmt.h>
|
|
#include <ghoul/logging/logmanager.h>
|
|
#include <numeric>
|
|
|
|
namespace {
|
|
const ImVec2 WindowSize = ImVec2(350, 500);
|
|
} // namespace
|
|
|
|
namespace openspace::gui {
|
|
|
|
GuiGlobeBrowsingComponent::GuiGlobeBrowsingComponent()
|
|
: GuiPropertyComponent("GlobeBrowsing", "Globe Browsing")
|
|
{}
|
|
|
|
void GuiGlobeBrowsingComponent::render() {
|
|
GlobeBrowsingModule* module = global::moduleEngine->module<GlobeBrowsingModule>();
|
|
using UrlInfo = GlobeBrowsingModule::UrlInfo;
|
|
using Capabilities = GlobeBrowsingModule::Capabilities;
|
|
using Layer = GlobeBrowsingModule::Layer;
|
|
|
|
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
|
|
|
bool e = _isEnabled;
|
|
|
|
ImGui::SetNextWindowSize(WindowSize, ImGuiCond_FirstUseEver);
|
|
ImGui::SetNextWindowBgAlpha(0.5f);
|
|
ImGui::Begin("Globe Browsing", &e);
|
|
_isEnabled = e;
|
|
_isCollapsed = ImGui::IsWindowCollapsed();
|
|
defer { ImGui::End(); };
|
|
|
|
// Render the list of planets
|
|
std::vector<SceneGraphNode*> nodes =
|
|
global::renderEngine->scene()->allSceneGraphNodes();
|
|
|
|
nodes.erase(
|
|
std::remove_if(
|
|
nodes.begin(),
|
|
nodes.end(),
|
|
[](SceneGraphNode* n) {
|
|
using namespace globebrowsing;
|
|
const Renderable* r = n->renderable();
|
|
const RenderableGlobe* rg = dynamic_cast<const RenderableGlobe*>(r);
|
|
return rg == nullptr;
|
|
}
|
|
),
|
|
nodes.end()
|
|
);
|
|
std::sort(
|
|
nodes.begin(),
|
|
nodes.end(),
|
|
[module](SceneGraphNode* lhs, SceneGraphNode* rhs) {
|
|
const bool lhsHasUrl = module->hasUrlInfo(lhs->identifier());
|
|
const bool rhsHasUrl = module->hasUrlInfo(rhs->identifier());
|
|
|
|
if (lhsHasUrl && !rhsHasUrl) {
|
|
return true;
|
|
}
|
|
if (!lhsHasUrl && rhsHasUrl) {
|
|
return false;
|
|
}
|
|
|
|
return lhs->guiName() < rhs->guiName();
|
|
}
|
|
);
|
|
|
|
|
|
auto firstWithoutUrl = std::find_if(
|
|
nodes.begin(),
|
|
nodes.end(),
|
|
[module](SceneGraphNode* n) {
|
|
return !module->hasUrlInfo(n->identifier());
|
|
}
|
|
);
|
|
nodes.insert(firstWithoutUrl, nullptr);
|
|
|
|
std::string nodeNames;
|
|
for (SceneGraphNode* n : nodes) {
|
|
// Add separator between nodes with URL and nodes without
|
|
if (n) {
|
|
nodeNames += n->identifier() + '\0';
|
|
}
|
|
else {
|
|
nodeNames += std::string("===== =====") + '\0';
|
|
}
|
|
}
|
|
|
|
int iNode = -1;
|
|
if (_currentNode.empty()) {
|
|
// We haven't selected a node yet, so first instinct is to use the current focus
|
|
// node
|
|
|
|
// Check if the focus node is a RenderableGlobe
|
|
const SceneGraphNode* const focus =
|
|
global::navigationHandler->orbitalNavigator().anchorNode();
|
|
|
|
const auto it = std::find(nodes.cbegin(), nodes.cend(), focus);
|
|
if (it != nodes.end()) {
|
|
_currentNode = focus->identifier();
|
|
iNode = static_cast<int>(std::distance(nodes.cbegin(), it));
|
|
}
|
|
}
|
|
else {
|
|
const auto it = std::find_if(
|
|
nodes.cbegin(),
|
|
nodes.cend(),
|
|
[this](SceneGraphNode* lhs) {
|
|
return lhs && (lhs->identifier() == _currentNode);
|
|
}
|
|
);
|
|
iNode = static_cast<int>(std::distance(nodes.cbegin(), it));
|
|
}
|
|
|
|
bool isNodeChanged = ImGui::Combo("Globe", &iNode, nodeNames.c_str());
|
|
|
|
ImGui::SameLine();
|
|
bool selectFocusNode = ImGui::Button("From Focus");
|
|
if (selectFocusNode) {
|
|
const SceneGraphNode* const focus =
|
|
global::navigationHandler->orbitalNavigator().anchorNode();
|
|
|
|
const auto it = std::find(nodes.cbegin(), nodes.cend(), focus);
|
|
if (it != nodes.end()) {
|
|
_currentNode = focus->identifier();
|
|
iNode = static_cast<int>(std::distance(nodes.cbegin(), it));
|
|
isNodeChanged = true;
|
|
}
|
|
}
|
|
|
|
if (iNode == -1) {
|
|
// This should only occur if the Focusnode is not a RenderableGlobe
|
|
// or if there are no nodes
|
|
return;
|
|
}
|
|
|
|
if (!nodes[iNode]) {
|
|
// The user selected the separator
|
|
return;
|
|
}
|
|
|
|
_currentNode = nodes[iNode]->identifier();
|
|
|
|
if (isNodeChanged) {
|
|
_currentServer = "";
|
|
}
|
|
|
|
ImGui::Separator();
|
|
|
|
// Render the list of servers for the planet
|
|
std::vector<UrlInfo> urlInfo = module->urlInfo(_currentNode);
|
|
|
|
std::string serverList = std::accumulate(
|
|
urlInfo.cbegin(),
|
|
urlInfo.cend(),
|
|
std::string(),
|
|
[](const std::string& lhs, const UrlInfo& i) {
|
|
return lhs + i.name + ": (" + i.url + ")" + '\0';
|
|
}
|
|
);
|
|
|
|
int iServer = -1;
|
|
if (_currentServer.empty()) {
|
|
// We haven't selected a server yet, so first instinct is to just use the first
|
|
if (!urlInfo.empty()) {
|
|
_currentServer = urlInfo[0].name;
|
|
iServer = 0;
|
|
}
|
|
}
|
|
else {
|
|
const auto it = std::find_if(
|
|
urlInfo.cbegin(),
|
|
urlInfo.cend(),
|
|
[this](const UrlInfo& i) {
|
|
return i.name == _currentServer;
|
|
}
|
|
);
|
|
if (it != urlInfo.end()) {
|
|
iServer = static_cast<int>(std::distance(urlInfo.cbegin(), it));
|
|
}
|
|
}
|
|
|
|
ImGui::Combo("Server", &iServer, serverList.c_str());
|
|
|
|
ImGui::SameLine(0.f, 60.f);
|
|
|
|
if (ImGui::Button("Add Server")) {
|
|
ImGui::OpenPopup("globebrowsing_add_server");
|
|
}
|
|
|
|
if (ImGui::BeginPopup("globebrowsing_add_server")) {
|
|
constexpr const int InputBufferSize = 512;
|
|
static char NameInputBuffer[InputBufferSize];
|
|
ImGui::InputText("Server Name", NameInputBuffer, InputBufferSize);
|
|
|
|
static char UrlInputBuffer[InputBufferSize];
|
|
ImGui::InputText("Server URL", UrlInputBuffer, InputBufferSize);
|
|
|
|
const bool addServer = ImGui::Button("Add Server");
|
|
if (addServer && (!_currentNode.empty())) {
|
|
module->loadWMSCapabilities(
|
|
std::string(NameInputBuffer),
|
|
_currentNode,
|
|
std::string(UrlInputBuffer)
|
|
);
|
|
std::memset(NameInputBuffer, 0, InputBufferSize * sizeof(char));
|
|
std::memset(UrlInputBuffer, 0, InputBufferSize * sizeof(char));
|
|
|
|
urlInfo = module->urlInfo(_currentNode);
|
|
_currentServer = urlInfo.back().name;
|
|
--iServer;
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::EndPopup();
|
|
}
|
|
ImGui::SameLine(0.f, 20.f);
|
|
|
|
const bool deleteServer = ImGui::Button("Delete Server");
|
|
if (deleteServer) {
|
|
module->removeWMSServer(_currentServer);
|
|
_currentServer = "";
|
|
iServer = -1;
|
|
|
|
}
|
|
|
|
if (iServer < 0 || urlInfo.empty()) {
|
|
// There are no server so we have to bail
|
|
return;
|
|
}
|
|
_currentServer = urlInfo[iServer].name;
|
|
|
|
ImGui::Separator();
|
|
|
|
Capabilities cap = module->capabilities(_currentServer);
|
|
|
|
if (cap.empty()) {
|
|
LWARNINGC("GlobeBrowsing", fmt::format("Unknown server: '{}'", _currentServer));
|
|
}
|
|
|
|
ImGui::Columns(6, nullptr, false);
|
|
|
|
const float width = ImGui::GetWindowWidth();
|
|
constexpr const float ButtonWidth = 60.f;
|
|
ImGui::SetColumnOffset(5, width - 1.5f * ButtonWidth);
|
|
ImGui::SetColumnOffset(4, width - 2.5f * ButtonWidth);
|
|
ImGui::SetColumnOffset(3, width - 3.5f * ButtonWidth);
|
|
ImGui::SetColumnOffset(2, width - 4.5f * ButtonWidth);
|
|
ImGui::SetColumnOffset(1, width - 5.5f * ButtonWidth);
|
|
ImGui::SetColumnOffset(0, 0);
|
|
|
|
ImGui::Text("%s", "Layer name");
|
|
ImGui::NextColumn();
|
|
ImGui::Text("%s", "Add as ...");
|
|
ImGui::NextColumn();
|
|
ImGui::NextColumn();
|
|
ImGui::NextColumn();
|
|
ImGui::NextColumn();
|
|
ImGui::NextColumn();
|
|
ImGui::Separator();
|
|
|
|
for (const Layer& l : cap) {
|
|
if (l.name.empty() || l.url.empty()) {
|
|
continue;
|
|
}
|
|
|
|
ImGui::PushID(l.url.c_str());
|
|
|
|
ImGui::Text("%s", l.name.c_str());
|
|
ImGui::NextColumn();
|
|
|
|
const bool addColor = ImGui::Button("Color", { ButtonWidth, 25.f });
|
|
ImGui::NextColumn();
|
|
|
|
const bool addNight = ImGui::Button("Night", { ButtonWidth, 25.f });
|
|
ImGui::NextColumn();
|
|
|
|
const bool addOverlay = ImGui::Button("Overlay", { ButtonWidth, 25.f });
|
|
ImGui::NextColumn();
|
|
|
|
const bool addHeight = ImGui::Button("Height", { ButtonWidth, 25.f });
|
|
ImGui::NextColumn();
|
|
|
|
const bool addWaterMask = ImGui::Button("Water", { ButtonWidth, 25.f });
|
|
ImGui::NextColumn();
|
|
|
|
auto addFunc = [n = _currentNode, &l](const std::string& type) {
|
|
std::string layerName = l.name;
|
|
std::replace(layerName.begin(), layerName.end(), '.', '-');
|
|
layerName.erase(
|
|
std::remove(layerName.begin(), layerName.end(), ' '),
|
|
layerName.end()
|
|
);
|
|
global::scriptEngine->queueScript(
|
|
fmt::format(
|
|
"openspace.globebrowsing.addLayer(\
|
|
'{}', \
|
|
'{}', \
|
|
{{ \
|
|
Identifier = '{}',\
|
|
Name = '{}',\
|
|
FilePath = '{}',\
|
|
Enabled = true\
|
|
}}\
|
|
);",
|
|
n,
|
|
type,
|
|
layerName,
|
|
l.name,
|
|
l.url
|
|
),
|
|
scripting::ScriptEngine::RemoteScripting::Yes
|
|
);
|
|
};
|
|
|
|
if (addColor) {
|
|
addFunc("ColorLayers");
|
|
}
|
|
if (addNight) {
|
|
addFunc("NightLayers");
|
|
}
|
|
if (addOverlay) {
|
|
addFunc("Overlays");
|
|
}
|
|
if (addHeight) {
|
|
addFunc("HeightLayers");
|
|
}
|
|
if (addWaterMask) {
|
|
addFunc("WaterMasks");
|
|
}
|
|
|
|
ImGui::PopID();
|
|
}
|
|
ImGui::Columns(1);
|
|
}
|
|
|
|
} // namespace openspace::gui
|