diff --git a/examples/worlds/minimal_scene.sdf b/examples/worlds/minimal_scene.sdf
index fa09de8c38..bbbd93d4bf 100644
--- a/examples/worlds/minimal_scene.sdf
+++ b/examples/worlds/minimal_scene.sdf
@@ -180,6 +180,16 @@ Missing for parity with GzScene3D:
true
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+
+
diff --git a/src/gui/gui.config b/src/gui/gui.config
index a250a3c1a9..c482aa74eb 100644
--- a/src/gui/gui.config
+++ b/src/gui/gui.config
@@ -116,6 +116,16 @@
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+
+
diff --git a/src/gui/plugins/CMakeLists.txt b/src/gui/plugins/CMakeLists.txt
index d74c63cca3..84d5f99e2a 100644
--- a/src/gui/plugins/CMakeLists.txt
+++ b/src/gui/plugins/CMakeLists.txt
@@ -121,6 +121,7 @@ add_subdirectory(modules)
add_subdirectory(align_tool)
add_subdirectory(banana_for_scale)
add_subdirectory(component_inspector)
+add_subdirectory(drop_from_fuel)
add_subdirectory(entity_context_menu)
add_subdirectory(entity_tree)
add_subdirectory(joint_position_controller)
diff --git a/src/gui/plugins/drop_from_fuel/CMakeLists.txt b/src/gui/plugins/drop_from_fuel/CMakeLists.txt
new file mode 100644
index 0000000000..2fd4256c6a
--- /dev/null
+++ b/src/gui/plugins/drop_from_fuel/CMakeLists.txt
@@ -0,0 +1,8 @@
+gz_add_gui_plugin(DropFromFuel
+ SOURCES
+ DropFromFuel.cc
+ QT_HEADERS
+ DropFromFuel.hh
+ PUBLIC_LINK_LIBS
+ ${PROJECT_LIBRARY_TARGET_NAME}-rendering
+)
diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.cc b/src/gui/plugins/drop_from_fuel/DropFromFuel.cc
new file mode 100644
index 0000000000..b52be5967f
--- /dev/null
+++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.cc
@@ -0,0 +1,231 @@
+/*
+ * 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 "DropFromFuel.hh"
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include
+
+#include
+
+namespace ignition::gazebo
+{
+ class DropFromFuelPrivate
+ {
+ /// \brief Update the 3D scene with new entities
+ public: void OnRender();
+
+ /// \brief User camera
+ public: rendering::CameraPtr camera{nullptr};
+
+ /// \brief Pointer to the rendering scene
+ public: rendering::ScenePtr scene{nullptr};
+
+ /// \brief Ray query for mouse clicks
+ public: rendering::RayQueryPtr rayQuery{nullptr};
+
+ /// \brief Transport node for making transform control requests
+ public: ignition::transport::Node node;
+
+ /// \brief Name of the world
+ public: std::string worldName;
+ };
+}
+
+using namespace ignition;
+using namespace gazebo;
+
+/////////////////////////////////////////////////
+void DropFromFuelPrivate::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(
+ this->scene->NodeByIndex(i));
+ if (cam)
+ {
+ if (std::get(cam->UserData("user-camera")))
+ {
+ this->camera = cam;
+
+ // Ray Query
+ this->rayQuery = this->camera->Scene()->CreateRayQuery();
+
+ igndbg << "DropFromFuel plugin is using camera ["
+ << this->camera->Name() << "]" << std::endl;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////
+DropFromFuel::DropFromFuel()
+ : ignition::gui::Plugin(),
+ dataPtr(std::make_unique())
+{
+}
+
+/////////////////////////////////////////////////
+DropFromFuel::~DropFromFuel() = default;
+
+/////////////////////////////////////////////////
+void DropFromFuel::LoadConfig(const tinyxml2::XMLElement *)
+{
+ if (this->title.empty())
+ this->title = "Drop from fuel";
+
+ // World name from window, to construct default topics and services
+ auto worldNames = gui::worldNames();
+ if (!worldNames.empty())
+ this->dataPtr->worldName = worldNames[0].toStdString();
+
+ ignition::gui::App()->findChild
+ ()->installEventFilter(this);
+}
+
+////////////////////////////////////////////////
+bool DropFromFuel::eventFilter(QObject *_obj, QEvent *_event)
+{
+ if (_event->type() == ignition::gui::events::Render::kType)
+ {
+ this->dataPtr->OnRender();
+ }
+ else if (_event->type() == ignition::gui::events::DropOnScene::kType)
+ {
+ auto dropOnSceneEvent =
+ reinterpret_cast(_event);
+ if (dropOnSceneEvent)
+ {
+ if (dropOnSceneEvent->DropText().empty())
+ {
+ ignerr << "Dropped empty entity URI.\n";
+ }
+ else
+ {
+ if (this->dataPtr->camera && this->dataPtr->rayQuery)
+ {
+ std::function cb =
+ [](const ignition::msgs::Boolean &_res, const bool _result)
+ {
+ if (!_result || !_res.data())
+ ignerr << "Error creating dropped entity." << std::endl;
+ };
+
+ math::Vector3d pos = ignition::rendering::screenToScene(
+ dropOnSceneEvent->Mouse(),
+ this->dataPtr->camera,
+ this->dataPtr->rayQuery);
+
+ msgs::EntityFactory req;
+ std::string dropStr = dropOnSceneEvent->DropText();
+ if (QUrl(QString(dropStr.c_str())).isLocalFile())
+ {
+ // mesh to sdf model
+ common::rtrim(dropStr);
+
+ if (!common::MeshManager::Instance()->IsValidFilename(dropStr))
+ {
+ ignerr << "Invalid URI: " + dropStr +
+ "\nOnly Fuel URLs or mesh file types DAE, OBJ, and STL"
+ "are supported.";
+ return QObject::eventFilter(_obj, _event);
+ }
+
+ // Fixes whitespace
+ dropStr = common::replaceAll(dropStr, "%20", " ");
+
+ std::string filename = common::basename(dropStr);
+ std::vector splitName = common::split(filename, ".");
+
+ std::string sdf = ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ "" + dropStr + ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ "" + dropStr + ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ "";
+
+ req.set_sdf(sdf);
+ }
+ else
+ {
+ // model from fuel
+ req.set_sdf_filename(dropStr);
+ }
+
+ req.set_allow_renaming(true);
+ msgs::Set(req.mutable_pose(),
+ math::Pose3d(pos.X(), pos.Y(), pos.Z(), 1, 0, 0, 0));
+
+ this->dataPtr->node.Request(
+ "/world/" + this->dataPtr->worldName + "/create",
+ req, cb);
+ }
+ }
+ }
+ }
+
+ return QObject::eventFilter(_obj, _event);
+}
+
+// Register this plugin
+IGNITION_ADD_PLUGIN(ignition::gazebo::DropFromFuel,
+ ignition::gui::Plugin)
diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.hh b/src/gui/plugins/drop_from_fuel/DropFromFuel.hh
new file mode 100644
index 0000000000..13fca93120
--- /dev/null
+++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.hh
@@ -0,0 +1,56 @@
+/*
+ * 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_GAZEBO_GUI_DROP_FROM_FUEL_HH_
+#define IGNITION_GAZEBO_GUI_DROP_FROM_FUEL_HH_
+
+#include
+
+#include
+
+namespace ignition
+{
+namespace gazebo
+{
+ class DropFromFuelPrivate;
+
+ /// \brief Allows to DropFromFuel models and lights using te gui event
+ /// DropFromFuelFromDescription
+ class DropFromFuel : public ignition::gui::Plugin
+ {
+ Q_OBJECT
+
+ /// \brief Constructor
+ public: DropFromFuel();
+
+ /// \brief Destructor
+ public: ~DropFromFuel() 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 dataPtr;
+ };
+}
+}
+
+#endif
diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.qml b/src/gui/plugins/drop_from_fuel/DropFromFuel.qml
new file mode 100644
index 0000000000..873da30014
--- /dev/null
+++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.qml
@@ -0,0 +1,28 @@
+/*
+ * 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
+
+// TODO: remove invisible rectangle, see
+// https://github.com/ignitionrobotics/ign-gui/issues/220
+Rectangle {
+ visible: false
+ Layout.minimumWidth: 100
+ Layout.minimumHeight: 100
+}
diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.qrc b/src/gui/plugins/drop_from_fuel/DropFromFuel.qrc
new file mode 100644
index 0000000000..91ce21f53b
--- /dev/null
+++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.qrc
@@ -0,0 +1,5 @@
+
+
+ DropFromFuel.qml
+
+