gazebosim / gz-gui

Builds on top of Qt to provide widgets which are useful when developing robotics applications, such as a 3D view, plots, dashboard, etc, and can be used together in a convenient unified interface.
https://gazebosim.org
Apache License 2.0
78 stars 44 forks source link

Splash screen support #336

Open peci1 opened 2 years ago

peci1 commented 2 years ago

Desired behavior

GUI can show a splash screen that disappears only when some specified plugins finish loading.

Alternatives considered

None.

Implementation suggestion

I don't know where to start as I'm not a Qt Quick guy. I've succeeded implementing a splash screen locally using QSplashScreen, but I've noticed that's not a Qt Quick component and it is in the QtWidgets part of Qt that is currently not requested in CMake. I found this tutorial for splash windows in Qt Quick: https://doc.qt.io/archives/qt-5.9/qtquick-window-splash-qml.html . However, after an hour of pondering, I wasn't able to get it working (I wanted to implement it as a GUI plugin, which might be a wrong way of doing it anyways).

Additional context

I assume that once the splash screen is working, the user should be able to specify the image to be displayed. How should relative paths be resolved in this case? Should they be resolved relative to one of the existing environment paths?

I was also thinking about creating a GuiEvent with a text parameter which could be emitted from plugins to signal to the splash screen the current state of loading.

When launching simple apps like the examples here, there's not enough time for a splash screen, but loading e.g final_event_04 world from SubT deserves one as the loading can take more than a minute. In the meantime, just a half-rendered non-responsive GUI is shown, which is anyways useless...

Last, I was thinking about how to figure out when to hide the splash screen. I haven't found any "GUI ready" event or message. Maybe that's even a bit complicated. As the case I was solving always contained a GzScene3D, I hooked /gui/camera/pose and hid the splash once the pose has changed from its first published value. I understand that this is not optimal and is only working in case a GzScene3D is in the config and a camera is set in follow mode. The implementation from Gazebo classic also hooks into the Scene3D and queries the readiness of rendering, but that resulted in premature hiding of the splash when I transplanted this approach to Ignition. One idea I had was creating a GuiEvent that would be emitted by plugins, and the GUI config would allow specifying that when a plugin of given name emits this event, the splash screen should be hidden.

chapulina commented 2 years ago

I wanted to implement it as a GUI plugin, which might be a wrong way of doing it anyways

Yeah I think this would be more of a core component of ign-gui. A good parallel may be the SideDrawer, which downstream applications like gazebo can override, see GazeboDrawer.

How should relative paths be resolved in this case? Should they be resolved relative to one of the existing environment paths?

I think it could be exposed with the project's QRC, see gazebo.qrc.

I was also thinking about creating a GuiEvent with a text parameter which could be emitted from plugins to signal to the splash screen the current state of loading.

That's a nice idea. It may be application-specific though if each application is allowed to override the splash screen completely. That means, for Gazebo, it may be a Gazebo gui event.

loading can take more than a minute. In the meantime, just a half-rendered non-responsive GUI is shown, which is anyways useless...

Agreed :+1:

how to figure out when to hide the splash screen.

Another idea would be to have 2 events, for example:

This allows plugins to opt-in, and the splash screen wouldn't wait for plugins unless they register. I prefer something like this over using the GUI config because I think this is something that should be enabled by the developer of a plugin, rather than by a user of a plugin.

peci1 commented 2 years ago

Yeah I think this would be more of a core component of ign-gui. A good parallel may be the SideDrawer, which downstream applications like gazebo can override, see GazeboDrawer.

Hmm, this doesn't seem very practical to me. Imagine e.g. the SubT simulator. If I understand your suggestion correctly, just changing the splash screen image would require to write a custom Gui app that would need to be launched instead of ign gazebo -g? I was rather thinking of something that could be completely specified via the XML Gui config.

I think it could be exposed with the project's QRC, see gazebo.qrc.

Only the default image could be shipped as a part of the QRC. What about user images?

Another idea would be to have 2 events

That sounds like a really practical solution. Internal logic of each of the plugins could then be used to determine when the plugin should be considered loaded. I think such event should not be bound to GUI only - it would even be useful for other parts of the system. E.g. cloudsim could determine that the simulation image is ready and solution images can start being launched, or the code in solution containers could wait until the simulation is up (if the events were further propagated via some topics). I'd also add a 3rd event type, PluginLoadingMessage, via which the plugin could communicate what it is doing.

It would also be useful to distinguish between loading server and client plugins. Sometimes you're interested in knowing whether the server is ready, while in other cases you might want to wait for both the GUI and the server. It would even make sense to me to make the server plugin loading events accessible as topics so that e.g. GUIs running in different processes or machines can still determine the server loading status.

chapulina commented 2 years ago

Imagine e.g. the SubT simulator. If I understand your suggestion correctly, just changing the splash screen image would require to write a custom Gui app that would need to be launched instead of ign gazebo -g?

Good point. I guess I was thinking of splash screens that can be customized with more than just an image (links, progress text, etc), because in that case you can't escape writing some QML.

Another thing to consider is that if you're going through the trouble of customizing the GUI for an application, I think it's not unreasonable to ask that you write some code. That's how ign-rviz and tesseract_ignition do it, for example. Because you won't want to customize just the splash screen. You probably want a custom drawer so you don't have ign-gui's About, etc.

Only the default image could be shipped as a part of the QRC. What about user images?

tl;dr: maybe just use absolute paths?

If we really want to expose just user images, we could use the window_icon option as an example. That's currently exposed through ign-launch, and downstream applications can set it with the absolute path, like how SubT does it.

It would also be useful to distinguish between loading server and client plugins.

Ah true. In that case we can't rely on events though. It sounds like we need something like ROS actions... Or a combination of topics and services that achieves the same behavior.

peci1 commented 2 years ago

Ok, so to sum it up (correct me if you don't agree):

It would also be useful to distinguish between loading server and client plugins.

Ah true. In that case we can't rely on events though. It sounds like we need something like ROS actions... Or a combination of topics and services that achieves the same behavior.

Isn't just topics enough? For the case that some message is dropped, there could be a timeout for the splash screen (or for each plugin? maybe the start message could contain the timeout and it'd be a responsibility of the plugin to estimate the maximum loading time)-

chapulina commented 2 years ago

Yup, it all sounds good to me, thanks!