Skip to content

Commit fd70696

Browse files
authored
Add support for setting a Makie scene and proper scaling (#25)
* Add support for setting a Makie scene and proper scaling Issue JuliaGraphics/QMLMakie.jl#4 * Update CI
1 parent 5fbebe2 commit fd70696

8 files changed

Lines changed: 163 additions & 41 deletions

File tree

.github/workflows/test.yml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,21 @@ jobs:
1515
fail-fast: false
1616
matrix:
1717
version:
18-
- '1.8'
19-
- '1.9'
18+
- '1.10'
19+
- '1'
2020
- 'nightly'
2121
os:
2222
- ubuntu-latest
23-
- macOS-latest
23+
- macos-latest
2424
- windows-latest
25-
arch:
26-
- x64
25+
arch: [x64, arm64]
26+
exclude:
27+
- os: ubuntu-latest
28+
arch: arm64
29+
- os: windows-latest
30+
arch: arm64
31+
- os: macos-latest
32+
arch: x64
2733
steps:
2834
- uses: actions/checkout@v3
2935
with:
@@ -34,18 +40,13 @@ jobs:
3440
repository: JuliaInterop/libcxxwrap-julia
3541
path: libcxxwrap
3642
- name: Install Qt
37-
uses: jurplel/install-qt-action@v3
38-
with:
39-
version: '6.4.2'
43+
uses: jurplel/install-qt-action@v4
4044
- uses: julia-actions/setup-julia@latest
4145
with:
4246
version: ${{ matrix.version }}
4347
arch: ${{ matrix.arch }}
4448
- name: Build libcxxwrap-julia
4549
run: |
46-
if [[ "$OSTYPE" != "darwin"* ]]; then
47-
rm -f /opt/hostedtoolcache/julia/1.6*/x64/lib/julia/libstdc++.so.6
48-
fi
4950
mkdir build-libcxxwrap && cd build-libcxxwrap
5051
cmake -DCMAKE_INSTALL_PREFIX=$HOME/install -DJLCXX_BUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Debug ../libcxxwrap
5152
VERBOSE=ON cmake --build . --config Debug --target install

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16.0)
22

33
project(JlQML)
44

5-
set(JlQML_VERSION 0.7.0)
5+
set(JlQML_VERSION 0.7.1)
66
message(STATUS "Project version: v${JlQML_VERSION}")
77

88
set(CMAKE_MACOSX_RPATH 1)

jlqml.hpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,21 @@
44
#include <jlcxx/functions.hpp>
55
#include <QMetaType>
66

7-
Q_DECLARE_METATYPE(jlcxx::SafeCFunction)
8-
Q_DECLARE_OPAQUE_POINTER(jl_value_t*)
9-
Q_DECLARE_METATYPE(jl_value_t*)
7+
namespace qmlwrap
8+
{
9+
10+
// Helper to store a Julia value of type Any in a GC-safe way
11+
struct QVariantAny
12+
{
13+
QVariantAny(jl_value_t* v);
14+
~QVariantAny();
15+
jl_value_t* value;
16+
};
17+
18+
using qvariant_any_t = std::shared_ptr<QVariantAny>;
19+
20+
}
21+
22+
Q_DECLARE_METATYPE(qmlwrap::qvariant_any_t)
1023

1124
#endif

makie_viewport.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ namespace qmlwrap
1313
class MakieRenderFunction : public RenderFunction
1414
{
1515
public:
16-
MakieRenderFunction(jl_value_t* const & screen_ptr) : m_screen_ptr(screen_ptr)
16+
MakieRenderFunction(jl_value_t* const & screen_ptr, jl_value_t*& scene) : m_screen_ptr(screen_ptr), m_scene(scene)
1717
{
18+
if(MakieViewport::m_default_render_function.fptr != nullptr)
19+
{
20+
m_scene_render_function = jlcxx::make_function_pointer<void(jl_value_t*, jl_value_t*)>(MakieViewport::m_default_render_function);
21+
}
1822
}
1923

2024
void setRenderFunction(jlcxx::SafeCFunction f) override
@@ -23,12 +27,22 @@ class MakieRenderFunction : public RenderFunction
2327
}
2428
void render() override
2529
{
26-
m_render_function(m_screen_ptr);
30+
if(m_scene != nullptr)
31+
{
32+
m_scene_render_function(m_screen_ptr, m_scene);
33+
}
34+
else if(m_render_function != nullptr)
35+
{
36+
m_render_function(m_screen_ptr);
37+
}
2738
}
2839
private:
2940
typedef void (*render_callback_t)(jl_value_t*);
30-
render_callback_t m_render_function;
41+
render_callback_t m_render_function = nullptr;
42+
typedef void (*scene_render_callback_t)(jl_value_t*, jl_value_t*); // Default render function takes an extra scene argument
43+
scene_render_callback_t m_scene_render_function;
3144
jl_value_t* const & m_screen_ptr;
45+
jl_value_t*& m_scene;
3246
};
3347

3448
jl_module_t* get_makie_support_module()
@@ -73,7 +87,7 @@ struct MakieSupport
7387
jlcxx::JuliaFunction on_context_destroy;
7488
};
7589

76-
MakieViewport::MakieViewport(QQuickItem *parent) : OpenGLViewport(parent, new MakieRenderFunction(m_screen))
90+
MakieViewport::MakieViewport(QQuickItem *parent) : OpenGLViewport(parent, new MakieRenderFunction(m_screen, m_scene))
7791
{
7892
get_makie_support_module(); // Throw the possible error early
7993
QObject::connect(this, &QQuickItem::windowChanged, [this] (QQuickWindow* w)
@@ -96,13 +110,33 @@ MakieViewport::~MakieViewport()
96110
{
97111
jlcxx::unprotect_from_gc(m_screen);
98112
}
113+
if(m_scene != nullptr)
114+
{
115+
jlcxx::unprotect_from_gc(m_scene);
116+
}
117+
}
118+
119+
qvariant_any_t MakieViewport::scene()
120+
{
121+
return std::make_shared<QVariantAny>(m_scene);
122+
}
123+
124+
void MakieViewport::setScene(qvariant_any_t scene)
125+
{
126+
jl_value_t* scene_val = scene->value;
127+
jlcxx::protect_from_gc(scene_val);
128+
if(m_scene != nullptr)
129+
{
130+
jlcxx::unprotect_from_gc(m_scene);
131+
}
132+
m_scene = scene_val;
99133
}
100134

101135
void MakieViewport::setup_buffer(QOpenGLFramebufferObject* fbo)
102136
{
103137
if(m_screen == nullptr)
104138
{
105-
m_screen = MakieSupport::instance().setup_screen(std::forward<QOpenGLFramebufferObject*>(fbo));
139+
m_screen = MakieSupport::instance().setup_screen(std::forward<QOpenGLFramebufferObject*>(fbo), window());
106140
jlcxx::protect_from_gc(m_screen);
107141
}
108142
else
@@ -113,5 +147,6 @@ void MakieViewport::setup_buffer(QOpenGLFramebufferObject* fbo)
113147
}
114148

115149
jl_module_t* MakieViewport::m_qmlmakie_mod = nullptr;
150+
jlcxx::SafeCFunction MakieViewport::m_default_render_function = {nullptr, nullptr, nullptr};
116151

117152
} // namespace qmlwrap

makie_viewport.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,23 @@ class MakieViewport : public OpenGLViewport
1111
{
1212
Q_OBJECT
1313
QML_ELEMENT
14+
Q_PROPERTY(qvariant_any_t scene READ scene WRITE setScene NOTIFY sceneChanged)
1415
public:
1516
MakieViewport(QQuickItem* parent = 0);
1617
virtual ~MakieViewport();
18+
qvariant_any_t scene();
19+
void setScene(qvariant_any_t scene);
20+
1721
static jl_module_t* m_qmlmakie_mod;
22+
static jlcxx::SafeCFunction m_default_render_function;
23+
24+
signals:
25+
void sceneChanged();
1826

1927
private:
2028
// Screen created and used on the Julia side
2129
jl_value_t* m_screen = nullptr;
30+
jl_value_t* m_scene = nullptr;
2231
virtual void setup_buffer(QOpenGLFramebufferObject* fbo) override;
2332
};
2433

opengl_viewport.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include <QOpenGLFramebufferObject>
99
#include <QQuickFramebufferObject>
1010

11-
// #include "jlqml.hpp"
11+
#include "jlqml.hpp"
1212

1313
namespace qmlwrap
1414
{

qmltests/crash.jl

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using QML
2+
3+
# const qml_file = joinpath(pwd(), "code", "qml", "test.qml")
4+
5+
function update_props()
6+
props["fruits"] = fruits2
7+
end
8+
9+
function main(qml_file, props)
10+
loadqml(qml_file, props=props)
11+
exec()
12+
end
13+
14+
mutable struct Fruit
15+
name::String
16+
cost::Float64
17+
end
18+
19+
fruits = JuliaItemModel([Fruit("apple", 1.0), Fruit("orange", 2.0)])
20+
fruits2 = JuliaItemModel([Fruit("banana", 1.0), Fruit("pear", 2.0)])
21+
22+
props = JuliaPropertyMap("fruits" => fruits)
23+
24+
@qmlfunction update_props
25+
26+
# main(qml_file, props)
27+
28+
29+
mktempdir() do folder
30+
path = joinpath(folder, "test.qml")
31+
write(
32+
path,
33+
"""
34+
import QtQuick
35+
import QtQuick.Controls
36+
import QtQuick.Layouts
37+
import org.julialang
38+
39+
ApplicationWindow {
40+
id: mainWin
41+
title: "My Application"
42+
width: 400
43+
height: 400
44+
visible: true
45+
46+
ColumnLayout{
47+
anchors.fill: parent
48+
49+
Button {
50+
height: 200
51+
Layout.fillWidth: true
52+
text: "Update Fruit"
53+
onClicked: {
54+
Julia.update_props()
55+
console.log("Value:", props.fruits)
56+
}
57+
}
58+
ListView {
59+
model: props.fruits
60+
Layout.fillHeight: true
61+
Layout.fillWidth: true
62+
delegate: Row {
63+
Text {
64+
text: name
65+
}
66+
}
67+
}
68+
}
69+
}
70+
"""
71+
)
72+
main(path, props)
73+
end

wrap_qml.cpp

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,15 @@ template<> struct SuperType<qmlwrap::JuliaItemModel> { using type = QAbstractTab
5151
namespace qmlwrap
5252
{
5353

54-
// Helper to store a Julia value of type Any in a GC-safe way
55-
struct QVariantAny
54+
QVariantAny::QVariantAny(jl_value_t* v) : value(v)
5655
{
57-
QVariantAny(jl_value_t* v) : value(v)
58-
{
59-
assert(v != nullptr);
60-
jlcxx::protect_from_gc(value);
61-
}
62-
~QVariantAny()
63-
{
64-
jlcxx::unprotect_from_gc(value);
65-
}
66-
jl_value_t* value;
67-
};
68-
69-
using qvariant_any_t = std::shared_ptr<QVariantAny>;
70-
56+
assert(v != nullptr);
57+
jlcxx::protect_from_gc(value);
7158
}
72-
73-
Q_DECLARE_METATYPE(qmlwrap::qvariant_any_t)
74-
75-
namespace qmlwrap
59+
QVariantAny::~QVariantAny()
7660
{
61+
jlcxx::unprotect_from_gc(value);
62+
}
7763

7864
using qvariant_types = jlcxx::ParameterList<bool, float, double, int32_t, int64_t, uint32_t, uint64_t, void*, jl_value_t*,
7965
QString, QUrl, jlcxx::SafeCFunction, QVariantMap, QVariantList, QStringList, QList<QUrl>, JuliaDisplay*, JuliaCanvas*, JuliaPropertyMap*, QObject*>;
@@ -296,6 +282,11 @@ JLCXX_MODULE define_julia_module(jlcxx::Module& qml_module)
296282
qmlwrap::MakieViewport::m_qmlmakie_mod = reinterpret_cast<jl_module_t*>(mod);
297283
});
298284

285+
qml_module.method("set_default_makie_renderfunction", [](jlcxx::SafeCFunction renderFunction)
286+
{
287+
qmlwrap::MakieViewport::m_default_render_function = renderFunction;
288+
});
289+
299290
// Enums
300291
qml_module.add_bits<Qt::Orientation>("Orientation", jlcxx::julia_type("CppEnum"));
301292
qml_module.set_const("Horizontal", Qt::Horizontal);

0 commit comments

Comments
 (0)