slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.58k stars 604 forks source link

Feature?: Direct support for Qt-Designer (*.ui) files #5491

Open antis81 opened 4 months ago

antis81 commented 4 months ago

Background

Few weeks ago I started wirting a little serializer fun tool that converts *.ui files into *.slint and *.qml (only latest Qt6) formats. Currently this is just for me to learn about Rust tooling. However the tool produces quite usable results in current state and I make good progress. The crate depends on quick_xml and serde to create the model(s) and yaserde for writing the output *.slint file (because quick_xml can only serialize into XML formats; not Slint).

Restrictions

Make it a Slint feature maybe?

Assuming Slint would be able to read those Qt-Designer files (like a "JIT") and render them. Do you think this will benefit both projects Qt and Slint? I think in best case it might even make Rust more interesting for Qt/C++ developers, because it just feels like Qt and people wouldn't even have to learn a new language (when used with C++ bindings).

ogoffart commented 4 months ago

Awsome. I think this tool could be usefull to migrate dialogs or some widgets from Qt widgets to Slint.

I'm not sure it should be integrated directly into slint.

It should probably be a tool can can be run once on your files.

I guess it could be a different build-dependency so the build.rs would look like:

// (this is pseudo code, naming need to be thought out and paths need to be relative to OUT_DIR and such)
qt_ui_to_slint::conver_ui_file("foo.ui", "foo.slint");
slint_build::compile("foo.slint");

And so this wouldn't be part of Slint itself but just another crate

Another solution i'm not suggesting is if you could do

import { Foo } from "foo.ui";

but that means we need to add support into Slint and keep compatibility.

Anyway, we could have that in our repository in the tools folder. Or you could just have it in a separate repository.

antis81 commented 4 months ago

Wow… actually I didn't think about importing a component directly from a "foo.ui". No question this would be really a powerful feature. Very ambitioned though (put in a single custom widget and… :zap:). Maybe with active support from Qt/KDE. Right now it's a dream, let's keep it this way (or at least mark this highly experimental :smile_cat:)…

The project repository lives currently on GitLab -> qt-ui-conv. When moving this into tools maybe I should start thinking about splitting out features (qt_ui_conv_slint, …qml, …cli, …gui?, …).

WilstonOreo commented 4 months ago

I also think this tool would be very useful when migrating from Qt Widgets to Slint. However, I think integrating it into build.rs or exposing it as a component is not really necessary, because I doubt there can be 100% compatibility between the two frameworks. Which effectively means you will have to touch the generated .slint file. Or, what if you want to use slint-only features like built-in animations? I guess a tool like slint-migrate-qt in tools with input .ui file and output .slint file is sufficient. @antis81 The idea is great though, really would love to see the source of the tool :)

antis81 commented 4 months ago

@WilstonOreo The source is linked above if you like to understand the model. When you compile it you can run with cargo run qt-ui-conv -- <qt-ui-file.ui>. (In the examples folder you will also find some ui files or you can use your own to experiment with.)

antis81 commented 3 weeks ago

image

Did a little case study out of curiosity and used the tool to convert LXQt's session settings GUI to Slint (1.8).

The individual pages came out quite good. Especially translatable text can be retained this way.

The side bar took a bit of manual effort though (no QStackedWidget in Slint). However I ended up with something like

struct PageInfo { identifier: string, title: string }

export component Page inherits VerticalBox { alignment: start; @children }

export componentn ApplicationWindow inherits PagedDialog {
  // pages is a "property <[PageInfo]>"
  pages: [ { identifier: page_1.identifier; … }, … ];

  page_1 := PageOneComponent /* inherits Page */ {
    out property <string>: identifier: "page-1";
    visible: root.active-page == self.identifier;
  }

  page_2 := PageTwoComponent /* inherits Page */ {
    out property <string>: identifier: "page-2";
    visible: root.active-page == self.identifier;
  }

  // etc.
}

This turned out quite well as a replacement and also didn't change the original file structure too much where QStackedWidget could basically just be replaced by stacked_widget := Rectangle { @children }