ruic

The Rust analog to Qt's uic.

Installation

cargo install ruic

Usage

``` USAGE: ruic [FLAGS] [OPTIONS] [path]

FLAGS: --all Load objects that would ordinarily be ignored -f, --format Run rustfmt on output -h, --help Prints help information --no-recursive Do not recursively scan directories -V, --version Prints version information

ARGS: Directory or file to scan [default: .]

OPTIONS: -o, --out Output file [default: path + "/uic.rs"] -s, --suffix Suffix to append to widget names, e.g. "Ui" to turn "App" into "AppUi" [default: ] ```

How It Works

ruic generates a single .rs file out of one or more Qt Designer .ui files. It does this by loading all the files into source code and generating a load method for each one. Generated files require a few dependencies:

Example

Suppose you use Qt Designer to create the following file:

xml <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>HelloWorld</class> <widget class="QDialog" name="HelloWorld"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>400</width> <height>300</height> </rect> </property> <property name="windowTitle"> <string>Dialog</string> </property> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QLabel" name="label_HelloWorld"> <property name="text"> <string>Hello world!</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="SayHi"/> </item> </layout> </widget> <resources/> <connections/> </ui>

Running ruic on it will output the following .rs file:

```rs // This file is automatically generated. use cppcore::{CastInto, Ptr}; use qtcore::{QBox, QPtr}; use qtuitools::QUiLoader; use qt_widgets::*;

[derive(Debug)]

pub struct HelloWorld { pub widget: QBox, pub sayhi: QPtr, } impl HelloWorld { pub fn load>>(parent: P) -> Self { unsafe { let loader = QUiLoader::new0a(); loader.setlanguagechangeenabled(true); let bytes = "HelloWorld00400300DialogHello world!".asbytes(); let widget = loader.loadbyteswithparent(bytes, parent); assert!(!widget.isnull(), "invalid ui file"); Self { sayhi: widget.findchild("SayHi").unwrap(), widget: QBox::fromqptr(widget.intoqptr().dynamic_cast()), } } } } ```

Note: load's safety is ensured by loading the entire content of the .ui file into source code.

To make use of this file, you could then write a Rust+Qt module along these lines:

```rs use std::rc::Rc;

use cppcore::{CastInto, Ptr}; use qtwidgets::QWidget;

use crate::uic;

pub struct HelloWorld { ui: uic::HelloWorld, }

impl HelloWorld { fn new>>(parent: P) -> Rc { let this = Rc::new(Self { ui: uic::HelloWorld::load(parent), }); unsafe { this.init() }; this }

unsafe fn init(self: &Rc<Self>) {
    /* add slot + signal connectors, etc. */
}

} ```

Alternatively, you could pass something like --suffix=Ui to ruic in order to turn crate::uic::HelloWorld into crate::uic::HelloWorldUi, allowing you to import it directly without a name clash.

Note that in Rust+Qt, the way to create a parentless widget is to pass NullPtr as the parent.

Ignored Fields

By default, some fields are not loaded as variables into the struct:

If you want to include such fields, pass --all to ruic on the command line. With --all, the generated file from the example above would instead be:

```rs // This file is automatically generated. use cppcore::{CastInto, Ptr}; use qtcore::{QBox, QPtr}; use qtuitools::QUiLoader; use qt_widgets::*;

[derive(Debug)]

pub struct HelloWorld { pub widget: QBox, pub horizontallayout: QPtr, pub labelhelloworld: QPtr, pub sayhi: QPtr, } impl HelloWorld { pub fn load>>(parent: P) -> Self { unsafe { let loader = QUiLoader::new0a(); loader.setlanguagechangeenabled(true); let bytes = "HelloWorld00400300DialogHello world!".asbytes(); let widget = loader.loadbyteswithparent(bytes, parent); assert!(!widget.isnull(), "invalid ui file"); Self { horizontallayout: widget.findchild("horizontalLayout").unwrap(), labelhelloworld: widget.findchild("labelHelloWorld").unwrap(), sayhi: widget.findchild("SayHi").unwrap(), widget: QBox::fromqptr(widget.intoqptr().dynamiccast()), } } } } ```