Implementing QcDocklet(s)

Hello everybody,
I have been following the SuperCollider 4: First Thoughts topic for a while now, and I would have some opinions to share. But there is one that I think could be implemented in SC3 as well. That is: the possibility to dock Windows (QWindow(s)) into the SCIDE.
I came up with this idea because my everyday practice is basically dependent on FreqScope, multichannelBus scoping, s.meter and GUI’s in general and I would love to keep my desktop clean, docking all these windows into the IDE.

I guess that a lot of people might take advantage of such a solution.
What do you think?

2 Likes

I spent the last week studying the sources and trying to prototype a potential “QcDocklet” class, but I realized that it is way more complicated than I expected.
I would therefore take advantage of this topic to try to recap how SC Widget development works and share my plan with you.

So here is what I understood:

  • Supercollider Widget source files are stored in the QtCollider/widget folder
  • cmake appends all widget sources and headers to the QT_COLLIDER_SRCS and QT_COLLIDER_HDRS list variables dynamically in the QtCollider/CMakeLists.txt
  • these files are then compiled and archived into libsclang which is eventually statically linked to the sclang executable.
  • this means that in order to create a new widget it is “enough” to create a new Class (Something.cpp, Something.hpp) inside the QCollider/widgets folder, add its correspondent SC Class (Something.sc) inside the SCClassLibrary folder (or any of its subfolder), reconfigure and rebuild SC.

Is everything correct?

In this stage of learning the SC Library (Qt and C++ :upside_down_face: ) it would have been enough for me to create an empty window which is dockable into the SCIDE with no other functionality.

But I already have some problems

A potential QcDocklet class should work exactly like a Window in the sense that it should contain a View in which any object could be created into.
So my first attempt was to copy the QcWindow constructor at once adapting the code accordingly.
The result is then:

#pragma once
#include "BasicWidgets.h"
#include <QDockWidget>

class QcDocklet : public QcCustomPainted {
    Q_OBJECT
public :
    QcDocklet(QWidget* parent = nullptr);
    Q_INVOKABLE QcDocklet(const QRectF& geom);
};

the plan wuld be to instantiate the Docklet only by setting its Geometry, hence the geom parameter in the Q_INVOKABLE constructor.
The QcDocklet should be of course a child of QDockWidget so I modified my code adding:

#include <QDockWidget>

class QcDocklet : public QcCustomPainted, public QDockWidget {
    Q_OBJECT
    ...

at this point I could implement the constructor in the source file.
It seemed to me that every widget has or needs a factory function in order to be created as proxy (right…?): a Button has the following statement:

QC_DECLARE_QWIDGET_FACTORY(QcButton);

but QcWindow has its own factory function and since QcDocklet should share the basic functionality of a window I considered copying the same function into the QcDocklet source as well.

So now the big question: hoe do I return a QDockWidgetinstead of a Window?

Some of you might say: “well learn Qt” since everything I have done until now has been copying code from another source. But I’m really struggling in understanding the Class tree…I don’t know why Widgets needs a Factory Function, why they should be returned as proxy and why a window is actually a Window (I mean is it declared somewhere?

I took a look into the docklet.cpp (from scide) and its children, but I get really confused.
So for example the class Docklet has a private member QDockWidget* mDockWidget; which is instantiated in the class constructor.

Does this returns an actual Docklet?

I hope that you are interested in this project and that you are willing to help me.

Thank you for your help!

sclang and scide are different processes. All those UI elements belong to sclang, but you want to dock them in the SC IDE.

Many operating systems resp. window managers allow to embed Windows from another process, but it is not trivial! I would recommend that you research if this is possible/practical with Qt in the first place.

Auch…I didn’t even think about it…
Sadly I set up a simpler ecosystem in which an application that instantiate a QDockWidget is launched as a QProcess from another application (which as far as I understood is kind of the same principle of scide starting sclang) and it doesn’t work. The problem is that you can dock a QDockWidget to a potential QWidget *parent but you cannot access the parent Application instance (hence neither its QWidgets I’m afraid) from the child app.

Someone suggests to take a look into one of these options. Is it worth the try? Is for example a shared memory a good idea?

I think it is more practical to first try to implement a docking area for sclang. It would still be seperate from the SC IDE, but at least you have a single place where you can dock all the Windows.