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, defining slots, especially on the Rust side, can be verbose and filled with boilerplate. You might just need to quickly debug something or add some simple functionality to a widget without having to go through the ritual of defining slots.

For example, compare the following 2 programs. Both programs do the same thing, the first uses this crate, and uses closures without having to define slots or deriving SlotNoArgs/SlotOfBool/SlotOfQString etc. The second doesn't use closures, it defines slots for the required signals, it requires importing SlotNoArgs/SlotOfBool/SlotOfQString boilerplate, and using the correct Slot type.

The first program (with closures): ```rust,norun // with closures use qtcb::prelude::*; use qtcore::qs; use qtwidgets::{ 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().tostd_string()); }); win.show(); QApplication::exec() }) } ```

The second program (no closures): ```rust,norun // no closures use cppcore::{Ptr, Ref, StaticUpcast}; use qtcore::{qs, slot, QBox, QObject, QString, SlotNoArgs, SlotOfBool, SlotOfQString}; use qtwidgets::{ 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() }) } ```

Notice the: rust,ignore ed.on_text_changed(|_ed, txt| { println!("current lineedit text: {}", txt.to_std_string()); }); checkbox.on_clicked(|b, checked| { println!( "{} is {}checked", b.text().to_std_string(), if checked { "" } else { "un" } ); }); button.on_pressed(move |_b| { println!("Hello {}", ed.text().to_std_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: rust,ignore impl InputExt for QBox<QLineEdit> { unsafe fn on_text_changed<F: FnMut(Ptr<QLineEdit>, Ref<QString>) + 'static>(&self, mut cb: F) { let wid: Ptr<QLineEdit> = self.cast_into(); wid.text_changed() .connect(&SlotOfQString::new(wid, move |b| { cb(wid, b); })); } }

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.