-
Notifications
You must be signed in to change notification settings - Fork 268
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: ahcorde <ahcorde@gmail.com>
- Loading branch information
Showing
7 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
gz_add_gui_plugin(EntityContextMenuPlugin | ||
SOURCES | ||
EntityContextMenuPlugin.cc | ||
QT_HEADERS | ||
EntityContextMenuPlugin.hh | ||
PUBLIC_LINK_LIBS | ||
${PROJECT_LIBRARY_TARGET_NAME}-rendering | ||
) |
207 changes: 207 additions & 0 deletions
207
src/gui/plugins/entity_context_menu/EntityContextMenuPlugin.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/* | ||
* 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 "EntityContextMenuPlugin.hh" | ||
|
||
#include <iostream> | ||
|
||
#include <QtQml> | ||
|
||
#include <ignition/common/Console.hh> | ||
#include <ignition/common/MouseEvent.hh> | ||
|
||
#include <ignition/gui/Application.hh> | ||
#include <ignition/gui/GuiEvents.hh> | ||
#include <ignition/gui/Helpers.hh> | ||
#include <ignition/gui/MainWindow.hh> | ||
|
||
#include <ignition/plugin/Register.hh> | ||
|
||
#include <ignition/rendering/Camera.hh> | ||
#include <ignition/rendering/RenderingIface.hh> | ||
#include <ignition/rendering/Visual.hh> | ||
#include <ignition/rendering/Scene.hh> | ||
|
||
namespace ignition::gazebo | ||
{ | ||
class EntityContextMenuPrivate | ||
{ | ||
/// \brief Perform operations in the render thread. | ||
public: void OnRender(); | ||
|
||
/// \brief Pointer to the rendering scene | ||
public: rendering::ScenePtr scene{nullptr}; | ||
|
||
/// \brief User camera | ||
public: rendering::CameraPtr camera{nullptr}; | ||
|
||
/// \brief Entity context menu hanlder | ||
public: EntityContextMenuHanlder entityContextMenuHanlder; | ||
}; | ||
} | ||
|
||
using namespace ignition; | ||
using namespace gazebo; | ||
|
||
///////////////////////////////////////////////// | ||
void EntityContextMenuPrivate::OnRender() | ||
{ | ||
if (nullptr == this->scene) | ||
{ | ||
this->scene = rendering::sceneFromFirstRenderEngine(); | ||
if (nullptr == this->scene) | ||
{ | ||
return; | ||
} | ||
|
||
for (unsigned int i = 0; i < this->scene->NodeCount(); ++i) | ||
{ | ||
auto cam = std::dynamic_pointer_cast<rendering::Camera>( | ||
this->scene->NodeByIndex(i)); | ||
if (cam) | ||
{ | ||
if (std::get<bool>(cam->UserData("user-camera"))) | ||
{ | ||
this->camera = cam; | ||
|
||
igndbg << "Spawn plugin is using camera [" | ||
<< this->camera->Name() << "]" << std::endl; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
///////////////////////////////////////////////// | ||
EntityContextMenu::EntityContextMenu() | ||
: gui::Plugin(), dataPtr(std::make_unique<EntityContextMenuPrivate>()) | ||
{ | ||
qmlRegisterType<EntityContextMenuItem>( | ||
"RenderWindowOverlay", 1, 0, "RenderWindowOverlay"); | ||
} | ||
|
||
EntityContextMenu::~EntityContextMenu() = default; | ||
|
||
///////////////////////////////////////////////// | ||
void EntityContextMenu::LoadConfig(const tinyxml2::XMLElement *) | ||
{ | ||
EntityContextMenuItem *renderWindowOverlay = | ||
this->PluginItem()->findChild<EntityContextMenuItem *>(); | ||
if (!renderWindowOverlay) | ||
{ | ||
ignerr << "Unable to find Render Window Overlay item. " | ||
<< "Render window overlay will not be created" << std::endl; | ||
return; | ||
} | ||
|
||
renderWindowOverlay->SetEntityContextMenuHanlder( | ||
this->dataPtr->entityContextMenuHanlder); | ||
|
||
if (this->title.empty()) | ||
this->title = "EntityContextMenu"; | ||
|
||
ignition::gui::App()->findChild | ||
<ignition::gui::MainWindow *>()->installEventFilter(this); | ||
} | ||
|
||
//////////////////////////////////////////////// | ||
bool EntityContextMenu::eventFilter(QObject *_obj, QEvent *_event) | ||
{ | ||
if (_event->type() == ignition::gui::events::Render::kType) | ||
{ | ||
this->dataPtr->OnRender(); | ||
} | ||
else if (_event->type() == ignition::gui::events::RightClickOnScene::kType) | ||
{ | ||
ignition::gui::events::RightClickOnScene *_e = | ||
static_cast<ignition::gui::events::RightClickOnScene*>(_event); | ||
if (_e) | ||
{ | ||
this->dataPtr->entityContextMenuHanlder.HandleMouseContextMenu( | ||
_e->Mouse(), this->dataPtr->camera); | ||
} | ||
} | ||
|
||
return QObject::eventFilter(_obj, _event); | ||
} | ||
|
||
|
||
///////////////////////////////////////////////// | ||
EntityContextMenuItem::EntityContextMenuItem(QQuickItem *_parent) | ||
: QQuickItem(_parent) | ||
{ | ||
this->setAcceptedMouseButtons(Qt::AllButtons); | ||
this->setFlag(ItemHasContents); | ||
} | ||
|
||
///////////////////////////////////////////////// | ||
void EntityContextMenuItem::SetIgnRenderer(EntityContextMenuHanlder &_entityContextMenuHanlder) | ||
{ | ||
entityContextMenuHanlder = &_entityContextMenuHanlder; | ||
this->connect(entityContextMenuHanlder, | ||
&EntityContextMenuHanlder::ContextMenuRequested, | ||
this, &EntityContextMenuItem::OnContextMenuRequested, Qt::QueuedConnection); | ||
} | ||
|
||
/////////////////////////////////////////////////// | ||
void EntityContextMenuItem::OnContextMenuRequested(QString _entity, int _mouseX, int _mouseY) | ||
{ | ||
emit openContextMenu(std::move(_entity), _mouseX, _mouseY); | ||
} | ||
|
||
///////////////////////////////////////////////// | ||
EntityContextMenuHanlder::EntityContextMenuHanlder() | ||
{ | ||
} | ||
|
||
void EntityContextMenuHanlder::HandleMouseContextMenu(const common::MouseEvent &_mouseEvent, | ||
const rendering::CameraPtr &_camera) | ||
{ | ||
if (!_mouseEvent.Dragging() && | ||
_mouseEvent.Type() == common::MouseEvent::RELEASE && | ||
_mouseEvent.Button() == common::MouseEvent::RIGHT) | ||
{ | ||
math::Vector2i dt = | ||
_mouseEvent.PressPos() - _mouseEvent.Pos(); | ||
|
||
// check for click with some tol for mouse movement | ||
if (dt.Length() > 5.0) | ||
return; | ||
|
||
rendering::VisualPtr visual =_camera->Scene()->VisualAt( | ||
_camera, | ||
_mouseEvent.Pos()); | ||
|
||
if (!visual) | ||
return; | ||
|
||
// get model visual | ||
while (visual->HasParent() && visual->Parent() != | ||
visual->Scene()->RootVisual()) | ||
{ | ||
visual = std::dynamic_pointer_cast<rendering::Visual>(visual->Parent()); | ||
} | ||
|
||
emit ContextMenuRequested( | ||
visual->Name().c_str(), _mouseEvent.Pos().X(), _mouseEvent.Pos().Y()); | ||
} | ||
} | ||
|
||
// Register this plugin | ||
IGNITION_ADD_PLUGIN(ignition::gazebo::EntityContextMenu, | ||
ignition::gui::Plugin) |
110 changes: 110 additions & 0 deletions
110
src/gui/plugins/entity_context_menu/EntityContextMenuPlugin.hh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* 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. | ||
* | ||
*/ | ||
|
||
#ifndef IGNITION_GUI_PLUGINS_ENTITY_CONTEXT_MENU_HH_ | ||
#define IGNITION_GUI_PLUGINS_ENTITY_CONTEXT_MENU_HH_ | ||
|
||
#include <ignition/common/MouseEvent.hh> | ||
|
||
#include <ignition/gui/Plugin.hh> | ||
|
||
#include <ignition/rendering/Camera.hh> | ||
|
||
namespace ignition | ||
{ | ||
namespace gazebo | ||
{ | ||
class EntityContextMenuPrivate; | ||
|
||
/// \brief This plugin is in charge to show the entity context menu when the | ||
/// right button is clicked on a visual. | ||
class EntityContextMenu : public ignition::gui::Plugin | ||
{ | ||
Q_OBJECT | ||
|
||
/// \brief Constructor | ||
public: EntityContextMenu(); | ||
|
||
/// \brief Destructor | ||
public: ~EntityContextMenu() override; | ||
|
||
// Documentation inherited | ||
public: void LoadConfig(const tinyxml2::XMLElement *_pluginElem) override; | ||
|
||
// Documentation inherited | ||
protected: bool eventFilter(QObject *_obj, QEvent *_event) override; | ||
|
||
/// \internal | ||
/// \brief Pointer to private data. | ||
private: std::unique_ptr<EntityContextMenuPrivate> dataPtr; | ||
}; | ||
|
||
class EntityContextMenuHanlder : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
/// \brief Constructor | ||
public: EntityContextMenuHanlder(); | ||
|
||
/// \brief Handle mouse event for context menu | ||
/// \param[in] _mouseEvent Right click mouse event | ||
/// \param[in] _camera User camera | ||
public: void HandleMouseContextMenu(const common::MouseEvent &_mouseEvent, | ||
const rendering::CameraPtr &_camera); | ||
|
||
/// \brief Signal fired when context menu event is triggered | ||
/// \param[in] _entity Scoped name of entity. | ||
/// \param[in] _mouseX X coordinate of the right click | ||
/// \param[in] _mouseY Y coordinate of the right click | ||
signals: void ContextMenuRequested(QString _entity, int _mouseX, int _mouseY); | ||
}; | ||
|
||
/// \brief A QQUickItem that manages the render window | ||
class EntityContextMenuItem : public QQuickItem | ||
{ | ||
Q_OBJECT | ||
|
||
/// \brief Constructor | ||
/// \param[in] _parent Parent item | ||
public: explicit EntityContextMenuItem(QQuickItem *_parent = nullptr); | ||
|
||
/// \brief Set the entity context menu hanlder | ||
/// \param[in] _EntityContextMenuHanlder Entity context menu hanlder | ||
public: void SetEntityContextMenuHanlder( | ||
EntityContextMenuHanlder &_EntityContextMenuHanlder); | ||
|
||
/// \brief Entity context menu hanlder | ||
public: EntityContextMenuHanlder *entityContextMenuHanlder; | ||
|
||
/// \brief Signal fired to open context menu | ||
/// Note that the function name needs to start with lowercase in order for | ||
/// the connection to work on the QML side | ||
/// \param[in] _entity Scoped name of entity. | ||
/// \param[in] _mouseX X coordinate of the right click | ||
/// \param[in] _mouseY Y coordinate of the right click | ||
signals: void openContextMenu(QString _entity, int _mouseX, int _mouseY); // NOLINT | ||
|
||
/// \brief Qt callback when context menu request is received | ||
/// \param[in] _entity Scoped name of entity. | ||
/// \param[in] _mouseX X coordinate of the right click | ||
/// \param[in] _mouseY Y coordinate of the right click | ||
public slots: void OnContextMenuRequested(QString _entity, int _mouseX, int _mouseY); | ||
}; | ||
} | ||
} | ||
|
||
#endif |
47 changes: 47 additions & 0 deletions
47
src/gui/plugins/entity_context_menu/EntityContextMenuPlugin.qml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* 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. | ||
* | ||
*/ | ||
|
||
import QtQuick 2.0 | ||
import QtQuick.Controls 2.0 | ||
import QtQuick.Layouts 1.3 | ||
import RenderWindowOverlay 1.0 | ||
import IgnGazebo 1.0 as IgnGazebo | ||
|
||
Rectangle { | ||
visible: false | ||
color: "transparent" | ||
|
||
RenderWindowOverlay { | ||
id: renderWindowOverlay | ||
objectName: "renderWindowOverlay" | ||
anchors.fill: parent | ||
|
||
Connections { | ||
target: renderWindowOverlay | ||
onOpenContextMenu: | ||
{ | ||
entityContextMenu.open(_entity, "model", | ||
_mouseX, _mouseY); | ||
} | ||
} | ||
} | ||
|
||
IgnGazebo.EntityContextMenu { | ||
id: entityContextMenu | ||
anchors.fill: parent | ||
} | ||
} |
Oops, something went wrong.