KDAB / cxx-qt

Safe interop between Rust and Qt
https://kdab.github.io/cxx-qt/book/
978 stars 67 forks source link

QWidgets example #143

Open Be-ing opened 2 years ago

Be-ing commented 2 years ago

It would be helpful to have an example how to use CXX-Qt in a QWidgets application.

brainchild0 commented 1 year ago

It has appeared from various documentation that much of the QWidget API is not accessible from a Rust language context with the current state of the project. For example, it seems not possible to allocate a window resource programmatically, then similarly add to it buttons, text boxes, and other standard widgets. Rather window layouts are only supported through QML.

Is this understanding accurate?

Be-ing commented 1 year ago

Yes, that's correct, and we don't plan to bind those numerous QWidget APIs. Our plan for how CXX-Qt could be used with QWidgets would be implementing models in Rust, but leaving the rest to C++.

brainchild0 commented 1 year ago

My understanding of CXX is a design to provide largely automated bindings between Rust and C++ calls through code generation. Meanwhile, I have understood that CXX-Qt attempts to add a natural mapping between the metaprograming constructs of Qt with Rust. Under such an understanding, the hope would be that support for bindings to an entire class library such as QWidget would become automatic. Do I misunderstand?

As a template for a basic application built through CXX-Qt, is it conceived that a project would have a main entry point and overall build process through Qt or through Rust? Alternatively, is it thought that due to many of the capabilities of the presentation layer of Qt being available through QML, an application would include little or no C++ source?

Be-ing commented 1 year ago

CXX is not fully automated; there's still work involved in developing and maintaining the bindings. What CXX automates is taking the description of the language boundaries and generating the C APIs for Rust and C++ to call each other without the developers needing to reduce everything to the language features C supports. Take a look at crates/cxx-qt-lib for what we have bindings for already.

We're not planning to create CXX bindings for the entire Qt API because the API surface is huge and it would be difficult to maintain. That's just what we're planning to work on though. If someone is really dedicated and wants to create CXX bindings for tons of QWidgets APIs to make it feasible to write QWidgets GUIs in Rust, we could consider merging that into cxx-qt-lib, though it may be better off as a separate crate that depends on cxx-qt-lib. If anyone actually wants to do that, I'd definitely recommend holding off a while for us to stabilize APIs upstream. :sweat_smile:

As a template for a basic application built through CXX-Qt, is it conceived that a project would have a main entry point and overall build process through Qt or through Rust?

Either. If you have an existing C++ application, you can integrate CXX-Qt into its build system. If you are starting a new application, you can just use Cargo. If you need some C++ but don't want a C++ build system, you can tell Cargo to compile the C++. The first chapter of the documentation goes into the build system setup in detail.

brainchild0 commented 1 year ago

If someone is really dedicated and wants to create CXX bindings for tons of QWidgets APIs to make it feasible to write QWidgets GUIs in Rust, we could consider merging that into cxx-qt-lib, though it may be better off as a separate crate that depends on cxx-qt-lib.

It seems then that the limitation would be the maintenance effort associated with changes to the API for subsequent versions of Qt. Has the Qt group itself expressed any interest in supporting an effort to maintain a complete integration layer? Could use of preprocessors or other annotations for declarations within the Qt code base, as a project policy, simplify an overall effort, by reducing the complexity of the external bindings descriptors?

We're not planning to create CXX bindings for the entire Qt API because the API surface is huge and it would be difficult to maintain.

Conceptually, what drives the choice for where to provide bindings, or not? What should developers expect concerning the broad capabilities and limitations for merging a Qt presentation layer into Rust business logic, speaking from a standpoint of natural understanding, rather than specific details of API calls?

Be-ing commented 1 year ago

Right, adding new APIs across Qt releases would be a hassle. The qt-build-utils crate already finds the Qt version and we already have a little bit of code that differs between Qt5 and Qt6, though we'd like to keep that to a minimum. That said, Qt is not adding new features for QWidgets anymore, so once the bindings were made, perhaps they wouldn't be so difficult to maintain.

Conceptually, what drives the choice for where to provide bindings, or not?

Only the amount of work involved in developing and maintaining the bindings; nothing ideological.

What should developers expect concerning the broad capabilities and limitations for merging a Qt presentation layer into Rust business logic, speaking from a standpoint of natural understanding, rather than specific details of API calls?

Generally speaking, we expect the bridge between Rust and Qt GUIs to be at the level of application-specific QAbstractItemModel subclasses which could be used with either QML or QWidgets. We're not quite there yet though. We have an ugly proof-of-concept implementing a custom QAbstractListModel subclass, but that currently requires writing some custom C++ glue code. Our major goal for the coming release(s) is improving that situation so you could implement the models all in Rust.

Be-ing commented 1 year ago

Has the Qt group itself expressed any interest in supporting an effort to maintain a complete integration layer? Could use of preprocessors or other annotations for declarations within the Qt code base, as a project policy, simplify an overall effort, by reducing the complexity of the external bindings descriptors?

The Qt Company let several people in KDAB present about CXX-Qt at the Qt World Summit 2022 meetups in the past few weeks and the reception was positive. They have not expressed interest in any official Rust support for Qt though (as far as I am aware). At least for the foreseeable future, CXX-Qt is an independent project from Qt. That said, we haven't hit any issues where we needed changes to Qt for CXX-Qt's purposes, and I don't anticipate we'll run into those.

brainchild0 commented 1 year ago

Conceptually, what drives the choice for where to provide bindings, or not?

Only the amount of work involved in developing and maintaining the bindings; nothing ideological.

I meant, broadly speaking, how do you select which parts of the API are given bindings, and which are excluded? Is selection at the level of a module, or specific calls within some modules?

Be-ing commented 1 year ago

Whatever we need bindings for, we'll make bindings for. We picked some types needed to build the simple examples in this repo. Perhaps in the future we'll focus on binding more Qt classes, but for now we still have work to do figuring out details for the code generators and adding bindings for Qt's collections and models. I also plan to add bindings for QGuiApplication and QQmlApplicationEngine (#113) to enable building QML applications without needing to write any C++ code.

brainchild0 commented 1 year ago

Thanks for the explanation.

My earlier thought was that if the Qt Company were willing to share the burden of supporting the bindings, then it could agree to include hints, in the form of extra markup embedded in the Qt source, to be ingested by the generator.

Your side could test changes to the bindings accompanying major releases, and submit upstream patches, or simply provide the testing framework to the Qt Company, so that some of the QA could be done in house.

Even if the Qt Company would not be testing the entire process, the fact of adding the tags to new API as part of regular development would make the process more tightly integrated. From the side of Qt Company, it might be a way to support Rust without supporting Rust, which might seem to be a sensible approach. That is, the approach would provide a way for Qt to ensure that Rust integration is supported, without being the owners.

I am sidestepping the technical question of support in the CXX generator for code annotations, whether any solution is yet available, but it definitely seems like a useful solution in its own right.

Be-ing commented 1 year ago

CXX doesn't make use of any annotations in C++ source code, so there's nothing for them to do upstream in Qt.

brainchild0 commented 1 year ago

Yes, I had no information about support from existing tools. It seems possible in principle, for example, that inputs to the CXX generator would be in turn generated from inline annotations, removing the need to maintain the bindings externally.

ahayzen-kdab commented 1 year ago

For widgets it's likely that something like https://github.com/google/autocxx would work, as exposing C++ classes to Rust CXX can already express (and things like signals are just normal functions). So if you really want to use QWidgets from Rust you could likely use autocxx to reach the types.

CXX-Qt is most useful for the direction exposing Rust to C++ as it can express properties, invokables, signals etc from Rust to C++. So for creating extra models or QObjects to work with QWidgets you could use CXX-Qt. And cxx-qt-lib already has some useful types wrapped. Note there is nothing stopping you from using CXX-Qt with QWidgets for the backend as it's just exposing normal QObjects.

The main question for QWidgets would be, is there any advantage to using something like autocxx to build UIs in Rust with the imperative API. Currently we think likely not as the API would still be direct bindings and would just be writing C++ with a probably unsafe Rust syntax, you'd still need knowledge of how the C++ API works, and not all of it could be easily wrapped.

So instead keeping the UI layer to C++ / UI files / QML is better and moving the business logic into Rust is our current focus for now.

brainchild0 commented 1 year ago

If Autocxx works safely with QWidget, then it might be useful in your project, but I am now understanding an important distinction.

For many developers, it would be interesting to move away from C++ and toward Rust, but the problem would remain of no equivalent toolkit as Qt. The demand arises for a means to write an application utilizing the Qt graphical toolkit, but doing so with the details of the C++ implementation and API completely hidden by a build layer.

In contrast, CXX-Qt seems to carry a different objective, to generalize the static bindings offered by CXX into the meta-programing aspects of Qt, in order to facilitate writing multi-langauge applications with light interfaces at the MVC junction. It certainly seems, at least on first glance, a sensible idea, and one much more feasible, compared to exposing every nuance of the API. It is also potentially more flexible, since the requirement of full API translation is substituted for an elegant approach to meta-programing generalizations.

I would look forward to seeing a working demonstration of an application featuring a Rust model interacting with a C++ and QML presentation. It would probably express better clarification of key concepts than I am able to understand from the explanations.

Be-ing commented 12 months ago

Work in progress with an example: #622