Warning, /sdk/rust-qt-binding-generator/tutorial/time_for_rust_and_qml.md is written in an unsupported language. File is not indexed.

0001 # Time for QML
0002 
0003 If you are new to QML, I can recommend the [QML book](https://qmlbook.github.io/). It walks you through many wonderful examples. In addition, Qt Creator comes with [many more](https://doc.qt.io/qt-5/qtexamples.html).
0004 
0005 It is a tradition in KDE to use clocks as examples. I will follow this tradition and create a widget that shows the time.
0006 
0007 We'll start without any Rust at all. The first code is only QML. It uses the Rust logo as SVG image for the background, [`rust-logo-blk.svg`](https://www.rust-lang.org/logos/rust-logo-blk.svg). So download this file (or pick another SVG image and store it with that name).
0008 
0009 The syntax of QML is declarative. The rotation of the Rust logo is given by the statement `angle: time.second * 6`. This is a binding. The value of `angle` updates automatically whenever `time.second` changes. The rotation of the logo changes every second because of this declarative binding.
0010 
0011 Another example is `anchors.fill: parent` on the `Image` item. This means that the image takes up the same rectangular space as the parent item. If that item is resized, the image will scale along with it.
0012 
0013 In this file, we added a temporary `QtObject` with properties `hour`, `minute` and `second`. The values in this object are updated every second by the `Timer` item. The JavaScript code between `{}` runs every second and updates the values in the `QtObject`. This object has `id: time` and the logo and hands are bound to this object.
0014 
0015 The `QtObject` is a functional placeholder for the Rust code that we are going to write later.
0016 
0017 ```qml
0018 // just_qml.qml
0019 
0020 import QtQuick 2.5
0021 import QtQuick.Window 2.2
0022 
0023 Window {
0024     width: 512
0025     height: 512
0026     visible: true
0027 
0028     // A mock-up of the time object that we will
0029     // implement in Rust
0030     QtObject {
0031         id: time
0032         property int hour
0033         property int minute
0034         property int second
0035     }
0036     // This timer will also become Rust code
0037     Timer {
0038         interval: 1000; running: true; repeat: true
0039         onTriggered: {
0040             var date = new Date()
0041             time.hour = date.getHours()
0042             time.minute = date.getMinutes()
0043             time.second = date.getSeconds()
0044         }
0045     }
0046 
0047     // the clock face
0048     Image {
0049         anchors.fill: parent
0050         source: "rust-logo-blk.svg"
0051         sourceSize: Qt.size(width, height) // ensure rendered SVG canvas matches used size
0052         fillMode: Image.PreserveAspectFit
0053         transform: Rotation {
0054             origin.x: width / 2
0055             origin.y: height / 2
0056             angle: time.second * 6 // convert seconds to degrees
0057         }
0058     }
0059     // the minute hand
0060     Rectangle {
0061         id: minute
0062         x: (parent.width - width) / 2
0063         y: 0
0064         width: parent.width / 100
0065         height: parent.height / 1.8
0066         radius: width
0067         color: "#3daefd"
0068         transform: Rotation {
0069             origin.x: hour.width / 2
0070             origin.y: height / 2
0071             // convert minutes to degrees
0072             angle: time.minute * 6
0073         }
0074     }
0075     // the hour hand
0076     Rectangle {
0077         id: hour
0078         x: (parent.width - width) / 2
0079         y: parent.height / 6
0080         width: parent.width / 50
0081         height: parent.height / 2.8
0082         radius: width
0083         color: "#3daefd"
0084         transform: Rotation {
0085             origin.x: hour.width / 2
0086             origin.y: height / 3
0087             // convert hours to degrees
0088             angle: time.hour * 30 + time.minute / 2
0089         }
0090     }
0091 }
0092 ```
0093 
0094 You can run the plain QML file with the tool `qmlscene`.
0095 
0096 ```
0097 $ qmlscene just_qml.qml
0098 ```
0099 
0100 
0101 <figure>
0102   <img src="time.png" alt="Time for Rust and QML"/>
0103   <figcaption>Time for Rust and QML</figcaption>
0104 </figure>
0105 
0106 `qmlscene` can run any plain QML files. If you have QML plugins installed, these can be used too. You can make plugins that are implemented in Rust, but we'll not go into that now.
0107 
0108 
0109 ## Set up a QML project with Rust
0110 
0111 Before we can replace the `QtObject`, we have to set up a project. Rust Qt Binding Generator comes with a template project for QML in the folder [`templates/qt_quick`](https://commits.kde.org/rust-qt-binding-generator?path=templates/qt_quick).
0112 
0113 You can get set up like so. You will need to have Qt, Rust and CMake installed.
0114 
0115 First build `rust_qt_binding_generator`.
0116 
0117 ```
0118 $ git clone git://anongit.kde.org/rust-qt-binding-generator
0119 $ mkdir build
0120 $ cd rust-qt-binding-generator/build
0121 $ cmake ..
0122 $ make rust_qt_binding_generator
0123 $ export PATH=$PATH:$PWD/src
0124 ```
0125 
0126 `cmake ..` uses `make` by default, but you can use another build tool, for example Ninja, like this: `cmake -GNinja ..`.
0127 
0128 Now build and run the template project.
0129 
0130 ```
0131 $ mkdir ../templates/qt_quick/build
0132 $ cd ../templates/qt_quick/build
0133 $ cmake ..
0134 $ make
0135 $ ./MyExe
0136 ```
0137 
0138 You will be greeted with a 'Hello World' application.
0139 
0140 
0141 ## Starting from a template
0142 
0143 So what just happened? The template project is based on CMake. CMake is the build system that most KDE projects use. A template in CMake is an example of how to add Rust code to KDE programs. It is possible to use another build system.
0144 
0145 CMake performs four steps as instructed by the `CMakeLists.txt` file. It
0146 
0147 1) generates Rust and C++ from `bindings.json` by calling `rust_qt_binding_generator`,
0148 2) compiles the Rust code in `rust/` into a static library by calling `cargo`,
0149 3) compiles the C++ code,
0150 4) links the C++ objects, the QML files, and the Rust library into an executable.
0151 
0152 If you prefer to use only `cargo`, you'll have to tell it to perform steps 1, 3 and 4 in a `build.js` file.
0153 
0154 
0155 ## Adding some Rust
0156 
0157 Now let's turn this clock into the [Antikythera mechanism](https://en.wikipedia.org/wiki/Antikythera_mechanism) by adding some Rust.
0158 
0159 We want the Rust code to have a Time object that indicates the hour, the minute and the second. We write this interface into `bindings.json`.
0160 
0161 ```json
0162 {
0163     "cppFile": "src/Bindings.cpp",
0164     "rust": {
0165         "dir": "rust",
0166         "interfaceModule": "interface",
0167         "implementationModule": "implementation"
0168     },
0169     "objects": {
0170         "Time": {
0171             "type": "Object",
0172             "properties": {
0173                 "hour": {
0174                     "type": "quint32"
0175                 },
0176                 "minute": {
0177                     "type": "quint32"
0178                 },
0179                 "second": {
0180                     "type": "quint32"
0181                 }
0182             }
0183         }
0184     }
0185 }
0186 ```
0187 
0188 Now if we run `make` again, three files will be updated: `src/Bindings.h`, `src/Bindings.cpp`, and `rust/src/interface.rs`. And then we'll get a compile error from `cargo`.
0189 
0190 That is because we have to adapt `rust/src/implementation.rs` to the new `interface.rs`. `interface.rs` specifies a trait that must be implemented in `implementation.rs`.
0191 
0192 This is the generated trait:
0193 
0194 ```rust
0195 // rust/src/interface.rs
0196 
0197 pub trait TimeTrait {
0198     fn new(emit: TimeEmitter) -> Self;
0199     fn emit(&self) -> &TimeEmitter;
0200     fn hour(&self) -> u32;
0201     fn minute(&self) -> u32;
0202     fn second(&self) -> u32;
0203 }
0204 ```
0205 
0206 Note that the trait has getters, but no setters. With `"write": true`, you can add setters on properties.
0207 
0208 For now, we implement a fixed time in our new `implementation.rs`.
0209 
0210 ```rust
0211 // rust/src/implementation.rs
0212 
0213 use interface::*;
0214 
0215 pub struct Time {
0216     emit: TimeEmitter
0217 }
0218 
0219 impl TimeTrait for Time {
0220     fn new(emit: TimeEmitter) -> Self {
0221         Time {
0222             emit
0223         }
0224     }
0225     fn emit(&self) -> &TimeEmitter {
0226         &self.emit
0227     }
0228     fn hour(&self) -> u32 {
0229         1
0230     }
0231     fn minute(&self) -> u32 {
0232         52
0233     }
0234     fn second(&self) -> u32 {
0235         0
0236     }
0237 }
0238 ```
0239 
0240 Now whenever the QML application wants to know the time, it can ask the Rust code. Well, almost. We have to change three more files and one of them is a C++ file. It is a very simple change and it is needed to tell the QML code about the Rust QObject. In `src/main.cpp`, change this line:
0241 
0242 ```c++
0243     // src/main.cpp
0244 
0245     qmlRegisterType<Simple>("RustCode", 1, 0, "Simple");
0246 ```
0247 
0248 to this
0249 
0250 ```c++
0251     // src/main.cpp
0252 
0253     qmlRegisterType<Time>("RustCode", 1, 0, "Time");
0254 ```
0255 
0256 Next we add the Rust logo to the program, by copying the file `rust-logo-blk.svg` into the toplevel dir of the template and noting it as resource in `qml.qrc`. That file lists files that should be compiled into the executable.
0257 
0258 ```xml
0259 <RCC>
0260     <qresource prefix="/">
0261         <file>main.qml</file>
0262         <file>rust-logo-blk.svg</file>
0263     </qresource>
0264 </RCC>
0265 ```
0266 
0267 Now create the file `main.qml`. The line `import RustCode 1.0` imports our Rust object into the application. Our mockup `QtObject` and the `Timer` have been replaced with `Time { id: time }`.
0268 
0269 This `Time` still has the properties `hour`, `minute`, and `second`. Whenever these change, the user interface is updated.
0270 
0271 ```qml
0272 // main.qml
0273 
0274 import QtQuick 2.5
0275 import QtQuick.Window 2.2
0276 import RustCode 1.0
0277 
0278 Window {
0279     width: 512
0280     height: 512
0281     visible: true
0282 
0283     // here is our Rust time
0284     Time {
0285         id: time
0286     }
0287 
0288     // the clock face
0289     Image {
0290         anchors.fill: parent
0291         source: "rust-logo-blk.svg"
0292         sourceSize: Qt.size(width, height) // ensure rendered SVG canvas matches used size
0293         fillMode: Image.PreserveAspectFit
0294         transform: Rotation {
0295             origin.x: width / 2
0296             origin.y: height / 2
0297             angle: time.second * 6 // convert seconds to degrees
0298         }
0299     }
0300     // the minute hand
0301     Rectangle {
0302         id: minute
0303         x: (parent.width - width) / 2
0304         y: 0
0305         width: parent.width / 100
0306         height: parent.height / 1.8
0307         radius: width
0308         color: "#3daefd"
0309         transform: Rotation {
0310             origin.x: hour.width / 2
0311             origin.y: height / 2
0312             // convert minutes to degrees
0313             angle: time.minute * 6
0314         }
0315     }
0316     // the hour hand
0317     Rectangle {
0318         id: hour
0319         x: (parent.width - width) / 2
0320         y: parent.height / 6
0321         width: parent.width / 50
0322         height: parent.height / 2.8
0323         radius: width
0324         color: "#3daefd"
0325         transform: Rotation {
0326             origin.x: hour.width / 2
0327             origin.y: height / 3
0328             // convert hours to degrees
0329             angle: time.hour * 30 + time.minute / 2
0330         }
0331     }
0332 }
0333 ```
0334 
0335 
0336 ## Start the time
0337 
0338 <figure>
0339   <img src="happy_time.png" alt="The time is now"/>
0340   <figcaption>A happy clock</figcaption>
0341 </figure>
0342 
0343 Are you still here? That was quite a few instructions to follow for a simple example. The good news is that this setup does not get harder when you add more interfaces.
0344 
0345 Anyway, now the part you've been waiting for. We will let Rust update the time and send it to the user interface. The crate `chrono` is used to get the time. Add it to `lib.rs` and `Cargo.toml`.
0346 
0347 ```toml
0348 # rust/Cargo.toml
0349 ...
0350 
0351 [dependencies]
0352 chrono = "*"
0353 ...
0354 ```
0355 
0356 ```rust
0357 // rust/src/lib.rs
0358 ...
0359 extern crate chrono;
0360 ...
0361 ```
0362 
0363 This code goes in `implementation.rs`. A thread wakes up every second and sends a signal to the user interface whenever a property changes.
0364 
0365 ```rust
0366 // rust/src/implementation.rs
0367 
0368 use interface::*;
0369 use chrono::{Local, Timelike};
0370 use std::thread;
0371 use std::time::Duration;
0372 
0373 pub struct Time {
0374     emit: TimeEmitter,
0375 }
0376 
0377 fn emit_time(emit: TimeEmitter) {
0378     thread::spawn(move || {
0379         loop {
0380             thread::sleep(Duration::from_secs(1));
0381             emit.second_changed();
0382             if Local::now().second() == 0 {
0383                 emit.minute_changed();
0384                 if Local::now().minute() == 0 {
0385                     emit.hour_changed();
0386                 }
0387             }
0388         }
0389     });
0390 }
0391 
0392 impl TimeTrait for Time {
0393     fn new(emit: TimeEmitter) -> Self {
0394         emit_time(emit.clone());
0395         Time {
0396             emit
0397         }
0398     }
0399     fn emit(&self) -> &TimeEmitter {
0400         &self.emit
0401     }
0402     fn hour(&self) -> u32 {
0403         Local::now().hour()
0404     }
0405     fn minute(&self) -> u32 {
0406         Local::now().minute()
0407     }
0408     fn second(&self) -> u32 {
0409         Local::now().second()
0410     }
0411 }
0412 ```
0413 
0414 
0415 ## Closing remarks
0416 
0417 This was a pretty long tutorial with quite a few different parts. That was the point of the tutorial: to learn the parts that make up a binding between Qt and Rust.