diff --git a/Changelog.md b/Changelog.md index d59a95c72..824908605 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,19 @@ ## Gazebo GUI 9 -### Gazebo GUI 9.0.0 (2024-09-24) +### Gazebo GUI 9.0.0 (2024-09-25) + +1. **Baseline:** this includes all changes from 8.3.0 and earlier. + +1. Only set shadow texture size if configured by the user in the SDFormat file + * [Pull request #642](https://github.com/gazebosim/gz-gui/pull/642) + +1. Miscellaneous documentation fixes + * [Pull request #640](https://github.com/gazebosim/gz-gui/pull/640) + * [Pull request #639](https://github.com/gazebosim/gz-gui/pull/639) + * [Pull request #638](https://github.com/gazebosim/gz-gui/pull/638) + +1. Update badges for ionic gz-gui9 + * [Pull request #636](https://github.com/gazebosim/gz-gui/pull/636) 1. Expose shadow texture size for directional lighting in SDF * [Pull request #633](https://github.com/gazebosim/gz-gui/pull/633) @@ -445,7 +458,7 @@ * [Pull request #343](https://github.com/gazebosim/gz-gui/pull/343) * [Pull request #327](https://github.com/gazebosim/gz-gui/pull/327) * [Pull request #313](https://github.com/gazebosim/gz-gui/pull/313) - * [Pull request #301](https://github.com/gazebosim/gz-gui/pull/301) + * [Pull request #301](https://github.com/gazebosim/gz-gui/pull/301) 1. Added macOS source code installation * [Pull request #297](https://github.com/gazebosim/gz-gui/pull/297) diff --git a/README.md b/README.md index 9daa010f1..732dfad42 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Build | Status -- | -- -Test coverage | [![codecov](https://codecov.io/gh/gazebosim/gz-gui/branch/main/graph/badge.svg)](https://codecov.io/gh/gazebosim/gz-gui/branch/main) +Test coverage | [![codecov](https://codecov.io/gh/gazebosim/gz-gui/tree/main/graph/badge.svg)](https://codecov.io/gh/gazebosim/gz-gui/tree/main) Ubuntu Noble| [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_gui-ci-main-noble-amd64)](https://build.osrfoundation.org/job/gz_gui-ci-main-noble-amd64) Homebrew | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_gui-ci-main-homebrew-amd64)](https://build.osrfoundation.org/job/gz_gui-ci-main-homebrew-amd64) Windows | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=gz_gui-main-win)](https://build.osrfoundation.org/job/gz_gui-main-win) @@ -33,9 +33,9 @@ which can be used to add custom widgets. [Folder Structure](#folder-structure) -[Code of Conduct](#code-of-conduct) +[Contributing](#contributing) -[Contributing](#code-of-contributing) +[Code of Conduct](#code-of-conduct) [Versioning](#versioning) @@ -66,12 +66,12 @@ line tools from `gz-tools` may not work correctly. A workaround for a single package is to define the environment variable `GZ_CONFIG_PATH` to point to the location of the Gazebo library installation, where the YAML file for the package is found, such as -```{.sh} +```bash export GZ_CONFIG_PATH=/usr/local/share/gz ``` Multiple paths can be specified using the `:` delimiter. For example, -```{.sh} +```bash export GZ_CONFIG_PATH=/user/local/share/gz/:/path/to/some/other/location ``` @@ -106,7 +106,7 @@ export GZ_CONFIG_PATH=/user/local/share/gz/:/path/to/some/other/location # Contributing Please see -[CONTRIBUTING.md](https://gazebosim.org/docs/all/contributing). +[the contribution guide](https://gazebosim.org/docs/all/contributing). # Code of Conduct diff --git a/include/gz/gui/Application.hh b/include/gz/gui/Application.hh index 0397372ed..5cd17a73c 100644 --- a/include/gz/gui/Application.hh +++ b/include/gz/gui/Application.hh @@ -98,6 +98,12 @@ namespace gz::gui /// \sa InitializeDialogs public: bool LoadConfig(const std::string &_path); + /// \brief Load window configuration from XML element. + /// This is the `` element inside a gui config file. + /// \param[in] _window XML element that contains the window configuration + /// \return True if successful + public: bool LoadWindowConfig(const tinyxml2::XMLElement &_window); + /// \brief Load the configuration from the default config file. /// \return True if successful /// \sa SetDefaultConfigPath @@ -118,7 +124,14 @@ namespace gz::gui /// \return The default configuration path. /// \sa LoadDefaultConfig /// \sa SetDefaultConfigPath - public: std::string DefaultConfigPath(); + public: std::string DefaultConfigPath() const; + + /// \brief Given an input config path, resolve its absolute path, + /// potentially searching for it in locations specified by + /// `GZ_GUI_RESOURCE_PATH`. + /// \param[in] _path Path to a config file. If the path is absolute + /// \return The resolved path + public: std::string ResolveConfigFile(const std::string &_path) const; /// \brief Set the environment variable which defines the paths to /// look for plugins. diff --git a/src/Application.cc b/src/Application.cc index 2a414003e..8f8b34cb6 100644 --- a/src/Application.cc +++ b/src/Application.cc @@ -325,31 +325,7 @@ bool Application::LoadConfig(const std::string &_config) return false; } - std::string configFull = _config; - - // Check if the passed in config file exists. - // (If the default config path doesn't exist yet, it's expected behavior. - // It will be created the first time the user presses "Save configuration".) - if (!common::exists(configFull) && (configFull != this->DefaultConfigPath())) - { - // If not, then check environment variable - std::string configPathEnv; - common::env("GZ_GUI_RESOURCE_PATH", configPathEnv); - - if (!configPathEnv.empty()) - { - std::vector parentPaths = common::Split(configPathEnv, ':'); - for (const auto &parentPath : parentPaths) - { - std::string tempPath = common::joinPaths(parentPath, configFull); - if (common::exists(tempPath)) - { - configFull = tempPath; - break; - } - } - } - } + const auto configFull = this->ResolveConfigFile(_config); // Use tinyxml to read config tinyxml2::XMLDocument doc; @@ -404,108 +380,114 @@ bool Application::LoadConfig(const std::string &_config) // Process window properties if (auto *winElem = doc.FirstChildElement("window")) { - gzdbg << "Loading window config" << std::endl; + this->LoadWindowConfig(*winElem); + } + + this->ApplyConfig(); + + return true; +} + +///////////////////////////////////////////////// +bool Application::LoadWindowConfig(const tinyxml2::XMLElement &_winElem) +{ + gzdbg << "Loading window config" << std::endl; + + tinyxml2::XMLPrinter printer; + if (!_winElem.Accept(&printer)) + { + gzwarn << "There was an error parsing the element" + << std::endl; + return false; + } + this->dataPtr->windowConfig.MergeFromXML(std::string(printer.CStr())); - tinyxml2::XMLPrinter printer; - if (!winElem->Accept(&printer)) + // Closing behavior. + if (auto *defaultExitActionElem = + _winElem.FirstChildElement("default_exit_action")) + { + ExitAction action{ExitAction::CLOSE_GUI}; + const auto value = common::lowercase(defaultExitActionElem->GetText()); + if (value == "shutdown_server") { - gzwarn << "There was an error parsing the element" - << std::endl; - return false; + action = ExitAction::SHUTDOWN_SERVER; } - this->dataPtr->windowConfig.MergeFromXML(std::string(printer.CStr())); - - // Closing behavior. - if (auto *defaultExitActionElem = - winElem->FirstChildElement("default_exit_action")) + else if (value != "close_gui" && !value.empty()) { - ExitAction action{ExitAction::CLOSE_GUI}; - const auto value = common::lowercase(defaultExitActionElem->GetText()); - if (value == "shutdown_server") - { - action = ExitAction::SHUTDOWN_SERVER; - } - else if (value != "close_gui" && !value.empty()) - { - gzwarn << "Value '" << value << "' of is " - << "invalid. Allowed values are CLOSE_GUI and SHUTDOWN_SERVER. " - << "Selecting CLOSE_GUI as fallback." << std::endl; - } - this->dataPtr->mainWin->SetDefaultExitAction(action); + gzwarn << "Value '" << value << "' of is " + << "invalid. Allowed values are CLOSE_GUI and SHUTDOWN_SERVER. " + << "Selecting CLOSE_GUI as fallback." << std::endl; } + this->dataPtr->mainWin->SetDefaultExitAction(action); + } - // Dialog on exit - if (auto *dialogOnExitElem = winElem->FirstChildElement("dialog_on_exit")) + // Dialog on exit + if (auto *dialogOnExitElem = _winElem.FirstChildElement("dialog_on_exit")) + { + bool showDialogOnExit{false}; + dialogOnExitElem->QueryBoolText(&showDialogOnExit); + this->dataPtr->mainWin->SetShowDialogOnExit(showDialogOnExit); + } + + if (auto *dialogOnExitOptionsElem = + _winElem.FirstChildElement("dialog_on_exit_options")) + { + if (auto *promptElem = + dialogOnExitOptionsElem->FirstChildElement("prompt_text")) { - bool showDialogOnExit{false}; - dialogOnExitElem->QueryBoolText(&showDialogOnExit); - this->dataPtr->mainWin->SetShowDialogOnExit(showDialogOnExit); + this->dataPtr->mainWin->SetDialogOnExitText( + QString::fromStdString(promptElem->GetText())); } - - if (auto *dialogOnExitOptionsElem = - winElem->FirstChildElement("dialog_on_exit_options")) + if (auto *showShutdownElem = + dialogOnExitOptionsElem->FirstChildElement("show_shutdown_button")) { - if (auto *promptElem = - dialogOnExitOptionsElem->FirstChildElement("prompt_text")) - { - this->dataPtr->mainWin->SetDialogOnExitText( - QString::fromStdString(promptElem->GetText())); - } - if (auto *showShutdownElem = - dialogOnExitOptionsElem->FirstChildElement("show_shutdown_button")) - { - bool showShutdownButton{false}; - showShutdownElem->QueryBoolText(&showShutdownButton); - this->dataPtr->mainWin->SetExitDialogShowShutdown(showShutdownButton); - } - if (auto *showCloseGuiElem = - dialogOnExitOptionsElem->FirstChildElement("show_close_gui_button")) - { - bool showCloseGuiButton{false}; - showCloseGuiElem->QueryBoolText(&showCloseGuiButton); - this->dataPtr->mainWin->SetExitDialogShowCloseGui(showCloseGuiButton); - } - if (auto *shutdownTextElem = - dialogOnExitOptionsElem->FirstChildElement("shutdown_button_text")) - { - this->dataPtr->mainWin->SetExitDialogShutdownText( - QString::fromStdString(shutdownTextElem->GetText())); - } - if (auto *closeGuiTextElem = - dialogOnExitOptionsElem->FirstChildElement("close_gui_button_text")) - { - this->dataPtr->mainWin->SetExitDialogCloseGuiText( - QString::fromStdString(closeGuiTextElem->GetText())); - } + bool showShutdownButton{false}; + showShutdownElem->QueryBoolText(&showShutdownButton); + this->dataPtr->mainWin->SetExitDialogShowShutdown(showShutdownButton); } - - // Server control service topic - std::string serverControlService{"/server_control"}; - auto *serverControlElem = - winElem->FirstChildElement("server_control_service"); - if (nullptr != serverControlElem && nullptr != serverControlElem->GetText()) + if (auto *showCloseGuiElem = + dialogOnExitOptionsElem->FirstChildElement("show_close_gui_button")) { - serverControlService = transport::TopicUtils::AsValidTopic( - serverControlElem->GetText()); + bool showCloseGuiButton{false}; + showCloseGuiElem->QueryBoolText(&showCloseGuiButton); + this->dataPtr->mainWin->SetExitDialogShowCloseGui(showCloseGuiButton); } - - if (serverControlService.empty()) + if (auto *shutdownTextElem = + dialogOnExitOptionsElem->FirstChildElement("shutdown_button_text")) { - gzerr << "Failed to create valid server control service" << std::endl; + this->dataPtr->mainWin->SetExitDialogShutdownText( + QString::fromStdString(shutdownTextElem->GetText())); } - else + if (auto *closeGuiTextElem = + dialogOnExitOptionsElem->FirstChildElement("close_gui_button_text")) { - gzmsg << "Using server control service [" << serverControlService - << "]" << std::endl; - this->dataPtr->mainWin->SetServerControlService(serverControlService); + this->dataPtr->mainWin->SetExitDialogCloseGuiText( + QString::fromStdString(closeGuiTextElem->GetText())); } } - this->ApplyConfig(); + // Server control service topic + std::string serverControlService{"/server_control"}; + auto *serverControlElem = + _winElem.FirstChildElement("server_control_service"); + if (nullptr != serverControlElem && nullptr != serverControlElem->GetText()) + { + serverControlService = transport::TopicUtils::AsValidTopic( + serverControlElem->GetText()); + } + if (serverControlService.empty()) + { + gzerr << "Failed to create valid server control service" << std::endl; + } + else + { + gzmsg << "Using server control service [" << serverControlService + << "]" << std::endl; + this->dataPtr->mainWin->SetServerControlService(serverControlService); + } return true; } - ///////////////////////////////////////////////// bool Application::LoadDefaultConfig() { @@ -519,11 +501,48 @@ void Application::SetDefaultConfigPath(const std::string &_path) } ///////////////////////////////////////////////// -std::string Application::DefaultConfigPath() +std::string Application::DefaultConfigPath() const { return this->dataPtr->defaultConfigPath; } +///////////////////////////////////////////////// +std::string Application::ResolveConfigFile(const std::string &_path) const +{ + std::string configFull = _path; + + // Check if the passed in config file exists. + // (If the default config path doesn't exist yet, it's expected behavior. + // It will be created the first time the user presses "Save configuration".) + if (!common::exists(configFull) && (configFull != this->DefaultConfigPath())) + { + // If not, then check environment variable + std::string configPathEnv; + common::env("GZ_GUI_RESOURCE_PATH", configPathEnv); + + if (!configPathEnv.empty()) + { + std::vector parentPaths = common::Split(configPathEnv, ':'); + for (const auto &parentPath : parentPaths) + { + std::string tempPath = common::joinPaths(parentPath, configFull); + if (common::exists(tempPath)) + { + configFull = tempPath; + break; + } + } + } + } + + if (common::isRelativePath(configFull)) + { + configFull = common::absPath(configFull); + } + + return configFull; +} + ///////////////////////////////////////////////// bool Application::LoadPlugin(const std::string &_filename, const tinyxml2::XMLElement *_pluginElem) diff --git a/src/plugins/minimal_scene/MinimalScene.cc b/src/plugins/minimal_scene/MinimalScene.cc index aa34a15a7..6479d69c1 100644 --- a/src/plugins/minimal_scene/MinimalScene.cc +++ b/src/plugins/minimal_scene/MinimalScene.cc @@ -762,11 +762,12 @@ std::string GzRenderer::Initialize(RenderThreadRhi &_rhi) scene->SetSkyEnabled(true); } - if (!scene->SetShadowTextureSize(rendering::LightType::DIRECTIONAL, - this->directionalLightTextureSize)) + if (this->directionalLightTextureSize.has_value() && + !scene->SetShadowTextureSize(rendering::LightType::DIRECTIONAL, + *this->directionalLightTextureSize)) { gzerr << "Unable to set directional light shadow to '" - << this->directionalLightTextureSize + << *this->directionalLightTextureSize << "'. Using default texture size of " << scene->ShadowTextureSize(rendering::LightType::DIRECTIONAL) << std::endl; diff --git a/src/plugins/minimal_scene/MinimalScene.hh b/src/plugins/minimal_scene/MinimalScene.hh index 46a7b7e40..ee61b96a9 100644 --- a/src/plugins/minimal_scene/MinimalScene.hh +++ b/src/plugins/minimal_scene/MinimalScene.hh @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -240,7 +241,7 @@ namespace gz::gui::plugins public: bool skyEnable = false; /// \brief Shadow texture size for directional light - public: unsigned int directionalLightTextureSize = 2048u; + public: std::optional directionalLightTextureSize; /// \brief Horizontal FOV of the camera; public: math::Angle cameraHFOV = math::Angle(M_PI * 0.5); diff --git a/tutorials/01_install.md b/tutorials/01_install.md index a8d7bfee0..e07b83210 100644 --- a/tutorials/01_install.md +++ b/tutorials/01_install.md @@ -60,7 +60,7 @@ Binary install is pending `gz-rendering` and `gz-gui` being added to conda-forge ## Source Install -### Ubuntu Focal 20.04 or above +### Ubuntu Noble 24.04 or above #### Install Prerequisites @@ -75,7 +75,7 @@ Add OSRF packages: Clone source code: ``` - # This checks out the default branch. You can append `-b ign-gui#` (replace # with a number) to checkout a specific version + # This checks out the default branch. You can append `-b gz-gui<#>` (replace # with a number) to checkout a specific version git clone http://github.com/gazebosim/gz-gui ``` @@ -161,7 +161,7 @@ Before [gz-rendering](https://github.com/gazebosim/gz-rendering) becomes availab 1. Navigate to where you would like to build the library, and clone the repository. ``` - # Optionally, append `-b ign-gui#` (replace # with a number) to check out a specific version + # Optionally, append `-b gz-gui#` (replace # with a number) to check out a specific version git clone https://github.com/gazebosim/gz-gui.git ``` diff --git a/tutorials/03_plugins.md b/tutorials/03_plugins.md index 47abe9514..b0b457411 100644 --- a/tutorials/03_plugins.md +++ b/tutorials/03_plugins.md @@ -20,7 +20,7 @@ Gazebo GUI will look for plugins on the following paths, in this order: 1. All paths set on the `GZ_GUI_PLUGIN_PATH` environment variable 2. All paths added by calling `gz::gui::addPluginPath` 3. `~/.gz/gui/plugins` -4. [Plugins which are installed with Gazebo GUI](https://gazebosim.org/api/gui/6.0/namespace gz_1_1gui_1_1plugins.html) +4. [Plugins which are installed with Gazebo GUI](https://gazebosim.org/api/gui/9/namespacegz_1_1gui_1_1plugins.html) ## Configuring plugins @@ -120,4 +120,4 @@ order: 1. All paths set on the `GZ_GUI_DISPLAY_PLUGIN_PATH` environment variable 2. `~/.gz/gui/display_plugins` -3. [Display plugins that are installed with Gazebo GUI](https://gazebosim.org/api/gui/0.1/namespace gz_1_1gui_1_1display_plugins.html) +3. [Display plugins that are installed with Gazebo GUI](https://gazebosim.org/api/gui/9/namespacegz_1_1gui_1_1plugins.html)