diff --git a/include/ignition/gazebo/gui/GuiEvents.hh b/include/ignition/gazebo/gui/GuiEvents.hh index d05645a49e..8bac275993 100644 --- a/include/ignition/gazebo/gui/GuiEvents.hh +++ b/include/ignition/gazebo/gui/GuiEvents.hh @@ -23,6 +23,8 @@ #include #include #include +#include +#include "ignition/gazebo/gui/Export.hh" #include "ignition/gazebo/Entity.hh" #include "ignition/gazebo/config.hh" @@ -38,7 +40,7 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { namespace events { /// \brief Event that notifies when new entities have been selected. - class EntitiesSelected : public QEvent + class IGNITION_GAZEBO_GUI_VISIBLE EntitiesSelected : public QEvent { /// \brief Constructor /// \param[in] _entities All the selected entities @@ -76,7 +78,7 @@ namespace events }; /// \brief Event that notifies when all entities have been deselected. - class DeselectAllEntities : public QEvent + class IGNITION_GAZEBO_GUI_VISIBLE DeselectAllEntities : public QEvent { /// \brief Constructor /// \param[in] _fromUser True if the event was directly generated by the @@ -100,68 +102,60 @@ namespace events private: bool fromUser{false}; }; - /// \brief Event that contains newly created and removed entities - class AddedRemovedEntities : public QEvent + /// \brief Event that contains entities newly created or removed from the + /// GUI, but that aren't present on the server yet. + /// \sa NewRemovedEntities + class IGNITION_GAZEBO_GUI_VISIBLE GuiNewRemovedEntities : public QEvent { /// \brief Constructor /// \param[in] _newEntities Set of newly created entities /// \param[in] _removedEntities Set of recently removed entities - public: AddedRemovedEntities(const std::set &_newEntities, - const std::set &_removedEntities) - : QEvent(kType), newEntities(_newEntities), - removedEntities(_removedEntities) - { - } + public: GuiNewRemovedEntities(const std::set &_newEntities, + const std::set &_removedEntities); /// \brief Get the set of newly created entities - public: const std::set &NewEntities() const - { - return this->newEntities; - } + public: const std::set &NewEntities() const; /// \brief Get the set of recently removed entities - public: const std::set &RemovedEntities() const - { - return this->removedEntities; - } + public: const std::set &RemovedEntities() const; /// \brief Unique type for this event. static const QEvent::Type kType = QEvent::Type(QEvent::User + 3); - /// \brief Set of newly created entities - private: std::set newEntities; - - /// \brief Set of recently removed entities - private: std::set removedEntities; + /// \internal + /// \brief Private data pointer + IGN_UTILS_IMPL_PTR(dataPtr) }; - /// \brief Event that notifies when new entities have been removed. - class RemovedEntities : public QEvent + /// \brief Event that notifies when new entities have been created or removed + /// on the server. This is a duplication of what `GuiSystem`s would get from + /// `EachNew` / `EachRemoved` ECM calls. + /// \sa GuiNewRemovedEntities + class IGNITION_GAZEBO_GUI_VISIBLE NewRemovedEntities : public QEvent { /// \brief Constructor - /// \param[in] _entities All the removed entities - public: explicit RemovedEntities(const std::vector &_entities) - : QEvent(kType), entities(_entities) - { - } + /// \param[in] _newEntities Set of newly created entities + /// \param[in] _removedEntities Set of recently removed entities + public: NewRemovedEntities(const std::set &_newEntities, + const std::set &_removedEntities); - /// \brief Get the data sent with the event. - /// \return The entities being removed. - public: std::vector Data() const - { - return this->entities; - } + /// \brief Get the set of newly created entities + public: const std::set &NewEntities() const; + + /// \brief Get the set of recently removed entities + public: const std::set &RemovedEntities() const; /// \brief Unique type for this event. static const QEvent::Type kType = QEvent::Type(QEvent::User + 4); - /// \brief The removed entities. - private: std::vector entities; + /// \internal + /// \brief Private data pointer + IGN_UTILS_IMPL_PTR(dataPtr) }; /// \brief True if a transform control is currently active (translate / /// rotate / scale). False if we're in selection mode. - class TransformControlModeActive : public QEvent + class IGNITION_GAZEBO_GUI_VISIBLE TransformControlModeActive : public QEvent { /// \brief Constructor /// \param[in] _tranformModeActive is the transform control mode active diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index fa9d276b0f..ae0de7d3da 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,6 +1,7 @@ set (gui_sources AboutDialogHandler.cc Gui.cc + GuiEvents.cc GuiFileHandler.cc GuiRunner.cc PathManager.cc @@ -8,6 +9,7 @@ set (gui_sources set (gtest_sources Gui_TEST.cc + GuiEvents_TEST.cc ) add_subdirectory(plugins) diff --git a/src/gui/GuiEvents.cc b/src/gui/GuiEvents.cc new file mode 100644 index 0000000000..dd89de306f --- /dev/null +++ b/src/gui/GuiEvents.cc @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include "ignition/gazebo/gui/GuiEvents.hh" + +class ignition::gazebo::gui::events::GuiNewRemovedEntities::Implementation +{ + /// \brief Set of newly created entities + public: std::set newEntities; + + /// \brief Set of recently removed entities + public: std::set removedEntities; +}; + +class ignition::gazebo::gui::events::NewRemovedEntities::Implementation +{ + /// \brief Set of newly created entities + public: std::set newEntities; + + /// \brief Set of recently removed entities + public: std::set removedEntities; +}; + +using namespace ignition; +using namespace gazebo; +using namespace gui; +using namespace events; + +///////////////////////////////////////////////// +GuiNewRemovedEntities::GuiNewRemovedEntities( + const std::set &_newEntities, + const std::set &_removedEntities) + : QEvent(kType), dataPtr(utils::MakeImpl()) +{ + this->dataPtr->newEntities = _newEntities; + this->dataPtr->removedEntities = _removedEntities; +} + +///////////////////////////////////////////////// +const std::set &GuiNewRemovedEntities::NewEntities() const +{ + return this->dataPtr->newEntities; +} + +///////////////////////////////////////////////// +const std::set &GuiNewRemovedEntities::RemovedEntities() const +{ + return this->dataPtr->removedEntities; +} + +///////////////////////////////////////////////// +NewRemovedEntities::NewRemovedEntities( + const std::set &_newEntities, + const std::set &_removedEntities) + : QEvent(kType), dataPtr(utils::MakeImpl()) +{ + this->dataPtr->newEntities = _newEntities; + this->dataPtr->removedEntities = _removedEntities; +} + +///////////////////////////////////////////////// +const std::set &NewRemovedEntities::NewEntities() const +{ + return this->dataPtr->newEntities; +} + +///////////////////////////////////////////////// +const std::set &NewRemovedEntities::RemovedEntities() const +{ + return this->dataPtr->removedEntities; +} diff --git a/src/gui/GuiEvents_TEST.cc b/src/gui/GuiEvents_TEST.cc new file mode 100644 index 0000000000..cb0bebc999 --- /dev/null +++ b/src/gui/GuiEvents_TEST.cc @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include + +#include "ignition/gazebo/test_config.hh" +#include "ignition/gazebo/gui/GuiEvents.hh" + +using namespace ignition; +using namespace gazebo; +using namespace gui; + +///////////////////////////////////////////////// +TEST(GuiEventsTest, GuiNewRemovedEntities) +{ + events::GuiNewRemovedEntities event({1, 2, 3}, {4, 5}); + + EXPECT_LT(QEvent::User, event.type()); + + auto addedEntities = event.NewEntities(); + EXPECT_EQ(3u, addedEntities.size()); + EXPECT_NE(addedEntities.find(1), addedEntities.end()); + EXPECT_NE(addedEntities.find(2), addedEntities.end()); + EXPECT_NE(addedEntities.find(3), addedEntities.end()); + EXPECT_EQ(addedEntities.find(100), addedEntities.end()); + + auto removedEntities = event.RemovedEntities(); + EXPECT_EQ(2u, removedEntities.size()); + EXPECT_NE(removedEntities.find(4), removedEntities.end()); + EXPECT_NE(removedEntities.find(5), removedEntities.end()); + EXPECT_EQ(removedEntities.find(6), removedEntities.end()); +} + +///////////////////////////////////////////////// +TEST(GuiEventsTest, NewRemovedEntities) +{ + events::NewRemovedEntities event({1, 2, 3}, {4, 5}); + + EXPECT_LT(QEvent::User, event.type()); + + auto addedEntities = event.NewEntities(); + EXPECT_EQ(3u, addedEntities.size()); + EXPECT_NE(addedEntities.find(1), addedEntities.end()); + EXPECT_NE(addedEntities.find(2), addedEntities.end()); + EXPECT_NE(addedEntities.find(3), addedEntities.end()); + EXPECT_EQ(addedEntities.find(100), addedEntities.end()); + + auto removedEntities = event.RemovedEntities(); + EXPECT_EQ(2u, removedEntities.size()); + EXPECT_NE(removedEntities.find(4), removedEntities.end()); + EXPECT_NE(removedEntities.find(5), removedEntities.end()); + EXPECT_EQ(removedEntities.find(6), removedEntities.end()); +} diff --git a/src/gui/plugins/entity_tree/EntityTree.cc b/src/gui/plugins/entity_tree/EntityTree.cc index de909caa38..a1eb39a2e1 100644 --- a/src/gui/plugins/entity_tree/EntityTree.cc +++ b/src/gui/plugins/entity_tree/EntityTree.cc @@ -556,13 +556,15 @@ bool EntityTree::eventFilter(QObject *_obj, QEvent *_event) } } else if (_event->type() == - ignition::gazebo::gui::events::AddedRemovedEntities::kType) + ignition::gazebo::gui::events::GuiNewRemovedEntities::kType) { std::lock_guard lock(this->dataPtr->newRemovedEntityMutex); auto addedRemovedEvent = - reinterpret_cast(_event); + reinterpret_cast(_event); if (addedRemovedEvent) { + // TODO(chapulina) Make these entities visually different from entities + // created from the server. for (auto entity : addedRemovedEvent->NewEntities()) this->dataPtr->newEntities.insert(entity); diff --git a/src/gui/plugins/scene_manager/GzSceneManager.cc b/src/gui/plugins/scene_manager/GzSceneManager.cc index 802c350575..88710b0e9b 100644 --- a/src/gui/plugins/scene_manager/GzSceneManager.cc +++ b/src/gui/plugins/scene_manager/GzSceneManager.cc @@ -17,7 +17,7 @@ #include "GzSceneManager.hh" -#include +#include #include #include @@ -85,16 +85,25 @@ void GzSceneManager::Update(const UpdateInfo &_info, this->dataPtr->renderUtil.UpdateECM(_info, _ecm); this->dataPtr->renderUtil.UpdateFromECM(_info, _ecm); - // Emit entities removed event - std::vector removed; + // Emit entities created / removed event for gui::Plugins which don't have + // direct access to the ECM. + std::set created; + _ecm.EachNew( + [&](const Entity &_entity, const components::Name *)->bool + { + created.insert(_entity); + return true; + }); + std::set removed; _ecm.EachRemoved( [&](const Entity &_entity, const components::Name *)->bool { - removed.push_back(_entity); + removed.insert(_entity); return true; }); - ignition::gazebo::gui::events::RemovedEntities removedEvent(removed); + ignition::gazebo::gui::events::NewRemovedEntities removedEvent( + created, removed); ignition::gui::App()->sendEvent( ignition::gui::App()->findChild(), &removedEvent); diff --git a/src/gui/plugins/select_entities/SelectEntities.cc b/src/gui/plugins/select_entities/SelectEntities.cc index c08dc0963b..d3513888f7 100644 --- a/src/gui/plugins/select_entities/SelectEntities.cc +++ b/src/gui/plugins/select_entities/SelectEntities.cc @@ -574,13 +574,13 @@ bool SelectEntities::eventFilter(QObject *_obj, QEvent *_event) } } else if (_event->type() == - ignition::gazebo::gui::events::RemovedEntities::kType) + ignition::gazebo::gui::events::NewRemovedEntities::kType) { if (!this->dataPtr->wireBoxes.empty()) { - auto removedEvent = - reinterpret_cast(_event); - for (auto &entity : removedEvent->Data()) + auto event = + reinterpret_cast(_event); + for (auto &entity : event->RemovedEntities()) { auto wireBoxIt = this->dataPtr->wireBoxes.find(entity); if (wireBoxIt != this->dataPtr->wireBoxes.end())