Skip to content

jnbooth/ruic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ruic

crates.io Linux: Build Status

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:
    <path>    Directory or file to scan [default: .]

OPTIONS:
    -o, --out <out>          Output file [default: path + "/uic.rs"]
    -s, --suffix <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:

Demo

Suppose you use Qt Designer to create the following file:

<?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:

// 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<QDialog>,
    pub say_hi: QPtr<QLineEdit>,
}
impl HelloWorld {
    pub fn load<P: CastInto<Ptr<QWidget>>>(parent: P) -> Self {
        unsafe {
            let loader = QUiLoader::new_0a();
            loader.set_language_change_enabled(true);
            let bytes = "<?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>".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 module along these lines:

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<P: CastInto<Ptr<QWidget>>>(parent: P) -> Rc<Self> {
        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, ruic ignores QButtonBoxes, QFrames, QGroupBoxes, QLabels, QLayouts, and QWidgets if they follow Qt Designer's default naming scheme for fields that are left unnamed: "<type>", "<type>_*" or "_*". 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:

// 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<QDialog>,
    pub horizontal_layout: QPtr<QHBoxLayout>,
    pub label_hello_world: QPtr<QLabel>,
    pub say_hi: QPtr<QLineEdit>,
}
impl HelloWorld {
    pub fn load<P: CastInto<Ptr<QWidget>>>(parent: P) -> Self {
        unsafe {
            let loader = QUiLoader::new_0a();
            loader.set_language_change_enabled(true);
            let bytes = "<?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>".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()),
            }
        }
    }
}

About

The Rust analog to Qt's uic

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages