Current state of GUI development in Rust?

Latest status update of OrbTkt https://www.reddit.com/r/rust/comments/e725t9.

5 Likes

What would be the right place to discuss OrbTk design and implementation? There's a behavior I'd like to change (current: focus remaining on previously used textbox even though button was clicked since; new: each widget is focusable unless explicitly opted out) and if I get it to work (I'm Rust neophyte), I'd like to open PR so it may be merged upstream. But what I want may not be what you want :slight_smile: so it's probably best to discuss it first. Would a ticket over at GitHub work?

The focus management in OrbTk is very basic and need to be expanded. I think your suggestion goes to the right direction. Iā€˜m glade :slightly_smiling_face: if you create an pr. But if you first want to share your ideas you could discuss with us on the Redox chat (orbital channel) https://www.redox-os.org/community/.

I just stumbled upon this new qt library and I was floored after playing with it. If you are a QT user, this is pretty amazing IMHO. While the api is inherently "unsafe", as long as you follow QT's ownership rules, it seems to work out quite nicely. And it seems to be more performant than the gtk bindings, at least based on my experiments.

The one thing that I am unclear on is how it handles (or doesn't) inheritance. This primarily would impact you if you want to write a custom model for QT's MVD classes.

The author seems to have recently authored a book on QT5. Hopefully we will hear something official about this (or maybe i just missed it)

Here is an example main.rs that I put together to test...

use cpp_core::{CppBox, MutPtr};
use qt_core::{QString, Slot};
use qt_widgets::{
    QApplication, QHBoxLayout, QLabel, QLineEdit, QListWidget, QPushButton, QVBoxLayout, QWidget,
};

struct Form<'a> {
    // owned pointer to the QWidget
    _widget: CppBox<QWidget>,
    // reference to the button used in slot
    _button: MutPtr<QPushButton>,
   // reference to the line edit, used in a slot
    _line_edit: MutPtr<QLineEdit>,
    // reference to the listwidget, used in a slot
    _history: MutPtr<QListWidget>,
   // slot that gets called when the line edit is updated
    line_edit_edited: Slot<'a>,
   // slot that is triggered when the button is pushed
    button_pushed: Slot<'a>,
}
impl<'a> Form<'a> {
    unsafe fn add_button(
        mut layout: MutPtr<QHBoxLayout>,
    ) -> (MutPtr<QLineEdit>, MutPtr<QPushButton>) {
        let mut button = QPushButton::from_q_string(&QString::from_std_str("Button"));
        let bp = button.as_mut_ptr();
        let label = QLabel::from_q_string(&QString::from_std_str("Push to Reset"));
        let mut vlayout = QVBoxLayout::new_0a();
        vlayout.add_stretch_1a(1);
        vlayout.add_widget(label.into_ptr());
        vlayout.add_widget(button.into_ptr());
        vlayout.add_stretch_1a(1);
        layout.add_stretch_1a(1);
        layout.add_layout_1a(vlayout.into_ptr());
        let mut le = QLineEdit::new();
        let le_ptr = le.as_mut_ptr();
        layout.add_widget(le.into_ptr());
        layout.add_stretch_1a(1);
        (le_ptr, bp)
    }
    unsafe fn new() -> Self {
        let mut widget = QWidget::new_0a();
        let mut master_layout = QVBoxLayout::new_0a();
        let mut layout = QHBoxLayout::new_0a();
       // use into_ptr to transfer ownership to a widget or layout (there should be a single owner)
        let (le, bp) = Self::add_button(layout.as_mut_ptr());
        let mut history = QListWidget::new_0a();
        let mut hist_ptr = history.as_mut_ptr();
        master_layout.add_layout_1a(layout.into_ptr());
        master_layout.add_widget(history.into_ptr());
        widget.set_layout(master_layout.into_ptr());
        widget.show();
        let mut le_ptr = le.clone();
        let mut bp_ptr = bp.clone();
        let form = Form {
            _widget: widget,
            _button: bp,
            _line_edit: le,
            _history: hist_ptr,
            line_edit_edited: Slot::new(move || {
                let letext = le_ptr.text();
                bp_ptr.set_text(letext.as_ref());
            }),
            button_pushed: Slot::new(move || {
                let txt = bp_ptr.text();
                hist_ptr.add_item_q_string(&txt);
                le_ptr.clear();
                bp_ptr.set_text(&QString::from_std_str("Push Me"));
            }),
        };
       // wire up signals to slots. Slots can be rust closures
        le_ptr.text_edited().connect(&form.line_edit_edited);
        bp_ptr.clicked().connect(&form.button_pushed);
        form
    }
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    QApplication::init(|_| unsafe {
        let _form = Form::new();
        QApplication::exec()
    });
}

And here is the Cargo.toml

[package]
name = "qtstuff"
version = "0.1.0"
edition = "2018"

[dependencies]
qt_core = "0.4.0"
qt_gui = "0.4.0"
qt_widgets = "0.4.0"
qt_ui_tools = "0.4.0"
cpp_core = "0.5.0"
1 Like

Hey @jlgerber, good to see you here :wink:

Did you see this?

Or the matching video?

That way you can mix C++ and Rust code as you like. Do the GUI enterly in C++, do the logic, functions, maintain the data in Rust ... You can even use cargo to compile the C++ Qt stuff ... and you can start with QML if you like. I prefer pure C++ and pure Rust with a minimal JSON description which data to exchange.

1 Like

Thanks @wahn. I have significant time/energy invested in Qt Widgets, and don't necessarily have the desire to move to qml (and as someone developing desktop apps, i don't know that I am really the target audience). The last time I looked at QML, it seemed like a mobile first framework. I do know that a lot has changed but....
In terms of rust-qt-binding-generator, I was also turned off by having to write the json file, and generally have to think about c++ at all. rust-qt is IMHO far simpler to drop into.

Oh it's never been mobile first. It's just a markup language for defining the GUI's. Take the desktop environment KDE for example, about everything is defined in QML, and thus about everything is redesignable down to very detailed levels. It's a very quick way to build Qt apps and it builds an entire scenetree for very quick rendering.

As far as I can make out QML is basically a way of using Qt from Javascript.

Basically they added the JS layer when it was realized that creating complex, fluid, GUIs in C++ was too difficult.

:slight_smile:

QML isn't JavaScript. It can have logic in JavaScript inside, but it is a declarative language like XML.

It can look like this:

Rectangle {
    color: Red,
    height: 100,
    width: 200,
    top: Point {
        x: 10,
        y: 5
    }
}

(I'm not sure if it's valid QML, but it gets the gist across.)

1 Like

Looks like Javascript to me. I was referring to this:
https://doc.qt.io/qt-5/qtqml-javascript-expressions.html

TypeName { ... } is not valid JavaScript.

1 Like

It's a fair cop. It's not JS exactly.

More like JS/JSON than the old XML layout language though.

If they had seen it through and put the V8 JS engine into Qt we could build apps with that instead of having to use Electron.

Even in the JS world itself, they use stuff like JSX and Handlebars. Domain-specific languages. All of them.

That example is actually really close to Rust struct literals, but I'm guessing it would have to take ownership of the strings if it was real, and the callback thing would have to be a closure, so it would look like this:

Rectangle {
    id: "colorbutton".to_owned(),
    width: 200, height: 80,

    color: || if inputHandler.pressed { "steelblue" } else { "lightsteelblue" }.to_owned(),

    TapHandler {
        id: "inputHandler".to_owned(),
    }
}

I think we'd also have to sprinkle .. Default::default() around liberally as well. And do something about that inputHandler thing.

It's very rare for a general language to be as nice as a DSL. So, seriously, please don't hold C++ to that impossible standard. It reeks of language zealotry.

1 Like
Old post version I'm a moron with outdated info

QtScript is JavascriptCore from WebKit. QML might even be based on it. I dunno. I stopped using Qt for anything around the Qt4 era. In any case, replacing JSC with V8 would be irrelevant. Unless you hit a weird slow path in a corner case somewhere, both are interchangeable.

QJSEngine is V8, and it is the basis of QML

Electron literally runs existing web apps. The DOM as much a part of its value proposition as V8 is.

I don't do zealotry much. I can complain like hell about all the languages I have ever used. Or anything else for that matter.

Many times what I want to know are objective criteria: Does it fit in the space available? Does it perform well? Is it a cross-platform solution? Will whatever is made with it still be maintainable in 10 years, or twenty ... ?

Yes, I know.

What I was idly musing about is that Qt could adopt the V8 JS engine. There is no need for the DOM anymore than when V8 is used in node.js.

Rather there would be the API between JS and Qt. Kind of node.js with a GUI.