# ruic The Rust analog to Qt's [uic](https://doc.qt.io/qt-5/uic.html). ## 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](https://doc.qt.io/qt-5/qtdesigner-manual.html) .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: - [cpp_core](https://crates.io/crates/cpp_core) - [qt_core](https://crates.io/crates/qt_core) - [qt_widgets](https://crates.io/crates/qt_widgets) - [qt_ui_tools](https://crates.io/crates/qt_ui_tools) ## Example Suppose you use Qt Designer to create the following file: ```xml HelloWorld 0 0 400 300 Dialog Hello world! ``` Running ruic on it will output the following .rs file: ```rs // This file is automatically generated. use cpp_core::{CastInto, Ptr}; use qt_core::{QBox, QPtr}; use qt_ui_tools::QUiLoader; use qt_widgets::*; #[derive(Debug)] pub struct HelloWorld { pub widget: QBox, pub say_hi: QPtr, } impl HelloWorld { pub fn load>>(parent: P) -> Self { unsafe { let loader = QUiLoader::new_0a(); loader.set_language_change_enabled(true); let bytes = "HelloWorld00400300DialogHello world!".as_bytes(); let widget = loader.load_bytes_with_parent(bytes, parent); assert!(!widget.is_null(), "invalid ui file"); Self { say_hi: widget.find_child("SayHi").unwrap(), widget: QBox::from_q_ptr(widget.into_q_ptr().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](https://github.com/rust-qt/examples) module along these lines: ```rs use std::rc::Rc; use cpp_core::{CastInto, Ptr}; use qt_widgets::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) { /* 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](https://docs.rs/cpp_core/newest/cpp_core/struct.NullPtr.html) as the parent. ## Ignored Fields By default, some fields are not loaded as variables into the struct: - [QLabel](https://doc.qt.io/qt-5/qlabel.html)s that are named "label", start with "label_", or end with "_label" - [QGroupBox](https://doc.qt.io/qt-5/qgroupbox.html)es - [QLayout](https://doc.qt.io/qt-5/qlayout.html)s with children 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 cpp_core::{CastInto, Ptr}; use qt_core::{QBox, QPtr}; use qt_ui_tools::QUiLoader; use qt_widgets::*; #[derive(Debug)] pub struct HelloWorld { pub widget: QBox, pub horizontal_layout: QPtr, pub label_hello_world: QPtr, pub say_hi: QPtr, } impl HelloWorld { pub fn load>>(parent: P) -> Self { unsafe { let loader = QUiLoader::new_0a(); loader.set_language_change_enabled(true); let bytes = "HelloWorld00400300DialogHello world!".as_bytes(); let widget = loader.load_bytes_with_parent(bytes, parent); assert!(!widget.is_null(), "invalid ui file"); Self { horizontal_layout: widget.find_child("horizontalLayout").unwrap(), label_hello_world: widget.find_child("label_HelloWorld").unwrap(), say_hi: widget.find_child("SayHi").unwrap(), widget: QBox::from_q_ptr(widget.into_q_ptr().dynamic_cast()), } } } } ```