woboq / qmetaobject-rs

Integrate Qml and Rust by building the QMetaObject at compile time.
MIT License
637 stars 89 forks source link

Trying to wrap QQuickPaintedItem for PieChart Example #25

Open Pfeil opened 5 years ago

Pfeil commented 5 years ago

Hi, I'm trying replicate this example (Chapter 1) of a PieChart implemented in C++ for QML, but in Rust (to unterstand better how things in qmetaobject work). I do not have much experience with Qt or the cpp macro.

In this example, I need to derive from QQuickPaintedItem. So I tried to wrap it like it is done with QQuickItem, since QQuickPaintedItem derives from it. Here is how I tried it (I implemented the paint method directly in c++ to avoid more complications for now):

qtdeclarative.rs

pub trait QQuickPaintedItem: QQuickItem {
    fn get_object_description() -> &'static QObjectDescription
    where
        Self: Sized,
    {
        unsafe {
            &*cpp!([]-> *const QObjectDescription as "RustObjectDescription const*" {
            return rustObjectDescription<Rust_QQuickPaintedItem>();
        } )
        }
    }
}

cpp! {{
#include <qmetaobject_rust.hpp>
#include <QtQuick/QQuickPaintedItem>
#include <QPen>
#include <QPainter>
struct Rust_QQuickPaintedItem : RustObject<QQuickPaintedItem> {
    void paint(QPainter *painter) override
    {
        QPen pen(m_color, 2);
        painter->setPen(pen);
        painter->setRenderHints(QPainter::Antialiasing, true);
        painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
        // TODO use a trait changeable painting method
        //rust!(Rust_QQuickPaintedItem_paint[rust_object : QObjectPinned<QQuickPaintedItem> as "TraitObject"] {
        //    rust_object.borrow_mut().paint();
        //});
    }
};

}} // END cpp!

But it does not compile. What am I doing wrong? I implemented it within qmetaobject/src/declatative.rs because I thought I may need to change more things to make it work in my crate. The error message is somewhat non-informative, so I also added the backtrace:

Click to see the error and backtrace. ``` qmetaobject> env RUST_BACKTRACE=1 cargo build Compiling qmetaobject v0.0.5 (/home/verpfeilt/Git/qmetaobject-rs/qmetaobject) error: failed to run custom build command for `qmetaobject v0.0.5 (/home/verpfeilt/Git/qmetaobject-rs/qmetaobject)` process didn't exit successfully: `/home/verpfeilt/Git/qmetaobject-rs/qmetaobject/target/debug/build/qmetaobject-4a8cf3a876705a03/build-script-build` (exit code: 101) --- stderr thread 'main' panicked at 'Error while parsing cpp! macro: "src/qtdeclarative.rs":581:Lexing error', /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:430:25 stack backtrace: 0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49 1: std::sys_common::backtrace::_print at src/libstd/sys_common/backtrace.rs:71 2: std::panicking::default_hook::{{closure}} at src/libstd/sys_common/backtrace.rs:59 at src/libstd/panicking.rs:211 3: std::panicking::default_hook at src/libstd/panicking.rs:227 4: std::panicking::rust_panic_with_hook at src/libstd/panicking.rs:495 5: std::panicking::continue_panic_fmt at src/libstd/panicking.rs:398 6: std::panicking::begin_panic_fmt at src/libstd/panicking.rs:353 7: cpp_build::parser::Parser::find_cpp_macros::{{closure}} at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:430 8: >::unwrap_or_else at /rustc/9fda7c2237db910e41d6a712e9a2139b352e558b/src/libcore/result.rs:774 9: cpp_build::parser::Parser::find_cpp_macros at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:429 10: cpp_build::parser::Parser::parse_mod at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:350 11: >::visit_item_mod at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:557 12: syn::gen::visit::visit_item at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-0.15.26/src/gen/visit.rs:2174 13: syn::gen::visit::Visit::visit_item at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-0.15.26/src/gen/visit.rs:430 14: syn::gen::visit::visit_file at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-0.15.26/src/gen/visit.rs:1839 15: syn::gen::visit::Visit::visit_file at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-0.15.26/src/gen/visit.rs:342 16: cpp_build::parser::Parser::parse_mod at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:351 17: cpp_build::parser::Parser::parse_crate at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/parser.rs:326 18: cpp_build::Config::build at /home/verpfeilt/.cargo/registry/src/github.com-1ecc6299db9ec823/cpp_build-0.5.1/src/lib.rs:621 19: build_script_build::main at ./build.rs:36 20: std::rt::lang_start::{{closure}} at /rustc/9fda7c2237db910e41d6a712e9a2139b352e558b/src/libstd/rt.rs:74 21: std::panicking::try::do_call at src/libstd/rt.rs:59 at src/libstd/panicking.rs:310 22: __rust_maybe_catch_panic at src/libpanic_unwind/lib.rs:102 23: std::rt::lang_start_internal at src/libstd/panicking.rs:289 at src/libstd/panic.rs:398 at src/libstd/rt.rs:58 24: std::rt::lang_start at /rustc/9fda7c2237db910e41d6a712e9a2139b352e558b/src/libstd/rt.rs:74 25: main 26: __libc_start_main 27: _start ```

I'm using up-to-date stable rust.

ogoffart commented 5 years ago

The problem is in the cpp_build crate. It appears that it fails to parse the rust! if it is within a comment.

ogoffart commented 5 years ago

I made a fix for the cpp_build crate there: https://github.com/mystor/rust-cpp/pull/50

Pfeil commented 5 years ago

Wow. I did not know that Macros are working on such a level that this can happen. Thanks for the quick response! It worked after removing the comment and with some simple adjustments (fixing the cpp imports). Thanks! Now I have to wrap around QPainter to make the paint(&self, painter: &QPainter) method available in the trait. I assume I could implement it similar to i.e. QColor. Would that be the right way? Should QPainter then also go into the qttypes.rs module? (I'm aiming to create a pull request in the next few days in case you are interested.)

ogoffart commented 5 years ago

Thanks for looking into this. Yes, I you'll have to wrap the QPainter API, and i guess another module (qpainter.rs ?) would be better, since it is a quite big API