From bf794142639290f46063f25447f3ca51c4209888 Mon Sep 17 00:00:00 2001 From: Micah Date: Wed, 14 Oct 2020 16:31:21 -0400 Subject: [PATCH 01/29] adding color range as runtime property for billboards --- data/assets/scene/digitaluniverse/sdss.asset | 2 +- .../rendering/renderablebillboardscloud.cpp | 17 +++++++++++++++++ .../rendering/renderablebillboardscloud.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/data/assets/scene/digitaluniverse/sdss.asset b/data/assets/scene/digitaluniverse/sdss.asset index aea7142560..765290c676 100644 --- a/data/assets/scene/digitaluniverse/sdss.asset +++ b/data/assets/scene/digitaluniverse/sdss.asset @@ -27,7 +27,7 @@ local object = { File = speck .. "/SDSSgals.speck", ColorMap = speck .. "/SDSSgals.cmap", ColorOption = { "redshift", "proximity" }, - ColorRange = { { 0.0, 0.075 }, { 1.0, 50.0 } }, + ColorRange = { { 0.001, 2.0 }, { 1.0, 50.0 } }, Texture = textures .. "/point3A.png", Unit = "Mpc", -- Fade in value in the same unit as "Unit" diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index 54a9dc6649..84ca5205e4 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -186,6 +186,12 @@ namespace { "astronomical objects." }; + constexpr openspace::properties::Property::PropertyInfo OptionColorRangeInfo = { + "OptionColorRange", + "Option Color Range", + "This value changes the range of values to be mapped with the current color map." + }; + constexpr openspace::properties::Property::PropertyInfo SizeOptionInfo = { "SizeOption", "Size Option Variable", @@ -435,6 +441,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di , _drawLabels(DrawLabelInfo, false) , _pixelSizeControl(PixelSizeControlInfo, false) , _colorOption(ColorOptionInfo, properties::OptionProperty::DisplayType::Dropdown) + , _optionColorRangeData(OptionColorRangeInfo, glm::vec2(0.f)) + , _datavarSizeOption( SizeOptionInfo, properties::OptionProperty::DisplayType::Dropdown @@ -548,6 +556,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di } _colorOption.onChange([&]() { _dataIsDirty = true; + const glm::vec2 colorRange = _colorRangeData[_colorOption.value()]; + _optionColorRangeData = colorRange; _colorOptionString = _optionConversionMap[_colorOption.value()]; }); addProperty(_colorOption); @@ -561,7 +571,14 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di rangeDataDict.value(std::to_string(i + 1)) ); } + _optionColorRangeData = _colorRangeData[_colorRangeData.size() - 1]; } + _optionColorRangeData.onChange([&]() { + const glm::vec2 colorRange = _optionColorRangeData; + _colorRangeData[_colorOption.value()] = colorRange; + _dataIsDirty = true; + }); + addProperty(_optionColorRangeData); if (dictionary.hasKey(ExactColorMapInfo.identifier)) { _isColorMapExact = dictionary.value(ExactColorMapInfo.identifier); diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.h b/modules/digitaluniverse/rendering/renderablebillboardscloud.h index 1c95698927..4747258811 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.h +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.h @@ -123,6 +123,7 @@ private: properties::BoolProperty _drawLabels; properties::BoolProperty _pixelSizeControl; properties::OptionProperty _colorOption; + properties::Vec2Property _optionColorRangeData; properties::OptionProperty _datavarSizeOption; properties::Vec2Property _fadeInDistance; properties::BoolProperty _disableFadeInDistance; From cde1fa8b5debf44b9e6f0200b38ae64d7ec0059f Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Thu, 15 Oct 2020 16:50:27 -0400 Subject: [PATCH 02/29] Temporally fixed attribute location error for NightLayers layer. --- modules/globebrowsing/src/renderableglobe.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 697c32f96e..18299b199f 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -1050,6 +1050,10 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, if (_globalRenderer.updatedSinceLastCall) { const std::array& layerGroups = _layerManager.layerGroups(); + + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); + _globalRenderer.program->setIgnoreAttributeLocationError(IgnoreError::Yes); for (size_t i = 0; i < layerGroups.size(); ++i) { const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; _globalRenderer.gpuLayerGroups[i].bind( @@ -1059,6 +1063,8 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, static_cast(i) ); } + _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::No); + _globalRenderer.program->setIgnoreAttributeLocationError(IgnoreError::No); const float dsf = static_cast( _generalProperties.currentLodScaleFactor * _ellipsoid.minimumRadius() @@ -1074,6 +1080,8 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, if (_localRenderer.updatedSinceLastCall) { const std::array& layerGroups = _layerManager.layerGroups(); + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); for (size_t i = 0; i < layerGroups.size(); ++i) { const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; _localRenderer.gpuLayerGroups[i].bind( @@ -1083,6 +1091,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, static_cast(i) ); } + _localRenderer.program->setIgnoreUniformLocationError(IgnoreError::No); const float dsf = static_cast( _generalProperties.currentLodScaleFactor * _ellipsoid.minimumRadius() From 522072c57f3be49401e4a8a72b171f50a05f2bbc Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Thu, 15 Oct 2020 16:53:45 -0400 Subject: [PATCH 03/29] Removed unused ignore. --- modules/globebrowsing/src/renderableglobe.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 18299b199f..3a8b9ed982 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -1053,7 +1053,6 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); - _globalRenderer.program->setIgnoreAttributeLocationError(IgnoreError::Yes); for (size_t i = 0; i < layerGroups.size(); ++i) { const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; _globalRenderer.gpuLayerGroups[i].bind( @@ -1064,8 +1063,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, ); } _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::No); - _globalRenderer.program->setIgnoreAttributeLocationError(IgnoreError::No); - + const float dsf = static_cast( _generalProperties.currentLodScaleFactor * _ellipsoid.minimumRadius() ); From bef3e0d66161b64a927670651ae06221b5829346 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 15 Oct 2020 09:48:40 +0200 Subject: [PATCH 04/29] Test every planet for insufficient data, not just the first one --- modules/exoplanets/exoplanetshelper.cpp | 11 +++++++++++ modules/exoplanets/exoplanetshelper.h | 3 +++ modules/exoplanets/exoplanetsmodule_lua.inl | 18 ++++++++---------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp index 05b8105e17..1db7a0f564 100644 --- a/modules/exoplanets/exoplanetshelper.cpp +++ b/modules/exoplanets/exoplanetshelper.cpp @@ -81,6 +81,17 @@ std::string_view csvStarName(std::string_view name) { return name; } +bool hasSufficientData(const Exoplanet& p) { + bool invalidPos = std::isnan(p.positionX) + || std::isnan(p.positionY) + || std::isnan(p.positionZ); + + bool hasSemiMajorAxis = !std::isnan(p.a); + bool hasOrbitalPeriod = !std::isnan(p.per); + + return !invalidPos && hasSemiMajorAxis && hasOrbitalPeriod; +} + std::string starColor(float bv) { std::ifstream colorMap(absPath(BvColormapPath), std::ios::in); diff --git a/modules/exoplanets/exoplanetshelper.h b/modules/exoplanets/exoplanetshelper.h index 81bd3221c7..a8637d6cfe 100644 --- a/modules/exoplanets/exoplanetshelper.h +++ b/modules/exoplanets/exoplanetshelper.h @@ -72,6 +72,9 @@ std::string_view speckStarName(std::string_view name); // Convert speck-file specific names to the corresponding name in the csv data file std::string_view csvStarName(std::string_view name); +// Check if the exoplanet p has sufficient data for visualization +bool hasSufficientData(const Exoplanet& p); + // Compute star color in RGB from b-v color index std::string starColor(float bv); diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index a44ef59f87..f2307fa03c 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -121,6 +121,14 @@ void createExoplanetSystem(std::string_view starName) { planetNames.push_back(name); planetSystem.push_back(p); found = true; + + if (!hasSufficientData(p)) { + LERROR(fmt::format( + "Insufficient data available for visualizion of exoplanet system: '{}'", + starName + )); + return; + } } } @@ -132,16 +140,6 @@ void createExoplanetSystem(std::string_view starName) { return; } - bool notEnoughData = std::isnan(p.positionX) || std::isnan(p.a) || std::isnan(p.per); - - if (notEnoughData) { - LERROR(fmt::format( - "Insufficient data available for representing the exoplanet system: '{}'", - starName - )); - return; - } - const glm::dvec3 starPosition = glm::dvec3( p.positionX * distanceconstants::Parsec, p.positionY * distanceconstants::Parsec, From 6b25489819defba8af3e78074756e428cdabf0b8 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 15 Oct 2020 15:37:47 +0200 Subject: [PATCH 05/29] Compute valid angles for KeplerTranslation --- modules/exoplanets/exoplanetsmodule_lua.inl | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index f2307fa03c..fec7f88706 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -259,15 +259,18 @@ void createExoplanetSystem(std::string_view starName) { if (std::isnan(planet.ecc)) { planet.ecc = 0.f; } - if (std::isnan(planet.i)) { - planet.i = 90.f; - } - if (std::isnan(planet.bigOmega)) { - planet.bigOmega = 180.f; - } - if (std::isnan(planet.omega)) { - planet.omega = 90.f; - } + + // KeplerTranslation requires angles in range [0, 360] + auto validAngle = [](float angle, float defaultValue) { + if (std::isnan(angle)) { return defaultValue; } + if (angle < 0.f) { return angle + 360.f; } + if (angle > 360.f) { return angle - 360.f; } + }; + + planet.i = validAngle(planet.i, 90.f); + planet.bigOmega = validAngle(planet.bigOmega, 180.f); + planet.omega = validAngle(planet.omega, 90.f); + Time epoch; std::string sEpoch; if (!std::isnan(planet.tt)) { From 11425dfdb7a8bfcfb9de1b9af6b4670524ce217b Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 15 Oct 2020 16:03:38 +0200 Subject: [PATCH 06/29] Replace unused system rotation computation with the one that is actually used --- modules/exoplanets/exoplanetshelper.cpp | 66 ++++++++++----------- modules/exoplanets/exoplanetshelper.h | 2 +- modules/exoplanets/exoplanetsmodule_lua.inl | 36 +---------- 3 files changed, 34 insertions(+), 70 deletions(-) diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp index 1db7a0f564..99af61238f 100644 --- a/modules/exoplanets/exoplanetshelper.cpp +++ b/modules/exoplanets/exoplanetshelper.cpp @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -137,44 +138,41 @@ glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom, float omega) { return orbitPlaneRotation; } -// Rotate the original coordinate system (where x is pointing to First Point of Aries) -// so that x is pointing from star to the sun. -// Modified from "http://www.opengl-tutorial.org/intermediate-tutorials/ -// tutorial-17-quaternions/ #how-do-i-find-the-rotation-between-2-vectors" -glm::dmat3 exoplanetSystemRotation(glm::dvec3 start, glm::dvec3 end) { - glm::quat rotationQuat; - glm::dvec3 rotationAxis; - const float cosTheta = static_cast(glm::dot(start, end)); - constexpr float Epsilon = 1E-3f; +glm::dmat3 computeSystemRotation(glm::dvec3 starPosition) { + const glm::dvec3 sunPosition = glm::dvec3(0.0, 0.0, 0.0); + const glm::dvec3 starToSunVec = glm::normalize(sunPosition - starPosition); + const glm::dvec3 galacticNorth = glm::dvec3(0.0, 0.0, 1.0); - if (cosTheta < -1.f + Epsilon) { - // special case when vectors in opposite directions: - // there is no "ideal" rotation axis - // So guess one; any will do as long as it's perpendicular to start vector - rotationAxis = glm::cross(glm::dvec3(0.0, 0.0, 1.0), start); - if (glm::length2(rotationAxis) < 0.01f) { - // bad luck, they were parallel, try again! - rotationAxis = glm::cross(glm::dvec3(1.0, 0.0, 0.0), start); - } + const glm::dmat3 galacticToCelestialMatrix = + SpiceManager::ref().positionTransformMatrix("GALACTIC", "J2000", 0.0); - rotationAxis = glm::normalize(rotationAxis); - rotationQuat = glm::quat(glm::radians(180.f), rotationAxis); - return glm::dmat3(glm::toMat4(rotationQuat)); - } - - rotationAxis = glm::cross(start, end); - - const float s = sqrt((1.f + cosTheta) * 2.f); - const float invs = 1.f / s; - - rotationQuat = glm::quat( - s * 0.5f, - static_cast(rotationAxis.x * invs), - static_cast(rotationAxis.y * invs), - static_cast(rotationAxis.z * invs) + const glm::dvec3 celestialNorth = glm::normalize( + galacticToCelestialMatrix * galacticNorth ); - return glm::dmat3(glm::toMat4(rotationQuat)); + // Earth's north vector projected onto the skyplane, the plane perpendicular to the + // viewing vector (starToSunVec) + const float celestialAngle = static_cast(glm::dot( + celestialNorth, + starToSunVec + )); + glm::dvec3 northProjected = glm::normalize( + celestialNorth - (celestialAngle / glm::length(starToSunVec)) * starToSunVec + ); + + const glm::dvec3 beta = glm::normalize(glm::cross(starToSunVec, northProjected)); + + return glm::dmat3( + northProjected.x, + northProjected.y, + northProjected.z, + beta.x, + beta.y, + beta.z, + starToSunVec.x, + starToSunVec.y, + starToSunVec.z + ); } std::string createIdentifier(std::string name) { diff --git a/modules/exoplanets/exoplanetshelper.h b/modules/exoplanets/exoplanetshelper.h index a8637d6cfe..e5a0fcc729 100644 --- a/modules/exoplanets/exoplanetshelper.h +++ b/modules/exoplanets/exoplanetshelper.h @@ -82,7 +82,7 @@ glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom, float omega); // Rotate the original coordinate system (where x is pointing to First Point of Aries) // so that x is pointing from star to the sun. -glm::dmat3 exoplanetSystemRotation(glm::dvec3 start, glm::dvec3 end); +glm::dmat3 computeSystemRotation(glm::dvec3 starPosition); // Create an identifier without whitespaces std::string createIdentifier(std::string name); diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index fec7f88706..79884f0b5a 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -146,40 +145,7 @@ void createExoplanetSystem(std::string_view starName) { p.positionZ * distanceconstants::Parsec ); - const glm::dvec3 sunPosition = glm::dvec3(0.0, 0.0, 0.0); - const glm::dvec3 starToSunVec = glm::normalize(sunPosition - starPosition); - const glm::dvec3 galacticNorth = glm::dvec3(0.0, 0.0, 1.0); - - const glm::dmat3 galaxticToCelestialMatrix = - SpiceManager::ref().positionTransformMatrix("GALACTIC", "J2000", 0.0); - - const glm::dvec3 celestialNorth = glm::normalize( - galaxticToCelestialMatrix * galacticNorth - ); - - // Earth's north vector projected onto the skyplane, the plane perpendicular to the - // viewing vector (starToSunVec) - const float celestialAngle = static_cast(glm::dot( - celestialNorth, - starToSunVec - )); - glm::dvec3 northProjected = glm::normalize( - celestialNorth - (celestialAngle / glm::length(starToSunVec)) * starToSunVec - ); - - const glm::dvec3 beta = glm::normalize(glm::cross(starToSunVec, northProjected)); - - const glm::dmat3 exoplanetSystemRotation = glm::dmat3( - northProjected.x, - northProjected.y, - northProjected.z, - beta.x, - beta.y, - beta.z, - starToSunVec.x, - starToSunVec.y, - starToSunVec.z - ); + const glm::dmat3 exoplanetSystemRotation = computeSystemRotation(starPosition); // Star renderable globe, if we have a radius and bv color index std::string starGlobeRenderableString; From 98ef020c4afb74a8dd1265d28072a85ae7f73575 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 15 Oct 2020 16:20:37 +0200 Subject: [PATCH 07/29] Clean up some headers --- modules/exoplanets/exoplanetsmodule_lua.inl | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index 79884f0b5a..273b2e6448 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -36,13 +35,7 @@ #include #include #include -#include -#include -#include -#include -#include #include -#include #include namespace { From f4628cd296b087f58577c7c5a4f7ff1adbd1a3ab Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 16 Oct 2020 09:34:55 +0200 Subject: [PATCH 08/29] Don't list systems where there is not enough data --- modules/exoplanets/exoplanetsmodule_lua.inl | 47 +++++++++++++-------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index 273b2e6448..1686822238 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -432,10 +432,22 @@ int removeExoplanetSystem(lua_State* L) { return 0; } -std::vector readHostStarNames(std::ifstream& lookupTableFile) { +std::vector hostStarsWithSufficientData() { std::vector names; std::string line; + std::ifstream lookupTableFile(absPath(LookUpTablePath)); + if (!lookupTableFile.good()) { + LERROR(fmt::format("Failed to open lookup table file '{}'", LookUpTablePath)); + return {}; + } + + std::ifstream data(absPath(ExoplanetsDataPath), std::ios::in | std::ios::binary); + if (!data.good()) { + LERROR(fmt::format("Failed to open data file '{}'", ExoplanetsDataPath)); + return {}; + } + // Read number of lines int nExoplanets = 0; while (getline(lookupTableFile, line)) { @@ -445,13 +457,26 @@ std::vector readHostStarNames(std::ifstream& lookupTableFile) { lookupTableFile.seekg(0); names.reserve(nExoplanets); + Exoplanet p; while (getline(lookupTableFile, line)) { std::stringstream ss(line); std::string name; getline(ss, name, ','); // Remove the last two characters, that specify the planet name = name.substr(0, name.size() - 2); - names.push_back(name); + + // Don't want to list systems where there is not enough data to visualize. + // So, test if there is before adding the name to the list. + std::string location_s; + getline(ss, location_s); + long location = std::stol(location_s.c_str()); + + data.seekg(location); + data.read(reinterpret_cast(&p), sizeof(Exoplanet)); + + if (hasSufficientData(p)) { + names.push_back(name); + } } // For easier read, sort by names and remove duplicates @@ -464,14 +489,7 @@ std::vector readHostStarNames(std::ifstream& lookupTableFile) { int getListOfExoplanets(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfExoplanets"); - std::ifstream file(absPath(LookUpTablePath)); - if (!file.good()) { - return ghoul::lua::luaError( - L, fmt::format("Failed to open file '{}'", LookUpTablePath - )); - } - - std::vector names = readHostStarNames(file); + std::vector names = hostStarsWithSufficientData(); lua_newtable(L); int number = 1; @@ -487,14 +505,7 @@ int getListOfExoplanets(lua_State* L) { int listAvailableExoplanetSystems(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::listAvailableExoplanetSystems"); - std::ifstream file(absPath(LookUpTablePath)); - if (!file.good()) { - return ghoul::lua::luaError( - L, fmt::format("Failed to open file '{}'", LookUpTablePath - )); - } - - std::vector names = readHostStarNames(file); + std::vector names = hostStarsWithSufficientData(); std::string output; for (auto it = names.begin(); it != names.end(); ++it) { From 2699eb1d7190d32c2e7cf6c307830531cb6fea89 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 16 Oct 2020 13:29:39 +0200 Subject: [PATCH 09/29] Avoid problems with apostrophes in star names --- modules/exoplanets/exoplanetshelper.cpp | 8 ++++++++ modules/exoplanets/exoplanetshelper.h | 2 ++ modules/exoplanets/exoplanetsmodule_lua.inl | 9 +++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp index 99af61238f..ed624d67de 100644 --- a/modules/exoplanets/exoplanetshelper.cpp +++ b/modules/exoplanets/exoplanetshelper.cpp @@ -177,7 +177,15 @@ glm::dmat3 computeSystemRotation(glm::dvec3 starPosition) { std::string createIdentifier(std::string name) { std::replace(name.begin(), name.end(), ' ', '_'); + sanitizeNameString(name); return name; } +void sanitizeNameString(std::string& s) { + // We want to avoid quotes and apostrophes in names, since they cause problems + // when a string is translated to a script call + s.erase(remove(s.begin(), s.end(), '\"'), s.end()); + s.erase(remove(s.begin(), s.end(), '\''), s.end()); +} + } // namespace openspace::exoplanets diff --git a/modules/exoplanets/exoplanetshelper.h b/modules/exoplanets/exoplanetshelper.h index e5a0fcc729..29e6b5a7ac 100644 --- a/modules/exoplanets/exoplanetshelper.h +++ b/modules/exoplanets/exoplanetshelper.h @@ -87,6 +87,8 @@ glm::dmat3 computeSystemRotation(glm::dvec3 starPosition); // Create an identifier without whitespaces std::string createIdentifier(std::string name); +void sanitizeNameString(std::string& s); + } // namespace openspace::exoplanets #endif // __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSMODULE___H__ diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index 1686822238..5d69860264 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -59,7 +59,11 @@ void createExoplanetSystem(std::string_view starName) { const std::string starNameSpeck = std::string(speckStarName(starName)); const std::string starIdentifier = createIdentifier(starNameSpeck); - const std::string guiPath = ExoplanetsGuiPath + starNameSpeck; + + std::string sanitizedStarName = starNameSpeck; + sanitizeNameString(sanitizedStarName); + + const std::string guiPath = ExoplanetsGuiPath + sanitizedStarName; SceneGraphNode* existingStarNode = sceneGraphNode(starIdentifier); if (existingStarNode) { @@ -110,6 +114,7 @@ void createExoplanetSystem(std::string_view starName) { data.seekg(location); data.read(reinterpret_cast(&p), sizeof(Exoplanet)); + sanitizeNameString(name); planetNames.push_back(name); planetSystem.push_back(p); found = true; @@ -200,7 +205,7 @@ void createExoplanetSystem(std::string_view starName) { "}," "Tag = {'exoplanet_system'}," "GUI = {" - "Name = '" + starNameSpeck + " (Star)'," + "Name = '" + sanitizedStarName + " (Star)'," "Path = '" + guiPath + "'" "}" "}"; From 68eb52c74036a7e127358ceacaa45a7127a126b3 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 16 Oct 2020 14:35:38 +0200 Subject: [PATCH 10/29] Make removeSceneGraphNode only remove one SGN Regex match version for removing several nodes at once is kept as its own function. Also, remove potentional fmt format exceptions when trying to remove parent node. --- src/scene/scene.cpp | 8 ++++++ src/scene/scene_lua.inl | 56 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index aa2e434579..9acf5a9015 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -675,6 +675,14 @@ scripting::LuaLibrary Scene::luaLibrary() { "string", "Removes the SceneGraphNode identified by name" }, + { + "removeSceneGraphNodesFromRegex", + &luascriptfunctions::removeSceneGraphNodesFromRegex, + {}, + "string", + "Removes all SceneGraphNodes with identifiers matching the input regular " + "expression" + }, { "hasSceneGraphNode", &luascriptfunctions::hasSceneGraphNode, diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index 67ed7b2991..5bf13fb19b 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -531,6 +531,54 @@ int removeSceneGraphNode(lua_State* L) { std::string name = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); + SceneGraphNode* foundNode = sceneGraphNode(name); + if (!foundNode) { + LERRORC( + "removeSceneGraphNode", + fmt::format("Did not find a match for identifier: {} ", name) + ); + return 0; + } + + SceneGraphNode* parent = foundNode->parent(); + if (!parent) { + LERRORC( + "removeSceneGraphNode", + fmt::format("Cannot remove root node") + ); + return 0; + } + + // Remove the node and all its children + std::function removeNode = + [&removeNode](SceneGraphNode* localNode) { + std::vector children = localNode->children(); + + ghoul::mm_unique_ptr n = localNode->parent()->detachChild( + *localNode + ); + ghoul_assert(n.get() == localNode, "Wrong node returned from detaching"); + + for (SceneGraphNode* c : children) { + removeNode(c); + } + + localNode->deinitializeGL(); + localNode->deinitialize(); + n = nullptr; + }; + + removeNode(foundNode); + + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + return 0; +} + +int removeSceneGraphNodesFromRegex(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeSceneGraphNodesFromRegex"); + + std::string name = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); + const std::vector& nodes = global::renderEngine.scene()->allSceneGraphNodes(); @@ -553,8 +601,8 @@ int removeSceneGraphNode(lua_State* L) { SceneGraphNode* parent = node->parent(); if (!parent) { LERRORC( - "removeSceneGraphNode", - fmt::format("{}: Cannot remove root node") + "removeSceneGraphNodesFromRegex", + fmt::format("Cannot remove root node") ); } else { @@ -565,8 +613,8 @@ int removeSceneGraphNode(lua_State* L) { if (!foundMatch) { LERRORC( - "removeSceneGraphNode", - "Did not find a match for identifier: " + name + "removeSceneGraphNodesFromRegex", + fmt::format("Did not find a match for identifier: {}", name) ); return 0; } From 823bd872c27c873fe09ee6da45ac4f29b13a8c6a Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Fri, 16 Oct 2020 09:28:28 -0400 Subject: [PATCH 11/29] Update Ghoul. --- ext/ghoul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ghoul b/ext/ghoul index 8f7d89335b..0648ae153a 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 8f7d89335b70b0ac2007d4dd12bafa640903a8fd +Subproject commit 0648ae153af4f8975e17c9a93db9f9bb75b4dcfa From 4b86f1e232f97652d50bb4ca6ced1fab26703901 Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Fri, 16 Oct 2020 10:06:58 -0400 Subject: [PATCH 12/29] Removed the extra pop from GL group stack. --- src/rendering/framebufferrenderer.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index bb8cf2e839..256b44b214 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -1208,10 +1208,6 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac TracyGpuZone("Raycaster Tasks") GLDebugGroup group("Raycaster Tasks"); performRaycasterTasks(tasks.raycasterTasks); - - if (HasGLDebugInfo) { - glPopDebugGroup(); - } } if (!tasks.deferredcasterTasks.empty()) { From e0b9951e7092f6b26cd293cd05f141ebce3be207 Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Fri, 16 Oct 2020 10:27:36 -0400 Subject: [PATCH 13/29] OpenGL state is back to a stable state. --- src/rendering/framebufferrenderer.cpp | 169 +++++++++++++------------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 256b44b214..93d54d6f43 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -171,111 +171,35 @@ void FramebufferRenderer::initialize() { // GBuffers glGenTextures(1, &_gBuffers.colorTexture); - if (HasGLDebugInfo) { - glObjectLabel(GL_TEXTURE, _gBuffers.colorTexture, -1, "G-Buffer Color"); - } glGenTextures(1, &_gBuffers.depthTexture); - if (HasGLDebugInfo) { - glObjectLabel(GL_TEXTURE, _gBuffers.depthTexture, -1, "G-Buffer Depth"); - } glGenTextures(1, &_gBuffers.positionTexture); - if (HasGLDebugInfo) { - glObjectLabel(GL_TEXTURE, _gBuffers.positionTexture, -1, "G-Buffer Position"); - } glGenTextures(1, &_gBuffers.normalTexture); - if (HasGLDebugInfo) { - glObjectLabel(GL_TEXTURE, _gBuffers.normalTexture, -1, "G-Buffer Normal"); - } glGenFramebuffers(1, &_gBuffers.framebuffer); - if (HasGLDebugInfo) { - glObjectLabel(GL_FRAMEBUFFER, _gBuffers.framebuffer, -1, "G-Buffer Main"); - } + // PingPong Buffers // The first pingpong buffer shares the color texture with the renderbuffer: _pingPongBuffers.colorTexture[0] = _gBuffers.colorTexture; glGenTextures(1, &_pingPongBuffers.colorTexture[1]); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel( - GL_TEXTURE, - _pingPongBuffers.colorTexture[1], - -1, - "G-Buffer Color Ping-Pong" - ); - } glGenFramebuffers(1, &_pingPongBuffers.framebuffer); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel( - GL_FRAMEBUFFER, - _pingPongBuffers.framebuffer, - -1, - "G-Buffer Ping-Pong" - ); - } - + // Exit framebuffer glGenTextures(1, &_exitColorTexture); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit color"); - } - glGenTextures(1, &_exitDepthTexture); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit depth"); - } + glGenTextures(1, &_exitDepthTexture); glGenFramebuffers(1, &_exitFramebuffer); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_FRAMEBUFFER, _exitFramebuffer, -1, "Exit"); - } // HDR / Filtering Buffers glGenFramebuffers(1, &_hdrBuffers.hdrFilteringFramebuffer); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_FRAMEBUFFER, _exitFramebuffer, -1, "HDR filtering"); - } glGenTextures(1, &_hdrBuffers.hdrFilteringTexture); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_TEXTURE, _hdrBuffers.hdrFilteringTexture, -1, "HDR filtering"); - } - - + // FXAA Buffers glGenFramebuffers(1, &_fxaaBuffers.fxaaFramebuffer); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_FRAMEBUFFER, _fxaaBuffers.fxaaFramebuffer, -1, "FXAA"); - } glGenTextures(1, &_fxaaBuffers.fxaaTexture); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel(GL_TEXTURE, _fxaaBuffers.fxaaTexture, -1, "FXAA"); - } - + // DownscaleVolumeRendering glGenFramebuffers(1, &_downscaleVolumeRendering.framebuffer); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel( - GL_FRAMEBUFFER, - _downscaleVolumeRendering.framebuffer, - -1, - "Downscaled Volume" - ); - } glGenTextures(1, &_downscaleVolumeRendering.colorTexture); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel( - GL_TEXTURE, - _downscaleVolumeRendering.colorTexture, - -1, - "Downscaled Volume Color" - ); - } glGenTextures(1, &_downscaleVolumeRendering.depthbuffer); - if (glbinding::Binding::ObjectLabel.isResolved()) { - glObjectLabel( - GL_TEXTURE, - _downscaleVolumeRendering.depthbuffer, - -1, - "Downscaled Volume Depth" - ); - } // Allocate Textures/Buffers Memory updateResolution(); @@ -311,6 +235,9 @@ void FramebufferRenderer::initialize() { _gBuffers.depthTexture, 0 ); + if (HasGLDebugInfo) { + glObjectLabel(GL_FRAMEBUFFER, _gBuffers.framebuffer, -1, "G-Buffer Main"); + } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -339,6 +266,14 @@ void FramebufferRenderer::initialize() { _gBuffers.depthTexture, 0 ); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel( + GL_FRAMEBUFFER, + _pingPongBuffers.framebuffer, + -1, + "G-Buffer Ping-Pong" + ); + } status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -362,6 +297,9 @@ void FramebufferRenderer::initialize() { _exitDepthTexture, 0 ); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_FRAMEBUFFER, _exitFramebuffer, -1, "Exit"); + } status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -378,6 +316,9 @@ void FramebufferRenderer::initialize() { _hdrBuffers.hdrFilteringTexture, 0 ); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_FRAMEBUFFER, _hdrBuffers.hdrFilteringFramebuffer, -1, "HDR filtering"); + } status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -394,6 +335,9 @@ void FramebufferRenderer::initialize() { _fxaaBuffers.fxaaTexture, 0 ); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_FRAMEBUFFER, _fxaaBuffers.fxaaFramebuffer, -1, "FXAA"); + } status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -416,6 +360,14 @@ void FramebufferRenderer::initialize() { _downscaleVolumeRendering.depthbuffer, 0 ); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel( + GL_FRAMEBUFFER, + _downscaleVolumeRendering.framebuffer, + -1, + "Downscaled Volume" + ); + } status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -797,6 +749,10 @@ void FramebufferRenderer::updateResolution() { ZoneScoped TracyGpuZone("Renderer updateResolution") + HasGLDebugInfo = glbinding::Binding::ObjectLabel.isResolved() && + glbinding::Binding::PushDebugGroup.isResolved() && + glbinding::Binding::PopDebugGroup.isResolved(); + glBindTexture(GL_TEXTURE_2D, _gBuffers.colorTexture); glTexImage2D( GL_TEXTURE_2D, @@ -811,6 +767,9 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (HasGLDebugInfo) { + glObjectLabel(GL_TEXTURE, _gBuffers.colorTexture, -1, "G-Buffer Color"); + } glBindTexture(GL_TEXTURE_2D, _gBuffers.positionTexture); glTexImage2D( @@ -826,6 +785,9 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (HasGLDebugInfo) { + glObjectLabel(GL_TEXTURE, _gBuffers.positionTexture, -1, "G-Buffer Position"); + } glBindTexture(GL_TEXTURE_2D, _gBuffers.normalTexture); glTexImage2D( @@ -841,6 +803,9 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (HasGLDebugInfo) { + glObjectLabel(GL_TEXTURE, _gBuffers.normalTexture, -1, "G-Buffer Normal"); + } glBindTexture(GL_TEXTURE_2D, _gBuffers.depthTexture); glTexImage2D( @@ -856,6 +821,9 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (HasGLDebugInfo) { + glObjectLabel(GL_TEXTURE, _gBuffers.depthTexture, -1, "G-Buffer Depth"); + } glBindTexture(GL_TEXTURE_2D, _pingPongBuffers.colorTexture[1]); glTexImage2D( @@ -871,6 +839,14 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel( + GL_TEXTURE, + _pingPongBuffers.colorTexture[1], + -1, + "G-Buffer Color Ping-Pong" + ); + } // HDR / Filtering glBindTexture(GL_TEXTURE_2D, _hdrBuffers.hdrFilteringTexture); @@ -887,6 +863,9 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _hdrBuffers.hdrFilteringTexture, -1, "HDR filtering"); + } // FXAA glBindTexture(GL_TEXTURE_2D, _fxaaBuffers.fxaaTexture); @@ -903,6 +882,9 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _fxaaBuffers.fxaaTexture, -1, "FXAA"); + } // Downscale Volume Rendering glBindTexture(GL_TEXTURE_2D, _downscaleVolumeRendering.colorTexture); @@ -925,6 +907,14 @@ void FramebufferRenderer::updateResolution() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); float volumeBorderColor[] = { 0.0f, 0.0f, 0.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, volumeBorderColor); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel( + GL_TEXTURE, + _downscaleVolumeRendering.colorTexture, + -1, + "Downscaled Volume Color" + ); + } glBindTexture(GL_TEXTURE_2D, _downscaleVolumeRendering.depthbuffer); glTexImage2D( @@ -944,6 +934,14 @@ void FramebufferRenderer::updateResolution() { ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel( + GL_TEXTURE, + _downscaleVolumeRendering.depthbuffer, + -1, + "Downscaled Volume Depth" + ); + } // Volume Rendering Textures glBindTexture(GL_TEXTURE_2D, _exitColorTexture); @@ -958,12 +956,13 @@ void FramebufferRenderer::updateResolution() { GL_UNSIGNED_SHORT, nullptr ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit color"); + } glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); - glTexImage2D( GL_TEXTURE_2D, 0, @@ -975,9 +974,11 @@ void FramebufferRenderer::updateResolution() { GL_FLOAT, nullptr ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit depth"); + } _dirtyResolution = false; } From d31b20decffc4c86e85d2f50e00ca2f1511d15c4 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 16 Oct 2020 17:01:35 +0200 Subject: [PATCH 14/29] Adapt disc shader to handle asymmetric uncertainty intervals --- modules/exoplanets/shaders/orbitdisc_fs.glsl | 30 ++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/modules/exoplanets/shaders/orbitdisc_fs.glsl b/modules/exoplanets/shaders/orbitdisc_fs.glsl index 373ea936dc..bf8cb01c5c 100644 --- a/modules/exoplanets/shaders/orbitdisc_fs.glsl +++ b/modules/exoplanets/shaders/orbitdisc_fs.glsl @@ -56,12 +56,16 @@ Fragment getFragment() { // Moving the origin to the center vec2 st = (vs_st - vec2(0.5)) * 2.0; + float offsetLower = textureOffset.x; + float offsetUpper = textureOffset.y; + float offsetIntervalSize = offsetLower + offsetUpper; + float AUpper = semiMajorAxis; float BUpper = semiMinorAxis(AUpper, eccentricity); float CUpper = sqrt(AUpper*AUpper - BUpper*BUpper); float outerApoapsisDistance = AUpper * (1 + eccentricity); - float ALower = AUpper - AstronomicalUnit * (textureOffset.x + textureOffset.y); + float ALower = AUpper - AstronomicalUnit * offsetIntervalSize; float BLower = semiMinorAxis(ALower, eccentricity); float CLower = sqrt(ALower*ALower - BLower*BLower); float innerApoapsisDistance = ALower * (1 + eccentricity); @@ -91,18 +95,28 @@ Fragment getFragment() { // Find outer ellipse: where along the direction does the equation == 1? float denominator = pow(BU_n * dir.x, 2.0) + pow(AU_n * dir.y, 2.0); - float first = -(pow(BU_n, 2.0) * dir.x * CU_n) / denominator; - float second = pow((pow(BU_n, 2.0) * dir.x * CU_n) / denominator, 2.0); + float first = -(BU_n * BU_n * dir.x * CU_n) / denominator; + float second = pow((BU_n * BU_n * dir.x * CU_n) / denominator, 2.0); float third = (pow(BU_n * CU_n, 2.0) - pow(AU_n * BU_n, 2.0)) / denominator; float scale = first + sqrt(second - third); - vec2 max = dir * scale; - vec2 min = max * (innerApoapsisDistance / outerApoapsisDistance); + vec2 outerPoint = dir * scale; + vec2 innerPoint = outerPoint * (innerApoapsisDistance / outerApoapsisDistance); - float distance1 = distance(max, min); - float distance2 = distance(max, st); - float textureCoord = distance2 / distance1; + float discWidth = distance(outerPoint, innerPoint); + float distanceFromOuterEdge = distance(outerPoint, st); + float textureCoord = distanceFromOuterEdge / discWidth; + + // Scale texture coordinate to handle asymmetric offset intervals + float textureMid = offsetUpper / offsetIntervalSize; + + if(textureCoord > textureMid) { + textureCoord = 0.5 + 0.5 * (textureCoord - textureMid) / (1.0 - textureMid); + } + else { + textureCoord = 0.5 * textureCoord / textureMid; + } vec4 diffuse = texture(discTexture, textureCoord); diffuse.a *= opacity; From c7f239d3dc6854f5e9085a938698eeea787cfb9e Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Fri, 16 Oct 2020 16:56:51 -0400 Subject: [PATCH 15/29] Fixed issue 1323. --- modules/globebrowsing/shaders/texturetilemapping.hglsl | 2 +- modules/globebrowsing/src/renderableglobe.cpp | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index a866211b85..b6bcf749fd 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -363,7 +363,7 @@ vec4 calculateNight(vec4 currentColor, vec2 uv, vec3 levelWeights, // Filter to night side vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha); - color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha); + color = blendNightLayers#{i}(color, newColor, adjustedAlpha); } #endfor diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 3a8b9ed982..4ea6fb38e7 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -1051,8 +1051,6 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, const std::array& layerGroups = _layerManager.layerGroups(); - using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; - _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); for (size_t i = 0; i < layerGroups.size(); ++i) { const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; _globalRenderer.gpuLayerGroups[i].bind( @@ -1062,8 +1060,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, static_cast(i) ); } - _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::No); - + const float dsf = static_cast( _generalProperties.currentLodScaleFactor * _ellipsoid.minimumRadius() ); @@ -1078,8 +1075,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, if (_localRenderer.updatedSinceLastCall) { const std::array& layerGroups = _layerManager.layerGroups(); - using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; - _localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); + for (size_t i = 0; i < layerGroups.size(); ++i) { const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; _localRenderer.gpuLayerGroups[i].bind( @@ -1089,7 +1085,6 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, static_cast(i) ); } - _localRenderer.program->setIgnoreUniformLocationError(IgnoreError::No); const float dsf = static_cast( _generalProperties.currentLodScaleFactor * _ellipsoid.minimumRadius() From 0779c54a077c048f634bcf29aa6ce0cc42890f1e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 17 Oct 2020 20:10:15 +0200 Subject: [PATCH 16/29] Provide correct error message if the ProfileName is empty Don't include Voyager and Pioneer in the base asset as it takes too long to load Ensure that the webgui asset can load without the dashboard Fix scripting issue in Rosetta scene with trails Fix issue with Dashboards that would actually render one line too far down causing trouble with multiline text Set the render option for renderablebillboards to view direction by default as the normal mode has some issues (see #1342) Set more sensible maximum value for RenderablePlanesCloud Correctly show the number of significant digits in the altitude Replace setPropertyValue with setPropertyValueSingle when clicking on the friction "buttons" on screen Add a new script function hasProperty to check whether a property exits --- .../ext/launcher/src/profile/profileedit.cpp | 22 +++++++++---------- data/assets/base.asset | 1 - data/assets/util/webgui.asset | 8 +++++-- data/profiles/rosetta.profile | 4 ++-- ext/ghoul | 2 +- modules/base/dashboard/dashboarditemangle.cpp | 4 ++-- modules/base/dashboard/dashboarditemdate.cpp | 2 +- .../base/dashboard/dashboarditemdistance.cpp | 2 +- .../base/dashboard/dashboarditemframerate.cpp | 18 +++++++++++++-- .../base/dashboard/dashboarditemmission.cpp | 4 ++-- .../dashboarditemparallelconnection.cpp | 2 +- .../dashboard/dashboarditempropertyvalue.cpp | 2 +- .../dashboarditemsimulationincrement.cpp | 2 +- .../base/dashboard/dashboarditemvelocity.cpp | 2 +- .../rendering/renderablebillboardscloud.cpp | 2 +- .../rendering/renderableplanescloud.cpp | 2 +- .../src/dashboarditemglobelocation.cpp | 12 +++++----- src/rendering/dashboard.cpp | 2 +- src/rendering/renderengine.cpp | 6 ++--- src/scene/scene.cpp | 10 +++++++-- src/scene/scene_lua.inl | 21 +++++++++++++++++- 21 files changed, 86 insertions(+), 44 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp b/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp index fe3a78509c..ccbff3ccb9 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp @@ -496,27 +496,27 @@ bool ProfileEdit::isReadOnly(std::string profileSave) { void ProfileEdit::approved() { QString profileName = _profileEdit->text(); + if (profileName.isEmpty()) { + _errorMsg->setText("Profile name must be specified"); + return; + } + if ((profileName.length() > 0) && !isReadOnly(profileName.toStdString())) { _saveSelected = true; _errorMsg->setText(""); accept(); } else { - //QString formatText = ""; - //formatText += ui->label_profile->text(); - //formatText += ""; - //ui->label_profile->setText(formatText); - QString errorLabel = ""; - errorLabel += "This is a read-only profile. Click 'duplicate' or rename & save."; - errorLabel += ""; - _errorMsg->setText(errorLabel); + _errorMsg->setText( + "This is a read-only profile. Click 'duplicate' or rename & save" + ); } } -void ProfileEdit::keyPressEvent(QKeyEvent *evt) -{ - if(evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) +void ProfileEdit::keyPressEvent(QKeyEvent* evt) { + if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) { return; + } QDialog::keyPressEvent(evt); } diff --git a/data/assets/base.asset b/data/assets/base.asset index 7aa99367de..ee94a61231 100644 --- a/data/assets/base.asset +++ b/data/assets/base.asset @@ -15,7 +15,6 @@ asset.require('scene/solarsystem/planets/mars/moons/deimos') asset.require('scene/solarsystem/dwarf_planets/pluto/system') asset.require('scene/solarsystem/dwarf_planets/pluto/default_layers') asset.require('scene/solarsystem/dwarf_planets/pluto/charon/default_layers') -asset.require('scene/solarsystem/missions/voyagerpioneer/voyager1_2__pioneer10_11') asset.require('scene/milkyway/milkyway/volume') asset.require('scene/milkyway/constellations/constellation_art') asset.require('scene/milkyway/constellations/constellation_keybinds') diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 42932e3636..f6b2a418b9 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -40,8 +40,12 @@ asset.onInitialize(function () -- The GUI contains date and simulation increment, -- so let's remove these from the dashboard. if openspace.getPropertyValue('Modules.CefWebGui.Visible') then - openspace.setPropertyValueSingle('Dashboard.Date.Enabled', false) - openspace.setPropertyValueSingle('Dashboard.SimulationIncrement.Enabled', false) + if openspace.hasProperty('Dashboard.Date.Enabled') then + openspace.setPropertyValueSingle('Dashboard.Date.Enabled', false) + end + if openspace.hasProperty('Dashboard.SimulationIncrement.Enabled') then + openspace.setPropertyValueSingle('Dashboard.SimulationIncrement.Enabled', false) + end end end) diff --git a/data/profiles/rosetta.profile b/data/profiles/rosetta.profile index b5f3c0ba9e..3f344c3893 100644 --- a/data/profiles/rosetta.profile +++ b/data/profiles/rosetta.profile @@ -98,7 +98,7 @@ "is_local": false, "key": "O", "name": "Toggle Philae trail", - "script": "openspace.setPropertyValueSingle(Scene.PhilaeTrail.Renderable.Enabled', not openspace.getPropertyValue(Scene.PhilaeTrail.Renderable.Enabled'));" + "script": "openspace.setPropertyValueSingle('Scene.PhilaeTrail.Renderable.Enabled', not openspace.getPropertyValue('Scene.PhilaeTrail.Renderable.Enabled'));" }, { "documentation": "Enables or disables the image projection on 67P.", @@ -106,7 +106,7 @@ "is_local": false, "key": "P", "name": "Toggle 67P projection", - "script": "openspace.setPropertyValueSingle(Scene.67P.Renderable.ProjectionComponent.PerformProjection', not openspace.getPropertyValue(Scene.67P.Renderable.ProjectionComponent.PerformProjection'));" + "script": "openspace.setPropertyValueSingle('Scene.67P.Renderable.ProjectionComponent.PerformProjection', not openspace.getPropertyValue('Scene.67P.Renderable.ProjectionComponent.PerformProjection'));" } ], "mark_nodes": [ diff --git a/ext/ghoul b/ext/ghoul index 0648ae153a..a9842afb9e 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 0648ae153af4f8975e17c9a93db9f9bb75b4dcfa +Subproject commit a9842afb9ee64f636c746844dfa8ec2eecaca582 diff --git a/modules/base/dashboard/dashboarditemangle.cpp b/modules/base/dashboard/dashboarditemangle.cpp index 991afa4520..e2a3c49b5d 100644 --- a/modules/base/dashboard/dashboarditemangle.cpp +++ b/modules/base/dashboard/dashboarditemangle.cpp @@ -404,7 +404,6 @@ void DashboardItemAngle::render(glm::vec2& penPosition) { std::fill(_buffer.begin(), _buffer.end(), 0); if (glm::length(a) == 0.0 || glm::length(b) == 0) { - penPosition.y -= _font->height(); char* end = fmt::format_to( _buffer.data(), "Could not compute angle at {} between {} and {}", @@ -412,13 +411,13 @@ void DashboardItemAngle::render(glm::vec2& penPosition) { ); std::string_view text = std::string_view(_buffer.data(), end - _buffer.data()); RenderFont(*_font, penPosition, text); + penPosition.y -= _font->height(); } else { const double angle = glm::degrees( glm::acos(glm::dot(a, b) / (glm::length(a) * glm::length(b))) ); - penPosition.y -= _font->height(); char* end = fmt::format_to( _buffer.data(), "Angle at {} between {} and {}: {} degrees", @@ -426,6 +425,7 @@ void DashboardItemAngle::render(glm::vec2& penPosition) { ); std::string_view text = std::string_view(_buffer.data(), end - _buffer.data()); RenderFont(*_font, penPosition, text); + penPosition.y -= _font->height(); } } diff --git a/modules/base/dashboard/dashboarditemdate.cpp b/modules/base/dashboard/dashboarditemdate.cpp index b003e06882..0cd58ffe29 100644 --- a/modules/base/dashboard/dashboarditemdate.cpp +++ b/modules/base/dashboard/dashboarditemdate.cpp @@ -113,12 +113,12 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary) void DashboardItemDate::render(glm::vec2& penPosition) { ZoneScoped - penPosition.y -= _font->height(); RenderFont( *_font, penPosition, fmt::format("Date: {} UTC", global::timeManager.time().UTC()) ); + penPosition.y -= _font->height(); } glm::vec2 DashboardItemDate::size() const { diff --git a/modules/base/dashboard/dashboarditemdistance.cpp b/modules/base/dashboard/dashboarditemdistance.cpp index 655e7881a8..5780801960 100644 --- a/modules/base/dashboard/dashboarditemdistance.cpp +++ b/modules/base/dashboard/dashboarditemdistance.cpp @@ -444,7 +444,6 @@ void DashboardItemDistance::render(glm::vec2& penPosition) { dist = { convertedD, nameForDistanceUnit(unit, convertedD != 1.0) }; } - penPosition.y -= _font->height(); std::fill(_buffer.begin(), _buffer.end(), 0); char* end = fmt::format_to( _buffer.data(), @@ -454,6 +453,7 @@ void DashboardItemDistance::render(glm::vec2& penPosition) { std::string_view text = std::string_view(_buffer.data(), end - _buffer.data()); RenderFont(*_font, penPosition, text); + penPosition.y -= _font->height(); } glm::vec2 DashboardItemDistance::size() const { diff --git a/modules/base/dashboard/dashboarditemframerate.cpp b/modules/base/dashboard/dashboarditemframerate.cpp index 08c660c509..8471fa2280 100644 --- a/modules/base/dashboard/dashboarditemframerate.cpp +++ b/modules/base/dashboard/dashboarditemframerate.cpp @@ -149,6 +149,21 @@ namespace { throw ghoul::MissingCaseException(); } } + + [[ nodiscard ]] int nLines( + openspace::DashboardItemFramerate::FrametimeType frametimeType) + { + using FrametimeType = openspace::DashboardItemFramerate::FrametimeType; + switch (frametimeType) { + case FrametimeType::DtTimeAvg: return 1; + case FrametimeType::DtTimeExtremes: return 2; + case FrametimeType::DtStandardDeviation: return 1; + case FrametimeType::DtCoefficientOfVariation: return 1; + case FrametimeType::FPS: return 1; + case FrametimeType::FPSAvg: return 1; + default: throw ghoul::MissingCaseException(); + } + } } // namespace namespace openspace { @@ -309,13 +324,12 @@ void DashboardItemFramerate::render(glm::vec2& penPosition) { int nLines = output.empty() ? 0 : static_cast((std::count(output.begin(), output.end(), '\n') + 1)); - penPosition.y -= _font->height() * static_cast(nLines); - ghoul::fontrendering::FontRenderer::defaultRenderer().render( *_font, penPosition, output ); + penPosition.y -= _font->height() * static_cast(nLines); } glm::vec2 DashboardItemFramerate::size() const { diff --git a/modules/base/dashboard/dashboarditemmission.cpp b/modules/base/dashboard/dashboarditemmission.cpp index eb65bc8651..e2be50766f 100644 --- a/modules/base/dashboard/dashboarditemmission.cpp +++ b/modules/base/dashboard/dashboarditemmission.cpp @@ -209,7 +209,6 @@ void DashboardItemMission::render(glm::vec2& penPosition) { 1.0 - remaining / phase->timeRange().duration() ); const std::string progress = progressToStr(25, t); - penPosition.y -= _font->height(); RenderFont( *_font, penPosition, @@ -219,16 +218,17 @@ void DashboardItemMission::render(glm::vec2& penPosition) { ), currentMissionColor ); + penPosition.y -= _font->height(); } else { if (!phase->name().empty()) { - penPosition.y -= _font->height(); RenderFont( *_font, penPosition, phase->name(), nonCurrentMissionColor ); + penPosition.y -= _font->height(); } } penPosition.x -= depth * PixelIndentation; diff --git a/modules/base/dashboard/dashboarditemparallelconnection.cpp b/modules/base/dashboard/dashboarditemparallelconnection.cpp index 54a2642387..a7858f74b7 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.cpp +++ b/modules/base/dashboard/dashboarditemparallelconnection.cpp @@ -161,8 +161,8 @@ void DashboardItemParallelConnection::render(glm::vec2& penPosition) { } if (!connectionInfo.empty()) { - penPosition.y -= _font->height(); RenderFont(*_font, penPosition, connectionInfo); + penPosition.y -= _font->height(); } } diff --git a/modules/base/dashboard/dashboarditempropertyvalue.cpp b/modules/base/dashboard/dashboarditempropertyvalue.cpp index d388e379fb..052370463d 100644 --- a/modules/base/dashboard/dashboarditempropertyvalue.cpp +++ b/modules/base/dashboard/dashboarditempropertyvalue.cpp @@ -163,8 +163,8 @@ void DashboardItemPropertyValue::render(glm::vec2& penPosition) { std::string value; _property->getStringValue(value); - penPosition.y -= _font->height(); RenderFont(*_font, penPosition, fmt::format(_displayString.value(), value)); + penPosition.y -= _font->height(); } } diff --git a/modules/base/dashboard/dashboarditemsimulationincrement.cpp b/modules/base/dashboard/dashboarditemsimulationincrement.cpp index def2b6f9e1..06b6375cf0 100644 --- a/modules/base/dashboard/dashboarditemsimulationincrement.cpp +++ b/modules/base/dashboard/dashboarditemsimulationincrement.cpp @@ -203,7 +203,6 @@ void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) { std::string pauseText = global::timeManager.isPaused() ? " (Paused)" : ""; - penPosition.y -= _font->height(); if (targetDt != currentDt && !global::timeManager.isPaused()) { // We are in the middle of a transition RenderFont( @@ -227,6 +226,7 @@ void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) { ) ); } + penPosition.y -= _font->height(); } glm::vec2 DashboardItemSimulationIncrement::size() const { diff --git a/modules/base/dashboard/dashboarditemvelocity.cpp b/modules/base/dashboard/dashboarditemvelocity.cpp index e89fedb6be..7c12cc40be 100644 --- a/modules/base/dashboard/dashboarditemvelocity.cpp +++ b/modules/base/dashboard/dashboarditemvelocity.cpp @@ -208,7 +208,6 @@ void DashboardItemVelocity::render(glm::vec2& penPosition) { dist = { convertedD, nameForDistanceUnit(unit, convertedD != 1.0) }; } - penPosition.y -= _font->height(); RenderFont( *_font, penPosition, @@ -216,6 +215,7 @@ void DashboardItemVelocity::render(glm::vec2& penPosition) { "Camera velocity: {} {}/s", dist.first, dist.second ) ); + penPosition.y -= _font->height(); _prevPosition = currentPos; } diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index 84ca5205e4..be3f8bae03 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -481,7 +481,7 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di _renderOption.addOption(RenderOptionViewDirection, "Camera View Direction"); _renderOption.addOption(RenderOptionPositionNormal, "Camera Position Normal"); - _renderOption = RenderOptionPositionNormal; + _renderOption = RenderOptionViewDirection; if (dictionary.hasKeyAndValue(RenderOptionInfo.identifier)) { const std::string o = dictionary.value(RenderOptionInfo.identifier); diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index 863c844aac..bf103c7920 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -299,7 +299,7 @@ documentation::Documentation RenderablePlanesCloud::Documentation() { RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary) : Renderable(dictionary) - , _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 10000.f) + , _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 100.f) , _textColor(TextColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) , _textOpacity(TextOpacityInfo, 1.f, 0.f, 1.f) , _textSize(TextSizeInfo, 8.0, 0.5, 24.0) diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp index d23f1cf868..a696958163 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -139,10 +139,10 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation( auto updateFormatString = [this]() { using namespace fmt::literals; - _formatString = - "Position: {{:03.{0}f}}{{}}, {{:03.{0}f}}{{}} Altitude: {{}} {{}}"_format( - _significantDigits.value() - ); + _formatString = fmt::format( + "Position: {{:03.{0}f}}{{}}, {{:03.{0}f}}{{}} Altitude: {{:03.{0}f}} {{}}", + _significantDigits.value() + ); }; _significantDigits.onChange(updateFormatString); addProperty(_significantDigits); @@ -199,8 +199,6 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { std::pair dist = simplifyDistance(altitude); - penPosition.y -= _font->height(); - std::fill(_buffer.begin(), _buffer.end(), 0); char* end = fmt::format_to( _buffer.data(), @@ -212,7 +210,9 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { std::string_view text = std::string_view(_buffer.data(), end - _buffer.data()); RenderFont(*_font, penPosition, text); + penPosition.y -= _font->height(); } + glm::vec2 DashboardItemGlobeLocation::size() const { ZoneScoped diff --git a/src/rendering/dashboard.cpp b/src/rendering/dashboard.cpp index c700326cbc..43bc3bb4c5 100644 --- a/src/rendering/dashboard.cpp +++ b/src/rendering/dashboard.cpp @@ -52,7 +52,7 @@ Dashboard::Dashboard() : properties::PropertyOwner({ "Dashboard" }) , _isEnabled(EnabledInfo, true) , _startPositionOffset( - properties::IVec2Property(StartPositionOffsetInfo, glm::ivec2(10, -10)) + properties::IVec2Property(StartPositionOffsetInfo, glm::ivec2(10, -25)) ) { addProperty(_isEnabled); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 8985e28cee..2ad38678f1 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -758,7 +758,7 @@ bool RenderEngine::mouseActivationCallback(const glm::dvec2& mousePosition) cons if (intersects(mousePosition, _cameraButtonLocations.rotation)) { constexpr const char* ToggleRotationFrictionScript = R"( local f = 'NavigationHandler.OrbitalNavigator.Friction.RotationalFriction'; - openspace.setPropertyValue(f, not openspace.getPropertyValue(f));)"; + openspace.setPropertyValueSingle(f, not openspace.getPropertyValue(f));)"; global::scriptEngine.queueScript( ToggleRotationFrictionScript, @@ -770,7 +770,7 @@ bool RenderEngine::mouseActivationCallback(const glm::dvec2& mousePosition) cons if (intersects(mousePosition, _cameraButtonLocations.zoom)) { constexpr const char* ToggleZoomFrictionScript = R"( local f = 'NavigationHandler.OrbitalNavigator.Friction.ZoomFriction'; - openspace.setPropertyValue(f, not openspace.getPropertyValue(f));)"; + openspace.setPropertyValueSingle(f, not openspace.getPropertyValue(f));)"; global::scriptEngine.queueScript( ToggleZoomFrictionScript, @@ -782,7 +782,7 @@ bool RenderEngine::mouseActivationCallback(const glm::dvec2& mousePosition) cons if (intersects(mousePosition, _cameraButtonLocations.roll)) { constexpr const char* ToggleRollFrictionScript = R"( local f = 'NavigationHandler.OrbitalNavigator.Friction.RollFriction'; - openspace.setPropertyValue(f, not openspace.getPropertyValue(f));)"; + openspace.setPropertyValueSingle(f, not openspace.getPropertyValue(f));)"; global::scriptEngine.queueScript( ToggleRollFrictionScript, diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 9acf5a9015..d364354be3 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -636,13 +636,19 @@ scripting::LuaLibrary Scene::luaLibrary() { "This is the same as calling the setValue method and passing 'single' as " "the fourth argument to setPropertyValue." }, + { + "hasProperty", + &luascriptfunctions::property_hasProperty, + {}, + "string", + "Returns whether a property with the given URI exists" + }, { "getPropertyValue", &luascriptfunctions::property_getValue, {}, "string", - "Returns the value the property, identified by " - "the provided URI." + "Returns the value the property, identified by the provided URI." }, { "getProperty", diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index 5bf13fb19b..9af3720b5a 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -376,6 +376,25 @@ int property_setValueSingle(lua_State* L) { return property_setValue(L); } +/** + * \ingroup LuaScripts + * hasProperty(string): + * Returns whether a property with the given URI exists + */ +int property_hasProperty(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_hasProperty"); + + std::string uri = ghoul::lua::value( + L, + 1, + ghoul::lua::PopValue::Yes + ); + + openspace::properties::Property* prop = property(uri); + ghoul::lua::push(L, prop != nullptr); + return 1; +} + /** * \ingroup LuaScripts * getPropertyValue(string): @@ -389,7 +408,7 @@ int property_getValue(lua_State* L) { L, 1, ghoul::lua::PopValue::Yes - ); + ); openspace::properties::Property* prop = property(uri); if (!prop) { From e49b8ce71e3b775d08c5dcff93d71e42a2df5c22 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 17 Oct 2020 20:20:21 +0200 Subject: [PATCH 17/29] Switch order of SetPropertyValue and SetPropertyValueSingle in the Profile ui --- .../launcher/src/profile/propertiesdialog.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp index b78fc49531..4608478841 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp @@ -35,15 +35,17 @@ #include #include +using namespace openspace; + namespace { - const openspace::Profile::Property kBlank { - openspace::Profile::Property::SetType::SetPropertyValue, + const Profile::Property kBlank { + Profile::Property::SetType::SetPropertyValueSingle, "", "" }; } // namespace -PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent) +PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent) : QDialog(parent) , _profile(profile) , _data(_profile.properties()) @@ -93,7 +95,7 @@ PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent) layout->addWidget(_commandLabel); _commandCombo = new QComboBox; - _commandCombo->addItems({ "SetPropertyValue", "SetPropertyValueSingle" }); + _commandCombo->addItems({ "SetPropertyValueSingle", "SetPropertyValue" }); layout->addWidget(_commandCombo); _propertyLabel = new QLabel("Property"); @@ -154,12 +156,12 @@ PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent) transitionFromEditMode(); } -QString PropertiesDialog::createOneLineSummary(openspace::Profile::Property p) { +QString PropertiesDialog::createOneLineSummary(Profile::Property p) { QString summary = QString::fromStdString(p.name); summary += " = "; summary += QString::fromStdString(p.value); summary += " (SetPropertyValue"; - if (p.setType == openspace::Profile::Property::SetType::SetPropertyValueSingle) { + if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) { summary += "Single"; } summary += ")"; @@ -171,8 +173,8 @@ void PropertiesDialog::listItemSelected() { int index = _list->row(item); if (_data.size() > 0) { - openspace::Profile::Property& p = _data[index]; - if (p.setType == openspace::Profile::Property::SetType::SetPropertyValue) { + Profile::Property& p = _data[index]; + if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) { _commandCombo->setCurrentIndex(0); } else { @@ -199,7 +201,7 @@ void PropertiesDialog::listItemAdded(void) { int currentListSize = _list->count(); if ((currentListSize == 1) && (isLineEmpty(0))) { - //Special case where list is "empty" but really has one line that is blank. + // Special case where list is "empty" but really has one line that is blank. // This is done because QListWidget does not seem to like having its sole // remaining item being removed. _data.at(0) = kBlank; @@ -232,12 +234,10 @@ void PropertiesDialog::listItemSave(void) { if ( _data.size() > 0) { if (_commandCombo->currentIndex() == 0) { - _data[index].setType - = openspace::Profile::Property::SetType::SetPropertyValue; + _data[index].setType = Profile::Property::SetType::SetPropertyValueSingle; } else { - _data[index].setType - = openspace::Profile::Property::SetType::SetPropertyValueSingle; + _data[index].setType = Profile::Property::SetType::SetPropertyValue; } _data[index].name = _propertyEdit->text().toStdString(); _data[index].value = _valueEdit->text().toStdString(); From 250998fede2ae96aa54901290a6184f6e9e95483 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 18 Oct 2020 14:10:20 +0200 Subject: [PATCH 18/29] Update version to Beta-8 RC1 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd4adeff10..7343b90e4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,9 +27,9 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(OpenSpace) set(OPENSPACE_VERSION_MAJOR 0) -set(OPENSPACE_VERSION_MINOR 15) -set(OPENSPACE_VERSION_PATCH 2) -set(OPENSPACE_VERSION_STRING "Beta-7") +set(OPENSPACE_VERSION_MINOR 16) +set(OPENSPACE_VERSION_PATCH 0) +set(OPENSPACE_VERSION_STRING "Beta-8 RC1") set(OPENSPACE_BASE_DIR "${PROJECT_SOURCE_DIR}") set(OPENSPACE_CMAKE_EXT_DIR "${OPENSPACE_BASE_DIR}/support/cmake") From 940723342d83abe2df71e409b627566c47897626 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 18 Oct 2020 19:00:26 +0200 Subject: [PATCH 19/29] Add the ability to filter the colormap linearly in the RenderableBillboardCloud Add a butting to the RenderableBillboardsCloud to set the color table range to the min/max value of the dataset --- .../rendering/renderablebillboardscloud.cpp | 99 ++++++++++++++++--- .../rendering/renderablebillboardscloud.h | 3 + 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index be3f8bae03..7481deea0c 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -257,6 +257,19 @@ namespace { "Enable pixel size control.", "Enable pixel size control for rectangular projections." }; + + constexpr openspace::properties::Property::PropertyInfo UseLinearFiltering = { + "UseLinearFiltering", + "Use Linear Filtering", + "Determines whether the provided color map should be sampled nearest neighbor " + "(=off) or linearly (=on" + }; + + constexpr openspace::properties::Property::PropertyInfo SetRangeFromData = { + "SetRangeFromData", + "Set Data Range from Data", + "Set the data range based on the available data" + }; } // namespace namespace openspace { @@ -422,6 +435,12 @@ documentation::Documentation RenderableBillboardsCloud::Documentation() { new BoolVerifier, Optional::Yes, PixelSizeControlInfo.description + }, + { + UseLinearFiltering.identifier, + new BoolVerifier, + Optional::Yes, + UseLinearFiltering.description } } }; @@ -459,6 +478,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di , _correctionSizeEndDistance(CorrectionSizeEndDistanceInfo, 17.f, 12.f, 25.f) , _correctionSizeFactor(CorrectionSizeFactorInfo, 8.f, 0.f, 20.f) , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) + , _setRangeFromData(SetRangeFromData) + , _useLinearFiltering(UseLinearFiltering, false) { documentation::testSpecificationAndThrow( Documentation(), @@ -713,6 +734,28 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di _pixelSizeControl = dictionary.value(PixelSizeControlInfo.identifier); addProperty(_pixelSizeControl); } + + _setRangeFromData.onChange([this]() { + const int colorMapInUse = + _hasColorMapFile ? _variableDataPositionMap[_colorOptionString] : 0; + + float minValue = std::numeric_limits::max(); + float maxValue = std::numeric_limits::min(); + for (size_t i = 0; i < _fullData.size(); i += _nValuesPerAstronomicalObject) { + float colorIdx = _fullData[i + 3 + colorMapInUse]; + maxValue = colorIdx >= maxValue ? colorIdx : maxValue; + minValue = colorIdx < minValue ? colorIdx : minValue; + } + + _optionColorRangeData = glm::vec2(minValue, maxValue); + }); + addProperty(_setRangeFromData); + + if (dictionary.hasKey(UseLinearFiltering.identifier)) { + _useLinearFiltering = dictionary.value(UseLinearFiltering.identifier); + } + _useLinearFiltering.onChange([&]() { _dataIsDirty = true; }); + addProperty(_useLinearFiltering); } bool RenderableBillboardsCloud::isReady() const { @@ -1668,11 +1711,9 @@ void RenderableBillboardsCloud::createDataSlice() { _slicedData.push_back(position[j]); biggestCoord = biggestCoord < position[j] ? position[j] : biggestCoord; } - // Note: if exact colormap option is not selected, the first color and the // last color in the colormap file are the outliers colors. - int variableColor = static_cast(_fullData[i + 3 + colorMapInUse]); - int colorIndex = 0; + float variableColor = _fullData[i + 3 + colorMapInUse]; float cmax, cmin; if (_colorRangeData.empty()) { @@ -1686,19 +1727,51 @@ void RenderableBillboardsCloud::createDataSlice() { } if (_isColorMapExact) { - colorIndex = variableColor + cmin; + int colorIndex = variableColor + cmin; + for (int j = 0; j < 4; ++j) { + _slicedData.push_back(_colorMapData[colorIndex][j]); + } } else { - float ncmap = static_cast(_colorMapData.size()); - float normalization = ((cmax != cmin) && (ncmap > 2)) ? - (ncmap - 2) / (cmax - cmin) : 0; - colorIndex = (variableColor - cmin) * normalization + 1; - colorIndex = colorIndex < 0 ? 0 : colorIndex; - colorIndex = colorIndex >= ncmap ? ncmap - 1 : colorIndex; - } + if (_useLinearFiltering) { + const float value = variableColor; - for (int j = 0; j < 4; ++j) { - _slicedData.push_back(_colorMapData[colorIndex][j]); + float valueT = (value - cmin) / (cmax - cmin); // in [0, 1) + valueT = std::clamp(valueT, 0.f, 1.f); + + const float idx = valueT * (_colorMapData.size() - 1); + const int floorIdx = static_cast(std::floor(idx)); + const int ceilIdx = static_cast(std::ceil(idx)); + + const glm::vec4 floorColor = _colorMapData[floorIdx]; + const glm::vec4 ceilColor = _colorMapData[ceilIdx]; + + if (floorColor != ceilColor) { + const glm::vec4 c = floorColor + idx * (ceilColor - floorColor); + _slicedData.push_back(c.r); + _slicedData.push_back(c.g); + _slicedData.push_back(c.b); + _slicedData.push_back(c.a); + } + else { + _slicedData.push_back(floorColor.r); + _slicedData.push_back(floorColor.g); + _slicedData.push_back(floorColor.b); + _slicedData.push_back(floorColor.a); + } + } + else { + float ncmap = static_cast(_colorMapData.size()); + float normalization = ((cmax != cmin) && (ncmap > 2)) ? + (ncmap - 2) / (cmax - cmin) : 0; + int colorIndex = (variableColor - cmin) * normalization + 1; + colorIndex = colorIndex < 0 ? 0 : colorIndex; + colorIndex = colorIndex >= ncmap ? ncmap - 1 : colorIndex; + + for (int j = 0; j < 4; ++j) { + _slicedData.push_back(_colorMapData[colorIndex][j]); + } + } } if (_hasDatavarSize) { diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.h b/modules/digitaluniverse/rendering/renderablebillboardscloud.h index 4747258811..e4e6d40d9b 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.h +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -131,6 +132,8 @@ private: properties::FloatProperty _billboardMinSize; properties::FloatProperty _correctionSizeEndDistance; properties::FloatProperty _correctionSizeFactor; + properties::BoolProperty _useLinearFiltering; + properties::TriggerProperty _setRangeFromData; // DEBUG: properties::OptionProperty _renderOption; From 8e05054602c063d5aadef5b252d74c0d54919c39 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 18 Oct 2020 19:00:45 +0200 Subject: [PATCH 20/29] Make profile saving not crash --- src/scene/profile_lua.inl | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index a60c6b4c59..970eb5ac45 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -65,11 +66,14 @@ int saveSettingsToProfile(lua_State* L) { utcTime->tm_min, utcTime->tm_sec ); - std::string newFile = fmt::format( - "{}_{}.{}", - f.fullBaseName(), time, f.fileExtension() - ); - std::filesystem::copy(global::configuration.profile, newFile); + std::string newFile = fmt::format("{}_{}", f.fullBaseName(), time); + std::string sourcePath = + absPath("${PROFILES}") + '/' + global::configuration.profile + ".profile"; + std::string destPath = + absPath("${PROFILES}") + '/' + newFile + ".profile"; + + LINFOC("Profile", fmt::format("Saving a copy of the old profile as {}", newFile)); + std::filesystem::copy(sourcePath, destPath); saveFilePath = global::configuration.profile; } else { @@ -97,14 +101,14 @@ int saveSettingsToProfile(lua_State* L) { } const std::string absFilename = absPath("${PROFILES}/" + saveFilePath + ".profile"); - const bool overwrite = (n == 2) ? ghoul::lua::value(L, 2) : false; + const bool overwrite = (n == 2) ? ghoul::lua::value(L, 2) : true; if (FileSys.fileExists(absFilename) && !overwrite) { return luaL_error( L, fmt::format( - "Unable to save profile '{}'. File of same name already exists.", - absFilename.c_str() + "Unable to save profile '{}'. File of same name already exists", + absFilename ).c_str() ); } @@ -130,8 +134,7 @@ int saveSettingsToProfile(lua_State* L) { return luaL_error( L, fmt::format( - "Data write error to file: {} ({})", - absFilename, e.what() + "Data write error to file: {} ({})", absFilename, e.what() ).c_str() ); } From 37ac1466b43d337cb4aa1f66df9f7a41f7b8dc86 Mon Sep 17 00:00:00 2001 From: GPayne Date: Sun, 18 Oct 2020 14:13:27 -0600 Subject: [PATCH 21/29] Fix for crash if screenspace image load fails --- ext/ghoul | 2 +- .../rendering/renderableplaneimageonline.cpp | 34 ++++++++++-------- .../base/rendering/screenspaceimageonline.cpp | 36 +++++++++++-------- 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index a9842afb9e..e75af2a3be 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit a9842afb9ee64f636c746844dfa8ec2eecaca582 +Subproject commit e75af2a3be7cf1b71db04e4a083efa899a2faa01 diff --git a/modules/base/rendering/renderableplaneimageonline.cpp b/modules/base/rendering/renderableplaneimageonline.cpp index 148da49c50..3914cd2ae0 100644 --- a/modules/base/rendering/renderableplaneimageonline.cpp +++ b/modules/base/rendering/renderableplaneimageonline.cpp @@ -120,24 +120,30 @@ void RenderablePlaneImageOnline::update(const UpdateData&) { return; } - std::unique_ptr texture = - ghoul::io::TextureReader::ref().loadTexture( - reinterpret_cast(imageFile.buffer), - imageFile.size, - imageFile.format - ); + try { + std::unique_ptr texture = + ghoul::io::TextureReader::ref().loadTexture( + reinterpret_cast(imageFile.buffer), + imageFile.size, + imageFile.format + ); - if (texture) { - // Images don't need to start on 4-byte boundaries, for example if the - // image is only RGB - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture) { + // Images don't need to start on 4-byte boundaries, for example if the + // image is only RGB + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); - texture->purgeFromRAM(); + texture->uploadTexture(); + texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + texture->purgeFromRAM(); - _texture = std::move(texture); + _texture = std::move(texture); + _textureIsDirty = false; + } + } + catch (const ghoul::io::TextureReader::InvalidLoadException& e) { _textureIsDirty = false; + LERRORC(e.component, e.message); } } } diff --git a/modules/base/rendering/screenspaceimageonline.cpp b/modules/base/rendering/screenspaceimageonline.cpp index 10ad87dbde..5dd4b7c736 100644 --- a/modules/base/rendering/screenspaceimageonline.cpp +++ b/modules/base/rendering/screenspaceimageonline.cpp @@ -129,25 +129,31 @@ void ScreenSpaceImageOnline::update() { return; } - std::unique_ptr texture = - ghoul::io::TextureReader::ref().loadTexture( - reinterpret_cast(imageFile.buffer), - imageFile.size, - imageFile.format - ); + try { + std::unique_ptr texture = + ghoul::io::TextureReader::ref().loadTexture( + reinterpret_cast(imageFile.buffer), + imageFile.size, + imageFile.format + ); - if (texture) { - // Images don't need to start on 4-byte boundaries, for example if the - // image is only RGB - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture) { + // Images don't need to start on 4-byte boundaries, for example if the + // image is only RGB + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); - texture->purgeFromRAM(); + texture->uploadTexture(); + texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + texture->purgeFromRAM(); - _texture = std::move(texture); - _objectSize = _texture->dimensions(); + _texture = std::move(texture); + _objectSize = _texture->dimensions(); + _textureIsDirty = false; + } + } + catch (const ghoul::io::TextureReader::InvalidLoadException& e) { _textureIsDirty = false; + LERRORC(e.component, e.message); } } } From 09e0a55efb92fb08b93ec4f14d53deb1f62ff72d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Oct 2020 14:00:48 +0200 Subject: [PATCH 22/29] Delete Jenkins workspace after each run to save storage space --- Jenkinsfile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 545a72709b..53b9c5ab90 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -95,7 +95,8 @@ parallel tools: { tool: cppCheck() ) } - } + cleanWs() + } // node('tools') }, linux_gcc: { node('linux' && 'gcc') { @@ -119,6 +120,7 @@ linux_gcc: { stage('linux-gcc/test') { // testHelper.runUnitTests('build/OpenSpaceTest'); } + cleanWs() } // node('linux') }, linux_clang: { @@ -143,6 +145,7 @@ linux_clang: { stage('linux-clang/test') { // testHelper.runUnitTests('build/OpenSpaceTest'); } + cleanWs() } // node('linux') }, windows: { @@ -164,7 +167,8 @@ windows: { // testHelper.runUnitTests('bin\\Debug\\OpenSpaceTest') } } // node('windows') - } + cleanWs() + } // node('windows') }, macos: { node('macos') { @@ -182,5 +186,6 @@ macos: { // Currently, the unit tests are crashing on OS X // testHelper.runUnitTests('build/Debug/OpenSpaceTest') } - } // node('osx') + cleanWs() + } // node('macos') } From 811a84df0f16d2201f68f9ff19e28e4131b34291 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Oct 2020 17:48:16 +0200 Subject: [PATCH 23/29] Fix issue where Wormhole server's script messages could not be decoded Fix issue where dashboard item for parallel peer would not report line number correctly Closes #1011 --- apps/Wormhole/main.cpp | 57 +++++------ include/openspace/network/messagestructures.h | 26 ++++- include/openspace/network/parallelserver.h | 4 - .../dashboarditemparallelconnection.cpp | 6 +- src/network/parallelserver.cpp | 95 +++++++++---------- 5 files changed, 102 insertions(+), 86 deletions(-) diff --git a/apps/Wormhole/main.cpp b/apps/Wormhole/main.cpp index 12b3764abb..487244aef8 100644 --- a/apps/Wormhole/main.cpp +++ b/apps/Wormhole/main.cpp @@ -44,42 +44,33 @@ int main(int argc, char** argv) { CommandlineParser::AllowUnknownCommands::Yes ); - std::stringstream defaultPassword; - defaultPassword << std::hex << std::setfill('0') << std::setw(6) << - (std::hash{}( - std::chrono::system_clock::now().time_since_epoch().count() - ) % 0xffffff); + struct { + std::string port; + std::string password; + std::string changeHostPassword; + } settings; - std::stringstream defaultChangeHostPassword; - defaultChangeHostPassword << std::hex << std::setfill('0') << std::setw(6) << - (std::hash{}( - std::chrono::system_clock::now().time_since_epoch().count() + 1 - ) % 0xffffff); - - std::string portString; commandlineParser.addCommand( std::make_unique>( - portString, + settings.port, "--port", "-p", "Sets the port to listen on" ) ); - std::string password; commandlineParser.addCommand( std::make_unique>( - password, + settings.password, "--password", "-l", "Sets the password to use" ) ); - std::string changeHostPassword; commandlineParser.addCommand( std::make_unique>( - changeHostPassword, + settings.changeHostPassword, "--hostpassword", "-h", "Sets the host password to use" @@ -89,29 +80,41 @@ int main(int argc, char** argv) { commandlineParser.setCommandLine(arguments); commandlineParser.execute(); - if (password.empty()) { - password = defaultPassword.str(); + if (settings.password.empty()) { + std::stringstream defaultPassword; + defaultPassword << std::hex << std::setfill('0') << std::setw(6) << + (std::hash{}( + std::chrono::system_clock::now().time_since_epoch().count() + ) % 0xffffff); + + settings.password = defaultPassword.str(); } - if (changeHostPassword.empty()) { - changeHostPassword = defaultChangeHostPassword.str(); + if (settings.changeHostPassword.empty()) { + std::stringstream defaultChangeHostPassword; + defaultChangeHostPassword << std::hex << std::setfill('0') << std::setw(6) << + (std::hash{}( + std::chrono::system_clock::now().time_since_epoch().count() + 1 + ) % 0xffffff); + + settings.changeHostPassword = defaultChangeHostPassword.str(); } - LINFO(fmt::format("Connection password: {}", password)); - LINFO(fmt::format("Host password: {}", changeHostPassword)); + LINFO(fmt::format("Connection password: {}", settings.password)); + LINFO(fmt::format("Host password: {}", settings.changeHostPassword)); int port = 25001; - if (!portString.empty()) { + if (!settings.port.empty()) { try { - port = std::stoi(portString); + port = std::stoi(settings.port); } catch (const std::invalid_argument&) { - LERROR(fmt::format("Invalid port: {}", portString)); + LERROR(fmt::format("Invalid port: {}", settings.port)); } } ParallelServer server; - server.start(port, password, changeHostPassword); + server.start(port, settings.password, settings.changeHostPassword); server.setDefaultHostAddress("127.0.0.1"); LINFO(fmt::format("Server listening to port {}", port)); diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index ec27c27dd1..bea328662d 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -26,6 +26,8 @@ #define __OPENSPACE_CORE___MESSAGESTRUCTURES___H__ #include +#include +#include #include #include #include @@ -373,17 +375,31 @@ struct ScriptMessage { double _timestamp = 0.0; void serialize(std::vector& buffer) const { - size_t strLen = _script.size(); - size_t writeSize_bytes = sizeof(size_t); + uint32_t strLen = static_cast(_script.size()); - unsigned char const *p = reinterpret_cast(&strLen); - buffer.insert(buffer.end(), p, p + writeSize_bytes); + const char* p = reinterpret_cast(&strLen); + buffer.insert(buffer.end(), p, p + sizeof(uint32_t)); buffer.insert(buffer.end(), _script.begin(), _script.end()); }; void deserialize(const std::vector& buffer) { - _script.assign(buffer.begin(), buffer.end()); + const char* p = buffer.data(); + const uint32_t len = *reinterpret_cast(p); + + if (buffer.size() != (sizeof(uint32_t) + len)) { + LERRORC( + "ParallelPeer", + fmt::format( + "Received buffer with wrong size. Expected {} got {}", + len, buffer.size() + ) + ); + return; + } + + // We can skip over the first uint32_t that encoded the length + _script.assign(buffer.begin() + sizeof(uint32_t), buffer.end()); }; void write(std::ostream* out) const { diff --git a/include/openspace/network/parallelserver.h b/include/openspace/network/parallelserver.h index 18ce60e573..684ac62f2a 100644 --- a/include/openspace/network/parallelserver.h +++ b/include/openspace/network/parallelserver.h @@ -50,9 +50,6 @@ public: private: struct Peer { - //Peer(size_t id_, std::string name_, ParallelConnection parallelConnection_, - //ParallelConnection::Status status_, std::thread ) - size_t id; std::string name; ParallelConnection parallelConnection; @@ -87,7 +84,6 @@ private: void handleData(const Peer& peer, std::vector data); void handleHostshipRequest(std::shared_ptr peer, std::vector message); void handleHostshipResignation(Peer& peer); - void handleDisconnection(std::shared_ptr peer); void handleNewPeers(); void eventLoop(); diff --git a/modules/base/dashboard/dashboarditemparallelconnection.cpp b/modules/base/dashboard/dashboarditemparallelconnection.cpp index a7858f74b7..be39c9bac4 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.cpp +++ b/modules/base/dashboard/dashboarditemparallelconnection.cpp @@ -121,6 +121,8 @@ void DashboardItemParallelConnection::render(glm::vec2& penPosition) { const size_t nConnections = global::parallelPeer.nConnections(); const std::string& hostName = global::parallelPeer.hostName(); + int nLines = 1; + std::string connectionInfo; int nClients = static_cast(nConnections); if (status == ParallelConnection::Status::Host) { @@ -158,11 +160,13 @@ void DashboardItemParallelConnection::render(glm::vec2& penPosition) { else if (nClients == 1) { connectionInfo += "You are the only client"; } + + nLines = 2; } if (!connectionInfo.empty()) { RenderFont(*_font, penPosition, connectionInfo); - penPosition.y -= _font->height(); + penPosition.y -= _font->height() * nLines; } } diff --git a/src/network/parallelserver.cpp b/src/network/parallelserver.cpp index 499aa642f8..a52caeb410 100644 --- a/src/network/parallelserver.cpp +++ b/src/network/parallelserver.cpp @@ -50,12 +50,12 @@ void ParallelServer::start(int port, const std::string& password, } void ParallelServer::setDefaultHostAddress(std::string defaultHostAddress) { - std::lock_guard lock(_hostInfoMutex); + std::lock_guard lock(_hostInfoMutex); _defaultHostAddress = std::move(defaultHostAddress); } std::string ParallelServer::defaultHostAddress() const { - std::lock_guard lock(_hostInfoMutex); + std::lock_guard lock(_hostInfoMutex); return _defaultHostAddress; } @@ -66,29 +66,26 @@ void ParallelServer::stop() { void ParallelServer::handleNewPeers() { while (!_shouldStop) { - std::unique_ptr socket = - _socketServer.awaitPendingTcpSocket(); + std::unique_ptr s = _socketServer.awaitPendingTcpSocket(); - socket->startStreams(); + s->startStreams(); const size_t id = _nextConnectionId++; std::shared_ptr p = std::make_shared(Peer{ id, "", - ParallelConnection(std::move(socket)), + ParallelConnection(std::move(s)), ParallelConnection::Status::Connecting, std::thread() }); auto it = _peers.emplace(p->id, p); - it.first->second->thread = std::thread([this, id]() { - handlePeer(id); - }); + it.first->second->thread = std::thread([this, id]() { handlePeer(id); }); } } std::shared_ptr ParallelServer::peer(size_t id) { - std::lock_guard lock(_peerListMutex); - auto it = _peers.find(id); + std::lock_guard lock(_peerListMutex); + const auto it = _peers.find(id); if (it == _peers.end()) { return nullptr; } @@ -107,15 +104,19 @@ void ParallelServer::handlePeer(size_t id) { } try { ParallelConnection::Message m = p->parallelConnection.receiveMessage(); - _incomingMessages.push({id, m}); - } catch (const ParallelConnection::ConnectionLostError&) { + PeerMessage msg; + msg.peerId = id; + msg.message = m; + _incomingMessages.push(msg); + } + catch (const ParallelConnection::ConnectionLostError&) { LERROR(fmt::format("Connection lost to {}", p->id)); - _incomingMessages.push({ - id, - ParallelConnection::Message( - ParallelConnection::MessageType::Disconnection, std::vector() - ) - }); + PeerMessage msg; + msg.peerId = id; + msg.message = ParallelConnection::Message( + ParallelConnection::MessageType::Disconnection, std::vector() + ); + _incomingMessages.push(msg); return; } } @@ -137,9 +138,9 @@ void ParallelServer::handlePeerMessage(PeerMessage peerMessage) { std::shared_ptr& peer = it->second; - const ParallelConnection::MessageType messageType = peerMessage.message.type; + const ParallelConnection::MessageType type = peerMessage.message.type; std::vector& data = peerMessage.message.content; - switch (messageType) { + switch (type) { case ParallelConnection::MessageType::Authentication: handleAuthentication(peer, std::move(data)); break; @@ -156,9 +157,7 @@ void ParallelServer::handlePeerMessage(PeerMessage peerMessage) { disconnect(*peer); break; default: - LERROR(fmt::format( - "Unsupported message type: {}", static_cast(messageType) - )); + LERROR(fmt::format("Unsupported message type: {}", static_cast(type))); break; } } @@ -192,19 +191,19 @@ void ParallelServer::handleAuthentication(std::shared_ptr peer, setName(*peer, name); - LINFO(fmt::format("Connection established with {} \"{}\"", peer->id, name)); + LINFO(fmt::format("Connection established with {} ('{}')", peer->id, name)); std::string defaultHostAddress; { - std::lock_guard _hostMutex(_hostInfoMutex); + std::lock_guard _hostMutex(_hostInfoMutex); defaultHostAddress = _defaultHostAddress; } if (_hostPeerId == 0 && peer->parallelConnection.socket()->address() == defaultHostAddress) { - // Directly promote the conenction to host (initialize) - // if there is no host, and ip matches default host ip. - LINFO(fmt::format("Connection {} directly promoted to host.", peer->id)); + // Directly promote the conenction to host (initialize) if there is no host, and + // ip matches default host ip. + LINFO(fmt::format("Connection {} directly promoted to host", peer->id)); assignHost(peer); for (std::pair>& it : _peers) { // sendConnectionStatus(it->second) ? @@ -221,11 +220,10 @@ void ParallelServer::handleAuthentication(std::shared_ptr peer, void ParallelServer::handleData(const Peer& peer, std::vector data) { if (peer.id != _hostPeerId) { LINFO(fmt::format( - "Connection {} tried to send data without being the host. Ignoring", peer.id + "Ignoring connection {} trying to send data without being host", peer.id )); } sendMessageToClients(ParallelConnection::MessageType::Data, data); - } void ParallelServer::handleHostshipRequest(std::shared_ptr peer, @@ -233,43 +231,43 @@ void ParallelServer::handleHostshipRequest(std::shared_ptr peer, { std::stringstream input(std::string(message.begin(), message.end())); - LINFO(fmt::format("Connection {} requested hostship.", peer->id)); + LINFO(fmt::format("Connection {} requested hostship", peer->id)); uint64_t passwordHash = 0; input.read(reinterpret_cast(&passwordHash), sizeof(uint64_t)); if (passwordHash != _changeHostPasswordHash) { - LERROR(fmt::format("Connection {} provided incorrect host password.", peer->id)); + LERROR(fmt::format("Connection {} provided incorrect host password", peer->id)); return; } size_t oldHostPeerId = 0; { - std::lock_guard lock(_hostInfoMutex); + std::lock_guard lock(_hostInfoMutex); oldHostPeerId = _hostPeerId; } if (oldHostPeerId == peer->id) { - LINFO(fmt::format("Connection {} is already the host.", peer->id)); + LINFO(fmt::format("Connection {} is already the host", peer->id)); return; } assignHost(peer); - LINFO(fmt::format("Switched host from {} to {}.", oldHostPeerId, peer->id)); + LINFO(fmt::format("Switched host from {} to {}", oldHostPeerId, peer->id)); } void ParallelServer::handleHostshipResignation(Peer& peer) { - LINFO(fmt::format("Connection {} wants to resign its hostship.", peer.id)); + LINFO(fmt::format("Connection {} wants to resign its hostship", peer.id)); size_t oldHostPeerId = 0; { - std::lock_guard lock(_hostInfoMutex); + std::lock_guard lock(_hostInfoMutex); oldHostPeerId = _hostPeerId; } setToClient(peer); - LINFO(fmt::format("Connection {} resigned as host.", peer.id)); + LINFO(fmt::format("Connection {} resigned as host", peer.id)); } bool ParallelServer::isConnected(const Peer& peer) const { @@ -277,8 +275,7 @@ bool ParallelServer::isConnected(const Peer& peer) const { peer.status != ParallelConnection::Status::Disconnected; } -void ParallelServer::sendMessage(Peer& peer, - ParallelConnection::MessageType messageType, +void ParallelServer::sendMessage(Peer& peer, ParallelConnection::MessageType messageType, const std::vector& message) { peer.parallelConnection.sendMessage({ messageType, message }); @@ -311,12 +308,12 @@ void ParallelServer::disconnect(Peer& peer) { size_t hostPeerId = 0; { - std::lock_guard lock(_hostInfoMutex); + std::lock_guard lock(_hostInfoMutex); hostPeerId = _hostPeerId; } - // Make sure any disconnecting host is first degraded to client, - // in order to notify other clients about host disconnection. + // Make sure any disconnecting host is first degraded to client, in order to notify + // other clients about host disconnection. if (peer.id == hostPeerId) { setToClient(peer); } @@ -327,7 +324,7 @@ void ParallelServer::disconnect(Peer& peer) { } void ParallelServer::setName(Peer& peer, std::string name) { - peer.name = name; + peer.name = std::move(name); size_t hostPeerId = 0; { std::lock_guard lock(_hostInfoMutex); @@ -338,7 +335,7 @@ void ParallelServer::setName(Peer& peer, std::string name) { if (peer.id == hostPeerId) { { std::lock_guard lock(_hostInfoMutex); - _hostName = name; + _hostName = peer.name; } for (std::pair>& it : _peers) { @@ -374,7 +371,7 @@ void ParallelServer::setToClient(Peer& peer) { { std::lock_guard lock(_hostInfoMutex); _hostPeerId = 0; - _hostName = ""; + _hostName.clear(); } // If host becomes client, make all clients hostless. @@ -421,8 +418,8 @@ void ParallelServer::sendConnectionStatus(Peer& peer) { data.insert( data.end(), - reinterpret_cast(_hostName.data()), - reinterpret_cast(_hostName.data() + outHostNameSize) + _hostName.data(), + _hostName.data() + outHostNameSize ); sendMessage(peer, ParallelConnection::MessageType::ConnectionStatus, data); From 8a890534cf954109301a58e66d50c063dc560bb5 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Oct 2020 18:34:50 +0200 Subject: [PATCH 24/29] Use the correct buffer size in the ScreenLog (closes #1330) --- src/rendering/renderengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 2ad38678f1..5c4dec9343 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -1447,7 +1447,7 @@ void RenderEngine::renderScreenLog() { const glm::vec4 white(0.9f, 0.9f, 0.9f, alpha); - std::array buf; + std::array buf; { std::fill(buf.begin(), buf.end(), char(0)); char* end = fmt::format_to( From 41ce15a6f9dcbbaf9694dcfa3a6f9d33e5d89fce Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Oct 2020 18:59:35 +0200 Subject: [PATCH 25/29] Increase the number of messages and length of messages --- src/rendering/renderengine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 5c4dec9343..6c2c1a5965 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -1409,9 +1409,9 @@ void RenderEngine::renderScreenLog() { _log->removeExpiredEntries(); - constexpr const int MaxNumberMessages = 10; + constexpr const int MaxNumberMessages = 20; constexpr const int CategoryLength = 30; - constexpr const int MessageLength = 140; + constexpr const int MessageLength = 280; constexpr const std::chrono::seconds FadeTime(5); const std::vector& entries = _log->entries(); @@ -1493,7 +1493,7 @@ void RenderEngine::renderScreenLog() { RenderFont( *_fontLog, glm::vec2( - 10 + 30 * _fontLog->pointSize(), + 10 + (30 + 3) * _fontLog->pointSize(), _fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset ), levelText, @@ -1504,7 +1504,7 @@ void RenderEngine::renderScreenLog() { RenderFont( *_fontLog, glm::vec2( - 10 + 41 * _fontLog->pointSize(), + 10 + 44 * _fontLog->pointSize(), _fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset ), message, From 92838990b2f2beaf4add77001a6f779c0dfcc41c Mon Sep 17 00:00:00 2001 From: Micah Date: Mon, 19 Oct 2020 15:08:33 -0400 Subject: [PATCH 26/29] fix for spice manager with no exceptions; fix for nh profile camera --- data/profiles/newhorizons.profile | 18 ++++++++++-------- src/util/spicemanager.cpp | 3 +++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/data/profiles/newhorizons.profile b/data/profiles/newhorizons.profile index 0bccbac92b..abe410ecc9 100644 --- a/data/profiles/newhorizons.profile +++ b/data/profiles/newhorizons.profile @@ -8,18 +8,20 @@ "camera": { "aim": "", "anchor": "NewHorizons", - "frame": "", + "frame": "Root", + "pitch": 0.036092, "position": { - "x": -65.72656, - "y": -72.39404, - "z": -21.1189 + "x": -111.9326, + "y": -35.20605, + "z": 33.42737 }, "type": "setNavigationState", "up": { - "x": 0.102164, - "y": -0.362945, - "z": 0.926193 - } + "x": -0.188963, + "y": 0.921904, + "z": 0.338209 + }, + "yaw": 0.0563239 }, "delta_times": [ 1.0, diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index ab1bfb678a..51ed9fdc47 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -194,6 +194,9 @@ void throwSpiceError(const std::string& errorMessage) { reset_c(); throw openspace::SpiceManager::SpiceException(errorMessage + ": " + buffer); } + else { + reset_c(); + } } SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) { From 95393ad6c2b8207f2f37859d5d8b9072127c1893 Mon Sep 17 00:00:00 2001 From: Micah Date: Mon, 19 Oct 2020 15:09:32 -0400 Subject: [PATCH 27/29] resetting color map for du sdss --- data/assets/scene/digitaluniverse/sdss.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/scene/digitaluniverse/sdss.asset b/data/assets/scene/digitaluniverse/sdss.asset index 765290c676..aea7142560 100644 --- a/data/assets/scene/digitaluniverse/sdss.asset +++ b/data/assets/scene/digitaluniverse/sdss.asset @@ -27,7 +27,7 @@ local object = { File = speck .. "/SDSSgals.speck", ColorMap = speck .. "/SDSSgals.cmap", ColorOption = { "redshift", "proximity" }, - ColorRange = { { 0.001, 2.0 }, { 1.0, 50.0 } }, + ColorRange = { { 0.0, 0.075 }, { 1.0, 50.0 } }, Texture = textures .. "/point3A.png", Unit = "Mpc", -- Fade in value in the same unit as "Unit" From 5fc0a151c3e7a03ebe7f9223ae1fa455e9d6e184 Mon Sep 17 00:00:00 2001 From: Micah Date: Mon, 19 Oct 2020 16:00:12 -0400 Subject: [PATCH 28/29] updating webgui hash --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index f6b2a418b9..f72e690643 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "6b5ac33a77fff6f46088c1fffdaf04d59ec5bb5f" +local frontendHash = "5d9b8d52e43260c71f641e73e44e4c90bc9f5d6a" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From eb6e6aad5f10b1c7baed62505db6050be8f88d5d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Oct 2020 23:15:50 +0200 Subject: [PATCH 29/29] Feature/launcher cleanup (#1350) General cleanup of the launcher --- apps/OpenSpace/ext/launcher/CMakeLists.txt | 2 + .../ext/launcher/include/filesystemaccess.h | 2 +- .../ext/launcher/include/launcherwindow.h | 52 +-- .../include/profile/additionalscriptsdialog.h | 2 + .../launcher/include/profile/assetsdialog.h | 18 +- .../launcher/include/profile/assettreemodel.h | 22 +- .../launcher/include/profile/cameradialog.h | 1 + .../include/profile/deltatimesdialog.h | 10 +- .../include/profile/keybindingsdialog.h | 10 +- .../ext/launcher/include/profile/line.h | 35 ++ .../include/profile/marknodesdialog.h | 8 +- .../ext/launcher/include/profile/metadialog.h | 9 +- .../launcher/include/profile/modulesdialog.h | 15 +- .../launcher/include/profile/profileedit.h | 57 +-- .../include/profile/propertiesdialog.h | 12 +- .../ext/launcher/include/profile/timedialog.h | 10 +- .../ext/launcher/src/filesystemaccess.cpp | 4 +- .../ext/launcher/src/launcherwindow.cpp | 424 +++++++++--------- .../src/profile/additionalscriptsdialog.cpp | 35 +- .../ext/launcher/src/profile/assetsdialog.cpp | 40 +- .../launcher/src/profile/assettreeitem.cpp | 12 +- .../launcher/src/profile/assettreemodel.cpp | 20 +- .../ext/launcher/src/profile/cameradialog.cpp | 90 ++-- .../launcher/src/profile/deltatimesdialog.cpp | 53 +-- .../src/profile/keybindingsdialog.cpp | 112 ++--- .../ext/launcher/src/profile/line.cpp | 30 ++ .../launcher/src/profile/marknodesdialog.cpp | 11 +- .../ext/launcher/src/profile/metadialog.cpp | 73 +-- .../launcher/src/profile/modulesdialog.cpp | 71 ++- .../ext/launcher/src/profile/profileedit.cpp | 283 ++++++------ .../launcher/src/profile/propertiesdialog.cpp | 36 +- .../ext/launcher/src/profile/timedialog.cpp | 56 ++- apps/OpenSpace/main.cpp | 125 +++--- 33 files changed, 881 insertions(+), 859 deletions(-) create mode 100644 apps/OpenSpace/ext/launcher/include/profile/line.h create mode 100644 apps/OpenSpace/ext/launcher/src/profile/line.cpp diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index 14ae92bd01..573d872042 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -34,6 +34,7 @@ set(HEADER_FILES include/profile/cameradialog.h include/profile/deltatimesdialog.h include/profile/keybindingsdialog.h + include/profile/line.h include/profile/marknodesdialog.h include/profile/metadialog.h include/profile/modulesdialog.h @@ -52,6 +53,7 @@ set(SOURCE_FILES src/profile/cameradialog.cpp src/profile/deltatimesdialog.cpp src/profile/keybindingsdialog.cpp + src/profile/line.cpp src/profile/marknodesdialog.cpp src/profile/metadialog.cpp src/profile/modulesdialog.cpp diff --git a/apps/OpenSpace/ext/launcher/include/filesystemaccess.h b/apps/OpenSpace/ext/launcher/include/filesystemaccess.h index 35e0dcdde9..4538e33835 100644 --- a/apps/OpenSpace/ext/launcher/include/filesystemaccess.h +++ b/apps/OpenSpace/ext/launcher/include/filesystemaccess.h @@ -54,7 +54,7 @@ public: * * \param dir The directory from which to start the search from */ - std::string useQtFileSystemModelToTraverseDir(QString dir); + std::string useQtFileSystemModelToTraverseDir(std::string dir); private: void parseChildDirElements(QFileInfo item, std::string space, int level, diff --git a/apps/OpenSpace/ext/launcher/include/launcherwindow.h b/apps/OpenSpace/ext/launcher/include/launcherwindow.h index f85248851d..6b7283ea23 100644 --- a/apps/OpenSpace/ext/launcher/include/launcherwindow.h +++ b/apps/OpenSpace/ext/launcher/include/launcherwindow.h @@ -27,20 +27,20 @@ #include -#include -#include "profile/profileedit.h" -#include "filesystemaccess.h" #include -#include #include +namespace openspace::configuration { struct Configuration; } + +class QComboBox; +class QLabel; + class LauncherWindow : public QMainWindow { Q_OBJECT public: /** * Constructor for LauncherWindow class * - * \param basePath The base OpenSpace installation path * \param profileEnabled true if profile selection combo box will be enabled * \param globalConfig reference to global configuration for OpenSpace settings * \param sgctConfigEnabled true if window selection combo box will be enabled @@ -49,9 +49,9 @@ public: * \param parentItem The parent that contains this (and possibly other) children * in the tree structure. */ - LauncherWindow(std::string basePath, bool profileEnabled, - openspace::configuration::Configuration& globalConfig, bool sgctConfigEnabled, - std::string sgctConfigName, QWidget* parent); + LauncherWindow(bool profileEnabled, + const openspace::configuration::Configuration& globalConfig, + bool sgctConfigEnabled, std::string sgctConfigName, QWidget* parent); /** * Returns bool for whether "start OpenSpace" was chosen when this window closed. @@ -61,14 +61,6 @@ public: */ bool wasLaunchSelected() const; - /** - * Returns true if both the profile and sgct window configuration were specified - * at the command line (and so the launcher will not run). - * - * \return true if both profile and sgct window config were specified at CLI - */ - bool isFullyConfiguredFromCliArgs() const; - /** * Returns the selected profile name when launcher window closed * @@ -85,29 +77,23 @@ public: */ std::string selectedWindowConfig() const; -public slots: - void openWindowEdit(); - void openWindowNew(); - void startOpenSpace(); - private: + QWidget* createCentralWidget(); + void setBackgroundImage(const std::string& syncPath); + + void openProfileEditor(const std::string& profile); + void populateProfilesList(std::string preset); void populateWindowConfigsList(std::string preset); - std::optional loadProfileFromFile(std::string filename); - void saveProfileToFile(const std::string& path, const openspace::Profile& p); - FileSystemAccess _fileAccessProfiles; - FileSystemAccess _fileAccessWinConfigs; - FileSystemAccess _filesystemAccess; - std::string _reportAssetsInFilesystem; - openspace::configuration::Configuration& _globalConfig; - QString _basePath; - bool _launch = false; - bool _fullyConfiguredViaCliArgs = false; - bool _profileChangeAllowed = true; - bool _sgctConfigChangeAllowed = true; + const std::string _assetPath; + const std::string _configPath; + const std::string _profilePath; + const std::vector& _readOnlyProfiles; + bool _shouldLaunch = false; QComboBox* _profileBox = nullptr; QComboBox* _windowConfigBox = nullptr; + QLabel* _backgroundImage = nullptr; }; #endif // __OPENSPACE_UI_LAUNCHER___LAUNCHERWINDOW___H__ diff --git a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h index afc48b068d..c8288565bc 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h @@ -47,6 +47,8 @@ private slots: void parseScript(); private: + void createWidgets(); + openspace::Profile& _profile; QTextEdit* _textScripts = nullptr; }; diff --git a/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h index 1090f5ac45..4bb35e62f2 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h @@ -28,7 +28,6 @@ #include #include "assettreemodel.h" -#include "filesystemaccess.h" namespace openspace { class Profile; } @@ -43,14 +42,18 @@ public: * * \param profile The #openspace::Profile object containing all data of the * new or imported profile. - * \param reportAssets A full summary of all assets and their respective paths in - * a text format unique to this application (more details are - * in class #assetTreeModel) + * \param assetBasePath The path to the folder in which all of the assets are living * \param parent Pointer to parent Qt widget */ - AssetsDialog(openspace::Profile& profile, const std::string reportAssets, + AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath, QWidget* parent); +private slots: + void parseSelections(); + void selected(const QModelIndex&); + +private: + void createWidgets(); /** * Creates a text summary of all assets and their paths * @@ -58,11 +61,6 @@ public: */ QString createTextSummary(); -private slots: - void parseSelections(); - void selected(const QModelIndex&); - -private: openspace::Profile& _profile; AssetTreeModel _assetTreeModel; QTreeView* _assetTree = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h b/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h index 42fad3ab8c..1426e3ff39 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h +++ b/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h @@ -32,7 +32,7 @@ #include class AssetTreeModel : public QAbstractItemModel { - Q_OBJECT +Q_OBJECT public: AssetTreeModel(QObject* parent = nullptr); @@ -145,23 +145,11 @@ public: std::vector& outputItems); /** - * Imports asset tree data for this model. The import text format is unique to - * this asset tree structure. - * Each line starts with an character (0, 1, or x) to represent its checked status - * or if it doesn't exist in the current filesystem. - * This is followed by the name of either an asset or directory, with a space for - * each level of sub-directory. Example: - * 0Base - * 0 Directory - * 0 Asset1 - * 1 Asset2 - * 0 Asset3 - * 1Asset4 - * This format is used internally to translate from code that reads the filesystem - * - * \param contents asset recursive listing of directory in format described above + * Imports asset tree data for this model by recursively traversing the folder + * structure. + * \param assetBasePath The base path where to find all assets */ - void importModelData(const std::string& contents); + void importModelData(const std::string& assetBasePath); /** * Returns bool for if item is checked/selected diff --git a/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h b/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h index 8bb6994023..34b497b34a 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h @@ -50,6 +50,7 @@ private slots: void tabSelect(int); private: + void createWidgets(); QWidget* createNavStateWidget(); QWidget* createGeoWidget(); diff --git a/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h index a98b433dcd..3d192af852 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h @@ -41,9 +41,9 @@ public: /** * Constructor for deltaTimes class * - * \param imported The #openspace::Profile object containing all data of the + * \param profile The #openspace::Profile object containing all data of the * new or imported profile. - * \param parent Pointer to parent Qt widget (optional) + * \param parent Pointer to parent Qt widget */ DeltaTimesDialog(openspace::Profile& profile, QWidget* parent); @@ -61,10 +61,10 @@ public: * * \param evt #QKeyEvent object for the key press event */ - void keyPressEvent(QKeyEvent *evt); + void keyPressEvent(QKeyEvent* evt); -public slots: +private slots: void listItemSelected(); void valueChanged(const QString& text); void saveDeltaTimeValue(); @@ -74,6 +74,8 @@ public slots: void parseSelections(); private: + void createWidgets(); + /** * Called to transition to editing a particular dt value (gui settings) * diff --git a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h index a9a5033233..2bc01477ca 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h @@ -45,7 +45,7 @@ public: /** * Constructor for keybindings class * - * \param imported The #openspace::Profile object containing all data of the + * \param profile The #openspace::Profile object containing all data of the * new or imported profile. * \param parent Pointer to parent Qt widget (optional) */ @@ -56,9 +56,9 @@ public: * * \param evt #QKeyEvent object for the key press event */ - void keyPressEvent(QKeyEvent *evt); + void keyPressEvent(QKeyEvent* evt); -public slots: +private slots: void listItemSelected(); void listItemAdded(); void listItemRemove(); @@ -69,13 +69,11 @@ public slots: void keySelected(int index); private: + void createWidgets(); void transitionFromEditMode(); void editBoxDisabled(bool disabled); int indexInKeyMapping(std::vector& mapVector, int keyInt); bool areRequiredFormsFilled(); - std::string truncateString(std::string& s); - void replaceChars(std::string& src, const std::string& from, - const std::string& to); bool isLineEmpty(int index); openspace::Profile& _profile; diff --git a/apps/OpenSpace/ext/launcher/include/profile/line.h b/apps/OpenSpace/ext/launcher/include/profile/line.h new file mode 100644 index 0000000000..ebe27607dc --- /dev/null +++ b/apps/OpenSpace/ext/launcher/include/profile/line.h @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_UI_LAUNCHER___LINE___H__ +#define __OPENSPACE_UI_LAUNCHER___LINE___H__ + +#include + +class Line : public QFrame { +public: + Line(); +}; + +#endif // __OPENSPACE_UI_LAUNCHER___LINE___H__ diff --git a/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h index 5c96392bc7..eae3617543 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h @@ -40,8 +40,8 @@ public: /** * Constructor for markNodes class * - * \param imported The #openspace::Profile object containing all data of the - * new or imported profile. + * \param profile The #openspace::Profile object containing all data of the + * new or imported profile. * \param parent Pointer to parent Qt widget */ MarkNodesDialog(openspace::Profile& profile, QWidget* parent); @@ -53,13 +53,15 @@ public: */ void keyPressEvent(QKeyEvent* evt); -public slots: +private slots: void listItemSelected(); void listItemAdded(); void listItemRemove(); void parseSelections(); private: + void createWidgets(); + std::vector _markedNodesListItems; openspace::Profile& _profile; std::vector _data; diff --git a/apps/OpenSpace/ext/launcher/include/profile/metadialog.h b/apps/OpenSpace/ext/launcher/include/profile/metadialog.h index 952cccbb3f..f3a79acdfd 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/metadialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/metadialog.h @@ -35,20 +35,21 @@ class QTextEdit; class MetaDialog : public QDialog { Q_OBJECT public: - /** * Constructor for meta class * - * \param imported The #openspace::Profile object containing all data of the - * new or imported profile. + * \param profile The #openspace::Profile object containing all data of the + * new or imported profile. * \param parent Pointer to parent Qt widget */ MetaDialog(openspace::Profile& profile, QWidget* parent); -public slots: +private slots: void save(); private: + void createWidgets(); + openspace::Profile& _profile; QLineEdit* _nameEdit = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h index cf790ae8bf..c2c419528f 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h @@ -41,20 +41,20 @@ public: /** * Constructor for osmodules class * - * \param imported The #openspace::Profile object containing all data of the - * new or imported profile. + * \param profile The #openspace::Profile object containing all data of the + * new or imported profile. * \param parent Pointer to parent Qt widget */ - ModulesDialog(openspace::Profile& profiles, QWidget* parent); + ModulesDialog(openspace::Profile& profile, QWidget* parent); /** * Handles keypress while the Qt dialog window is open * * \param evt #QKeyEvent object for the key press event */ - void keyPressEvent(QKeyEvent *evt); + void keyPressEvent(QKeyEvent* evt); -public slots: +private slots: void listItemSelected(); void listItemAdded(); void listItemRemove(); @@ -64,15 +64,16 @@ public slots: void parseSelections(); private: + void createWidgets(); + QString createOneLineSummary(openspace::Profile::Module m); void transitionFromEditMode(); void editBoxDisabled(bool disabled); - bool isLineEmpty(int index); + bool isLineEmpty(int index) const; openspace::Profile& _profile; std::vector _data; bool _editModeNewItem = false; - const openspace::Profile::Module kBlank = {"", "", ""}; QListWidget* _list = nullptr; QLabel* _moduleLabel = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/profileedit.h b/apps/OpenSpace/ext/launcher/include/profile/profileedit.h index d595cbd4c8..d8de4c4ab9 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/profileedit.h +++ b/apps/OpenSpace/ext/launcher/include/profile/profileedit.h @@ -26,18 +26,15 @@ #define __OPENSPACE_UI_LAUNCHER___PROFILEEDIT___H__ #include -#include -#include "profile/metadialog.h" -#include "profile/propertiesdialog.h" -#include "profile/modulesdialog.h" -#include "profile/keybindingsdialog.h" -#include "profile/assetsdialog.h" -#include "profile/timedialog.h" -#include "profile/additionalscriptsdialog.h" -#include "profile/deltatimesdialog.h" -#include "profile/cameradialog.h" -#include "profile/marknodesdialog.h" -#include +#include +#include + +namespace openspace { class Profile; } + +class QWidget; +class QLabel; +class QLineEdit; +class QTextEdit; class ProfileEdit : public QDialog { Q_OBJECT @@ -45,24 +42,18 @@ public: /** * Constructor for ProfileEdit class * - * \param imported The #openspace::Profile object containing all data of the - * new or imported profile. - * \param reportedAssets string list of assets reported by filesystemAccess class + * \param profile The #openspace::Profile object containing all data of the + * new or imported profile. + * \param profileName The name of the profile to create + * \param assetBasePath The path to the folder where the assets live + * \param profileName The path to the folder in which all profiles live * \param profilesReadOnly vector list of profile names that are read-only and must * not be overwritten - * \param parent Pointer to parent Qt widget (optional) + * \param parent Pointer to parent Qt widget */ - ProfileEdit(openspace::Profile& profile, const std::string reportedAssets, - std::vector& profilesReadOnly, QWidget* parent); - - /** - * Sets the profile name in top save/edit window. This can be changed by user in - * order to save to a different file. - * - * \param profileToSet name of the profile to set to - */ - void setProfileName(QString profileToSet); - + ProfileEdit(openspace::Profile& profile, const std::string& profileName, + std::string assetBasePath, std::string profileBasePath, + const std::vector& profilesReadOnly, QWidget* parent); /** * Gets the status of the save when the window is closed; was the file saved? @@ -86,7 +77,7 @@ public: */ void keyPressEvent(QKeyEvent* evt); -public slots: +private slots: void duplicateProfile(); void openMeta(); void openProperties(); @@ -102,16 +93,14 @@ public slots: void approved(); private: + void createWidgets(const std::string& profileName); void initSummaryTextForEachCategory(); - std::string summarizeAssets(); - std::string summarizeProperties(); - std::string summarizeKeybindings(); - bool isReadOnly(std::string profileToSave); openspace::Profile& _profile; - const std::string _reportedAssets; + const std::string _assetBasePath; + const std::string _profileBasePath; bool _saveSelected = false; - std::vector _readOnlyProfiles; + const std::vector& _readOnlyProfiles; QLineEdit* _profileEdit = nullptr; QLabel* _modulesLabel = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h index 0aab138fd3..ac13ed474e 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h @@ -42,9 +42,9 @@ public: /** * Constructor for properties class * - * \param imported The #openspace::Profile object containing all data of the - * new or imported profile. - * \param parent Pointer to parent Qt widget (optional) + * \param profile The #openspace::Profile object containing all data of the + * new or imported profile. + * \param parent Pointer to parent Qt widget */ PropertiesDialog(openspace::Profile& profile, QWidget* parent); @@ -53,9 +53,9 @@ public: * * \param evt #QKeyEvent object for the key press event */ - void keyPressEvent(QKeyEvent *evt); + void keyPressEvent(QKeyEvent* evt); -public slots: +private slots: void listItemSelected(); void listItemAdded(); void listItemRemove(); @@ -65,6 +65,8 @@ public slots: void parseSelections(); private: + void createWidgets(); + QString createOneLineSummary(openspace::Profile::Property p); void transitionFromEditMode(); void editBoxDisabled(bool disabled); diff --git a/apps/OpenSpace/ext/launcher/include/profile/timedialog.h b/apps/OpenSpace/ext/launcher/include/profile/timedialog.h index 9dd5bd222f..9a0a6c4421 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/timedialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/timedialog.h @@ -40,18 +40,20 @@ public: /** * Constructor for ostime class * - * \param imported The #openspace::Profile object containing all data of the - * new or imported profile. - * \param parent Pointer to parent Qt widget (optional) + * \param profile The #openspace::Profile object containing all data of the + * new or imported profile. + * \param parent Pointer to parent Qt widget */ TimeDialog(openspace::Profile& profile, QWidget* parent); -public slots: +private slots: void enableAccordingToType(int); void approved(); private: + void createWidgets(); void enableFormatForAbsolute(bool enableAbs); + openspace::Profile& _profile; openspace::Profile::Time _data; bool _initializedAsAbsolute = true; diff --git a/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp b/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp index bf5e760174..f0a98ce58d 100644 --- a/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp +++ b/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp @@ -33,8 +33,8 @@ FileSystemAccess::FileSystemAccess(std::string fileExtension, , _useCheckboxes(useCheckboxes) {} -std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(QString dir) { - _filesystemModel.setRootPath(dir); +std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(std::string dir) { + _filesystemModel.setRootPath(QString::fromStdString(dir)); QModelIndex index = _filesystemModel.index(_filesystemModel.rootPath()); QFileInfo fileInfo = _filesystemModel.fileInfo(index); std::vector dirsNested; diff --git a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp index c957289c09..6d1e775849 100644 --- a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp +++ b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp @@ -22,19 +22,22 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include #include "launcherwindow.h" -#include -#include -#include "filesystemaccess.h" + +#include "profile/profileedit.h" + #include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include #include +#include +#include +#include + +using namespace openspace; namespace { constexpr const int ScreenWidth = 480; @@ -68,29 +71,82 @@ namespace { LeftRuler, TopRuler + 380, SmallItemWidth, SmallItemHeight ); } // geometry + + std::optional loadProfileFromFile(QWidget* parent, std::string filename) { + std::ifstream inFile; + try { + inFile.open(filename, std::ifstream::in); + } + catch (const std::ifstream::failure& e) { + throw ghoul::RuntimeError(fmt::format( + "Exception opening {} profile for read: {}", filename, e.what() + )); + } + std::string content; + std::string line; + while (std::getline(inFile, line)) { + content += line; + } + try { + return Profile(content); + } + catch (const Profile::ParsingError& e) { + QMessageBox::critical( + parent, + "Exception", + QString::fromStdString(fmt::format( + "ParsingError exception in {}: {}, {}", + filename, e.component, e.message + )) + ); + return std::nullopt; + } + catch (const ghoul::RuntimeError& e) { + QMessageBox::critical( + parent, + "Exception", + QString::fromStdString(fmt::format( + "RuntimeError exception in {}, component {}: {}", + filename, e.component, e.message + )) + ); + return std::nullopt; + } + } + + void saveProfile(QWidget* parent, const std::string& path, const Profile& p) { + std::ofstream outFile; + try { + outFile.open(path, std::ofstream::out); + outFile << p.serialize(); + } + catch (const std::ofstream::failure& e) { + QMessageBox::critical( + parent, + "Exception", + QString::fromStdString(fmt::format( + "Error writing data to file: {} ({})", path, e.what() + )) + ); + } + } } // namespace using namespace openspace; -LauncherWindow::LauncherWindow(std::string basePath, bool profileEnabled, - configuration::Configuration& globalConfig, +LauncherWindow::LauncherWindow(bool profileEnabled, + const configuration::Configuration& globalConfig, bool sgctConfigEnabled, std::string sgctConfigName, QWidget* parent) : QMainWindow(parent) - , _fileAccessProfiles(".profile", { "./" }, true, false) - , _fileAccessWinConfigs(".xml", { "./" }, true, false) - , _filesystemAccess( - ".asset", { "scene", "global", "customization", "examples", "util" }, true, true - ) - , _basePath(QString::fromStdString(basePath)) - , _profileChangeAllowed(profileEnabled) - , _sgctConfigChangeAllowed(sgctConfigEnabled) - , _globalConfig(globalConfig) + , _assetPath(absPath(globalConfig.pathTokens.at("ASSETS")) + '/') + , _configPath(absPath(globalConfig.pathTokens.at("CONFIG")) + '/') + , _profilePath(absPath(globalConfig.pathTokens.at("PROFILES")) + '/') + , _readOnlyProfiles(globalConfig.readOnlyProfiles) { Q_INIT_RESOURCE(resources); qInstallMessageHandler( - // Now that the log is enabled and available, we can pipe all Qt messages to that [](QtMsgType type, const QMessageLogContext&, const QString& msg) { if (type == QtCriticalMsg || type == QtFatalMsg || type == QtSystemMsg) { std::cerr << msg.toStdString() << std::endl; @@ -109,11 +165,33 @@ LauncherWindow::LauncherWindow(std::string basePath, bool profileEnabled, setStyleSheet(styleSheet); } + setCentralWidget(createCentralWidget()); - QWidget* centralWidget = new QWidget(this); - QLabel* backgroundImage = new QLabel(centralWidget); - backgroundImage->setGeometry(geometry::BackgroundImage); + populateProfilesList(globalConfig.profile); + _profileBox->setEnabled(profileEnabled); + + populateWindowConfigsList(sgctConfigName); + _windowConfigBox->setEnabled(sgctConfigEnabled); + + + std::string p = absPath(globalConfig.pathTokens.at("SYNC") + "/http/launcher_images"); + if (std::filesystem::exists(p)) { + try { + setBackgroundImage(p); + } + catch (const std::exception& e) { + std::cerr << "Error occurrred while reading background images: " << e.what(); + } + } +} + +QWidget* LauncherWindow::createCentralWidget() { + QWidget* centralWidget = new QWidget; + + _backgroundImage = new QLabel(centralWidget); + _backgroundImage->setGeometry(geometry::BackgroundImage); + _backgroundImage->setPixmap(QPixmap(":/images/launcher-background.png")); QLabel* logoImage = new QLabel(centralWidget); logoImage->setObjectName("clear"); @@ -139,227 +217,164 @@ LauncherWindow::LauncherWindow(std::string basePath, bool profileEnabled, _windowConfigBox->setGeometry(geometry::WindowConfigBox); QPushButton* startButton = new QPushButton("START", centralWidget); - connect(startButton, &QPushButton::released, this, &LauncherWindow::startOpenSpace); + connect( + startButton, &QPushButton::released, + [this]() { + _shouldLaunch = true; + close(); + } + ); startButton->setObjectName("large"); startButton->setGeometry(geometry::StartButton); startButton->setCursor(Qt::PointingHandCursor); - + QPushButton* newButton = new QPushButton("New", centralWidget); - connect(newButton, &QPushButton::released, this, &LauncherWindow::openWindowNew); + connect( + newButton, &QPushButton::released, + [this]() { + openProfileEditor(""); + } + ); newButton->setObjectName("small"); newButton->setGeometry(geometry::NewButton); newButton->setCursor(Qt::PointingHandCursor); QPushButton* editButton = new QPushButton("Edit", centralWidget); - connect(editButton, &QPushButton::released, this, &LauncherWindow::openWindowEdit); + connect( + editButton, &QPushButton::released, + [this]() { + const std::string selection = _profileBox->currentText().toStdString(); + openProfileEditor(selection); + } + ); editButton->setObjectName("small"); editButton->setGeometry(geometry::EditButton); editButton->setCursor(Qt::PointingHandCursor); - setCentralWidget(centralWidget); + return centralWidget; +} +void LauncherWindow::setBackgroundImage(const std::string& syncPath) { + namespace fs = std::filesystem; + // First, we iterate through all folders in the launcher_images sync folder and we get + // the folder with the highest number + struct { + fs::directory_entry path; + int version = -1; + } latest; + for (const fs::directory_entry& p : fs::directory_iterator(syncPath)) { + if (!p.is_directory()) { + continue; + } + const std::string versionStr = p.path().stem().string(); + // All folder names in the sync folder should only be a digit, so we should be + // find to just convert it here + const int version = std::stoi(versionStr); - _reportAssetsInFilesystem = _filesystemAccess.useQtFileSystemModelToTraverseDir( - QString::fromStdString(basePath) + "/data/assets" - ); - populateProfilesList(globalConfig.profile); - - _profileBox->setEnabled(_profileChangeAllowed); - - populateWindowConfigsList(sgctConfigName); - _windowConfigBox->setEnabled(_sgctConfigChangeAllowed); - _fullyConfiguredViaCliArgs = (!profileEnabled && !sgctConfigEnabled); - - bool hasSyncFiles = false; - QString syncFilePath = QString::fromStdString( - globalConfig.pathTokens["SYNC"] + "/http/launcher_images/1/profile1.png" - ); - QFileInfo check_file(syncFilePath); - // check if file exists and if yes: Is it really a file and no directory? - if (check_file.exists() && check_file.isFile()) { - hasSyncFiles = true; + if (version > latest.version) { + latest.version = version; + latest.path = p; + } } - QString filename; - QString bgpath; - if (hasSyncFiles) { - std::random_device rd; - std::mt19937 rng(rd()); - std::uniform_int_distribution uni(0, 4); - int random_integer = uni(rng); - filename = QString::fromStdString( - "/http/launcher_images/1/profile" + std::to_string(random_integer) + ".png" - ); - bgpath = QString::fromStdString(globalConfig.pathTokens["SYNC"]) + filename; - } - else { - bgpath = QString::fromStdString(":/images/launcher-background.png"); + if (latest.version == -1) { + // The sync folder existed, but nothing was in there. Kinda weird, but still + return; } - backgroundImage->setPixmap(QPixmap(bgpath)); + // Now we know which folder to use, we will pick an image at random + std::vector files; + for (const fs::directory_entry& p : fs::directory_iterator(latest.path)) { + files.push_back(p.path().string()); + } + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(files.begin(), files.end(), g); + // We know there has to be at least one folder, so it's fine to just pick the first + std::string image = files.front(); + _backgroundImage->setPixmap(QPixmap(QString::fromStdString(image))); } void LauncherWindow::populateProfilesList(std::string preset) { + namespace fs = std::filesystem; + _profileBox->clear(); - std::string reportProfiles = _fileAccessProfiles.useQtFileSystemModelToTraverseDir( - _basePath + "/data/profiles" - ); - std::stringstream instream(reportProfiles); - std::string iline; - QStringList profilesListLine; - while (std::getline(instream, iline)) { - if (_profileBox->findText(QString::fromStdString(iline)) == -1) { - _profileBox->addItem(QString::fromStdString(iline)); + + // Add all the files with the .profile extension to the dropdown + for (const fs::directory_entry& p : fs::directory_iterator(_profilePath)) { + if (p.path().extension() != ".profile") { + continue; } + _profileBox->addItem(QString::fromStdString(p.path().stem().string())); } - if (preset.length() > 0) { - int presetMatchIdx = _profileBox->findText(QString::fromStdString(preset)); - if (presetMatchIdx != -1) { - _profileBox->setCurrentIndex(presetMatchIdx); - } + + // Try to find the requested profile and set it as the current one + const int idx = _profileBox->findText(QString::fromStdString(std::move(preset))); + if (idx != -1) { + _profileBox->setCurrentIndex(idx); + } } void LauncherWindow::populateWindowConfigsList(std::string preset) { - std::string reportConfigs = _fileAccessWinConfigs.useQtFileSystemModelToTraverseDir( - _basePath + "/config" - ); - std::stringstream instream(reportConfigs); - std::string iline; - QStringList windowConfigsListLine; - while (std::getline(instream, iline)) { - windowConfigsListLine << QString::fromStdString(iline); + namespace fs = std::filesystem; + + _windowConfigBox->clear(); + // Add all the files with the .xml extension to the dropdown + for (const fs::directory_entry& p : fs::directory_iterator(_configPath)) { + if (p.path().extension() != ".xml") { + continue; + } + _windowConfigBox->addItem(QString::fromStdString(p.path().stem().string())); } - _windowConfigBox->addItems(windowConfigsListLine); - if (preset.length() > 0) { - int presetMatchIdx = _windowConfigBox->findText(QString::fromStdString(preset)); - if (presetMatchIdx != -1) { - _windowConfigBox->setCurrentIndex(presetMatchIdx); - } - else { - _windowConfigBox->addItem(QString::fromStdString(preset)); - _windowConfigBox->setCurrentIndex(_windowConfigBox->count() - 1); - } + + // Try to find the requested configuration file and set it as the current one. As we + // have support for function-generated configuration files that will not be in the + // list we need to add a preset that doesn't exist a file for + const int idx = _windowConfigBox->findText(QString::fromStdString(std::move(preset))); + if (idx != -1) { + _windowConfigBox->setCurrentIndex(idx); + } + else { + // Add the requested preset at the top + _windowConfigBox->insertItem(0, QString::fromStdString(preset)); + _windowConfigBox->setCurrentIndex(0); } } -void LauncherWindow::openWindowNew() { - std::string initialProfileSelection = _profileBox->currentText().toStdString(); - Profile profile; - ProfileEdit editor( - profile, - _reportAssetsInFilesystem, - _globalConfig.readOnlyProfiles, - this - ); +void LauncherWindow::openProfileEditor(const std::string& profile) { + std::optional p; + if (profile.empty()) { + // If the requested profile is the empty string, then we want to create a new one + + p = Profile(); + } + else { + // Otherwise, we want to load that profile + + std::string fullProfilePath = _profilePath + profile + ".profile"; + p = loadProfileFromFile(this, fullProfilePath); + if (!p.has_value()) { + return; + } + } + + ProfileEdit editor(*p, profile, _assetPath, _profilePath, _readOnlyProfiles, this); editor.exec(); if (editor.wasSaved()) { - std::string saveProfilePath = _basePath.toStdString(); - saveProfilePath += "/data/profiles/"; - saveProfilePath += editor.specifiedFilename() + ".profile"; - saveProfileToFile(saveProfilePath, profile); + const std::string path = _profilePath + editor.specifiedFilename() + ".profile"; + saveProfile(this, path, *p); populateProfilesList(editor.specifiedFilename()); } else { - populateProfilesList(initialProfileSelection); - } -} - -void LauncherWindow::openWindowEdit() { - std::string initialProfileSelection = _profileBox->currentText().toStdString(); - std::string profilePath = _basePath.toStdString() + "/data/profiles/"; - int selectedProfileIdx = _profileBox->currentIndex(); - QString profileToSet = _profileBox->itemText(selectedProfileIdx); - std::string editProfilePath = profilePath + profileToSet.toStdString() + ".profile"; - - std::optional profile = loadProfileFromFile(editProfilePath); - if (profile.has_value()) { - ProfileEdit editor( - *profile, - _reportAssetsInFilesystem, - _globalConfig.readOnlyProfiles, - this - ); - editor.setProfileName(profileToSet); - editor.exec(); - if (editor.wasSaved()) { - profilePath += editor.specifiedFilename() + ".profile"; - saveProfileToFile(profilePath, *profile); - populateProfilesList(editor.specifiedFilename()); - } - else { - populateProfilesList(initialProfileSelection); - } - } -} - -void LauncherWindow::saveProfileToFile(const std::string& path, const Profile& p) { - std::ofstream outFile; - try { - outFile.open(path, std::ofstream::out); - outFile << p.serialize(); - } - catch (const std::ofstream::failure& e) { - QMessageBox::critical( - this, - "Exception", - QString::fromStdString(fmt::format( - "Error writing data to file: {} ({})", path, e.what() - )) - ); - } -} - -std::optional LauncherWindow::loadProfileFromFile(std::string filename) { - std::ifstream inFile; - try { - inFile.open(filename, std::ifstream::in); - } - catch (const std::ifstream::failure& e) { - throw ghoul::RuntimeError(fmt::format( - "Exception opening {} profile for read: ({})", - filename, - e.what() - )); - } - std::string content; - std::string line; - while (std::getline(inFile, line)) { - content += line; - } - try { - return Profile(content); - } - catch (const Profile::ParsingError& e) { - QMessageBox::critical( - this, - "Exception", - QString::fromStdString(fmt::format( - "ParsingError exception in {}: {}, {}", filename, e.component, e.message - )) - ); - return std::nullopt; - } - catch (const ghoul::RuntimeError& e) { - QMessageBox::critical( - this, - "Exception", - QString::fromStdString(fmt::format( - "RuntimeError exception in {}, component {}: {}", - filename, e.component, e.message - )) - ); - return std::nullopt; + const std::string current = _profileBox->currentText().toStdString(); + populateProfilesList(current); } } bool LauncherWindow::wasLaunchSelected() const { - return _launch; -} - -bool LauncherWindow::isFullyConfiguredFromCliArgs() const { - return _fullyConfiguredViaCliArgs; + return _shouldLaunch; } std::string LauncherWindow::selectedProfile() const { @@ -369,8 +384,3 @@ std::string LauncherWindow::selectedProfile() const { std::string LauncherWindow::selectedWindowConfig() const { return _windowConfigBox->currentText().toStdString(); } - -void LauncherWindow::startOpenSpace() { - _launch = true; - close(); -} diff --git a/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp index 4f13e52092..30a6ccec84 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp @@ -24,6 +24,7 @@ #include "profile/additionalscriptsdialog.h" +#include "profile/line.h" #include #include #include @@ -37,7 +38,18 @@ AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile, , _profile(profile) { setWindowTitle("Additional Scripts"); + createWidgets(); + std::vector scripts = _profile.additionalScripts(); + std::string scriptText = std::accumulate( + scripts.begin(), scripts.end(), + std::string(), [](std::string lhs, std::string rhs) { return lhs + rhs + '\n'; } + ); + _textScripts->setText(QString::fromStdString(std::move(scriptText))); + _textScripts->moveCursor(QTextCursor::MoveOperation::End); +} + +void AdditionalScriptsDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); { QLabel* heading = new QLabel("Additional Lua Scripts for Configuration"); @@ -49,12 +61,7 @@ AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile, _textScripts->setAcceptRichText(false); layout->addWidget(_textScripts, 1); - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QDialogButtonBox* buttons = new QDialogButtonBox; @@ -69,24 +76,16 @@ AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile, ); layout->addWidget(buttons); } - - std::vector scripts = _profile.additionalScripts(); - std::string scpts = std::accumulate( - scripts.begin(), scripts.end(), - std::string(), [](std::string lhs, std::string rhs) { return lhs + rhs + '\n'; } - ); - _textScripts->setText(QString::fromStdString(std::move(scpts))); - _textScripts->moveCursor(QTextCursor::MoveOperation::End); } void AdditionalScriptsDialog::parseScript() { - std::vector tmpMultilineStringToVector; + std::vector additionalScripts; std::istringstream iss(_textScripts->toPlainText().toStdString()); while (!iss.eof()) { std::string s; - getline(iss, s); - tmpMultilineStringToVector.push_back(s); + std::getline(iss, s); + additionalScripts.push_back(std::move(s)); } - _profile.setAdditionalScripts(tmpMultilineStringToVector); + _profile.setAdditionalScripts(additionalScripts); accept(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp index 4cc42fb61a..e8d99b617c 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp @@ -24,6 +24,7 @@ #include "profile/assetsdialog.h" +#include "profile/line.h" #include #include #include @@ -58,8 +59,8 @@ namespace { void traverseToFindFilesystemMatch(AssetTreeModel& model, QModelIndex parent, int nRows, const std::string& path) { - size_t slash = path.find_first_of('/', 0); - bool endOfPath = (slash == std::string::npos); + const size_t slash = path.find_first_of('/', 0); + const bool endOfPath = (slash == std::string::npos); std::string firstDir = endOfPath ? "" : path.substr(0, slash); if (!endOfPath) { @@ -71,7 +72,7 @@ namespace { QModelIndex idx = model.index(r, 0, parent); std::string assetName = model.name(idx).toStdString(); if (!model.isAsset(idx)) { - if (firstDir.compare(assetName) == 0) { + if (firstDir == assetName) { int nChildRows = model.childCount(idx); foundDirMatch = true; traverseToFindFilesystemMatch(model, idx, nChildRows, nextPath); @@ -83,7 +84,7 @@ namespace { } } if (!foundDirMatch) { - //Insert missing directory here with name and exists=false condition + // Insert missing directory here with name and exists=false condition model.assetItem(parent)->insertChildren(nRows, 1, 3); QModelIndex idx = model.index(nRows, 0, parent); model.setName(idx, QString::fromStdString(firstDir)); @@ -97,14 +98,14 @@ namespace { QModelIndex idx = model.index(r, 0, parent); std::string assetName = model.name(idx).toStdString(); - if (path.compare(assetName) == 0) { + if (path == assetName) { foundFileMatch = true; model.setChecked(idx, true); break; } } if (!foundFileMatch) { - //Insert missing file here with name and exists=false condition + // Insert missing file here with name and exists=false condition model.assetItem(parent)->insertChildren(nRows, 1, 3); QModelIndex idx = model.index(nRows, 0, parent); model.setName(idx, QString::fromStdString(path)); @@ -115,13 +116,17 @@ namespace { } } // namespace -AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string reportAssets, +AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath, QWidget* parent) : QDialog(parent) , _profile(profile) { setWindowTitle("Assets"); + _assetTreeModel.importModelData(assetBasePath); + createWidgets(); +} +void AssetsDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); { QLabel* heading = new QLabel("Select assets from /data/assets"); @@ -129,8 +134,6 @@ AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string report layout->addWidget(heading); } { - _assetTreeModel.importModelData(reportAssets); - _assetTree = new QTreeView; _assetTree->setToolTip( "Expand arrow entries to browse assets in this OpenSpace installation. " @@ -177,12 +180,8 @@ AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string report _summary->setText(createTextSummary()); layout->addWidget(_summary); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + + layout->addWidget(new Line); { QDialogButtonBox* buttons = new QDialogButtonBox; @@ -210,10 +209,13 @@ QString AssetsDialog::createTextSummary() { QString summary; for (int i = 0; i < summaryItems.size(); ++i) { bool existsInFilesystem = summaryItems.at(i)->doesExistInFilesystem(); - std::string s = fmt::format("{}
", - (existsInFilesystem ? "black" : "red"), - summaryPaths.at(i) - ); + + constexpr const char* ExistsFormat = "{}
"; + constexpr const char* NotExistsFormat = "{}
"; + + std::string s = existsInFilesystem ? + fmt::format("{}
", summaryPaths.at(i)) : + fmt::format("{}
", summaryPaths.at(i)); summary += QString::fromStdString(s); } return summary; diff --git a/apps/OpenSpace/ext/launcher/src/profile/assettreeitem.cpp b/apps/OpenSpace/ext/launcher/src/profile/assettreeitem.cpp index f02b57ce3d..199a755fb1 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/assettreeitem.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/assettreeitem.cpp @@ -30,7 +30,9 @@ AssetTreeItem::AssetTreeItem(const std::vector& data, AssetTreeItem* p {} AssetTreeItem::~AssetTreeItem() { - qDeleteAll(_childItems); + for (AssetTreeItem* item : _childItems) { + delete item; + } } AssetTreeItem* AssetTreeItem::child(int row) { @@ -48,12 +50,12 @@ int AssetTreeItem::childCount() const { int AssetTreeItem::row() const { if (_parentItem) { - auto it = std::find( - _parentItem->_childItems.begin(), - _parentItem->_childItems.end(), + const auto it = std::find( + _parentItem->_childItems.cbegin(), + _parentItem->_childItems.cend(), this ); - return std::distance(_parentItem->_childItems.begin(), it); + return std::distance(_parentItem->_childItems.cbegin(), it); } else { return 0; diff --git a/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp b/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp index 4b1573c5bd..16b7ba2b77 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp @@ -24,6 +24,7 @@ #include "profile/assettreeitem.h" #include "profile/assettreemodel.h" +#include "filesystemaccess.h" #include #include @@ -57,7 +58,8 @@ namespace { } bool importGetNextLine(ImportElement& elem, std::istringstream& iss) { - bool ok = std::getline(iss, elem.line) ? true : false; + std::getline(iss, elem.line); + const bool ok = iss.good(); if (!ok) { elem.line = ""; elem.level = -1; @@ -143,8 +145,16 @@ AssetTreeModel::AssetTreeModel(QObject* parent) ); } -void AssetTreeModel::importModelData(const std::string& contents) { - std::istringstream iss(contents); +void AssetTreeModel::importModelData(const std::string& assetBasePath) { + FileSystemAccess assets( + ".asset", + { "scene", "global", "customization", "examples", "util" }, + true, + true + ); + std::string assetList = assets.useQtFileSystemModelToTraverseDir(assetBasePath); + + std::istringstream iss(assetList); ImportElement rootElem = { "", 0, false }; if (importGetNextLine(rootElem, iss)) { @@ -164,8 +174,8 @@ AssetTreeItem* AssetTreeModel::getItem(const QModelIndex& index) const { bool AssetTreeModel::isChecked(QModelIndex& index) const { AssetTreeItem* item = getItem(index); - int checked = item->data(1).toInt(); - return checked == Qt::Checked; + const int isChecked = item->data(1).toInt(); + return isChecked == Qt::Checked; } bool AssetTreeModel::isAsset(QModelIndex& index) const { diff --git a/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp index 1689dffc31..2137770c36 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp @@ -24,6 +24,7 @@ #include "profile/cameradialog.h" +#include "profile/line.h" #include #include #include @@ -60,37 +61,7 @@ CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent) , _profile(profile) { setWindowTitle("Set Camera Position"); - - QBoxLayout* layout = new QVBoxLayout(this); - _tabWidget = new QTabWidget; - connect(_tabWidget, &QTabWidget::tabBarClicked, this, &CameraDialog::tabSelect); - _tabWidget->addTab(createNavStateWidget(), "Navigation State"); - _tabWidget->addTab(createGeoWidget(), "Geo State"); - layout->addWidget(_tabWidget); - - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } - - { - QBoxLayout* footerLayout = new QHBoxLayout; - - _errorMsg = new QLabel; - _errorMsg->setObjectName("error-message"); - _errorMsg->setWordWrap(true); - footerLayout->addWidget(_errorMsg); - - QDialogButtonBox* buttons = new QDialogButtonBox; - buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); - connect(buttons, &QDialogButtonBox::accepted, this, &CameraDialog::approved); - connect(buttons, &QDialogButtonBox::rejected, this, &CameraDialog::reject); - footerLayout->addWidget(buttons); - - layout->addLayout(footerLayout); - } + createWidgets(); if (_profile.camera().has_value()) { openspace::Profile::CameraType type = *_profile.camera(); @@ -163,6 +134,34 @@ CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent) } } +void CameraDialog::createWidgets() { + QBoxLayout* layout = new QVBoxLayout(this); + _tabWidget = new QTabWidget; + connect(_tabWidget, &QTabWidget::tabBarClicked, this, &CameraDialog::tabSelect); + _tabWidget->addTab(createNavStateWidget(), "Navigation State"); + _tabWidget->addTab(createGeoWidget(), "Geo State"); + layout->addWidget(_tabWidget); + + layout->addWidget(new Line); + + { + QBoxLayout* footerLayout = new QHBoxLayout; + + _errorMsg = new QLabel; + _errorMsg->setObjectName("error-message"); + _errorMsg->setWordWrap(true); + footerLayout->addWidget(_errorMsg); + + QDialogButtonBox* buttons = new QDialogButtonBox; + buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); + connect(buttons, &QDialogButtonBox::accepted, this, &CameraDialog::approved); + connect(buttons, &QDialogButtonBox::rejected, this, &CameraDialog::reject); + footerLayout->addWidget(buttons); + + layout->addLayout(footerLayout); + } +} + QWidget* CameraDialog::createNavStateWidget() { QWidget* box = new QWidget; QGridLayout* layout = new QGridLayout(box); @@ -175,14 +174,16 @@ QWidget* CameraDialog::createNavStateWidget() { layout->addWidget(new QLabel("Aim:"), 1, 0); _navState.aim = new QLineEdit; _navState.aim->setToolTip( - "[OPTIONAL] If specified, camera will be aimed at this node while keeping the " - "anchor node in the same view location" + "If specified, camera will be aimed at this node while keeping the anchor node " + "in the same view location" ); + _navState.aim->setPlaceholderText("optional"); layout->addWidget(_navState.aim, 1, 1); layout->addWidget(new QLabel("Reference Frame:"), 2, 0); _navState.refFrame = new QLineEdit; - _navState.refFrame->setToolTip("[OPTIONAL] Camera location in reference to this frame"); + _navState.refFrame->setToolTip("Camera location in reference to this frame"); + _navState.refFrame->setPlaceholderText("optional"); layout->addWidget(_navState.refFrame, 2, 1); layout->addWidget(new QLabel("Position:"), 3, 0); @@ -218,19 +219,22 @@ QWidget* CameraDialog::createNavStateWidget() { upLayout->addWidget(new QLabel("X")); _navState.upX = new QLineEdit; _navState.upX->setValidator(new QDoubleValidator); - _navState.upX->setToolTip("[OPTIONAL] Camera up vector (x)"); + _navState.upX->setToolTip("Camera up vector (x)"); + _navState.upX->setPlaceholderText("semioptional"); upLayout->addWidget(_navState.upX); upLayout->addWidget(new QLabel("Y")); _navState.upY = new QLineEdit; _navState.upY->setValidator(new QDoubleValidator); - _navState.upY->setToolTip("[OPTIONAL] Camera up vector (y)"); + _navState.upY->setToolTip("Camera up vector (y)"); + _navState.upY->setPlaceholderText("semioptional"); upLayout->addWidget(_navState.upY); upLayout->addWidget(new QLabel("Z")); _navState.upZ = new QLineEdit; _navState.upZ->setValidator(new QDoubleValidator); - _navState.upZ->setToolTip("[OPTIONAL] Camera up vector (z)"); + _navState.upZ->setToolTip("Camera up vector (z)"); + _navState.upZ->setPlaceholderText("semioptional"); upLayout->addWidget(_navState.upZ); layout->addWidget(upBox, 4, 1); } @@ -238,13 +242,15 @@ QWidget* CameraDialog::createNavStateWidget() { layout->addWidget(new QLabel("Yaw angle:"), 5, 0); _navState.yaw = new QLineEdit; _navState.yaw->setValidator(new QDoubleValidator); - _navState.yaw->setToolTip("[OPTIONAL] yaw angle +/- 360 degrees"); + _navState.yaw->setToolTip("Yaw angle +/- 360 degrees"); + _navState.yaw->setPlaceholderText("optional"); layout->addWidget(_navState.yaw, 5, 1); layout->addWidget(new QLabel("Pitch angle:"), 6, 0); _navState.pitch = new QLineEdit; _navState.pitch->setValidator(new QDoubleValidator); - _navState.pitch->setToolTip("[OPTIONAL] pitch angle +/- 360 degrees"); + _navState.pitch->setToolTip("Pitch angle +/- 360 degrees"); + _navState.pitch->setPlaceholderText("optional"); layout->addWidget(_navState.pitch, 6, 1); return box; @@ -274,8 +280,8 @@ QWidget* CameraDialog::createGeoWidget() { layout->addWidget(new QLabel("Altitude"), 3, 0); _geoState.altitude = new QLineEdit; _geoState.altitude->setValidator(new QDoubleValidator); - _geoState.altitude->setToolTip("[OPTIONAL] Altitude of camera (meters)"); - //altitude->setPlaceholderText("optional"); + _geoState.altitude->setToolTip("Altitude of camera (meters)"); + _geoState.altitude->setPlaceholderText("optional"); layout->addWidget(_geoState.altitude, 3, 1); return box; @@ -354,7 +360,7 @@ bool CameraDialog::areRequiredFormsFilledAndValid() { void CameraDialog::addErrorMsg(QString errorDescription) { QString contents = _errorMsg->text(); - if (contents.length() > 0) { + if (!contents.isEmpty()) { contents += ", "; } contents += errorDescription; diff --git a/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp index 6cea3ec749..8beac8fb1d 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp @@ -24,6 +24,7 @@ #include "profile/deltatimesdialog.h" +#include "profile/line.h" #include #include #include @@ -76,7 +77,6 @@ namespace { } return checkForTimeDescription(i, value); } - } // namespace DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) @@ -84,6 +84,19 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) , _profile(profile) { setWindowTitle("Simulation Time Increments"); + createWidgets(); + + _data = _profile.deltaTimes(); + + for (size_t d = 0; d < _data.size(); ++d) { + std::string summary = createSummaryForDeltaTime(d, true); + _listWidget->addItem(new QListWidgetItem(QString::fromStdString(summary))); + } + + transitionEditMode(_listWidget->count() - 1, false); +} + +void DeltaTimesDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); { _listWidget = new QListWidget; @@ -105,7 +118,7 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) ); buttonLayout->addWidget(_addButton); - _removeButton = new QPushButton("Remove LastEntry"); + _removeButton = new QPushButton("Remove Last Entry"); connect( _removeButton, &QPushButton::clicked, this, &DeltaTimesDialog::removeDeltaTimeValue @@ -130,7 +143,7 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) box->addWidget(_value); layout->addLayout(box); } - + { QBoxLayout* box = new QHBoxLayout; _saveButton = new QPushButton("Save"); @@ -150,12 +163,7 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) box->addStretch(); layout->addLayout(box); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QBoxLayout* footer = new QHBoxLayout; _errorMsg = new QLabel; @@ -173,16 +181,6 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) footer->addWidget(_buttonBox); layout->addLayout(footer); } - - - _data = _profile.deltaTimes(); - - for (size_t d = 0; d < _data.size(); ++d) { - std::string summary = createSummaryForDeltaTime(d, true); - _listWidget->addItem(new QListWidgetItem(QString::fromStdString(summary))); - } - - transitionEditMode(_listWidget->count() - 1, false); } std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forListView) { @@ -205,9 +203,7 @@ std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forList } if (forListView) { - s += "\t" + std::to_string(_data.at(idx)); - s += "\t"; - s += timeDescription(_data.at(idx)); + s += '\t' + std::to_string(_data.at(idx)) + '\t' + timeDescription(_data.at(idx)); } return s; } @@ -220,7 +216,7 @@ void DeltaTimesDialog::listItemSelected() { _listWidget->setCurrentRow(index); } - if (_data.size() > 0) { + if (!_data.empty()) { if (_data.at(index) == 0) { _seconds->clear(); } @@ -238,9 +234,7 @@ void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string colo index = _data.size() - 1; } if (editMode) { - labelS += " '"; - labelS += createSummaryForDeltaTime(index, false); - labelS += "':"; + labelS += " '" + createSummaryForDeltaTime(index, false) + "':"; } _adjustLabel->setText(QString::fromStdString( "" + labelS + "" @@ -248,7 +242,7 @@ void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string colo } void DeltaTimesDialog::valueChanged(const QString& text) { - if (_seconds->text() == "") { + if (_seconds->text().isEmpty()) { _errorMsg->setText(""); } else { @@ -297,21 +291,20 @@ void DeltaTimesDialog::addDeltaTimeValue() { } void DeltaTimesDialog::saveDeltaTimeValue() { - QListWidgetItem *item = _listWidget->currentItem(); + QListWidgetItem* item = _listWidget->currentItem(); if (item != nullptr) { int index = _listWidget->row(item); if (_data.size() > 0) { _data.at(index) = _seconds->text().toDouble(); std::string summary = createSummaryForDeltaTime(index, true); _listWidget->item(index)->setText(QString::fromStdString(summary)); - //setLabelForKey(index, true, "black"); transitionEditMode(index, false); _editModeNewItem = false; } } } -void DeltaTimesDialog::discardDeltaTimeValue(void) { +void DeltaTimesDialog::discardDeltaTimeValue() { listItemSelected(); transitionEditMode(_listWidget->count() - 1, false); if (_editModeNewItem && !_data.empty() && _data.back() == 0) { diff --git a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp index 657e886efc..2201d728ba 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp @@ -24,6 +24,7 @@ #include "profile/keybindingsdialog.h" +#include "profile/line.h" #include #include #include @@ -38,9 +39,11 @@ #include #include +using namespace openspace; + namespace { - const openspace::Profile::Keybinding kBlank = { - { openspace::Key::Unknown, openspace::KeyModifier::NoModifier }, + const Profile::Keybinding BlankKey= { + { Key::Unknown, KeyModifier::NoModifier }, "", "", "", @@ -52,8 +55,7 @@ namespace { std::string newString; std::string::size_type found, last = 0; - while ((found = src.find(from, last)) != std::string::npos) - { + while ((found = src.find(from, last)) != std::string::npos) { newString.append(src, last, (found - last)); newString += to; last = found + from.length(); @@ -72,16 +74,16 @@ namespace { return s; } - std::string createOneLineSummary(openspace::Profile::Keybinding k) { + std::string createOneLineSummary(Profile::Keybinding k) { std::string summary; int keymod = static_cast(k.key.modifier); - if (keymod != static_cast(openspace::KeyModifier::NoModifier)) { - summary += openspace::KeyModifierNames.at(keymod) + " "; + if (keymod != static_cast(KeyModifier::NoModifier)) { + summary += KeyModifierNames.at(keymod) + " "; } int keyname = static_cast(k.key.key); - summary += openspace::KeyNames.at(keyname) + " "; + summary += KeyNames.at(keyname) + " "; summary += truncateString(k.name) + " ("; summary += truncateString(k.documentation) + ") @ "; summary += truncateString(k.guiPath) + " "; @@ -93,13 +95,18 @@ namespace { } // namespace -KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *parent) +KeybindingsDialog::KeybindingsDialog(Profile& profile, QWidget *parent) : QDialog(parent) , _profile(profile) , _data(_profile.keybindings()) { setWindowTitle("Assign Keybindings"); + createWidgets(); + transitionFromEditMode(); +} + +void KeybindingsDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); { _list = new QListWidget; @@ -136,12 +143,7 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren box->addStretch(); layout->addLayout(box); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QGridLayout* box = new QGridLayout; @@ -154,7 +156,7 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren QStringList comboModKeysStringList; int modIdx = 0; - for (const std::pair& m : openspace::KeyModifierNames) { + for (const std::pair& m : KeyModifierNames) { comboModKeysStringList += QString::fromStdString(m.second); _mapModKeyComboBoxIndexToKeyValue.push_back(modIdx++); } @@ -168,9 +170,9 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren _keyCombo->setToolTip("Key to press for this keybinding"); QStringList comboKeysStringList; - for (int i = 0; i < static_cast(openspace::Key::Last); ++i) { - if (openspace::KeyNames.find(i) != openspace::KeyNames.end()) { - comboKeysStringList += QString::fromStdString(openspace::KeyNames.at(i)); + for (int i = 0; i < static_cast(Key::Last); ++i) { + if (KeyNames.find(i) != KeyNames.end()) { + comboKeysStringList += QString::fromStdString(KeyNames.at(i)); // Create map to relate key combo box to integer value defined in Key _mapKeyComboBoxIndexToKeyValue.push_back(i); } @@ -243,12 +245,7 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren box->addLayout(buttonBox, 8, 1, 1, 2); layout->addLayout(box); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QBoxLayout* footerLayout = new QHBoxLayout; @@ -270,23 +267,21 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren footerLayout->addWidget(_buttonBox); layout->addLayout(footerLayout); } - - transitionFromEditMode(); } -void KeybindingsDialog::listItemSelected(void) { +void KeybindingsDialog::listItemSelected() { QListWidgetItem *item = _list->currentItem(); int index = _list->row(item); if (_data.size() > 0) { - openspace::Profile::Keybinding& k = _data[index]; + Profile::Keybinding& k = _data[index]; const int modifierKey = indexInKeyMapping( _mapModKeyComboBoxIndexToKeyValue, static_cast(k.key.modifier) ); _keyModCombo->setCurrentIndex(modifierKey); - if (k.key.key == openspace::Key::Unknown) { + if (k.key.key == Key::Unknown) { _keyCombo->setCurrentIndex(0); } else { @@ -308,13 +303,13 @@ void KeybindingsDialog::listItemSelected(void) { } void KeybindingsDialog::keySelected(int index) { - const QString numKeyWarning = "Warning: using a number key may conflict with the " - "keybindings for simulation time increments. "; + const QString numKeyWarning = "Warning: Using a number key may conflict with the " + "keybindings for simulation time increments."; QString errorContents = _errorMsg->text(); bool alreadyContainsWarning = (errorContents.length() >= numKeyWarning.length() && errorContents.left(numKeyWarning.length()) == numKeyWarning); - if (_mapKeyComboBoxIndexToKeyValue[index] >= static_cast(openspace::Key::Num0) - && _mapKeyComboBoxIndexToKeyValue[index] <= static_cast(openspace::Key::Num9)) + if (_mapKeyComboBoxIndexToKeyValue[index] >= static_cast(Key::Num0) + && _mapKeyComboBoxIndexToKeyValue[index] <= static_cast(Key::Num9)) { if (!alreadyContainsWarning) { errorContents = numKeyWarning + errorContents; @@ -327,8 +322,8 @@ void KeybindingsDialog::keySelected(int index) { } int KeybindingsDialog::indexInKeyMapping(std::vector& mapVector, int keyInt) { - auto it = std::find(mapVector.begin(), mapVector.end(), keyInt); - return std::distance(mapVector.begin(), it); + const auto it = std::find(mapVector.cbegin(), mapVector.cend(), keyInt); + return std::distance(mapVector.cbegin(), it); } bool KeybindingsDialog::isLineEmpty(int index) { @@ -345,25 +340,14 @@ bool KeybindingsDialog::isLineEmpty(int index) { void KeybindingsDialog::listItemAdded() { int currentListSize = _list->count(); - //if ((currentListSize == 1) && (isLineEmpty(0))) { - //if (currentListSize == 0) { - // // Special case where list is "empty" but really has one line that is blank. - // // This is done because QListWidget does not seem to like having its sole - // // remaining item being removed. - // _data.at(0) = kBlank; - // _list->item(0)->setText(" (Enter details below & click 'Save')"); - // transitionToEditMode(); - // } - // else { - _data.push_back(kBlank); - _list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')")); - //Scroll down to that blank line highlighted - _list->setCurrentRow(_list->count() - 1); - //} + _data.push_back(BlankKey); + _list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')")); + // Scroll down to that blank line highlighted + _list->setCurrentRow(_list->count() - 1); // Blank-out the 2 text fields, set combo box to index 0 _keyModCombo->setCurrentIndex(static_cast(_data.back().key.modifier)); - if (_data.back().key.key == openspace::Key::Unknown) { + if (_data.back().key.key == Key::Unknown) { _keyCombo->setCurrentIndex(0); } else { @@ -379,7 +363,7 @@ void KeybindingsDialog::listItemAdded() { _editModeNewItem = true; } -void KeybindingsDialog::listItemSave(void) { +void KeybindingsDialog::listItemSave() { if (!areRequiredFormsFilled()) { return; } @@ -390,9 +374,9 @@ void KeybindingsDialog::listItemSave(void) { if (!_data.empty()) { int keyModIdx = _mapModKeyComboBoxIndexToKeyValue.at( _keyModCombo->currentIndex()); - _data[index].key.modifier = static_cast(keyModIdx); + _data[index].key.modifier = static_cast(keyModIdx); int keyIdx = _mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex()); - _data[index].key.key = static_cast(keyIdx); + _data[index].key.key = static_cast(keyIdx); _data[index].name = _nameEdit->text().toStdString(); _data[index].guiPath = _guiPathEdit->text().toStdString(); _data[index].documentation = _documentationEdit->text().toStdString(); @@ -412,14 +396,14 @@ bool KeybindingsDialog::areRequiredFormsFilled() { requiredFormsFilled = false; } if (_nameEdit->text().length() == 0) { - if (errors.length() > 0) { + if (!errors.empty()) { errors += ", "; } errors += "Missing keybinding name"; requiredFormsFilled = false; } - if (_scriptEdit->toPlainText().length() == 0) { - if (errors.length() > 0) { + if (_scriptEdit->toPlainText().isEmpty()) { + if (!errors.empty()) { errors += ", "; } errors += "Missing script"; @@ -429,31 +413,31 @@ bool KeybindingsDialog::areRequiredFormsFilled() { return requiredFormsFilled; } -void KeybindingsDialog::listItemCancelSave(void) { +void KeybindingsDialog::listItemCancelSave() { listItemSelected(); transitionFromEditMode(); if (_editModeNewItem && !_data.empty() && (_data.back().name.length() == 0 || _data.back().script.length() == 0 || - _data.back().key.key == openspace::Key::Unknown)) + _data.back().key.key == Key::Unknown)) { listItemRemove(); } _editModeNewItem = false; } -void KeybindingsDialog::listItemRemove(void) { +void KeybindingsDialog::listItemRemove() { if (_list->count() > 0) { if (_list->count() == 1) { // Special case where last remaining item is being removed (QListWidget does // not like the final item being removed so instead clear it & leave it) - _data.at(0) = kBlank; + _data.at(0) = BlankKey; _list->item(0)->setText(""); } else { int index = _list->currentRow(); if (index >= 0 && index < _list->count()) { _list->takeItem(index); - if (_data.size() > 0) { + if (!_data.empty()) { _data.erase(_data.begin() + index); } } @@ -481,7 +465,7 @@ void KeybindingsDialog::transitionToEditMode() { _errorMsg->setText(""); } -void KeybindingsDialog::transitionFromEditMode(void) { +void KeybindingsDialog::transitionFromEditMode() { _list->setDisabled(false); _addButton->setDisabled(false); _removeButton->setDisabled(false); diff --git a/apps/OpenSpace/ext/launcher/src/profile/line.cpp b/apps/OpenSpace/ext/launcher/src/profile/line.cpp new file mode 100644 index 0000000000..336dc722a0 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/src/profile/line.cpp @@ -0,0 +1,30 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 "profile/line.h" + +Line::Line() { + setFrameShape(QFrame::HLine); + setFrameShadow(QFrame::Sunken); +} diff --git a/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp index 5564f1582e..604827f837 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp @@ -24,6 +24,7 @@ #include "profile/marknodesdialog.h" +#include "profile/line.h" #include #include #include @@ -40,7 +41,10 @@ MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent) , _data(_profile.markNodes()) { setWindowTitle("Mark Interesting Nodes"); + createWidgets(); +} +void MarkNodesDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); _list = new QListWidget; connect( @@ -80,6 +84,7 @@ MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent) box->addWidget(addButton); layout->addLayout(box); } + layout->addWidget(new Line); { QDialogButtonBox* buttons = new QDialogButtonBox; buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); @@ -95,11 +100,11 @@ MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent) } } -void MarkNodesDialog::listItemSelected(void) { +void MarkNodesDialog::listItemSelected() { _removeButton->setEnabled(true); } -void MarkNodesDialog::listItemAdded(void) { +void MarkNodesDialog::listItemAdded() { if (_newNode->text().isEmpty()) { return; } @@ -140,7 +145,7 @@ void MarkNodesDialog::parseSelections() { accept(); } -void MarkNodesDialog::keyPressEvent(QKeyEvent *evt) { +void MarkNodesDialog::keyPressEvent(QKeyEvent* evt) { if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) { if (_newNode->text().length() > 0 && _newNode->hasFocus()) { listItemAdded(); diff --git a/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp index 35d184ecd9..c96c206426 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp @@ -24,6 +24,7 @@ #include "profile/metadialog.h" +#include "profile/line.h" #include #include #include @@ -38,40 +39,7 @@ MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent) , _profile(profile) { setWindowTitle("Meta"); - - QBoxLayout* layout = new QVBoxLayout(this); - layout->addWidget(new QLabel("Name")); - _nameEdit = new QLineEdit; - layout->addWidget(_nameEdit); - - layout->addWidget(new QLabel("Version")); - _versionEdit = new QLineEdit; - layout->addWidget(_versionEdit); - - layout->addWidget(new QLabel("Description")); - _descriptionEdit = new QTextEdit; - _descriptionEdit->setAcceptRichText(false); - _descriptionEdit->setTabChangesFocus(true); - layout->addWidget(_descriptionEdit); - - layout->addWidget(new QLabel("Author")); - _authorEdit = new QLineEdit; - layout->addWidget(_authorEdit); - - layout->addWidget(new QLabel("URL")); - _urlEdit = new QLineEdit; - layout->addWidget(_urlEdit); - - layout->addWidget(new QLabel("License")); - _licenseEdit = new QLineEdit; - layout->addWidget(_licenseEdit); - - QDialogButtonBox* buttons = new QDialogButtonBox; - buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); - QObject::connect(buttons, &QDialogButtonBox::accepted, this, &MetaDialog::save); - QObject::connect(buttons, &QDialogButtonBox::rejected, this, &MetaDialog::reject); - layout->addWidget(buttons); - + createWidgets(); if (_profile.meta().has_value()) { openspace::Profile::Meta meta = *_profile.meta(); @@ -96,6 +64,43 @@ MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent) } } +void MetaDialog::createWidgets() { + QBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(new QLabel("Name")); + _nameEdit = new QLineEdit; + layout->addWidget(_nameEdit); + + layout->addWidget(new QLabel("Version")); + _versionEdit = new QLineEdit; + layout->addWidget(_versionEdit); + + layout->addWidget(new QLabel("Description")); + _descriptionEdit = new QTextEdit; + _descriptionEdit->setAcceptRichText(false); + _descriptionEdit->setTabChangesFocus(true); + layout->addWidget(_descriptionEdit); + + layout->addWidget(new QLabel("Author")); + _authorEdit = new QLineEdit; + layout->addWidget(_authorEdit); + + layout->addWidget(new QLabel("URL")); + _urlEdit = new QLineEdit; + layout->addWidget(_urlEdit); + + layout->addWidget(new QLabel("License")); + _licenseEdit = new QLineEdit; + layout->addWidget(_licenseEdit); + + layout->addWidget(new Line); + + QDialogButtonBox* buttons = new QDialogButtonBox; + buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); + QObject::connect(buttons, &QDialogButtonBox::accepted, this, &MetaDialog::save); + QObject::connect(buttons, &QDialogButtonBox::rejected, this, &MetaDialog::reject); + layout->addWidget(buttons); +} + void MetaDialog::save() { const bool allEmpty = _nameEdit->text().isEmpty() && _versionEdit->text().isEmpty() && diff --git a/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp index f2576028b0..217ea9e5d8 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp @@ -24,6 +24,7 @@ #include "profile/modulesdialog.h" +#include "profile/line.h" #include #include #include @@ -33,15 +34,25 @@ #include #include -ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent) +using namespace openspace; + +namespace { + const Profile::Module Blank = { "", "", "" }; +} // namespace + +ModulesDialog::ModulesDialog(Profile& profile, QWidget *parent) : QDialog(parent) , _profile(profile) , _data(_profile.modules()) { setWindowTitle("Modules"); + createWidgets(); + transitionFromEditMode(); +} + +void ModulesDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); - { _list = new QListWidget; connect( @@ -52,8 +63,8 @@ ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent) _list->setMovement(QListView::Free); _list->setResizeMode(QListView::Adjust); - for (size_t i = 0; i < _data.size(); ++i) { - _list->addItem(new QListWidgetItem(createOneLineSummary(_data[i]))); + for (const Profile::Module& m : _data) { + _list->addItem(new QListWidgetItem(createOneLineSummary(m))); } layout->addWidget(_list); } @@ -117,12 +128,7 @@ ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent) layout->addLayout(box); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QBoxLayout* footerLayout = new QHBoxLayout; @@ -144,11 +150,9 @@ ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent) footerLayout->addWidget(_buttonBox); layout->addLayout(footerLayout); } - - transitionFromEditMode(); } -QString ModulesDialog::createOneLineSummary(openspace::Profile::Module m) { +QString ModulesDialog::createOneLineSummary(Profile::Module m) { QString summary = QString::fromStdString(m.name); bool hasCommandForLoaded = (m.loadedInstruction->length() > 0); bool hasCommandForNotLoaded = (m.notLoadedInstruction->length() > 0); @@ -169,11 +173,11 @@ QString ModulesDialog::createOneLineSummary(openspace::Profile::Module m) { } void ModulesDialog::listItemSelected() { - QListWidgetItem *item = _list->currentItem(); + QListWidgetItem* item = _list->currentItem(); int index = _list->row(item); - if (_data.size() > 0) { - const openspace::Profile::Module& m = _data[index]; + if (!_data.empty()) { + const Profile::Module& m = _data[index]; _moduleEdit->setText(QString::fromStdString(m.name)); if (m.loadedInstruction.has_value()) { _loadedEdit->setText(QString::fromStdString(*m.loadedInstruction)); @@ -191,7 +195,7 @@ void ModulesDialog::listItemSelected() { transitionToEditMode(); } -bool ModulesDialog::isLineEmpty(int index) { +bool ModulesDialog::isLineEmpty(int index) const { bool isEmpty = true; if (!_list->item(index)->text().isEmpty()) { isEmpty = false; @@ -202,20 +206,20 @@ bool ModulesDialog::isLineEmpty(int index) { return isEmpty; } -void ModulesDialog::listItemAdded(void) { +void ModulesDialog::listItemAdded() { int currentListSize = _list->count(); if ((currentListSize == 1) && (isLineEmpty(0))) { - //Special case where list is "empty" but really has one line that is blank. + // Special case where list is "empty" but really has one line that is blank. // This is done because QListWidget does not seem to like having its sole // remaining item being removed. - _data.at(0) = kBlank; + _data.at(0) = Blank; _list->item(0)->setText(" (Enter details below & click 'Save')"); _list->setCurrentRow(0); transitionToEditMode(); } else { - _data.push_back(kBlank); + _data.push_back(Blank); _list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')")); //Scroll down to that blank line highlighted _list->setCurrentRow(_list->count() - 1); @@ -242,9 +246,8 @@ void ModulesDialog::listItemAdded(void) { _editModeNewItem = true; } -void ModulesDialog::listItemSave(void) { +void ModulesDialog::listItemSave() { if (_moduleEdit->text().isEmpty()) { - //ui->label_module->setText("Module"); _errorMsg->setText("Missing module name"); return; } @@ -262,32 +265,28 @@ void ModulesDialog::listItemSave(void) { _editModeNewItem = false; } -void ModulesDialog::listItemCancelSave(void) { +void ModulesDialog::listItemCancelSave() { transitionFromEditMode(); - if (_editModeNewItem) { - if (_data.size() > 0) { - if(_data.back().name.length() == 0) { - listItemRemove(); - } - } + if (_editModeNewItem && !_data.empty() && _data.back().name.empty()) { + listItemRemove(); } _editModeNewItem = false; } -void ModulesDialog::listItemRemove(void) { +void ModulesDialog::listItemRemove() { if (_list->count() > 0) { if (_list->currentRow() >= 0 && _list->currentRow() < _list->count()) { if (_list->count() == 1) { - //Special case where last remaining item is being removed (QListWidget + // Special case where last remaining item is being removed (QListWidget // doesn't like the final item being removed so instead clear it) - _data.at(0) = kBlank; + _data.at(0) = Blank; _list->item(0)->setText(""); } else { int index = _list->currentRow(); if (index >= 0 && index < _list->count()) { delete _list->takeItem(index); - if (_data.size() > 0) { + if (!_data.empty()) { _data.erase(_data.begin() + index); } } @@ -297,7 +296,7 @@ void ModulesDialog::listItemRemove(void) { transitionFromEditMode(); } -void ModulesDialog::transitionToEditMode(void) { +void ModulesDialog::transitionToEditMode() { _list->setDisabled(true); _buttonAdd->setDisabled(true); _buttonRemove->setDisabled(true); @@ -312,7 +311,7 @@ void ModulesDialog::transitionToEditMode(void) { _errorMsg->setText(""); } -void ModulesDialog::transitionFromEditMode(void) { +void ModulesDialog::transitionFromEditMode() { _list->setDisabled(false); _buttonAdd->setDisabled(false); _buttonRemove->setDisabled(false); diff --git a/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp b/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp index ccbff3ccb9..46e7a8d942 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp @@ -22,22 +22,34 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include #include "profile/profileedit.h" -#include "filesystemaccess.h" + +#include "profile/additionalscriptsdialog.h" +#include "profile/assetsdialog.h" +#include "profile/cameradialog.h" +#include "profile/deltatimesdialog.h" +#include "profile/keybindingsdialog.h" +#include "profile/line.h" +#include "profile/marknodesdialog.h" +#include "profile/metadialog.h" +#include "profile/modulesdialog.h" +#include "profile/propertiesdialog.h" +#include "profile/timedialog.h" +#include +#include #include -#include -#include #include #include #include #include -#include +#include +#include +#include +#include + +using namespace openspace; namespace { - template struct overloaded : Ts... { using Ts::operator()...; }; - template overloaded(Ts...)->overloaded; - QString labelText(int size, QString title) { QString label; if (size > 0) { @@ -48,19 +60,56 @@ namespace { } return label; } + + std::string summarizeAssets(const std::vector& assets) { + std::string results; + for (const std::string& a : assets) { + results += a + '\n'; + } + return results; + } + + std::string summarizeKeybindings(const std::vector& keybindings) + { + std::string results; + for (Profile::Keybinding k : keybindings) { + results += k.name + " ("; + int keymod = static_cast(k.key.modifier); + if (keymod != static_cast(openspace::KeyModifier::NoModifier)) { + results += openspace::KeyModifierNames.at(keymod) + "+"; + } + results += openspace::KeyNames.at(static_cast(k.key.key)); + results += ")\n"; + } + return results; + } + + std::string summarizeProperties(const std::vector& properties) { + std::string results; + for (openspace::Profile::Property p : properties) { + results += p.name + " = " + p.value + '\n'; + } + return results; + } } // namespace -using namespace openspace; - -ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, - std::vector& readOnlyProfiles, QWidget* parent) +ProfileEdit::ProfileEdit(Profile& profile, const std::string& profileName, + std::string assetBasePath, std::string profileBasePath, + const std::vector& readOnlyProfiles, + QWidget* parent) : QDialog(parent) - , _reportedAssets(reportedAssets) + , _assetBasePath(std::move(assetBasePath)) + , _profileBasePath(std::move(profileBasePath)) , _profile(profile) , _readOnlyProfiles(readOnlyProfiles) { setWindowTitle("Profile Editor"); + createWidgets(profileName); + initSummaryTextForEachCategory(); +} + +void ProfileEdit::createWidgets(const std::string& profileName) { QBoxLayout* layout = new QVBoxLayout(this); QBoxLayout* topLayout = new QHBoxLayout; QBoxLayout* leftLayout = new QVBoxLayout; @@ -70,7 +119,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, profileLabel->setObjectName("profile"); container->addWidget(profileLabel); - _profileEdit = new QLineEdit; + _profileEdit = new QLineEdit(QString::fromStdString(profileName)); container->addWidget(_profileEdit); QPushButton* duplicateButton = new QPushButton("Duplicate Profile"); @@ -82,12 +131,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, layout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QGridLayout* container = new QGridLayout; container->setColumnStretch(1, 1); @@ -110,12 +154,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, leftLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - leftLayout->addWidget(line); - } + leftLayout->addWidget(new Line); { QGridLayout* container = new QGridLayout; container->setColumnStretch(1, 1); @@ -135,12 +174,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, leftLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - leftLayout->addWidget(line); - } + leftLayout->addWidget(new Line); { QGridLayout* container = new QGridLayout; container->setColumnStretch(1, 1); @@ -165,12 +199,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, } topLayout->addLayout(leftLayout, 3); - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - topLayout->addWidget(line); - } + topLayout->addWidget(new Line); QBoxLayout* rightLayout = new QVBoxLayout; { @@ -186,12 +215,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, container->addWidget(metaEdit); rightLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - rightLayout->addWidget(line); - } + rightLayout->addWidget(new Line); { QBoxLayout* container = new QVBoxLayout; _interestingNodesLabel = new QLabel("Mark Interesting Nodes"); @@ -208,12 +232,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, container->addWidget(interestingNodesEdit); rightLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - rightLayout->addWidget(line); - } + rightLayout->addWidget(new Line); { QBoxLayout* container = new QVBoxLayout; _deltaTimesLabel = new QLabel("Simulation Time Increments"); @@ -230,12 +249,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, container->addWidget(deltaTimesEdit); rightLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - rightLayout->addWidget(line); - } + rightLayout->addWidget(new Line); { QBoxLayout* container = new QVBoxLayout; _cameraLabel = new QLabel("Camera"); @@ -249,12 +263,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, container->addWidget(cameraEdit); rightLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - rightLayout->addWidget(line); - } + rightLayout->addWidget(new Line); { QBoxLayout* container = new QVBoxLayout; _timeLabel = new QLabel("Time"); @@ -268,12 +277,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, container->addWidget(timeEdit); rightLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - rightLayout->addWidget(line); - } + rightLayout->addWidget(new Line); { QBoxLayout* container = new QVBoxLayout; _modulesLabel = new QLabel("Modules"); @@ -287,12 +291,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, container->addWidget(modulesEdit); rightLayout->addLayout(container); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - rightLayout->addWidget(line); - } + rightLayout->addWidget(new Line); { QBoxLayout* container = new QVBoxLayout; _additionalScriptsLabel = new QLabel("Additional Scripts"); @@ -312,12 +311,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, topLayout->addLayout(rightLayout); layout->addLayout(topLayout); - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QBoxLayout* footer = new QHBoxLayout; @@ -333,21 +327,23 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets, footer->addWidget(buttons); layout->addLayout(footer); } - - initSummaryTextForEachCategory(); } void ProfileEdit::initSummaryTextForEachCategory() { _modulesLabel->setText(labelText(_profile.modules().size(), "Modules")); _assetsLabel->setText(labelText(_profile.assets().size(), "Assets")); - _assetsEdit->setText(QString::fromStdString(summarizeAssets())); + _assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets()))); _propertiesLabel->setText(labelText(_profile.properties().size(), "Properties")); - _propertiesEdit->setText(QString::fromStdString(summarizeProperties())); + _propertiesEdit->setText( + QString::fromStdString(summarizeProperties(_profile.properties())) + ); _keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings")); - _keybindingsEdit->setText(QString::fromStdString(summarizeKeybindings())); + _keybindingsEdit->setText( + QString::fromStdString(summarizeKeybindings(_profile.keybindings())) + ); _deltaTimesLabel->setText( labelText(_profile.deltaTimes().size(), "Simulation Time Increments") @@ -357,28 +353,47 @@ void ProfileEdit::initSummaryTextForEachCategory() { ); } -void ProfileEdit::setProfileName(QString profileToSet) { - _profileEdit->setText(profileToSet); -} - void ProfileEdit::duplicateProfile() { - QString currentProfile = _profileEdit->text(); - if (!currentProfile.isEmpty()) { - QString duplicatedName = currentProfile + "_1"; - if ((currentProfile.length() > 2) - && (currentProfile.midRef(currentProfile.length() - 2, 1) == "_")) - { - QStringRef num = currentProfile.midRef(currentProfile.length() - 1, 1); - bool validConversion = false; - int val = num.toInt(&validConversion, 10); - if (validConversion && val < 9) { - duplicatedName = currentProfile.left(currentProfile.length() - 2) - + "_" + QString::number(val + 1); - } - } - _profileEdit->setText(duplicatedName); - } _errorMsg->clear(); + std::string profile = _profileEdit->text().toStdString(); + if (profile.empty()) { + return; + } + + constexpr const char Separator = '_'; + int version = 0; + if (size_t it = profile.rfind(Separator); it != std::string::npos) { + // If the value exists, we have a profile that potentially already has a version + // number attached to it + std::string versionStr = profile.substr(it + 1); + try { + version = std::stoi(versionStr); + + // We will re-add the separator with the new version string to the file, so we + // will remove the suffix here first + profile = profile.substr(0, it); + } + catch (const std::invalid_argument& e) { + // If this exception is thrown, we did find a separator character but the + // substring afterwards was not a number, so the user just added a separator + // by themselves. In this case we don't do anything + } + } + + // By this point we have our current profile (without any suffix) in 'profile' and the + // currently active version in 'version'. Now we need to put both together again and + // also make sure that we don't pick a version number that already exists + while (true) { + version++; + + std::string candidate = profile + Separator + std::to_string(version); + std::string candidatePath = _profileBasePath + candidate + ".profile"; + + if (!std::filesystem::exists(candidatePath)) { + _profileEdit->setText(QString::fromStdString(std::move(candidate))); + return; + } + } } void ProfileEdit::openMeta() { @@ -396,23 +411,25 @@ void ProfileEdit::openProperties() { _errorMsg->clear(); PropertiesDialog(_profile, this).exec(); _propertiesLabel->setText(labelText(_profile.properties().size(), "Properties")); - _propertiesEdit->setText(QString::fromStdString(summarizeProperties())); + _propertiesEdit->setText( + QString::fromStdString(summarizeProperties(_profile.properties())) + ); } void ProfileEdit::openKeybindings() { _errorMsg->clear(); KeybindingsDialog(_profile, this).exec(); _keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings")); - _keybindingsEdit->setText(QString::fromStdString(summarizeKeybindings())); + _keybindingsEdit->setText( + QString::fromStdString(summarizeKeybindings(_profile.keybindings())) + ); } void ProfileEdit::openAssets() { _errorMsg->clear(); - AssetsDialog assets(_profile, _reportedAssets, this); - assets.exec(); + AssetsDialog(_profile, _assetBasePath, this).exec(); _assetsLabel->setText(labelText(_profile.assets().size(), "Assets")); - _assetsEdit->setText(assets.createTextSummary()); - _assetsEdit->setText(QString::fromStdString(summarizeAssets())); + _assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets()))); } void ProfileEdit::openTime() { @@ -446,36 +463,6 @@ void ProfileEdit::openMarkNodes() { ); } -std::string ProfileEdit::summarizeProperties() { - std::string results; - for (openspace::Profile::Property p : _profile.properties()) { - results += p.name + " = " + p.value + '\n'; - } - return results; -} - -std::string ProfileEdit::summarizeKeybindings() { - std::string results; - for (openspace::Profile::Keybinding k : _profile.keybindings()) { - results += k.name + " ("; - int keymod = static_cast(k.key.modifier); - if (keymod != static_cast(openspace::KeyModifier::NoModifier)) { - results += openspace::KeyModifierNames.at(keymod) + "+"; - } - results += openspace::KeyNames.at(static_cast(k.key.key)); - results += ")\n"; - } - return results; -} - -std::string ProfileEdit::summarizeAssets() { - std::string results; - for (const std::string& a : _profile.assets()) { - results += a + '\n'; - } - return results; -} - bool ProfileEdit::wasSaved() const { return _saveSelected; } @@ -489,26 +476,22 @@ void ProfileEdit::cancel() { reject(); } -bool ProfileEdit::isReadOnly(std::string profileSave) { - auto it = std::find(_readOnlyProfiles.begin(), _readOnlyProfiles.end(), profileSave); - return !(it == _readOnlyProfiles.end()); -} - void ProfileEdit::approved() { - QString profileName = _profileEdit->text(); - if (profileName.isEmpty()) { + std::string profileName = _profileEdit->text().toStdString(); + if (profileName.empty()) { _errorMsg->setText("Profile name must be specified"); return; } - if ((profileName.length() > 0) && !isReadOnly(profileName.toStdString())) { + auto it = std::find(_readOnlyProfiles.begin(), _readOnlyProfiles.end(), profileName); + if (it == _readOnlyProfiles.end()) { _saveSelected = true; _errorMsg->setText(""); accept(); } else { _errorMsg->setText( - "This is a read-only profile. Click 'duplicate' or rename & save" + "This is a read-only profile. Click 'Duplicate' or rename & save" ); } } diff --git a/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp index 4608478841..5ae897d8b8 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp @@ -24,6 +24,7 @@ #include "profile/propertiesdialog.h" +#include "profile/line.h" #include #include #include @@ -38,7 +39,7 @@ using namespace openspace; namespace { - const Profile::Property kBlank { + const Profile::Property Blank { Profile::Property::SetType::SetPropertyValueSingle, "", "" @@ -51,7 +52,12 @@ PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent) , _data(_profile.properties()) { setWindowTitle("Set Property Values"); + createWidgets(); + transitionFromEditMode(); +} + +void PropertiesDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); { _list = new QListWidget; @@ -84,12 +90,7 @@ PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent) layout->addLayout(box); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { _commandLabel = new QLabel("Property Set Command"); layout->addWidget(_commandLabel); @@ -130,6 +131,7 @@ PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent) layout->addLayout(box); } } + layout->addWidget(new Line); { QBoxLayout* footerLayout = new QHBoxLayout; @@ -152,8 +154,6 @@ PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent) footerLayout->addWidget(_buttonBox); layout->addLayout(footerLayout); } - - transitionFromEditMode(); } QString PropertiesDialog::createOneLineSummary(Profile::Property p) { @@ -197,20 +197,20 @@ bool PropertiesDialog::isLineEmpty(int index) { return isEmpty; } -void PropertiesDialog::listItemAdded(void) { +void PropertiesDialog::listItemAdded() { int currentListSize = _list->count(); if ((currentListSize == 1) && (isLineEmpty(0))) { // Special case where list is "empty" but really has one line that is blank. // This is done because QListWidget does not seem to like having its sole // remaining item being removed. - _data.at(0) = kBlank; + _data.at(0) = Blank; _list->item(0)->setText(" (Enter details below & click 'Save')"); _list->setCurrentRow(0); transitionToEditMode(); } else { - _data.push_back(kBlank); + _data.push_back(Blank); _list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')")); //Scroll down to that blank line highlighted _list->setCurrentRow(_list->count() - 1); @@ -224,7 +224,7 @@ void PropertiesDialog::listItemAdded(void) { _editModeNewItem = true; } -void PropertiesDialog::listItemSave(void) { +void PropertiesDialog::listItemSave() { if (!areRequiredFormsFilled()) { return; } @@ -265,7 +265,7 @@ bool PropertiesDialog::areRequiredFormsFilled() { return requiredFormsFilled; } -void PropertiesDialog::listItemCancelSave(void) { +void PropertiesDialog::listItemCancelSave() { listItemSelected(); transitionFromEditMode(); if (_editModeNewItem) { @@ -278,13 +278,13 @@ void PropertiesDialog::listItemCancelSave(void) { _editModeNewItem = false; } -void PropertiesDialog::listItemRemove(void) { +void PropertiesDialog::listItemRemove() { if (_list->count() > 0) { if (_list->currentRow() >= 0 && _list->currentRow() < _list->count()) { if (_list->count() == 1) { //Special case where last remaining item is being removed (QListWidget // doesn't like the final item being removed so instead clear it) - _data.at(0) = kBlank; + _data.at(0) = Blank; _list->item(0)->setText(""); } else { @@ -301,7 +301,7 @@ void PropertiesDialog::listItemRemove(void) { transitionFromEditMode(); } -void PropertiesDialog::transitionToEditMode(void) { +void PropertiesDialog::transitionToEditMode() { _list->setDisabled(true); _addButton->setDisabled(true); _removeButton->setDisabled(true); @@ -316,7 +316,7 @@ void PropertiesDialog::transitionToEditMode(void) { _errorMsg->setText(""); } -void PropertiesDialog::transitionFromEditMode(void) { +void PropertiesDialog::transitionFromEditMode() { _list->setDisabled(false); _addButton->setDisabled(false); _removeButton->setDisabled(false); diff --git a/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp index 71d2966b89..678b5bf504 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp @@ -24,6 +24,7 @@ #include "profile/timedialog.h" +#include "profile/line.h" #include #include #include @@ -41,9 +42,32 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent) , _profile(profile) { setWindowTitle("Time"); + createWidgets(); + QStringList types = { "Absolute", "Relative" }; + _typeCombo->addItems(types); + if (_profile.time().has_value()) { + _data = *_profile.time(); + if (_data.type == Profile::Time::Type::Relative) { + if (_data.value == "") { + _data.value = "now"; + } + _relativeEdit->setSelection(0, _relativeEdit->text().length()); + } + else { + _absoluteEdit->setSelectedSection(QDateTimeEdit::YearSection); + } + } + else { + _data.type = Profile::Time::Type::Relative; + _data.value = "now"; + } + _initializedAsAbsolute = (_data.type == Profile::Time::Type::Absolute); + enableAccordingToType(static_cast(_data.type)); +} + +void TimeDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); - { layout->addWidget(new QLabel("Time Type")); _typeCombo = new QComboBox; @@ -71,12 +95,7 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent) ); layout->addWidget(_relativeEdit); } - { - QFrame* line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); - } + layout->addWidget(new Line); { QDialogButtonBox* buttons = new QDialogButtonBox; buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); @@ -85,29 +104,6 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent) QObject::connect(buttons, &QDialogButtonBox::rejected, this, &TimeDialog::reject); layout->addWidget(buttons); } - - - - QStringList types { "Absolute", "Relative" }; - _typeCombo->addItems(types); - if (_profile.time().has_value()) { - _data = *_profile.time(); - if (_data.type == Profile::Time::Type::Relative) { - if (_data.value == "") { - _data.value = "now"; - } - _relativeEdit->setSelection(0, _relativeEdit->text().length()); - } - else { - _absoluteEdit->setSelectedSection(QDateTimeEdit::YearSection); - } - } - else { - _data.type = Profile::Time::Type::Relative; - _data.value = "now"; - } - _initializedAsAbsolute = (_data.type == Profile::Time::Type::Absolute); - enableAccordingToType(static_cast(_data.type)); } void TimeDialog::enableAccordingToType(int idx) { diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 8684d9d744..d7d4c60fd5 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -927,29 +927,29 @@ void setSgctDelegateFunctions() { }; } -void analyzeCommandLineArgsForSettings(int& argc, char** argv, bool& sgct, bool& profile, - std::string& sgctFunctionName) +void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& hasProfile, + std::string& sgctFunctionName) { - bool haveCliConfigFlag = false; for (int i = 1; i < argc; ++i) { - std::string a = argv[i]; - if (a.compare("-c") == 0 || a.compare("--config") == 0) { - haveCliConfigFlag = true; - } - else if (haveCliConfigFlag) { - a.erase(remove_if(a.begin(), a.end(), isspace), a.end()); + const std::string arg = argv[i]; + if (arg == "-c" || arg == "--config") { + std::string p = ((i + 1) < argc) ? argv[i + 1] : ""; + p.erase(std::remove_if(p.begin(), p.end(), ::isspace), p.end()); + const std::string sgctAssignment = "SGCTConfig="; - size_t findSgct = a.find(sgctAssignment); - size_t findBracket = a.find("}"); + const size_t findSgct = p.find(sgctAssignment); + const size_t findBracket = p.find("}"); if (findSgct != std::string::npos) { if (findBracket != std::string::npos) { - sgctFunctionName = a.substr(findSgct + sgctAssignment.length(), - findBracket - findSgct); + sgctFunctionName = arg.substr( + findSgct + sgctAssignment.length(), + findBracket - findSgct + ); } - sgct = true; + hasSGCT = true; } - if (a.find("Profile=") != std::string::npos) { - profile = true; + if (p.find("Profile=") != std::string::npos) { + hasProfile = true; } } } @@ -959,40 +959,35 @@ std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile, const std::string xmlExt, bool haveCliSGCTConfig, const std::string& sgctFunctionName) { - const std::string labelFromCli = " (from CLI)"; + configuration::Configuration& config = global::configuration; + std::string preset; - bool sgctConfigFileSpecifiedByLuaFunction - = (global::configuration.sgctConfigNameInitialized.length() > 0); + bool sgctConfigFileSpecifiedByLuaFunction = !config.sgctConfigNameInitialized.empty(); if (haveCliSGCTConfig) { - preset = (sgctFunctionName.length() > 0) ? sgctFunctionName - : global::configuration.windowConfiguration; - preset += labelFromCli; + preset = sgctFunctionName.empty() ? config.windowConfiguration : sgctFunctionName; + preset += " (from CLI)"; } else if (sgctConfigFileSpecifiedByLuaFunction) { - preset = global::configuration.sgctConfigNameInitialized; - preset += labelFromCfgFile; + preset = config.sgctConfigNameInitialized + labelFromCfgFile; } else { - preset = global::configuration.windowConfiguration; - if (preset.find("/") != std::string::npos) { - preset.erase(0, preset.find_last_of("/") + 1); + preset = config.windowConfiguration; + if (preset.find('/') != std::string::npos) { + preset.erase(0, preset.find_last_of('/') + 1); } if (preset.length() >= xmlExt.length()) { - if (preset.substr(preset.length() - xmlExt.length()) - .compare(xmlExt) == 0) - { - preset = preset.substr(0, preset.length() - - xmlExt.length()); + if (preset.substr(preset.length() - xmlExt.length()) == xmlExt) { + preset = preset.substr(0, preset.length() - xmlExt.length()); } } } return preset; } -std::string getSelectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTConfig, - std::string windowConfiguration, - const std::string& labelFromCfgFile, - const std::string& xmlExt) +std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTConfig, + std::string windowConfiguration, + const std::string& labelFromCfgFile, + const std::string& xmlExt) { std::string config = windowConfiguration; if (!hasCliSGCTConfig) { @@ -1152,39 +1147,40 @@ int main(int argc, char** argv) { global::openSpaceEngine.registerPathTokens(); - bool haveCliSGCTConfig = false; - bool haveCliProfile = false; - std::string sgctFunctionName; - analyzeCommandLineArgsForSettings(argc, argv, haveCliSGCTConfig, haveCliProfile, - sgctFunctionName); - //Call profile GUI + bool hasSGCTConfig = false; + bool hasProfile = false; + std::string sgctFunctionName; + checkCommandLineForSettings(argc, argv, hasSGCTConfig, hasProfile, sgctFunctionName); + + // Call profile GUI const std::string labelFromCfgFile = " (from .cfg)"; const std::string xmlExt = ".xml"; - std::string windowCfgPreset = setWindowConfigPresetForGui(labelFromCfgFile, xmlExt, - haveCliSGCTConfig, sgctFunctionName); + std::string windowCfgPreset = setWindowConfigPresetForGui( + labelFromCfgFile, + xmlExt, + hasSGCTConfig, + sgctFunctionName + ); - std::shared_ptr qaobj; - std::shared_ptr launchwin; - bool skipLauncherSinceProfileAndWindowAreConfiguredInCli = - (haveCliProfile && haveCliSGCTConfig) || global::configuration.bypassLauncher; - - if (!skipLauncherSinceProfileAndWindowAreConfiguredInCli) { + bool skipLauncher = + (hasProfile && hasSGCTConfig) || global::configuration.bypassLauncher; + if (!skipLauncher) { int qac = 0; - qaobj.reset(new QApplication(qac, nullptr)); - launchwin.reset(new LauncherWindow(absPath("${BASE}"), !haveCliProfile, - global::configuration, !haveCliSGCTConfig, windowCfgPreset, nullptr)); - launchwin->show(); - qaobj->exec(); + QApplication app(qac, nullptr); + LauncherWindow win(!hasProfile, + global::configuration, !hasSGCTConfig, windowCfgPreset, nullptr); + win.show(); + app.exec(); - if (!launchwin->wasLaunchSelected()) { - exit(EXIT_FAILURE); + if (!win.wasLaunchSelected()) { + exit(EXIT_SUCCESS); } - global::configuration.profile = launchwin->selectedProfile(); - windowConfiguration = getSelectedSgctProfileFromLauncher( - *launchwin, - haveCliSGCTConfig, + global::configuration.profile = win.selectedProfile(); + windowConfiguration = selectedSgctProfileFromLauncher( + win, + hasSGCTConfig, windowConfiguration, labelFromCfgFile, xmlExt @@ -1305,13 +1301,6 @@ int main(int argc, char** argv) { } #endif // OPENSPACE_HAS_SPOUT - if (launchwin != nullptr) { - launchwin->close(); - } - if (qaobj != nullptr) { - qaobj->quit(); - } - ghoul::deinitialize(); exit(EXIT_SUCCESS); }