Skip to content

Commit

Permalink
Merged in 2_to_3_select (pull request #539)
Browse files Browse the repository at this point in the history
Forward port Selection to Citadel

Approved-by: Louise Poubel <[email protected]>
  • Loading branch information
chapulina committed Mar 3, 2020
2 parents a2b4ac8 + 9769e3a commit c66b467
Show file tree
Hide file tree
Showing 13 changed files with 1,585 additions and 81 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ for dependency installation instructions for each supported operating system.
1. Install third-party libraries:
```
sudo apt-get -y install cmake build-essential curl cppcheck g++-8 libbenchmark-dev libgflags-dev doxygen ruby-ronn libtinyxml2-dev libtinyxml-dev software-properties-common libeigen3-dev
sudo apt-get -y install cmake build-essential curl cppcheck g++-8 libbenchmark-dev libgflags-dev doxygen ruby-ronn libtinyxml2-dev libtinyxml-dev software-properties-common libeigen3-dev qtdeclarative5-models-plugin
```
2. Install required Ignition libraries:
Expand Down
117 changes: 117 additions & 0 deletions include/ignition/gazebo/gui/GuiEvents.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright (C) 2020 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.
*
*/
#ifndef IGNITION_GAZEBO_GUI_GUIEVENTS_HH_
#define IGNITION_GAZEBO_GUI_GUIEVENTS_HH_

#include <QEvent>
#include <utility>
#include <vector>
#include "ignition/gazebo/Entity.hh"
#include "ignition/gazebo/config.hh"

namespace ignition
{
namespace gazebo
{
namespace gui {
// Inline bracket to help doxygen filtering.
inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
/// \brief Namespace for all events. Refer to the EventManager class for
/// more information about events.
namespace events
{
/// \brief Event that notifies when new entities have been selected.
class EntitiesSelected : public QEvent
{
/// \brief Constructor
/// \param[in] _entities All the selected entities
/// \param[in] _fromUser True if the event was directly generated by the
/// user, false in case it's been propagated through a different mechanism.
public: explicit EntitiesSelected(
const std::vector<Entity> &_entities, // NOLINT
bool _fromUser = false)
: QEvent(kType), entities(_entities), fromUser(_fromUser)
{
}

/// \brief Get the data sent with the event.
/// \return The entities being selected.
public: std::vector<Entity> Data() const
{
return this->entities;
}

/// \brief Get whether the event was generated by the user.
/// \return True for the user.
public: bool FromUser() const
{
return this->fromUser;
}

/// \brief Unique type for this event.
static const QEvent::Type kType = QEvent::Type(QEvent::User + 1);

/// \brief The selected entities.
private: std::vector<Entity> entities;

/// \brief Whether the event was generated by the user,
private: bool fromUser{false};
};

/// \brief Event that notifies when all entities have been deselected.
class DeselectAllEntities : public QEvent
{
/// \brief Constructor
/// \param[in] _fromUser True if the event was directly generated by the
/// user, false in case it's been propagated through a different mechanism.
public: explicit DeselectAllEntities(bool _fromUser = false)
: QEvent(kType), fromUser(_fromUser)
{
}

/// \brief Get whether the event was generated by the user.
/// \return True for the user.
public: bool FromUser() const
{
return this->fromUser;
}

/// \brief Unique type for this event.
static const QEvent::Type kType = QEvent::Type(QEvent::User + 2);

/// \brief Whether the event was generated by the user,
private: bool fromUser{false};
};

/// \brief Event called in the render thread of a 3D scene.
/// It's safe to make rendering calls in this event's callback.
class Render : public QEvent
{
public: Render()
: QEvent(Type)
{
}
/// \brief Unique type for this event.
static const QEvent::Type Type = QEvent::Type(QEvent::User + 3);
};
} // namespace events
}
} // namespace gui
} // namespace gazebo
} // namespace ignition

#endif // IGNITION_GAZEBO_GUI_GUIEVENTS_HH_
22 changes: 20 additions & 2 deletions include/ignition/gazebo/rendering/RenderUtil.hh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <memory>
#include <string>
#include <vector>

#include <sdf/Sensor.hh>

Expand Down Expand Up @@ -120,12 +121,29 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {

/// \brief Set the entity being selected
/// \param[in] _node Node representing the selected entity
/// \TODO(anyone) Make const ref when merging forward
// NOLINTNEXTLINE
public: void SetSelectedEntity(rendering::NodePtr _node);

/// \brief Get the entity being selected
/// \return Node representing the selected entity
/// \brief Get the entity for a given node.
/// \param[in] _node Node to get the entity for.
/// \return The entity for that node, or `kNullEntity` for no entity.
/// \deprecated Use `ignition::rendering::Visual::UserData` instead.
public: Entity IGN_DEPRECATED(3)
EntityFromNode(const rendering::NodePtr &_node);

/// \brief Get the entity being selected. This will only return the
/// last entity selected.
/// \TODO(anyone) Deprecate in favour of SelectedEntities
public: rendering::NodePtr SelectedEntity() const;

/// \brief Get the entities currently selected, in order of selection.
/// \return Map of currently selected entities, entity to rendering node id
public: std::vector<Entity> SelectedEntities() const;

/// \brief Clears the set of selected entities and lowlights all of them.
public: void DeselectAllEntities();

/// \brief Set whether the transform controls are currently being dragged.
/// \param[in] _active True if active.
public: void SetTransformActive(bool _active);
Expand Down
19 changes: 18 additions & 1 deletion include/ignition/gazebo/rendering/SceneManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
/// \return true if exists, false otherwise
public: bool HasEntity(Entity _id) const;

/// \brief Get a rendering node given an id
/// \brief Get a rendering node given an entity id
/// \param[in] _id Entity's unique id
/// \return Pointer to requested entity's node
public: rendering::NodePtr NodeById(Entity _id) const;
Expand All @@ -144,6 +144,13 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
/// \param[in] _id Entity's unique id
public: void RemoveEntity(Entity _id);

/// \brief Get the entity for a given node.
/// \param[in] _node Node to get the entity for.
/// \return The entity for that node, or `kNullEntity` for no entity.
/// \todo(anyone) Deprecate in favour of
/// `ignition::rendering::Node::UserData` once that's available.
public: Entity EntityFromNode(const rendering::NodePtr &_node) const;

/// \brief Load a geometry
/// \param[in] _geom Geometry sdf dom
/// \param[out] _scale Geometry scale that will be set based on sdf
Expand All @@ -164,9 +171,19 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
/// Usually, this will be a model or a light.
/// \param[in] _visual Child visual
/// \return Top level visual containining this visual
/// \TODO(anyone) Make it const ref when merging forward
public: rendering::VisualPtr TopLevelVisual(
// NOLINTNEXTLINE
rendering::VisualPtr _visual) const;

/// \brief Get the top level node for the given node, which
/// is the ancestor which is a direct child to the root visual.
/// Usually, this will be a model or a light.
/// \param[in] _node Child node
/// \return Top level node containining this node
public: rendering::NodePtr TopLevelNode(
const rendering::NodePtr &_node) const;

/// \internal
/// \brief Pointer to private data class
private: std::unique_ptr<SceneManagerPrivate> dataPtr;
Expand Down
79 changes: 77 additions & 2 deletions src/gui/plugins/entity_tree/EntityTree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <ignition/common/Console.hh>
#include <ignition/common/Profiler.hh>
#include <ignition/gui/Application.hh>
#include <ignition/gui/MainWindow.hh>
#include <ignition/plugin/Register.hh>

#include "ignition/gazebo/components/Collision.hh"
Expand All @@ -34,6 +35,7 @@
#include "ignition/gazebo/components/Visual.hh"
#include "ignition/gazebo/components/World.hh"
#include "ignition/gazebo/EntityComponentManager.hh"
#include "ignition/gazebo/gui/GuiEvents.hh"

#include "EntityTree.hh"

Expand Down Expand Up @@ -223,6 +225,21 @@ QString TreeModel::ScopedName(const QModelIndex &_index) const
return scopedName;
}

/////////////////////////////////////////////////
unsigned int TreeModel::EntityId(const QModelIndex &_index) const
{
Entity entity{kNullEntity};
QStandardItem *item = this->itemFromIndex(_index);
if (!item)
return entity;

QVariant entityVar = item->data(this->roleNames().key("entity"));
if (!entityVar.isValid())
return entity;

return entityVar.toUInt();
}

/////////////////////////////////////////////////
QHash<int, QByteArray> TreeModel::roleNames() const
{
Expand All @@ -237,8 +254,8 @@ EntityTree::EntityTree()
: GuiSystem(), dataPtr(std::make_unique<EntityTreePrivate>())
{
// Connect model
gui::App()->Engine()->rootContext()->setContextProperty("EntityTreeModel",
&this->dataPtr->treeModel);
ignition::gui::App()->Engine()->rootContext()->setContextProperty(
"EntityTreeModel", &this->dataPtr->treeModel);
}

/////////////////////////////////////////////////
Expand All @@ -249,6 +266,9 @@ void EntityTree::LoadConfig(const tinyxml2::XMLElement *)
{
if (this->title.empty())
this->title = "Entity tree";

ignition::gui::App()->findChild<
ignition::gui::MainWindow *>()->installEventFilter(this);
}

//////////////////////////////////////////////////
Expand Down Expand Up @@ -336,6 +356,61 @@ void EntityTree::Update(const UpdateInfo &, EntityComponentManager &_ecm)
});
}

/////////////////////////////////////////////////
void EntityTree::OnEntitySelectedFromQml(unsigned int _entity)
{
std::vector<Entity> entitySet {_entity};
auto event = new gui::events::EntitiesSelected(entitySet, true);
ignition::gui::App()->sendEvent(
ignition::gui::App()->findChild<ignition::gui::MainWindow *>(),
event);
}

/////////////////////////////////////////////////
void EntityTree::DeselectAllEntities()
{
auto event = new gui::events::DeselectAllEntities(true);
ignition::gui::App()->sendEvent(
ignition::gui::App()->findChild<ignition::gui::MainWindow *>(),
event);
}

/////////////////////////////////////////////////
bool EntityTree::eventFilter(QObject *_obj, QEvent *_event)
{
if (_event->type() == ignition::gazebo::gui::events::EntitiesSelected::kType)
{
auto selectedEvent =
reinterpret_cast<gui::events::EntitiesSelected *>(_event);
if (selectedEvent && !selectedEvent->Data().empty())
{
for (const auto &entity : selectedEvent->Data())
{
if (entity == kNullEntity)
continue;

QMetaObject::invokeMethod(this->PluginItem(), "onEntitySelectedFromCpp",
Qt::QueuedConnection, Q_ARG(QVariant,
QVariant(static_cast<unsigned int>(entity))));
}
}
}
else if (_event->type() ==
ignition::gazebo::gui::events::DeselectAllEntities::kType)
{
auto deselectAllEvent =
reinterpret_cast<gui::events::DeselectAllEntities *>(_event);
if (deselectAllEvent)
{
QMetaObject::invokeMethod(this->PluginItem(), "deselectAllEntities",
Qt::QueuedConnection);
}
}

// Standard event processing
return QObject::eventFilter(_obj, _event);
}

// Register this plugin
IGNITION_ADD_PLUGIN(ignition::gazebo::EntityTree,
ignition::gui::Plugin)
17 changes: 17 additions & 0 deletions src/gui/plugins/entity_tree/EntityTree.hh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ namespace gazebo
/// \return Scoped name of the entity
public: Q_INVOKABLE QString ScopedName(const QModelIndex &_index) const;

/// \brief Get the entity ID of a tree item at specified index
/// \param[in] _index Model index
/// \return Entity ID
public: Q_INVOKABLE unsigned int EntityId(const QModelIndex &_index) const;

/// \brief Keep track of which item corresponds to which entity.
private: std::map<Entity, QStandardItem *> entityItems;
};
Expand All @@ -92,6 +97,18 @@ namespace gazebo
// Documentation inherited
public: void Update(const UpdateInfo &, EntityComponentManager &) override;

/// \brief Callback when an entity has been selected. This should be
/// called from QML.
/// \param[in] _entity Entity being selected.
public: Q_INVOKABLE void OnEntitySelectedFromQml(unsigned int _entity);

/// \brief Callback when all entities have been deselected.
/// This should be called from QML.
public: Q_INVOKABLE void DeselectAllEntities();

// Documentation inherited
protected: bool eventFilter(QObject *_obj, QEvent *_event) override;

/// \internal
/// \brief Pointer to private data.
private: std::unique_ptr<EntityTreePrivate> dataPtr;
Expand Down
Loading

0 comments on commit c66b467

Please sign in to comment.