qt-cb

Provides several convenience closure taking methods to rust-qt.

Rationale

Even though Qt's signal and slot mechanism is quite powerful and allows for very dynamic code and programming model, it's not always needed, especially for simple functionality or simple debugging.

In both C++ and Rust, defining signals and slots can become verbose at times, and even Qt itself supports closures on the C++ side.

For example, compare the following 2 programs for readability and writing ergonomics. Both programs do the same thing, the first doesn't use closures, it defines slots for the required signals. The second program, uses this crate, and uses closures without having to define slots in a separate object, nor does it require the derive SlotNoArgs/SlotOfBool/SlotOfQString boilerplate.

The first program (no closures): ```rust // no closures use cppcore::{Ptr, Ref, StaticUpcast}; use qtcore::{qs, slot, QBox, QObject, QString, SlotNoArgs, SlotOfBool, SlotOfQString}; use qt_widgets::{ QApplication, QCheckBox, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, QWidget, }; use std::rc::Rc;

struct Form { win: QBox, ed: QBox, checkbox: QBox, button: QBox, }

impl StaticUpcast for Form { unsafe fn staticupcast(ptr: Ptr) -> Ptr { ptr.win.asptr().static_upcast() } }

impl Form { fn new() -> Rc

{ unsafe { let win = QWidget::new0a(); win.setfixedsize2a(400, 300); let vbox = QVBoxLayout::new1a(&win); let ed = QLineEdit::new(); ed.setplaceholdertext(&qs("Enter name")); vbox.addwidget(&ed); let hbox = QHBoxLayout::new0a(); vbox.addlayout1a(&hbox); let checkbox = QCheckBox::new(); hbox.addwidget(&checkbox); checkbox.settext(&qs("Check me!")); let button = QPushButton::new(); hbox.addwidget(&button); button.set_text(&qs("Greet!")); win.show();

        let this = Rc::new(Self {
            win,
            ed,
            checkbox,
            button,
        });
        this.init();
        this
    }
}

unsafe fn init(self: &Rc<Self>) {
    self.ed
        .text_changed()
        .connect(&self.slot_on_lineedit_text_changed());
    self.button
        .pressed()
        .connect(&self.slot_on_button_pressed());
    self.checkbox
        .clicked()
        .connect(&self.slot_on_checkbox_clicked());
}

#[slot(SlotNoArgs)]
unsafe fn on_button_pressed(self: &Rc<Self>) {
    println!("Hello {}", self.ed.text().to_std_string());
}

#[slot(SlotOfBool)]
unsafe fn on_checkbox_clicked(self: &Rc<Self>, checked: bool) {
    println!(
        "{} is {}checked",
        self.checkbox.text().to_std_string(),
        if checked { "" } else { "un" }
    );
}

#[slot(SlotOfQString)]
unsafe fn on_lineedit_text_changed(self: &Rc<Self>, txt: Ref<QString>) {
    println!("current lineedit text: {}", txt.to_std_string());
}

}

fn main() { QApplication::init(|_| unsafe { let _form = Form::new(); QApplication::exec() }) } ```

The second program (with closures): ```rust // with closures use qtcb::prelude::*; use qtcore::qs; use qt_widgets::{ QApplication, QCheckBox, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, QWidget, };

fn main() { QApplication::init(|| unsafe { QApplication::setstyleqstring(&qs("Fusion")); let win = QWidget::new0a(); win.setfixedsize2a(400, 300); let vbox = QVBoxLayout::new1a(&win); let ed = QLineEdit::new(); ed.setplaceholdertext(&qs("Enter name")); ed.ontextchanged(|ed, txt| { println!("current lineedit text: {}", txt.tostdstring()); }); vbox.addwidget(&ed); let hbox = QHBoxLayout::new0a(); vbox.addlayout1a(&hbox); let checkbox = QCheckBox::new(); hbox.addwidget(&checkbox); checkbox.settext(&qs("Check me!")); checkbox.onclicked(|b, checked| { println!( "{} is {}checked", b.text().tostdstring(), if checked { "" } else { "un" } ); }); let button = QPushButton::new(); hbox.addwidget(&button); button.settext(&qs("Greet!")); button.onpressed(move |b| { println!("Hello {}", ed.text().tostdstring()); }); win.show(); QApplication::exec() }) } Notice the: rust ed.ontextchanged(|ed, txt| { println!("current lineedit text: {}", txt.tostdstring()); }); checkbox.onclicked(|b, checked| { println!( "{} is {}checked", b.text().tostdstring(), if checked { "" } else { "un" } ); }); button.onpressed(move |b| { println!("Hello {}", ed.text().tostd_string()); }); ```

Instead of: ```rust self.ed .textchanged() .connect(&self.slotonlineedittextchanged()); self.button .pressed() .connect(&self.slotonbuttonpressed()); self.checkbox .clicked() .connect(&self.slotoncheckbox_clicked());

#[slot(SlotNoArgs)]
unsafe fn on_button_pressed(self: &Rc<Self>) {
    println!("Hello {}", self.ed.text().to_std_string());
}

#[slot(SlotOfBool)]
unsafe fn on_checkbox_clicked(self: &Rc<Self>, checked: bool) {
    println!(
        "{} is {}checked",
        self.checkbox.text().to_std_string(),
        if checked { "" } else { "un" }
    );
}

#[slot(SlotOfQString)]
unsafe fn on_lineedit_text_changed(self: &Rc<Self>, txt: Ref<QString>) {
    println!("current lineedit text: {}", txt.to_std_string());
}

```

Implementation details

qt-cb uses functionality already provided in rust-qt. It instantiates the necessary Slot, and passes a closure directly to it. It also passes the widget itself into the closure, so you get access to the widget as well in your closure.

Usage

```toml [dependencies] qt-cb = "0.1.0"

the rest of the dependencies or rust-qt

```

Requirements

This crate has the same requirements of rust-qt.