diff --git a/data/scene/atmosphereearth.scene b/data/scene/atmosphereearth.scene index bbfaf10dd1..4bfbb611d8 100644 --- a/data/scene/atmosphereearth.scene +++ b/data/scene/atmosphereearth.scene @@ -19,6 +19,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", true) diff --git a/data/scene/dawn.scene b/data/scene/dawn.scene index 6dddbc93fd..17af47aae4 100644 --- a/data/scene/dawn.scene +++ b/data/scene/dawn.scene @@ -19,6 +19,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", true) diff --git a/data/scene/default.scene b/data/scene/default.scene index 784ad59f1c..051c39c1ef 100644 --- a/data/scene/default.scene +++ b/data/scene/default.scene @@ -74,6 +74,8 @@ function preInitialization() end function postInitialization() + set_default_gui_sorting() + openspace.addVirtualProperty( "BoolProperty", "Show Trails", diff --git a/data/scene/fieldlines.scene b/data/scene/fieldlines.scene index 2a9da28b7c..f83e512809 100644 --- a/data/scene/fieldlines.scene +++ b/data/scene/fieldlines.scene @@ -19,6 +19,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", false) diff --git a/data/scene/juno.scene b/data/scene/juno.scene index 89b3c8374a..1a9a1a3924 100755 --- a/data/scene/juno.scene +++ b/data/scene/juno.scene @@ -27,6 +27,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", true) diff --git a/data/scene/milkyway/digitaluniverse/digitaluniverse.mod b/data/scene/milkyway/digitaluniverse/digitaluniverse.mod index 95a3dd81b2..debbcdfa69 100644 --- a/data/scene/milkyway/digitaluniverse/digitaluniverse.mod +++ b/data/scene/milkyway/digitaluniverse/digitaluniverse.mod @@ -7,7 +7,7 @@ return { Size = 9.2E20, Segments = 40, Alpha = 0.4, - Texture = "textures/DarkUniverse_mellinger_8k.jpg", + Texture = "textures/DarkUniverse_mellinger_4k.jpg", Orientation = "Inside/Outside", FadeOutThreshould = 0.25 }, diff --git a/data/scene/newhorizons.scene b/data/scene/newhorizons.scene index ee57e63c69..0dd32ec865 100644 --- a/data/scene/newhorizons.scene +++ b/data/scene/newhorizons.scene @@ -28,6 +28,7 @@ function preInitialization() which the scene should start and other settings that might determine initialization critical objects. ]]-- + set_default_gui_sorting() openspace.spice.loadKernel("${SPICE}/naif0012.tls") openspace.spice.loadKernel("${SPICE}/pck00010.tpc") diff --git a/data/scene/osirisrex.scene b/data/scene/osirisrex.scene index 946582269a..a1b21a8e3c 100644 --- a/data/scene/osirisrex.scene +++ b/data/scene/osirisrex.scene @@ -83,6 +83,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", false) diff --git a/data/scene/rosetta.scene b/data/scene/rosetta.scene index 3341deb7af..213ec20465 100644 --- a/data/scene/rosetta.scene +++ b/data/scene/rosetta.scene @@ -93,6 +93,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", true) diff --git a/data/scene/volumetricmilkyway.scene b/data/scene/volumetricmilkyway.scene index 7a0708ea32..4b2b5ecabf 100644 --- a/data/scene/volumetricmilkyway.scene +++ b/data/scene/volumetricmilkyway.scene @@ -19,6 +19,8 @@ function postInitialization() created and initialized, but before the first render call. This is the place to set graphical settings for the renderables. ]]-- + set_default_gui_sorting() + openspace.printInfo("Setting default values") openspace.setPropertyValue("Sun.renderable.Enabled", false) openspace.setPropertyValue("SunMarker.renderable.Enabled", true) diff --git a/data/scene/voyager.scene b/data/scene/voyager.scene index 7d6b0430e1..4b3d77c7fc 100644 --- a/data/scene/voyager.scene +++ b/data/scene/voyager.scene @@ -19,6 +19,8 @@ end function postInitialization() openspace.printInfo("Setting default values") + set_default_gui_sorting() + openspace.setPropertyValueSingle("Global Properties.GlobeBrowsing.GdalWrapper.LogGdalErrors", false) openspace.setPropertyValueSingle("Earth.RenderableGlobe.Debug.LevelByProjectedAreaElseDistance", false) diff --git a/ext/ghoul b/ext/ghoul index ecb186c4ec..347e2bba03 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit ecb186c4eca7feeff3d970234d6e3b4b213a640a +Subproject commit 347e2bba03d2788b3ec6ea2031b05675a9dd8dcb diff --git a/include/openspace/properties/numericalproperty.h b/include/openspace/properties/numericalproperty.h index 9bf680556c..16f3bee541 100644 --- a/include/openspace/properties/numericalproperty.h +++ b/include/openspace/properties/numericalproperty.h @@ -38,6 +38,8 @@ public: T maximumValue); NumericalProperty(Property::PropertyInfo info, T value, T minimumValue, T maximumValue, T steppingValue); + NumericalProperty(Property::PropertyInfo info, T value, T minimumValue, + T maximumValue, T steppingValue, float exponent); bool getLuaValue(lua_State* state) const override; bool setLuaValue(lua_State* state) override; @@ -52,6 +54,12 @@ public: T maxValue() const; void setMaxValue(T value); + T steppingValue() const; + void setSteppingValue(T value); + + float exponent() const; + void setExponent(float exponent); + virtual std::string className() const override; using TemplateProperty::operator=; @@ -60,12 +68,14 @@ protected: static const std::string MinimumValueKey; static const std::string MaximumValueKey; static const std::string SteppingValueKey; + static const std::string ExponentValueKey; std::string generateAdditionalDescription() const override; T _minimumValue; T _maximumValue; T _stepping; + float _exponent; }; } // namespace openspace::properties diff --git a/include/openspace/properties/numericalproperty.inl b/include/openspace/properties/numericalproperty.inl index 95b027b692..671e2e7fd2 100644 --- a/include/openspace/properties/numericalproperty.inl +++ b/include/openspace/properties/numericalproperty.inl @@ -229,6 +229,9 @@ const std::string NumericalProperty::MaximumValueKey = "MaximumValue"; template const std::string NumericalProperty::SteppingValueKey = "SteppingValue"; +template +const std::string NumericalProperty::ExponentValueKey = "Exponent"; + // Delegating constructors are necessary; automatic template deduction cannot // deduce template argument for 'U' if 'default' methods are used as default values in // a single constructor @@ -240,7 +243,8 @@ NumericalProperty::NumericalProperty(Property::PropertyInfo info) PropertyDelegate>::template defaultValue(), PropertyDelegate>::template defaultMinimumValue(), PropertyDelegate>::template defaultMaximumValue(), - PropertyDelegate>::template defaultSteppingValue() + PropertyDelegate>::template defaultSteppingValue(), + 1.f ) {} @@ -251,7 +255,8 @@ NumericalProperty::NumericalProperty(Property::PropertyInfo info, T value) std::move(value), PropertyDelegate>::template defaultMinimumValue(), PropertyDelegate>::template defaultMaximumValue(), - PropertyDelegate>::template defaultSteppingValue() + PropertyDelegate>::template defaultSteppingValue(), + 1.f ) {} @@ -260,18 +265,36 @@ NumericalProperty::NumericalProperty(Property::PropertyInfo info, T value, T minimumValue, T maximumValue) : NumericalProperty( std::move(info), - std::move(value), std::move(minimumValue), std::move(maximumValue), - PropertyDelegate>::template defaultSteppingValue() + std::move(value), + std::move(minimumValue), + std::move(maximumValue), + PropertyDelegate>::template defaultSteppingValue(), + 1.f ) {} template NumericalProperty::NumericalProperty(Property::PropertyInfo info, T value, T minimumValue, T maximumValue, T steppingValue) + : NumericalProperty( + std::move(info), + std::move(value), + std::move(minimumValue), + std::move(maximumValue), + std::move(steppingValue), + 1.f + ) +{} + +template +NumericalProperty::NumericalProperty(Property::PropertyInfo info, T value, + T minimumValue, T maximumValue, T steppingValue, + float exponent) : TemplateProperty(std::move(info), std::move(value)) , _minimumValue(std::move(minimumValue)) , _maximumValue(std::move(maximumValue)) , _stepping(std::move(steppingValue)) + , _exponent(exponent) {} template @@ -342,12 +365,33 @@ void NumericalProperty::setMaxValue(T value) { _maximumValue = std::move(value); } +template +T NumericalProperty::steppingValue() const { + return _steppingValue; +} + +template +void NumericalProperty::setSteppingValue(T value) { + _steppingValue = std::move(value); +} + +template +float NumericalProperty::exponent() const { + return _exponent; +} + +template +void NumericalProperty::setExponent(float exponent) { + _exponent = exponent; +} + template std::string NumericalProperty::generateAdditionalDescription() const { std::string result; result += MinimumValueKey + " = " + std::to_string(_minimumValue) + ","; result += MaximumValueKey + " = " + std::to_string(_maximumValue) + ","; - result += SteppingValueKey + " = " + std::to_string(_stepping); + result += SteppingValueKey + " = " + std::to_string(_stepping) + ","; + result += ExponentValueKey + " = " + std::to_string(_exponent); return result; } diff --git a/include/openspace/properties/stringlistproperty.h b/include/openspace/properties/stringlistproperty.h new file mode 100644 index 0000000000..0d45ae5c82 --- /dev/null +++ b/include/openspace/properties/stringlistproperty.h @@ -0,0 +1,39 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_CORE___STRINGLISTPROPERTY___H__ +#define __OPENSPACE_CORE___STRINGLISTPROPERTY___H__ + +#include + +#include +#include + +namespace openspace::properties { + +REGISTER_TEMPLATEPROPERTY_HEADER(StringListProperty, std::vector) + +} // namespace openspace::properties + +#endif // __OPENSPACE_CORE___STRINGLISTPROPERTY___H__ diff --git a/include/openspace/rendering/loadingscreen.h b/include/openspace/rendering/loadingscreen.h index 1ae6525a85..8870f9ac59 100644 --- a/include/openspace/rendering/loadingscreen.h +++ b/include/openspace/rendering/loadingscreen.h @@ -51,6 +51,7 @@ public: using ShowMessage = ghoul::Boolean; using ShowNodeNames = ghoul::Boolean; using ShowProgressbar = ghoul::Boolean; + using CatastrophicError = ghoul::Boolean; LoadingScreen(ShowMessage showMessage, ShowNodeNames showNodeNames, ShowProgressbar showProgressbar); @@ -59,6 +60,7 @@ public: void render(); void postMessage(std::string message); + void setCatastrophicError(CatastrophicError catastrophicError); void finalize(); @@ -110,6 +112,7 @@ private: GLuint vboBox; } _progressbar; + bool _hasCatastrophicErrorOccurred; std::string _message; std::mutex _messageMutex; @@ -118,9 +121,6 @@ private: ItemStatus status; bool hasLocation; -#ifdef LOADINGSCREEN_DEBUGGING - bool exhaustedSearch; -#endif // LOADINGSCREEN_DEBUGGING glm::vec2 ll; glm::vec2 ur; diff --git a/include/openspace/util/camera.h b/include/openspace/util/camera.h index 5020ca2641..f8c6467e4a 100644 --- a/include/openspace/util/camera.h +++ b/include/openspace/util/camera.h @@ -160,22 +160,22 @@ public: } sgctInternal; // Deprecated - [[deprecated("Replaced by Camera::setPositionVec3()")]] + // [[deprecated("Replaced by Camera::setPositionVec3()")]] void setPosition(psc pos); - [[deprecated("Replaced by Camera::setFocusPositionVec3()")]] + // [[deprecated("Replaced by Camera::setFocusPositionVec3()")]] void setFocusPosition(psc pos); - [[deprecated("Replaced by Camera::positionVec3()")]] + // [[deprecated("Replaced by Camera::positionVec3()")]] psc position() const; - [[deprecated("Replaced by Camera::unsynchedPositionVec3()")]] + // [[deprecated("Replaced by Camera::unsynchedPositionVec3()")]] psc unsynchedPosition() const; - [[deprecated("Replaced by Camera::focusPositionVec3()")]] + // [[deprecated("Replaced by Camera::focusPositionVec3()")]] psc focusPosition() const; // @TODO use Camera::SgctInternal interface instead - [[deprecated("Replaced by Camera::SgctInternal::viewMatrix()")]] + // [[deprecated("Replaced by Camera::SgctInternal::viewMatrix()")]] const glm::mat4& viewMatrix() const; - [[deprecated("Replaced by Camera::SgctInternal::projectionMatrix()")]] + // [[deprecated("Replaced by Camera::SgctInternal::projectionMatrix()")]] const glm::mat4& projectionMatrix() const; - [[deprecated("Replaced by Camera::SgctInternal::viewProjectionMatrix()")]] + // [[deprecated("Replaced by Camera::SgctInternal::viewProjectionMatrix()")]] const glm::mat4& viewProjectionMatrix() const; diff --git a/modules/imgui/imguimodule.cpp b/modules/imgui/imguimodule.cpp index c76772e64f..10c0d1360b 100644 --- a/modules/imgui/imguimodule.cpp +++ b/modules/imgui/imguimodule.cpp @@ -189,7 +189,10 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { OsEng.registerModuleKeyboardCallback( [&](Key key, KeyModifier mod, KeyAction action) -> bool { - if (gui.isEnabled() || gui._performance.isEnabled()) { + // A list of all the windows that can show up by themselves + if (gui.isEnabled() || gui._performance.isEnabled() || + gui._property.isEnabled()) + { return gui.keyCallback(key, mod, action); } else { @@ -200,7 +203,10 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { OsEng.registerModuleCharCallback( [&](unsigned int codepoint, KeyModifier modifier) -> bool { - if (gui.isEnabled() || gui._performance.isEnabled()) { + // A list of all the windows that can show up by themselves + if (gui.isEnabled() || gui._performance.isEnabled() || + gui._property.isEnabled()) + { return gui.charCallback(codepoint, modifier); } else { @@ -211,7 +217,10 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { OsEng.registerModuleMouseButtonCallback( [&](MouseButton button, MouseAction action) -> bool { - if (gui.isEnabled() || gui._performance.isEnabled()) { + // A list of all the windows that can show up by themselves + if (gui.isEnabled() || gui._performance.isEnabled() || + gui._property.isEnabled()) + { return gui.mouseButtonCallback(button, action); } else { @@ -222,7 +231,10 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { OsEng.registerModuleMouseScrollWheelCallback( [&](double, double posY) -> bool { - if (gui.isEnabled() || gui._performance.isEnabled()) { + // A list of all the windows that can show up by themselves + if (gui.isEnabled() || gui._performance.isEnabled() || + gui._property.isEnabled()) + { return gui.mouseWheelCallback(posY); } else { diff --git a/modules/imgui/include/gui.h b/modules/imgui/include/gui.h index 7d89e05550..13d15626f5 100644 --- a/modules/imgui/include/gui.h +++ b/modules/imgui/include/gui.h @@ -94,6 +94,8 @@ private: properties::Property::Visibility _currentVisibility; + properties::BoolProperty _allHidden; + std::vector _contexts; }; diff --git a/modules/imgui/include/guicomponent.h b/modules/imgui/include/guicomponent.h index 1821957e4b..9d6e16a998 100644 --- a/modules/imgui/include/guicomponent.h +++ b/modules/imgui/include/guicomponent.h @@ -72,6 +72,9 @@ public: protected: /// true if this component is enabled and visible on the screen properties::BoolProperty _isEnabled; + /// if true this window is currently collapsed. This setting mirrors the + /// ImGui internal state of the window + properties::BoolProperty _isCollapsed; }; } // namespace openspace::gui diff --git a/modules/imgui/include/guipropertycomponent.h b/modules/imgui/include/guipropertycomponent.h index 1a7078d898..b467b2bfe7 100644 --- a/modules/imgui/include/guipropertycomponent.h +++ b/modules/imgui/include/guipropertycomponent.h @@ -28,6 +28,8 @@ #include #include +#include +#include #include @@ -47,11 +49,9 @@ public: using SourceFunction = std::function()>; using UseTreeLayout = ghoul::Boolean; - using IsTopLevelWindow = ghoul::Boolean; - GuiPropertyComponent(std::string name, UseTreeLayout useTree = UseTreeLayout::No, - IsTopLevelWindow isTopLevel = IsTopLevelWindow::No); + GuiPropertyComponent(std::string name, UseTreeLayout useTree = UseTreeLayout::No); // This is the function that evaluates to the list of Propertyowners that this // component should render @@ -74,9 +74,10 @@ protected: /// are regular, i.e., not containing wildcards, regex, or groups /// This variable only has an impact on which \c setPropertyValue function is called bool _hasOnlyRegularProperties = false; - UseTreeLayout _useTreeLayout; - bool _currentUseTreeLayout; - IsTopLevelWindow _isTopLevel; + + properties::BoolProperty _useTreeLayout; + properties::StringListProperty _treeOrdering; + bool _showHelpTooltip; }; diff --git a/modules/imgui/include/guispacetimecomponent.h b/modules/imgui/include/guispacetimecomponent.h index 726cea870c..872b2bb4c7 100644 --- a/modules/imgui/include/guispacetimecomponent.h +++ b/modules/imgui/include/guispacetimecomponent.h @@ -27,6 +27,8 @@ #include +#include + namespace openspace::gui { class GuiSpaceTimeComponent : public GuiComponent { @@ -34,6 +36,10 @@ public: GuiSpaceTimeComponent(); void render() override; + +private: + properties::FloatProperty _minMaxDeltaTime; + float _localMinMaxDeltatime; // We don't want the default display inside the component }; } // namespace openspace::gui diff --git a/modules/imgui/include/renderproperties.h b/modules/imgui/include/renderproperties.h index 497209b318..ee61492052 100644 --- a/modules/imgui/include/renderproperties.h +++ b/modules/imgui/include/renderproperties.h @@ -57,6 +57,10 @@ void renderStringProperty(properties::Property* prop, const std::string& ownerNa IsRegularProperty isRegular = IsRegularProperty::Yes, ShowToolTip showTooltip = ShowToolTip::Yes); +void renderStringListProperty(properties::Property* prop, const std::string& ownerName, + IsRegularProperty isRegular = IsRegularProperty::Yes, + ShowToolTip showTooltip = ShowToolTip::Yes); + void renderDoubleProperty(properties::Property* prop, const std::string& ownerName, IsRegularProperty isRegular = IsRegularProperty::Yes, ShowToolTip showTooltip = ShowToolTip::Yes); diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index 49541bce94..06b95087e0 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -253,6 +253,13 @@ static const openspace::properties::Property::PropertyInfo ShowHelpInfo = { "explaining what impact they have on the visuals." }; +static const openspace::properties::Property::PropertyInfo HiddenInfo = { + "IsHidden", + "Is Hidden", + "If this value is true, all GUI items will not be rendered, regardless of their " + "status" +}; + } // namespace namespace openspace::gui { @@ -272,23 +279,25 @@ GUI::GUI() ) , _screenSpaceProperty("ScreenSpace Properties") , _virtualProperty("Virtual Properties") - , _featuredProperties("Featured Properties", - GuiPropertyComponent::UseTreeLayout::No, - GuiPropertyComponent::IsTopLevelWindow::Yes) + , _featuredProperties("Featured Properties", GuiPropertyComponent::UseTreeLayout::No) , _showInternals(false) , _showHelpText(ShowHelpInfo, true) , _currentVisibility(properties::Property::Visibility::Developer) + , _allHidden(HiddenInfo, true) { addPropertySubOwner(_help); addPropertySubOwner(_performance); addPropertySubOwner(_globalProperty); addPropertySubOwner(_property); addPropertySubOwner(_screenSpaceProperty); + _featuredProperties.setEnabled(true); + addPropertySubOwner(_featuredProperties); addPropertySubOwner(_virtualProperty); #ifdef GLOBEBROWSING_USE_GDAL addPropertySubOwner(_globeBrowsing); #endif // GLOBEBROWSING_USE_GDAL addPropertySubOwner(_filePath); + _spaceTime.setEnabled(true); addPropertySubOwner(_spaceTime); addPropertySubOwner(_mission); #ifdef OPENSPACE_MODULE_ISWA_ENABLED @@ -302,6 +311,8 @@ GUI::GUI() _screenSpaceProperty.setShowHelpTooltip(_showHelpText); _virtualProperty.setShowHelpTooltip(_showHelpText); }); + + addProperty(_allHidden); } void GUI::initialize() { @@ -626,8 +637,11 @@ void GUI::endFrame() { _performance.render(); } - if (_isEnabled) { - render(); + if (!_allHidden) { + + if (_isEnabled) { + render(); + } if (_globalProperty.isEnabled()) { _globalProperty.render(); @@ -666,11 +680,13 @@ void GUI::endFrame() { _mission.render(); } - // We always want to render the Space/Time component - _spaceTime.render(); + if (_spaceTime.isEnabled()) { + _spaceTime.render(); + } - // We always want to render the featured properties component - _featuredProperties.render(); + if (_featuredProperties.isEnabled()) { + _featuredProperties.render(); + } } ImGui::Render(); @@ -744,7 +760,11 @@ bool GUI::charCallback(unsigned int character, KeyModifier) { } void GUI::render() { + ImGui::SetNextWindowCollapsed(_isCollapsed); + ImGui::Begin("OpenSpace GUI", nullptr); + + _isCollapsed = ImGui::IsWindowCollapsed(); bool property = _property.isEnabled(); ImGui::Checkbox("Scene Graph Properties", &property); @@ -754,10 +774,18 @@ void GUI::render() { ImGui::Checkbox("ScreenSpace Properties", &screenSpaceProperty); _screenSpaceProperty.setEnabled(screenSpaceProperty); + bool featuredProperties = _featuredProperties.isEnabled(); + ImGui::Checkbox("Featured Properties", &featuredProperties); + _featuredProperties.setEnabled(featuredProperties); + bool globalProperty = _globalProperty.isEnabled(); ImGui::Checkbox("Global Properties", &globalProperty); _globalProperty.setEnabled(globalProperty); + bool spacetime = _spaceTime.isEnabled(); + ImGui::Checkbox("Space/Time", &spacetime); + _spaceTime.setEnabled(spacetime); + bool parallel = _parallel.isEnabled(); ImGui::Checkbox("Parallel Connection", ¶llel); _parallel.setEnabled(parallel); diff --git a/modules/imgui/src/guicomponent.cpp b/modules/imgui/src/guicomponent.cpp index 98ea884383..eab952eb7d 100644 --- a/modules/imgui/src/guicomponent.cpp +++ b/modules/imgui/src/guicomponent.cpp @@ -30,6 +30,12 @@ namespace { "Is Enabled", "This setting determines whether this object will be visible or not." }; + + static const openspace::properties::Property::PropertyInfo CollapsedInfo = { + "Collapsed", + "Is Collapsed", + "This setting determines whether this window is collapsed or not." + }; } // namespace namespace openspace::gui { @@ -37,8 +43,10 @@ namespace openspace::gui { GuiComponent::GuiComponent(std::string name) : properties::PropertyOwner({ std::move(name) }) , _isEnabled(EnabledInfo, false) + , _isCollapsed(CollapsedInfo, false) { addProperty(_isEnabled); + addProperty(_isCollapsed); } bool GuiComponent::isEnabled() const { diff --git a/modules/imgui/src/guifilepathcomponent.cpp b/modules/imgui/src/guifilepathcomponent.cpp index 84fdef894f..d137fde5e2 100644 --- a/modules/imgui/src/guifilepathcomponent.cpp +++ b/modules/imgui/src/guifilepathcomponent.cpp @@ -35,8 +35,11 @@ GuiFilePathComponent::GuiFilePathComponent() {} void GuiFilePathComponent::render() { + ImGui::SetNextWindowCollapsed(_isCollapsed); + bool v = _isEnabled; ImGui::Begin("File Path", &v); + _isCollapsed = ImGui::IsWindowCollapsed(); ImGui::Text( "%s", diff --git a/modules/imgui/src/guiglobebrowsingcomponent.cpp b/modules/imgui/src/guiglobebrowsingcomponent.cpp index cee66900d8..4bfe79cd19 100644 --- a/modules/imgui/src/guiglobebrowsingcomponent.cpp +++ b/modules/imgui/src/guiglobebrowsingcomponent.cpp @@ -63,10 +63,13 @@ void GuiGlobeBrowsingComponent::render() { using Capabilities = GlobeBrowsingModule::Capabilities; using Layer = GlobeBrowsingModule::Layer; + ImGui::SetNextWindowCollapsed(_isCollapsed); + bool e = _isEnabled; ImGui::Begin("Globe Browsing", &e, WindowSize, 0.5f); _isEnabled = e; + _isCollapsed = ImGui::IsWindowCollapsed(); OnExit([]() {ImGui::End(); }); // We escape early from this function in a few places diff --git a/modules/imgui/src/guihelpcomponent.cpp b/modules/imgui/src/guihelpcomponent.cpp index 997ab5cb1b..ba979d78dc 100644 --- a/modules/imgui/src/guihelpcomponent.cpp +++ b/modules/imgui/src/guihelpcomponent.cpp @@ -37,9 +37,12 @@ GuiHelpComponent::GuiHelpComponent() {} void GuiHelpComponent::render() { + ImGui::SetNextWindowCollapsed(_isCollapsed); + bool v = _isEnabled; ImGui::Begin("Help", &v, size, 0.5f); _isEnabled = v; + _isCollapsed = ImGui::IsWindowCollapsed(); ImGui::ShowUserGuide(); ImGui::End(); } diff --git a/modules/imgui/src/guiiswacomponent.cpp b/modules/imgui/src/guiiswacomponent.cpp index ef742966b6..bf363a4c1a 100644 --- a/modules/imgui/src/guiiswacomponent.cpp +++ b/modules/imgui/src/guiiswacomponent.cpp @@ -54,11 +54,12 @@ void GuiIswaComponent::render() { bool oldGmImageValue = _gmImage; bool oldIonDataValue = _ionData; + ImGui::SetNextWindowCollapsed(_isCollapsed); + bool e = _isEnabled; - ImGui::Begin("ISWA", &e, WindowSize, 0.5f); - _isEnabled = e; + _isCollapsed = ImGui::IsWindowCollapsed(); ImGui::Text("Global Magnetosphere"); ImGui::Checkbox("Gm From Data", &_gmData); ImGui::SameLine(); diff --git a/modules/imgui/src/guimissioncomponent.cpp b/modules/imgui/src/guimissioncomponent.cpp index 1d64832502..263311dab8 100644 --- a/modules/imgui/src/guimissioncomponent.cpp +++ b/modules/imgui/src/guimissioncomponent.cpp @@ -98,9 +98,12 @@ namespace openspace::gui { GuiMissionComponent::GuiMissionComponent() : GuiComponent("Mission Information") {} void GuiMissionComponent::render() { + ImGui::SetNextWindowCollapsed(_isCollapsed); bool v = _isEnabled; ImGui::Begin(name().c_str(), &v, Size, 0.75f); _isEnabled = v; + + _isCollapsed = ImGui::IsWindowCollapsed(); ghoul_assert( MissionManager::ref().hasCurrentMission(), diff --git a/modules/imgui/src/guiparallelcomponent.cpp b/modules/imgui/src/guiparallelcomponent.cpp index 25b21479cb..25f599f0b0 100644 --- a/modules/imgui/src/guiparallelcomponent.cpp +++ b/modules/imgui/src/guiparallelcomponent.cpp @@ -159,9 +159,11 @@ void GuiParallelComponent::renderHost() { void GuiParallelComponent::render() { + ImGui::SetNextWindowCollapsed(_isCollapsed); bool v = _isEnabled; ImGui::Begin("Parallel Connection", &v); _isEnabled = v; + _isCollapsed = ImGui::IsWindowCollapsed(); ParallelConnection::Status status = OsEng.parallelConnection().status(); diff --git a/modules/imgui/src/guiperformancecomponent.cpp b/modules/imgui/src/guiperformancecomponent.cpp index 26cee553c2..68211ae965 100644 --- a/modules/imgui/src/guiperformancecomponent.cpp +++ b/modules/imgui/src/guiperformancecomponent.cpp @@ -97,9 +97,12 @@ void GuiPerformanceComponent::render() { using ghoul::SharedMemory; using namespace performance; + ImGui::SetNextWindowCollapsed(_isCollapsed); bool v = _isEnabled; ImGui::Begin("Performance", &v); _isEnabled = v; + _isCollapsed = ImGui::IsWindowCollapsed(); + RenderEngine& re = OsEng.renderEngine(); PerformanceLayout* layout = re.performanceManager()->performanceData(); diff --git a/modules/imgui/src/guipropertycomponent.cpp b/modules/imgui/src/guipropertycomponent.cpp index 7886957175..1c71cb3013 100644 --- a/modules/imgui/src/guipropertycomponent.cpp +++ b/modules/imgui/src/guipropertycomponent.cpp @@ -37,6 +37,22 @@ namespace { const ImVec2 size = ImVec2(350, 500); + static const openspace::properties::Property::PropertyInfo UseTreeInfo = { + "TreeLayout", + "Use Tree Layout", + "If this value is checked, this component will display the properties using a " + "tree layout, rather than using a flat map. This value should only be set on " + "property windows that display SceneGraphNodes, or the application might crash." + }; + + static const openspace::properties::Property::PropertyInfo OrderingInfo = { + "Ordering", + "Tree Ordering", + "This list determines the order of the first tree layer if it is used. Elements " + "present in this list will be shown first, with an alphabetical ordering for " + "elements not listed." + }; + int nVisibleProperties(const std::vector& props, openspace::properties::Property::Visibility visibility) { @@ -146,13 +162,14 @@ namespace { namespace openspace::gui { -GuiPropertyComponent::GuiPropertyComponent(std::string name, UseTreeLayout useTree, - IsTopLevelWindow topLevel) +GuiPropertyComponent::GuiPropertyComponent(std::string name, UseTreeLayout useTree) : GuiComponent(std::move(name)) - , _useTreeLayout(useTree) - , _currentUseTreeLayout(useTree) - , _isTopLevel(topLevel) -{} + , _useTreeLayout(UseTreeInfo, useTree) + , _treeOrdering(OrderingInfo) +{ + addProperty(_useTreeLayout); + addProperty(_treeOrdering); +} void GuiPropertyComponent::setSource(SourceFunction function) { _function = std::move(function); @@ -236,21 +253,16 @@ void GuiPropertyComponent::renderPropertyOwner(properties::PropertyOwner* owner) } void GuiPropertyComponent::render() { - if (_isTopLevel) { - ImGui::Begin(name().c_str(), nullptr, size, 0.75f); - } - else { - bool v = _isEnabled; - ImGui::Begin(name().c_str(), &v, size, 0.75f); - _isEnabled = v; - } + ImGui::SetNextWindowCollapsed(_isCollapsed); + + bool v = _isEnabled; + ImGui::Begin(name().c_str(), &v, size, 0.75f); + _isEnabled = v; + + _isCollapsed = ImGui::IsWindowCollapsed(); + using namespace properties; if (_function) { - if (_useTreeLayout) { - ImGui::Checkbox("Use Tree layout", &_currentUseTreeLayout); - } - - std::vector owners = _function(); std::sort( @@ -261,7 +273,7 @@ void GuiPropertyComponent::render() { } ); - if (_currentUseTreeLayout) { + if (_useTreeLayout) { for (properties::PropertyOwner* owner : owners) { ghoul_assert( dynamic_cast(owner), @@ -271,12 +283,14 @@ void GuiPropertyComponent::render() { } // Sort: - // if guigrouping, sort by name and shortest first + // if guigrouping, sort by name and shortest first, but respect the user + // specified ordering // then all w/o guigroup + const std::vector& ordering = _treeOrdering; std::stable_sort( owners.begin(), owners.end(), - [](properties::PropertyOwner* lhs, properties::PropertyOwner* rhs) { + [&ordering](PropertyOwner* lhs, PropertyOwner* rhs) { std::string lhsGroup = static_cast(lhs)->guiPath(); std::string rhsGroup = static_cast(rhs)->guiPath(); @@ -286,7 +300,40 @@ void GuiPropertyComponent::render() { if (rhsGroup.empty()) { return true; } - return lhsGroup < rhsGroup; + + if (ordering.empty()) { + return lhsGroup < rhsGroup; + } + + std::vector lhsToken = ghoul::tokenizeString( + lhsGroup, + '/' + ); + // The first token is always empty + auto lhsIt = std::find(ordering.begin(), ordering.end(), lhsToken[1]); + + std::vector rhsToken = ghoul::tokenizeString( + rhsGroup, + '/' + ); + // The first token is always empty + auto rhsIt = std::find(ordering.begin(), ordering.end(), rhsToken[1]); + + if (lhsIt != ordering.end() && rhsIt != ordering.end()) { + // If both top-level groups are in the ordering list, the order + // of the iterators gives us the order of the groups + return lhsIt < rhsIt; + } + else if (lhsIt != ordering.end() && rhsIt == ordering.end()) { + // If only one of them is in the list, we have a sorting + return true; + } + else if (lhsIt == ordering.end() && rhsIt != ordering.end()) { + return false; + } + else { + return lhsGroup < rhsGroup; + } } ); } @@ -329,7 +376,7 @@ void GuiPropertyComponent::render() { } }; - if (!_currentUseTreeLayout || noGuiGroups) { + if (!_useTreeLayout || noGuiGroups) { std::for_each(owners.begin(), owners.end(), renderProp); } else { // _useTreeLayout && gui groups exist @@ -398,6 +445,7 @@ void GuiPropertyComponent::renderProperty(properties::Property* prop, { "DMat3Property", &renderDMat3Property }, { "DMat4Property", &renderDMat4Property }, { "StringProperty", &renderStringProperty }, + { "StringListProperty", &renderStringListProperty }, { "OptionProperty", &renderOptionProperty }, { "TriggerProperty", &renderTriggerProperty }, { "SelectionProperty", &renderSelectionProperty } diff --git a/modules/imgui/src/guispacetimecomponent.cpp b/modules/imgui/src/guispacetimecomponent.cpp index edd3f16057..3106d43a24 100644 --- a/modules/imgui/src/guispacetimecomponent.cpp +++ b/modules/imgui/src/guispacetimecomponent.cpp @@ -38,14 +38,34 @@ namespace { static const ImVec2 Size = ImVec2(350, 500); + + static const openspace::properties::Property::PropertyInfo MinMaxInfo = { + "MinMax", + "Minimum/Maximum value for delta time", + "This value determines the minimum and maximum value for the delta time slider." + }; + } // namespace namespace openspace::gui { -GuiSpaceTimeComponent::GuiSpaceTimeComponent() : GuiComponent("Space/Time") {} +GuiSpaceTimeComponent::GuiSpaceTimeComponent() + : GuiComponent("Space/Time") + , _minMaxDeltaTime(MinMaxInfo, 100000.f, 0.f, 1e8f, 1.f, 5.f) + , _localMinMaxDeltatime(100000.f) +{ + _minMaxDeltaTime.onChange([this]() { + _localMinMaxDeltatime = _minMaxDeltaTime; + }); + addProperty(_minMaxDeltaTime); +} void GuiSpaceTimeComponent::render() { - ImGui::Begin(name().c_str(), nullptr, Size, 0.5f, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::SetNextWindowCollapsed(_isCollapsed); + bool v = _isEnabled; + ImGui::Begin(name().c_str(), &v, Size, 0.5f, ImGuiWindowFlags_AlwaysAutoResize); + _isEnabled = v; + _isCollapsed = ImGui::IsWindowCollapsed(); std::vector nodes = OsEng.renderEngine().scene()->allSceneGraphNodes(); @@ -58,15 +78,6 @@ void GuiSpaceTimeComponent::render() { } ); - ImGui::BeginGroup(); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip( - "%s", - "These buttons and the dropdown menu determine the focus object in the scene " - "that is the center of all camera movement" - ); - } - CaptionText("Focus Selection"); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.f); @@ -117,8 +128,6 @@ void GuiSpaceTimeComponent::render() { ); } - ImGui::EndGroup(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.f); ImGui::Separator(); @@ -127,15 +136,6 @@ void GuiSpaceTimeComponent::render() { ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.f); - - ImGui::BeginGroup(); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip( - "%s", - "These elements determine the simulation time inside OpenSpace." - ); - } - CaptionText("Time Controls"); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.f); @@ -253,17 +253,24 @@ void GuiSpaceTimeComponent::render() { ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.f); + bool minMaxChanged = ImGui::InputFloat( + "Time slider range", + &_localMinMaxDeltatime + ); + if (minMaxChanged) { + _minMaxDeltaTime = _localMinMaxDeltatime; + } float deltaTime = static_cast(OsEng.timeManager().time().deltaTime()); - bool changed = ImGui::SliderFloat( + bool deltaChanged = ImGui::SliderFloat( "Delta Time", &deltaTime, - -100000.f, - 100000.f, - "%.3f", + -_minMaxDeltaTime, + _minMaxDeltaTime, + "%.6f", 5.f ); - if (changed) { + if (deltaChanged) { OsEng.scriptEngine().queueScript( "openspace.time.setDeltaTime(" + std::to_string(deltaTime) + ")", scripting::ScriptEngine::RemoteScripting::Yes @@ -373,9 +380,6 @@ void GuiSpaceTimeComponent::render() { } ImGui::SameLine(); - - ImGui::EndGroup(); - ImGui::End(); } diff --git a/modules/imgui/src/renderproperties.cpp b/modules/imgui/src/renderproperties.cpp index c6ac3deba1..847eb06910 100644 --- a/modules/imgui/src/renderproperties.cpp +++ b/modules/imgui/src/renderproperties.cpp @@ -32,11 +32,13 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -247,6 +249,56 @@ void renderStringProperty(Property* prop, const std::string& ownerName, ImGui::PopID(); } +void renderStringListProperty(Property* prop, const std::string& ownerName, + IsRegularProperty isRegular, ShowToolTip showTooltip) +{ + ghoul_assert(prop, "prop must not be nullptr"); + StringListProperty* p = static_cast(prop); + std::string name = p->guiName(); + ImGui::PushID((ownerName + "." + name).c_str()); + + std::string value; + p->getStringValue(value); + // const std::string value = p->value(); + + static const int bufferSize = 512; + static char buffer[bufferSize]; +#ifdef _MSC_VER + strcpy_s(buffer, value.length() + 1, value.c_str()); +#else + strcpy(buffer, value.c_str()); +#endif + bool hasNewValue = ImGui::InputText( + name.c_str(), + buffer, + bufferSize, + ImGuiInputTextFlags_EnterReturnsTrue + ); + if (showTooltip) { + renderTooltip(prop); + } + + if (hasNewValue) { + std::vector tokens = ghoul::tokenizeString(std::string(buffer), ','); + std::string script = "{"; + for (std::string& token : tokens) { + if (!token.empty()) { + ghoul::trimWhitespace(token); + script += "[[" + token + "]],"; + } + } + script += "}"; + + executeScript( + p->fullyQualifiedIdentifier(), + std::move(script), + isRegular + ); + } + + ImGui::PopID(); +} + void renderDoubleProperty(properties::Property* prop, const std::string& ownerName, IsRegularProperty isRegular, ShowToolTip showTooltip) { @@ -259,7 +311,7 @@ void renderDoubleProperty(properties::Property* prop, const std::string& ownerNa float min = static_cast(p->minValue()); float max = static_cast(p->maxValue()); - ImGui::SliderFloat(name.c_str(), &value, min, max, "%.5f"); + ImGui::SliderFloat(name.c_str(), &value, min, max, "%.5f", p->exponent()); if (showTooltip) { renderTooltip(prop); } @@ -402,7 +454,7 @@ void renderFloatProperty(Property* prop, const std::string& ownerName, FloatProperty::ValueType value = *p; float min = p->minValue(); float max = p->maxValue(); - ImGui::SliderFloat(name.c_str(), &value, min, max, "%.5f"); + ImGui::SliderFloat(name.c_str(), &value, min, max, "%.5f", p->exponent()); if (showTooltip) { renderTooltip(prop); } @@ -431,7 +483,8 @@ void renderVec2Property(Property* prop, const std::string& ownerName, &value.x, min, max, - "%.5f" + "%.5f", + p->exponent() ); if (showTooltip) { renderTooltip(prop); @@ -472,7 +525,8 @@ void renderVec3Property(Property* prop, const std::string& ownerName, glm::value_ptr(value), min, max, - "%.5f" + "%.5f", + p->exponent() ); } if (showTooltip) { @@ -514,7 +568,8 @@ void renderVec4Property(Property* prop, const std::string& ownerName, glm::value_ptr(value), min, max, - "%.5f" + "%.5f", + p->exponent() ); } if (showTooltip) { @@ -548,7 +603,8 @@ void renderDVec2Property(Property* prop, const std::string& ownerName, &value.x, min, max, - "%.5f" + "%.5f", + p->exponent() ); if (showTooltip) { renderTooltip(prop); @@ -582,7 +638,8 @@ void renderDVec3Property(Property* prop, const std::string& ownerName, glm::value_ptr(value), min, max, - "%.5f" + "%.5f", + p->exponent() ); if (showTooltip) { renderTooltip(prop); @@ -616,7 +673,8 @@ void renderDVec4Property(Property* prop, const std::string& ownerName, &value.x, min, max, - "%.5f" + "%.5f", + p->exponent() ); if (showTooltip) { renderTooltip(prop); @@ -656,8 +714,8 @@ void renderDMat2Property(Property* prop, const std::string& ownerName, }; float max = static_cast(glm::compMax(maxValues)); - ImGui::SliderFloat2("[0]", glm::value_ptr(value[0]), min, max); - ImGui::SliderFloat2("[1]", glm::value_ptr(value[1]), min, max); + ImGui::SliderFloat2("[0]", glm::value_ptr(value[0]), min, max, "%.5f", p->exponent()); + ImGui::SliderFloat2("[1]", glm::value_ptr(value[1]), min, max, "%.5f", p->exponent()); if (showTooltip) { renderTooltip(prop); @@ -700,9 +758,9 @@ void renderDMat3Property(Property* prop, const std::string& ownerName, float max = static_cast(glm::compMax(maxValues)); - ImGui::SliderFloat3("[0]", glm::value_ptr(value[0]), min, max); - ImGui::SliderFloat3("[1]", glm::value_ptr(value[1]), min, max); - ImGui::SliderFloat3("[2]", glm::value_ptr(value[2]), min, max); + ImGui::SliderFloat3("[0]", glm::value_ptr(value[0]), min, max, "%.5f", p->exponent()); + ImGui::SliderFloat3("[1]", glm::value_ptr(value[1]), min, max, "%.5f", p->exponent()); + ImGui::SliderFloat3("[2]", glm::value_ptr(value[2]), min, max, "%.5f", p->exponent()); if (showTooltip) { renderTooltip(prop); @@ -747,10 +805,10 @@ void renderDMat4Property(Property* prop, const std::string& ownerName, float max = static_cast(glm::compMax(maxValues)); - ImGui::SliderFloat4("[0]", glm::value_ptr(value[0]), min, max); - ImGui::SliderFloat4("[1]", glm::value_ptr(value[1]), min, max); - ImGui::SliderFloat4("[2]", glm::value_ptr(value[2]), min, max); - ImGui::SliderFloat4("[3]", glm::value_ptr(value[3]), min, max); + ImGui::SliderFloat4("[0]", glm::value_ptr(value[0]), min, max, "%.5f", p->exponent()); + ImGui::SliderFloat4("[1]", glm::value_ptr(value[1]), min, max, "%.5f", p->exponent()); + ImGui::SliderFloat4("[2]", glm::value_ptr(value[2]), min, max, "%.5f", p->exponent()); + ImGui::SliderFloat4("[3]", glm::value_ptr(value[3]), min, max, "%.5f", p->exponent()); if (showTooltip) { renderTooltip(prop); diff --git a/scripts/common.lua b/scripts/common.lua index 90519ff352..bec249a5ba 100644 --- a/scripts/common.lua +++ b/scripts/common.lua @@ -14,11 +14,32 @@ helper.scheduledScript.reversible = {} helper.setCommonKeys = function() openspace.bindKeyLocal( "F1", - helper.property.invert('Global Properties.ImGUI.Main.Enabled'), - "Toggles the visibility of the on-screen GUI." + [[local b = openspace.getPropertyValue('Global Properties.ImGUI.Main.Enabled'); + openspace.setPropertyValueSingle('Global Properties.ImGUI.Main.Enabled', not b); + openspace.setPropertyValueSingle('Global Properties.ImGUI.Main.IsHidden', b);]], + "Shows or hides the entire user interface" ) + openspace.bindKeyLocal( "F2", + [[local b = openspace.getPropertyValue('Global Properties.ImGUI.Main.Properties.Enabled'); + local c = openspace.getPropertyValue('Global Properties.ImGUI.Main.IsHidden'); + openspace.setPropertyValue('Global Properties.ImGUI.*.Enabled', false); + if b and c then + -- This can happen if the main properties window is enabled, the main gui is enabled + -- and then closed again. So the main properties window is enabled, but also all + -- windows are hidden + openspace.setPropertyValueSingle('Global Properties.ImGUI.Main.IsHidden', false); + openspace.setPropertyValueSingle('Global Properties.ImGUI.Main.Properties.Enabled', true); + else + openspace.setPropertyValueSingle('Global Properties.ImGUI.Main.Properties.Enabled', not b); + openspace.setPropertyValueSingle('Global Properties.ImGUI.Main.IsHidden', b); + end]], + "Shows or hides the properties window" + ) + + openspace.bindKeyLocal( + "F3", helper.property.invert("RenderEngine.PerformanceMeasurements"), "Toogles performance measurements that shows rendering time informations." ) diff --git a/scripts/scene_helper.lua b/scripts/scene_helper.lua index b97a32d37c..ce611a7df9 100644 --- a/scripts/scene_helper.lua +++ b/scripts/scene_helper.lua @@ -5,3 +5,12 @@ mark_interesting_nodes = function(nodes) end end end + +set_default_gui_sorting = function() + openspace.setPropertyValueSingle( + 'Global Properties.ImGUI.Main.Properties.Ordering', + { + "Solar System", "Milky Way", "Universe", "Other" + } + ) +end \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 22baa8c2e9..ee95c98925 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/properties/propertyowner.cpp ${OPENSPACE_BASE_DIR}/src/properties/selectionproperty.cpp ${OPENSPACE_BASE_DIR}/src/properties/stringproperty.cpp + ${OPENSPACE_BASE_DIR}/src/properties/stringlistproperty.cpp ${OPENSPACE_BASE_DIR}/src/properties/triggerproperty.cpp ${OPENSPACE_BASE_DIR}/src/properties/matrix/dmat2property.cpp ${OPENSPACE_BASE_DIR}/src/properties/matrix/dmat2x3property.cpp @@ -230,6 +231,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/properties/scalarproperty.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/selectionproperty.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/stringproperty.h + ${OPENSPACE_BASE_DIR}/include/openspace/properties/stringlistproperty.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/templateproperty.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/templateproperty.inl ${OPENSPACE_BASE_DIR}/include/openspace/properties/triggerproperty.h diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 9eeacc42e8..47267f22f9 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -576,12 +576,14 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) { } ); + bool errorWithPreInit = false; // Run start up scripts try { runPreInitializationScripts(scenePath); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); + errorWithPreInit = true; } Scene* scene; @@ -622,60 +624,68 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) { // an OpenGL context std::atomic_bool initializeFinished(false); bool errorWhileLoading = false; - std::thread t([&scene, scenePath, &initializeFinished, &errorWhileLoading, this]() { - _loadingScreen->postMessage("Creating scene..."); - _loadingScreen->setPhase(LoadingScreen::Phase::Construction); - try { - scene = _sceneManager->loadScene(scenePath); - } - catch (const ghoul::FileNotFoundError& e) { - LERRORC(e.component, e.message); - errorWhileLoading = true; - return; - } - catch (const Scene::InvalidSceneError& e) { - LERRORC(e.component, e.message); - errorWhileLoading = true; - return; - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - errorWhileLoading = true; - return; - } - catch (const std::exception& e) { - LERROR(e.what()); - errorWhileLoading = true; - return; - } - catch (...) { - LERROR("Unknown error loading the scene"); - errorWhileLoading = true; - return; + std::thread t([&scene, scenePath, &initializeFinished, &errorWhileLoading, + &errorWithPreInit, this]() + { + if (errorWithPreInit) { + _loadingScreen->postMessage("Failed loading scene '" + scenePath + "'"); + _loadingScreen->setCatastrophicError(LoadingScreen::CatastrophicError::Yes); } + else { + _loadingScreen->postMessage("Creating scene..."); + _loadingScreen->setPhase(LoadingScreen::Phase::Construction); + try { + scene = _sceneManager->loadScene(scenePath); + } + catch (const ghoul::FileNotFoundError& e) { + LERRORC(e.component, e.message); + errorWhileLoading = true; + return; + } + catch (const Scene::InvalidSceneError& e) { + LERRORC(e.component, e.message); + errorWhileLoading = true; + return; + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + errorWhileLoading = true; + return; + } + catch (const std::exception& e) { + LERROR(e.what()); + errorWhileLoading = true; + return; + } + catch (...) { + LERROR("Unknown error loading the scene"); + errorWhileLoading = true; + return; + } - Scene* previousScene = _renderEngine->scene(); - if (previousScene) { - _syncEngine->removeSyncables(_timeManager->getSyncables()); - _syncEngine->removeSyncables(_renderEngine->getSyncables()); - _syncEngine->removeSyncable(_scriptEngine.get()); + Scene* previousScene = _renderEngine->scene(); + if (previousScene) { + _syncEngine->removeSyncables(_timeManager->getSyncables()); + _syncEngine->removeSyncables(_renderEngine->getSyncables()); + _syncEngine->removeSyncable(_scriptEngine.get()); - _renderEngine->setScene(nullptr); - _renderEngine->setCamera(nullptr); - _sceneManager->unloadScene(*previousScene); + _renderEngine->setScene(nullptr); + _renderEngine->setCamera(nullptr); + _sceneManager->unloadScene(*previousScene); + } + + // Initialize the RenderEngine + _renderEngine->setScene(scene); + _renderEngine->setCamera(scene->camera()); + _renderEngine->setGlobalBlackOutFactor(0.0); + _renderEngine->startFading(1, 3.0); + + _loadingScreen->setPhase(LoadingScreen::Phase::Initialization); + + scene->initialize(); + _loadingScreen->postMessage("Finished initializing"); + initializeFinished = true; } - - // Initialize the RenderEngine - _renderEngine->setScene(scene); - _renderEngine->setCamera(scene->camera()); - _renderEngine->setGlobalBlackOutFactor(0.0); - _renderEngine->startFading(1, 3.0); - - _loadingScreen->setPhase(LoadingScreen::Phase::Initialization); - - scene->initialize(); - _loadingScreen->postMessage("Finished initializing"); - initializeFinished = true; }); // While the SceneGraphNodes initialize themselves, we can hand over control to the @@ -1319,6 +1329,10 @@ void OpenSpaceEngine::drawOverlays() { // and we won't need this if we are shutting down _renderEngine->renderCameraInformation(); } + else { + // If we are in shutdown mode, we can display the remaining time + _renderEngine->renderShutdownInformation(_shutdown.timer, _shutdown.waitTime); + } _console->render(); } @@ -1429,12 +1443,10 @@ void OpenSpaceEngine::externalControlCallback(const char* receivedChars, int siz void OpenSpaceEngine::toggleShutdownMode() { if (_shutdown.inShutdown) { // If we are already in shutdown mode, we want to disable it - LINFO("Disabled shutdown mode"); _shutdown.inShutdown = false; } else { // Else, we have to enable it - LINFO("Shutting down OpenSpace"); _shutdown.timer = _shutdown.waitTime; _shutdown.inShutdown = true; } diff --git a/src/properties/stringlistproperty.cpp b/src/properties/stringlistproperty.cpp new file mode 100644 index 0000000000..ef137f585f --- /dev/null +++ b/src/properties/stringlistproperty.cpp @@ -0,0 +1,120 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 + +#include +#include + +#include + +namespace { + +std::vector fromLuaConversion(lua_State* state, bool& success) { + if (!lua_istable(state, -1)) { + success = false; + return {}; + } + + std::vector result; + lua_pushnil(state); + while (lua_next(state, -2) != 0) { + if (lua_isstring(state, -1)) { + result.push_back(lua_tostring(state, -1)); + } + else { + success = false; + return {}; + } + lua_pop(state, 1); + } + success = true; + return result; +} + +bool toLuaConversion(lua_State* state, std::vector val) { + lua_createtable(state, static_cast(val.size()), 0); + + int i = 1; + for (std::string& v : val) { + lua_pushstring(state, std::to_string(i).c_str()); + lua_pushstring(state, v.c_str()); + lua_settable(state, -3); + } + + return true; +} + +std::vector fromStringConversion(std::string val, bool& success) { + std::vector tokens = ghoul::tokenizeString(val, ','); + for (std::string& token : tokens) { + // Each incoming string is of the form "value" + // so we want to remove the leading and trailing " characters + if (token.size() > 2 && (token[0] == '"' && token[token.size() - 1] == '"')) { + token = token.substr(1, token.size() - 2); + } + } + + success = true; + return tokens; +} + +bool toStringConversion(std::string& outValue, std::vector inValue) { + outValue = ""; + for (const std::string& v : inValue) { + if (&v != &*inValue.cbegin()) { + outValue += ", " + v; + } + else { + outValue += v; + } + } + + // outValue = std::accumulate( + // inValue.begin(), + // inValue.end(), + // std::string(""), + // [](std::string lhs, std::string rhs) { + // return lhs + "," + "\"" + rhs + "\""; + // } + // ); + return true; +} + +} // namespace + +namespace openspace::properties { + +REGISTER_TEMPLATEPROPERTY_SOURCE( + StringListProperty, + std::vector, + std::vector(), + fromLuaConversion, + toLuaConversion, + fromStringConversion, + toStringConversion, + LUA_TTABLE +) + +} // namespace openspace::properties diff --git a/src/rendering/loadingscreen.cpp b/src/rendering/loadingscreen.cpp index 077b0a7f5d..9a34ec9cd0 100644 --- a/src/rendering/loadingscreen.cpp +++ b/src/rendering/loadingscreen.cpp @@ -108,6 +108,7 @@ LoadingScreen::LoadingScreen(ShowMessage showMessage, ShowNodeNames showNodeName , _loadingFont(nullptr) , _messageFont(nullptr) , _itemFont(nullptr) + , _hasCatastrophicErrorOccurred(false) , _logo{ 0, 0 } , _progressbar{ 0, 0, 0, 0 } , _randomEngine(_randomDevice()) @@ -412,12 +413,17 @@ void LoadingScreen::render() { using FR = ghoul::fontrendering::FontRenderer; FR& renderer = FR::defaultRenderer(); + + std::string headline = + _hasCatastrophicErrorOccurred ? + "Failure": + "Loading..."; // We use "Loading" to center the text, but render "Loading..." to make it look more // pleasing FR::BoundingBoxInformation bbox = renderer.boundingBox( *_loadingFont, "%s", - "Loading." + headline.substr(0, headline.size() - 2).c_str() ); glm::vec2 loadingLl = glm::vec2( @@ -431,7 +437,7 @@ void LoadingScreen::render() { loadingLl, glm::vec4(1.f, 1.f, 1.f, 1.f), "%s", - "Loading..." + headline.c_str() ); glm::vec2 messageLl; @@ -620,6 +626,10 @@ void LoadingScreen::postMessage(std::string message) { _message = std::move(message); } +void LoadingScreen::setCatastrophicError(CatastrophicError catastrophicError) { + _hasCatastrophicErrorOccurred = catastrophicError; +} + void LoadingScreen::finalize() { _items.erase( std::remove_if( diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 616366fdbe..6aa4880ae2 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -47,7 +47,7 @@ #include #include #include -#include > +#include #include #include #include @@ -646,6 +646,15 @@ void RenderEngine::renderShutdownInformation(float timer, float fullTime) { timer, fullTime ); + + RenderFontCr( + *_fontDate, + penPosition, + "%s", + // Important: length of this string is the same as the shutdown time text + // to make them align + "Press ESC again to abort" + ); } void RenderEngine::postDraw() { diff --git a/src/util/timeconversion.cpp b/src/util/timeconversion.cpp index ec3647c2bb..badd95a2c2 100644 --- a/src/util/timeconversion.cpp +++ b/src/util/timeconversion.cpp @@ -24,6 +24,8 @@ #include +#include + #include namespace { @@ -43,7 +45,7 @@ namespace { namespace openspace { std::pair simplifyTime(double seconds) { - double secondsVal = abs(seconds); + double secondsVal = glm::abs(seconds); if (secondsVal > 1e-3 && secondsVal < SecondsPerMinute) { return { seconds, seconds == 1.0 ? "second" : "seconds" };