Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Track and Follow options in gui EntityContextMenu #2402

Merged
merged 8 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 99 additions & 8 deletions src/gui/plugins/modules/EntityContextMenu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
#include "EntityContextMenu.hh"

#include <gz/msgs/boolean.pb.h>
#include <gz/msgs/stringmsg.pb.h>
#include <gz/msgs/cameratrack.pb.h>
bperseghetti marked this conversation as resolved.
Show resolved Hide resolved
#include <gz/msgs/entity.pb.h>
#include <gz/msgs/stringmsg.pb.h>

#include <iostream>
#include <mutex>
bperseghetti marked this conversation as resolved.
Show resolved Hide resolved
#include <string>

#include <gz/common/Console.hh>
Expand All @@ -35,14 +37,21 @@ namespace gz::sim
/// \brief Private data class for EntityContextMenu
class EntityContextMenuPrivate
{

/// \brief Protects variable changed through services.
public: std::mutex mutex;

/// \brief Gazebo communication node.
public: transport::Node node;

/// \brief Move to service name
public: std::string moveToService;

/// \brief Follow service name
public: std::string followService;
/// \brief Track topic name
public: std::string trackTopic;

/// \brief Currently tracked topic name
public: std::string currentTrackTopic;

/// \brief Remove service name
public: std::string removeService;
Expand Down Expand Up @@ -76,12 +85,41 @@ namespace gz::sim

/// \brief Name of world.
public: std::string worldName;

/// \brief Storing last follow target for look at.
public: std::string followTargetLookAt;

/// \brief Flag used to disable look at when not following target.
public: bool followingTarget{false};

/// \brief /gui/track publisher
public: transport::Node::Publisher trackPub;
};
}

using namespace gz;
using namespace sim;

/////////////////////////////////////////////////
void EntityContextMenu::OnCurrentlyTrackedSub(const msgs::CameraTrack &_msg)
{
std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
if (_msg.track_mode() == gz::msgs::CameraTrack::FOLLOW ||
_msg.track_mode() == gz::msgs::CameraTrack::FOLLOW_LOOK_AT ||
_msg.track_mode() == gz::msgs::CameraTrack::FOLLOW_FREE_LOOK)
{
this->dataPtr->followingTarget = true;
this->FollowingTargetChanged();
}
else
{
this->dataPtr->followingTarget = false;
this->FollowingTargetChanged();
}

return;
bperseghetti marked this conversation as resolved.
Show resolved Hide resolved
}

/////////////////////////////////////////////////
void GzSimPlugin::registerTypes(const char *_uri)
{
Expand All @@ -94,11 +132,17 @@ void GzSimPlugin::registerTypes(const char *_uri)
EntityContextMenu::EntityContextMenu()
: dataPtr(std::make_unique<EntityContextMenuPrivate>())
{
this->dataPtr->currentTrackTopic = "/gui/currently_tracked";
this->dataPtr->node.Subscribe(this->dataPtr->currentTrackTopic,
&EntityContextMenu::OnCurrentlyTrackedSub, this);
gzmsg << "Currently tracking topic on ["
<< this->dataPtr->currentTrackTopic << "]" << std::endl;

// For move to service requests
this->dataPtr->moveToService = "/gui/move_to";

// For follow service requests
this->dataPtr->followService = "/gui/follow";
// For track topic message
this->dataPtr->trackTopic = "/gui/track";

// For remove service requests
this->dataPtr->removeService = "/world/default/remove";
Expand Down Expand Up @@ -129,11 +173,27 @@ EntityContextMenu::EntityContextMenu()

// For paste service requests
this->dataPtr->pasteService = "/gui/paste";

this->dataPtr->trackPub =
this->dataPtr->node.Advertise<msgs::CameraTrack>(this->dataPtr->trackTopic);
}

/////////////////////////////////////////////////
EntityContextMenu::~EntityContextMenu() = default;

/////////////////////////////////////////////////
void EntityContextMenu::SetFollowingTarget(bool &_followingTarget)
{
this->dataPtr->followingTarget = _followingTarget;
this->FollowingTargetChanged();
}

/////////////////////////////////////////////////
bool EntityContextMenu::FollowingTarget() const
{
return this->dataPtr->followingTarget;
}

/////////////////////////////////////////////////
void EntityContextMenu::OnRemove(
const QString &_data, const QString &_type)
Expand Down Expand Up @@ -196,9 +256,40 @@ void EntityContextMenu::OnRequest(const QString &_request, const QString &_data)
}
else if (request == "follow")
{
msgs::StringMsg req;
req.set_data(_data.toStdString());
this->dataPtr->node.Request(this->dataPtr->followService, req, cb);
msgs::CameraTrack followMsg;
followMsg.mutable_follow_target()->set_name(_data.toStdString());
followMsg.set_track_mode(msgs::CameraTrack::FOLLOW);
this->dataPtr->followTargetLookAt = followMsg.follow_target().name();
gzmsg << "Follow target: " << followMsg.follow_target().name() << std::endl;
this->dataPtr->trackPub.Publish(followMsg);
}
else if (request == "free_look")
{
msgs::CameraTrack followMsg;
followMsg.mutable_follow_target()->set_name(_data.toStdString());
followMsg.set_track_mode(msgs::CameraTrack::FOLLOW_FREE_LOOK);
this->dataPtr->followTargetLookAt = followMsg.follow_target().name();
gzmsg << "Follow target: " << followMsg.follow_target().name() << std::endl;
this->dataPtr->trackPub.Publish(followMsg);
}
else if (request == "look_at")
{
msgs::CameraTrack followMsg;
followMsg.mutable_track_target()->set_name(_data.toStdString());
followMsg.set_track_mode(msgs::CameraTrack::FOLLOW_LOOK_AT);
followMsg.mutable_follow_target()->set_name(
this->dataPtr->followTargetLookAt);
gzmsg << "Follow target: " << followMsg.follow_target().name() << std::endl;
gzmsg << "Look at target: " << followMsg.track_target().name() << std::endl;
this->dataPtr->trackPub.Publish(followMsg);
}
else if (request == "track")
{
msgs::CameraTrack trackMsg;
trackMsg.mutable_track_target()->set_name(_data.toStdString());
trackMsg.set_track_mode(msgs::CameraTrack::TRACK);
gzmsg << "Track target: " << trackMsg.track_target().name() << std::endl;
this->dataPtr->trackPub.Publish(trackMsg);
}
else if (request == "view_transparent")
{
Expand Down
23 changes: 23 additions & 0 deletions src/gui/plugins/modules/EntityContextMenu.hh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define GZ_SIM_GUI_ENTITYCONTEXTMENU_HH_

#include <gz/gui/qt.h>
#include <gz/msgs/cameratrack.pb.h>
#include <QtQml/QQmlExtensionPlugin>
#include <memory>

Expand Down Expand Up @@ -46,13 +47,35 @@ namespace sim
class EntityContextMenu : public QQuickItem
{
Q_OBJECT
/// \brief followingTarget
Q_PROPERTY(
bool followingTarget
READ FollowingTarget
WRITE SetFollowingTarget
NOTIFY FollowingTargetChanged
)

/// \brief Constructor
public: EntityContextMenu();

/// \brief Destructor
public: ~EntityContextMenu() override;

/// \brief Get whether it is following target
/// \return True if followingTarget
public: Q_INVOKABLE bool FollowingTarget() const;

/// \brief Set whether followingTarget
/// \param[in] _followingTarget True if followingTarget
public: Q_INVOKABLE void SetFollowingTarget(bool &_followingTarget);

/// \brief Notify that followingTarget has changed
signals: void FollowingTargetChanged();

/// \brief Callback function to get data from the message
/// \param[in] _msg CameraTrack message
public: void OnCurrentlyTrackedSub(const msgs::CameraTrack &_msg);

/// \brief Callback when a context menu item is invoked
/// \param[in] _data Request data
/// \param[in] _type Entity type
Expand Down
56 changes: 52 additions & 4 deletions src/gui/plugins/modules/EntityContextMenu.qml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,19 @@ Item {
onTriggered: context.OnRequest("move_to", context.entity)
}
MenuItem {
id: followMenu
text: "Follow"
onTriggered: context.OnRequest("follow", context.entity)
id: followOptionsSubmenu
text: "Follow Options >"
MouseArea {
id: followOptionsSubMouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: secondMenu.open()
}
}
MenuItem {
id: trackMenu
text: "Track"
onTriggered: context.OnRequest("track", context.entity)
}
MenuItem {
id: removeMenu
Expand Down Expand Up @@ -67,13 +77,42 @@ Item {
id: viewSubMouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: secondMenu.open()
onEntered: thirdMenu.open()
}
}
}
Menu {
id: secondMenu
x: menu.x + menu.width
y: menu.y + followOptionsSubmenu.y
MenuItem {
id: followMenu
text: "Follow"
onTriggered: {
menu.close()
context.OnRequest("follow", context.entity)
}
}
MenuItem {
id: followFreeLookMenu
text: "Free Look"
onTriggered: {
menu.close()
context.OnRequest("free_look", context.entity)
}
}
MenuItem {
id: followLookAtMenu
text: "Look At"
onTriggered: {
menu.close()
context.OnRequest("look_at", context.entity)
}
}
}
Menu {
id: thirdMenu
x: menu.x + menu.width
y: menu.y + viewSubmenu.y
MenuItem {
id: viewCOMMenu
Expand Down Expand Up @@ -140,6 +179,9 @@ Item {
context.type = _type
moveToMenu.enabled = false
followMenu.enabled = false
followFreeLookMenu.enabled = false
followLookAtMenu.enabled = false
trackMenu.enabled = false
removeMenu.enabled = false
viewTransparentMenu.enabled = false;
viewCOMMenu.enabled = false;
Expand All @@ -156,6 +198,12 @@ Item {
{
moveToMenu.enabled = true
followMenu.enabled = true
followFreeLookMenu.enabled = true
if (context.followingTarget)
{
followLookAtMenu.enabled = true
}
trackMenu.enabled = true
}

if (context.type == "model" || context.type == "light")
Expand Down
Loading