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

Create a reactive programming API for controllers #13440

Open
christophehenry opened this issue Jul 4, 2024 · 10 comments
Open

Create a reactive programming API for controllers #13440

christophehenry opened this issue Jul 4, 2024 · 10 comments

Comments

@christophehenry
Copy link
Contributor

christophehenry commented Jul 4, 2024

Feature Description

This is an issue that I've already risen in the past proposing to add ability to pass arbitrary keys engine.setValue and engine.setParameter but this seem to have met some opposition.

So I'd like to start a broader discussion about adding an API to do reactive programming in controller especially now that I started working on ES6+ components JS.

What I propose is to reflect on a standard API for Mixxx, setting aside the implementation. This API could mimic ES Event API with methods like dispatchEvent, addEventListener and removeEventListener a be closer to Qt's signals/slots API (also I'm not sure what this would look like…).

This API could be standard to Component and ComponentContainer.

Regarding the implementation, I propose a first implementation in pure JS using EventTarget, CustomEvent and Proxy (this seem supported by Mixxx' JS engine, also I need to formally check) as follows:

class Component {
        __signals = new (class extends EventTarget {
            constructor() {
                super();
                return new Proxy(this, {
                    set: (target, property, value) => {
                        const previousValue = target[property];
                        target[property] = value;
                        this.dispatchEvent(new CustomEvent(property, { detail: {value, previousValue} }));
                        return true;
                    },
                });
            }
        })();

        connect(name, callback) {
            this.__signals.addEventListener(name, (evt) => {
                callback(name, evt.detail.value, evt.detail.previousValue)
            })
        }
}

that could be transparantly replaced by a C++ implem in the engine namespace thanks to the standard API.

@Swiftb0y
Copy link
Member

Swiftb0y commented Jul 4, 2024

I'm slightly confused, is this about a reactive programming paradigm or sharing data between QJSEngine instances?

IMO the long term plan for enabling reactive programming in Mixxx would be to programm mappings in a QQmlEngine and use native QML reactive bindings. Have you looked into that?

@christophehenry
Copy link
Contributor Author

christophehenry commented Jul 5, 2024

No I'm talking specifically about cross-component communication between components inside the same controller for complex use cases (like the one I exposed in #12766).

Correct me if I'm wrong but a QQmlEngine implementation is not comming any time soon anyway?

@Swiftb0y
Copy link
Member

Swiftb0y commented Jul 5, 2024

Well, actually #11407 did a good job at laying the foundations. Its currently controller screen focused, but I'm sure we can bend it to work for plain controllers as well.

@christophehenry
Copy link
Contributor Author

Ok, so EventTarget is not declared by QJSEngine so my first proposition of a pure JS implementation is off the table 😔

@Swiftb0y
Copy link
Member

Swiftb0y commented Jul 7, 2024

Yeah... EventTarget is part of the DOM Spec...

Wdyt about the QML experiment?

@christophehenry
Copy link
Contributor Author

christophehenry commented Jul 7, 2024

I don't really know where to start. I know very little Qt, let alone QML. I don't really understand the code you pointed me. I would need some guidance. Just to be clear: if I start working on QML, it's better to drop the ES6 implementation of ComponentsJS in favor of a QML impl?

@Swiftb0y
Copy link
Member

Swiftb0y commented Jul 7, 2024

if I start working on QML, it's better to drop the ES6 implementation of ComponentsJS in favor of a QML impl?

Depends. I think we can still modernize componentsJS but rather just as a refactoring without signficant API changes (so more like #4550 instead of #13437). I would treat the QML Components separate from JS components for now.

I know very little Qt, let alone QML.

Then I'd recommend you spend a little time getting to know both. The relevant parts from Qt are really "just" signals and slots and the property system and for QML there is the QML reference (though you'll need to watch out on what belongs to just QML and what belongs to QtQuick (the GUI framework built on top of QML)).

After you have familiarized yourself with those topics, you can either apply some of the new knowledge in the form of the experimental QML skin (start a build from main with --qml) or you can start right away with disentangling some of code I linked earlier.

@christophehenry
Copy link
Contributor Author

Honestly, if #13437 risks to be controversial because of API breaking changes, I'd rather start working on a QML API right away.

@Swiftb0y
Copy link
Member

Swiftb0y commented Jul 8, 2024

Sounds good to me.

@Swiftb0y
Copy link
Member

Swiftb0y commented Jul 8, 2024

Mind that before diving into an API, you'll probably need to do a little bit of refactoring to decouple the current QQmlEngine from the the controller screen usecase it was designed for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants