Skip to content

Commit

Permalink
Image support
Browse files Browse the repository at this point in the history
Issue #5 and #7
  • Loading branch information
barche committed Apr 15, 2016
1 parent 13c28d8 commit 6b55ed1
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 8 deletions.
2 changes: 2 additions & 0 deletions deps/src/qmlwrap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ endif(WIN32)
add_library(qmlwrap SHARED
julia_api.hpp
julia_api.cpp
julia_display.hpp
julia_display.cpp
julia_object.hpp
julia_object.cpp
julia_signals.hpp
Expand Down
2 changes: 1 addition & 1 deletion deps/src/qmlwrap/julia_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ QVariant JuliaAPI::call(const QString& fname, const QVariantList& args)
result = jl_call(func, julia_args, nb_args);
if (jl_exception_occurred())
{
qWarning() << "Exception in Julia callback " << fname << ": " << QString(cxx_wrap::julia_type_name((jl_datatype_t*)jl_typeof(jl_exception_occurred())).c_str()) << ": " << jl_string_data(jl_fieldref(jl_exception_occurred(),0));
qWarning() << "Exception in Julia callback " << fname << ": " << QString(cxx_wrap::julia_type_name((jl_datatype_t*)jl_typeof(jl_exception_occurred())).c_str());// << ": " << jl_string_data(jl_fieldref(jl_exception_occurred(),0));
JL_GC_POP();
JL_GC_POP();
return QVariant();
Expand Down
46 changes: 46 additions & 0 deletions deps/src/qmlwrap/julia_display.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <QDebug>
#include <QPainter>

#include "julia_display.hpp"
namespace qmlwrap
{

JuliaDisplay::JuliaDisplay(QQuickItem *parent) : QQuickPaintedItem(parent)
{
}

void JuliaDisplay::paint(QPainter *painter)
{
painter->drawPixmap(0,0,m_pixmap);
}

void JuliaDisplay::load_png(cxx_wrap::ArrayRef<unsigned char> data)
{
if(m_pixmap.isNull())
{
clear();
}
if(!m_pixmap.loadFromData(data.data(), data.size(), "PNG"))
{
qWarning() << "Failed to load PNG data";
clear();
}
update();
}

void JuliaDisplay::clear()
{
m_pixmap = QPixmap(width(), height());
m_pixmap.fill(Qt::transparent);
}

void JuliaDisplay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry);
if(newGeometry != oldGeometry)
{
clear();
}
}

} // namespace qmlwrap
36 changes: 36 additions & 0 deletions deps/src/qmlwrap/julia_display.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef QML_JULIA_DISPLAY_H
#define QML_JULIA_DISPLAY_H

#include <cxx_wrap.hpp>

#include <QObject>
#include <QPixmap>
#include <QQuickPaintedItem>

namespace qmlwrap
{

/// Groups signals (defined using QML) that can be emitted from Julia
class JuliaDisplay : public QQuickPaintedItem
{
Q_OBJECT

public:
JuliaDisplay(QQuickItem *parent = 0);

void paint(QPainter *painter);

void load_png(cxx_wrap::ArrayRef<unsigned char> data);

void clear();

protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);

private:
QPixmap m_pixmap;
};

} // namespace qmlwrap

#endif
19 changes: 13 additions & 6 deletions deps/src/qmlwrap/type_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <QFileInfo>
#include <QUrl>

#include "julia_display.hpp"
#include "julia_object.hpp"
#include "type_conversion.hpp"

Expand Down Expand Up @@ -59,17 +60,22 @@ jl_value_t* convert_to_julia<QString>(const QVariant& v)
return nullptr;
}

template<typename... TypesT>
template<int T = 0>
jl_value_t* try_qobject_cast(QObject* o)
{
qWarning() << "got unknown QObject* type in QVariant conversion: " << o->metaObject()->className();
return nullptr;
}

template<typename Type1, typename... TypesT>
jl_value_t* try_qobject_cast(QObject* o)
{
for(auto* cast_o : {qobject_cast<TypesT*>(o)...})
Type1* cast_o = qobject_cast<Type1*>(o);
{
if(cast_o != nullptr)
return cxx_wrap::convert_to_julia(cast_o);
return try_qobject_cast<TypesT...>(o);
}

qWarning() << "got unknown QObject* type in QVariant conversion: " << o->metaObject()->className();
return nullptr;
}

// QObject*
Expand All @@ -78,7 +84,8 @@ jl_value_t* convert_to_julia<QObject*>(const QVariant& v)
{
if(v.type() == qMetaTypeId<QObject*>())
{
return try_qobject_cast<JuliaObject>(v.value<QObject*>());
// Add new types here
return try_qobject_cast<JuliaObject, JuliaDisplay>(v.value<QObject*>());
}

return nullptr;
Expand Down
7 changes: 6 additions & 1 deletion deps/src/qmlwrap/wrap_qml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QtQml>

#include "julia_api.hpp"
#include "julia_display.hpp"
#include "julia_object.hpp"
#include "julia_signals.hpp"
#include "type_conversion.hpp"
Expand Down Expand Up @@ -43,6 +44,7 @@ JULIA_CPP_MODULE_BEGIN(registry)

qmlRegisterSingletonType("org.julialang", 1, 0, "Julia", qmlwrap::julia_js_singletontype_provider);
qmlRegisterType<qmlwrap::JuliaSignals>("org.julialang", 1, 0, "JuliaSignals");
qmlRegisterType<qmlwrap::JuliaDisplay>("org.julialang", 1, 0, "JuliaDisplay");

qml_module.add_abstract<QObject>("QObject");

Expand Down Expand Up @@ -145,6 +147,9 @@ JULIA_CPP_MODULE_BEGIN(registry)
}
});

qml_module.add_type<qmlwrap::JuliaDisplay>("JuliaDisplay", julia_type("CppDisplay"))
.method("load_png", &qmlwrap::JuliaDisplay::load_png);

// Exports:
qml_module.export_symbols("QApplication", "QQmlApplicationEngine", "QQmlContext", "set_context_property", "root_context", "load", "qt_prefix_path", "QQuickView", "set_source", "engine", "QByteArray", "QQmlComponent", "set_data", "create", "QQuickItem", "content_item", "QQuickWindow", "QQmlEngine", "JuliaObject", "QTimer", "context_property", "emit");
qml_module.export_symbols("QApplication", "QQmlApplicationEngine", "QQmlContext", "set_context_property", "root_context", "load", "qt_prefix_path", "QQuickView", "set_source", "engine", "QByteArray", "QQmlComponent", "set_data", "create", "QQuickItem", "content_item", "QQuickWindow", "QQmlEngine", "JuliaObject", "QTimer", "context_property", "emit", "JuliaDisplay");
JULIA_CPP_MODULE_END
6 changes: 6 additions & 0 deletions src/QML.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ macro qmlfunction(fname...)
esc(:(QML.register_function($(Any[string(f) for f in fname]))))
end

function Base.display(d::JuliaDisplay, x)
buf = IOBuffer()
writemime(buf, MIME"image/png"(), x)
load_png(d, takebuf_array(buf))
end

export @qmlget, @qmlset, @emit, @qmlfunction

@doc """
Expand Down
24 changes: 24 additions & 0 deletions test/image.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Base.Test
using QML
using TestImages

function test_display(d::JuliaDisplay)
img = testimage("lena_color_256")
display(d, img)
end

@qmlfunction test_display

qml_file = joinpath(Pkg.dir("QML"), "test", "qml", "image.qml")

app = QML.application()
qml_engine4 = QQmlApplicationEngine()

# Load QML after setting context properties, to avoid errors
load(qml_engine4, qml_file)

# Run the application
QML.exec()

# Needed to prevent crash-on-exit
finalize(app)
28 changes: 28 additions & 0 deletions test/qml/image.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
import org.julialang 1.0

ApplicationWindow {
title: "My Application"
width: 300
height: 300
visible: true

ColumnLayout {
spacing: 6
anchors.centerIn: parent

Button {
Layout.alignment: Qt.AlignCenter
text: "Push Me"
onClicked: Julia.test_display(jdisp)
}

JuliaDisplay {
id: jdisp
width: 256
height: 256
}
}
}
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ include("qquickview.jl")
include("qqmlcomponent.jl")
include("julia_object.jl")
include("julia_signal.jl")
include("image.jl")

0 comments on commit 6b55ed1

Please sign in to comment.